@sphekes/koishi-plugin-palctrl
Version:
A simple extension to manage PalWorld Server
259 lines (255 loc) • 11.1 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Config: () => Config,
apply: () => apply,
inject: () => inject,
name: () => name
});
module.exports = __toCommonJS(src_exports);
var import_ping = __toESM(require("ping"));
var import_nodejs_winrm = __toESM(require("nodejs-winrm"));
// src/config.ts
var import_koishi = require("koishi");
var Config = import_koishi.Schema.intersect([
import_koishi.Schema.object({
host: import_koishi.Schema.string().description("幻兽帕鲁服务器名").required(),
timeout: import_koishi.Schema.number().description("请求超时时间[ms]").default(1e3)
}).description("基本设置"),
import_koishi.Schema.object({
// restUrl: Schema.string().description("幻兽帕鲁服务器 REST API 地址(例: http://localhost:8212/v1/api/)<br>建议公网帕鲁服务器使用 HTTPS 反代 API 确保账号密码安全").required(),
restPort: import_koishi.Schema.number().description("REST API 端口号").default(8212),
restUsername: import_koishi.Schema.string().description("管理员名称").default("admin"),
restPassword: import_koishi.Schema.string().description("管理员密码").default("123456"),
useHttps: import_koishi.Schema.boolean().description("是否使用https").default(false)
}).description("REST api连接设置"),
import_koishi.Schema.object({
winrmPort: import_koishi.Schema.number().description("winRM 端口号").default(5985),
winrmUsername: import_koishi.Schema.string().description("openssh 用户名").default(""),
winrmPassword: import_koishi.Schema.string().description("openssh 密码,需要开启密码登录").default(""),
winrmServiceName: import_koishi.Schema.string().description("PalWorld服务名").default("PalServer")
}).description("WinRM连接设置")
]);
// src/index.ts
var name = "azimiao-palworld-server-tool";
var inject = ["http"];
function apply(ctx, config) {
function wr_ping(host) {
return setTimeoutPromise(import_ping.default.promise.probe(host));
}
__name(wr_ping, "wr_ping");
function wr_get(url, config2) {
return setTimeoutPromise(ctx.http.get(url, config2));
}
__name(wr_get, "wr_get");
function wr_post(url, data, config2) {
return setTimeoutPromise(ctx.http.post(url, data, config2));
}
__name(wr_post, "wr_post");
function wr_runCommand(command, host, name2, pass, port) {
return setTimeoutPromise(import_nodejs_winrm.default.runCommand(command, host, name2, pass, port));
}
__name(wr_runCommand, "wr_runCommand");
function setTimeoutPromise(promise) {
const timeoutPromise = new Promise(
(_, reject) => setTimeout(() => reject(new Error("Operation timed out")), config.timeout)
);
return Promise.race([promise, timeoutPromise]);
}
__name(setTimeoutPromise, "setTimeoutPromise");
function getFullUrl(method) {
let url = `http://${config.host}:${config.restPort}/v1/api/${method}`;
return url;
}
__name(getFullUrl, "getFullUrl");
ctx.command("pal", "控制帕鲁服务器").action((_) => {
return `控制帕鲁服务器`;
});
ctx.command("pal").subcommand("info [arg]", "获取幻兽帕鲁服务器信息").action(async (argv, arg) => {
let msg = "";
if (arg == "ping") {
await wr_ping(config.host).then((res) => {
msg = res.alive ? `主机${config.host}在线,ping延迟 ${res.time} ms。` : `主机${config.host}不在线。`;
}).catch((err) => {
console.error("Error pinging the server:", err);
});
} else {
await wr_get(getFullUrl("info"), {
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64")
},
responseType: "json"
}).then(async (res) => {
if (res.servername && res.version && res.description) {
msg = `帕鲁服务器运行中
- 名称: ${res.servername}
- 版本: ${res.version}
- 描述: ${res.description}`;
await wr_get(getFullUrl("metrics"), {
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64")
},
responseType: "json"
}).then((res2) => {
res2 ? msg += ` - 当前玩家数: ${res2.currentplayernum}
- 服务器帧率: ${res2.serverfps}fps
- 游玩天数: ${res2.days}
- 服务器运行时间: ${res2.uptime}s
` : msg = "获取信息失败: 返回信息错误";
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
} else {
msg = "获取信息失败: 返回信息错误";
}
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
}
return msg;
});
ctx.command("pal").subcommand("players", "获取幻兽帕鲁服务器在线玩家").action(async (argv) => {
let msg = "";
await wr_get(getFullUrl("players"), {
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64")
},
responseType: "json"
}).then((res) => {
if (res.players) {
if (res.players.length > 0) {
msg = `当前共有 ${res.players.length} 位玩家在线:
`;
res.players.forEach((player, index) => {
msg += `- [Lv.${player.level}] ${player.name} ${player.userId}\r
`;
});
} else {
msg = "当前没有玩家在线";
}
} else {
msg = "获取信息失败: 返回信息错误";
}
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
return msg;
});
ctx.command("pal").subcommand("announce <message:text>", "向帕鲁服务器发送公屏消息").action(async (_, message) => {
let msg = "";
if (!message) {
return "请输入发送的消息";
}
await wr_post(
getFullUrl("announce"),
JSON.stringify({
"message": message
}),
{
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64"),
"Content-Type": "application/json"
}
}
).then((res) => {
msg = `发送成功,${res}`;
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
return msg;
});
ctx.command("pal").subcommand("save", "向幻兽帕鲁服务器发送保存命令").action(async (argv, message) => {
let msg = "";
await wr_post(
getFullUrl("save"),
"",
{
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64")
}
}
).then((res) => {
msg = `保存成功,${res}`;
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
return msg;
});
ctx.command("pal").subcommand("start", "启动帕鲁服务器").action(async (_) => {
let msg = "";
try {
var result = await wr_runCommand(`sc start ${config.winrmServiceName}`, config.host, config.winrmUsername, config.winrmPassword, config.winrmPort);
msg = result;
} catch (error) {
msg = `请求失败: ${error}`;
}
return msg;
});
ctx.command("pal").subcommand("stop", "立刻关闭帕鲁服务器").action(async (_) => {
let msg = "";
try {
var result = await wr_runCommand(`sc stop ${config.winrmServiceName}`, config.host, config.winrmUsername, config.winrmPassword, config.winrmPort);
msg = result;
} catch (error) {
msg = `请求失败: ${error}`;
}
return msg;
});
ctx.command("pal").subcommand("shutdown", "关闭帕鲁服务器并发送消息").option("now", "-n").option("waittime", "-t <waittime>").option("message", "-m <message>").action(async ({ options }) => {
let msg = "";
await wr_post(
getFullUrl("shutdown"),
JSON.stringify({
"waittime": !options || options.now ? 1 : options.waittime ? options.waittime : 30,
"message": options && options.message ? options.message : "服务器将在30s后关闭"
}),
{
headers: {
"Authorization": "Basic " + Buffer.from(`${config.restUsername}:${config.restPassword}`).toString("base64"),
"Content-Type": "application/json"
}
}
).then((res) => {
msg = `发送成功,${res}`;
}).catch((error) => {
msg = error.response ? `请求错误: ${error.response.data}` : `请求失败: ${error.code ? `错误码 ${error.code})}` : "连接服务器失败,请检查服务器状态或后台配置信息"}`;
});
return msg;
});
}
__name(apply, "apply");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Config,
apply,
inject,
name
});