This is not a proposal for ssb. This is just me synthesizing a few thoughts on plugin-based architectures in general, while completely avoiding the open questions, namely the notion of (un)trusted identities, and handling p2p connections.
Changes to this spec are published on github.
Min-Bus
A somewhat minimal system for coordinating inter-process communication.
Abstractions
Min-Bus is a system that allows different processes - called plugins - to discover and talk to each other. To do so, it provides a server, where plugins can connect to. When connecting to the server, a plugin must specify a name (arbitrary byte string not longer than 255 bytes), and a version (unsigned 16 bit integer). Connecting succeeds if no other plugin with the same name is currently connected. Versions signify non-breaking changes to the API exposed by a plugin. If a plugin performs breaking changes to its API, it needs to change its name.
Once the connection is established, the plugin can perform the following actions:
- query the currently connected plugins (name + version)
- this opens a stream where the server first sends the list of currently connected plugins, and then sends a notification whenever a plugin connects or disconnects
- the plugin can cancel the stream at any time
- be notified of other plugins that what to connect to it. It can either reject the connection, or allow it.
- ask to be connected to another plugin (by name). If the other plugin accepts, both of them are given
- a bidirectional, byte-oriented communication channel to the other plugin
- with an explicit, credit-based backpressure mechanism
- with heartbeats
- either plugin is allowed to close/cancel it
- plugins can use any protocol they like to communicate
- a bidirectional, byte-oriented communication channel to the other plugin
- disconnect
Implementation
A server implementation is free to choose any mechanism for plugins to connect to, as long as there is a bpmux implementation that runs over that mechanism. For example, the server could listen for tcp connections on a specific port, or it could use unix domain sockets. A server is allowed to expose any number of such mechanisms (e.g. both a local unix domain socket and a tcp socket with a public address), all plugins can talk to each other regardless of how they connected to the server. For public-facing ports, it is recommended to enforce authentication and to encrypt all data.
After connection establishment, all communication happens via bpmux. The server should should always supply the plugin with enough credit so that it can perform queries. The server should also respond to any heartbeat pings. The server may send heartbeat pings to a plugin and disconnect it if it does not react after a well-documented, implementation specific time.
Registration Message
Initially, the server does nothing but wait for the plugin to send its registration message. This is a message that consists of an unsigned 8 bit integer, followed by that many bytes as the name of the plugin, followed by a uint16 version of the plugin. If there is already a plugin of that name, the server simply terminates the connection. Else it notifies all subscribed plugins that the new plugin has been registered and goes into the connected state.
After sending the registration message, a plugin can send any of the following to the server:
Disconnection Message
The plugin sends a message with a zero-length payload. This is not strictly necessary, the plugin can instead directly terminate the underlying connection. But in case of connection types where this can not be directly detected by the server, it is polite to send this message prior to disconnecting.
Upon receiving this message, the server does all the cleanup necessary for disconnected plugins (see section "Server Behavior Upon Plugin Disconnection")
Connection Query
The plugin sends a request with a zero-length payload. The server sends a response containing the repeated <length_uint8><name><version_uint16>
tuples of all currently connected plugins, except for the requesting plugin itself.
Connection Stream
The plugin opens a stream with a zero-length payload. The server immediately sends the set of currently connected plugins (except for the plugin itself) as a single message to the stream, containing repeated <length_uint8><name><version_uint16>
tuples. Afterwards, whenever a plugin connects, the server sends a message containing the byte 0000_0000
followed by the <length_uint8><name><version_uint16>
of the plugin to the stream. Whenever a plugin disconnects, the server sends a message containing the byte 0000_0001
followed by the <length_uint8><name><version_uint16>
of the plugin to the stream,.
If a plugin opens a connection stream
while it still has another one open, the server must immediately cancel the new one (with a zero-length payload).
continued in next post...