diff --git a/example/web/tdweb/src/index.js b/example/web/tdweb/src/index.js index 56cdcb453..768c907b9 100644 --- a/example/web/tdweb/src/index.js +++ b/example/web/tdweb/src/index.js @@ -57,7 +57,7 @@ class TdClient { delete options.onUpdate; } options.instanceName = options.instanceName || 'tdlib'; - this.fileManager = new FileManager(options.instanceName); + this.fileManager = new FileManager(options.instanceName, this); this.worker.postMessage({ '@type': 'init', options: options }); this.closeOtherClients(options); } @@ -432,13 +432,14 @@ class ListNode { /** @private */ class FileManager { - constructor(instanceName) { + constructor(instanceName, client) { this.instanceName = instanceName; this.cache = new Map(); this.pending = []; this.transaction_id = 0; this.totalSize = 0; this.lru = new ListNode(-1); + this.client = client; } init() { @@ -471,53 +472,55 @@ class FileManager { } registerFile(file) { - const cached_info = this.cache.get(file.id); - if (cached_info && !file.idb_key) { - delete cached_info.idb_key; - } if (file.idb_key || file.arr) { file.is_downloading_completed = true; - let info = {}; - if (cached_info) { - info = cached_info; - } else { - this.cache.set(file.id, info); - } - if (file.idb_key) { - info.idb_key = file.idb_key; - delete file.idb_key; - } - if (file.arr) { - const now = Date.now(); - while (this.totalSize > 10000000) { - const node = this.lru.getLru(); - // immunity for 5 seconds - if (node.usedAt + 5 * 1000 > now) { - break; - } - const lru_info = this.cache.get(node.value); - this.unload(lru_info); - } - - if (info.arr) { - log.warn('Got file.arr at least twice for the same file'); - this.totalSize -= info.arr.length; - } - info.arr = file.arr; - this.totalSize += info.arr.length; - if (!info.node) { - log.debug( - 'LRU: create file_id: ', - file.id, - ' with arr.length: ', - info.arr.length - ); - info.node = new ListNode(file.id); - } - this.lru.onUsed(info.node); - log.info('Total file.arr size: ', this.totalSize); - } } + let info = {}; + const cached_info = this.cache.get(file.id); + if (cached_info) { + info = cached_info; + } else { + this.cache.set(file.id, info); + } + if (file.idb_key) { + info.idb_key = file.idb_key; + // TODO: uncomment after supported in telegram-react + //delete file.idb_key; + } else { + delete info.idb_key; + } + if (file.arr) { + const now = Date.now(); + while (this.totalSize > 10000000) { + const node = this.lru.getLru(); + // immunity for 5 seconds + if (node.usedAt + 5 * 1000 > now) { + break; + } + const lru_info = this.cache.get(node.value); + this.unload(lru_info); + } + + if (info.arr) { + log.warn('Got file.arr at least twice for the same file'); + this.totalSize -= info.arr.length; + } + info.arr = file.arr; + delete file.arr; + this.totalSize += info.arr.length; + if (!info.node) { + log.debug( + 'LRU: create file_id: ', + file.id, + ' with arr.length: ', + info.arr.length + ); + info.node = new ListNode(file.id); + } + this.lru.onUsed(info.node); + log.info('Total file.arr size: ', this.totalSize); + } + info.file = file; return file; } @@ -535,7 +538,7 @@ class FileManager { request.onsuccess = event => { const blob = event.target.result; if (blob) { - if (blob.size == 0) { + if (blob.size === 0) { log.error('Got empty blob from db ', query.key); } query.resolve({ data: blob, transaction_id: transaction_id }); @@ -556,15 +559,61 @@ class FileManager { this.pending.push({ key: key, resolve: resolve, reject: reject }); } - async doLoad(info) { + async doLoadFull(info) { if (info.arr) { return { data: new Blob([info.arr]), transaction_id: -1 }; } - const idb_key = info.idb_key; - //return this.store.getItem(idb_key); - return await new Promise((resolve, reject) => { - this.load(idb_key, resolve, reject); - }); + if (info.idb_key) { + const idb_key = info.idb_key; + //return this.store.getItem(idb_key); + return await new Promise((resolve, reject) => { + this.load(idb_key, resolve, reject); + }); + } + throw new Error('File is not loaded'); + } + async doLoad(info, offset, size) { + log.error('LOAD', info); + if (!info.arr && !info.idb_key && info.file.local.path) { + try { + const count = await this.client.sendInternal({ + '@type': 'getFileDownloadedPrefixSize', + file_id: info.file.id, + offset: offset + }); + log.error(count, size); + if (!size) { + size = count.count; + } else if (size > count.count) { + throw new Error('File not loaded yet'); + } + const res = await this.client.sendInternal({ + '@type': 'readFilePart', + path: info.file.local.path, + offset: offset, + size: size + }); + res.data = new Blob([res.data]); + res.transaction_id = -2; + log.error(res); + return res; + } catch (e) { + log.info('readFilePart failed', info, offset, size, e); + } + } + + const res = await this.doLoadFull(info); + + // return slice(size, offset + size) + const data_size = res.data.size; + if (!size) { + size = data_size; + } + if (offset > data_size) { + offset = data_size; + } + res.data = res.data.slice(offset, offset + size); + return res; } doDelete(info) { @@ -574,9 +623,6 @@ class FileManager { async readFile(query) { try { - if (query.offset || query.size) { - throw new Error('readFilePart: offset and size are not supported yet'); - } if (!this.isInited) { throw new Error('FileManager is not inited'); } @@ -587,7 +633,9 @@ class FileManager { if (info.node) { this.lru.onUsed(info.node); } - const response = await this.doLoad(info); + query.offset = query.offset || 0; + query.size = query.size || 0; + const response = await this.doLoad(info, query.offset, query.size); return { '@type': 'filePart', '@extra': query['@extra'], diff --git a/example/web/tdweb/src/worker.js b/example/web/tdweb/src/worker.js index 6457b7dc3..2f4f0bab2 100644 --- a/example/web/tdweb/src/worker.js +++ b/example/web/tdweb/src/worker.js @@ -640,13 +640,13 @@ class TdClient { '@type': 'error', '@extra': query['@extra'], code: 400, - message: e + message: e.toString() }); return; } this.callback( { - '@type': 'FilePart', + '@type': 'filePart', '@extra': query['@extra'], data: res },