| … | … | @@ -249,16 +249,27 @@ export class Router { |
| 249 | 249 | } else if (generic) { |
| 250 | 250 | system = generic |
| 251 | 251 | } |
| 252 | | // Extract file attachments |
| 253 | | const rawFiles = msg.message?.files || [] |
| 254 | | const files = Array.isArray(rawFiles) ? rawFiles.map(f => ({ |
| 255 | | id: f.pointer?.externalBlob?.id || null, |
| 256 | | name: f.name || f.fileName || 'file', |
| 257 | | type: f.mimeType || '', |
| 258 | | size: f.size || 0, |
| 259 | | dimensions: f.dimensions || null, |
| 260 | | httpLink: f.httpLink || '' |
| 261 | | })) : [] |
| 252 | // Extract file attachments (encoded file structure from keet-core API) |
| 253 | // Encoded files have: metadata.{name,mimetype,size,dimensions}, entry.{httpLink, preview.small.httpLink}, |
| 254 | // pointer.externalBlob.id (z32 key). Raw files have: name, mimeType, size at top level. |
| 255 | const rawFiles = msg.message?.files || msg.files || [] |
| 256 | const files = Array.isArray(rawFiles) ? rawFiles.map(f => { |
| 257 | const meta = f.metadata || {} |
| 258 | const entry = f.entry || {} |
| 259 | const name = meta.name || f.name || f.fileName || 'file' |
| 260 | return { |
| 261 | id: name, // Use filename as canonical ID (most reliable across encoded/raw formats) |
| 262 | name, |
| 263 | type: meta.mimetype || f.mimeType || '', |
| 264 | size: meta.size || f.size || 0, |
| 265 | dimensions: meta.dimensions || f.dimensions || null, |
| 266 | httpLink: entry.httpLink || f.httpLink || '', |
| 267 | preview: entry.preview ? { |
| 268 | small: entry.preview.small?.httpLink || '', |
| 269 | medium: entry.preview.medium?.httpLink || '' |
| 270 | } : null |
| 271 | } |
| 272 | }) : [] |
| 262 | 273 | |
| 263 | 274 | return { |
| 264 | 275 | memberId, |
| … | … | @@ -776,16 +787,33 @@ export class Router { |
| 776 | 787 | const files = await this.backend.api.core.getLocalFiles(params.roomId) |
| 777 | 788 | const entries = Array.isArray(files) ? files : (files?.data || files?.entries || []) |
| 778 | 789 | |
| 779 | | // Match file by blob ID — handle Buffer vs string comparison |
| 790 | console.log('[keet-daemon] file.preview: looking for "%s" among %d local files', params.fileId, entries.length) |
| 791 | if (entries.length > 0) { |
| 792 | const sample = entries[0] |
| 793 | const sObj = sample.file || sample |
| 794 | console.log('[keet-daemon] sample entry keys:', Object.keys(sObj).join(','), |
| 795 | 'metadata.name:', sObj?.metadata?.name, |
| 796 | 'pointer.externalBlob:', sObj?.pointer?.externalBlob ? 'yes' : 'no') |
| 797 | } |
| 798 | |
| 799 | // Match file by FILENAME (primary) or blob ID (fallback) |
| 780 | 800 | const targetId = String(params.fileId) |
| 781 | 801 | const entry = entries.find(f => { |
| 782 | 802 | const fileObj = f.file || f |
| 803 | // Try filename match first (most reliable — Godot sends filename as fileId) |
| 804 | const name = fileObj?.metadata?.name || '' |
| 805 | if (name && name === targetId) return true |
| 806 | // Fallback: match by blob ID (z32 or hex) |
| 783 | 807 | const blobId = fileObj?.pointer?.externalBlob?.id |
| 784 | 808 | if (!blobId) return false |
| 785 | 809 | const idStr = Buffer.isBuffer(blobId) ? blobId.toString('hex') : String(blobId) |
| 786 | 810 | return idStr === targetId |
| 787 | 811 | }) |
| 788 | | if (!entry) throw new Error('File not found: ' + params.fileId) |
| 812 | |
| 813 | if (!entry) { |
| 814 | const names = entries.slice(0, 5).map(f => (f.file || f)?.metadata?.name || '?').join(', ') |
| 815 | throw new Error('File not found: ' + params.fileId + ' (have: ' + names + ')') |
| 816 | } |
| 789 | 817 | |
| 790 | 818 | // Generate httpLink using FileManager's blob server |
| 791 | 819 | const fileObj = entry.file || entry |
| … | … | @@ -796,13 +824,14 @@ export class Router { |
| 796 | 824 | console.error('[keet-daemon] getFileLink error:', err.message) |
| 797 | 825 | } |
| 798 | 826 | |
| 827 | console.log('[keet-daemon] file.preview: found "%s" -> httpLink=%s', params.fileId, (httpLink || '').slice(0, 80)) |
| 828 | |
| 799 | 829 | const meta = fileObj?.metadata || {} |
| 800 | 830 | return { |
| 801 | 831 | name: meta.name || 'file', |
| 802 | 832 | type: meta.mimetype || '', |
| 803 | 833 | size: meta.size || 0, |
| 804 | 834 | httpLink, |
| 805 | | fullHttpLink: httpLink, |
| 806 | 835 | dimensions: meta.dimensions || null |
| 807 | 836 | } |
| 808 | 837 | } |