diff --git a/example/web/tdweb/src/index.js b/example/web/tdweb/src/index.js index 0ac70b014..94e921590 100644 --- a/example/web/tdweb/src/index.js +++ b/example/web/tdweb/src/index.js @@ -5,7 +5,40 @@ import log from './logger.js'; const sleep = ms => new Promise(res => setTimeout(res, ms)); +/** + * TDLib in browser + * + * TDLib can be used from javascript through the [JSON](https://github.com/tdlib/td#using-json) interface. + * This is a convenient wrapper around it. + * Internally it uses TDLib built with emscripten as asm.js or WebAssembly. All work happens in a WebWorker. + * TdClient itself just sends queries to WebWorker, recieve updates and results from WebWorker. + * + *

+ * Differences from TDLib API
+ * 1. updateFatalError error:string = Update;
+ * 3. file <..as in td_api..> idb_key:string = File;
+ * 2. setJsVerbosity verbosity:int = Ok; // currenly no result will be sent
+ * 3. inputFileBlob blob: = InputFile;
+ *
+ * 4. setVerbosity verbosity:int = Ok; // Deprecated + */ class TdClient { + /** + * @callback updateCallback + * @param {Object} update + */ + + /** + * Create TdClient + * @param {Object} options - Options + * @param {updateCallback} options.onUpdate - Callback for all updates. Could also be set explicitly right after TdClient construction. + * @param {number} [options.jsVerbosity='info'] - Verbosity level for javascript part of the code (error, warning, info, log, debug) + * @param {number} [options.verbosity=5] - Verbosity level for tdlib + * @param {string} [options.prefix=tdlib] Currently only one instance of TdClient per a prefix is allowed. All but one created instances will be automatically closed. Usually, the newest instace is kept alive. + * @param {boolean} [options.isBackground=false] - When choosing which instace to keep alive, we prefer instance with isBackground=false + * @param {string} [options.mode=wasm] - Type of tdlib build to use. 'asmjs' for asm.js and 'wasm' for WebAssembly. + * @param {boolean} [options.readOnly=false] - Open tdlib in read-only mode. Changes to tdlib database won't be persisted. For debug only. + */ constructor(options) { log.setVerbosity(options.jsVerbosity); this.worker = new MyWorker(); @@ -53,10 +86,47 @@ class TdClient { }; this.query_id = 0; this.query_callbacks = new Map(); + if ('onUpdate' in options) { + this.onUpdate = options.onUpdate; + delete options.onUpdate; + } this.worker.postMessage({ '@type': 'init', options: options }); this.closeOtherClients(options); } + /** + * Send query to tdlib. + * + * If query contains an '@extra' field, the same field will be added into the result. + * '@extra' may contain any js object, it won't be sent to web worker. + * + * @param {Object} query - Query for tdlib. + * @returns {Promise} Promise represents the result of the query. + */ + send(query) { + this.query_id++; + if (query['@extra']) { + query['@extra'] = { + '@old_extra': JSON.parse(JSON.stringify(query.extra)), + query_id: this.query_id + }; + } else { + query['@extra'] = { + query_id: this.query_id + }; + } + if (query['@type'] === 'setJsVerbosity') { + log.setVerbosity(query.verbosity); + } + + log.info('send to worker: ', query); + this.worker.postMessage(query); + return new Promise((resolve, reject) => { + this.query_callbacks.set(this.query_id, [resolve, reject]); + }); + } + + /** @private */ onBroadcastMessage(e) { var message = e.data; log.info('got broadcast message: ', message); @@ -84,6 +154,7 @@ class TdClient { } } + /** @private */ postState() { let state = { id: this.uid, @@ -95,19 +166,24 @@ class TdClient { this.channel.postMessage(state); } + /** @private */ onWaitSetEmpty() { // nop } + /** @private */ onInited() { this.isInited = true; this.doSendStart(); } + + /** @private */ sendStart() { this.wantSendStart = true; this.doSendStart(); } + /** @private */ doSendStart() { if (!this.isInited || !this.wantSendStart || this.state !== 'start') { return; @@ -119,6 +195,7 @@ class TdClient { this.worker.postMessage(query); } + /** @private */ onClosed() { this.isClosing = true; this.worker.terminate(); @@ -127,6 +204,7 @@ class TdClient { this.postState(); } + /** @private */ close() { if (this.isClosing) { return; @@ -154,6 +232,7 @@ class TdClient { this.postState(); } + /** @private */ async closeOtherClients(options) { this.uid = uuid4(); this.state = 'start'; @@ -181,32 +260,10 @@ class TdClient { this.sendStart(); } + /** @private */ onUpdate(response) { log.info('ignore onUpdate'); //nop } - - send(query) { - this.query_id++; - if (query['@extra']) { - query['@extra'] = { - '@old_extra': JSON.parse(JSON.stringify(query.extra)), - query_id: this.query_id - }; - } else { - query['@extra'] = { - query_id: this.query_id - }; - } - if (query['@type'] === 'setJsVerbosity') { - log.setVerbosity(query.verbosity); - } - - log.info('send to worker: ', query); - this.worker.postMessage(query); - return new Promise((resolve, reject) => { - this.query_callbacks.set(this.query_id, [resolve, reject]); - }); - } } export default TdClient; diff --git a/example/web/tdweb/src/worker.js b/example/web/tdweb/src/worker.js index 3145d90e8..074e9da00 100644 --- a/example/web/tdweb/src/worker.js +++ b/example/web/tdweb/src/worker.js @@ -406,7 +406,7 @@ class TdClient { this.savingFiles = new Map(); this.send({ '@type': 'setOption', - name: 'language_pack_database_path' + name: 'language_pack_database_path', value: { '@type': 'optionValueString', value: this.tdfs.dbFileSystem.root + '/language'