mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
108 lines
2.6 KiB
TypeScript
108 lines
2.6 KiB
TypeScript
import axios from "axios";
|
|
|
|
import cp from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import crypto from "node:crypto";
|
|
|
|
import { pythonRpcLogger } from "./logger";
|
|
import { Readable } from "node:stream";
|
|
import { app, dialog } from "electron";
|
|
|
|
interface GamePayload {
|
|
game_id: number;
|
|
url: string;
|
|
save_path: string;
|
|
}
|
|
|
|
const binaryNameByPlatform: Partial<Record<NodeJS.Platform, string>> = {
|
|
darwin: "hydra-python-rpc",
|
|
linux: "hydra-python-rpc",
|
|
win32: "hydra-python-rpc.exe",
|
|
};
|
|
|
|
export class PythonRPC {
|
|
public static readonly BITTORRENT_PORT = "5881";
|
|
public static readonly RPC_PORT = "8084";
|
|
private static readonly RPC_PASSWORD = crypto.randomBytes(32).toString("hex");
|
|
|
|
private static pythonProcess: cp.ChildProcess | null = null;
|
|
|
|
public static readonly rpc = axios.create({
|
|
baseURL: `http://localhost:${this.RPC_PORT}`,
|
|
headers: {
|
|
"x-hydra-rpc-password": this.RPC_PASSWORD,
|
|
},
|
|
});
|
|
|
|
private static logStderr(readable: Readable | null) {
|
|
if (!readable) return;
|
|
|
|
readable.setEncoding("utf-8");
|
|
readable.on("data", pythonRpcLogger.log);
|
|
}
|
|
|
|
public static spawn(
|
|
initialDownload?: GamePayload,
|
|
initialSeeding?: GamePayload[]
|
|
) {
|
|
const commonArgs = [
|
|
this.BITTORRENT_PORT,
|
|
this.RPC_PORT,
|
|
this.RPC_PASSWORD,
|
|
initialDownload ? JSON.stringify(initialDownload) : "",
|
|
initialSeeding ? JSON.stringify(initialSeeding) : "",
|
|
];
|
|
|
|
if (app.isPackaged) {
|
|
const binaryName = binaryNameByPlatform[process.platform]!;
|
|
const binaryPath = path.join(
|
|
process.resourcesPath,
|
|
"hydra-python-rpc",
|
|
binaryName
|
|
);
|
|
|
|
if (!fs.existsSync(binaryPath)) {
|
|
dialog.showErrorBox(
|
|
"Fatal",
|
|
"Hydra Python Instance binary not found. Please check if it has been removed by Windows Defender."
|
|
);
|
|
|
|
app.quit();
|
|
}
|
|
|
|
const childProcess = cp.spawn(binaryPath, commonArgs, {
|
|
windowsHide: true,
|
|
stdio: ["inherit", "inherit"],
|
|
});
|
|
|
|
this.logStderr(childProcess.stderr);
|
|
|
|
this.pythonProcess = childProcess;
|
|
} else {
|
|
const scriptPath = path.join(
|
|
__dirname,
|
|
"..",
|
|
"..",
|
|
"python_rpc",
|
|
"main.py"
|
|
);
|
|
|
|
const childProcess = cp.spawn("python3", [scriptPath, ...commonArgs], {
|
|
stdio: ["inherit", "inherit"],
|
|
});
|
|
|
|
this.logStderr(childProcess.stderr);
|
|
|
|
this.pythonProcess = childProcess;
|
|
}
|
|
}
|
|
|
|
public static kill() {
|
|
if (this.pythonProcess) {
|
|
pythonRpcLogger.log("Killing python process");
|
|
this.pythonProcess.kill();
|
|
this.pythonProcess = null;
|
|
}
|
|
}
|
|
}
|