fix: Bug - Sending files and attachment issues
Normalize attachment MIME types from filenames, hydrate playable media and gallery tiles from disk without redundant peer requests, reset stalled partial downloads, and improve gallery retry/hydration UX across chat and DMs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+46
-12
@@ -13,10 +13,13 @@ import { isSharingFromThisDevice, canHostAttachment } from '../../domain/logic/a
|
||||
import { selectFileRequestPeer } from '../../domain/logic/attachment-request.rules';
|
||||
import {
|
||||
canReceiveAttachment,
|
||||
needsAttachmentDisplayHydration,
|
||||
shouldCopyLargeUploaderFileToAppData,
|
||||
shouldPersistDownloadedAttachment,
|
||||
shouldStreamAttachmentReceiveToDisk
|
||||
} from '../../domain/logic/attachment.logic';
|
||||
import { normalizeAttachmentMeta } from '../../domain/logic/attachment-normalize.rules';
|
||||
import { resolveAttachmentMime } from '../../domain/logic/attachment-mime.rules';
|
||||
import { shouldServeAttachmentFromDiskPath } from '../../domain/logic/attachment-serve.rules';
|
||||
import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.model';
|
||||
import {
|
||||
@@ -141,9 +144,11 @@ export class AttachmentTransferService {
|
||||
const alreadyKnown = existing.find((entry) => entry.id === meta.id);
|
||||
|
||||
if (!alreadyKnown) {
|
||||
const attachment: Attachment = { ...meta,
|
||||
const attachment: Attachment = {
|
||||
...normalizeAttachmentMeta(meta),
|
||||
available: false,
|
||||
receivedBytes: 0 };
|
||||
receivedBytes: 0
|
||||
};
|
||||
|
||||
existing.push(attachment);
|
||||
newAttachments.push(attachment);
|
||||
@@ -171,6 +176,16 @@ export class AttachmentTransferService {
|
||||
// request makes the sender stream the file twice and corrupts byte accounting.
|
||||
this.runtimeStore.setPendingRequestPeers(requestKey, new Set<string>());
|
||||
|
||||
if (needsAttachmentDisplayHydration(attachment)) {
|
||||
const hydratedLocally = await this.persistence.tryRestoreAttachmentFromLocal(attachment);
|
||||
|
||||
if (hydratedLocally) {
|
||||
this.runtimeStore.deletePendingRequest(requestKey);
|
||||
this.runtimeStore.touch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!attachment.available) {
|
||||
const restoredLocally = await this.persistence.tryRestoreAttachmentFromLocal(attachment);
|
||||
|
||||
@@ -230,6 +245,10 @@ export class AttachmentTransferService {
|
||||
}
|
||||
|
||||
requestImageFromAnyPeer(messageId: string, attachment: Attachment): Promise<void> {
|
||||
if (needsAttachmentDisplayHydration(attachment)) {
|
||||
return this.requestFromAnyPeer(messageId, attachment);
|
||||
}
|
||||
|
||||
if ((attachment.receivedBytes ?? 0) > 0 || this.hasPendingRequest(messageId, attachment.id)) {
|
||||
this.cancelRequest(messageId, attachment);
|
||||
}
|
||||
@@ -259,7 +278,7 @@ export class AttachmentTransferService {
|
||||
messageId,
|
||||
filename: file.name,
|
||||
size: file.size,
|
||||
mime: file.type || DEFAULT_ATTACHMENT_MIME_TYPE,
|
||||
mime: resolveAttachmentMime(file.name, file.type || DEFAULT_ATTACHMENT_MIME_TYPE),
|
||||
isImage: resolvePublishAttachmentIsImage(file),
|
||||
uploaderPeerId,
|
||||
filePath: (file as LocalFileWithPath).path,
|
||||
@@ -327,29 +346,40 @@ export class AttachmentTransferService {
|
||||
const alreadyKnown = list.find((entry) => entry.id === file.id);
|
||||
|
||||
if (alreadyKnown) {
|
||||
alreadyKnown.filename = file.filename;
|
||||
alreadyKnown.size = file.size;
|
||||
alreadyKnown.mime = resolveAttachmentMime(file.filename, file.mime);
|
||||
alreadyKnown.isImage = isImageAttachment({
|
||||
filename: file.filename,
|
||||
isImage: !!file.isImage,
|
||||
mime: alreadyKnown.mime
|
||||
});
|
||||
|
||||
alreadyKnown.uploaderPeerId = file.uploaderPeerId ?? alreadyKnown.uploaderPeerId;
|
||||
this.runtimeStore.touch();
|
||||
void this.persistence.persistAttachmentMeta(alreadyKnown);
|
||||
return false;
|
||||
}
|
||||
|
||||
const attachment: Attachment = {
|
||||
const normalizedMeta = normalizeAttachmentMeta({
|
||||
id: file.id,
|
||||
messageId,
|
||||
filename: file.filename,
|
||||
size: file.size,
|
||||
mime: file.mime,
|
||||
isImage: isImageAttachment({
|
||||
filename: file.filename,
|
||||
isImage: !!file.isImage,
|
||||
mime: file.mime
|
||||
}),
|
||||
uploaderPeerId: file.uploaderPeerId,
|
||||
isImage: !!file.isImage,
|
||||
uploaderPeerId: file.uploaderPeerId
|
||||
});
|
||||
const runtimeAttachment: Attachment = {
|
||||
...normalizedMeta,
|
||||
available: false,
|
||||
receivedBytes: 0
|
||||
};
|
||||
|
||||
list.push(attachment);
|
||||
list.push(runtimeAttachment);
|
||||
this.runtimeStore.setAttachmentsForMessage(messageId, list);
|
||||
this.runtimeStore.touch();
|
||||
void this.persistence.persistAttachmentMeta(attachment);
|
||||
void this.persistence.persistAttachmentMeta(runtimeAttachment);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -793,6 +823,10 @@ export class AttachmentTransferService {
|
||||
this.runtimeStore.touch();
|
||||
void this.persistence.persistAttachmentMeta(attachment);
|
||||
void this.announceLocalHost(attachment);
|
||||
|
||||
if (this.isPlayableMedia(attachment)) {
|
||||
await this.hydratePlayableMediaAfterDiskReceive(attachment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user