forked from mirror/MCSM-Daemon
重构了按需启动逻辑
This commit is contained in:
parent
09f3c4d93d
commit
0b17fd05c9
3445
package-lock.json
generated
3445
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
import { ChildProcess, exec, execSync, SpawnOptionsWithoutStdio } from "child_process";
|
||||
import os from "os";
|
||||
import logger from "../service/log";
|
||||
import { log } from "console";
|
||||
|
||||
export class NetworkPort {
|
||||
static readonly PROTO_TCP = "tcp";
|
||||
@ -46,6 +47,7 @@ export function getProcessListeningTcpPort(pid: number | string): NetworkPort[]
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -56,9 +58,10 @@ function portEstablishedWin32(ports: NetworkPort[]): NetworkPort[] {
|
||||
const lines = out.split("\n");
|
||||
for (const line of lines) {
|
||||
const line_arr = line.split(/\s+/);
|
||||
if (line_arr[0].startsWith("TCP") &&
|
||||
line_arr[1].split(":")[1] === port.port.toString() &&
|
||||
line_arr[3] === NetworkPort.STATE_ESTABLISHED) {
|
||||
if (line_arr.length < 5) continue; // windows may have empty line F**K windows
|
||||
if (line_arr[1].startsWith("TCP") &&
|
||||
line_arr[2].split(":")[1] === port.port.toString() &&
|
||||
line_arr[4] === NetworkPort.STATE_ESTABLISHED) {
|
||||
port.established = true;
|
||||
break;
|
||||
}
|
||||
@ -73,7 +76,7 @@ function portEstablishedLinux(ports: NetworkPort[]): NetworkPort[] {
|
||||
const lines = out.split("\n");
|
||||
for (const line of lines) {
|
||||
const line_arr = line.split(/\s+/);
|
||||
if (line_arr[0].startsWith("tcp") &&
|
||||
if (line_arr[0].startsWith("tcp") &&
|
||||
line_arr[3].split(":")[1] === port.port.toString() &&
|
||||
line_arr[5] === NetworkPort.STATE_ESTABLISHED) {
|
||||
port.established = true;
|
||||
@ -90,7 +93,7 @@ function portEstablishedDarwin(ports: NetworkPort[]): NetworkPort[] {
|
||||
const lines = out.split("\n");
|
||||
for (const line of lines) {
|
||||
const line_arr = line.split(/\s+/);
|
||||
if (line_arr[0].startsWith("tcp") &&
|
||||
if (line_arr[0].startsWith("tcp") &&
|
||||
line_arr[3].split(".").pop() === port.port.toString() &&
|
||||
line_arr[5] === NetworkPort.STATE_ESTABLISHED) {
|
||||
port.established = true;
|
||||
@ -105,16 +108,19 @@ function getListenTcpPortWin32(pid: number): NetworkPort[] {
|
||||
const result: NetworkPort[] = [];
|
||||
const output = execSync(`netstat -ano | findstr ${pid}`).toString();
|
||||
const lines = output.split("\n");
|
||||
// TCP
|
||||
// Proto Local Address Foreign Address State PID
|
||||
// TCP 0.0.0.0:25565 0.0.0.0:0 LISTENING 3716
|
||||
// TCP [::]:25565 [::]:0 LISTENING 3716
|
||||
for (const line of lines) {
|
||||
const line_arr = line.split(/\s+/);
|
||||
if (line_arr.length < 5) continue; // windows may have empty line F**K windows
|
||||
const port = new NetworkPort();
|
||||
if (line_arr[0].startsWith("TCP")) {
|
||||
if (line_arr[1].startsWith("TCP")) {
|
||||
port.protocol = NetworkPort.PROTO_TCP;
|
||||
port.pid = pid;
|
||||
port.port = parseInt(line_arr[2].split(":")[1]);
|
||||
port.state = line_arr[3];
|
||||
// if get port failed, skip this line
|
||||
if (isNaN(port.port)) continue;
|
||||
port.state = line_arr[4];
|
||||
result.push(port);
|
||||
}
|
||||
}
|
||||
@ -145,6 +151,8 @@ function getLinstenTcpPortLinux(pid: number): NetworkPort[] {
|
||||
port.protocol = NetworkPort.PROTO_TCP;
|
||||
port.pid = pid;
|
||||
port.port = parseInt(line_arr[3].split(":")[1]);
|
||||
// if get port failed, skip this line
|
||||
if (isNaN(port.port)) continue;
|
||||
port.state = NetworkPort.STATE_LISTEN
|
||||
result.push(port);
|
||||
}
|
||||
@ -168,6 +176,8 @@ function getLinstenTcpPortDarwin(pid: number): NetworkPort[] {
|
||||
port.protocol = NetworkPort.PROTO_TCP;
|
||||
port.pid = pid;
|
||||
port.port = parseInt(line_arr[3].split(".").pop());
|
||||
// if get port failed, skip this line
|
||||
if (isNaN(port.port)) continue;
|
||||
port.state = NetworkPort.STATE_LISTEN
|
||||
result.push(port);
|
||||
}
|
||||
@ -187,6 +197,8 @@ function getLinstenTcpPortDocker(pid: string): NetworkPort[] {
|
||||
port.protocol = NetworkPort.PROTO_TCP;
|
||||
port.pid = pid;
|
||||
port.port = parseInt(line_arr[0].split("/")[0]);
|
||||
// if get port failed, skip this line
|
||||
if (isNaN(port.port)) continue;
|
||||
port.state = NetworkPort.STATE_LISTEN
|
||||
result.push(port);
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ export default class KillCommand extends InstanceCommand {
|
||||
if (instance.config.eventTask && instance.config.eventTask.autoRestart) instance.config.eventTask.ignore = true;
|
||||
|
||||
// send stop command
|
||||
if (instance.isRunningOnDemand()) {
|
||||
instance.stopOnDemand();
|
||||
}
|
||||
return await instance.execPreset("kill");
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { $t } from "../../i18n";
|
||||
import { getProcessListeningTcpPort } from "../../common/net_tools"
|
||||
import { NetworkPort } from "../../common/net_tools"
|
||||
import EventEmitter from "events";
|
||||
import { log } from "console";
|
||||
|
||||
export class OnDemandRunner {
|
||||
public readonly STATUS_STOP = -1;
|
||||
@ -32,13 +33,23 @@ export class OnDemandRunner {
|
||||
public async run() {
|
||||
logger.info(`${this.instance.instanceUuid} `, $t("on_demand.start"));
|
||||
this.instance.println("INFO", $t("on_demand.start"));
|
||||
this.instance.execPreset("start", "OnDemandRunner");
|
||||
this.status = this.STATUS_RUNNING;
|
||||
// this.instance.execPreset("start", "OnDemandRunner");
|
||||
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.eventEmitter.emit("stop");
|
||||
logger.info(`${this.instance.instanceUuid} `, $t("on_demand.stop"));
|
||||
this.instance.println("INFO", $t("on_demand.stop"));
|
||||
if (this.instance.instanceStatus === Instance.STATUS_RUNNING) {
|
||||
this.instance.execPreset("stop", "OnDemandRunner");
|
||||
}
|
||||
this.status = this.STATUS_STOP;
|
||||
for (const server of this.socketServers) {
|
||||
server.close();
|
||||
}
|
||||
this.socketServers = new Array();
|
||||
clearInterval(this.interval);
|
||||
this.instance.instanceStatus = Instance.STATUS_STOP;
|
||||
}
|
||||
|
||||
public isRunning() {
|
||||
@ -51,7 +62,7 @@ export class OnDemandRunner {
|
||||
var established = false;
|
||||
// if no tcp port is established, guess the instance is udp or other process
|
||||
// consider it is established so that the instance will not be stopped
|
||||
if (this.ports.length === 0) established = true;
|
||||
if (this.ports.length === 0) return true;
|
||||
for (const port of this.ports) {
|
||||
if (port.established) {
|
||||
established = true;
|
||||
@ -63,24 +74,66 @@ export class OnDemandRunner {
|
||||
|
||||
private intervalCheckConnectionStatus() {
|
||||
return setInterval(() => {
|
||||
if (this.status !== this.STATUS_RUNNING) return;
|
||||
if (this.status !== this.STATUS_RUNNING ||
|
||||
!this.instance.process ||
|
||||
this.instance.instanceStatus !== Instance.STATUS_RUNNING) return;
|
||||
if (!this.anyConnectionEstablished()) {
|
||||
this.count++;
|
||||
} else {
|
||||
this.count = 0;
|
||||
}
|
||||
if (this.count > 30) {
|
||||
if (this.count > 1) {
|
||||
this.eventEmitter.emit("noConnection");
|
||||
this.count = 0;
|
||||
}
|
||||
}, 1000 * 60);
|
||||
}
|
||||
|
||||
private onNoConnection() {
|
||||
private async onNoConnection() {
|
||||
logger.info(`${this.instance.instanceUuid} `, $t("on_demand.over30minClose"));
|
||||
this.instance.println("INFO", $t("on_demand.over30minClose"));
|
||||
this.instance.execPreset("stop", "OnDemandRunner");
|
||||
let max_try = 3;
|
||||
while (true) {
|
||||
if (max_try <= 0) break;
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * 10));
|
||||
if (this.instance.instanceStatus != Instance.STATUS_STOP) {
|
||||
this.instance.execPreset("kill", "OnDemandRunner");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
max_try--;
|
||||
}
|
||||
if (max_try <= 0) {
|
||||
logger.error(`${this.instance.instanceUuid} cant kill instance`);
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
this.instance.instanceStatus = Instance.STATUS_SLEEPING;
|
||||
this.status = this.STATUS_PROXY_LISTENING;
|
||||
const net = require("net");
|
||||
for (const port of this.ports) {
|
||||
const server = net.createServer();
|
||||
server.listen(port.port, () => {
|
||||
logger.info(`${this.instance.instanceUuid} socket server listening on port ${port.port}`);
|
||||
});
|
||||
server.on("connection", (socket: any) => {
|
||||
this.eventEmitter.emit("connectionIncoming");
|
||||
});
|
||||
this.socketServers.push(server);
|
||||
}
|
||||
logger.info(`${this.instance.instanceUuid} `, $t("on_demand.instanceSleeping"));
|
||||
this.instance.println("INFO", $t("on_demand.instanceSleeping"));
|
||||
}
|
||||
|
||||
private onConnectionIncoming() {
|
||||
logger.info(`${this.instance.instanceUuid} `, $t("on_demand.playerConnected"));
|
||||
this.instance.println("INFO", $t("on_demand.playerConnected"));
|
||||
this.status = this.STATUS_RUNNING;
|
||||
for (const server of this.socketServers) {
|
||||
server.close();
|
||||
}
|
||||
this.socketServers = new Array();
|
||||
this.instance.execPreset("start", "OnDemandRunner");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user