Messenger: Rooms and Messages

Overview

Messenger is responsible for the messaging components of the Pivot platform. Users experience this as Chat Rooms, Post Rooms, Audio Rooms, Video Rooms, and streaming rooms.

This means that entities such as Room, Message, and RoomMember live in Messenger, but because SpaceMember and Block do not, there are some substantial synchronous dependencies between Messenger and Blockhead.

Note that we rely on LiveKit for the actual audio and video transport via Stagehand as well as on Blobby to manage audio/video recording object storage in S3 and Asimov for AI/ML metadata (e.g. transcripts) for those recordings. These interactions are a mix of gRPC (creating LiveKit rooms and tokens, creating Blobby files) and NATS (consuming new recordings from Stagehand NATS messages, Asimov's consumption of new audio/video files from Blobby NATS messages).

Messenger/Blockhead Integration

There are multiple touchpoints where Messenger integrates with Blockhead:

  1. Messenger uses Blockhead to authorize access to Space Rooms and and messages sent in Space Rooms, because there are no RoomMembers in this case.

  2. Users can create blocks in the context of a room, in which case Blockhead relies on Messenger to authorize access to that block and its decendents, if the message is in a direct or group room. Messenger just stores the boolean field HasAttachedBlocks to determine when a Message has at least one attached block, which are then stored in Blockhead with corresponding AttachedToMessageId instead of a SpaceId.

  3. Blockhead uses Messenger to create a room when a 'Room' block is created in Blockhead.

API

Pilot Tokens for Rooms

The Room Protobuf type includes a PilotToken field, enabling clients who are members of a room or member's of the associated space who have access to join a Pilot scope for the room.

CreateRoom

When Messenger creates a Pivot room of type audio, video, direct or streaming, it also creates a LiveKit AvRoom, by using Stagehand. This is synchronous – if Stagehand or LiveKit is down Messenger will fail.

AvToken Generation and File Uploads

Messenger provides multiple gRPC methods that wrap Stagehand, but provide Messenger specific authorization, for the purpose of supporting various live audio and video featuers. These features also utilize Blobby, which can also be used to support arbitrary file uploads.

  1. GenerateRoomAvToken (Messenger) – Simple Messenger authz check and Stagehand call.
  2. CreateFile (Blobby) – This Blobby RPC allows user to upload files via Blobby that can then be attached to a Messenger message. This is used for audio messages as well as general files. This RPC returns either an S3 pre-signed URL or a Mux direct upload URL, depending on the file type stated in the request. The client still has to attach the File later with CreateMessageAttachment, which forces the client to know whether they even tried to do so and allows Messenger to verify the upload.

Recordings

Messenger is responsible for leveraging Stagehand NATS messages to determine when a new recording has been created for a Room or a Message (i.e., an audio or video file that represents an audio or video message). Messenger processes these messages by using the Blobby API to create a File in Blobby and associates that with a RoomAttachedFile or a MessageAttachedFile.

Presence

To support rendering presence for an AvRoom, Messenger's Room entity includes an AvRoomPresence field, which it pulls from Stagehand via gRPC. Clients don't have to poll for this, as new presence values are pushed directly via Dealer events.

NATS

Publication

Messenger publishes a message to messenger.change_feed each time an entity it owns is created or modified. For example, messenger.change_feed.message.{roomId}.createdV1.

Consumption

  1. Messenger reads from stagehand.change_feed.raw_recording.pivot_room.created to process relevant raw LiveKit recordings.

  2. dealer.read_receipt.createdV1 to create read receipts for messages, as they get read.

Databases

Messenger uses Postgres to store messages, rooms, and related data.

  1. Room – A room is a container for messages. Users can create rooms and rooms can also be created as part of the process of creating a 'Room' block in Blockhead.

  2. Message – A message is sent by a user in a room. It may have rich text content and/or attached files.

  3. UserMessageHistory – Each user who 1) is a member of a room or 2) has access to a room through Blockhead, has at most one UserMessageHistory record per message. In order for this record to be created, the user must have 1) reacted to or 2) read the message.

  4. RoomMember – For rooms that are not associated with a space, members are managed by Messenger. These are referred to as direct rooms (exactly two members) and group rooms (any number of members).

  5. MessageAttachment – A message attachment represents the association between a message and a fileId which is managed by Blobby. This file ID is resolved into a URL by Blobby upon request from Messenger. If it is an attached audio or video file, that could represent an audio or video message, which is determined by the MessageAttachment type.

  6. RoomRecording – A recording represents the association between a Blobby fileId and a room, along with the recording-specific metadata. When a recording is clipped, that is a distinct RoomRecording record.

Temporal Workflows

  1. Messages that are scheduled for the future trigger a workflow, which sleeps and then sends the message, unless the message is unscheduled or manually sent.

Deployment

Deployed as Docker Container to ECS cluster. Runs as a replica set that scales up and down with demand.

Observability

  • Structured logging to stdout
  • Otel tracing of incoming/outgoing gRPC requests

Security

  • Only accessible from inside the VPC
  • Security group restricts access from inside the VPC to specific other services