Messaging Data Structures
The core application supported by Towns Protocol is messaging. Towns Stream Nodes are tasked with serving stream events, which are represented as data using protobufs. Stream events themselves may contain message-like events or metadata to support event validation.Protocol Messaging Protobuf
The data schema of the Towns protocol can be defined declaratively by protobuf.proto. Below is an elided snapshot ofprotocol.proto as of January 2024 containing only schema definitions used in a messaging context within the Towns protocol.
SpacePayload
StreamEvent messages encapsulate all message types handled by Towns Nodes. The primary unit of account for messaging is described in SpacePayload. A newly minted Space is represented on-chain with the SpaceFactory contract as well of in Towns Nodes and the Towns Chain, which stores the streamId of the Space.
There exists a 1-to-many relation between Spaces as defined in data by the SpacePayload message and Channels. Furthermore, Memberships, usernames, and display_names are stored and snapshotted within the streamId of a Space.
SpacePayload is made polymorphic using oneof in the above definition. Towns Nodes apply rules to each message after unpacking the payload field from the StreamEvent, which is the message transmitted to the Towns Node over the wire. These rules validate the legality of the event for writes that addEvent to the stream.
Channel messages
Channel messages are the primary messages used to facilitate group chat within Spaces. They are defined inChannelPayload in protocol.proto. Each ChannelPayload message is typed as EncryptedData, which is a message that defines the payload of ciphertext.
Remember, Towns nodes never see plain text of messages. The protocol defines any message-like event or event that requires encryption with anEncryptedDataorWrappedEncryptedDatamessage type inprotocol.proto.
DM Channel messages
Direct messages are the second messaging primitive supported by the Towns protocol. The data structure representing direct messaging is defined by theDmChannelPayload protobuf. Each DM is created with the pair of users privy to the DM conversation. Note that just like with channel messages, DM’s are EncryptedData messages from the node’s vantage point.
GDM Channel messages
Group direct message messages are supported by the Towns protocol as their own streams as well. Each Group DM is created with the list of members that forms the initial Membership roster. Though outside the specification of the protocol, the membership roster is meant to convey entitlement to encryption keys, such that clients can implement logic to share keys only with members of the same group dm.
DM’s, and GDM’s are all created as new streams in the Towns Node using the createStream rpc client method. Unlike Spaces and Channels though, there exists no on-chain record of these streams.
Media messages
Media files are supported as separate streams in Towns protocol associated with a parentchannel_id. Messages added to a Towns node containing media must pass validation criteria that proves the creator is a member of that channel_id to prevent man-in-the-middle type attacks.
Media files can be quite large in size and as such are chunked in byte arrays on nodes and therefore support pagination by clients.