Feat: complete openfrp flow

This commit is contained in:
unitwk 2022-11-19 10:40:09 +08:00
parent a5910f68c1
commit fab1952638
7 changed files with 33 additions and 112 deletions

View File

@ -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)));

View File

@ -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 };

View File

@ -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());

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}