koishi-plugin-minecraft-search 1.3.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +22 -8
- package/lib/index.js +258 -64
- package/package.json +1 -1
- package/readme.md +79 -38
package/lib/index.d.ts
CHANGED
|
@@ -2,19 +2,33 @@ import { Context, Schema } from 'koishi';
|
|
|
2
2
|
export declare const name = "minecraft-search";
|
|
3
3
|
export interface ServerConfig {
|
|
4
4
|
id: number;
|
|
5
|
+
userId: string;
|
|
6
|
+
groupId: string;
|
|
5
7
|
name: string;
|
|
6
8
|
host: string;
|
|
9
|
+
port: number;
|
|
10
|
+
serverType: 'java' | 'bedrock';
|
|
11
|
+
timeout: number;
|
|
7
12
|
minekuaiInstanceId?: string;
|
|
8
|
-
timeout?: number;
|
|
9
|
-
serverType?: 'java' | 'bedrock';
|
|
10
13
|
}
|
|
11
|
-
export interface
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export interface MinekuaiSettings {
|
|
16
|
-
apiUrl: string;
|
|
14
|
+
export interface ApiKeyConfig {
|
|
15
|
+
id: number;
|
|
16
|
+
userId: string;
|
|
17
|
+
groupId: string;
|
|
17
18
|
apiKey: string;
|
|
18
19
|
}
|
|
20
|
+
export interface Config {
|
|
21
|
+
minekuaiApiUrl: string;
|
|
22
|
+
showIpInDetail: boolean;
|
|
23
|
+
}
|
|
19
24
|
export declare const Config: Schema<Config>;
|
|
25
|
+
export declare const inject: {
|
|
26
|
+
required: string[];
|
|
27
|
+
};
|
|
28
|
+
declare module 'koishi' {
|
|
29
|
+
interface Tables {
|
|
30
|
+
minecraft_server: ServerConfig;
|
|
31
|
+
minecraft_api_key: ApiKeyConfig;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
Config: () => Config,
|
|
34
34
|
apply: () => apply,
|
|
35
|
+
inject: () => inject,
|
|
35
36
|
name: () => name
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -43,23 +44,39 @@ import("mc-server-util").then((m) => {
|
|
|
43
44
|
var name = "minecraft-search";
|
|
44
45
|
var Config = import_koishi.Schema.intersect([
|
|
45
46
|
import_koishi.Schema.object({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
name: import_koishi.Schema.string().required().description("服务器名称"),
|
|
49
|
-
host: import_koishi.Schema.string().required().description("服务器地址"),
|
|
50
|
-
serverType: import_koishi.Schema.union(["java", "bedrock"]).default("java").description("服务器类型"),
|
|
51
|
-
timeout: import_koishi.Schema.number().default(5).description("查询超时时间(秒)"),
|
|
52
|
-
minekuaiInstanceId: import_koishi.Schema.string().description("麦块实例ID (可选)")
|
|
53
|
-
})).description("服务器列表").role("table").required()
|
|
54
|
-
}).description("服务器配置"),
|
|
47
|
+
minekuaiApiUrl: import_koishi.Schema.string().description("麦块API地址").default("https://minekuai.com/api/client")
|
|
48
|
+
}).description("麦块联机配置"),
|
|
55
49
|
import_koishi.Schema.object({
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
apiKey: import_koishi.Schema.string().description("麦块API密钥")
|
|
59
|
-
})
|
|
60
|
-
}).description("麦块联机配置(可选)")
|
|
50
|
+
showIpInDetail: import_koishi.Schema.boolean().default(true).description("在查询详细状态时显示服务器IP地址")
|
|
51
|
+
}).description("显示配置")
|
|
61
52
|
]);
|
|
53
|
+
var inject = {
|
|
54
|
+
required: ["database"]
|
|
55
|
+
};
|
|
62
56
|
function apply(ctx, config) {
|
|
57
|
+
ctx.model.extend("minecraft_server", {
|
|
58
|
+
id: "unsigned",
|
|
59
|
+
userId: "string",
|
|
60
|
+
groupId: "string",
|
|
61
|
+
name: "string",
|
|
62
|
+
host: "string",
|
|
63
|
+
port: "integer",
|
|
64
|
+
serverType: "string",
|
|
65
|
+
timeout: "float",
|
|
66
|
+
minekuaiInstanceId: "string"
|
|
67
|
+
}, {
|
|
68
|
+
autoInc: true,
|
|
69
|
+
primary: "id"
|
|
70
|
+
});
|
|
71
|
+
ctx.model.extend("minecraft_api_key", {
|
|
72
|
+
id: "unsigned",
|
|
73
|
+
userId: "string",
|
|
74
|
+
groupId: "string",
|
|
75
|
+
apiKey: "string"
|
|
76
|
+
}, {
|
|
77
|
+
autoInc: true,
|
|
78
|
+
primary: "id"
|
|
79
|
+
});
|
|
63
80
|
function parseServerAddress(hostString, defaultPort) {
|
|
64
81
|
if (hostString.includes(":")) {
|
|
65
82
|
const [host, portStr] = hostString.split(":");
|
|
@@ -75,14 +92,16 @@ function apply(ctx, config) {
|
|
|
75
92
|
};
|
|
76
93
|
}
|
|
77
94
|
__name(parseServerAddress, "parseServerAddress");
|
|
78
|
-
async function minekuaiApiRequest(instanceId, operation, maxRetries = 3) {
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
async function minekuaiApiRequest(instanceId, operation, groupId, maxRetries = 3) {
|
|
96
|
+
const apiKeys = await ctx.database.get("minecraft_api_key", { groupId });
|
|
97
|
+
if (!apiKeys || apiKeys.length === 0) {
|
|
98
|
+
throw new Error("本群未配置麦块API密钥,请先使用 绑定密钥 指令");
|
|
99
|
+
}
|
|
100
|
+
const apiKeyRecord = apiKeys[0];
|
|
101
|
+
const baseUrl = config.minekuaiApiUrl.replace(/\/+$/, "");
|
|
83
102
|
const url = `${baseUrl}/servers/${instanceId}/power`;
|
|
84
103
|
const headers = {
|
|
85
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
104
|
+
"Authorization": `Bearer ${apiKeyRecord.apiKey}`,
|
|
86
105
|
"Content-Type": "application/json",
|
|
87
106
|
"Accept": "application/json"
|
|
88
107
|
};
|
|
@@ -109,8 +128,7 @@ function apply(ctx, config) {
|
|
|
109
128
|
if (!getMinecraftServerStatus) {
|
|
110
129
|
throw new Error("mc-server-util 模块未正确加载");
|
|
111
130
|
}
|
|
112
|
-
const
|
|
113
|
-
const { host, port } = parseServerAddress(server.host, defaultPort);
|
|
131
|
+
const { host, port } = parseServerAddress(server.host, server.port || 25565);
|
|
114
132
|
const timeout = (server.timeout || 5) * 1e3;
|
|
115
133
|
let result;
|
|
116
134
|
if (server.serverType === "bedrock") {
|
|
@@ -142,18 +160,28 @@ function apply(ctx, config) {
|
|
|
142
160
|
}
|
|
143
161
|
}
|
|
144
162
|
__name(queryServerStatus, "queryServerStatus");
|
|
163
|
+
function getServerName(server) {
|
|
164
|
+
return server.name || "Minecraft 服务器";
|
|
165
|
+
}
|
|
166
|
+
__name(getServerName, "getServerName");
|
|
145
167
|
function formatShortStatus(result, server) {
|
|
168
|
+
const displayName = getServerName(server);
|
|
146
169
|
if (!result.online) {
|
|
147
|
-
return `🔴 ${
|
|
170
|
+
return `🔴 ${displayName} - 离线`;
|
|
148
171
|
}
|
|
149
172
|
const players = result.players ? `${result.players.online}/${result.players.max}` : "N/A";
|
|
150
173
|
const version = result.version ? result.version.name : "N/A";
|
|
151
|
-
return `🟢 ${
|
|
174
|
+
return `🟢 ${displayName} - 在线 | 玩家: ${players} | 版本: ${version}`;
|
|
152
175
|
}
|
|
153
176
|
__name(formatShortStatus, "formatShortStatus");
|
|
154
|
-
function formatDetailedStatus(result, server) {
|
|
177
|
+
function formatDetailedStatus(result, server, showIp) {
|
|
178
|
+
const displayName = getServerName(server);
|
|
155
179
|
if (!result.online) {
|
|
156
|
-
|
|
180
|
+
if (showIp) {
|
|
181
|
+
return `🔴 ${displayName} (${server.host}) 当前离线`;
|
|
182
|
+
} else {
|
|
183
|
+
return `🔴 ${displayName} 当前离线`;
|
|
184
|
+
}
|
|
157
185
|
}
|
|
158
186
|
let motdText = "暂无描述";
|
|
159
187
|
if (result.description) {
|
|
@@ -172,12 +200,13 @@ function apply(ctx, config) {
|
|
|
172
200
|
descriptionStr = descriptionStr.replace(/§[0-9a-fk-or]/gi, "");
|
|
173
201
|
motdText = descriptionStr.replace(/\n/g, " ").replace(/\s+/g, " ").trim();
|
|
174
202
|
}
|
|
175
|
-
|
|
176
|
-
const { host, port } = parseServerAddress(server.host, defaultPort);
|
|
177
|
-
let message = `🟢 ${server.name} 状态信息
|
|
203
|
+
let message = `🟢 ${displayName} 状态信息
|
|
178
204
|
`;
|
|
179
|
-
|
|
205
|
+
if (showIp) {
|
|
206
|
+
const { host, port } = parseServerAddress(server.host, server.port || 25565);
|
|
207
|
+
message += `📡 地址: ${host}:${port}
|
|
180
208
|
`;
|
|
209
|
+
}
|
|
181
210
|
message += `🎮 类型: ${server.serverType || "Java"}
|
|
182
211
|
`;
|
|
183
212
|
if (result.version) {
|
|
@@ -199,12 +228,13 @@ function apply(ctx, config) {
|
|
|
199
228
|
return message;
|
|
200
229
|
}
|
|
201
230
|
__name(formatDetailedStatus, "formatDetailedStatus");
|
|
202
|
-
ctx.command("mc/查服 [
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
231
|
+
ctx.command("mc/查服 [target:text]", "查询Minecraft服务器状态").action(async ({ session }, target) => {
|
|
232
|
+
const servers = await ctx.database.get("minecraft_server", {});
|
|
233
|
+
if (target === void 0) {
|
|
234
|
+
if (servers.length === 0) {
|
|
235
|
+
return "❌ 本群未绑定任何服务器,请先使用 绑定 指令";
|
|
206
236
|
}
|
|
207
|
-
const queries =
|
|
237
|
+
const queries = servers.map((server) => queryServerStatus(server));
|
|
208
238
|
const results = await Promise.all(queries);
|
|
209
239
|
const onlineCount = results.filter((r) => r.success && r.data && r.data.online).length;
|
|
210
240
|
let message = `📊 服务器状态汇总 (当前在线${onlineCount}/${results.length}台)
|
|
@@ -217,77 +247,203 @@ function apply(ctx, config) {
|
|
|
217
247
|
message += `[ID:${serverId}] ${originalStatus}
|
|
218
248
|
`;
|
|
219
249
|
} else {
|
|
220
|
-
message += `[ID:${serverId}] 🔴 ${result2.server
|
|
250
|
+
message += `[ID:${serverId}] 🔴 ${getServerName(result2.server)} - 离线 | 原因:${result2.error}
|
|
221
251
|
`;
|
|
222
252
|
}
|
|
223
253
|
});
|
|
224
254
|
message += `
|
|
225
|
-
💡 输入"查服+服务器ID"即可查询详细状态,例如:查服 ${
|
|
255
|
+
💡 输入"查服+服务器ID"即可查询详细状态,例如:查服 ${servers[0]?.id || 1}`;
|
|
256
|
+
message += `
|
|
257
|
+
💡 也可以直接输入IP地址查询`;
|
|
226
258
|
return message;
|
|
227
259
|
}
|
|
228
|
-
const
|
|
260
|
+
const id = parseInt(target);
|
|
261
|
+
if (!isNaN(id)) {
|
|
262
|
+
const server = servers.find((s) => s.id === id);
|
|
263
|
+
if (server) {
|
|
264
|
+
const result2 = await queryServerStatus(server);
|
|
265
|
+
if (!result2.success) {
|
|
266
|
+
return `🔴 ${getServerName(server)} - 离线 | 原因:${result2.error}`;
|
|
267
|
+
}
|
|
268
|
+
return formatDetailedStatus(result2.data, server, config.showIpInDetail);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const host = String(target);
|
|
272
|
+
const defaultPort = 25565;
|
|
273
|
+
const { host: parsedHost, port: parsedPort } = parseServerAddress(host, defaultPort);
|
|
274
|
+
const tempServer = {
|
|
275
|
+
id: 0,
|
|
276
|
+
userId: session.userId,
|
|
277
|
+
groupId: session.guildId || "",
|
|
278
|
+
name: parsedHost,
|
|
279
|
+
host: parsedHost,
|
|
280
|
+
port: parsedPort,
|
|
281
|
+
serverType: "java",
|
|
282
|
+
timeout: 5
|
|
283
|
+
};
|
|
284
|
+
const result = await queryServerStatus(tempServer);
|
|
285
|
+
if (!result.success) {
|
|
286
|
+
return `🔴 服务器 ${parsedHost}:${parsedPort} - 离线 | 原因:${result.error}`;
|
|
287
|
+
}
|
|
288
|
+
return formatDetailedStatus(result.data, tempServer, config.showIpInDetail);
|
|
289
|
+
});
|
|
290
|
+
ctx.guild().command("mc/绑定 <host:string>", "绑定Minecraft服务器").option("name", "-n <name:string>", { fallback: "" }).option("timeout", "-t <timeout:number>", { fallback: 5 }).action(async ({ session, options }, host) => {
|
|
291
|
+
if (!host) {
|
|
292
|
+
return "请提供服务器地址,例如:绑定+IP地址(不带端口时默认为25565)";
|
|
293
|
+
}
|
|
294
|
+
const groupId = session.guildId;
|
|
295
|
+
const userId = session.userId;
|
|
296
|
+
const defaultPort = 25565;
|
|
297
|
+
const { host: parsedHost, port: parsedPort } = parseServerAddress(host, defaultPort);
|
|
298
|
+
const existingServers = await ctx.database.get("minecraft_server", {
|
|
299
|
+
groupId,
|
|
300
|
+
host: parsedHost,
|
|
301
|
+
port: parsedPort
|
|
302
|
+
});
|
|
303
|
+
if (existingServers.length > 0) {
|
|
304
|
+
return `该服务器 (${parsedHost}:${parsedPort}) 已在本群绑定,服务器ID为: ${existingServers[0].id}`;
|
|
305
|
+
}
|
|
306
|
+
const createData = {
|
|
307
|
+
userId,
|
|
308
|
+
groupId,
|
|
309
|
+
host: parsedHost,
|
|
310
|
+
port: parsedPort,
|
|
311
|
+
serverType: "java",
|
|
312
|
+
timeout: options.timeout,
|
|
313
|
+
minekuaiInstanceId: ""
|
|
314
|
+
};
|
|
315
|
+
if (options.name) {
|
|
316
|
+
createData.name = options.name;
|
|
317
|
+
}
|
|
318
|
+
await ctx.database.create("minecraft_server", createData);
|
|
319
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
320
|
+
const newServer = servers[servers.length - 1];
|
|
321
|
+
return `✅ 服务器绑定成功!
|
|
322
|
+
服务器ID: ${newServer.id}
|
|
323
|
+
名称: ${newServer.name || "Minecraft 服务器"}
|
|
324
|
+
地址: ${parsedHost}:${parsedPort}`;
|
|
325
|
+
});
|
|
326
|
+
ctx.guild().command("mc/绑定密钥 <apiKey:string>", "绑定麦块API密钥").action(async ({ session }, apiKey) => {
|
|
327
|
+
if (!apiKey) {
|
|
328
|
+
return "请提供API密钥";
|
|
329
|
+
}
|
|
330
|
+
const groupId = session.guildId;
|
|
331
|
+
const userId = session.userId;
|
|
332
|
+
const existingKeys = await ctx.database.get("minecraft_api_key", { groupId });
|
|
333
|
+
if (existingKeys.length > 0) {
|
|
334
|
+
await ctx.database.set("minecraft_api_key", { groupId }, { apiKey });
|
|
335
|
+
return "✅ API密钥更新成功!";
|
|
336
|
+
}
|
|
337
|
+
await ctx.database.create("minecraft_api_key", {
|
|
338
|
+
userId,
|
|
339
|
+
groupId,
|
|
340
|
+
apiKey
|
|
341
|
+
});
|
|
342
|
+
return "✅ API密钥绑定成功!";
|
|
343
|
+
});
|
|
344
|
+
ctx.guild().command("mc/解绑 <id:number>", "解绑Minecraft服务器").action(async ({ session }, id) => {
|
|
345
|
+
if (!id) {
|
|
346
|
+
return "请提供服务器ID,例如:解绑 1";
|
|
347
|
+
}
|
|
348
|
+
const groupId = session.guildId;
|
|
349
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
350
|
+
const server = servers.find((s) => s.id === id);
|
|
229
351
|
if (!server) {
|
|
230
352
|
return `❌ 未找到ID为 ${id} 的服务器`;
|
|
231
353
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
354
|
+
await ctx.database.remove("minecraft_server", { id });
|
|
355
|
+
return `✅ 服务器 ${server.name} 已解绑`;
|
|
356
|
+
});
|
|
357
|
+
ctx.guild().command("mc/修改 <id:number>", "修改Minecraft服务器信息").option("name", "-n <name:string>", { fallback: "" }).option("timeout", "-t <timeout:number>", { fallback: 0 }).action(async ({ session, options }, id) => {
|
|
358
|
+
if (!id) {
|
|
359
|
+
return "请提供服务器ID,例如:修改 1";
|
|
360
|
+
}
|
|
361
|
+
const groupId = session.guildId;
|
|
362
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
363
|
+
const server = servers.find((s) => s.id === id);
|
|
364
|
+
if (!server) {
|
|
365
|
+
return `❌ 未找到ID为 ${id} 的服务器`;
|
|
235
366
|
}
|
|
236
|
-
|
|
367
|
+
const updates = {};
|
|
368
|
+
if (options.name) {
|
|
369
|
+
updates.name = options.name;
|
|
370
|
+
}
|
|
371
|
+
if (options.timeout > 0) {
|
|
372
|
+
updates.timeout = options.timeout;
|
|
373
|
+
}
|
|
374
|
+
if (Object.keys(updates).length === 0) {
|
|
375
|
+
return "请提供要修改的参数,使用 -n 指定新名称,-t 指定新超时时间";
|
|
376
|
+
}
|
|
377
|
+
await ctx.database.set("minecraft_server", { id }, updates);
|
|
378
|
+
const parts = [];
|
|
379
|
+
if (updates.name) parts.push(`名称: ${updates.name}`);
|
|
380
|
+
if (updates.timeout) parts.push(`超时: ${updates.timeout}秒`);
|
|
381
|
+
return `✅ 服务器信息已更新!
|
|
382
|
+
${parts.join("\n")}`;
|
|
237
383
|
});
|
|
238
|
-
ctx.command("mc/开服 <id:number>", "启动麦块服务器").action(async ({ session }, id) => {
|
|
384
|
+
ctx.guild().command("mc/开服 <id:number>", "启动麦块服务器").action(async ({ session }, id) => {
|
|
239
385
|
if (!id) return "请提供服务器ID,例如:开服 1";
|
|
240
|
-
const
|
|
241
|
-
|
|
386
|
+
const groupId = session.guildId;
|
|
387
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
388
|
+
const server = servers.find((s) => s.id === id);
|
|
389
|
+
if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
|
|
242
390
|
if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
|
|
243
391
|
try {
|
|
244
|
-
await minekuaiApiRequest(server.minekuaiInstanceId, "start", 3);
|
|
392
|
+
await minekuaiApiRequest(server.minekuaiInstanceId, "start", groupId, 3);
|
|
245
393
|
return `✅ 已发送启动指令到服务器 ${server.name} (ID: ${id})`;
|
|
246
394
|
} catch (error) {
|
|
247
395
|
return `❌ 启动服务器 ${server.name} 失败: ${error.message}`;
|
|
248
396
|
}
|
|
249
397
|
});
|
|
250
|
-
ctx.command("mc/重启 <id:number>", "重启麦块服务器").action(async ({ session }, id) => {
|
|
398
|
+
ctx.guild().command("mc/重启 <id:number>", "重启麦块服务器").action(async ({ session }, id) => {
|
|
251
399
|
if (!id) return "请提供服务器ID,例如:重启 1";
|
|
252
|
-
const
|
|
253
|
-
|
|
400
|
+
const groupId = session.guildId;
|
|
401
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
402
|
+
const server = servers.find((s) => s.id === id);
|
|
403
|
+
if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
|
|
254
404
|
if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
|
|
255
405
|
try {
|
|
256
|
-
await minekuaiApiRequest(server.minekuaiInstanceId, "restart", 3);
|
|
406
|
+
await minekuaiApiRequest(server.minekuaiInstanceId, "restart", groupId, 3);
|
|
257
407
|
return `✅ 服务器 ${server.name} 重启指令已发送完成,请稍后检查服务器状态`;
|
|
258
408
|
} catch (error) {
|
|
259
409
|
return `❌ 重启服务器 ${server.name} 失败: ${error.message}`;
|
|
260
410
|
}
|
|
261
411
|
});
|
|
262
|
-
ctx.command("mc/强制重启 <id:number>", "强制重启麦块服务器").action(async ({ session }, id) => {
|
|
412
|
+
ctx.guild().command("mc/强制重启 <id:number>", "强制重启麦块服务器").action(async ({ session }, id) => {
|
|
263
413
|
if (!id) return "请提供服务器ID,例如:强制重启 1";
|
|
264
|
-
const
|
|
265
|
-
|
|
414
|
+
const groupId = session.guildId;
|
|
415
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
416
|
+
const server = servers.find((s) => s.id === id);
|
|
417
|
+
if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
|
|
266
418
|
if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
|
|
267
419
|
try {
|
|
268
|
-
await minekuaiApiRequest(server.minekuaiInstanceId, "stop", 3);
|
|
420
|
+
await minekuaiApiRequest(server.minekuaiInstanceId, "stop", groupId, 3);
|
|
269
421
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
270
|
-
await minekuaiApiRequest(server.minekuaiInstanceId, "kill", 3);
|
|
422
|
+
await minekuaiApiRequest(server.minekuaiInstanceId, "kill", groupId, 3);
|
|
271
423
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
272
|
-
await minekuaiApiRequest(server.minekuaiInstanceId, "start", 3);
|
|
424
|
+
await minekuaiApiRequest(server.minekuaiInstanceId, "start", groupId, 3);
|
|
273
425
|
return `✅ 服务器 ${server.name} 强制重启指令已发送完成,请稍后检查服务器状态`;
|
|
274
426
|
} catch (error) {
|
|
275
427
|
return `❌ 强制重启服务器 ${server.name} 失败: ${error.message}`;
|
|
276
428
|
}
|
|
277
429
|
});
|
|
278
|
-
ctx.command("mc/资源 <id:number>", "查看麦块服务器资源使用情况").action(async ({ session }, id) => {
|
|
430
|
+
ctx.guild().command("mc/资源 <id:number>", "查看麦块服务器资源使用情况").action(async ({ session }, id) => {
|
|
279
431
|
if (!id) return "请提供服务器ID,例如:资源 1";
|
|
280
|
-
const
|
|
281
|
-
|
|
432
|
+
const groupId = session.guildId;
|
|
433
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
434
|
+
const server = servers.find((s) => s.id === id);
|
|
435
|
+
if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
|
|
282
436
|
if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
|
|
283
437
|
try {
|
|
284
|
-
const
|
|
285
|
-
if (!
|
|
286
|
-
|
|
287
|
-
|
|
438
|
+
const apiKeys = await ctx.database.get("minecraft_api_key", { groupId });
|
|
439
|
+
if (!apiKeys || apiKeys.length === 0) {
|
|
440
|
+
throw new Error("本群未配置麦块API密钥,请先使用 绑定密钥 指令");
|
|
441
|
+
}
|
|
442
|
+
const apiKeyRecord = apiKeys[0];
|
|
443
|
+
const baseUrl = config.minekuaiApiUrl.replace(/\/+$/, "");
|
|
288
444
|
const url = `${baseUrl}/servers/${server.minekuaiInstanceId}/resources`;
|
|
289
445
|
const headers = {
|
|
290
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
446
|
+
"Authorization": `Bearer ${apiKeyRecord.apiKey}`,
|
|
291
447
|
"Content-Type": "application/json",
|
|
292
448
|
"Accept": "application/json"
|
|
293
449
|
};
|
|
@@ -330,11 +486,49 @@ function apply(ctx, config) {
|
|
|
330
486
|
return `❌ 查询服务器 ${server.name} 资源使用情况失败: ${error.message}`;
|
|
331
487
|
}
|
|
332
488
|
});
|
|
489
|
+
ctx.guild().command("mc/服务器列表", "查看已绑定的服务器列表").action(async ({ session }) => {
|
|
490
|
+
const groupId = session.guildId;
|
|
491
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
492
|
+
if (servers.length === 0) {
|
|
493
|
+
return "本群暂未绑定任何服务器";
|
|
494
|
+
}
|
|
495
|
+
let message = `📋 本群已绑定 ${servers.length} 台服务器:
|
|
496
|
+
|
|
497
|
+
`;
|
|
498
|
+
servers.forEach((server) => {
|
|
499
|
+
message += `[ID:${server.id}] ${server.name}
|
|
500
|
+
`;
|
|
501
|
+
message += ` 地址: ${server.host}:${server.port}
|
|
502
|
+
`;
|
|
503
|
+
message += ` 类型: ${server.serverType} | 超时: ${server.timeout}秒
|
|
504
|
+
`;
|
|
505
|
+
if (server.minekuaiInstanceId) {
|
|
506
|
+
message += ` 麦块实例: ${server.minekuaiInstanceId}
|
|
507
|
+
`;
|
|
508
|
+
}
|
|
509
|
+
message += "\n";
|
|
510
|
+
});
|
|
511
|
+
return message.trim();
|
|
512
|
+
});
|
|
513
|
+
ctx.guild().command("mc/设置实例 <id:number> <instanceId:string>", "设置服务器的麦块实例ID").action(async ({ session }, id, instanceId) => {
|
|
514
|
+
if (!id || !instanceId) {
|
|
515
|
+
return "请提供服务器ID和实例ID,例如:设置实例 1 abc123";
|
|
516
|
+
}
|
|
517
|
+
const groupId = session.guildId;
|
|
518
|
+
const servers = await ctx.database.get("minecraft_server", { groupId });
|
|
519
|
+
const server = servers.find((s) => s.id === id);
|
|
520
|
+
if (!server) {
|
|
521
|
+
return `❌ 未找到ID为 ${id} 的服务器`;
|
|
522
|
+
}
|
|
523
|
+
await ctx.database.set("minecraft_server", { id }, { minekuaiInstanceId: instanceId });
|
|
524
|
+
return `✅ 服务器 ${server.name} 的麦块实例ID已设置为: ${instanceId}`;
|
|
525
|
+
});
|
|
333
526
|
}
|
|
334
527
|
__name(apply, "apply");
|
|
335
528
|
// Annotate the CommonJS export names for ESM import in node:
|
|
336
529
|
0 && (module.exports = {
|
|
337
530
|
Config,
|
|
338
531
|
apply,
|
|
532
|
+
inject,
|
|
339
533
|
name
|
|
340
534
|
});
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
### ⚡ 服务器电源控制
|
|
17
17
|
- 支持通过麦块联机 API 启动服务器
|
|
18
18
|
- 支持通过麦块联机 API 重启服务器
|
|
19
|
+
- 支持通过麦块联机 API 强制重启服务器
|
|
19
20
|
- 自动重试机制,提高操作成功率
|
|
20
21
|
|
|
21
22
|
### 📊 服务器资源查询
|
|
@@ -25,6 +26,18 @@
|
|
|
25
26
|
- 显示服务器运行时间
|
|
26
27
|
- 显示服务器状态和暂停状态
|
|
27
28
|
|
|
29
|
+
### 🗄️ 数据库存储
|
|
30
|
+
- 使用数据库存储服务器配置,支持多群组管理
|
|
31
|
+
- 支持按群组绑定服务器,每个群组只能管理自己的服务器
|
|
32
|
+
- 支持 API 密钥按群组存储
|
|
33
|
+
|
|
34
|
+
### 🔧 服务器管理
|
|
35
|
+
- 支持绑定服务器(自动解析地址和端口)
|
|
36
|
+
- 支持解绑服务器
|
|
37
|
+
- 支持修改服务器信息(名称、超时时间)
|
|
38
|
+
- 支持设置麦块实例ID
|
|
39
|
+
- 支持查看服务器列表
|
|
40
|
+
|
|
28
41
|
## 安装
|
|
29
42
|
|
|
30
43
|
1. 安装插件:
|
|
@@ -36,34 +49,30 @@ npm install koishi-plugin-minecraft-search
|
|
|
36
49
|
|
|
37
50
|
## 配置说明
|
|
38
51
|
|
|
39
|
-
###
|
|
40
|
-
```typescript
|
|
41
|
-
servers: [
|
|
42
|
-
{
|
|
43
|
-
id: 1, // 服务器ID(数字)
|
|
44
|
-
name: "主服务器", // 服务器名称
|
|
45
|
-
host: "play.example.com:25565", // 服务器地址(支持带端口)
|
|
46
|
-
serverType: "java", // 服务器类型:java/bedrock
|
|
47
|
-
timeout: 5.0, // 查询超时时间(秒)
|
|
48
|
-
minekuaiInstanceId: "xxx" // 麦块实例ID(可选,用于电源控制)
|
|
49
|
-
}
|
|
50
|
-
]
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 麦块联机配置(可选)
|
|
52
|
+
### 基础配置
|
|
54
53
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
{
|
|
55
|
+
"minekuaiApiUrl": "https://minekuai.com/api/client", // 麦块API地址
|
|
56
|
+
"showIpInDetail": true // 是否在详细状态中显示IP地址
|
|
58
57
|
}
|
|
59
58
|
```
|
|
60
59
|
|
|
61
60
|
## 使用指令
|
|
62
61
|
|
|
62
|
+
### 服务器管理
|
|
63
|
+
```
|
|
64
|
+
mc/绑定 <host> [-n <name>] [-t <timeout>] # 绑定服务器,支持指定名称和超时时间
|
|
65
|
+
mc/解绑 <id> # 解绑服务器
|
|
66
|
+
mc/修改 <id> [-n <name>] [-t <timeout>] # 修改服务器信息
|
|
67
|
+
mc/服务器列表 # 查看已绑定的服务器列表
|
|
68
|
+
mc/设置实例 <id> <instanceId> # 设置服务器的麦块实例ID
|
|
69
|
+
mc/绑定API密钥 <apiKey> # 绑定麦块API密钥
|
|
70
|
+
```
|
|
71
|
+
|
|
63
72
|
### 查询服务器状态
|
|
64
73
|
```
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
mc/查服 # 查询全部服务器状态(简短信息)
|
|
75
|
+
mc/查服 1 # 查询ID为1的服务器的详细信息
|
|
67
76
|
```
|
|
68
77
|
|
|
69
78
|
**输出示例:**
|
|
@@ -79,14 +88,14 @@ minekuaiSettings: {
|
|
|
79
88
|
|
|
80
89
|
### 服务器电源控制
|
|
81
90
|
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
mc/开服 1 # 启动ID为1的麦块服务器
|
|
92
|
+
mc/重启 1 # 重启ID为1的麦块服务器
|
|
93
|
+
mc/强制重启 1 # 强制重启ID为1的麦块服务器
|
|
85
94
|
```
|
|
86
95
|
|
|
87
96
|
### 服务器资源查询
|
|
88
97
|
```
|
|
89
|
-
|
|
98
|
+
mc/资源 1 # 查看ID为1的麦块服务器资源使用情况
|
|
90
99
|
```
|
|
91
100
|
|
|
92
101
|
**输出示例:**
|
|
@@ -103,15 +112,35 @@ minekuaiSettings: {
|
|
|
103
112
|
⏰ 查询时间: 2026-03-13 12:00:00
|
|
104
113
|
```
|
|
105
114
|
|
|
106
|
-
##
|
|
107
|
-
|
|
108
|
-
###
|
|
109
|
-
- `
|
|
110
|
-
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
+
## 指令说明
|
|
116
|
+
|
|
117
|
+
### 绑定服务器
|
|
118
|
+
- **命令**:`mc/绑定 <host> [-n <name>] [-t <timeout>]`
|
|
119
|
+
- **参数**:
|
|
120
|
+
- `<host>`:服务器地址,支持带端口格式(如:`play.example.com:25565`)
|
|
121
|
+
- `-n <name>`:服务器名称(可选,默认使用地址作为名称)
|
|
122
|
+
- `-t <timeout>`:查询超时时间(可选,默认5秒)
|
|
123
|
+
- **示例**:
|
|
124
|
+
- `mc/绑定 s3.ungc.com.cn` - 绑定默认端口的服务器
|
|
125
|
+
- `mc/绑定 s3.ungc.com.cn:37095 -n 测试服 -t 10` - 绑定指定端口、名称和超时的服务器
|
|
126
|
+
|
|
127
|
+
### 绑定API密钥
|
|
128
|
+
- **命令**:`mc/绑定API密钥 <apiKey>`
|
|
129
|
+
- **参数**:
|
|
130
|
+
- `<apiKey>`:麦块联机平台的API密钥
|
|
131
|
+
- **说明**:每个群组只需绑定一次,后续会自动使用该密钥
|
|
132
|
+
|
|
133
|
+
### 服务器管理指令
|
|
134
|
+
- **`mc/解绑 <id>`**:解绑指定ID的服务器
|
|
135
|
+
- **`mc/修改 <id> [-n <name>] [-t <timeout>]`**:修改服务器名称或超时时间
|
|
136
|
+
- **`mc/设置实例 <id> <instanceId>`**:为服务器设置麦块实例ID,用于电源控制
|
|
137
|
+
- **`mc/服务器列表`**:查看当前群组已绑定的所有服务器
|
|
138
|
+
|
|
139
|
+
### 服务器控制指令
|
|
140
|
+
- **`mc/开服 <id>`**:启动指定服务器
|
|
141
|
+
- **`mc/重启 <id>`**:重启指定服务器
|
|
142
|
+
- **`mc/强制重启 <id>`**:强制停止并重启指定服务器
|
|
143
|
+
- **`mc/资源 <id>`**:查询服务器资源使用情况
|
|
115
144
|
|
|
116
145
|
## 技术特性
|
|
117
146
|
|
|
@@ -120,19 +149,22 @@ minekuaiSettings: {
|
|
|
120
149
|
- 📱 **友好输出格式**:使用 emoji 和清晰排版,信息易读
|
|
121
150
|
- ⚡ **高性能查询**:支持并行查询多个服务器
|
|
122
151
|
- 🛡️ **错误处理**:完善的错误处理和用户提示
|
|
152
|
+
- 🗄️ **数据库存储**:使用数据库存储服务器配置,支持多群组管理
|
|
153
|
+
- 🔒 **权限控制**:每个群组只能管理自己绑定的服务器
|
|
123
154
|
|
|
124
155
|
## 依赖说明
|
|
125
156
|
|
|
126
157
|
- 使用 https://www.npmjs.com/package/mc-server-util 库进行服务器状态查询
|
|
127
158
|
- 支持麦块联机平台的 API 集成
|
|
128
|
-
- 基于 Koishi
|
|
159
|
+
- 基于 Koishi 框架开发,依赖数据库插件
|
|
129
160
|
|
|
130
161
|
## 注意事项
|
|
131
162
|
|
|
132
163
|
1. 麦块联机功能需要配置正确的 API 地址和密钥
|
|
133
|
-
2.
|
|
134
|
-
3.
|
|
135
|
-
4.
|
|
164
|
+
2. 服务器地址支持带端口格式(如:`play.example.com:25565`)
|
|
165
|
+
3. 插件会自动处理 MOTD 中的换行符,确保输出整洁
|
|
166
|
+
4. 所有服务器操作指令均限制为群组指令,只能操作本群绑定的服务器
|
|
167
|
+
5. API 密钥按群组存储,每个群组需要单独绑定
|
|
136
168
|
|
|
137
169
|
## 故障排除
|
|
138
170
|
|
|
@@ -141,11 +173,20 @@ minekuaiSettings: {
|
|
|
141
173
|
- 网络连接是否正常
|
|
142
174
|
- 防火墙是否阻止了查询请求
|
|
143
175
|
- 麦块 API 配置是否正确
|
|
176
|
+
- 服务器是否为本群绑定的服务器
|
|
144
177
|
|
|
145
178
|
## 更新日志
|
|
146
179
|
<details>
|
|
147
180
|
<summary>点我查看更新日志详情</summary>
|
|
148
181
|
|
|
182
|
+
### v2.0.0
|
|
183
|
+
- 全新数据库存储架构,支持多群组管理
|
|
184
|
+
- 新增服务器绑定、解绑、修改等管理指令
|
|
185
|
+
- 支持按群组存储 API 密钥
|
|
186
|
+
- 增加服务器列表查看功能
|
|
187
|
+
- 优化错误提示,明确权限限制
|
|
188
|
+
- 移除配置文件中的服务器列表,改为数据库存储
|
|
189
|
+
|
|
149
190
|
### v1.3.6
|
|
150
191
|
- 新增服务器资源使用情况查询功能
|
|
151
192
|
- 支持查看 CPU、内存、磁盘使用情况
|
|
@@ -176,4 +217,4 @@ minekuaiSettings: {
|
|
|
176
217
|
|
|
177
218
|
## 支持与反馈
|
|
178
219
|
|
|
179
|
-
如有问题或建议,请通过相关渠道联系开发者。
|
|
220
|
+
如有问题或建议,请通过相关渠道联系开发者。
|