feat(settings): mux-wire user prefs mesh and composeDrafts default
USER_PREFS gossip uses pearcord-drive wire channels; composeDrafts sync for companion/desktop draft continuity; manageListeners flag for shared swarm. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -23,7 +23,8 @@ const DEFAULT_USER_PREFS = {
|
||||
showLinkPreviews: true,
|
||||
showSecondsInTimestamps: false,
|
||||
blurSpoilers: true,
|
||||
auditLogExportFilter: 'all'
|
||||
auditLogExportFilter: 'all',
|
||||
composeDrafts: {}
|
||||
}
|
||||
|
||||
class PearcordSettings extends EventEmitter {
|
||||
@@ -134,24 +135,26 @@ class PearcordSettings extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async joinMesh (swarm, { deviceId } = {}) {
|
||||
async joinMesh (swarm, { deviceId, manageListeners = true } = {}) {
|
||||
if (!swarm) throw new Error('swarm required')
|
||||
if (!this.userId) throw new Error('userId required')
|
||||
if (this._meshJoined && this.swarm === swarm) return this
|
||||
await this.leaveMesh().catch(() => {})
|
||||
await this.leaveMesh({ manageListeners }).catch(() => {})
|
||||
this.deviceId = deviceId || null
|
||||
this.swarm = swarm
|
||||
this.swarm.removeAllListeners('connection')
|
||||
this.swarm.on('connection', (conn) => {
|
||||
const peerId = b4a.toString(conn.remotePublicKey, 'hex')
|
||||
const ch = attachUserPrefsMesh(this, conn)
|
||||
this._channels.set(peerId, ch)
|
||||
this.emit('peer', { peerId, type: 'join' })
|
||||
conn.on('close', () => {
|
||||
this._channels.delete(peerId)
|
||||
this.emit('peer', { peerId, type: 'leave' })
|
||||
if (manageListeners) {
|
||||
this.swarm.removeAllListeners('connection')
|
||||
this.swarm.on('connection', (conn) => {
|
||||
const peerId = b4a.toString(conn.remotePublicKey, 'hex')
|
||||
const ch = attachUserPrefsMesh(this, conn)
|
||||
this._channels.set(peerId, ch)
|
||||
this.emit('peer', { peerId, type: 'join' })
|
||||
conn.on('close', () => {
|
||||
this._channels.delete(peerId)
|
||||
this.emit('peer', { peerId, type: 'leave' })
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
await this.swarm.join(topicToBuffer(userPrefsTopic(this.userId)), {
|
||||
server: true,
|
||||
client: true
|
||||
@@ -160,13 +163,13 @@ class PearcordSettings extends EventEmitter {
|
||||
return this
|
||||
}
|
||||
|
||||
async leaveMesh () {
|
||||
async leaveMesh ({ manageListeners = true } = {}) {
|
||||
this._channels.clear()
|
||||
this._meshJoined = false
|
||||
if (this.swarm && this.userId) {
|
||||
await this.swarm.leave(topicToBuffer(userPrefsTopic(this.userId))).catch(() => {})
|
||||
}
|
||||
if (this.swarm) this.swarm.removeAllListeners('connection')
|
||||
if (this.swarm && manageListeners) this.swarm.removeAllListeners('connection')
|
||||
this.swarm = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,15 @@
|
||||
const Protomux = require('protomux')
|
||||
const b4a = require('b4a')
|
||||
const { encodeRpc, decodeRpc } = require('pearcord-shared')
|
||||
const { openWireChannel, wireReady } = require('pearcord-drive/mux-wire')
|
||||
|
||||
const USER_PREFS_PROTOCOL = 'pearcord-userprefs-v1'
|
||||
|
||||
function attachUserPrefsMesh (settings, conn) {
|
||||
const mux = Protomux.from(conn)
|
||||
const channel = mux.createChannel({
|
||||
return openWireChannel(mux, {
|
||||
protocol: USER_PREFS_PROTOCOL,
|
||||
onopen () {
|
||||
channel.open()
|
||||
},
|
||||
onmessage (buf) {
|
||||
ondata (buf) {
|
||||
let packet
|
||||
try {
|
||||
packet = decodeRpc(buf)
|
||||
@@ -24,21 +22,22 @@ function attachUserPrefsMesh (settings, conn) {
|
||||
}
|
||||
}
|
||||
})
|
||||
return channel
|
||||
}
|
||||
|
||||
function broadcastUserPrefsGossip (settings, method, payload) {
|
||||
async function broadcastUserPrefsGossip (settings, method, payload) {
|
||||
const buf = encodeRpc(method, b4a.from(JSON.stringify(payload)))
|
||||
for (const ch of settings._channels.values()) {
|
||||
ch.fullyOpened().then((ok) => {
|
||||
if (!ok) return
|
||||
const sessions = [...settings._channels.values()]
|
||||
await Promise.all(
|
||||
sessions.map(async (session) => {
|
||||
try {
|
||||
ch.send(buf)
|
||||
const ok = await wireReady(session, 6000)
|
||||
if (!ok) return
|
||||
session.send(buf)
|
||||
} catch {
|
||||
// peer gone
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = { attachUserPrefsMesh, broadcastUserPrefsGossip, USER_PREFS_PROTOCOL }
|
||||
|
||||
+7
-2
@@ -5,8 +5,13 @@
|
||||
"type": "commonjs",
|
||||
"description": "P2P user appearance and UX prefs sync for Pearcord",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.8.0",
|
||||
"bare-path": "^3.0.0",
|
||||
"pearcord-db": "git+https://git.ssh.surf/pearcord/pearcord-db.git#main",
|
||||
"pearcord-shared": "git+https://git.ssh.surf/pearcord/pearcord-shared.git#main"
|
||||
"b4a": "^1.6.7",
|
||||
"hyperswarm": "^4.8.0",
|
||||
"protomux": "^3.0.0",
|
||||
"pearcord-db": "file:../pearcord-db",
|
||||
"pearcord-drive": "file:../pearcord-drive",
|
||||
"pearcord-shared": "file:../pearcord-shared"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user