修复linux下退出处理

添加docker websocket标准输入接口
This commit is contained in:
RimuruChan 2022-02-11 03:18:10 +08:00
parent 32188c8e96
commit 0e52576f82
No known key found for this signature in database
GPG Key ID: F6E1836BEE44BC49
10 changed files with 121 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

View File

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

View File

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

View File

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