Skip to main content

Crate actioncable

Crate actioncable 

Source
Expand description

A client for Rails’ Action Cable.

A Client owns one WebSocket connection to an Action Cable server and multiplexes any number of channel subscriptions over it. It keeps the connection alive the way the official JavaScript client does: the server beats a ping every three seconds, and a connection that goes quiet for longer than ClientBuilder::stale_after is torn down and redialed with backoff. Subscriptions survive reconnects; they are resubscribed as soon as the server says welcome.

use actioncable::{Client, Identifier};
use serde_json::json;

let client = Client::builder("wss://example.com/cable").build()?;
client.connect().await?;

let room = client
    .subscribe(Identifier::new("RoomChannel").param("id", 42))
    .await?;

let reader = room.clone();
tokio::spawn(async move {
    while let Some(message) = reader.next().await {
        println!("{message}");
    }
});

room.perform("speak", json!({ "body": "Hello!" })).await?;
room.unsubscribe().await?;
client.close().await;

Two things are pluggable. A Transport carries bytes: the built-in WebSocketTransport speaks RFC 6455 over tokio-tungstenite behind the default websocket feature, and any other WebSocket library can be dropped in behind the same trait with ClientBuilder::transport. Without the feature and without a transport, ClientBuilder::build returns Error::NoTransport. A Protocol speaks one Action Cable wire format, negotiated as one WebSocket subprotocol: V1Json implements actioncable-v1-json, and a new format is a new Protocol rather than a fork of this client. ClientBuilder::protocols offers several, and the server picks the one it knows.

Where the Go client takes a context, this one takes nothing: Client::connect and Client::subscribe wait until the server answers or the client stops, and a caller who wants a deadline wraps the call in tokio::time::timeout. Dropping either future is safe. The client keeps running — Client::last_error says what it is failing on — and a subscription the server never confirmed is forgotten.

A client that stops for good says so through Client::done and Client::err: the server hung up and said not to come back, the attempts ClientBuilder::max_attempts allows ran out, or ClientBuilder::stop_on_error recognized a failure no reconnect can repair.

Where the Go client takes callbacks, this one offers both: a stream of Events on every Subscription, and SubscribeRequest for the callback form on top of the same stream. Headers that expire come from a HeaderProvider, which a closure returning a future satisfies. Nothing here logs through a logger of its own; the client’s chatter goes to tracing.

The test-support feature adds actioncable::test_support, an in-memory transport a test plays the server on, for testing code built on this client without a network.

Modules§

test_support
In-memory connections a test can play the server on, and a made-up protocol that stamps everything it encodes so a test can tell which protocol the client settled on. Behind the test-support feature, for this crate’s own tests and for the tests of anything built on it.

Structs§

Client
One connection to an Action Cable server and the subscriptions running over it. Build one with builder, start it with connect, and hang up with close. Handles are cheap to clone and share the connection.
ClientBuilder
Configures a Client. Nothing touches the network until Client::connect.
Command
A client-to-server message. data carries the already encoded action payload and is only set for CommandName::Message.
DialOptions
What the client needs the transport to negotiate: the subprotocols its protocols speak, most preferred first, and the headers that authenticate the request, a cookie or a token, since an Action Cable server authorizes the upgrade request itself.
Identifier
Names one subscription: a channel and the params that go with it, like the id of the record the channel streams for.
Incoming
A decoded server-to-client frame. reason and reconnect are only set on Kind::Disconnect, message on Kind::Message and Kind::Ping, and the identifier is empty on the frames that concern the connection rather than a subscription. A Kind::Message frame with no message is dropped and logged rather than delivered empty, which is where this client parts from the Go one.
Message
The undecoded payload a channel broadcast or transmitted, exactly as it came off the wire. Its shape is entirely up to the channel, so decode it into the type you expect.
SubscribeRequest
What to subscribe to, and what to do when its connection changes. The callbacks mirror the Go client’s OnConnected, OnDisconnected and OnRejected; the same events also arrive on Subscription::next_event, so use whichever reads better. A bare Identifier converts into a request with no callbacks, which is what Client::subscribe takes most of the time.
Subscription
One channel subscription on a client. Read what the channel sends with next, watch the connection with next_event, and talk back with perform or send.
V1Json
The actioncable-v1-json protocol: JSON objects in text frames, keyed by command going out and by type coming in.
WebSocketTransport
The built-in transport: tokio-tungstenite over rustls, trusting the platform’s root certificates. It handles the upgrade handshake, answers pings, and reassembles fragmented messages. The request carries User-Agent: actioncable/<version> unless the caller set one, and never negotiates extensions.

Enums§

CommandName
The verb of a client-to-server command.
DisconnectReason
Why an Action Cable server hung up. Rails names four; anything else it might send in the future arrives as Other.
Error
Everything a caller can get back from a cable. It is Clone because a client that stopped for good hands the same failure to everyone who asks it afterwards.
Event
What happened to a subscription’s connection. Some channels only send what’s new, so a reconnect can leave a gap, and only the client knows a reconnect happened.
Kind
The type of a server-to-client frame.

Constants§

SUBPROTOCOL_UNSUPPORTED
The sentinel an Action Cable server names when it speaks none of the subprotocols offered. The client offers it last on every handshake, the way Rails’ own clients do, so a server with nothing in common can say so outright instead of leaving the subprotocol blank.
SUBPROTOCOL_V1_JSON
The subprotocol every Rails Action Cable server speaks.

Traits§

Conn
One live connection. The client reads from one task and writes from another, one write at a time, and may call close concurrently with either. Closing has to interrupt a read in flight so the reader learns the connection is gone.
HeaderProvider
Builds the headers for a dial, asked on every dial rather than once. A client reconnects on its own for as long as it runs, which is longer than a credential that expires lives, and a reconnect carrying the token the first dial used would be turned down for good.
Protocol
Translates between Action Cable commands and the bytes on the wire. It is the seam where an Action Cable protocol plugs in.
Transport
Dials the network connection a client talks over. It is the seam where a network handler plugs in: the built-in WebSocketTransport speaks RFC 6455 over tokio-tungstenite, and wrapping another WebSocket crate, or an in-memory pipe for tests, means implementing this and Conn and nothing else.