import { Injectable, inject } from '@angular/core'; import { RealtimeSessionFacade } from '../../../../core/realtime'; import { AttachmentStorageService } from '../../infrastructure/services/attachment-storage.service'; import { FILE_CHUNK_SIZE_BYTES } from '../../domain/constants/attachment-transfer.constants'; import { FileChunkEvent } from '../../domain/models/attachment-transfer.model'; import { arrayBufferToBase64, decodeBase64, iterateBlobChunks } from '../../../../shared-kernel'; @Injectable({ providedIn: 'root' }) export class AttachmentTransferTransportService { private readonly webrtc = inject(RealtimeSessionFacade); private readonly attachmentStorage = inject(AttachmentStorageService); decodeBase64(base64: string): Uint8Array { return decodeBase64(base64); } async streamFileToPeer( targetPeerId: string, messageId: string, fileId: string, file: File, isCancelled: () => boolean ): Promise { for await (const chunk of iterateBlobChunks(file, FILE_CHUNK_SIZE_BYTES)) { if (isCancelled()) break; const fileChunkEvent: FileChunkEvent = { type: 'file-chunk', messageId, fileId, index: chunk.index, total: chunk.total, data: chunk.base64 }; await this.webrtc.sendToPeerBuffered(targetPeerId, fileChunkEvent); } } async streamFileFromDiskToPeer( targetPeerId: string, messageId: string, fileId: string, diskPath: string, isCancelled: () => boolean ): Promise { const base64Full = await this.attachmentStorage.readFile(diskPath); if (!base64Full) return; const fileBytes = decodeBase64(base64Full); const totalChunks = Math.ceil(fileBytes.byteLength / FILE_CHUNK_SIZE_BYTES); for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) { if (isCancelled()) break; const start = chunkIndex * FILE_CHUNK_SIZE_BYTES; const end = Math.min(fileBytes.byteLength, start + FILE_CHUNK_SIZE_BYTES); const slice = fileBytes.subarray(start, end); const sliceBuffer = (slice.buffer as ArrayBuffer).slice( slice.byteOffset, slice.byteOffset + slice.byteLength ); const base64Chunk = arrayBufferToBase64(sliceBuffer); const fileChunkEvent: FileChunkEvent = { type: 'file-chunk', messageId, fileId, index: chunkIndex, total: totalChunks, data: base64Chunk }; this.webrtc.sendToPeer(targetPeerId, fileChunkEvent); } } }