fix: Bug - Sending files and attachment issues

Hydrate playable media after disk receive, relay file-announce to sibling
devices via account_sync, bind DM attachments to pre-allocated message ids,
and improve gallery retry/cancel UX with bounded parallel auto-downloads.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-14 13:05:23 +02:00
co-authored by Cursor
parent bb0ac930ad
commit fa45052432
30 changed files with 785 additions and 71 deletions
@@ -229,6 +229,10 @@ export class AttachmentTransferService {
}
requestImageFromAnyPeer(messageId: string, attachment: Attachment): Promise<void> {
if ((attachment.receivedBytes ?? 0) > 0 || this.hasPendingRequest(messageId, attachment.id)) {
this.cancelRequest(messageId, attachment);
}
return this.requestFromAnyPeer(messageId, attachment);
}
@@ -456,22 +460,22 @@ export class AttachmentTransferService {
}
cancelRequest(messageId: string, attachment: Attachment): void {
const targetPeerId = attachment.uploaderPeerId;
if (!targetPeerId)
return;
try {
const requestKey = this.buildRequestKey(messageId, attachment.id);
const assemblyKey = `${messageId}:${attachment.id}`;
const pendingPeers = this.runtimeStore.getPendingRequestPeers(requestKey);
this.runtimeStore.deleteChunkBuffer(assemblyKey);
this.runtimeStore.deleteChunkCount(assemblyKey);
this.runtimeStore.deletePendingRequest(requestKey);
void this.deleteDiskReceiveAssembly(assemblyKey);
this.chunkAcks.cancelPendingForFile(messageId, attachment.id);
attachment.receivedBytes = 0;
attachment.speedBps = 0;
attachment.startedAtMs = undefined;
attachment.lastUpdateMs = undefined;
attachment.requestError = undefined;
if (attachment.objectUrl) {
try {
@@ -489,8 +493,21 @@ export class AttachmentTransferService {
messageId,
fileId: attachment.id
};
const peersToNotify = new Set<string>();
this.webrtc.sendToPeer(targetPeerId, fileCancelEvent);
if (pendingPeers) {
for (const peerId of pendingPeers) {
peersToNotify.add(peerId);
}
}
if (attachment.uploaderPeerId) {
peersToNotify.add(attachment.uploaderPeerId);
}
for (const peerId of peersToNotify) {
this.webrtc.sendToPeer(peerId, fileCancelEvent);
}
} catch { /* best-effort */ }
}
@@ -997,6 +1014,23 @@ export class AttachmentTransferService {
this.runtimeStore.touch();
void this.persistence.persistAttachmentMeta(attachment);
void this.announceLocalHost(attachment);
void this.hydratePlayableMediaAfterDiskReceive(attachment);
}
private async hydratePlayableMediaAfterDiskReceive(attachment: Attachment): Promise<void> {
if (!this.isPlayableMedia(attachment) || !attachment.savedPath) {
return;
}
const nativeUrl = await this.attachmentStorage.getFileUrl(attachment.savedPath);
if (nativeUrl) {
attachment.objectUrl = nativeUrl;
this.runtimeStore.touch();
return;
}
await this.persistence.ensureInlineDisplayObjectUrl(attachment);
}
private async getOrCreateDiskReceiveAssembly(