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