diff --git a/doc/architecture.md b/doc/architecture.md new file mode 100644 index 0000000..3484185 --- /dev/null +++ b/doc/architecture.md @@ -0,0 +1,37 @@ +# soju architecture + +soju manages two types of connections: + +- Upstream connections: soju maintains persistent connections to + user-configured IRC servers +- Downstream connections: soju accepts connections from IRC clients + +On startup, soju will iterate over the list of networks stored in the database +and try to open an upstream connection for each network. + +## Ring buffer + +In order to correctly send history to each downstream client, soju maintains +for each network a single-producer multiple-consumer ring buffer. The network's +upstream connection produces messages and multiple downstream connections +consume these messages. Each downstream client may have a different cursor in +the history: for instance a client may be 10 messages late while another has +consumed all pending messages. + +## Goroutines + +Each type of connection has two dedicated goroutines: the first one reads +incoming messages, the second one writes outgoing messages. + +Each user has a dedicated goroutine responsible for dispatching all messages. +It communicates via channels with the per-connection reader and writer +goroutines. This allows to keep the dispatching logic simple (by avoiding any +race condition or inconsistent state) and to rate-limit each user. + +The user dispatcher goroutine receives from the `user.events` channel. Upstream +and downstream message handlers are called from this goroutine, thus they can +safely access both upstream and downstream state. + +In addition to these goroutines, each downstream connection also has one +goroutine per network to handle new upstream messages coming from the ring +buffer.