tdweb: support readFilePart

GitOrigin-RevId: d0443ebbd2d476db74249449e0586c5bdd1684a5
This commit is contained in:
Arseny Smirnov 2019-05-10 15:47:39 +02:00
parent c99a76f422
commit ce84c34c23
2 changed files with 107 additions and 59 deletions

View File

@ -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'],

View File

@ -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
},