AnyCable client consists of multiple building blocks that could be replaced independently of each other (unless interfaces are satisfied). The core entities are Cable, Transport, Protocol, Encoder, and Channels. We also have Logger, Hub, and Monitor.
Check out also the createCable
function implementation to see how all the pieces are glued together.
The diagram below shows the data flow through the client:
Cable acts as a container for all other components. It's also responsible for data from Transport to Channels and vice versa. Cable implements Consumer (for Protocol) and Receiver (for Channel) interfaces (see data flow above).
Transport is responsible for sending/receiving data from/to a server. That's it. No knowledge of data format/serialization or whatever.
Encoder is responsible for serializing/deserializing data from Protocol to Transport format. One protocol may be represented via different serialization formats, e.g., JSON, Msgpack. Encoder aims to localize this difference, so other parts shouldn't care about it.
Protocol translates library models into a wire protocol format (e.g., Action Cable). AnyCable client uses its own internal model not coupled with any particular server protocol.
Channel is a business-logic abstraction (similar to Action Cable Channel). It only needs a Receiver (implemented by Cable) to perform remote actions.
Hub is a part of Cable, which keeps track of Subscriptions. Subscription represents a server-side channel instance and MAY have multiple client-side Channel instances attached.Incoming data go to Hub, which transmits it further to a designated Subscription, which in its turn notify channels. One interesting feature of Hub is that it helps to deal with race conditions when subscribing to and unsubscribing from channels.
Monitor is responsible for keeping Cable connected. First, it tracks Ping messages and triggers reconnection if they're missing. Secondly, it tries to reconnect when an unexpected disconnect occurs (using a configurable backoff strategy).