tdlib-native
Version:
🚀 Telegram TDLib native nodejs wrapper
199 lines (198 loc) • 4.89 kB
JavaScript
import path from "path";
import { getAddonFolderPath } from "./path.mjs";
import { createRequire } from "module";
import { promiseWithResolvers } from "../shared/async.mjs";
import { family } from "detect-libc";
const builtinAddonPath = path.resolve(
getAddonFolderPath(),
"..",
"..",
"build",
"Release",
"td.node"
);
async function loadAddon(addonPath = builtinAddonPath) {
const baseDirectory = getAddonFolderPath();
const load = createRequire(baseDirectory);
const addon = load(addonPath);
return addon;
}
async function getTDLibPath() {
let packageName = `@tdlib-native/tdjson-${process.platform}-${process.arch}`;
if (process.platform === "android") {
packageName += "-glibc";
}
if (process.platform === "linux") {
packageName += `-${await family()}`;
}
try {
const { tdlibPath } = await import(packageName);
return tdlibPath;
} catch (error) {
throw new Error(
`There is no prebuilt TDLib for your platform (${process.platform} ${process.arch}). You can ask for it: https://github.com/AlexXanderGrib/node-tdlib/issues`,
{
cause: error
}
);
}
}
class ReceiveQueueEntry {
constructor(client, promise) {
this.client = client;
this.promise = promise;
Object.freeze(this);
}
}
class ClientMeta {
constructor(timeout) {
this.timeout = timeout;
}
destroyed = false;
}
class TDLibAddon {
/**
* Creates an instance of TDLibAddon.
* @param {Addon} _addon
* @memberof TDLibAddon
*/
constructor(_addon) {
this._addon = _addon;
}
/**
*
*
* @static
* @param {string} [tdlibPath] Resolves to prebuild TDLib for your platform
* @param {string} [addonPath]
* @returns {Promise<TDLib>}
* @memberof TDLibAddon
*/
static async create(tdlibPath, addonPath) {
tdlibPath ??= await getTDLibPath();
const addon = await loadAddon(addonPath);
addon.load_tdjson(tdlibPath);
return new TDLibAddon(addon);
}
_isTDLib = true;
_clients = /* @__PURE__ */ new WeakMap();
/**
*
*
* @readonly
* @memberof TDLibAddon
*/
get name() {
return "addon";
}
/**
*
*
* @returns {TDLibClient} {TDLibClient}
* @memberof TDLibAddon
*/
create(timeout) {
const client = this._addon.td_json_client_create(timeout);
this._clients.set(client, new ClientMeta(timeout));
return client;
}
_getMeta(client) {
const meta = this._clients.get(client);
if (!meta) {
throw new Error("Unknown client");
}
return meta;
}
/**
*
*
* @param {TDLibClient} client
* @memberof TDLibAddon
* @returns {Promise<void>}
*/
async destroy(client) {
if (this._getMeta(client).destroyed) {
throw new Error("Client already destroyed");
}
for (const entry of this._queue) {
if (entry.client === client) {
entry.promise.reject(new Error("Client is destroyed"));
}
}
await this._thread;
this._addon.td_json_client_destroy(client);
}
/**
*
*
* @param {(TDLibClient | null)} client
* @param {string} json
* @returns {(string | null)} {(string | null)}
* @memberof TDLibAddon
*/
execute(client, json) {
return this._addon.td_json_client_execute(client, json);
}
_queue = [];
_thread;
async _receive() {
while (this._queue.length > 0) {
const task = this._queue.shift();
if (!task) break;
await this._addon.td_json_client_receive(task.client).then(task.promise.resolve, task.promise.reject);
}
}
/**
*
*
* @param {TDLibClient} client
* @returns {Promise<string|null>} {(Promise<string | null>)}
* @memberof TDLibAddon
*/
receive(client) {
const meta = this._getMeta(client);
if (meta.destroyed) {
return Promise.reject(new Error("Client is destroyed"));
}
const entryWithSameClient = this._queue.find((entry2) => entry2.client === client);
if (entryWithSameClient) {
return Promise.reject(new Error("This client is already receiving updates"));
}
const promise = promiseWithResolvers();
const entry = new ReceiveQueueEntry(client, promise);
this._queue.push(entry);
if (!this._thread) {
this._thread = this._receive().finally(() => {
this._thread = void 0;
});
}
return promise.promise;
}
/**
*
*
* @param {TDLibClient} client
* @param {string} json
* @memberof TDLibAddon
* @returns {void}
*/
send(client, json) {
if (this._getMeta(client).destroyed) {
throw new Error("Client is destroyed");
}
this._addon.td_json_client_send(client, json);
}
/**
*
*
* @param {function(errorMessage: string): void=} callback
* @memberof TDLibAddon
* @returns {void}
*/
setLogMessageCallback(level, callback) {
this._addon.td_set_log_message_callback(level, callback);
}
}
export {
TDLibAddon
};