diff --git a/example/web/tdweb/src/index.js b/example/web/tdweb/src/index.js
index 92a6c4792..223c83bd0 100644
--- a/example/web/tdweb/src/index.js
+++ b/example/web/tdweb/src/index.js
@@ -17,10 +17,10 @@ const sleep = ms => new Promise(res => setTimeout(res, ms));
*
* Differences from TDLib API:
* 1. Added the update updateFatalError error:string = Update;
which is sent whenever a TDLib fatal error is encountered.
- * 2. Added the field idb_key
to file
object, which contains IndexedDB key in which the file content is stored.
+ * 2. Added the field idb_key
to file
object, which contains IndexedDB key in which the file content is stored. IndexedDB table name is options.instanceName.
* This field is non-empty only for fully downloaded files. IndexedDB database name is chosen during TdClient creation.
* 3. Added the method setJsLogVerbosityLevel new_verbosity_level:string = Ok;
, which allows to change the verbosity level of tdweb logging.
- * 4. Added the possibility to use blobs as input files via constructor inputFileBlob blob: = InputFile;
.
+ * 4. Added the possibility to use blobs as input files via constructor inputFileBlob data: = InputFile;
.
* 5. Added the method readFilePart path:string offset:int64 size:int64 = FilePart;
and class filePart data: = FilePart;
* which can be used on a partially downloaded file to support media streaming.
* 6. Methods getStorageStatistics
, getStorageStatisticsFast
, optimizeStorage
, addProxy
are not supported.
@@ -36,58 +36,20 @@ class TdClient {
* Create TdClient.
* @param {Object} options - The options for TDLib instance creation.
* @param {TdClient~updateCallback} options.onUpdate - The callback for all incoming updates.
- * @param {string} [options.prefix=tdlib] - The name of the IndexedDB database which will be used for persistent data storage. Currently only one instance of TdClient per a database is allowed. All but one created instances will be automatically closed. Usually, the newest non-background instance is kept alive.
+ * @param {string} [options.instanceName=tdlib] - The name of the TDLib instance. Currently only one instance of TdClient with a given name is allowed. All but one created instances with a given name will be automatically closed. Usually, the newest non-background instance is kept alive. Files will be stored in IndexedDb table with the same name.
* @param {boolean} [options.isBackground=false] - Pass true, if the instance is opened from the background.
- * @param {string} [options.mode=wasm] - The type of the TDLib build to use. 'asmjs' for asm.js and 'wasm' for WebAssembly.
* @param {string} [options.jsLogVerbosityLevel='info'] - The initial verbosity level of the JavaScript part of the code (one of 'error', 'warning', 'info', 'log', 'debug').
* @param {number} [options.logVerbosityLevel=2] - The initial verbosity level for TDLib internal logging (0-1023).
- * @param {boolean} [options.noDb=false] - Pass true to use TDLib without database and secret chats. It will significantly improve load time, but some functionality will be unavailable.
- * @param {boolean} [options.readOnly=false] - Pass true to open TDLib database in read-only mode. For debug only.
+ * @param {boolean} [options.useDatabase=true] - Pass false to use TDLib without database and secret chats. It will significantly improve load time, but some functionality will be unavailable.
+ * @param {string} [options.mode='auto'] - For debug only. The type of the TDLib build to use. 'asmjs' for asm.js and 'wasm' for WebAssembly. If mode == 'auto' WebAbassembly will be used if supported by browser, asm.js otherwise.
+ * @param {boolean} [options.readOnly=false] - For debug only. Pass true to open TDLib database in read-only mode
*/
constructor(options) {
log.setVerbosity(options.jsLogVerbosityLevel);
this.worker = new MyWorker();
var self = this;
- this.worker.onmessage = function(e) {
- let response = e.data;
- log.debug(
- 'receive from worker: ',
- JSON.parse(
- JSON.stringify(response, (key, value) => {
- if (key === 'arr') {
- return undefined;
- }
- return value;
- })
- )
- );
- if ('@extra' in response) {
- var query_id = response['@extra'].query_id;
- var [resolve, reject] = self.query_callbacks.get(query_id);
- self.query_callbacks.delete(query_id);
- if ('@old_extra' in response['@extra']) {
- response['@extra'] = response['@extra']['@old_extra'];
- }
- if (resolve) {
- if (response['@type'] === 'error') {
- reject(response);
- } else {
- resolve(response);
- }
- }
- } else {
- if (response['@type'] === 'inited') {
- self.onInited();
- return;
- }
- if (
- response['@type'] === 'updateAuthorizationState' &&
- response.authorization_state['@type'] === 'authorizationStateClosed'
- ) {
- self.onClosed();
- }
- self.onUpdate(response);
- }
+ this.worker.onmessage = e => {
+ self.onResponse(e.data);
};
this.query_id = 0;
this.query_callbacks = new Map();
@@ -95,6 +57,7 @@ class TdClient {
this.onUpdate = options.onUpdate;
delete options.onUpdate;
}
+ options.instanceName = options.instanceName || 'tdlib';
this.worker.postMessage({ '@type': 'init', options: options });
this.closeOtherClients(options);
}
@@ -111,11 +74,6 @@ class TdClient {
* @returns {Promise} Promise object represents the result of the query.
*/
send(query) {
- let unsupportedMethods = ['getStorageStatistics', 'getStorageStatisticsFast', 'optimizeStorage', 'addProxy', 'init', 'start'];
- if (unsupportedMethods.includes(query['@type'])) {
- return; // TODO what we need to return?
- }
-
this.query_id++;
if (query['@extra']) {
query['@extra'] = {
@@ -132,10 +90,75 @@ class TdClient {
}
log.debug('send to worker: ', query);
- this.worker.postMessage(query);
- return new Promise((resolve, reject) => {
+ let res = new Promise((resolve, reject) => {
this.query_callbacks.set(this.query_id, [resolve, reject]);
});
+ this.externalPostMessage(query);
+ return res;
+ }
+
+ /** @private */
+ externalPostMessage(query) {
+ let unsupportedMethods = [
+ 'getStorageStatistics',
+ 'getStorageStatisticsFast',
+ 'optimizeStorage',
+ 'addProxy',
+ 'init',
+ 'start'
+ ];
+ if (unsupportedMethods.includes(query['@type'])) {
+ this.onResponse({
+ '@type': 'error',
+ '@extra': query['@extra'],
+ code: 400,
+ message: "method '" + query['@type'] + "' is not supported"
+ });
+ return;
+ }
+ this.worker.postMessage(query);
+ }
+
+ /** @private */
+ onResponse(response) {
+ log.debug(
+ 'receive from worker: ',
+ JSON.parse(
+ JSON.stringify(response, (key, value) => {
+ if (key === 'arr') {
+ return undefined;
+ }
+ return value;
+ })
+ )
+ );
+ if ('@extra' in response) {
+ var query_id = response['@extra'].query_id;
+ var [resolve, reject] = this.query_callbacks.get(query_id);
+ this.query_callbacks.delete(query_id);
+ if ('@old_extra' in response['@extra']) {
+ response['@extra'] = response['@extra']['@old_extra'];
+ }
+ if (resolve) {
+ if (response['@type'] === 'error') {
+ reject(response);
+ } else {
+ resolve(response);
+ }
+ }
+ } else {
+ if (response['@type'] === 'inited') {
+ this.onInited();
+ return;
+ }
+ if (
+ response['@type'] === 'updateAuthorizationState' &&
+ response.authorization_state['@type'] === 'authorizationStateClosed'
+ ) {
+ this.onClosed();
+ }
+ this.onUpdate(response);
+ }
}
/** @private */
@@ -253,8 +276,7 @@ class TdClient {
this.waitSet = new Set();
log.info('close other clients');
- let prefix = options.prefix || 'tdlib';
- this.channel = new BroadcastChannel(prefix);
+ this.channel = new BroadcastChannel(options.instanceName);
this.postState();
diff --git a/example/web/tdweb/src/worker.js b/example/web/tdweb/src/worker.js
index 36f2c8f91..ba9e22e33 100644
--- a/example/web/tdweb/src/worker.js
+++ b/example/web/tdweb/src/worker.js
@@ -144,8 +144,12 @@ async function loadTdLib(mode, onFS) {
return false;
})();
if (!wasmSupported) {
- log.warning('WebAssembly is not supported, trying to use asmjs');
- mode = 'asmjs';
+ if (mode === 'wasm') {
+ log.error('WebAssembly is not supported, trying to use it anyway');
+ } else {
+ log.warning('WebAssembly is not supported, trying to use asmjs');
+ mode = 'asmjs';
+ }
}
if (mode === 'asmjs') {
@@ -367,15 +371,16 @@ class TdFileSystem {
FS.mkdir(prefix);
return FS;
}
- static async create(prefix, FS_promise, readOnly = false) {
+ static async create(instanceName, FS_promise, readOnly = false) {
try {
let tdfs = new TdFileSystem();
+ let prefix = '/' + instanceName;
tdfs.prefix = prefix;
FS_promise = TdFileSystem.init_fs(prefix, FS_promise);
//MEMFS. Store to IDB and delete files as soon as possible
let inboundFileSystem = InboundFileSystem.create(
- prefix,
+ instanceName,
prefix + '/inboundfs',
FS_promise
);
@@ -460,14 +465,16 @@ class TdClient {
self.onFS = resolve;
});
- let prefix = options.prefix || 'tdlib';
let tdfs_promise = TdFileSystem.create(
- '/' + prefix,
+ options.instanceName,
FS_promise,
options.readOnly
);
- this.noDb = options.noDb || false;
+ this.useDatabase = true;
+ if ('useDatabase' in options) {
+ this.useDatabase = options.useDatabase;
+ }
log.info('load TdModule');
this.TdModule = await loadTdLib(mode, self.onFS);
@@ -549,7 +556,7 @@ class TdClient {
name: 'ignore_background_updates',
value: {
'@type': 'optionValueBoolean',
- value: this.noDb
+ value: !this.useDatabase
}
});
@@ -562,7 +569,7 @@ class TdClient {
if (query['@type'] === 'inputFileBlob') {
return {
'@type': 'inputFileLocal',
- path: this.tdfs.outboundFileSystem.blobToPath(query.blob, query.name)
+ path: this.tdfs.outboundFileSystem.blobToPath(query.data, query.name)
};
}
for (var key in query) {
@@ -579,7 +586,7 @@ class TdClient {
query.parameters.database_directory = this.tdfs.dbFileSystem.root;
query.parameters.files_directory = this.tdfs.inboundFileSystem.root;
- let useDb = !this.noDb;
+ let useDb = this.useDatabase;
query.parameters.use_file_database = useDb;
query.parameters.use_chat_info_database = useDb;
query.parameters.use_message_database = useDb;