diff --git a/src/helpers/fileName.ts b/src/helpers/fileName.ts index 6da5d122..a8c5807b 100644 --- a/src/helpers/fileName.ts +++ b/src/helpers/fileName.ts @@ -7,39 +7,52 @@ import type { InputFileLocation, InputStickerSet } from "../layer"; import type { DownloadOptions } from "../lib/mtproto/apiFileManager"; +const FILENAME_JOINER = '_'; + export function getFileNameByLocation(location: InputFileLocation, options?: Partial<{ fileName: string }>) { const fileName = '';//(options?.fileName || '').split('.'); const ext = fileName[fileName.length - 1] || ''; + let str: string; switch(location._) { - case 'inputPhotoFileLocation': + case 'inputPhotoFileLocation': { + str = ['photo', fileName[0], location.id, location.thumb_size].filter(Boolean).join(FILENAME_JOINER); + break; + } + case 'inputDocumentFileLocation': { - const thumbPart = location.thumb_size ? '_' + location.thumb_size : ''; - return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext); + str = ['document', fileName[0], location.id, location.thumb_size].filter(Boolean).join(FILENAME_JOINER); + break; } case 'inputPeerPhotoFileLocation': - return ['peerPhoto', location.photo_id, location.pFlags.big ? 'big' : 'small'].join('_'); + str = ['peerPhoto', location.photo_id, location.pFlags.big ? 'big' : 'small'].join(FILENAME_JOINER); + break; case 'inputStickerSetThumb': { const id = (location.stickerset as InputStickerSet.inputStickerSetID).id || (location.stickerset as InputStickerSet.inputStickerSetShortName).short_name || (location.stickerset as InputStickerSet.inputStickerSetDice).emoticon || location.stickerset._; - return ['stickerSetThumb', id, location.thumb_version].join('_'); + str = ['stickerSetThumb', id, location.thumb_version].join(FILENAME_JOINER); + break; } case 'inputFileLocation': { - return location.volume_id + '_' + location.local_id + (ext ? '.' + ext : ext); + str = location.volume_id + '_' + location.local_id; + break; } default: { console.error('Unrecognized location:', location); - return ''; + str = ''; + break; } } + + return str + (ext ? '.' + ext : ext); } export type FileURLType = 'photo' | 'thumb' | 'document' | 'stream' | 'download'; diff --git a/src/lib/mtproto/apiFileManager.ts b/src/lib/mtproto/apiFileManager.ts index 1da4bebb..cba9a8cd 100644 --- a/src/lib/mtproto/apiFileManager.ts +++ b/src/lib/mtproto/apiFileManager.ts @@ -45,17 +45,17 @@ type MyUploadFile = UploadFile.uploadFile; const MAX_FILE_SAVE_SIZE = 20e6; export class ApiFileManager { - public cacheStorage = new CacheStorageController('cachedFiles'); + private cacheStorage = new CacheStorageController('cachedFiles'); - public cachedDownloadPromises: { + private cachedDownloadPromises: { [fileName: string]: CancellablePromise } = {}; - public uploadPromises: { - [fileName: string]: CancellablePromise + private uploadPromises: { + [fileName: string]: Set> } = {}; - public downloadPulls: { + private downloadPulls: { [dcId: string]: Array<{ id: number, queueId: number, @@ -67,7 +67,7 @@ export class ApiFileManager { activeDelta: number }> } = {}; - public downloadActives: {[dcId: string]: number} = {}; + private downloadActives: {[dcId: string]: number} = {}; public webpConvertPromises: {[fileName: string]: CancellablePromise} = {}; @@ -76,9 +76,9 @@ export class ApiFileManager { private queueId = 0; private debug = Modes.debug; - public downloadRequest(dcId: 'upload', id: number, cb: () => Promise, activeDelta: number, queueId?: number): Promise; - public downloadRequest(dcId: number, id: number, cb: () => Promise, activeDelta: number, queueId?: number): Promise; - public downloadRequest(dcId: number | string, id: number, cb: () => Promise, activeDelta: number, queueId: number = 0) { + private downloadRequest(dcId: 'upload', id: number, cb: () => Promise, activeDelta: number, queueId?: number): Promise; + private downloadRequest(dcId: number, id: number, cb: () => Promise, activeDelta: number, queueId?: number): Promise; + private downloadRequest(dcId: number | string, id: number, cb: () => Promise, activeDelta: number, queueId: number = 0) { if(this.downloadPulls[dcId] === undefined) { this.downloadPulls[dcId] = []; this.downloadActives[dcId] = 0; @@ -97,7 +97,7 @@ export class ApiFileManager { return promise; } - public downloadCheck(dcId: string | number) { + private downloadCheck(dcId: string | number) { const downloadPull = this.downloadPulls[dcId]; const downloadLimit = dcId === 'upload' ? 24 : 24; //const downloadLimit = Infinity; @@ -136,18 +136,23 @@ export class ApiFileManager { this.queueId = queueId; } - public getFileStorage() { + private getFileStorage() { return this.cacheStorage; } public cancelDownload(fileName: string) { - const promise = this.cachedDownloadPromises[fileName] || this.uploadPromises[fileName]; - if(promise && !promise.isRejected && !promise.isFulfilled) { - promise.cancel(); - return true; + const promises = (this.cachedDownloadPromises[fileName] ? [this.cachedDownloadPromises[fileName]] : []) || + (this.uploadPromises[fileName] ? Array.from(this.uploadPromises[fileName]) : []); + let canceled = false; + for(let i = 0, length = promises.length; i < length; ++i) { + const promise = promises[i]; + if(promise && !promise.isRejected && !promise.isFulfilled) { + promise.cancel(); + canceled = true; + } } - return false; + return canceled; } public requestFilePart(dcId: number, location: InputFileLocation, offset: number, limit: number, id = 0, queueId = 0, checkCancel?: () => void) { @@ -184,13 +189,13 @@ export class ApiFileManager { return bytes * 1024; } - uncompressTGS = (bytes: Uint8Array, fileName: string) => { + private uncompressTGS = (bytes: Uint8Array, fileName: string) => { //this.log('uncompressTGS', bytes, bytes.slice().buffer); // slice нужен потому что в uint8array - 5053 length, в arraybuffer - 5084 return cryptoWorker.gzipUncompress(bytes.slice().buffer, true); }; - convertWebp = (bytes: Uint8Array, fileName: string) => { + private convertWebp = (bytes: Uint8Array, fileName: string) => { const convertPromise = deferredPromise(); const task = {type: 'convertWebp', payload: {fileName, bytes}}; @@ -203,8 +208,8 @@ export class ApiFileManager { return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'}); } - let size = options.size ?? 0; - let {dcId, location} = options; + const size = options.size ?? 0; + const {dcId, location} = options; let process: ApiFileManager['uncompressTGS'] | ApiFileManager['convertWebp']; @@ -393,10 +398,14 @@ export class ApiFileManager { this.cachedDownloadPromises[fileName] = deferred; + deferred.finally(() => { + delete this.cachedDownloadPromises[fileName]; + }); + return deferred; } - public deleteFile(fileName: string) { + private deleteFile(fileName: string) { //this.log('will delete file:', fileName); delete this.cachedDownloadPromises[fileName]; return this.getFileStorage().delete(fileName); @@ -581,10 +590,15 @@ export class ApiFileManager { }; deferred.finally(() => { - delete this.uploadPromises[fileName]; + set.delete(deferred); + if(!set.size) { + delete this.uploadPromises[fileName]; + } }); - return this.uploadPromises[fileName] = deferred; + const set = this.uploadPromises[fileName] ?? (this.uploadPromises[fileName] = new Set()); + set.add(deferred); + return deferred; } }