fix(p2p): author profiles on messages, DM users map, and download export

Gossip profile on every send, bundle author and attachmentMetas on messages,
build DM usersById from contacts, and export attachments via download-cache
before IPC to avoid stuck downloads.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-25 00:17:48 -04:00
co-authored by Cursor
parent 3dd4393487
commit bfcc944847
+133 -15
View File
@@ -875,17 +875,22 @@ class PearcordPlatform extends EventEmitter {
this.attachments?.ingestGossip(p).catch(() => {})
this.emit('attachment', p)
})
dmInstance.on('user', (u) => {
void this._ingestUserProfile(u).catch(() => {})
})
dmInstance.setMessageHandler(async (msg) => {
const existing = await this.db.get(COLLECTIONS.MESSAGES, {
channelId: msg.channelId,
id: msg.id
})
if (existing) return existing
await this.db.insert(COLLECTIONS.MESSAGES, msg)
const plain = this._messagePlaintext(msg)
await dmInstance.touchLastMessage(msg.channelId, { ...msg, content: plain })
await this._ingestMessageGossipExtras(msg)
const row = this._messageRowForStore(msg)
await this.db.insert(COLLECTIONS.MESSAGES, row)
const plain = this._messagePlaintext(row)
await dmInstance.touchLastMessage(row.channelId, { ...row, content: plain })
await this._maybeNotify({
message: { ...msg, content: plain },
message: { ...row, content: plain },
mode: 'dm',
guildId: null,
guildName: null,
@@ -895,8 +900,8 @@ class PearcordPlatform extends EventEmitter {
members: [],
usersById: {}
})
this.emit('message', msg)
return msg
this.emit('message', row)
return row
})
dmInstance.on('message', (msg) => this.emit('message', msg))
dmInstance.on('message-delete', (p) => this.emit('message-delete', p))
@@ -3373,7 +3378,8 @@ class PearcordPlatform extends EventEmitter {
_wireGuild (guildInstance) {
this._ingestInboundGuildMessage = async (msg) => {
const row = enrichMessageRow(msg)
await this._ingestMessageGossipExtras(msg)
const row = enrichMessageRow(this._messageRowForStore(msg))
const existing = await this.db.get(COLLECTIONS.MESSAGES, {
channelId: row.channelId,
id: row.id
@@ -3830,6 +3836,8 @@ class PearcordPlatform extends EventEmitter {
async _collectUsersForSync (members) {
const byId = new Map()
const self = this._userProfileForSync(this.identity?.user)
if (self) byId.set(self.id, self)
for (const mem of members || []) {
if (!mem?.userId) continue
const u = await this.db.get(COLLECTIONS.USERS, { id: mem.userId })
@@ -3861,10 +3869,79 @@ class PearcordPlatform extends EventEmitter {
return out
}
_activeDmMesh () {
return this.dm || this._dmBg || null
}
_gossipSelfUserProfile () {
const row = this._userProfileForSync(this.identity?.user)
if (!row || !this.guild) return
this.guild.gossipUserUpsert(row)
if (!row) return
if (this.guild) this.guild.gossipUserUpsert(row)
const dm = this._activeDmMesh()
if (dm?.gossipUserUpsert) dm.gossipUserUpsert(row)
}
_enrichOutboundMessage (msg, { attachmentMetas } = {}) {
const out = { ...msg }
const author = this._userProfileForSync(this.identity?.user)
if (author) out.author = author
if (attachmentMetas?.length) out.attachmentMetas = attachmentMetas
return out
}
async _ingestMessageGossipExtras (msg) {
if (msg?.author?.id) await this._ingestUserProfile(msg.author)
if (msg?.attachmentMetas?.length && this.attachments) {
for (const att of msg.attachmentMetas) {
await this.attachments.ingestGossip(att).catch(() => {})
}
this.emit('attachment', msg.attachmentMetas[msg.attachmentMetas.length - 1])
}
}
_messageRowForStore (msg) {
if (!msg) return msg
const { author, attachmentMetas, ...row } = msg
return row
}
async _buildDmUsersById (messages = [], dmConversations = []) {
const map = {}
const self = this.identity?.user
if (self?.id) map[self.id] = self
if (this.contacts) {
const rows = await this.contacts.listAccepted().catch(() => [])
for (const c of rows) {
if (!c?.peerUserId) continue
map[c.peerUserId] = {
id: c.peerUserId,
username: c.peerUsername || null,
displayName: c.peerDisplayName || c.peerUsername || null
}
}
}
for (const dm of dmConversations || []) {
const peer = dm.peerUserId
if (!peer) continue
const label = dm.name || dm.peerDisplayName
if (label && !map[peer]?.displayName && !map[peer]?.username) {
map[peer] = { id: peer, username: label, displayName: label }
}
}
const peer = this._dmPeerId()
if (peer && this.dm?.channel?.name && !map[peer]) {
map[peer] = {
id: peer,
username: this.dm.channel.name,
displayName: this.dm.channel.name
}
}
for (const m of messages || []) {
if (!m?.authorId || map[m.authorId]) continue
const u = await this.db.get(COLLECTIONS.USERS, { id: m.authorId }).catch(() => null)
if (u) map[m.authorId] = u
}
return map
}
_gossipGuildPresenceSnapshot () {
@@ -8861,6 +8938,28 @@ class PearcordPlatform extends EventEmitter {
return buf
}
/**
* Persist attachment bytes under storage for UI download / open-in-folder flows.
*/
async exportAttachmentForDownload (attachmentId) {
const row = await this.attachments?.get(attachmentId)
if (!row) throw new Error('attachment not found')
const { buf } = await this.readAttachmentBytesWithSource(attachmentId)
if (!buf?.length) throw new Error('attachment file empty')
const fs = require('bare-fs')
const dir = path.join(this.storagePath, 'download-cache')
fs.mkdirSync(dir, { recursive: true })
const safe = String(row.filename || 'file').replace(/[/\\]/g, '_').slice(0, 120) || 'file'
const filePath = path.join(dir, `${row.id}-${safe}`)
fs.writeFileSync(filePath, buf)
return {
filePath,
filename: row.filename || safe,
mimeType: row.mimeType || 'application/octet-stream',
size: buf.length
}
}
async readAttachmentPreview (attachmentId) {
const guildId = this.mode === 'dm' ? DM_GUILD_ID : this.guild?.guild?.id || null
const channelId = this.activeChannelId
@@ -11878,9 +11977,16 @@ class PearcordPlatform extends EventEmitter {
const row = await this.attachments.linkMessage(aid, msg.id)
linked.push(row)
if (this.guild) this.guild.gossipAttachmentMeta(row)
else if (this.dm) this.dm.gossipAttachmentMeta(row)
else {
const dm = this._activeDmMesh()
if (dm?.gossipAttachmentMeta) dm.gossipAttachmentMeta(row)
}
}
}
this._gossipSelfUserProfile()
const gossipMsg = this._enrichOutboundMessage(msg, {
attachmentMetas: linked.length ? linked : undefined
})
await this._recordSlowmodeSend()
if (this.mode === 'guild' && this.guild) {
const members = await this.guild.listMembers()
@@ -11902,11 +12008,16 @@ class PearcordPlatform extends EventEmitter {
})
}
}
if (this.mode === 'dm' && this.dm) {
await this.dm.touchLastMessage(msg.channelId, { ...msg, content })
this.dm.gossipMessage(msg)
if (this.mode === 'dm') {
const dm = this._activeDmMesh()
if (dm) {
const previewPlain =
this._messagePlaintext(msg) || (linked.length ? '📎 Attachment' : '')
await dm.touchLastMessage(msg.channelId, { ...msg, content: previewPlain })
dm.gossipMessage(gossipMsg)
}
} else if (this.guild) {
this.guild.gossipMessage(msg)
this.guild.gossipMessage(gossipMsg)
this._queueLinkEmbed(msg).catch(() => {})
this._fanoutBotEvent(BOT_EVENTS.MESSAGE_CREATE, { message: msg })
if (this.mode === 'guild') {
@@ -13740,8 +13851,15 @@ class PearcordPlatform extends EventEmitter {
if (rows.length) attachmentsByMessage[m.id] = rows
}
}
const usersById =
let usersById =
guild && members.length ? await this._usersById(members) : {}
if (user?.id) usersById = { ...usersById, [user.id]: user }
if (this.mode === 'dm') {
usersById = {
...usersById,
...(await this._buildDmUsersById(messages, dmConversations))
}
}
const memberTimeouts = {}
let communicationDisabled = false
if (guild && this.moderation) {