Skip to content
Stephen Bennett edited this page Dec 2, 2021 · 3 revisions

Code layout

Network state (irc_network crate)

This crate has the basic data model defining the current state of the network and the events that act to change it.

  • irc_network::event - Event and its constituent parts. An Event represents a single atomic change to the network state which is propagated between servers.
  • irc_network::state - Structures that contain the state information. These are what are stored persistently, and should contain only data, no object references. If an object refers to other objects, it should store that object's ID.
  • irc_network::wrapper - Ephemeral wrapper objects which provide logic and convenience accessors for the state objects.
  • irc_network::network - defines the Network object, which stores the network state and mutates it via incoming Event objects.

Server logic (irc_server crate)

This crate contains the client protocol logic and server code.

  • irc_server::Server - the main server class. This owns the Network object, consumes events via a channel, and passes them to the Network to apply. Currently the Server also interprets the Events directly in order to notify clients, but I'm in the process of changing that.
  • irc_server::messages::* - types that encapsulate protocol messages to be sent to clients
  • irc_server::command::* - client command handlers
  • irc_server::policy::* - defines traits and default implementations for policy decisions (e.g. can user x join #y, can user x see that y is in #z, etc.)

Network sync (ircd_sync crate)

Contains the network sync logic, and the EventLog class which stores and manages events, dependencies, etc.

Macros (ircd_macros crate)

Contains macros to simplify definition of repetitive types.

ircd crate

Contains the main function, and not much else.

Functional overview

The whole thing relies on an async runtime, currently tokio. It used to use async_std, but changed because of shortcomings in the integration between async_std and rustls. Some notable long-lived tasks include:

  • Network sync task - takes events from network sync listeners, manages the event log, and sends events to the server task as needed.
  • Server task - owns the Server object and processes incoming messages from client connections and network sync.
  • Connection tasks - one task per listener, and one per connection, both for clients and network sync. These feed messages via channels into the two above main tasks.

Writing various pieces

Network state

Each state object should be pure data - storing only IDs for related objects, and raw data. It should be accompanied by a corresponding wrapper object which provides (read-only) accessor methods, accessors for related objects (which should also return wrapper objects), and so on.

Most accessors on Network should return these wrappers, instead of the raw state objects.

The only way to change network state should be by applying an Event.

NB: once the Network sees an event, it has been committed to the event log and cannot be rejected. It must be handled in a manner which will result in consistent results across servers which see independent events in different orders.

Command handlers

Command handlers run with a read-only view of the server and network state. When a user command needs to mutate state, it does so by producing CommandAction objects, which can create new events or signal other mutable actions for the Server to take on the next loop iteration.

If a command handler needs to make a change and then observe the result, then it needs to be split into two - the command handler to make the change, and a network update handler to process the result.

Clone this wiki locally