Transport-agnostic async Rust client for the Signal Fish multiplayer signaling protocol. Connect to a Signal Fish server over any bidirectional transport, authenticate, join rooms, and receive strongly-typed events — all through a simple channel-based API.
Features
- Transport-agnostic — implement the
Transporttrait for any backend (WebSocket, TCP, QUIC, WebRTC data channels, etc.) - Wire-compatible — all protocol types match the Signal Fish server's v2 JSON format exactly
- Feature-gated WebSocket transport — the default
transport-websocketfeature provides a ready-to-useWebSocketTransport - Event-driven — receive typed
SignalFishEvents via a Tokio MPSC channel - Structured errors —
SignalFishError(9 variants) andErrorCode(40 variants) for precise error handling - Full protocol coverage — 11 client message types, 24 server message types, 26 event variants
Installation
[]
= "0.2.2"
Without the built-in WebSocket transport (bring your own):
[]
= { = "0.2.2", = false }
Quick Start
use ;
async
Feature Flags
| Feature | Default | Description |
|---|---|---|
transport-websocket |
yes | Built-in WebSocket transport via tokio-tungstenite and futures-util |
Architecture
| Module | Purpose |
|---|---|
client |
SignalFishClient handle, SignalFishConfig, JoinRoomParams |
event |
SignalFishEvent enum (24 server + 2 synthetic variants) |
protocol |
Wire-compatible ClientMessage (11) / ServerMessage (24) types |
error |
SignalFishError unified error type (9 variants) |
error_codes |
ErrorCode enum (40 server error code variants) |
transport |
Transport trait for pluggable backends |
transports |
Built-in transport implementations (WebSocketTransport) |
Examples
Basic Lobby
Full lifecycle: connect, authenticate, join a room, handle events, and shut down gracefully with Ctrl+C support.
# Override the server URL:
SIGNAL_FISH_URL=ws://my-server:3536/ws
Custom Transport
Implement a channel-based loopback transport, wire it into the client, and verify events flow correctly — no network required.
See examples/custom_transport.rs.
Custom Transport
Implement the Transport trait to plug in any I/O backend:
use async_trait;
use ;
Key requirements:
recv()must be cancel-safe (it's used insidetokio::select!)- Connection setup happens before constructing the transport — the trait only covers message I/O
- The transport must be
Send + 'static(required by the async task boundary)
Development
Run CI Locally
A unified script runs all CI checks locally:
# Run all checks (matches CI exactly)
# Quick mode: fmt + clippy + test only
Mandatory baseline
&& &&
Additional quality checks
| Command | CI Workflow | Install |
|---|---|---|
cargo deny check |
ci.yml | cargo install cargo-deny |
cargo audit |
security-supply-chain.yml | cargo install cargo-audit |
bash scripts/check-no-panics.sh |
no-panics.yml | (built-in) |
typos |
docs-validation.yml | cargo install typos-cli |
markdownlint-cli2 "**/*.md" |
docs-validation.yml | npm install -g markdownlint-cli2 |
lychee --config .lychee.toml "**/*.md" |
docs-validation.yml | cargo install lychee |
cargo machete |
unused-deps.yml | cargo install cargo-machete |
cargo semver-checks check-release |
semver-checks.yml | cargo install cargo-semver-checks |
bash scripts/check-workflows.sh |
workflow-lint.yml | (built-in) |
cargo +nightly miri test --test protocol_tests |
deep-safety.yml | rustup component add miri --toolchain nightly |
cd fuzz && cargo +nightly fuzz run ... |
deep-safety.yml | cargo install cargo-fuzz |
cargo mutants --file src/protocol.rs ... |
deep-safety.yml | cargo install cargo-mutants |
cargo llvm-cov --all-features --summary-only |
coverage.yml | cargo install cargo-llvm-cov + rustup component add llvm-tools-preview |
Minimum Supported Rust Version (MSRV)
1.85.0
Tested against the latest stable Rust and the declared MSRV. Bumping the MSRV is considered a minor version change.
AI Disclosure
🤖 AI Disclosure
This project was developed with substantial AI assistance. The protocol design and core technology concepts were created entirely by humans, but the vast majority of the code, documentation, and tests were written with the help of Claude Opus 4.6 and Codex 5.3. Human oversight covered code review and architectural decisions, but day-to-day implementation was primarily AI-driven. This transparency is provided so users can make informed decisions about using this crate.
License
MIT — Copyright (c) 2025-2026 Ambiguous Interactive