forked from mirror/MCSM-Daemon
Feat: complete openfrp flow
This commit is contained in:
parent
a5910f68c1
commit
fab1952638
@ -35,7 +35,7 @@ export class processWrapper extends EventEmitter {
|
||||
this.process = process;
|
||||
this.pid = process.pid;
|
||||
|
||||
process.emit("start", process.pid);
|
||||
this.emit("start", process.pid);
|
||||
if (!process || !process.pid) return reject(false);
|
||||
|
||||
process.stdout.on("data", (text) => this.emit("data", iconv.decode(text, this.code)));
|
||||
|
@ -3,12 +3,16 @@
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
|
||||
const ptyName = `pty_${os.platform()}_${os.arch()}${os.platform() === "win32" ? ".exe" : ""}`;
|
||||
const SYS_INFO = `${os.platform()}_${os.arch()}${os.platform() === "win32" ? ".exe" : ""}`;
|
||||
const ptyName = `pty_${SYS_INFO}`;
|
||||
const frpcName = `frpc_${SYS_INFO}`;
|
||||
|
||||
const PTY_PATH = path.normalize(path.join(process.cwd(), "lib", ptyName));
|
||||
|
||||
const FRPC_PATH = path.normalize(path.join(process.cwd(), "lib", frpcName));
|
||||
|
||||
const FILENAME_BLACKLIST = ["\\", "/", ".", "'", '"', "?", "*", "<", ">"];
|
||||
|
||||
const LOCAL_PRESET_LANG_PATH = path.normalize(path.join(process.cwd(), "language"));
|
||||
|
||||
export { FILENAME_BLACKLIST, PTY_PATH, LOCAL_PRESET_LANG_PATH };
|
||||
export { FILENAME_BLACKLIST, PTY_PATH, LOCAL_PRESET_LANG_PATH, FRPC_PATH };
|
||||
|
@ -20,6 +20,7 @@ import GeneralUpdateCommand from "./general/general_update";
|
||||
import PtyStartCommand from "./pty/pty_start";
|
||||
import PtyStopCommand from "./pty/pty_stop";
|
||||
import { PTY_PATH } from "../../const";
|
||||
import OpenFrpTask from "./task/openfrp";
|
||||
|
||||
// instance function scheduler
|
||||
// Dispatch and assign different functions according to different types
|
||||
@ -35,6 +36,7 @@ export default class FunctionDispatcher extends InstanceCommand {
|
||||
|
||||
// the component that the instance must mount
|
||||
instance.lifeCycleTaskManager.registerLifeCycleTask(new TimeCheck());
|
||||
instance.lifeCycleTaskManager.registerLifeCycleTask(new OpenFrpTask());
|
||||
|
||||
// Instance general preset capabilities
|
||||
instance.setPreset("command", new GeneralSendCommand());
|
||||
|
@ -12,22 +12,21 @@ import KillCommand from "../kill";
|
||||
import logger from "../../../service/log";
|
||||
import { $t } from "../../../i18n";
|
||||
import { processWrapper } from "../../../common/process_tools";
|
||||
|
||||
import { FRPC_PATH } from "../../../const";
|
||||
export class OpenFrp {
|
||||
public processWrapper: processWrapper;
|
||||
public fileName: string = os.platform() === "win32" ? "openfrp.exe" : "openfrp";
|
||||
public filePath: string;
|
||||
|
||||
constructor(public readonly token: string, public readonly tunnelId: string) {
|
||||
this.filePath = path.normalize(path.join(process.cwd(), "lib", "openfrp", this.fileName));
|
||||
|
||||
// ./frpc -u 用户密钥 -p 隧道ID
|
||||
this.processWrapper = new processWrapper(this.fileName, ["-u", this.token, "-p", this.tunnelId], path.dirname(this.filePath));
|
||||
this.processWrapper = new processWrapper(FRPC_PATH, ["-u", this.token, "-p", this.tunnelId], path.dirname(FRPC_PATH));
|
||||
}
|
||||
|
||||
public open() {
|
||||
logger.info("Start openfrp:", this.fileName);
|
||||
logger.info("Start openfrp:", FRPC_PATH);
|
||||
this.processWrapper.start();
|
||||
if (!this.processWrapper.getPid()) {
|
||||
throw new Error("pid is null");
|
||||
}
|
||||
}
|
||||
|
||||
public stop() {
|
||||
@ -46,17 +45,26 @@ export default class OpenFrpTask implements ILifeCycleTask {
|
||||
|
||||
async start(instance: Instance) {
|
||||
const { openFrpToken, openFrpTunnelId, isOpenFrp } = instance.config?.extraServiceConfig;
|
||||
if (openFrpToken && openFrpTunnelId && isOpenFrp) {
|
||||
if (openFrpToken && openFrpTunnelId) {
|
||||
const frpProcess = new OpenFrp(openFrpToken, openFrpTunnelId);
|
||||
frpProcess.processWrapper.on("start", () => {
|
||||
frpProcess.processWrapper.on("start", (pid) => {
|
||||
logger.info(`Instance ${instance.config.nickname}(${instance.instanceUuid}) ${pid} Frp task started!`);
|
||||
logger.info(`Params: ${openFrpTunnelId} | ${openFrpToken}`);
|
||||
instance.openFrp = frpProcess;
|
||||
instance.info.openFrpStatus = true;
|
||||
});
|
||||
frpProcess.processWrapper.on("exit", () => {
|
||||
logger.info(`Instance ${instance.config.nickname}(${instance.instanceUuid}) Frp task stopped!`);
|
||||
instance.info.openFrpStatus = false;
|
||||
instance.openFrp = null;
|
||||
});
|
||||
frpProcess.open();
|
||||
|
||||
try {
|
||||
frpProcess.open();
|
||||
} catch (error) {
|
||||
logger.warn(`Instance ${instance.config.nickname}(${instance.instanceUuid}) Frp task Start failure! ERR:`);
|
||||
logger.warn(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,12 @@ export default class Instance extends EventEmitter {
|
||||
configureEntityParams(this.config.terminalOption, cfg.terminalOption, "ptyWindowRow", Number);
|
||||
}
|
||||
|
||||
if (cfg?.extraServiceConfig) {
|
||||
configureEntityParams(this.config.extraServiceConfig, cfg.extraServiceConfig, "isOpenFrp", Boolean);
|
||||
configureEntityParams(this.config.extraServiceConfig, cfg.extraServiceConfig, "openFrpToken", String);
|
||||
configureEntityParams(this.config.extraServiceConfig, cfg.extraServiceConfig, "openFrpTunnelId", String);
|
||||
}
|
||||
|
||||
configureEntityParams(this.config, cfg, "nickname", String);
|
||||
configureEntityParams(this.config, cfg, "startCommand", String);
|
||||
configureEntityParams(this.config, cfg, "stopCommand", String);
|
||||
|
@ -21,7 +21,6 @@ import { ProcessConfig } from "../entity/instance/process_config";
|
||||
import RestartCommand from "../entity/commands/restart";
|
||||
import { TaskCenter } from "../service/async_task_service";
|
||||
import { createQuickInstallTask } from "../service/async_task_service/quick_install";
|
||||
import { OpenFrpTask, openOpenFrpTask } from "../service/async_task_service/openfrp_start";
|
||||
import { QuickInstallTask } from "../service/async_task_service/quick_install";
|
||||
|
||||
// Some instances operate router authentication middleware
|
||||
@ -299,15 +298,6 @@ routerApp.on("instance/asynchronous", (ctx, data) => {
|
||||
const task = createQuickInstallTask(targetLink, newInstanceName);
|
||||
return protocol.response(ctx, task.toObject());
|
||||
}
|
||||
// Start HiPer Network
|
||||
if (taskName === "hiper") {
|
||||
TaskCenter.deleteAllStoppedTask();
|
||||
const tasks = TaskCenter.getTasks(OpenFrpTask.TYPE);
|
||||
if (tasks.length != 0) throw new Error($t("hiper.alreadyExist"));
|
||||
const indexCode = String(parameter.indexCode);
|
||||
const task = openOpenFrpTask(indexCode);
|
||||
return protocol.response(ctx, task.toObject());
|
||||
}
|
||||
protocol.response(ctx, true);
|
||||
});
|
||||
|
||||
@ -344,7 +334,6 @@ routerApp.on("instance/query_asynchronous", (ctx, data) => {
|
||||
const taskId = data.parameter.taskId as string | undefined;
|
||||
const taskName = data.taskName as string;
|
||||
const taskNameTypeMap: IJson<string> = {
|
||||
hiper: OpenFrpTask.TYPE,
|
||||
quick_install: QuickInstallTask.TYPE
|
||||
};
|
||||
const type = String(taskNameTypeMap[taskName] || QuickInstallTask.TYPE);
|
||||
|
@ -1,88 +0,0 @@
|
||||
// Copyright (C) 2022 MCSManager <mcsmanager-dev@outlook.com>
|
||||
|
||||
import { v4 } from "uuid";
|
||||
import fs from "fs-extra";
|
||||
import Instance from "../../entity/instance/instance";
|
||||
import InstanceSubsystem from "../system_instance";
|
||||
import InstanceConfig from "../../entity/instance/Instance_config";
|
||||
import { $t, i18next } from "../../i18n";
|
||||
import path from "path";
|
||||
import { spawn, ChildProcess } from "child_process";
|
||||
import { getFileManager } from "../file_router_service";
|
||||
import EventEmitter from "events";
|
||||
import { AsyncTask, IAsyncTask, IAsyncTaskJSON, TaskCenter } from "./index";
|
||||
import logger from "../log";
|
||||
import { downloadFileToLocalFile } from "../download";
|
||||
import os from "os";
|
||||
import { killProcess } from "../../common/process_tools";
|
||||
|
||||
class OpenFrp {
|
||||
public process: ChildProcess;
|
||||
public fileName: string = os.platform() === "win32" ? "openfrp.exe" : "openfrp";
|
||||
public filePath: string;
|
||||
|
||||
public open(keyPath: string) {
|
||||
if (this.process) {
|
||||
throw new Error($t("quick_install.openfrpError"));
|
||||
}
|
||||
this.filePath = path.normalize(path.join(process.cwd(), "lib", "openfrp", this.fileName));
|
||||
logger.info("Start openfrp:", this.filePath);
|
||||
this.process = spawn(this.fileName, {
|
||||
cwd: path.dirname(this.filePath),
|
||||
stdio: "pipe",
|
||||
windowsHide: true
|
||||
});
|
||||
|
||||
if (!this.process.pid) throw new Error("OpenFrp program start failed! Pid is null!");
|
||||
this.process.on("exit", (code) => {});
|
||||
}
|
||||
|
||||
public stop() {
|
||||
try {
|
||||
if (this.process.exitCode == null) {
|
||||
killProcess(this.process.pid, this.process);
|
||||
}
|
||||
this.process = null;
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenFrpTask extends AsyncTask {
|
||||
public static readonly TYPE = "OpenFrpTask";
|
||||
public static ip: string = null;
|
||||
|
||||
constructor(public readonly indexCode: string) {
|
||||
super();
|
||||
this.taskId = `${OpenFrpTask.TYPE}-${v4()}`;
|
||||
this.type = OpenFrpTask.TYPE;
|
||||
}
|
||||
|
||||
async onStarted(): Promise<boolean | void> {
|
||||
try {
|
||||
} catch (error) {
|
||||
this.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onStopped(): Promise<boolean | void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
onError(err: Error): void {}
|
||||
|
||||
toObject(): IAsyncTaskJSON {
|
||||
return JSON.parse(
|
||||
JSON.stringify({
|
||||
taskId: this.taskId,
|
||||
status: this.status(),
|
||||
ip: OpenFrpTask.ip
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function openOpenFrpTask(indexCode: string) {
|
||||
const task = new OpenFrpTask(indexCode);
|
||||
TaskCenter.addTask(task);
|
||||
return task;
|
||||
}
|
Loading…
Reference in New Issue
Block a user