UNPKG

libaria2

Version:

A full-typing wrapper around aria2`, `The next generation download utility`.

1,143 lines (1,117 loc) 39.9 kB
'use strict'; const events = require('events'); const axios = require('axios'); const WebSocket = require('isomorphic-ws'); const crypto$1 = require('crypto'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const axios__default = /*#__PURE__*/_interopDefaultCompat(axios); const WebSocket__default = /*#__PURE__*/_interopDefaultCompat(WebSocket); function valueFromBoolean(val) { return val.toString(); } function valueFrombigint(val) { return val.toString(); } function valueFromnumber(val) { return val.toString(); } function valueToBoolean(val) { if (/^(false|true)$/.test(val)) { if (val == "true") { return true; } else { return false; } } else { throw "Unknown Boolean Value: " + val; } } function valueTonumber(val) { return Number(val); } function valueTobigint(val) { return BigInt(val); } function fromTAria2ClientInputOption(v) { let o = {}; for (const k in v) { if (v[k] != void 0) { if (typeof v[k] == "string") { o[k] = v[k]; } else if (typeof v[k] == "boolean") { o[k] = valueFromBoolean(v[k]); } else if (typeof v[k] == "number") { o[k] = valueFromnumber(v[k]); } else if (typeof v[k] == "bigint") { o[k] = valueFrombigint(v[k]); } else { throw "Unknown Value: " + v[k]; } } } return o; } function intoTAria2ClientInputOption(v) { let o = {}; for (const k in v) { if (v[k] != void 0) { if (typeof v[k] == "string") { o[k] = v[k]; } else if (typeof v[k] == "boolean") { o[k] = valueToBoolean(v[k]); } else if (typeof v[k] == "number") { o[k] = valueTonumber(v[k]); } else if (typeof v[k] == "bigint") { o[k] = valueTobigint(v[k]); } else { throw "Unknown Value: " + v[k]; } } } return o; } function intoIAria2DownloadStatus(v) { let o = Object.assign({}, v); if (v.totalLength != void 0) o.totalLength = valueTobigint(v.totalLength); if (v.totalLength != void 0) o.completedLength = valueTobigint(v.completedLength); if (v.totalLength != void 0) o.uploadLength = valueTobigint(v.uploadLength); if (v.totalLength != void 0) o.downloadSpeed = valueTobigint(v.downloadSpeed); if (v.totalLength != void 0) o.uploadSpeed = valueTobigint(v.uploadSpeed); if (v.numSeeders != void 0) { o.numSeeders = valueTobigint(v.numSeeders); } if (v.seeder != void 0) { o.seeder = valueToBoolean(v.seeder); } if (v.totalLength != void 0) o.pieceLength = valueTobigint(v.pieceLength); if (v.totalLength != void 0) o.numPieces = valueTobigint(v.numPieces); if (v.totalLength != void 0) o.connections = valueTobigint(v.connections); if (v.errorCode != void 0) { o.errorCode = valueTonumber(v.errorCode); } if (v.bittorrent != void 0) { if (v.bittorrent.creationDate != void 0) { o.bittorrent.creationDate = valueTobigint(v.bittorrent.creationDate); } } if (v.files != void 0) for (const l in v.files) { o.files[l] = intoIAria2FileStatus(v.files[l]); } return o; } function intoIAria2FileStatus(v) { let o = Object.assign({}, v); o.length = valueTobigint(v.length); o.completedLength = valueTobigint(v.completedLength); o.index = valueTonumber(v.index); o.selected = valueToBoolean(v.selected); return o; } function intoIAria2PeersInfo(v) { let o = Object.assign({}, v); o.amChoking = valueToBoolean(v.amChoking); o.downloadSpeed = valueTobigint(v.downloadSpeed); o.peerChoking = valueToBoolean(v.peerChoking); o.port = valueTonumber(v.port); o.seeder = valueToBoolean(v.seeder); o.uploadSpeed = valueTobigint(v.uploadSpeed); return o; } function intoIAria2ServerInfo(v) { let o = Object.assign({}, v); o.downloadSpeed = valueTobigint(v.downloadSpeed); return o; } function intoIAria2ServersInfoItem(v) { let o = Object.assign({}, v); o.index = valueTonumber(v.index); for (const k in v.servers) { o.servers[k] = intoIAria2ServerInfo(v.servers[k]); } return o; } function intoIAria2GlobalStat(v) { let o = Object.assign({}, v); o.downloadSpeed = valueTobigint(v.downloadSpeed); o.uploadSpeed = valueTobigint(v.uploadSpeed); o.numActive = valueTonumber(v.numActive); o.numWaiting = valueTonumber(v.numWaiting); o.numStopped = valueTonumber(v.numStopped); o.numStoppedTotal = valueTonumber(v.numStoppedTotal); return o; } var Base64; ((Base642) => { function atob(val) { return Buffer.from(val, "base64").toString(); } Base642.atob = atob; function btoa(val) { return Buffer.from(val).toString("base64"); } Base642.btoa = btoa; })(Base64 || (Base64 = {})); const isNode = () => { if (typeof globalThis?.process?.versions?.node == "string") { return true; } else return false; }; class Aria2ClientBaseClass extends events.EventEmitter { /** * @constructor * @param options Options for creating a client. */ constructor() { super(); } /** * This method adds a Metalink download by uploading a ".metalink" file. metalink is a base64-encoded string which contains the contents of the ".metalink" file. options is a struct and its members are pairs of option name and value. See Options below for more details. If position is given, it must be an integer starting from 0. The new download will be inserted at position in the waiting queue. If position is omitted or position is larger than the current size of the queue, the new download is appended to the end of the queue. This method returns an array of GIDs of newly registered downloads. If `--rpc-save-upload-metadata` is `true`, the uploaded data is saved as a file named hex string of SHA-1 hash of data plus ".metalink" in the directory specified by `--dir` option. E.g. a file name might be `0a3893293e27ac0490424c06de4d09242215f0a6.metalink`. If a file with the same name already exists, it is overwritten! If the file cannot be saved successfully or `--rpc-save-upload-metadata` is `false`, the downloads added by this method are not saved by `--save-session`. * * @example * ```ts * await aria2.addMetalink("....."); * ``` * @returns TAria2ClientGID[] */ async addMetalink(metalink, options, position) { if (isNode()) { if (metalink instanceof Buffer) metalink = metalink.toString("base64"); } let args = [metalink]; if (options != void 0) args.push(options); if (options != void 0 && position != void 0) args.push(position); else if (position != void 0) throw "Require `options`!"; return await this.rawCall( "aria2.addMetalink", ...args ); } /** * This method removes the download denoted by gid (string). If the specified download is in progress, it is first stopped. The status of the removed download becomes removed. This method returns GID of `removed` download. * * The following examples remove a download with GID#2089b05ecca3d829. * @example * ```ts * await aria2.remove('2089b05ecca3d829') * ```` * @returns TAria2ClientGID */ async remove(gid) { return await this.rawCall( "aria2.remove", gid ); } /** * This method removes the download denoted by gid. This method behaves just like `aria2.remove()` except that this method removes the download without performing any actions which take time, such as contacting BitTorrent trackers to unregister the download first. * @returns TAria2ClientGID */ async forceRemove(gid) { return await this.rawCall( "aria2.forceRemove", gid ); } /** * This method pauses the download denoted by gid (string). The status of paused download becomes `paused`. If the download was active, the download is placed in the front of waiting queue. While the status is `paused`, the download is not started. To change status to waiting, use the `aria2.unpause()` method. This method returns GID of paused download. * @returns TAria2ClientGID */ async pause(gid) { return await this.rawCall( "aria2.pause", gid ); } /** * This method pauses the download denoted by gid. This method behaves just like `aria2.pause()` except that this method pauses downloads without performing any actions which take time, such as contacting BitTorrent trackers to unregister the download first. * @returns TAria2ClientGID */ async forcePause(gid) { return await this.rawCall( "aria2.forcePause", gid ); } /** * This method is equal to calling `aria2.pause()` for every active/waiting download. This methods returns `OK`. * @returns TAria2PauseAllResult */ async pauseAll() { return await this.rawCall("aria2.pauseAll"); } /** * This method is equal to calling `aria2.forcePause()` for every active/waiting download. This methods returns `OK`. * @returns TAria2PauseAllResult */ async forcePauseAll() { return await this.rawCall( "aria2.forcePauseAll" ); } /** * This method changes the status of the download denoted by gid (string) from `paused` to `waiting`, making the download eligible to be restarted. This method returns the GID of the unpaused download. * @returns TAria2ClientGID */ async unpause(gid) { return await this.rawCall( "aria2.unpause", gid ); } /** * This method is equal to calling `aria2.unpause()` for every paused download. This methods returns `OK`. * @returns TAria2PauseAllResult */ async unpauseAll() { return await this.rawCall("aria2.unpauseAll"); } async tellStatus(gid, keys) { if (keys != void 0) { let resp = await this.rawCall( "aria2.tellStatus", gid, keys ); return intoIAria2DownloadStatus(resp); } else { let resp = await this.rawCall("aria2.tellStatus", gid); return intoIAria2DownloadStatus(resp); } } /** * This method returns the URIs used in the download denoted by gid (string). The response is an array of structs and it contains following keys. Values are string. * @returns IAria2UriStatus[] */ async getUris(gid) { return await this.rawCall( "aria2.getUris", gid ); } /** * This method returns the file list of the download denoted by gid (string). The response is an array of structs which contain following keys. Values are strings. * @returns IAria2FileStatus[] */ async getFiles(gid) { return await this.rawCall( "aria2.getFiles", gid ); } /** * This method returns a list peers of the download denoted by gid (string). This method is for BitTorrent only. The response is an array of structs and contains the following keys. Values are strings. * @returns IAria2PeersInfo[] */ async getPeers(gid) { let resp = await this.rawCall( "aria2.getPeers", gid ); return resp.map(intoIAria2PeersInfo); } /** * This method returns currently connected HTTP(S)/FTP/SFTP servers of the download denoted by gid (string). The response is an array of structs and contains the following keys. Values are strings. * @returns TAria2ServersInfo */ async getServers(gid) { let resp = await this.rawCall( "aria2.getServers", gid ); return resp.map(intoIAria2ServersInfoItem); } async tellActive(keys) { if (keys != void 0) { let resp = await this.rawCall( "aria2.tellActive", keys ); return resp.map(intoIAria2DownloadStatus); } else { let resp = await this.rawCall("aria2.tellActive"); return resp.map(intoIAria2DownloadStatus); } } async tellWaiting(offset, num, keys) { if (keys != void 0) { let resp = await this.rawCall( "aria2.tellWaiting", offset, num, keys ); return resp.map(intoIAria2DownloadStatus); } else { let resp = await this.rawCall( "aria2.tellWaiting", offset, num ); return resp.map(intoIAria2DownloadStatus); } } async tellStopped(offset, num, keys) { if (keys != void 0) { let resp = await this.rawCall( "aria2.tellStopped", offset, num, keys ); return resp.map(intoIAria2DownloadStatus); } else { let resp = await this.rawCall( "aria2.tellStopped", offset, num ); return resp.map(intoIAria2DownloadStatus); } } /** * This method changes the position of the download denoted by gid in the queue. pos is an integer. how is a string. If how is `POS_SET`, it moves the download to a position relative to the beginning of the queue. If how is `POS_CUR`, it moves the download to a position relative to the current position. If how is `POS_END`, it moves the download to a position relative to the end of the queue. If the destination position is less than 0 or beyond the end of the queue, it moves the download to the beginning or the end of the queue respectively. The response is an integer denoting the resulting position. (See enum `EAria2ChangePositionHow`) * * For example, if GID#2089b05ecca3d829 is currently in position 3, `aria2.changePosition('2089b05ecca3d829', -1, EAria2ChangePositionHow.Cur)` will change its position to 2. Additionally `aria2.changePosition('2089b05ecca3d829', 0, EAria2ChangePositionHow.Set)` will change its position to 0 (the beginning of the queue). * * The following examples move the download GID#2089b05ecca3d829 to the front of the queue. * @example * ```ts * await aria2.changePosition('2089b05ecca3d829', 0, EAria2ChangePositionHow.Set); * ``` * @returns TAria2ChangePositionResult */ async changePosition(gid, pos, how) { return await this.rawCall( "aria2.changePosition", gid, pos, how ); } /** * This method removes the URIs in delUris from and appends the URIs in addUris to download denoted by gid. delUris and addUris are lists of strings. A download can contain multiple files and URIs are attached to each file. fileIndex is used to select which file to remove/attach given URIs. fileIndex is 1-based. position is used to specify where URIs are inserted in the existing waiting URI list. position is 0-based. When position is omitted, URIs are appended to the back of the list. This method first executes the removal and then the addition. position is the position after URIs are removed, not the position when this method is called. When removing an URI, if the same URIs exist in download, only one of them is removed for each URI in delUris. In other words, if there are three URIs `http://example.org/aria2` and you want remove them all, you have to specify (at least) 3 `http://example.org/aria2` in delUris. This method returns a list which contains two integers. The first integer is the number of URIs deleted. The second integer is the number of URIs added. * * The following examples add the URI `http://example.org/file` to the file whose index is `1` and belongs to the download GID#2089b05ecca3d829. * @returns TAria2ChangeUriResult */ async changeUri(gid, fileIndex, delUris, addUris, position) { return await this.rawCall( "aria2.changeUri", gid, fileIndex, delUris, addUris, position ); } /** * This method returns options of the download denoted by gid. The response is a struct where keys are the names of options. The values are strings. Note that this method does not return options which have no default value and have not been set on the command-line, in configuration files or RPC methods. * * The following examples get options of the download GID#2089b05ecca3d829. * @returns TAria2ClientInputOption */ async getOption(gid) { let resp = await this.rawCall( "aria2.getOption", gid ); return intoTAria2ClientInputOption(resp); } /** * This method changes options of the download denoted by gid (string) dynamically. options is a struct. The options listed in Input File subsection are available, **except** for following options: * * - `dry-run` * - `metalink-base-uri` * - `parameterized-uri` * - `pause` * - `piece-length` * - `rpc-save-upload-metadata` * * Except for the following options, changing the other options of active download makes it restart (restart itself is managed by aria2, and no user intervention is required): * * - `bt-max-peers` * - `bt-request-peer-speed-limit` * - `bt-remove-unselected-file` * - `force-save` * - `max-download-limit` * - `max-upload-limit` * This method returns OK for success. * * The following examples set the `max-download-limit` option to 20K for the download GID#2089b05ecca3d829. * * @example * ```ts * await aria2.changeOption(`2089b05ecca3d829`, { * 'max-download-limit': '20K' * }); * ``` * * @returns TAria2ChangeOptionResult */ async changeOption(gid, options) { return await this.rawCall( "aria2.changeOption", gid, fromTAria2ClientInputOption(options) ); } /** * This method returns the global options. The response is a struct. Its keys are the names of options. Values are strings. Note that this method does not return options which have no default value and have not been set on the command-line, in configuration files or RPC methods. Because global options are used as a template for the options of newly added downloads, the response contains keys returned by the `aria2.getOption()` method. * @returns TAria2ClientInputOption */ async getGlobalOption() { let resp = await this.rawCall("aria2.getGlobalOption"); return intoTAria2ClientInputOption(resp); } /** * This method changes global options dynamically. options is a struct. **The following options are available**: * * - `bt-max-open-files` * - `download-result` * - `keep-unfinished-download-result` * - `log` * - `log-level` * - `max-concurrent-downloads` * - `max-download-result` * - `max-overall-download-limit` * - `max-overall-upload-limit` * - `optimize-concurrent-downloads` * - `save-cookies` * - `save-session` * - `server-stat-of` * * In addition, options listed in the Input File subsection are available, **except for following options**: `checksum`, `index-out`, `out`, `pause` and s`elect-file`. * * With the log option, you can dynamically start logging or change log file. To stop logging, specify an empty string("") as the parameter value. Note that log file is always opened in append mode. This method returns OK for success. * * @returns TAria2ChangeOptionResult */ async changeGlobalOption(options) { return await this.rawCall( "aria2.changeGlobalOption", fromTAria2ClientInputOption(options) ); } /** * This method returns global statistics such as the overall download and upload speeds. * @returns IAria2GlobalStat */ async getGlobalStat() { let resp = await this.rawCall("aria2.getGlobalStat"); return intoIAria2GlobalStat(resp); } /** * This method purges completed/error/removed downloads to free memory. This method returns `OK`. * @returns TAria2PurgeDownloadResult */ async purgeDownloadResult() { return await this.rawCall( "aria2.purgeDownloadResult" ); } /** * This method removes a completed/error/removed download denoted by gid from memory. This method returns `OK` for success. * * The following examples remove the download result of the download GID#2089b05ecca3d829. * * @example * ```ts * await aria2.removeDownloadResult('2089b05ecca3d829'); * ``` * * @returns TAria2RemoveDownloadResult */ async removeDownloadResult(gid) { return await this.rawCall( "aria2.removeDownloadResult", gid ); } /** * This method returns the version of aria2 and the list of enabled features. The response is a struct and contains following keys. * * @example * ```ts * await aria2.getVersion(); * ``` * @returns IAria2Version */ async getVersion() { return await this.rawCall("aria2.getVersion"); } /** * This method shuts down aria2. This method returns `OK`. * * @example * ```ts * await aria2.shutdown(); * ``` * @returns TAria2ShutdownResult */ async shutdown() { return await this.rawCall("aria2.shutdown"); } /** * This method shuts down aria2. This method behaves like function `aria2.shutdown()` without performing any actions which take time, such as contacting BitTorrent trackers to unregister downloads first. This method returns `OK`. * @example * ```ts * await aria2.forceShutdown(); * ``` * @returns TAria2ShutdownResult */ async forceShutdown() { return await this.rawCall("aria2.forceShutdown"); } /** * This method saves the current session to a file specified by the `--save-session` option. This method returns `OK` if it succeeds. * @example * ```ts * await aria2.saveSession(); * ``` * @returns TAria2SaveSessionResult */ async saveSession() { return await this.rawCall("aria2.saveSession"); } /** * This method returns session information. The response is a struct and contains following key. * @example * ```ts * await aria2.saveSession(); * ``` * @returns TAria2SaveSessionResult */ async getSessionInfo() { return await this.rawCall( "aria2.getSessioninfo" ); } /** * This method adds a new download. uris is an array of HTTP/FTP/SFTP/BitTorrent URIs (strings) pointing to the same resource. If you mix URIs pointing to different resources, then the download may fail or be corrupted without aria2 complaining. When adding BitTorrent Magnet URIs, uris must have only one element and it should be BitTorrent Magnet URI. options is a struct and its members are pairs of option name and value. See Options below for more details. If position is given, it must be an integer starting from 0. The new download will be inserted at position in the waiting queue. If position is omitted or position is larger than the current size of the queue, the new download is appended to the end of the queue. This method returns the GID of the newly registered download. * @param position `>= 0` * @example * ```ts * await aria2.addUri('http://example.org/file', {}, 0); * ``` * @returns TAria2ClientGID */ async addUri(uris, options, position) { if (typeof uris == "string") uris = [uris]; let args = [uris]; if (options != void 0) args.push(fromTAria2ClientInputOption(options)); if (options != void 0 && position != void 0) args.push(position); else if (position != void 0) throw "Require `options`!"; return await this.rawCall("aria2.addUri", ...args); } /** * This method adds a BitTorrent download by uploading a ".torrent" file. If you want to add a BitTorrent Magnet URI, use the `aria2.addUri()` method instead. torrent must be a base64-encoded string containing the contents of the ".torrent" file. uris is an array of URIs (string). uris is used for Web-seeding. For single file torrents, the URI can be a complete URI pointing to the resource; if URI ends with /, name in torrent file is added. For multi-file torrents, name and path in torrent are added to form a URI for each file. options is a struct and its members are pairs of option name and value. See Options below for more details. If position is given, it must be an integer starting from 0. The new download will be inserted at position in the waiting queue. If position is omitted or position is larger than the current size of the queue, the new download is appended to the end of the queue. This method returns the GID of the newly registered download. If `--rpc-save-upload-metadata` is `true`, the uploaded data is saved as a file named as the hex string of SHA-1 hash of data plus ".torrent" in the directory specified by `--dir` option. E.g. a file name might be `0a3893293e27ac0490424c06de4d09242215f0a6.torrent`. If a file with the same name already exists, it is overwritten! If the file cannot be saved successfully or `--rpc-save-upload-metadata` is `false`, the downloads added by this method are not saved by `--save-session`. * @param position `>= 0` * @example * ```ts * let torrent = fs.readFileSync('./file.torrent'); * await aria2.addTorrent(torrent); * ``` * @returns TAria2ClientGID */ async addTorrent(torrent, uris, options, position) { if (torrent instanceof Buffer) torrent = torrent.toString("base64"); if (typeof uris == "string") uris = [uris]; let args = [torrent, uris]; if (options != void 0) args.push(options); if (options != void 0 && position != void 0) args.push(position); else if (position != void 0) throw "Require `options`!"; return await this.rawCall("aria2.addTorrent", ...args); } addListener(event, listener) { super.on(event, listener); return this; } on(event, listener) { super.on(event, listener); return this; } once(event, listener) { super.once(event, listener); return this; } } var EAria2ChangePositionHow = /* @__PURE__ */ ((EAria2ChangePositionHow2) => { EAria2ChangePositionHow2["Set"] = "POS_SET"; EAria2ChangePositionHow2["Cur"] = "POS_CUR"; EAria2ChangePositionHow2["End"] = "POS_END"; return EAria2ChangePositionHow2; })(EAria2ChangePositionHow || {}); var EAria2DownloadState = /* @__PURE__ */ ((EAria2DownloadState2) => { EAria2DownloadState2["Active"] = "active"; EAria2DownloadState2["Waiting"] = "waiting"; EAria2DownloadState2["Paused"] = "paused"; EAria2DownloadState2["Error"] = "error"; EAria2DownloadState2["Complete"] = "complete"; EAria2DownloadState2["Removed"] = "removed"; return EAria2DownloadState2; })(EAria2DownloadState || {}); var EAria2UriStatusEnum = /* @__PURE__ */ ((EAria2UriStatusEnum2) => { EAria2UriStatusEnum2["Waiting"] = "waiting"; EAria2UriStatusEnum2["Used"] = "used"; return EAria2UriStatusEnum2; })(EAria2UriStatusEnum || {}); var EAria2DownloadBitTorrentMode = /* @__PURE__ */ ((EAria2DownloadBitTorrentMode2) => { EAria2DownloadBitTorrentMode2["Single"] = "single"; EAria2DownloadBitTorrentMode2["Multi"] = "multi"; return EAria2DownloadBitTorrentMode2; })(EAria2DownloadBitTorrentMode || {}); class Aria2ClientSystemMethodsBaseClass { /** @ignore */ constructor(client) { this._client = client; } } const adapter = { __proto__: null, Aria2ClientBaseClass: Aria2ClientBaseClass, Aria2ClientSystemMethodsBaseClass: Aria2ClientSystemMethodsBaseClass, EAria2ChangePositionHow: EAria2ChangePositionHow, EAria2DownloadBitTorrentMode: EAria2DownloadBitTorrentMode, EAria2DownloadState: EAria2DownloadState, EAria2UriStatusEnum: EAria2UriStatusEnum }; // Unique ID creation requires a high quality random # generator. In the browser we therefore // require the crypto API and do not support built-in fallback to lower quality random number // generators (like Math.random()). let getRandomValues; const rnds8$1 = new Uint8Array(16); function rng() { // lazy load so that environments that need to polyfill have a chance to do so if (!getRandomValues) { // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); if (!getRandomValues) { throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } return getRandomValues(rnds8$1); } /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ const byteToHex = []; for (let i = 0; i < 256; ++i) { byteToHex.push((i + 0x100).toString(16).slice(1)); } function unsafeStringify(arr, offset = 0) { // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); } const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); const native = { randomUUID }; function v4(options, buf, offset) { if (native.randomUUID && !buf && !options) { return native.randomUUID(); } options = options || {}; const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = rnds[6] & 0x0f | 0x40; rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided if (buf) { offset = offset || 0; for (let i = 0; i < 16; ++i) { buf[offset + i] = rnds[i]; } return buf; } return unsafeStringify(rnds); } const btoa = (() => { if (isNode()) { return Base64.btoa; } else if (globalThis.btoa != void 0) { return globalThis.btoa; } else { throw new Error("`btoa()` is not defined!"); } })(); (() => { if (isNode()) { return Base64.atob; } else if (globalThis.atob != void 0) { return globalThis.atob; } else { throw new Error("`atob()` is not defined!"); } })(); const rnds8 = new Uint8Array(16); const uuid = () => { return v4({ rng: () => crypto$1.webcrypto.getRandomValues(rnds8) }); }; exports.WebSocket = void 0; ((RpcWebSocket2) => { class Client extends Aria2ClientBaseClass { constructor(options) { super(); /** @ignore @internal */ this._cbs = /* @__PURE__ */ new Map(); /** @ignore @internal */ this._open_cbs = []; /** @ignore @internal */ this._opened = false; /** @ignore @internal */ this._systemMethods = new SystemMethods(this); this._options = Object.assign({}, options); this._conn = new WebSocket__default( `${options.protocol ?? "ws"}://${options.host}:${options.port}${options.path ?? "/jsonrpc"}`, (() => { if (isNode()) { return options.wsOptions ?? {}; } else { return void 0; } })() ); this._conn.onclose = () => { this.emit("ws.close"); this._opened = false; this._open_cbs = []; }; this._conn.onopen = () => { this.emit("ws.open"); this._opened = true; while (this._open_cbs.length > 0) { let cb = this._open_cbs.pop(); if (cb != void 0 && this._conn.readyState == 1) { cb(); } } }; this._conn.onmessage = (event) => { const data = event?.type == "message" || isNode() ? event.data : event; try { this.emit("ws.message", data); let message = JSON.parse(data.toString()); if (message instanceof Array) { let cb = this._cbs.get(message[0].id); if (cb != void 0) { cb(message); } this._cbs.delete(message[0].id); } else if (message.id != void 0 && this._cbs.has(message?.id)) { let cb = this._cbs.get(message.id); if (cb != void 0) { cb(message); } this._cbs.delete(message.id); } else if (message.method != void 0) { switch (message?.method) { case "aria2.onDownloadStart": this.emit( "aria2.onDownloadStart", ...message.params ?? [] ); break; case "aria2.onDownloadPause": this.emit( "aria2.onDownloadPause", ...message.params ?? [] ); break; case "aria2.onDownloadStop": this.emit( "aria2.onDownloadStop", ...message.params ?? [] ); break; case "aria2.onDownloadComplete": this.emit( "aria2.onDownloadComplete", ...message.params ?? [] ); break; case "aria2.onDownloadError": this.emit( "aria2.onDownloadError", ...message.params ?? [] ); break; case "aria2.onBtDownloadComplete": this.emit( "aria2.onBtDownloadComplete", ...message.params ?? [] ); break; } } } catch (e) { this.$errorHandle(e); throw e; } }; } /** @ignore @internal */ $errorHandle(e) { } /** * ## Wait WebSocket Open * @ignore @internal * @returns Promise<void> */ _waitOpened() { return new Promise((r, j) => { if (this._opened && this._conn.readyState == 1) { r(); } else if (this._conn.readyState < 1 && this._conn.readyState > 1) { j(this._conn.readyState); } else { this._open_cbs.push(r); } }); } /** * ## Send raw data * @ignore @internal * @param data Data to be sent */ _sendRaw(data) { return new Promise((r, j) => { try { this._conn.send(data); } catch (e) { j(e); } }); } /** @ignore @internal */ _sendJson(method, ...params) { return new Promise(async (r, j) => { await this._waitOpened(); let id = uuid(); let msg = { jsonrpc: "2.0", id, method, params: [] }; if (this._options?.auth?.secret != void 0) { msg.params.push("token:" + this._options.auth.secret); } msg.params = [...msg.params, ...params]; this._cbs.set(id, r); this._sendRaw(JSON.stringify(msg)).catch(j); }); } get system() { return this._systemMethods; } async rawCall(methods, ...args) { let resp = await this._sendJson(methods, ...args); if (resp.error != void 0) { throw resp.error; } else { return resp.result; } } async rawSend(data) { return await this._sendRaw(data); } async getCreateOptions() { return Object.freeze(this._options); } /** * Close the WebSocket Connection. * @param code Disconnect Code * @param data Some string */ async close(code, data) { this._conn.close(code, data); return; } on(event, listener) { super.on(event, listener); return this; } once(event, listener) { super.once(event, listener); return this; } addListener(event, listener) { super.on(event, listener); return this; } } RpcWebSocket2.Client = Client; class SystemMethods extends Aria2ClientSystemMethodsBaseClass { async listMethods() { return await this._client.rawCall( "system.listMethods" ); } async listNotifications() { return await this._client.rawCall( "system.listNotifications" ); } multicall(...items) { return new Promise(async (rr, j) => { let firstid = uuid(); let first = false; let sec = []; let options = await this._client.getCreateOptions(); if (options?.auth?.secret != void 0) { sec.push("token:" + options?.auth?.secret); } let s = []; for (const i of items) { if (first != true) { s.push({ jsonrpc: "2.0", id: firstid, method: i.methodName, params: [...sec, ...i.params] }); first = true; } else { s.push({ jsonrpc: "2.0", id: uuid(), method: i.methodName, params: [...sec, ...i.params] }); } } await this._client._waitOpened(); this._client._cbs.set(firstid, (data) => { let out = []; for (const d of data) { if (d.error != void 0) { out.push(Promise.reject(d.error)); } else { out.push(Promise.resolve(d.result)); } } rr(out); }); this._client.rawSend(JSON.stringify(s)).catch(j); }); } } RpcWebSocket2.SystemMethods = SystemMethods; })(exports.WebSocket || (exports.WebSocket = {})); exports.Http = void 0; ((RpcHttp2) => { class Client extends Aria2ClientBaseClass { constructor(options) { super(); this._options = options; this._system = new SystemMethods(this); } get system() { return this._system; } async rawCall(methods, ...args) { let id = uuid(); let arg = [...args]; if (this._options?.auth?.secret != void 0) { arg.push("token:" + this._options.auth.secret); } let url = `${this._options.protocol ?? "http"}://${this._options.host}:${this._options.port}/jsonrpc?method=${decodeURIComponent(methods)}&id=${decodeURIComponent( id )}&params=${btoa(JSON.stringify(arg))}`; let rsp = await axios__default(url, { method: "GET", ...this._options.fetchOptions }); let j = rsp.data; if (j.error == void 0) { return j.result; } else { throw j.error; } } async rawSend(data) { throw new Error("Method not implemented."); } async getCreateOptions() { return this._options; } } RpcHttp2.Client = Client; class SystemMethods extends Aria2ClientSystemMethodsBaseClass { async multicall(...items) { let rvers = {}; let args = []; let prs = []; let op = await this._client.getCreateOptions(); for (const i of items) { let id = uuid(); let a = []; if (op?.auth?.secret != void 0) a.push(op?.auth?.secret); args.push({ jsonrpc: "2.0", id, params: [...a, ...i.params], method: i.methodName }); prs.push( new Promise((r, j) => { rvers[id] = { r, j }; }) ); } new Promise(async () => { let url = `${op.protocol ?? "http"}://${op.host}:${op.port}/jsonrpc?method=&id=&params=${btoa(JSON.stringify(args))}`; let rep = await axios__default(url, { method: "GET", ...op.fetchOptions }); for (const r of rep.data) { if (r.id != void 0 && rvers[r.id] != void 0) { if (r.error != void 0) { rvers[r.id].j(r.error); } else { rvers[r.id].r(r.result); } } } }); return prs; } async listMethods() { return await this._client.rawCall( "system.listMethods" ); } async listNotifications() { return await this._client.rawCall( "system.listNotifications" ); } } RpcHttp2.SystemMethods = SystemMethods; })(exports.Http || (exports.Http = {})); exports.Adapter = adapter;