Browse Source

Torrent client IPC added

staging
David Ludwig 4 years ago
parent
commit
2d9a990ffb
3 changed files with 195 additions and 1 deletions
  1. +2
    -1
      services/torrent-webui/.env.example
  2. +36
    -0
      services/torrent-webui/src/server/common.ts
  3. +157
    -0
      services/torrent-webui/src/server/services/TorrentClientIpc.ts

+ 2
- 1
services/torrent-webui/.env.example View File

@ -1 +1,2 @@
SERVER_PORT =
SERVER_PORT = 3100
TORRENT_CLIENT_IPC_SOCKET = /tmp/torrent_client.sock

+ 36
- 0
services/torrent-webui/src/server/common.ts View File

@ -0,0 +1,36 @@
export interface ITorrent {
name: string,
infoHash: string,
progress: number,
state: TorrentState
}
export enum TorrentState {
Ready = 0x1,
Paused = 0x2,
Done = 0x4
}
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 interface ISerializedFile {
path : string;
size : number;
downloaded: number;
progress : number;
selected : boolean;
}

+ 157
- 0
services/torrent-webui/src/server/services/TorrentClientIpc.ts View File

@ -0,0 +1,157 @@
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) => {
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() {
console.log("IPC: Connection established");
this.__isConnected = true;
}
protected onError(error: string | Error) {
console.log("IPC: Error occurred:", error);
}
protected onDisconnect() {
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");
}
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;
}
}

Loading…
Cancel
Save