fix(contacts): improve friend requests and relay DM channel invites

Use server+client ephemeral joins with longer flush for CONTACT_REQUEST
delivery. Forward DM_CHANNEL_UPSERT to peers on the contacts mesh.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-24 23:55:23 -04:00
co-authored by Cursor
parent de66cdd593
commit 2a8b857162
2 changed files with 22 additions and 4 deletions
+20 -3
View File
@@ -110,6 +110,12 @@ class PearcordContacts extends EventEmitter {
return row return row
} }
async sendDmChannelInvite (peerUserId, channel) {
if (!peerUserId || !channel?.id) return null
await this._gossipToPeer(peerUserId, RPC.DM_CHANNEL_UPSERT, channel)
return channel
}
async acceptRequest (peerUserId) { async acceptRequest (peerUserId) {
const row = await this.get(peerUserId) const row = await this.get(peerUserId)
if (!row || row.status !== CONTACT_STATUS.PENDING_IN) { if (!row || row.status !== CONTACT_STATUS.PENDING_IN) {
@@ -231,6 +237,7 @@ class PearcordContacts extends EventEmitter {
id: blocked?.id || id(), id: blocked?.id || id(),
ownerId: this.userId, ownerId: this.userId,
peerUserId: from, peerUserId: from,
peerUsername: payload.fromUsername || null,
peerDisplayName: payload.fromDisplayName || payload.fromUsername || from.slice(0, 8), peerDisplayName: payload.fromDisplayName || payload.fromUsername || from.slice(0, 8),
status: mutual ? CONTACT_STATUS.ACCEPTED : CONTACT_STATUS.PENDING_IN, status: mutual ? CONTACT_STATUS.ACCEPTED : CONTACT_STATUS.PENDING_IN,
requestedAt: payload.at || now(), requestedAt: payload.at || now(),
@@ -343,6 +350,10 @@ class PearcordContacts extends EventEmitter {
this.emit('profile-cosmetic', payload) this.emit('profile-cosmetic', payload)
return return
} }
if (method === RPC.DM_CHANNEL_UPSERT) {
this.emit('dm-channel', payload)
return
}
if (method === RPC.CONTACT_REQUEST) { if (method === RPC.CONTACT_REQUEST) {
this.ingestRequest(payload).catch(() => {}) this.ingestRequest(payload).catch(() => {})
} else if (method === RPC.CONTACT_ACCEPT) { } else if (method === RPC.CONTACT_ACCEPT) {
@@ -359,6 +370,10 @@ class PearcordContacts extends EventEmitter {
} }
async simulateGossip (method, payload) { async simulateGossip (method, payload) {
if (method === RPC.DM_CHANNEL_UPSERT) {
this.emit('dm-channel', payload)
return payload
}
if (method === RPC.PRESENCE_UPDATE) return this.ingestFriendPresence(payload) if (method === RPC.PRESENCE_UPDATE) return this.ingestFriendPresence(payload)
if (method === RPC.PROFILE_COSMETIC_UPDATE) { if (method === RPC.PROFILE_COSMETIC_UPDATE) {
this.emit('profile-cosmetic', payload) this.emit('profile-cosmetic', payload)
@@ -413,13 +428,15 @@ class PearcordContacts extends EventEmitter {
const persistent = this._friendTopics.has(topic) const persistent = this._friendTopics.has(topic)
const wasEphemeral = this._ephemeralTopics.has(topic) const wasEphemeral = this._ephemeralTopics.has(topic)
if (!persistent && !wasEphemeral) { if (!persistent && !wasEphemeral) {
await this.swarm.join(buf, { server: false, client: true }) await this.swarm.join(buf, { server: true, client: true })
this._ephemeralTopics.add(topic) this._ephemeralTopics.add(topic)
} }
await this._flushSwarm() await this._flushSwarm(6000)
await broadcastContactsGossip(this, method, payload) await broadcastContactsGossip(this, method, payload)
if (!persistent && !wasEphemeral) { if (!persistent && !wasEphemeral) {
await new Promise((r) => setTimeout(r, 350)) await new Promise((r) => setTimeout(r, 1200))
await broadcastContactsGossip(this, method, payload).catch(() => {})
await new Promise((r) => setTimeout(r, 400))
await this.swarm.leave(buf).catch(() => {}) await this.swarm.leave(buf).catch(() => {})
this._ephemeralTopics.delete(topic) this._ephemeralTopics.delete(topic)
} }
+2 -1
View File
@@ -2,12 +2,13 @@
const Protomux = require('protomux') const Protomux = require('protomux')
const b4a = require('b4a') const b4a = require('b4a')
const { encodeRpc, decodeRpc } = require('pearcord-shared') const { encodeRpc, decodeRpc, wireSwarmConnection } = require('pearcord-shared')
const { openWireChannel, wireReady } = require('pearcord-drive/mux-wire') const { openWireChannel, wireReady } = require('pearcord-drive/mux-wire')
const CONTACTS_PROTOCOL = 'pearcord-contacts-v1' const CONTACTS_PROTOCOL = 'pearcord-contacts-v1'
function attachContactsMesh (contacts, conn) { function attachContactsMesh (contacts, conn) {
wireSwarmConnection(conn)
const mux = Protomux.from(conn) const mux = Protomux.from(conn)
return openWireChannel(mux, { return openWireChannel(mux, {
protocol: CONTACTS_PROTOCOL, protocol: CONTACTS_PROTOCOL,