Expand description
§Signal Fish Client
Transport-agnostic Rust client for the Signal Fish multiplayer signaling protocol.
This crate provides a high-level async client that communicates with a Signal Fish signaling server using JSON text messages over any bidirectional transport.
§Features
- Transport-agnostic — implement the
Transporttrait for any backend - Wire-compatible — all protocol types match the server’s v2 format exactly
- Protocol v2 relay + v3 mesh — v3 is additive and opt-in; a default client stays byte-identical to v2 (see Protocol versions)
- WebSocket built-in — default
transport-websocketfeature providesWebSocketTransport - Event-driven — receive typed
SignalFishEvents via a channel - No silent loss — events are delivered with backpressure and sends are bounded with explicit congestion signals (see Delivery guarantees)
§Choosing a client
The crate ships two clients with identical protocol behavior; pick by how your application is driven:
SignalFishClient(async) — spawns a background transport loop withtokio::spawn. Use it when a tokio runtime is running (a#[tokio::main]/block_onapplication, multi-thread orcurrent_thread). It only makes progress while the runtime is driven — manually “ticking” a runtime once per frame starves it (see the driving contract).SignalFishPollingClient(sync, featurepolling-client) — no background task, no runtime. You callpoll()once per frame from a game loop. This is the right client for frame-driven engines (Godot, Bevy without tokio, Unity via FFI) andwasm32targets.
§Protocol versions
The SDK speaks two protocol generations, and you choose which by how you
build SignalFishConfig:
- v2 — the relay floor (default).
SignalFishConfig::newadvertises no v3 capabilities, the server relays all traffic through itself, and theAuthenticatebytes are byte-identical to the old v2 client. This is the relay-floor guarantee: opt into nothing and nothing changes. - v3 — additive mesh (opt-in).
SignalFishConfig::enable_meshadvertises the WebRTC/relay transports and mesh/host/relay topologies, letting the server form a peer-to-peer session. v3 capabilities are additive to the v2 relay floor, and the server falls back to relay whenever it cannot form a session. On current servers, an eligible client explicitly callsSignalFishClient::start_gameafter readiness instead of relying on automatic start.
The negotiated version comes back in the server’s ProtocolInfo; check it via
SignalFishClient::negotiated_protocol_version /
SignalFishClient::supports_mesh. v3-only sends fail fast with
SignalFishError::ProtocolUnsupported until v3 is negotiated. The SDK is
signaling-only — it bundles no WebRTC stack; with the mesh feature you
implement the webrtc::WebRtcDriver seam (or use
webrtc::MeshController) against str0m / webrtc-rs / web-sys. The highest
version this SDK speaks is PROTOCOL_VERSION.
§Quick Start
use signal_fish_client::{
WebSocketTransport, SignalFishClient, SignalFishConfig,
JoinRoomParams, SignalFishEvent,
};
#[tokio::main]
async fn main() -> Result<(), signal_fish_client::SignalFishError> {
// 1. Connect a WebSocket transport to the signaling server.
let transport = WebSocketTransport::connect("ws://localhost:3536/ws").await?;
// 2. Build a client config with your application ID.
let config = SignalFishConfig::new("mb_app_abc123");
// 3. Start the client — returns a handle and an event receiver.
// The client automatically sends Authenticate on start.
let (mut client, mut event_rx) = SignalFishClient::start(transport, config);
// 4. Process events — wait for Authenticated before joining a room.
while let Some(event) = event_rx.recv().await {
match event {
SignalFishEvent::Authenticated { app_name, .. } => {
println!("Authenticated as {app_name}");
// Now it's safe to join a room.
client.join_room(JoinRoomParams::new("my-game", "Alice"))?;
}
SignalFishEvent::RoomJoined { room_code, .. } => {
println!("Joined room {room_code}");
client.set_ready()?;
}
// Protocol v2: the game starts explicitly, not on readiness.
SignalFishEvent::LobbyStateChanged { all_ready: true, .. } => {
client.start_game()?;
}
SignalFishEvent::Disconnected { .. } => break,
_ => {}
}
}
// 5. Shut down gracefully.
client.shutdown().await;
Ok(())
}Re-exports§
pub use client::ClientSnapshot;pub use client::ClientStats;pub use client::GameDataDelivery;pub use client::JoinRoomParams;pub use client::ProtocolViolationPolicy;pub use client::SignalFishClient;pub use client::SignalFishConfig;pub use client_api::SignalFishClientApi;pub use error::SignalFishError;pub use error_codes::ErrorCode;pub use event::ProtocolViolationKind;pub use event::ServerErrorInfo;pub use event::SignalFishEvent;pub use event::DECODE_FAILED_RAW_PREFIX_MAX;pub use protocol::decode_v3_binary_game_data;pub use protocol::ClientMessage;pub use protocol::DeliveryClass;pub use protocol::DeliveryCountersByClass;pub use protocol::DeliveryGap;pub use protocol::DeliveryGapReason;pub use protocol::DeliveryReportPayload;pub use protocol::IceServer;pub use protocol::LatestDeliveryCounters;pub use protocol::MessageTransport;pub use protocol::ReliableDeliveryCounters;pub use protocol::ReplayStatus;pub use protocol::SenderWatermark;pub use protocol::ServerMessage;pub use protocol::SessionPeer;pub use protocol::SessionPlanPayload;pub use protocol::Topology;pub use protocol::TransportKind;pub use protocol::V3BinaryGameDataFrame;pub use protocol::VolatileDeliveryCounters;pub use signal::PeerSignal;pub use transport::Transport;pub use transport::TransportCloseInfo;pub use transport::TransportDiagnostics;pub use transport::TransportFrame;pub use transports::WebSocketConnectOptions;pub use transports::WebSocketTransport;pub use polling_client::PollingClientOptions;pub use polling_client::PollingClosePolicy;pub use polling_client::PollingQueueAgeStats;pub use polling_client::PollingStats;pub use polling_client::PollingWorkBudget;pub use polling_client::SignalFishPollingClient;pub use mesh::MeshPeer;pub use mesh::MeshSession;pub use webrtc::DriverEvent;pub use webrtc::MeshEvent;pub use webrtc::WebRtcDriver;pub use webrtc::MeshController;
Modules§
- client
- Async client for the Signal Fish signaling protocol.
- client_
api - Common synchronous API implemented by both Signal Fish client drivers.
- error
- Error types for the Signal Fish client.
- error_
codes - Error codes for structured error handling in the Signal Fish protocol.
- event
- High-level events emitted by the Signal Fish client.
- mesh
- Optional zero-dependency mesh session tracker (protocol v3).
- polling_
client - Synchronous, polling-based client for the Signal Fish signaling protocol.
- protocol
- Wire-compatible protocol types for the Signal Fish signaling protocol.
- signal
- Typed WebRTC signaling payloads (protocol v3).
- transport
- Frame-capable polling transport contract.
- transports
- Transport implementations for the Signal Fish signaling protocol.
- webrtc
- The pluggable WebRTC driver seam and the
MeshControllerthat drives it (protocol v3,meshfeature).
Constants§
- PROTOCOL_
VERSION - Highest signaling protocol version this SDK speaks.