Compare commits

..

5 commits

Author SHA1 Message Date
hippoz
9683c4f41c
kill server child process on various signals 2022-03-12 18:04:18 +02:00
hippoz
490fdf26b3
add more info to mc-status 2022-03-12 18:00:01 +02:00
hippoz
fe7f1f8b43
floor result of serverStartedAt epoch 2022-03-12 17:14:18 +02:00
hippoz
39bfae7bc2
fix "server started at" metric in the mc-status command 2022-03-12 17:12:12 +02:00
hippoz
694e0e45ed
fix server not closing on timeout 2022-03-12 17:08:52 +02:00

View file

@ -11,7 +11,6 @@ import { spawn } from "node:child_process";
import Rcon from "rcon"; import Rcon from "rcon";
const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InN0YWdpbmctbWluZWNyYWZ0LWJyaWRnZSIsImF2YXRhclVSTCI6bnVsbCwiZGlzY29yZElEIjoiMCIsImd1aWxkQWNjZXNzIjpbIjczNjI5MjUwOTEzNDc0OTgwNyJdLCJpc1N1cGVyVG9rZW4iOnRydWUsImlhdCI6MTY0NDQ1MzM4MX0.-XIBl6VLnXVwve9iqhWs51ABZkm1i_v1tS6X01SPk3U"; // A supertoken is required to send messages from Minecraft. const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InN0YWdpbmctbWluZWNyYWZ0LWJyaWRnZSIsImF2YXRhclVSTCI6bnVsbCwiZGlzY29yZElEIjoiMCIsImd1aWxkQWNjZXNzIjpbIjczNjI5MjUwOTEzNDc0OTgwNyJdLCJpc1N1cGVyVG9rZW4iOnRydWUsImlhdCI6MTY0NDQ1MzM4MX0.-XIBl6VLnXVwve9iqhWs51ABZkm1i_v1tS6X01SPk3U"; // A supertoken is required to send messages from Minecraft.
const TARGET_GUILD_ID = "_"; const TARGET_GUILD_ID = "_";
const TARGET_CHANNEL_ID = "_"; const TARGET_CHANNEL_ID = "_";
@ -57,6 +56,8 @@ class GatewayClient {
this.ws = null; this.ws = null;
this.token = null; this.token = null;
this.user = null; this.user = null;
this.wasEverReady = false;
this.isReady = false;
this.onEvent = (e) => {}; this.onEvent = (e) => {};
} }
@ -112,6 +113,8 @@ class GatewayClient {
case messageTypes.READY: { case messageTypes.READY: {
console.log("gateway: READY"); console.log("gateway: READY");
this.user = message.d.user; this.user = message.d.user;
this.wasEverReady = true;
this.isReady = true;
break; break;
} }
case messageTypes.EVENT: { case messageTypes.EVENT: {
@ -129,6 +132,7 @@ class GatewayClient {
}); });
this.ws.on("close", () => { this.ws.on("close", () => {
console.log("gateway: closed, reconnecting in 4000ms"); console.log("gateway: closed, reconnecting in 4000ms");
this.isReady = false;
setTimeout(() => { setTimeout(() => {
console.log("gateway: reconnecting"); console.log("gateway: reconnecting");
this.connect(token); this.connect(token);
@ -137,6 +141,7 @@ class GatewayClient {
this.ws.on("error", (e) => { this.ws.on("error", (e) => {
console.error("gateway: error", e); console.error("gateway: error", e);
console.log("gateway: reconnecting in 4000ms due to previous error"); console.log("gateway: reconnecting in 4000ms due to previous error");
this.isReady = false;
setTimeout(() => { setTimeout(() => {
console.log("gateway: reconnecting"); console.log("gateway: reconnecting");
this.connect(token); this.connect(token);
@ -175,9 +180,22 @@ class Bridge {
this.userRequestedServerJob(); this.userRequestedServerJob();
return; return;
} else if (e.message.content === "!:mc-status") { } else if (e.message.content === "!:mc-status") {
const message = `:scroll: **Server information**
Player Count: **${this.playerCount}**
${this.serverStartedAt ? `Started: <t:${Math.floor(this.serverStartedAt/1000)}:R>` : "Started: [server is closed]"}
:gear: **Runtime Information**:
rconConnection exists: \`${!!this.rconConnection}\`
process exists: \`${!!this.process}\`
gatewayConnection.user exists: \`${!!this.gatewayConnection.user}\`
rconConnection.hasAuthed: \`${this.rconConnection.hasAuthed}\`
gatewayConnection.isReady: \`${this.gatewayConnection.isReady}\`
gatewayConnection.wasEverReady: \`${this.gatewayConnection.wasEverReady}\`
`;
this.sendBridgeMessageAs(TARGET_GUILD_ID, this.sendBridgeMessageAs(TARGET_GUILD_ID,
TARGET_CHANNEL_ID, TARGET_CHANNEL_ID,
`:scroll: **Server information**\n**Player Count**: ${this.playerCount}\n**Started**: <t:${this.serverStartedAt}:R>`, message,
null, null,
null null
); );
@ -281,12 +299,14 @@ class Bridge {
console.log(`server process: exited with code ${code}`); console.log(`server process: exited with code ${code}`);
this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":zap: Server is now closed.", null, null); this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":zap: Server is now closed.", null, null);
this.process = null; this.process = null;
this.serverStartedAt = null;
}); });
this.process.on("error", (e) => { this.process.on("error", (e) => {
console.error("server process: error", e); console.error("server process: error", e);
this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":flushed: Server process error.", null, null); this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":flushed: Server process error.", null, null);
this.process = null; this.process = null;
this.serverStartedAt = null;
}); });
} }
@ -370,6 +390,9 @@ class Bridge {
setTimeout(() => { setTimeout(() => {
if (this.playerCount === 0) { if (this.playerCount === 0) {
console.log("server job: no players on server after 5 minutes, closing..."); console.log("server job: no players on server after 5 minutes, closing...");
if (this.process) {
this.process.kill("SIGINT");
}
this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":pensive: Server was started, yet no one joined after 5 minutes. Closing again...", null, null); this.sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, ":pensive: Server was started, yet no one joined after 5 minutes. Closing again...", null, null);
} }
}, 300000); }, 300000);
@ -380,11 +403,14 @@ function main() {
const bridge = new Bridge(); const bridge = new Bridge();
bridge.start(); bridge.start();
process.on("beforeExit", () => { const onServerClosing = () => {
if (bridge.process) { if (bridge.process)
console.log("server process: killing on parent exit");
bridge.process.kill("SIGINT"); bridge.process.kill("SIGINT");
} process.exit();
};
['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM'].forEach((eventType) => {
process.on(eventType, onServerClosing);
}); });
} }