forked from mirror/MCSM-Daemon
修复linux下退出处理
添加docker websocket标准输入接口
This commit is contained in:
parent
32188c8e96
commit
0e52576f82
@ -127,12 +127,12 @@ console.log("");
|
||||
// 装载 终端界面UI
|
||||
import "./service/ui";
|
||||
|
||||
['SIGINT', 'SIGQUIT'].forEach(function (sig) {
|
||||
process.on(sig, function () {
|
||||
["SIGTERM", "SIGINT", "SIGQUIT"].forEach(function(sig) {
|
||||
process.on(sig, async function() {
|
||||
try {
|
||||
console.log("\n\n\n\n");
|
||||
logger.warn(`${sig} close process signal detected.`);
|
||||
InstanceSubsystem.exit();
|
||||
await InstanceSubsystem.exit();
|
||||
logger.info("The data is saved, thanks for using, goodbye!");
|
||||
logger.info("Closed.");
|
||||
} catch (err) {
|
||||
|
@ -31,6 +31,6 @@ export default class SendCommand extends InstanceCommand {
|
||||
}
|
||||
|
||||
async exec(instance: Instance) {
|
||||
return await instance.execPreset("write", this.cmd);
|
||||
return await instance.execPreset("command", this.cmd);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import GeneralKillCommand from "./general/general _kill";
|
||||
import GeneralSendCommand from "./general/general _command";
|
||||
import GeneralRestartCommand from "./general/general _restart";
|
||||
import DockerStartCommand from "./docker/docker _start";
|
||||
import GeneralInputCommand from "./general/general _input";
|
||||
import TimeCheck from "./task/time";
|
||||
import MinecraftBedrockGetPlayersCommand from "../minecraft/mc_getplayer_bedrock";
|
||||
|
||||
@ -52,14 +53,16 @@ export default class FuntionDispatcher extends InstanceCommand {
|
||||
// 根据实例启动类型来进行基本操作方式的预设
|
||||
if (!instance.config.processType || instance.config.processType === "general") {
|
||||
instance.setPreset("start", new GeneralStartCommand());
|
||||
instance.setPreset("write", new GeneralSendCommand());
|
||||
instance.setPreset("command", new GeneralSendCommand());
|
||||
instance.setPreset("input", new GeneralInputCommand());
|
||||
instance.setPreset("stop", new GeneralStopCommand());
|
||||
instance.setPreset("kill", new GeneralKillCommand());
|
||||
instance.setPreset("restart", new GeneralRestartCommand());
|
||||
}
|
||||
if (instance.config.processType === "docker") {
|
||||
instance.setPreset("start", new DockerStartCommand());
|
||||
instance.setPreset("write", new GeneralSendCommand());
|
||||
instance.setPreset("command", new GeneralSendCommand());
|
||||
instance.setPreset("input", new GeneralInputCommand());
|
||||
instance.setPreset("stop", new GeneralStopCommand());
|
||||
instance.setPreset("kill", new GeneralKillCommand());
|
||||
instance.setPreset("restart", new GeneralRestartCommand());
|
||||
|
@ -67,8 +67,8 @@ class DockerProcessAdapter extends EventEmitter implements IInstanceProcess {
|
||||
if (this.stream) this.stream.write(data);
|
||||
}
|
||||
|
||||
public kill(s?: string) {
|
||||
this.container.kill();
|
||||
public async kill(s?: string) {
|
||||
await this.container.kill();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
39
src/entity/commands/general/general _input.ts
Normal file
39
src/entity/commands/general/general _input.ts
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (C) 2022 RimuruChan <RealSprite233@outlook.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
According to the AGPL, it is forbidden to delete all copyright notices,
|
||||
and if you modify the source code, you must open source the
|
||||
modified source code.
|
||||
|
||||
版权所有 (C) 2022 RimuruChan <RealSprite233@outlook.com>
|
||||
|
||||
该程序是免费软件,您可以重新分发和/或修改据 GNU Affero 通用公共许可证的条款,
|
||||
由自由软件基金会,许可证的第 3 版,或(由您选择)任何更高版本。
|
||||
|
||||
根据 AGPL 与用户协议,您必须保留所有版权声明,如果修改源代码则必须开源修改后的源代码。
|
||||
可以前往 https://mcsmanager.com/ 阅读用户协议,申请闭源开发授权等。
|
||||
*/
|
||||
|
||||
import Instance from "../../instance/instance";
|
||||
import { encode } from "iconv-lite";
|
||||
import InstanceCommand from "../base/command";
|
||||
|
||||
export default class GeneralInputCommand extends InstanceCommand {
|
||||
constructor() {
|
||||
super("SendInput");
|
||||
}
|
||||
|
||||
async exec(instance: Instance, text?: string): Promise<any> {
|
||||
// 关服命令需要发送命令,但关服命令执行前会设置状态为关闭中状态。
|
||||
// 所以这里只能通过进程是否存在来执行命令
|
||||
if (!instance.process) {
|
||||
instance.failure(new Error("命令执行失败,因为实例实际进程不存在."));
|
||||
}
|
||||
instance.process.write(encode(text, instance.config.oe));
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ export default class GeneralKillCommand extends InstanceCommand {
|
||||
|
||||
async exec(instance: Instance) {
|
||||
if (instance.process) {
|
||||
instance.process.kill("SIGKILL");
|
||||
await instance.process.kill("SIGKILL");
|
||||
}
|
||||
instance.setLock(false);
|
||||
}
|
||||
|
36
src/entity/commands/input.ts
Normal file
36
src/entity/commands/input.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright (C) 2022 RimuruChan <RealSprite233@outlook.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
According to the AGPL, it is forbidden to delete all copyright notices,
|
||||
and if you modify the source code, you must open source the
|
||||
modified source code.
|
||||
|
||||
版权所有 (C) 2022 RimuruChan <RealSprite233@outlook.com>
|
||||
|
||||
该程序是免费软件,您可以重新分发和/或修改据 GNU Affero 通用公共许可证的条款,
|
||||
由自由软件基金会,许可证的第 3 版,或(由您选择)任何更高版本。
|
||||
|
||||
根据 AGPL 与用户协议,您必须保留所有版权声明,如果修改源代码则必须开源修改后的源代码。
|
||||
可以前往 https://mcsmanager.com/ 阅读用户协议,申请闭源开发授权等。
|
||||
*/
|
||||
|
||||
import Instance from "../instance/instance";
|
||||
import InstanceCommand from "./base/command";
|
||||
|
||||
export default class SendInput extends InstanceCommand {
|
||||
public cmd: string;
|
||||
|
||||
constructor(cmd: string) {
|
||||
super("SendInput");
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
async exec(instance: Instance) {
|
||||
return await instance.execPreset("input", this.cmd);
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import { missionPassport } from "../service/mission_passport";
|
||||
import InstanceSubsystem from "../service/system_instance";
|
||||
import logger from "../service/log";
|
||||
import SendCommand from "../entity/commands/cmd";
|
||||
import SendInput from "../entity/commands/input";
|
||||
import ProcessInfo from "../entity/commands/process_info";
|
||||
import ProcessInfoCommand from "../entity/commands/process_info";
|
||||
|
||||
@ -98,7 +99,7 @@ routerApp.on("stream/detail", async (ctx) => {
|
||||
});
|
||||
|
||||
// 执行命令
|
||||
routerApp.on("stream/input", async (ctx, data) => {
|
||||
routerApp.on("stream/command", async (ctx, data) => {
|
||||
try {
|
||||
const command = data.command;
|
||||
const instanceUuid = ctx.session.stream.instanceUuid;
|
||||
@ -108,3 +109,15 @@ routerApp.on("stream/input", async (ctx, data) => {
|
||||
protocol.responseError(ctx, error);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理终端输入
|
||||
routerApp.on("stream/input", async (ctx, data) => {
|
||||
try {
|
||||
const input = data.input;
|
||||
const instanceUuid = ctx.session.stream.instanceUuid;
|
||||
const instance = InstanceSubsystem.getInstance(instanceUuid);
|
||||
await instance.exec(new SendInput(input));
|
||||
} catch (error) {
|
||||
protocol.responseError(ctx, error);
|
||||
}
|
||||
});
|
||||
|
@ -78,8 +78,10 @@ class InstanceSubsystem extends EventEmitter {
|
||||
// 所有实例全部进行功能调度器
|
||||
instance
|
||||
.forceExec(new FuntionDispatcher())
|
||||
.then((v) => {})
|
||||
.catch((v) => {});
|
||||
.then((v) => {
|
||||
})
|
||||
.catch((v) => {
|
||||
});
|
||||
this.addInstance(instance);
|
||||
});
|
||||
// 处理自动启动
|
||||
@ -159,7 +161,8 @@ class InstanceSubsystem extends EventEmitter {
|
||||
// 删除计划任务
|
||||
InstanceControl.deleteInstanceAllTask(instanceUuid);
|
||||
// 异步删除文件
|
||||
if (deleteFile) fs.remove(instance.config.cwd, (err) => {});
|
||||
if (deleteFile) fs.remove(instance.config.cwd, (err) => {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
throw new Error("Instance does not exist");
|
||||
@ -168,13 +171,15 @@ class InstanceSubsystem extends EventEmitter {
|
||||
forward(targetInstanceUuid: string, socket: Socket) {
|
||||
try {
|
||||
this.instanceStream.requestForward(socket, targetInstanceUuid);
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
|
||||
stopForward(targetInstanceUuid: string, socket: Socket) {
|
||||
try {
|
||||
this.instanceStream.cannelForward(socket, targetInstanceUuid);
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
|
||||
forEachForward(instanceUuid: string, callback: (socket: Socket) => void) {
|
||||
@ -196,15 +201,18 @@ class InstanceSubsystem extends EventEmitter {
|
||||
}
|
||||
|
||||
async exit() {
|
||||
let promises = [];
|
||||
for (const iterator of this.instances) {
|
||||
const instance = iterator[1];
|
||||
if (instance.status() != Instance.STATUS_STOP) {
|
||||
logger.info(`Instance ${instance.config.nickname} (${instance.instanceUuid}) is running or busy, and is being forced to end.`);
|
||||
await instance.execCommand(new KillCommand());
|
||||
promises.push(instance.execCommand(new KillCommand()).then(() => {
|
||||
StorageSubsystem.store("InstanceConfig", instance.instanceUuid, instance.config);
|
||||
logger.info(`Instance ${instance.config.nickname} (${instance.instanceUuid}) saved successfully.`);
|
||||
}));
|
||||
}
|
||||
StorageSubsystem.store("InstanceConfig", instance.instanceUuid, instance.config);
|
||||
logger.info(`Instance ${instance.config.nickname} (${instance.instanceUuid}) saved successfully.`);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,11 @@ const rl = readline.createInterface({
|
||||
console.log('[终端] 守护进程拥有基本的交互功能,请输入"help"查看更多信息');
|
||||
|
||||
function stdin() {
|
||||
rl.question("> ", (answer) => {
|
||||
rl.question("> ", async (answer) => {
|
||||
try {
|
||||
const cmds = answer.split(" ");
|
||||
logger.info(`[Terminal] ${answer}`);
|
||||
const result = command(cmds[0], cmds[1], cmds[2], cmds[3]);
|
||||
const result = await command(cmds[0], cmds[1], cmds[2], cmds[3]);
|
||||
if (result) console.log(result);
|
||||
else console.log(`Command ${answer} does not exist, type help to get help.`);
|
||||
} catch (err) {
|
||||
@ -60,7 +60,7 @@ stdin();
|
||||
* @param {String} cmd
|
||||
* @return {String}
|
||||
*/
|
||||
function command(cmd: string, p1: string, p2: string, p3: string) {
|
||||
async function command(cmd: string, p1: string, p2: string, p3: string) {
|
||||
if (cmd === "instance") {
|
||||
if (p1 === "start") {
|
||||
InstanceSubsystem.getInstance(p2).exec(new StartCommand("Terminal"));
|
||||
@ -108,7 +108,7 @@ function command(cmd: string, p1: string, p2: string, p3: string) {
|
||||
if (cmd == "exit") {
|
||||
try {
|
||||
logger.info("Preparing to shut down the daemon...");
|
||||
InstanceSubsystem.exit();
|
||||
await InstanceSubsystem.exit();
|
||||
// logger.info("Data saved, thanks for using, goodbye!");
|
||||
logger.info("The data is saved, thanks for using, goodbye!");
|
||||
logger.info("closed.");
|
||||
|
Loading…
Reference in New Issue
Block a user