199 lines
5.3 KiB
JavaScript
199 lines
5.3 KiB
JavaScript
import c from 'compact-encoding'
|
|
|
|
/** Wire schema for payload records inside message `event` (uint8 in frame). */
|
|
export const BARE_OS_CHAT_WIRE_SCHEMA_VERSION = 1
|
|
|
|
/** Event kinds for `evtKind`. */
|
|
export const BARE_OS_CHAT_EVT_TEXT = 1
|
|
export const BARE_OS_CHAT_EVT_PRESENCE = 2
|
|
|
|
/**
|
|
* @param {number} len
|
|
*/
|
|
function fixedBuffer(len) {
|
|
return {
|
|
preencode(state, m) {
|
|
void m
|
|
state.end += len
|
|
},
|
|
encode(state, m) {
|
|
const b =
|
|
m instanceof Uint8Array ? m : /** @type {Uint8Array} */ (new Uint8Array(m))
|
|
if (b.byteLength !== len) {
|
|
throw new Error(`fixed buffer: expected ${len} bytes`)
|
|
}
|
|
state.buffer.set(b, state.start)
|
|
state.start += len
|
|
},
|
|
decode(state) {
|
|
const out = state.buffer.subarray(state.start, state.start + len)
|
|
state.start += len
|
|
return out
|
|
}
|
|
}
|
|
}
|
|
|
|
const buf16 = fixedBuffer(16)
|
|
const buf32 = fixedBuffer(32)
|
|
|
|
/** Message 0: hello — version + chat capability flag. */
|
|
export const msgChatHelloEncoding = {
|
|
preencode(state, m) {
|
|
c.uint16.preencode(state, m.chatSchemaVersion)
|
|
c.bool.preencode(state, m.swarmChatCapability)
|
|
},
|
|
encode(state, m) {
|
|
c.uint16.encode(state, m.chatSchemaVersion)
|
|
c.bool.encode(state, !!m.swarmChatCapability)
|
|
},
|
|
decode(state) {
|
|
return {
|
|
chatSchemaVersion: c.uint16.decode(state),
|
|
swarmChatCapability: c.bool.decode(state)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Message 1: helloAck — negotiated limits. */
|
|
export const msgChatHelloAckEncoding = {
|
|
preencode(state, m) {
|
|
c.uint16.preencode(state, m.chatSchemaVersion)
|
|
c.uint32.preencode(state, m.maxPayloadBytes)
|
|
},
|
|
encode(state, m) {
|
|
c.uint16.encode(state, m.chatSchemaVersion)
|
|
c.uint32.encode(state, m.maxPayloadBytes >>> 0)
|
|
},
|
|
decode(state) {
|
|
return {
|
|
chatSchemaVersion: c.uint16.decode(state),
|
|
maxPayloadBytes: c.uint32.decode(state)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Message 2: join room. */
|
|
export const msgChatJoinEncoding = {
|
|
preencode(state, m) {
|
|
c.string.preencode(state, m.roomId)
|
|
c.string.preencode(state, m.displayName)
|
|
buf32.preencode(state, m.senderPk)
|
|
buf16.preencode(state, m.clientInstanceId)
|
|
},
|
|
encode(state, m) {
|
|
c.string.encode(state, m.roomId)
|
|
c.string.encode(state, m.displayName)
|
|
buf32.encode(state, m.senderPk)
|
|
buf16.encode(state, m.clientInstanceId)
|
|
},
|
|
decode(state) {
|
|
return {
|
|
roomId: c.string.decode(state),
|
|
displayName: c.string.decode(state),
|
|
senderPk: buf32.decode(state),
|
|
clientInstanceId: buf16.decode(state)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Message 3: leave room. */
|
|
export const msgChatLeaveEncoding = {
|
|
preencode(state, m) {
|
|
c.string.preencode(state, m.roomId)
|
|
},
|
|
encode(state, m) {
|
|
c.string.encode(state, m.roomId)
|
|
},
|
|
decode(state) {
|
|
return { roomId: c.string.decode(state) }
|
|
}
|
|
}
|
|
|
|
/** Optional detached signature (Ed25519, length-prefixed buffer). */
|
|
const optionalSigEncoding = {
|
|
preencode(state, m) {
|
|
const has = !!(m.sigDetached && m.sigDetached.byteLength > 0)
|
|
c.bool.preencode(state, has)
|
|
if (has) c.buffer.preencode(state, m.sigDetached)
|
|
},
|
|
encode(state, m) {
|
|
const has = !!(m.sigDetached && m.sigDetached.byteLength > 0)
|
|
c.bool.encode(state, has)
|
|
if (has) c.buffer.encode(state, m.sigDetached)
|
|
},
|
|
decode(state) {
|
|
const has = c.bool.decode(state)
|
|
return has ? c.buffer.decode(state) : null
|
|
}
|
|
}
|
|
|
|
/** Message 4: chat event (text, presence, gossip relay). */
|
|
export const msgChatEventEncoding = {
|
|
preencode(state, m) {
|
|
c.uint8.preencode(state, m.schemaVersion)
|
|
c.uint8.preencode(state, m.evtKind)
|
|
c.string.preencode(state, m.roomId)
|
|
buf16.preencode(state, m.evtId)
|
|
c.uint.preencode(state, m.tsMs)
|
|
buf32.preencode(state, m.senderPk)
|
|
c.string.preencode(state, m.displayName)
|
|
c.string.preencode(state, m.body)
|
|
c.uint8.preencode(state, m.ttl)
|
|
optionalSigEncoding.preencode(state, m)
|
|
},
|
|
encode(state, m) {
|
|
c.uint8.encode(state, m.schemaVersion)
|
|
c.uint8.encode(state, m.evtKind)
|
|
c.string.encode(state, m.roomId)
|
|
buf16.encode(state, m.evtId)
|
|
c.uint.encode(state, m.tsMs)
|
|
buf32.encode(state, m.senderPk)
|
|
c.string.encode(state, m.displayName)
|
|
c.string.encode(state, m.body)
|
|
c.uint8.encode(state, m.ttl)
|
|
optionalSigEncoding.encode(state, m)
|
|
},
|
|
decode(state) {
|
|
const schemaVersion = c.uint8.decode(state)
|
|
const evtKind = c.uint8.decode(state)
|
|
const roomId = c.string.decode(state)
|
|
const evtId = buf16.decode(state)
|
|
const tsMs = c.uint.decode(state)
|
|
const senderPk = buf32.decode(state)
|
|
const displayName = c.string.decode(state)
|
|
const body = c.string.decode(state)
|
|
const ttl = c.uint8.decode(state)
|
|
const sigDetached = optionalSigEncoding.decode(state)
|
|
return {
|
|
schemaVersion,
|
|
evtKind,
|
|
roomId,
|
|
evtId,
|
|
tsMs,
|
|
senderPk,
|
|
displayName,
|
|
body,
|
|
ttl,
|
|
sigDetached
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Message 5: control stub (room list later). */
|
|
export const msgChatControlEncoding = {
|
|
preencode(state, m) {
|
|
c.string.preencode(state, m.op)
|
|
c.string.preencode(state, m.payloadJson)
|
|
},
|
|
encode(state, m) {
|
|
c.string.encode(state, m.op)
|
|
c.string.encode(state, m.payloadJson || '')
|
|
},
|
|
decode(state) {
|
|
return {
|
|
op: c.string.decode(state),
|
|
payloadJson: c.string.decode(state)
|
|
}
|
|
}
|
|
}
|