feat(attachments): expose fetchSource on preview and mesh retry
Add readAttachmentBytesWithSource so callers know whether bytes came from local staging, drive-local, protomux attach-mesh, or hyperdrive replication. readAttachmentPreview now returns fetchSource for UI and smokes. _fetchAttachMeshWithRetry mirrors banner prefetch (14s timeout + 600ms retry when attach sessions exist). Banner prefetch uses the same retry helper. Phase 60 / v0.8.25 — Pear attach preview mesh path. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -621,7 +621,7 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
const row = await this.attachments.get(attachmentId)
|
const row = await this.attachments.get(attachmentId)
|
||||||
if (row && this.attachments.hasLocalBytes(row)) return row
|
if (row && this.attachments.hasLocalBytes(row)) return row
|
||||||
if (!this.guild) return null
|
if (!this.guild) return null
|
||||||
const buf = await this.guild.fetchAttachmentFromPeers(attachmentId).catch(() => null)
|
const buf = await this._fetchAttachMeshWithRetry(attachmentId)
|
||||||
if (!buf) return null
|
if (!buf) return null
|
||||||
const meta = row || (await this.attachments.get(attachmentId))
|
const meta = row || (await this.attachments.get(attachmentId))
|
||||||
if (!meta) return null
|
if (!meta) return null
|
||||||
@@ -2124,21 +2124,33 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
async readAttachmentBytes (attachmentId) {
|
async _fetchAttachMeshWithRetry (attachmentId, timeoutMs = 14000) {
|
||||||
|
if (!this.guild) return null
|
||||||
|
let buf = await this.guild.fetchAttachmentFromPeers(attachmentId, timeoutMs).catch(() => null)
|
||||||
|
if (buf?.length) return buf
|
||||||
|
if (!(this.guild._attachChannels?.size > 0)) return null
|
||||||
|
await new Promise((r) => setTimeout(r, 600))
|
||||||
|
return this.guild.fetchAttachmentFromPeers(attachmentId, timeoutMs).catch(() => null)
|
||||||
|
}
|
||||||
|
|
||||||
|
async readAttachmentBytesWithSource (attachmentId) {
|
||||||
const row = await this.attachments?.get(attachmentId)
|
const row = await this.attachments?.get(attachmentId)
|
||||||
if (!row) throw new Error('attachment not found')
|
if (!row) throw new Error('attachment not found')
|
||||||
if (this.attachments.hasLocalBytes(row)) {
|
if (this.attachments.hasLocalBytes(row)) {
|
||||||
return this.attachments.readBytes(row)
|
return { buf: await this.attachments.readBytes(row), source: 'local' }
|
||||||
}
|
}
|
||||||
const drive = getGuildDrive(this.storagePath, row.guildId)
|
const drive = getGuildDrive(this.storagePath, row.guildId)
|
||||||
const localDrive = await drive.get(row.id, row.filename, row.drivePath)
|
const localDrive = await drive.get(row.id, row.filename, row.drivePath)
|
||||||
if (localDrive?.length) return localDrive
|
if (localDrive?.length) {
|
||||||
|
return { buf: localDrive, source: 'drive-local' }
|
||||||
let buf = null
|
|
||||||
if (this.guild) {
|
|
||||||
buf = await this.guild.fetchAttachmentFromPeers(attachmentId).catch(() => null)
|
|
||||||
}
|
}
|
||||||
if (!buf && isHexDriveKey(row.driveKey) && (this.guild?.peers?.size || 0) > 0) {
|
|
||||||
|
let buf = await this._fetchAttachMeshWithRetry(attachmentId)
|
||||||
|
if (buf?.length) {
|
||||||
|
await this.attachments.persistFetched(row, buf)
|
||||||
|
return { buf, source: 'attach-mesh' }
|
||||||
|
}
|
||||||
|
if (isHexDriveKey(row.driveKey) && (this.guild?.peers?.size || 0) > 0) {
|
||||||
buf = await drive.fetchRemote({
|
buf = await drive.fetchRemote({
|
||||||
driveKey: row.driveKey,
|
driveKey: row.driveKey,
|
||||||
drivePath: row.drivePath,
|
drivePath: row.drivePath,
|
||||||
@@ -2147,9 +2159,16 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
swarm: this.guild?.swarm,
|
swarm: this.guild?.swarm,
|
||||||
timeoutMs: 8000
|
timeoutMs: 8000
|
||||||
})
|
})
|
||||||
|
if (buf?.length) {
|
||||||
|
await this.attachments.persistFetched(row, buf)
|
||||||
|
return { buf, source: 'hyperdrive' }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!buf) throw new Error('attachment file missing')
|
throw new Error('attachment file missing')
|
||||||
await this.attachments.persistFetched(row, buf)
|
}
|
||||||
|
|
||||||
|
async readAttachmentBytes (attachmentId) {
|
||||||
|
const { buf } = await this.readAttachmentBytesWithSource(attachmentId)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2159,12 +2178,13 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
if (!String(row.mimeType || '').startsWith('image/')) {
|
if (!String(row.mimeType || '').startsWith('image/')) {
|
||||||
throw new Error('preview only for images')
|
throw new Error('preview only for images')
|
||||||
}
|
}
|
||||||
const buf = await this.readAttachmentBytes(attachmentId)
|
const { buf, source } = await this.readAttachmentBytesWithSource(attachmentId)
|
||||||
return {
|
return {
|
||||||
attachmentId: row.id,
|
attachmentId: row.id,
|
||||||
mimeType: row.mimeType,
|
mimeType: row.mimeType,
|
||||||
filename: row.filename,
|
filename: row.filename,
|
||||||
dataBase64: b4a.toString(buf, 'base64')
|
dataBase64: b4a.toString(buf, 'base64'),
|
||||||
|
fetchSource: source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user