You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

165 lines
4.8 KiB

import ipc from "node-ipc";
import { Socket } from "net";
import { ISerializedTorrent, ITorrent } from "../common";
interface IResponse {
response?: any,
error?: string | Error
}
export default class TorrentClientIpc
{
/**
* Indicate if there is an active connection to the IPC
*/
private __isConnected: boolean;
/**
* The active IPC socket
*/
protected socket!: Socket;
/**
* Create a new IPC client for the torrent client
*/
constructor() {
ipc.config.id = "torrent_webui";
ipc.config.retry = 1500;
ipc.config.silent = true;
this.__isConnected = false;
}
/**
* Boot the torrent client IPC service
*/
public boot() {
return new Promise<void>((resolve, reject) => {
console.log(process.env["TORRENT_CLIENT_IPC_SOCKET"]);
ipc.connectTo("torrent_client", process.env["TORRENT_CLIENT_IPC_SOCKET"], () => {
this.socket = ipc.of["torrent_client"];
this.installSocketEventHandlers(this.socket);
this.installSocketMessageHandlers(this.socket);
resolve();
});
});
}
/**
* Install the event handlers for the IPC socket
*/
protected installSocketEventHandlers(socket: Socket) {
socket.on("connect", () => this.onConnect());
socket.on("error", (error: any) => this.onError(error));
socket.on("disconnect", () => this.onDisconnect());
socket.on("destroy", () => this.onDestroy());
}
protected installSocketMessageHandlers(socket: Socket) {
}
// Socket Event Handlers -----------------------------------------------------------------------
protected onConnect() {
if (!this.__isConnected) {
console.log("IPC: Connection established");
}
this.__isConnected = true;
}
protected onError(error: string | Error) {
if (this.__isConnected) {
console.log("IPC: Error occurred:", error);
}
}
protected onDisconnect() {
if (this.__isConnected) {
console.log("IPC: Disconnected");
}
this.__isConnected = false;
}
protected onDestroy() {
console.log("IPC: Destroyed");
}
// Methods -------------------------------------------------------------------------------------
/**
* Perform a general request to the torrent client
*/
protected async request(method: string, ...message: any[]) {
return new Promise<IResponse>((resolve, reject) => {
if (!this.isConnected) {
throw new Error("Not connected to torrent client");
}
let respond = (response: any) => {
clearTimeout(timeout);
resolve(response);
}
// Include timeout mechanism in the off chance something breaks
let timeout = setTimeout(() => {
this.socket.off(method, respond);
reject("Torrent client IPC request timeout")
}, 1000);
this.socket.once(method, respond);
this.socket.emit(method, message);
});
}
/**
* Add a torrent to the client
* @param torrent Magnet URI or file buffer
*/
public async add(torrent: string | Buffer) {
let response = await this.request("add", torrent);
if (response.error) {
throw new Error("Failed to add torrent");
}
return <string>response.response;
}
/**
* Remove a torrent from the client
* @param torrent Torrent info hash
*/
public async remove(torrent: string) {
let response = await this.request("remove", torrent);
if (response.error) {
throw new Error("Failed to remove torrent");
}
}
/**
* Get a list of all torrents in the client
*/
public async list() {
let response = await this.request("list");
if (response.error) {
console.error(response.error);
throw new Error("Failed to obtain torrent list");
}
console.log("Response is:", response);
return <ITorrent[]>response.response;
}
/**
* Get full details of each of the provided torrents
* @param torrentIds Array of torrent info hashes
*/
public async details(...torrentIds: string[]) {
let response = await this.request("details", torrentIds);
if (response.error) {
console.error(response.error);
throw new Error("Failed to retrieve torrent details");
}
return <ISerializedTorrent[]>response.response;
}
// Accessors -----------------------------------------------------------------------------------
get isConnected() {
return this.__isConnected;
}
}