@ -0,0 +1,5 @@ | |||||
DB_HOST = database | |||||
DB_PORT = 3306 | |||||
DB_USER = root | |||||
DB_PASSWORD_FILE = /run/secrets/mysql_root_password | |||||
DB_DATABASE = autoplex_torrent |
@ -0,0 +1,3 @@ | |||||
# Autoplex Torrent Client | |||||
The torrent client for Autoplex. |
@ -0,0 +1,6 @@ | |||||
{ | |||||
"watch": ["src"], | |||||
"ext": "ts,json", | |||||
"ignore": ["src/**/*.spec.ts"], | |||||
"exec": "node --inspect=0.0.0.0:9229 -r ts-node/register src/index.ts" | |||||
} |
@ -0,0 +1,7 @@ | |||||
{ | |||||
"cli": { | |||||
"entitiesDir": "src/database/entities", | |||||
"migrationsDir": "src/database/migrations", | |||||
"subscribersDir": "src/database/subscribers" | |||||
} | |||||
} |
@ -0,0 +1,44 @@ | |||||
{ | |||||
"name": "@autoplex-service/torrent", | |||||
"version": "0.0.1", | |||||
"description": "A dedicated torrent client for Autoplex", | |||||
"main": "./dist/index.js", | |||||
"scripts": { | |||||
"clean": "rimraf ./dist", | |||||
"build": "tsc", | |||||
"start": "NODE_ENV=production; node .", | |||||
"start:dev": "nodemon", | |||||
"test": "echo \"Error: no test specified\" && exit 1", | |||||
"postinstall": "patch-package" | |||||
}, | |||||
"keywords": [], | |||||
"author": "David Ludwig", | |||||
"license": "ISC", | |||||
"devDependencies": { | |||||
"@types/glob": "^7.1.3", | |||||
"@types/node": "^14.14.37", | |||||
"@types/parse-torrent": "^5.8.3", | |||||
"@types/rimraf": "^3.0.0", | |||||
"@types/websocket": "^1.0.2", | |||||
"nodemon": "^2.0.7", | |||||
"postinstall-postinstall": "^2.1.0", | |||||
"ts-node": "^9.1.1", | |||||
"typescript": "^4.2.3" | |||||
}, | |||||
"dependencies": { | |||||
"@autoplex-api/torrent": "^0.0.0", | |||||
"@autoplex/ipc": "^0.0.0", | |||||
"@autoplex/microservice": "^0.0.0", | |||||
"@autoplex/utils": "^0.0.0", | |||||
"bitfield": "^4.0.0", | |||||
"mysql": "^2.18.1", | |||||
"node-ipc": "^9.1.4", | |||||
"parse-torrent": "^9.1.3", | |||||
"patch-package": "^6.4.7", | |||||
"reflect-metadata": "^0.1.13", | |||||
"rimraf": "^3.0.2", | |||||
"typeorm": "^0.2.32", | |||||
"websocket": "^1.0.33", | |||||
"webtorrent-hybrid": "^4.0.3" | |||||
} | |||||
} |
@ -0,0 +1,26 @@ | |||||
diff --git a/node_modules/webtorrent/lib/file.js b/node_modules/webtorrent/lib/file.js | |||||
index caa395d..80234de 100644 | |||||
--- a/node_modules/webtorrent/lib/file.js | |||||
+++ b/node_modules/webtorrent/lib/file.js | |||||
@@ -21,6 +21,7 @@ class File extends EventEmitter { | |||||
this.length = file.length | |||||
this.offset = file.offset | |||||
+ this.isSelected = true | |||||
this.done = false | |||||
const start = file.offset | |||||
@@ -85,11 +86,13 @@ class File extends EventEmitter { | |||||
select (priority) { | |||||
if (this.length === 0) return | |||||
+ this.isSelected = true | |||||
this._torrent.select(this._startPiece, this._endPiece, priority) | |||||
} | |||||
deselect () { | |||||
if (this.length === 0) return | |||||
+ this.isSelected = false | |||||
this._torrent.deselect(this._startPiece, this._endPiece, false) | |||||
} | |||||
@ -0,0 +1,29 @@ | |||||
export interface ISerializedFile { | |||||
path : string; | |||||
size : number; | |||||
downloaded: number; | |||||
progress : number; | |||||
selected : boolean; | |||||
} | |||||
export interface ISerializedTorrent { | |||||
name : string; | |||||
infoHash : string; | |||||
downloaded : number; | |||||
uploaded : number; | |||||
ratio : number; | |||||
size : number; | |||||
downloadSpeed: number; | |||||
uploadSpeed : number; | |||||
numPeers : number; | |||||
progress : number; | |||||
path : string; | |||||
state : TorrentState; | |||||
files : ISerializedFile[]; | |||||
} | |||||
export enum TorrentState { | |||||
Ready = 0x1, | |||||
Paused = 0x2, | |||||
Done = 0x4 | |||||
} |
@ -0,0 +1,73 @@ | |||||
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
@Entity() | |||||
export default class Torrent extends BaseEntity | |||||
{ | |||||
static fromWebTorrent(torrent: WebTorrent.Torrent) { | |||||
let entity = new Torrent(); | |||||
entity.infoHash = torrent.infoHash; | |||||
entity.torrentFile = torrent.torrentFile; | |||||
entity.setSelectedFiles(torrent.files); | |||||
entity.downloadPath = torrent.path; | |||||
return entity; | |||||
} | |||||
@PrimaryGeneratedColumn() | |||||
id!: number; | |||||
@Column() | |||||
infoHash!: string; | |||||
@Column("mediumblob") | |||||
torrentFile!: Buffer; | |||||
@Column({nullable: true}) | |||||
selectOnly?: string; | |||||
@Column() | |||||
downloadPath!: string; | |||||
/** | |||||
* Get the list of selected files | |||||
*/ | |||||
selectedFiles() { | |||||
let result: number[] = []; | |||||
for (let range of (this.selectOnly ?? "").split(',')) { | |||||
// @TODO Check this map function... it's weird | |||||
let [index, end] = range.split('-').map(num => parseInt(num)); | |||||
do { | |||||
result.push(index); | |||||
} while(index++ < end); | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* Update the selected files from the torrent | |||||
*/ | |||||
setSelectedFiles(files: WebTorrent.TorrentFile[]) { | |||||
let ranges: string[] = []; | |||||
let offset: number | null = null; | |||||
let range: number = 0; | |||||
files.forEach((file, i) => { | |||||
if (file.isSelected) { | |||||
if (offset === null) { | |||||
offset = i; | |||||
range = 0; | |||||
} else { | |||||
range++; | |||||
} | |||||
} else { | |||||
if (offset !== null) { | |||||
ranges.push(offset + (range > 0 ? `-${offset + range}` : "")); | |||||
offset = null; | |||||
} | |||||
} | |||||
}); | |||||
if (offset !== null) { | |||||
ranges.push(offset + (range > 0 ? `-${offset + range}` : "")); | |||||
} | |||||
this.selectOnly = ranges.join(','); | |||||
} | |||||
} |
@ -0,0 +1,5 @@ | |||||
import Torrent from "./Torrent"; | |||||
export default [ | |||||
Torrent | |||||
]; |
@ -0,0 +1,18 @@ | |||||
import { createConnection } from "typeorm"; | |||||
import entities from "./entities"; | |||||
export default async function connectToDatabase(host: string, port: number, username: string, | |||||
password: string, database: string) | |||||
{ | |||||
return createConnection({ | |||||
type: "mysql", | |||||
host, | |||||
port, | |||||
username, | |||||
password, | |||||
database, | |||||
synchronize: true, | |||||
entities, | |||||
migrations: ["src/migrations/*.ts"] | |||||
}); | |||||
} |
@ -0,0 +1,11 @@ | |||||
import { Microservice } from "@autoplex/microservice"; | |||||
import * as services from "./services"; | |||||
// Create the application | |||||
let app = new Microservice(); | |||||
// Install the services | |||||
app.installServices(Object.values(services)); | |||||
// Execute the app | |||||
app.exec().then(process.exit); |
@ -0,0 +1,36 @@ | |||||
import { Connection } from "typeorm"; | |||||
import connectToDatabase from "../database"; | |||||
import { env, secret } from "@autoplex/utils"; | |||||
import { InternalService } from "@autoplex/microservice"; | |||||
export default class Database extends InternalService | |||||
{ | |||||
/** | |||||
* The active database connection | |||||
*/ | |||||
public connection!: Connection; | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Database"; | |||||
/** | |||||
* Boot the database service | |||||
*/ | |||||
public async boot() { | |||||
let host = env("DB_HOST"); | |||||
let port = parseInt(env("DB_PORT")); | |||||
let username = env("DB_USER"); | |||||
let password = await secret(env("DB_PASSWORD_FILE")); | |||||
let database = env("DB_DATABASE"); | |||||
this.connection = await connectToDatabase(host, port, username, password, database); | |||||
} | |||||
/** | |||||
* Shutdown the database service | |||||
*/ | |||||
public async shutdown() { | |||||
await this.connection.close(); | |||||
} | |||||
} |
@ -0,0 +1,114 @@ | |||||
import assert from "assert"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
import TorrentClient from "./TorrentClient"; | |||||
import { IpcServerService } from "@autoplex/ipc"; | |||||
import { SOCKET_PATH } from "@autoplex-api/torrent"; | |||||
type IAddTorrent = string | { | |||||
type: "Buffer", | |||||
data: number[] | |||||
} | |||||
export default class IpcInterface extends IpcServerService | |||||
{ | |||||
/** | |||||
* The torrent client instance | |||||
*/ | |||||
protected torrentClient!: TorrentClient; | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "IPC"; | |||||
/** | |||||
* The path to the socket file | |||||
*/ | |||||
protected readonly SOCKET_PATH = SOCKET_PATH; | |||||
/** | |||||
* Boot the IPC interface | |||||
*/ | |||||
public async boot() { | |||||
this.torrentClient = this.app.service<TorrentClient>("Torrent Client"); | |||||
await super.boot(); | |||||
} | |||||
/** | |||||
* Install the the event handlers | |||||
*/ | |||||
protected installMessageHandlers() { | |||||
this.addMessageHandler("add", this.addTorrent); | |||||
this.addMessageHandler("remove", this.removeTorrent); | |||||
this.addMessageHandler("list", this.listTorrents); | |||||
this.addMessageHandler("details", this.torrentDetails); | |||||
this.torrentClient.on("torrent_finished", this.torrentFinished.bind(this)); | |||||
} | |||||
// Interface Methods --------------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
// protected async addTorrent(torrentInfo: IAddTorrent, downloadPath?: string) { | |||||
protected async addTorrent(payload: { torrent: IAddTorrent, downloadPath?: string }) { | |||||
let torrent: WebTorrent.Torrent; | |||||
if (typeof payload.torrent == "string") { | |||||
torrent = await this.torrentClient.add(payload.torrent, { downloadPath: payload.downloadPath }); | |||||
} else { | |||||
torrent = await this.torrentClient.add(Buffer.from(payload.torrent.data), { downloadPath: payload.downloadPath }); | |||||
} | |||||
return torrent.infoHash; | |||||
} | |||||
/** | |||||
* Remove a torrent from the | |||||
* @param message Add | |||||
*/ | |||||
protected async removeTorrent(torrentId: string) { | |||||
try { | |||||
await this.torrentClient.remove(torrentId); | |||||
} catch(e) {} | |||||
} | |||||
protected async listTorrents() { | |||||
return this.torrentClient.torrents.map(torrent => Object({ | |||||
name: torrent.name, | |||||
infoHash: torrent.infoHash, | |||||
progress: torrent.progress, | |||||
state: this.torrentClient.torrentState(torrent) | |||||
})); | |||||
} | |||||
protected async torrentDetails(torrentIds: string[]) { | |||||
let torrents: WebTorrent.Torrent[]; | |||||
if (torrentIds.length == 0) { | |||||
torrents = this.torrentClient.torrents; | |||||
} else { | |||||
torrents = torrentIds.map(torrentId => { | |||||
let torrent = this.torrentClient.get(torrentId); | |||||
assert(torrent != null, `Unknown torrent ID provided: ${torrentId}`); | |||||
return torrent; | |||||
}); | |||||
} | |||||
return torrents.map(torrent => this.torrentClient.serializeTorrent(torrent)); | |||||
} | |||||
// Subscription Interface Methods -------------------------------------------------------------- | |||||
/** | |||||
* Broadcast a message to the connected clients | |||||
*/ | |||||
// protected broadcast(method: string, ...message: any[]) { | |||||
// for (let socket of <Socket[]>(<any>ipc.server).sockets) { | |||||
// this.server.emit(socket, method, message); | |||||
// } | |||||
// } | |||||
/** | |||||
* Notify connected clients that a torrent has finished | |||||
*/ | |||||
public torrentFinished(torrent: WebTorrent.Torrent) { | |||||
this.broadcast("torrent_finished", torrent.infoHash); | |||||
} | |||||
} |
@ -0,0 +1,298 @@ | |||||
import { InternalService } from "@autoplex/microservice"; | |||||
import assert from "assert"; | |||||
import MagnetUri from "magnet-uri"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
import parseTorrent from "parse-torrent"; | |||||
import { extname, join, sep } from "path"; | |||||
import Torrent from "../database/entities/Torrent"; | |||||
import rimraf from "rimraf"; | |||||
import { ISerializedTorrent, TorrentState } from "../common"; | |||||
import { Database } from "."; | |||||
interface IAddOptions { | |||||
downloadPath?: string; | |||||
extensions?: string | string[]; | |||||
} | |||||
/** | |||||
* Available events in the torrent client | |||||
*/ | |||||
interface TorrentClientEvents { | |||||
"torrent_finished": (torrent: WebTorrent.Torrent) => void; | |||||
} | |||||
/** | |||||
* Declare the event types in the torrent client | |||||
*/ | |||||
export declare interface TorrentClient { | |||||
emit<U extends keyof TorrentClientEvents>( | |||||
event: U, ...args: Parameters<TorrentClientEvents[U]> | |||||
): boolean; | |||||
on<U extends keyof TorrentClientEvents>( | |||||
event: U, listener: TorrentClientEvents[U] | |||||
): this; | |||||
} | |||||
export class TorrentClient extends InternalService | |||||
{ | |||||
/** | |||||
* The current WebTorrent instance (available after boot) | |||||
*/ | |||||
private __webtorrent!: WebTorrent.Instance; | |||||
// --------------------------------------------------------------------------------------------- | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Torrent Client"; | |||||
/** | |||||
* Boot the service | |||||
*/ | |||||
public async boot() { | |||||
this.__webtorrent = new WebTorrent(); | |||||
this.__webtorrent.on("error", error => this.onError(error)); | |||||
this.__webtorrent.on("torrent", torrent => { | |||||
torrent.on("done", () => this.onTorrentFinish(torrent)); | |||||
// torrent.on("download", (...args) => this.onTorrentDownload(torrent, ...args)); | |||||
// torrent.on("upload", (...args) => this.onTorrentUpload(torrent, ...args)); | |||||
torrent.on("error", (...args) => this.onTorrentError(torrent, ...args)); | |||||
torrent.on("noPeers", (...args) => this.onTorrentNoPeers(torrent, ...args)); | |||||
torrent.on("wire", (...args) => this.onTorrentWire(torrent, ...args)); | |||||
}); | |||||
} | |||||
/** | |||||
* @TODO really this is kinda bad putting this here... | |||||
* Start the torrent client | |||||
*/ | |||||
public start() { | |||||
this.loadTorrents(); | |||||
} | |||||
// Event Handling ------------------------------------------------------------------------------ | |||||
/** | |||||
* Invoked when a WebTorrent client error occurs | |||||
*/ | |||||
protected onError(error: string | Error) { | |||||
console.error("A Webtorrent client error occurred:", error); | |||||
} | |||||
/** | |||||
* Invoked when a torrent error occurs | |||||
*/ | |||||
protected onTorrentError(torrent: WebTorrent.Torrent, error: string | Error) { | |||||
console.error("Torrent error occurred:", torrent.name, error); | |||||
Torrent.delete({ infoHash: torrent.infoHash }); | |||||
} | |||||
/** | |||||
* Invoked when a torrent has finished | |||||
*/ | |||||
protected onTorrentFinish(torrent: WebTorrent.Torrent) { | |||||
console.log("Torrent finished:", torrent.name); | |||||
this.emit("torrent_finished", torrent); | |||||
} | |||||
/** | |||||
* @NOTE: Ignoring these two events for performance purposes | |||||
*/ | |||||
// protected onTorrentDownload(torrent: WebTorrent.Torrent, bytes: number) {} | |||||
// protected onTorrentUpload(torrent: WebTorrent.Torrent, bytes: number) {} | |||||
protected onTorrentNoPeers(torrent: WebTorrent.Torrent, announceTypes: "tracker" | "dht") { | |||||
} | |||||
protected onTorrentWire(torrent: WebTorrent.Torrent, wire: any, address: string | undefined) { | |||||
} | |||||
// Torrent Storage ----------------------------------------------------------------------------- | |||||
/** | |||||
* Load the torrents from the database | |||||
*/ | |||||
protected async loadTorrents() { | |||||
let torrents = await Torrent.find(); | |||||
for (let torrent of torrents) { | |||||
try { | |||||
let torrentInfo = parseTorrent(torrent.torrentFile); | |||||
this.addTorrent(torrentInfo, torrent.downloadPath, torrent.selectedFiles()); | |||||
} catch(e) { | |||||
torrent.remove(); | |||||
continue; | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Delete a torrent from storage | |||||
*/ | |||||
protected async deleteTorrent(torrent: WebTorrent.Torrent) { | |||||
return await Torrent.delete({ infoHash: torrent.infoHash }); | |||||
} | |||||
/** | |||||
* Store a torrent in the database | |||||
*/ | |||||
protected async storeTorrent(torrent: WebTorrent.Torrent) { | |||||
return await Torrent.fromWebTorrent(torrent).save(); | |||||
} | |||||
/** | |||||
* Delete the download files from a torrent | |||||
*/ | |||||
protected async removeTorrentFiles(torrent: WebTorrent.Torrent) { | |||||
return new Promise<void>((resolve, reject) => { | |||||
let toRemove = new Set<string>(); | |||||
torrent.files.forEach(file => { | |||||
toRemove.add(file.path.split(sep)[0]); | |||||
}); | |||||
toRemove.forEach(path => { | |||||
rimraf(join(torrent.path, path), (err) => { | |||||
if (err) { | |||||
return reject(err); | |||||
} | |||||
resolve(); | |||||
}); | |||||
}); | |||||
}); | |||||
} | |||||
// Torrent Handling ---------------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
protected addTorrent(torrent: MagnetUri.Instance, downloadPath: string, selectOnly?: number[]) { | |||||
// Select only: Select no files by default due to broken selection mechanism in Webtorrent | |||||
torrent.so = selectOnly ?? []; | |||||
console.log("Torrent added:", torrent.infoHash); | |||||
return this.__webtorrent.add(torrent, { path: downloadPath }); | |||||
} | |||||
/** | |||||
* Remove a torrent from the client | |||||
*/ | |||||
protected removeTorrent(torrent: WebTorrent.Torrent) { | |||||
this.deleteTorrent(torrent); | |||||
// console.log("Torrent removed:", torrent.infoHash); | |||||
this.__webtorrent.remove(torrent); | |||||
} | |||||
/** | |||||
* Select the initial list of files to download on a newly added torrent | |||||
*/ | |||||
protected filterSelectFiles(torrent: WebTorrent.Torrent, extensions?: string | string[]) { | |||||
if (extensions === undefined) { | |||||
torrent.files.forEach(file => file.select()); | |||||
return; | |||||
} | |||||
let exts = new Set(typeof extensions === "string" ? extensions.split(',') : extensions); | |||||
torrent.files.forEach(file => { | |||||
if (exts.has(extname(file.path).slice(1))) { | |||||
file.select(); | |||||
} else { | |||||
file.deselect(); | |||||
} | |||||
}); | |||||
} | |||||
// Torrent Client Interface -------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
public async add(info: string | Buffer, options: IAddOptions = {}) { | |||||
// Parse the torrent | |||||
let torrentInfo = parseTorrent(info); | |||||
assert(typeof torrentInfo.infoHash === "string" && torrentInfo.infoHash.length > 0, "Invalid magnet link provided"); | |||||
// If the torrent already exists, skip it | |||||
assert(this.__webtorrent.get(torrentInfo.infoHash) === null, "Torrent has already been added"); | |||||
// Add the torrent to the client | |||||
let torrent = this.addTorrent(torrentInfo, options.downloadPath ?? "/mnt/storage/Downloads"); | |||||
// When the metadata has beened fetched, select the files to download and store the torrent | |||||
torrent.once("metadata", () => { | |||||
this.filterSelectFiles(torrent, options.extensions); | |||||
this.storeTorrent(torrent); | |||||
console.log(torrent.path); | |||||
}); | |||||
return torrent; | |||||
} | |||||
/** | |||||
* Remove a torrent from the client | |||||
*/ | |||||
public async remove(info: string | Buffer, withData: boolean = false) { | |||||
// Parse the torrent | |||||
let torrentInfo = parseTorrent(info); | |||||
assert(typeof torrentInfo.infoHash === "string"); | |||||
// Get the torrent and ensure it exists it exists | |||||
let torrent = this.__webtorrent.get(torrentInfo.infoHash); | |||||
assert(torrent !== null, "Torrent has not been added"); | |||||
// Remove the torrent | |||||
this.removeTorrent(torrent); | |||||
// Delete data if necessary | |||||
if (withData) { | |||||
this.removeTorrentFiles(torrent); | |||||
} | |||||
} | |||||
public has(infoHash: string) { | |||||
return this.__webtorrent.get(infoHash) != null; | |||||
} | |||||
public get(infoHash: string) { | |||||
return this.__webtorrent.get(infoHash); | |||||
} | |||||
public torrentState(torrent: WebTorrent.Torrent) { | |||||
let state = 0; | |||||
state |= <number>(torrent.ready && TorrentState.Ready); | |||||
state |= <number>(torrent.paused && TorrentState.Paused); | |||||
state |= <number>(torrent.done && TorrentState.Done); | |||||
return <TorrentState>state; | |||||
} | |||||
public serializeTorrent(torrent: WebTorrent.Torrent) { | |||||
return <ISerializedTorrent>{ | |||||
name: torrent.name, | |||||
infoHash: torrent.infoHash, | |||||
downloaded: torrent.downloaded, | |||||
uploaded: torrent.uploaded, | |||||
ratio: torrent.ratio, | |||||
size: torrent.length, | |||||
downloadSpeed: torrent.downloadSpeed, | |||||
uploadSpeed: torrent.uploadSpeed, | |||||
numPeers: torrent.numPeers, | |||||
progress: torrent.progress, | |||||
path: torrent.path, | |||||
state: this.torrentState(torrent), | |||||
files: torrent.files.map(file => Object({ | |||||
path: file.path, | |||||
size: file.length, | |||||
downloaded: file.downloaded, | |||||
progress: file.progress, | |||||
selected: file.isSelected | |||||
})) | |||||
}; | |||||
} | |||||
get torrents() { | |||||
return this.__webtorrent.torrents; | |||||
} | |||||
} | |||||
export default TorrentClient; |
@ -0,0 +1,9 @@ | |||||
import Database from "./Database"; | |||||
import IpcInterface from "./IpcInterface"; | |||||
import TorrentClient from "./TorrentClient"; | |||||
export { | |||||
Database, | |||||
IpcInterface, | |||||
TorrentClient | |||||
} |
@ -0,0 +1,31 @@ | |||||
declare const MagnetUri: MagnetUri.MagnetUri; | |||||
declare module "magnet-uri" { | |||||
declare namespace MagnetUri { | |||||
interface MagnetUri { | |||||
(uri: string): Instance; | |||||
decode(uri: string): Instance; | |||||
encode(parsed: Instance): string; | |||||
} | |||||
interface Instance extends Object { | |||||
dn?: string | string[]; | |||||
tr?: string | string[]; | |||||
xs?: string | string[]; | |||||
as?: string | string[]; | |||||
ws?: string | string[]; | |||||
kt?: string[]; | |||||
ix?: number | number[]; | |||||
xt?: string | string[]; | |||||
so?: number[]; | |||||
infoHash?: string; | |||||
infoHashBuffer?: Buffer; | |||||
name?: string | string[]; | |||||
keywords?: string | string[]; | |||||
announce?: string[]; | |||||
urlList?: string[]; | |||||
} | |||||
} | |||||
export = MagnetUri; | |||||
} |
@ -0,0 +1,350 @@ | |||||
/// <reference types="node"/> | |||||
declare module "node-ipc" { | |||||
import { Socket } from "net"; | |||||
declare const NodeIPC: NodeIPC.NodeIPC; | |||||
declare namespace NodeIPC { | |||||
interface NodeIPC extends IPC | |||||
{} | |||||
interface IPC { | |||||
/** | |||||
* Set these variables in the ipc.config scope to overwrite or set default values | |||||
*/ | |||||
config: Config; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#log | |||||
*/ | |||||
log(...args: any[]): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connectto | |||||
* Used for connecting as a client to local Unix Sockets and Windows Sockets. | |||||
* This is the fastest way for processes on the same machine to communicate | |||||
* because it bypasses the network card which TCP and UDP must both use. | |||||
* @param id is the string id of the socket being connected to. | |||||
* The socket with this id is added to the ipc.of object when created. | |||||
* @param path is the path of the Unix Domain Socket File, if the System is Windows, | |||||
* this will automatically be converted to an appropriate pipe with the same information as the Unix Domain Socket File. | |||||
* If not set this will default to ipc.config.socketRoot+ipc.config.appspace+id | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectTo(id: string, path?: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connectto | |||||
* Used for connecting as a client to local Unix Sockets and Windows Sockets. | |||||
* This is the fastest way for processes on the same machine to communicate | |||||
* because it bypasses the network card which TCP and UDP must both use. | |||||
* @param id is the string id of the socket being connected to. | |||||
* The socket with this id is added to the ipc.of object when created. | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectTo(id: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. For TCP & TLS sockets, | |||||
* this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param host is the host on which the TCP or TLS socket resides. | |||||
* This will default to ipc.config.networkHost if not specified | |||||
* @param port the port on which the TCP or TLS socket resides | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, host?: string, port?: number, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. For TCP & TLS sockets, | |||||
* this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. | |||||
* For TCP & TLS sockets, this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param host is the host on which the TCP or TLS socket resides. This will default to ipc.config.networkHost if not specified | |||||
* @param port the port on which the TCP or TLS socket resides | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, hostOrPort: number | string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#disconnect | |||||
* Used to disconnect a client from a Unix, Windows, TCP or TLS socket. | |||||
* The socket and its refrence will be removed from memory and the ipc.of scope. | |||||
* This can be local or remote. UDP clients do not maintain connections and so there are no Clients and this method has no value to them | |||||
* @param id is the string id of the socket from which to disconnect | |||||
*/ | |||||
disconnect(id: string): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
* @param path This is the path of the Unix Domain Socket File, if the System is Windows, | |||||
* this will automatically be converted to an appropriate pipe with the same information as the Unix Domain Socket File. | |||||
* If not set this will default to ipc.config.socketRoot+ipc.config.appspace+id | |||||
* @param callback This is a function to be called after the Server has started. | |||||
* This can also be done by binding an event to the start event like ipc.server.on('start',function(){}); | |||||
*/ | |||||
serve(path: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
* @param callback This is a function to be called after the Server has started. | |||||
* This can also be done by binding an event to the start event like ipc.server.on('start',function(){}); | |||||
*/ | |||||
serve(callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
*/ | |||||
serve(callback: null): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param host If not specified this defaults to the first address in os.networkInterfaces(). | |||||
* For TCP, TLS & UDP servers this is most likely going to be 127.0.0.1 or ::1 | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
* @param UDPType If set this will create the server as a UDP socket. 'udp4' or 'udp6' are valid values. | |||||
* This defaults to not being set. When using udp6 make sure to specify a valid IPv6 host, like ::1 | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(host?: string, port?: number, UDPType?: "udp4" | "udp6", callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param UDPType If set this will create the server as a UDP socket. 'udp4' or 'udp6' are valid values. | |||||
* This defaults to not being set. When using udp6 make sure to specify a valid IPv6 host, like ::1 | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(UDPType: "udp4" | "udp6", callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param callback Function to be called when the server is created | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
*/ | |||||
serveNet(callbackOrPort: EmptyCallback | number): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param host If not specified this defaults to the first address in os.networkInterfaces(). | |||||
* For TCP, TLS & UDP servers this is most likely going to be 127.0.0.1 or ::1 | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(host: string, port: number, callback?: () => void): void; | |||||
/** | |||||
* This is where socket connection refrences will be stored when connecting to them as a client via the ipc.connectTo | |||||
* or iupc.connectToNet. They will be stored based on the ID used to create them, eg : ipc.of.mySocket | |||||
*/ | |||||
of: any; | |||||
/** | |||||
* This is a refrence to the server created by ipc.serve or ipc.serveNet | |||||
*/ | |||||
server: Server; | |||||
} | |||||
type EmptyCallback = () => void; | |||||
interface Client { | |||||
/** | |||||
* triggered when a JSON message is received. The event name will be the type string from your message | |||||
* and the param will be the data object from your message eg : { type:'myEvent',data:{a:1}} | |||||
*/ | |||||
on(event: string, callback: (message: any, socket: Socket) => void): Client; | |||||
/** | |||||
* triggered when an error has occured | |||||
*/ | |||||
on(event: "error", callback: (err: any) => void): Client; | |||||
/** | |||||
* connect - triggered when socket connected | |||||
* disconnect - triggered by client when socket has disconnected from server | |||||
* destroy - triggered when socket has been totally destroyed, no further auto retries will happen and all references are gone | |||||
*/ | |||||
on(event: "connect" | "disconnect" | "destroy", callback: () => void): Client; | |||||
/** | |||||
* triggered by server when a client socket has disconnected | |||||
*/ | |||||
on(event: "socket.disconnected", callback: (socket: Socket, destroyedSocketID: string) => void): Client; | |||||
/** | |||||
* triggered when ipc.config.rawBuffer is true and a message is received | |||||
*/ | |||||
on(event: "data", callback: (buffer: Buffer) => void): Client; | |||||
emit(event: string, value?: any): Client; | |||||
/** | |||||
* Unbind subscribed events | |||||
*/ | |||||
off(event: string, handler: any): Client; | |||||
} | |||||
interface Server extends Client { | |||||
/** | |||||
* start serving need top call serve or serveNet first to set up the server | |||||
*/ | |||||
start(): void; | |||||
/** | |||||
* close the server and stop serving | |||||
*/ | |||||
stop(): void; | |||||
emit(value: any): Client; | |||||
emit(event: string, value: any): Client; | |||||
emit(socket: Socket | SocketConfig, event: string, value?: any): Server; | |||||
emit(socketConfig: Socket | SocketConfig, value?: any): Server; | |||||
} | |||||
interface SocketConfig { | |||||
address?: string; | |||||
port?: number; | |||||
} | |||||
interface Config { | |||||
/** | |||||
* Default: 'app.' | |||||
* Used for Unix Socket (Unix Domain Socket) namespacing. | |||||
* If not set specifically, the Unix Domain Socket will combine the socketRoot, appspace, | |||||
* and id to form the Unix Socket Path for creation or binding. | |||||
* This is available incase you have many apps running on your system, you may have several sockets with the same id, | |||||
* but if you change the appspace, you will still have app specic unique sockets | |||||
*/ | |||||
appspace: string; | |||||
/** | |||||
* Default: '/tmp/' | |||||
* The directory in which to create or bind to a Unix Socket | |||||
*/ | |||||
socketRoot: string; | |||||
/** | |||||
* Default: os.hostname() | |||||
* The id of this socket or service | |||||
*/ | |||||
id: string; | |||||
/** | |||||
* Default: 'localhost' | |||||
* The local or remote host on which TCP, TLS or UDP Sockets should connect | |||||
* Should resolve to 127.0.0.1 or ::1 see the table below related to this | |||||
*/ | |||||
networkHost: string; | |||||
/** | |||||
* Default: 8000 | |||||
* The default port on which TCP, TLS, or UDP sockets should connect | |||||
*/ | |||||
networkPort: number; | |||||
/** | |||||
* Default: 'utf8' | |||||
* the default encoding for data sent on sockets. Mostly used if rawBuffer is set to true. | |||||
* Valid values are : ascii utf8 utf16le ucs2 base64 hex | |||||
*/ | |||||
encoding: "ascii" | "utf8" | "utf16le" | "ucs2" | "base64" | "hex"; | |||||
/** | |||||
* Default: false | |||||
* If true, data will be sent and received as a raw node Buffer NOT an Object as JSON. | |||||
* This is great for Binary or hex IPC, and communicating with other processes in languages like C and C++ | |||||
*/ | |||||
rawBuffer: boolean; | |||||
/** | |||||
* Default: false | |||||
* Synchronous requests. Clients will not send new requests until the server answers | |||||
*/ | |||||
sync: boolean; | |||||
/** | |||||
* Default: false | |||||
* Turn on/off logging default is false which means logging is on | |||||
*/ | |||||
silent: boolean; | |||||
/** | |||||
* Default: true | |||||
* Turn on/off util.inspect colors for ipc.log | |||||
*/ | |||||
logInColor: boolean; | |||||
/** | |||||
* Default: 5 | |||||
* Set the depth for util.inspect during ipc.log | |||||
*/ | |||||
logDepth: number; | |||||
/** | |||||
* Default: console.log | |||||
* The function which receives the output from ipc.log; should take a single string argument | |||||
*/ | |||||
logger(msg: string): void; | |||||
/** | |||||
* Default: 100 | |||||
* This is the max number of connections allowed to a socket. It is currently only being set on Unix Sockets. | |||||
* Other Socket types are using the system defaults | |||||
*/ | |||||
maxConnections: number; | |||||
/** | |||||
* Default: 500 | |||||
* This is the time in milliseconds a client will wait before trying to reconnect to a server if the connection is lost. | |||||
* This does not effect UDP sockets since they do not have a client server relationship like Unix Sockets and TCP Sockets | |||||
*/ | |||||
retry: number; | |||||
/* */ | |||||
/** | |||||
* Default: false | |||||
* if set, it represents the maximum number of retries after each disconnect before giving up | |||||
* and completely killing a specific connection | |||||
*/ | |||||
maxRetries: boolean | number; | |||||
/** | |||||
* Default: false | |||||
* Defaults to false meaning clients will continue to retry to connect to servers indefinitely at the retry interval. | |||||
* If set to any number the client will stop retrying when that number is exceeded after each disconnect. | |||||
* If set to true in real time it will immediately stop trying to connect regardless of maxRetries. | |||||
* If set to 0, the client will NOT try to reconnect | |||||
*/ | |||||
stopRetrying: boolean; | |||||
/** | |||||
* Default: true | |||||
* Defaults to true meaning that the module will take care of deleting the IPC socket prior to startup. | |||||
* If you use node-ipc in a clustered environment where there will be multiple listeners on the same socket, | |||||
* you must set this to false and then take care of deleting the socket in your own code. | |||||
*/ | |||||
unlink: boolean; | |||||
/** | |||||
* Primarily used when specifying which interface a client should connect through. | |||||
* see the socket.connect documentation in the node.js api https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener | |||||
*/ | |||||
interfaces: { | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
localAddress?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
localPort?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
family?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
hints?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
lookup?: boolean; | |||||
}; | |||||
tls: { | |||||
rejectUnauthorized?: boolean; | |||||
public?: string; | |||||
private?: string; | |||||
}; | |||||
} | |||||
} | |||||
export = NodeIPC | |||||
// declare const RootIPC: NodeIPC.IPC & { IPC: new () => NodeIPC.IPC }; | |||||
// export = RootIPC; | |||||
} | |||||
@ -0,0 +1,38 @@ | |||||
import * as glob from "glob"; | |||||
import * as fs from "fs"; | |||||
declare function rimraf(path: string, options: rimraf.Options, callback: (error?: Error) => void): void; | |||||
declare function rimraf(path: string, callback: (error?: Error) => void): void; | |||||
declare namespace rimraf { | |||||
/** | |||||
* It can remove stuff synchronously, too. | |||||
* But that's not so good. Use the async API. | |||||
* It's better. | |||||
*/ | |||||
function sync(path: string, options?: Options): void; | |||||
/** | |||||
* see {@link https://github.com/isaacs/rimraf/blob/79b933fb362b2c51bedfa448be848e1d7ed32d7e/README.md#options} | |||||
*/ | |||||
interface Options { | |||||
maxBusyTries?: number; | |||||
emfileWait?: number; | |||||
/** @default false */ | |||||
disableGlob?: boolean; | |||||
glob?: glob.IOptions | false; | |||||
unlink?: typeof fs.unlink; | |||||
chmod?: typeof fs.chmod; | |||||
stat?: typeof fs.stat; | |||||
lstat?: typeof fs.lstat; | |||||
rmdir?: typeof fs.rmdir; | |||||
readdir?: typeof fs.readdir; | |||||
unlinkSync?: typeof fs.unlinkSync; | |||||
chmodSync?: typeof fs.chmodSync; | |||||
statSync?: typeof fs.statSync; | |||||
lstatSync?: typeof fs.lstatSync; | |||||
rmdirSync?: typeof fs.rmdirSync; | |||||
readdirSync?: typeof fs.readdirSync; | |||||
} | |||||
} | |||||
export = rimraf; |
@ -0,0 +1,232 @@ | |||||
// declare module "webtorrent-hybrid" { | |||||
// declare class WebTorrent { | |||||
// } | |||||
// declare const WebTorrent: WebTorrent.WebTorrent; | |||||
// declare namespace WebTorrent { | |||||
// interface WebTorrent { | |||||
// new (config?: Options): Instance; | |||||
// (config?: Options): Instance; | |||||
// WEBRTC_SUPPORT: boolean; | |||||
// } | |||||
// } | |||||
// export = WebTorrent; | |||||
// } | |||||
// Type definitions for WebTorrent 0.109 | |||||
// Project: https://github.com/feross/webtorrent, https://webtorrent.io | |||||
// Definitions by: Bazyli Brzóska <https://github.com/niieani> | |||||
// Tomasz Łaziuk <https://github.com/tlaziuk> | |||||
// Gabriel Juchault <https://github.com/gjuchault> | |||||
// Adam Crowder <https://github.com/cheeseandcereal> | |||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped | |||||
/// <reference types="node" /> | |||||
declare module "webtorrent-hybrid" { | |||||
import { Instance as MagnetUri } from 'magnet-uri'; | |||||
import { Instance as ParseTorrent } from 'parse-torrent'; | |||||
import { Instance as SimplePeer } from 'simple-peer'; | |||||
import { RequestOptions, Server } from 'http'; | |||||
import { Wire } from 'bittorrent-protocol'; | |||||
declare const WebTorrent: WebTorrent.WebTorrent; | |||||
declare namespace WebTorrent { | |||||
interface WebTorrent { | |||||
new (config?: Options): Instance; | |||||
(config?: Options): Instance; | |||||
WEBRTC_SUPPORT: boolean; | |||||
} | |||||
interface Options { | |||||
maxConns?: number; | |||||
nodeId?: string | Buffer; | |||||
peerId?: string | Buffer; | |||||
tracker?: boolean | {}; | |||||
dht?: boolean | {}; | |||||
webSeeds?: boolean; | |||||
utp?: boolean; | |||||
} | |||||
interface TorrentOptions { | |||||
announce?: any[]; | |||||
getAnnounceOpts?(): void; | |||||
maxWebConns?: number; | |||||
path?: string; | |||||
store?(chunkLength: number, storeOpts: { length: number, files: File[], torrent: Torrent, }): any; | |||||
private?: boolean; | |||||
} | |||||
interface TorrentDestroyOptions { | |||||
destroyStore?: boolean; | |||||
} | |||||
interface Instance extends NodeJS.EventEmitter { | |||||
on(event: 'torrent', callback: (torrent: Torrent) => void): this; | |||||
on(event: 'error', callback: (err: Error | string) => void): this; | |||||
add(torrent: string | Buffer | File | ParseTorrent | MagnetUri, opts?: TorrentOptions, cb?: (torrent: Torrent) => any): Torrent; | |||||
add(torrent: string | Buffer | File | ParseTorrent | MagnetUri, cb?: (torrent: Torrent) => any): Torrent; | |||||
seed(input: string | string[] | File | File[] | FileList | Buffer | Buffer[] | NodeJS.ReadableStream | NodeJS.ReadableStream[], opts?: TorrentOptions, cb?: (torrent: Torrent) => any): Torrent; | |||||
seed(input: string | string[] | File | File[] | FileList | Buffer | Buffer[] | NodeJS.ReadableStream | NodeJS.ReadableStream[], cb?: (torrent: Torrent) => any): Torrent; | |||||
remove(torrentId: Torrent | string | Buffer, opts?: TorrentDestroyOptions, callback?: (err: Error | string) => void): void; | |||||
destroy(callback?: (err: Error | string) => void): void; | |||||
readonly torrents: Torrent[]; | |||||
get(torrentId: Torrent | string | Buffer): Torrent | null; | |||||
readonly downloadSpeed: number; | |||||
readonly uploadSpeed: number; | |||||
readonly progress: number; | |||||
readonly ratio: number; | |||||
} | |||||
interface Torrent extends NodeJS.EventEmitter { | |||||
readonly infoHash: string; | |||||
readonly magnetURI: string; | |||||
readonly torrentFile: Buffer; | |||||
readonly torrentFileBlobURL: string; | |||||
readonly files: TorrentFile[]; | |||||
readonly announce: string[]; | |||||
readonly pieces: Array<TorrentPiece | null>; | |||||
readonly timeRemaining: number; | |||||
readonly received: number; | |||||
readonly downloaded: number; | |||||
readonly uploaded: number; | |||||
readonly downloadSpeed: number; | |||||
readonly uploadSpeed: number; | |||||
readonly progress: number; | |||||
readonly ratio: number; | |||||
readonly length: number; | |||||
readonly pieceLength: number; | |||||
readonly lastPieceLength: number; | |||||
readonly numPeers: number; | |||||
readonly path: string; | |||||
readonly ready: boolean; | |||||
readonly paused: boolean; | |||||
readonly done: boolean; | |||||
readonly name: string; | |||||
readonly created: Date; | |||||
readonly createdBy: string; | |||||
readonly comment: string; | |||||
readonly maxWebConns: number; | |||||
destroy(opts?: TorrentDestroyOptions, cb?: (err: Error | string) => void): void; | |||||
addPeer(peer: string | SimplePeer): boolean; | |||||
addWebSeed(url: string): void; | |||||
removePeer(peer: string | SimplePeer): void; | |||||
select(start: number, end: number, priority?: number, notify?: () => void): void; | |||||
deselect(start: number, end: number, priority: number): void; | |||||
createServer(opts?: RequestOptions): Server; | |||||
pause(): void; | |||||
resume(): void; | |||||
rescanFiles(callback?: (err: Error | string | null) => void): void; | |||||
on(event: 'infoHash' | 'metadata' | 'ready' | 'done', callback: () => void): this; | |||||
on(event: 'warning' | 'error', callback: (err: Error | string) => void): this; | |||||
on(event: 'download' | 'upload', callback: (bytes: number) => void): this; | |||||
on(event: 'wire', callback: (wire: Wire, addr?: string) => void): this; | |||||
on(event: 'noPeers', callback: (announceType: 'tracker' | 'dht') => void): this; | |||||
} | |||||
interface TorrentFile extends NodeJS.EventEmitter { | |||||
// Custom property to check if a file is selected | |||||
readonly isSelected: boolean; | |||||
readonly name: string; | |||||
readonly path: string; | |||||
readonly length: number; | |||||
readonly downloaded: number; | |||||
readonly progress: number; | |||||
select(): void; | |||||
deselect(): void; | |||||
createReadStream(opts?: { start: number, end: number, }): NodeJS.ReadableStream; | |||||
getBuffer(callback: (err: string | Error | undefined, buffer?: Buffer) => void): void; | |||||
appendTo( | |||||
rootElement: HTMLElement | string, | |||||
opts?: { autoplay?: boolean, controls?: boolean, maxBlobLength?: number }, | |||||
callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
appendTo(rootElement: HTMLElement | string, callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
renderTo( | |||||
rootElement: HTMLMediaElement | string, | |||||
opts?: { autoplay?: boolean, controls?: boolean, maxBlobLength?: number }, | |||||
callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
renderTo(rootElement: HTMLMediaElement | string, callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
getBlob(callback: (err: string | Error | undefined, blob?: Blob) => void): void; | |||||
getBlobURL(callback: (err: string | Error | undefined, blobURL?: string) => void): void; | |||||
} | |||||
interface TorrentPiece { | |||||
readonly length: number; | |||||
readonly missing: number; | |||||
} | |||||
} | |||||
export = WebTorrent; | |||||
} | |||||
@ -0,0 +1,71 @@ | |||||
{ | |||||
"compilerOptions": { | |||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */ | |||||
/* Basic Options */ | |||||
// "incremental": true, /* Enable incremental compilation */ | |||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ | |||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ | |||||
// "lib": [], /* Specify library files to be included in the compilation. */ | |||||
// "allowJs": true, /* Allow javascript files to be compiled. */ | |||||
// "checkJs": true, /* Report errors in .js files. */ | |||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ | |||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */ | |||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ | |||||
"sourceMap": true, /* Generates corresponding '.map' file. */ | |||||
// "outFile": "./", /* Concatenate and emit output to single file. */ | |||||
"outDir": "./dist", /* Redirect output structure to the directory. */ | |||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ | |||||
// "composite": true, /* Enable project compilation */ | |||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ | |||||
// "removeComments": true, /* Do not emit comments to output. */ | |||||
// "noEmit": true, /* Do not emit outputs. */ | |||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ | |||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ | |||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ | |||||
/* Strict Type-Checking Options */ | |||||
"strict": true, /* Enable all strict type-checking options. */ | |||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ | |||||
// "strictNullChecks": true, /* Enable strict null checks. */ | |||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ | |||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ | |||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ | |||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ | |||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ | |||||
/* Additional Checks */ | |||||
// "noUnusedLocals": true, /* Report errors on unused locals. */ | |||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */ | |||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ | |||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ | |||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ | |||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ | |||||
/* Module Resolution Options */ | |||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ | |||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ | |||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ | |||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ | |||||
"typeRoots": ["./src/typings"], /* List of folders to include type definitions from. */ | |||||
// "types": [], /* Type declaration files to be included in compilation. */ | |||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ | |||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | |||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ | |||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ | |||||
/* Source Map Options */ | |||||
"sourceRoot": "./src", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ | |||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ | |||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ | |||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ | |||||
/* Experimental Options */ | |||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ | |||||
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ | |||||
/* Advanced Options */ | |||||
"skipLibCheck": true, /* Skip type checking of declaration files. */ | |||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ | |||||
} | |||||
} |