feat: Add emoji and alot of other fixes

This commit is contained in:
2026-06-05 05:40:18 +02:00
parent ca069e2f61
commit 6865147e8f
72 changed files with 3885 additions and 413 deletions

View File

@@ -7,10 +7,13 @@ import { AttachmentStorageService } from '../../infrastructure/services/attachme
import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.model';
import { MAX_AUTO_SAVE_SIZE_BYTES } from '../../domain/constants/attachment.constants';
import { LEGACY_ATTACHMENTS_STORAGE_KEY } from '../../domain/constants/attachment-transfer.constants';
import { mergeAttachmentLocalPaths } from '../../domain/logic/attachment-persistence.rules';
import { AttachmentRuntimeStore } from './attachment-runtime.store';
@Injectable({ providedIn: 'root' })
export class AttachmentPersistenceService {
private initPromise: Promise<void> | null = null;
private readonly runtimeStore = inject(AttachmentRuntimeStore);
private readonly ngrxStore = inject(Store);
private readonly attachmentStorage = inject(AttachmentStorageService);
@@ -51,11 +54,26 @@ export class AttachmentPersistenceService {
}
}
whenReady(): Promise<void> {
if (this.database.isReady()) {
return this.initFromDatabase();
}
return this.initPromise ?? Promise.resolve();
}
async persistAttachmentMeta(attachment: Attachment): Promise<void> {
if (!this.database.isReady())
return;
try {
const storedRecords = await this.database.getAttachmentsForMessage(attachment.messageId);
const storedRecord = storedRecords.find((record) => record.id === attachment.id);
const localPaths = mergeAttachmentLocalPaths(attachment, storedRecord);
attachment.filePath = localPaths.filePath ?? undefined;
attachment.savedPath = localPaths.savedPath ?? undefined;
await this.database.saveAttachment({
id: attachment.id,
messageId: attachment.messageId,
@@ -64,8 +82,8 @@ export class AttachmentPersistenceService {
mime: attachment.mime,
isImage: attachment.isImage,
uploaderPeerId: attachment.uploaderPeerId,
filePath: attachment.filePath,
savedPath: attachment.savedPath
filePath: localPaths.filePath ?? undefined,
savedPath: localPaths.savedPath ?? undefined
});
} catch { /* persistence is best-effort */ }
}
@@ -87,9 +105,73 @@ export class AttachmentPersistenceService {
}
async initFromDatabase(): Promise<void> {
await this.loadFromDatabase();
await this.migrateFromLocalStorage();
await this.tryLoadSavedFiles();
if (!this.initPromise) {
this.initPromise = this.runInitFromDatabase();
}
return this.initPromise;
}
async tryRestoreAttachmentFromLocal(attachment: Attachment): Promise<boolean> {
if (attachment.available) {
return true;
}
let diskPath = await this.attachmentStorage.resolveExistingPath(attachment);
if (!diskPath) {
const roomName = await this.resolveStorageContainerName(attachment);
diskPath = await this.attachmentStorage.resolveCanonicalStoredPath(attachment, roomName);
if (diskPath) {
attachment.savedPath = diskPath;
void this.persistAttachmentMeta(attachment);
}
}
if (!diskPath) {
return false;
}
if (await this.restoreMediaAttachmentFromFileUrl(attachment, diskPath)) {
attachment.requestError = undefined;
return true;
}
const base64 = await this.attachmentStorage.readFile(diskPath);
if (!base64) {
return false;
}
this.restoreAttachmentFromDisk(attachment, base64);
attachment.requestError = undefined;
return true;
}
async persistUploadCopyFromSourcePath(attachment: Attachment, sourcePath: string): Promise<string | null> {
try {
const storageContainer = await this.resolveStorageContainerName(attachment);
const diskPath = await this.attachmentStorage.createWritableFile(attachment, storageContainer);
if (!diskPath) {
return null;
}
const copied = await this.attachmentStorage.copyFile(sourcePath, diskPath);
if (!copied) {
await this.attachmentStorage.deleteFile(diskPath);
return null;
}
attachment.savedPath = diskPath;
await this.persistAttachmentMeta(attachment);
return diskPath;
} catch {
return null;
}
}
async resolveMessageRoomId(messageId: string): Promise<string | null> {
@@ -173,50 +255,20 @@ export class AttachmentPersistenceService {
} catch { /* migration is best-effort */ }
}
private async runInitFromDatabase(): Promise<void> {
await this.loadFromDatabase();
await this.migrateFromLocalStorage();
await this.tryLoadSavedFiles();
}
private async tryLoadSavedFiles(): Promise<void> {
try {
let hasChanges = false;
for (const [, attachments] of this.runtimeStore.getAttachmentEntries()) {
for (const attachment of attachments) {
if (attachment.available)
continue;
if (attachment.savedPath) {
if (await this.restoreMediaAttachmentFromFileUrl(attachment, attachment.savedPath)) {
hasChanges = true;
continue;
}
const savedBase64 = await this.attachmentStorage.readFile(attachment.savedPath);
if (savedBase64) {
this.restoreAttachmentFromDisk(attachment, savedBase64);
hasChanges = true;
continue;
}
}
if (attachment.filePath) {
if (await this.restoreMediaAttachmentFromFileUrl(attachment, attachment.filePath)) {
hasChanges = true;
continue;
}
const originalBase64 = await this.attachmentStorage.readFile(attachment.filePath);
if (originalBase64) {
this.restoreAttachmentFromDisk(attachment, originalBase64);
hasChanges = true;
if (attachment.size <= MAX_AUTO_SAVE_SIZE_BYTES && attachment.objectUrl) {
const response = await fetch(attachment.objectUrl);
void this.saveFileToDisk(attachment, await response.blob());
}
continue;
}
if (await this.tryRestoreAttachmentFromLocal(attachment)) {
hasChanges = true;
}
}
}