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)
|
||||
if (row && this.attachments.hasLocalBytes(row)) return row
|
||||
if (!this.guild) return null
|
||||
const buf = await this.guild.fetchAttachmentFromPeers(attachmentId).catch(() => null)
|
||||
const buf = await this._fetchAttachMeshWithRetry(attachmentId)
|
||||
if (!buf) return null
|
||||
const meta = row || (await this.attachments.get(attachmentId))
|
||||
if (!meta) return null
|
||||
@@ -2124,21 +2124,33 @@ class PearcordPlatform extends EventEmitter {
|
||||
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)
|
||||
if (!row) throw new Error('attachment not found')
|
||||
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 localDrive = await drive.get(row.id, row.filename, row.drivePath)
|
||||
if (localDrive?.length) return localDrive
|
||||
|
||||
let buf = null
|
||||
if (this.guild) {
|
||||
buf = await this.guild.fetchAttachmentFromPeers(attachmentId).catch(() => null)
|
||||
if (localDrive?.length) {
|
||||
return { buf: localDrive, source: 'drive-local' }
|
||||
}
|
||||
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({
|
||||
driveKey: row.driveKey,
|
||||
drivePath: row.drivePath,
|
||||
@@ -2147,9 +2159,16 @@ class PearcordPlatform extends EventEmitter {
|
||||
swarm: this.guild?.swarm,
|
||||
timeoutMs: 8000
|
||||
})
|
||||
if (buf?.length) {
|
||||
await this.attachments.persistFetched(row, buf)
|
||||
return { buf, source: 'hyperdrive' }
|
||||
}
|
||||
}
|
||||
if (!buf) throw new Error('attachment file missing')
|
||||
await this.attachments.persistFetched(row, buf)
|
||||
throw new Error('attachment file missing')
|
||||
}
|
||||
|
||||
async readAttachmentBytes (attachmentId) {
|
||||
const { buf } = await this.readAttachmentBytesWithSource(attachmentId)
|
||||
return buf
|
||||
}
|
||||
|
||||
@@ -2159,12 +2178,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (!String(row.mimeType || '').startsWith('image/')) {
|
||||
throw new Error('preview only for images')
|
||||
}
|
||||
const buf = await this.readAttachmentBytes(attachmentId)
|
||||
const { buf, source } = await this.readAttachmentBytesWithSource(attachmentId)
|
||||
return {
|
||||
attachmentId: row.id,
|
||||
mimeType: row.mimeType,
|
||||
filename: row.filename,
|
||||
dataBase64: b4a.toString(buf, 'base64')
|
||||
dataBase64: b4a.toString(buf, 'base64'),
|
||||
fetchSource: source
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user