tdweb: support readFilePart
GitOrigin-RevId: d0443ebbd2d476db74249449e0586c5bdd1684a5
This commit is contained in:
parent
c99a76f422
commit
ce84c34c23
@ -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'],
|
||||
|
@ -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
|
||||
},
|
||||
|
Reference in New Issue
Block a user