type SyncMessage = {
type: 'SYNC_MESSAGE'
senderId: PeerId
recipientId: PeerId
documentId: DocumentId
payload: Uint8Array // Automerge binary sync message
}
type EphemeralMessage = {
type: 'EPHEMERAL_MESSAGE'
senderId: PeerId
documentId: DocumentId
payload: unknown // up to the application
}
// eventually
type AuthMessage = {
type: 'AUTH_MESSAGE'
senderId: PeerId
recipientId: PeerId
shareId: ShareId
payload: unknown // up to the application
}
type Message = SyncMessage | EphemeralMessage | AuthMessageMessages might contain the following properties:
peerId might be the ID of the sender or the recipient
targetId ID of the recipient (or * for broadcast messages)
senderId ID of the sender
channelId can mean a few different things:
DocumentIdfor sync messagesm/ + DocumentIdfor ephemeral messagesa/ + TeamIdfor auth messages- constant
SYNC_CHANNEL- I don't think this is used?
message is a byte array containing the automerge sync message
broadcast boolean
- ephemeral messages are always broadcast
arrivemessages in a BroadcastChannelNetworkAdapter are broadcast
Note: arrive, welcome, and join message types are specific to various network adapters and should be defined locally in those packages.
class NetworkAdapter {
sendMessage(
peerId: PeerId, //
channelId: ChannelId,
message: Uint8Array,
broadcast: boolean
): void {}
}
// events & payloads
interface PeerCandidatePayload {
peerId: PeerId
channelId: ChannelId
}
interface MessagePayload {
targetId: PeerId
channelId: ChannelId
message: Uint8Array
broadcast: boolean
}
interface InboundMessagePayload extends MessagePayload {
type?: string
senderId: PeerId
}class NetworkSubsystem {
sendMessage(
peerId: PeerId, //
channelId: ChannelId,
message: Uint8Array,
broadcast: boolean
) {}
}
// events & payloads
interface PeerPayload {
peerId: PeerId
channelId: ChannelId
}// in #sendSyncMessage
this.emit('message', {
targetId: peerId,
channelId, // here the channelId represents the documentId
message,
broadcast: false,
})class EphemeralData {
broadcast(
channelId: ChannelId, //
message: unknown
) {
this.emit('message', {
targetId: '*' as PeerId, // TODO: we don't really need a targetId for broadcast
channelId: ('m/' + channelId) as ChannelId,
message: messageBytes,
broadcast: true,
})
}
receive(
senderId: PeerId, //
grossChannelId: ChannelId,
message: Uint8Array
) {
this.emit('data', {
peerId: senderId,
channelId,
data,
})
}
}
// WHAT IN GOD'S NAME
export interface EphemeralDataPayload {
channelId: ChannelId
peerId: PeerId
data: {
peerId: PeerId
channelId: ChannelId
data: unknown
}
}// not used anywhere
interface DocHandleMessagePayload {
destinationId: PeerId
channelId: ChannelId
data: Uint8Array
}class BroadcastChannelNetworkAdapter {
connect(peerId: PeerId) {
// ...
this.#broadcastChannel.postMessage({
senderId: this.peerId,
targetId: senderId,
type: 'welcome',
})
// ...
this.emit('message', {
senderId,
targetId,
channelId,
message: new Uint8Array(message),
broadcast,
})
}
sendMessage(peerId: PeerId, channelId: ChannelId, uint8message: Uint8Array, broadcast: boolean) {
const message = uint8message.buffer.slice(
uint8message.byteOffset,
uint8message.byteOffset + uint8message.byteLength
)
this.#broadcastChannel.postMessage({
senderId: this.peerId,
targetId: peerId,
type: 'message',
channelId,
message,
broadcast,
})
}
join(joinChannelId: ChannelId) {
this.#broadcastChannel.postMessage({
senderId: this.peerId,
channelId: joinChannelId,
type: 'arrive',
broadcast: true,
})
}
}