mirror of
https://github.com/MCSManager/MCSManager.git
synced 2024-11-21 03:12:10 +08:00
Feat: ping minecraft server support
This commit is contained in:
parent
317af39265
commit
c33a40837b
@ -3,35 +3,55 @@
|
||||
|
||||
import net from "net";
|
||||
|
||||
export interface MinecraftPingResponse {
|
||||
host: string;
|
||||
port: number;
|
||||
online: boolean;
|
||||
version: string;
|
||||
motd: string;
|
||||
current_players: number;
|
||||
max_players: number;
|
||||
latency: number;
|
||||
}
|
||||
|
||||
export default class PingMinecraftServer {
|
||||
public port: number;
|
||||
public host: string;
|
||||
public status: any;
|
||||
public status: MinecraftPingResponse;
|
||||
public client?: net.Socket;
|
||||
|
||||
constructor(port: number, host: string) {
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
this.status = {
|
||||
online: null,
|
||||
version: null,
|
||||
motd: null,
|
||||
current_players: null,
|
||||
max_players: null,
|
||||
latency: null
|
||||
online: false,
|
||||
host,
|
||||
port,
|
||||
version: "",
|
||||
motd: "",
|
||||
current_players: 0,
|
||||
max_players: 0,
|
||||
latency: 0
|
||||
};
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<MinecraftPingResponse>((resolve, reject) => {
|
||||
var start_time = new Date().getTime();
|
||||
this.client = net.connect(this.port, this.host, () => {
|
||||
this.client = net.connect(
|
||||
{
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
timeout: 1000 * 15
|
||||
},
|
||||
() => {
|
||||
this.status.latency = Math.round(new Date().getTime() - start_time);
|
||||
// 0xFE packet identifier for a server list ping
|
||||
// 0x01 server list ping's payload (always 1)
|
||||
let data = Buffer.from([0xfe, 0x01]);
|
||||
this?.client?.write(data);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// The client can also receive data from the server by reading from its socket.
|
||||
this?.client?.on("data", (response: any) => {
|
||||
@ -39,9 +59,9 @@ export default class PingMinecraftServer {
|
||||
var server_info = response.toString().split("\x00\x00");
|
||||
|
||||
this.status = {
|
||||
online: true,
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
status: true,
|
||||
version: server_info[2].replace(/\u0000/g, ""),
|
||||
motd: server_info[3].replace(/\u0000/g, ""),
|
||||
current_players: server_info[4].replace(/\u0000/g, ""),
|
||||
|
@ -16,6 +16,8 @@ import RconCommand from "./steam/rcon_command";
|
||||
import DockerResizeCommand from "./docker/docker_pty_resize";
|
||||
import PtyResizeCommand from "./pty/pty_resize";
|
||||
import GeneralInstallCommand from "./general/general_install";
|
||||
import PingJavaMinecraftServerCommand from "./minecraft/mc_ping";
|
||||
import PingMinecraftServerTask from "./task/mc_players";
|
||||
|
||||
// If you add a new "Preset", Please add the definition here.
|
||||
export type IPresetCommand =
|
||||
@ -24,7 +26,7 @@ export type IPresetCommand =
|
||||
| "restart"
|
||||
| "kill"
|
||||
| "update"
|
||||
| "getPlayer"
|
||||
| "refreshPlayers"
|
||||
| "command"
|
||||
| "resize"
|
||||
| "install";
|
||||
@ -51,7 +53,7 @@ export default class FunctionDispatcher extends InstanceCommand {
|
||||
instance.setPreset("kill", new GeneralKillCommand());
|
||||
instance.setPreset("restart", new GeneralRestartCommand());
|
||||
instance.setPreset("update", new GeneralUpdateCommand());
|
||||
instance.setPreset("getPlayer", new NullCommand());
|
||||
instance.setPreset("refreshPlayers", new NullCommand());
|
||||
instance.setPreset("install", new GeneralInstallCommand());
|
||||
|
||||
// Preset the basic operation mode according to the instance startup type
|
||||
@ -74,18 +76,10 @@ export default class FunctionDispatcher extends InstanceCommand {
|
||||
instance.setPreset("command", new RconCommand());
|
||||
}
|
||||
|
||||
// Set different preset functions and functions according to different types
|
||||
// No suitable implementation solution found, not supported for the time being.
|
||||
// if (instance.config.type.includes(Instance.TYPE_UNIVERSAL)) {
|
||||
// instance.setPreset("getPlayer", new NullCommand());
|
||||
// }
|
||||
// if (instance.config.type.includes(Instance.TYPE_MINECRAFT_JAVA)) {
|
||||
// instance.setPreset("getPlayer", new MinecraftGetPlayersCommand());
|
||||
// instance.lifeCycleTaskManager.registerLifeCycleTask(new RefreshPlayer());
|
||||
// }
|
||||
// if (instance.config.type.includes(Instance.TYPE_MINECRAFT_BEDROCK)) {
|
||||
// instance.setPreset("getPlayer", new MinecraftBedrockGetPlayersCommand());
|
||||
// instance.lifeCycleTaskManager.registerLifeCycleTask(new RefreshPlayer());
|
||||
// }
|
||||
// Minecraft Ping
|
||||
if (instance.config.type.includes(Instance.TYPE_MINECRAFT_JAVA)) {
|
||||
instance.setPreset("refreshPlayers", new PingJavaMinecraftServerCommand());
|
||||
instance.lifeCycleTaskManager.registerLifeCycleTask(new PingMinecraftServerTask());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
daemon/src/entity/commands/minecraft/mc_ping.ts
Normal file
30
daemon/src/entity/commands/minecraft/mc_ping.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import Instance from "../../instance/instance";
|
||||
import InstanceCommand from "../base/command";
|
||||
import { MCServerStatus } from "common";
|
||||
|
||||
export default class PingJavaMinecraftServerCommand extends InstanceCommand {
|
||||
constructor() {
|
||||
super("PingJavaMinecraftServerCommand");
|
||||
}
|
||||
|
||||
async exec(instance: Instance) {
|
||||
const host = instance.config.pingConfig.ip || "localhost";
|
||||
try {
|
||||
if (instance.config.pingConfig.port) {
|
||||
const result = await new MCServerStatus(instance.config.pingConfig.port, host).getStatus();
|
||||
if (result.online) {
|
||||
instance.info.mcPingOnline = true;
|
||||
instance.info.currentPlayers = result.current_players;
|
||||
instance.info.maxPlayers = result.max_players;
|
||||
instance.info.version = result.version;
|
||||
} else {
|
||||
instance.resetPingInfo();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (error) {
|
||||
// ignore error
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import dgram from "dgram";
|
||||
import Instance from "../instance/instance";
|
||||
import InstanceCommand from "../commands/base/command";
|
||||
import Instance from "../../instance/instance";
|
||||
import InstanceCommand from "../base/command";
|
||||
|
||||
// Get Minecraft Bedrock server MOTD information
|
||||
// Author: https://github.com/Mcayear
|
22
daemon/src/entity/commands/task/mc_players.ts
Executable file
22
daemon/src/entity/commands/task/mc_players.ts
Executable file
@ -0,0 +1,22 @@
|
||||
import { ILifeCycleTask } from "../../instance/life_cycle";
|
||||
import Instance from "../../instance/instance";
|
||||
import { MCServerStatus } from "common";
|
||||
|
||||
// When the instance is running, continue to check the expiration time
|
||||
export default class PingMinecraftServerTask implements ILifeCycleTask {
|
||||
public status: number = 0;
|
||||
public name: string = "TimeCheck";
|
||||
|
||||
private task?: NodeJS.Timeout;
|
||||
|
||||
async start(instance: Instance) {
|
||||
this.task = setInterval(() => {
|
||||
instance.execPreset("refreshPlayers");
|
||||
}, 1000 * 60);
|
||||
}
|
||||
|
||||
async stop(instance: Instance) {
|
||||
instance.resetPingInfo();
|
||||
clearInterval(this.task);
|
||||
}
|
||||
}
|
@ -18,12 +18,14 @@ import { t } from "i18next";
|
||||
|
||||
// The instance does not need to store additional information persistently
|
||||
interface IInstanceInfo {
|
||||
mcPingOnline: boolean;
|
||||
currentPlayers: number;
|
||||
maxPlayers: number;
|
||||
version: string;
|
||||
fileLock: number;
|
||||
playersChart: Array<{ value: string }>;
|
||||
openFrpStatus: boolean;
|
||||
latency: number;
|
||||
}
|
||||
|
||||
interface IWatcherInfo {
|
||||
@ -74,12 +76,14 @@ export default class Instance extends EventEmitter {
|
||||
public config: InstanceConfig;
|
||||
|
||||
public info: IInstanceInfo = {
|
||||
currentPlayers: -1,
|
||||
maxPlayers: -1,
|
||||
mcPingOnline: false,
|
||||
currentPlayers: 0,
|
||||
maxPlayers: 0,
|
||||
version: "",
|
||||
fileLock: 0,
|
||||
playersChart: [],
|
||||
openFrpStatus: false
|
||||
openFrpStatus: false,
|
||||
latency: 0
|
||||
};
|
||||
|
||||
public watchers: Map<string, IWatcherInfo> = new Map();
|
||||
@ -407,6 +411,14 @@ export default class Instance extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
public resetPingInfo() {
|
||||
this.info.mcPingOnline = false;
|
||||
this.info.currentPlayers = 0;
|
||||
this.info.maxPlayers = 0;
|
||||
this.info.version = "";
|
||||
this.info.latency = 0;
|
||||
}
|
||||
|
||||
private pushOutput(data: string) {
|
||||
if (data.length > LINE_MAX_SIZE * 100) {
|
||||
this.outputStack.push(IGNORE_TEXT);
|
||||
|
@ -17,7 +17,7 @@ export class LifeCycleTaskManager {
|
||||
this.lifeCycleTask.push(task);
|
||||
}
|
||||
|
||||
execLifeCycleTask(type: number) {
|
||||
execLifeCycleTask(type: 1 | 0) {
|
||||
if (type == 1) {
|
||||
this.lifeCycleTask.forEach((v) => {
|
||||
if (v.status === 0) v.start(this.self);
|
||||
|
@ -1,20 +0,0 @@
|
||||
import Instance from "../instance/instance";
|
||||
import InstanceCommand from "../commands/base/command";
|
||||
import { MCServerStatus } from "common";
|
||||
|
||||
export default class MinecraftGetPlayersCommand extends InstanceCommand {
|
||||
constructor() {
|
||||
super("MinecraftGetPlayersCommand");
|
||||
}
|
||||
|
||||
async exec(instance: Instance) {
|
||||
if (instance.config.pingConfig.ip && instance.config.pingConfig.port) {
|
||||
const player = await new MCServerStatus(
|
||||
instance.config.pingConfig.port,
|
||||
instance.config.pingConfig.ip
|
||||
).getStatus();
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { $t } from "../../i18n";
|
||||
import Instance from "../instance/instance";
|
||||
import InstanceCommand from "../commands/base/command";
|
||||
|
||||
export default class MinecraftUpdateCommand extends InstanceCommand {
|
||||
constructor() {
|
||||
super("MinecraftUpdateCommand");
|
||||
}
|
||||
|
||||
async exec(instance: Instance) {
|
||||
// Not supported yet
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user