koishi-plugin-bind-bot 2.0.0 → 2.0.3
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/LICENSE +35 -0
- package/lib/handlers/base.handler.d.ts +16 -1
- package/lib/handlers/mcid.handler.d.ts +3 -39
- package/lib/handlers/mcid.handler.js +147 -150
- package/lib/handlers/whitelist.handler.d.ts +0 -4
- package/lib/handlers/whitelist.handler.js +9 -34
- package/lib/index.js +126 -162
- package/lib/repositories/mcidbind.repository.d.ts +13 -1
- package/lib/repositories/mcidbind.repository.js +50 -1
- package/lib/types/database.d.ts +2 -0
- package/lib/utils/error-utils.d.ts +30 -0
- package/lib/utils/error-utils.js +111 -0
- package/lib/utils/helpers.d.ts +33 -0
- package/lib/utils/helpers.js +87 -0
- package/package.json +2 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 错误处理工具函数集合
|
|
4
|
+
* 提供统一的错误信息格式化和分类功能
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getFriendlyErrorMessage = getFriendlyErrorMessage;
|
|
8
|
+
exports.getUserFacingErrorMessage = getUserFacingErrorMessage;
|
|
9
|
+
exports.isWarningError = isWarningError;
|
|
10
|
+
exports.isCriticalError = isCriticalError;
|
|
11
|
+
/**
|
|
12
|
+
* 获取用户友好的错误信息
|
|
13
|
+
* 将技术性错误转换为用户可理解的提示
|
|
14
|
+
* @param error 错误对象或错误消息字符串
|
|
15
|
+
* @returns 格式化后的用户友好错误信息
|
|
16
|
+
*/
|
|
17
|
+
function getFriendlyErrorMessage(error) {
|
|
18
|
+
const errorMsg = error instanceof Error ? error.message : error;
|
|
19
|
+
// 拆分错误信息
|
|
20
|
+
const userError = getUserFacingErrorMessage(errorMsg);
|
|
21
|
+
// 将警告级别错误标记出来
|
|
22
|
+
if (isWarningError(userError)) {
|
|
23
|
+
return `⚠️ ${userError}`;
|
|
24
|
+
}
|
|
25
|
+
// 将严重错误标记出来
|
|
26
|
+
if (isCriticalError(userError)) {
|
|
27
|
+
return `❌ ${userError}`;
|
|
28
|
+
}
|
|
29
|
+
return userError;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 提取用户友好的错误信息
|
|
33
|
+
* 根据错误消息内容返回对应的用户提示
|
|
34
|
+
* @param errorMsg 原始错误消息
|
|
35
|
+
* @returns 用户可理解的错误提示
|
|
36
|
+
*/
|
|
37
|
+
function getUserFacingErrorMessage(errorMsg) {
|
|
38
|
+
// Mojang API相关错误
|
|
39
|
+
if (errorMsg.includes('ECONNABORTED') || errorMsg.includes('timeout')) {
|
|
40
|
+
return '无法连接到Mojang服务器,请稍后再试';
|
|
41
|
+
}
|
|
42
|
+
if (errorMsg.includes('404')) {
|
|
43
|
+
return '该Minecraft用户名不存在';
|
|
44
|
+
}
|
|
45
|
+
if (errorMsg.includes('network') || errorMsg.includes('connect')) {
|
|
46
|
+
return '网络连接异常,请稍后再试';
|
|
47
|
+
}
|
|
48
|
+
// 数据库相关错误
|
|
49
|
+
if (errorMsg.includes('unique') || errorMsg.includes('duplicate')) {
|
|
50
|
+
return '该Minecraft用户名已被其他用户绑定';
|
|
51
|
+
}
|
|
52
|
+
// RCON相关错误
|
|
53
|
+
if (errorMsg.includes('RCON') || errorMsg.includes('服务器')) {
|
|
54
|
+
if (errorMsg.includes('authentication') || errorMsg.includes('auth') || errorMsg.includes('认证')) {
|
|
55
|
+
return 'RCON认证失败,服务器拒绝访问,请联系管理员检查密码';
|
|
56
|
+
}
|
|
57
|
+
if (errorMsg.includes('ECONNREFUSED') || errorMsg.includes('ETIMEDOUT') || errorMsg.includes('无法连接')) {
|
|
58
|
+
return '无法连接到游戏服务器,请确认服务器是否在线或联系管理员';
|
|
59
|
+
}
|
|
60
|
+
if (errorMsg.includes('command') || errorMsg.includes('执行命令')) {
|
|
61
|
+
return '服务器命令执行失败,请稍后再试';
|
|
62
|
+
}
|
|
63
|
+
return '与游戏服务器通信失败,请稍后再试';
|
|
64
|
+
}
|
|
65
|
+
// 用户名相关错误
|
|
66
|
+
if (errorMsg.includes('用户名') || errorMsg.includes('username')) {
|
|
67
|
+
if (errorMsg.includes('不存在')) {
|
|
68
|
+
return '该Minecraft用户名不存在,请检查拼写';
|
|
69
|
+
}
|
|
70
|
+
if (errorMsg.includes('已被')) {
|
|
71
|
+
return '该Minecraft用户名已被其他用户绑定,请使用其他用户名';
|
|
72
|
+
}
|
|
73
|
+
if (errorMsg.includes('格式')) {
|
|
74
|
+
return 'Minecraft用户名格式不正确,应为3-16位字母、数字和下划线';
|
|
75
|
+
}
|
|
76
|
+
return '用户名验证失败,请检查用户名并重试';
|
|
77
|
+
}
|
|
78
|
+
// 默认错误信息
|
|
79
|
+
return '操作失败,请稍后再试';
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 判断是否为警告级别错误(用户可能输入有误)
|
|
83
|
+
* @param errorMsg 错误消息
|
|
84
|
+
* @returns 是否为警告级别错误
|
|
85
|
+
*/
|
|
86
|
+
function isWarningError(errorMsg) {
|
|
87
|
+
const warningPatterns = [
|
|
88
|
+
'用户名不存在',
|
|
89
|
+
'格式不正确',
|
|
90
|
+
'已被其他用户绑定',
|
|
91
|
+
'已在白名单中',
|
|
92
|
+
'不在白名单中',
|
|
93
|
+
'未绑定MC账号',
|
|
94
|
+
'冷却期内'
|
|
95
|
+
];
|
|
96
|
+
return warningPatterns.some(pattern => errorMsg.includes(pattern));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 判断是否为严重错误(系统问题)
|
|
100
|
+
* @param errorMsg 错误消息
|
|
101
|
+
* @returns 是否为严重错误
|
|
102
|
+
*/
|
|
103
|
+
function isCriticalError(errorMsg) {
|
|
104
|
+
const criticalPatterns = [
|
|
105
|
+
'无法连接',
|
|
106
|
+
'RCON认证失败',
|
|
107
|
+
'服务器通信失败',
|
|
108
|
+
'数据库操作出错'
|
|
109
|
+
];
|
|
110
|
+
return criticalPatterns.some(pattern => errorMsg.includes(pattern));
|
|
111
|
+
}
|
package/lib/utils/helpers.d.ts
CHANGED
|
@@ -74,3 +74,36 @@ export declare function escapeRegExp(string: string): string;
|
|
|
74
74
|
* @returns 清理后的输入内容
|
|
75
75
|
*/
|
|
76
76
|
export declare function cleanUserInput(content: string, session: Session, botNickname: string, logger?: Logger): string;
|
|
77
|
+
/**
|
|
78
|
+
* 计算两个字符串之间的Levenshtein距离
|
|
79
|
+
* Levenshtein距离是指将一个字符串转换成另一个字符串所需的最少编辑操作次数
|
|
80
|
+
* @param str1 第一个字符串
|
|
81
|
+
* @param str2 第二个字符串
|
|
82
|
+
* @returns 两个字符串之间的编辑距离
|
|
83
|
+
*/
|
|
84
|
+
export declare function levenshteinDistance(str1: string, str2: string): number;
|
|
85
|
+
/**
|
|
86
|
+
* 计算两个字符串的相似度(基于Levenshtein距离)
|
|
87
|
+
* @param str1 第一个字符串
|
|
88
|
+
* @param str2 第二个字符串
|
|
89
|
+
* @returns 相似度值(0到1之间,1表示完全相同)
|
|
90
|
+
*/
|
|
91
|
+
export declare function calculateSimilarity(str1: string, str2: string): number;
|
|
92
|
+
/**
|
|
93
|
+
* 规范化 Minecraft 用户名(统一小写,用于存储和比较)
|
|
94
|
+
* Minecraft 用户名不区分大小写,但 Mojang 返回的是规范大小写
|
|
95
|
+
* 为避免 "Notch" 和 "notch" 被视为不同用户,统一转小写存储
|
|
96
|
+
*
|
|
97
|
+
* @param username MC 用户名
|
|
98
|
+
* @param logger Koishi Logger实例(用于日志)
|
|
99
|
+
* @returns 规范化后的用户名(小写)
|
|
100
|
+
*/
|
|
101
|
+
export declare function normalizeUsername(username: string, logger?: Logger): string;
|
|
102
|
+
/**
|
|
103
|
+
* 比较两个 Minecraft 用户名是否相同(不区分大小写)
|
|
104
|
+
*
|
|
105
|
+
* @param username1 第一个用户名
|
|
106
|
+
* @param username2 第二个用户名
|
|
107
|
+
* @returns 是否相同
|
|
108
|
+
*/
|
|
109
|
+
export declare function isSameUsername(username1: string, username2: string): boolean;
|
package/lib/utils/helpers.js
CHANGED
|
@@ -9,6 +9,10 @@ exports.getStarlightSkinUrl = getStarlightSkinUrl;
|
|
|
9
9
|
exports.checkIrrelevantInput = checkIrrelevantInput;
|
|
10
10
|
exports.escapeRegExp = escapeRegExp;
|
|
11
11
|
exports.cleanUserInput = cleanUserInput;
|
|
12
|
+
exports.levenshteinDistance = levenshteinDistance;
|
|
13
|
+
exports.calculateSimilarity = calculateSimilarity;
|
|
14
|
+
exports.normalizeUsername = normalizeUsername;
|
|
15
|
+
exports.isSameUsername = isSameUsername;
|
|
12
16
|
/**
|
|
13
17
|
* 通用工具函数集合
|
|
14
18
|
*/
|
|
@@ -273,3 +277,86 @@ function cleanUserInput(content, session, botNickname, logger) {
|
|
|
273
277
|
}
|
|
274
278
|
return cleanedContent;
|
|
275
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* 计算两个字符串之间的Levenshtein距离
|
|
282
|
+
* Levenshtein距离是指将一个字符串转换成另一个字符串所需的最少编辑操作次数
|
|
283
|
+
* @param str1 第一个字符串
|
|
284
|
+
* @param str2 第二个字符串
|
|
285
|
+
* @returns 两个字符串之间的编辑距离
|
|
286
|
+
*/
|
|
287
|
+
function levenshteinDistance(str1, str2) {
|
|
288
|
+
const matrix = [];
|
|
289
|
+
// 初始化第一列
|
|
290
|
+
for (let i = 0; i <= str2.length; i++) {
|
|
291
|
+
matrix[i] = [i];
|
|
292
|
+
}
|
|
293
|
+
// 初始化第一行
|
|
294
|
+
for (let j = 0; j <= str1.length; j++) {
|
|
295
|
+
matrix[0][j] = j;
|
|
296
|
+
}
|
|
297
|
+
// 填充矩阵
|
|
298
|
+
for (let i = 1; i <= str2.length; i++) {
|
|
299
|
+
for (let j = 1; j <= str1.length; j++) {
|
|
300
|
+
if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
|
|
301
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // 替换
|
|
305
|
+
matrix[i][j - 1] + 1, // 插入
|
|
306
|
+
matrix[i - 1][j] + 1 // 删除
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return matrix[str2.length][str1.length];
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 计算两个字符串的相似度(基于Levenshtein距离)
|
|
315
|
+
* @param str1 第一个字符串
|
|
316
|
+
* @param str2 第二个字符串
|
|
317
|
+
* @returns 相似度值(0到1之间,1表示完全相同)
|
|
318
|
+
*/
|
|
319
|
+
function calculateSimilarity(str1, str2) {
|
|
320
|
+
const distance = levenshteinDistance(str1, str2);
|
|
321
|
+
const maxLength = Math.max(str1.length, str2.length);
|
|
322
|
+
return 1 - distance / maxLength;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* 规范化 Minecraft 用户名(统一小写,用于存储和比较)
|
|
326
|
+
* Minecraft 用户名不区分大小写,但 Mojang 返回的是规范大小写
|
|
327
|
+
* 为避免 "Notch" 和 "notch" 被视为不同用户,统一转小写存储
|
|
328
|
+
*
|
|
329
|
+
* @param username MC 用户名
|
|
330
|
+
* @param logger Koishi Logger实例(用于日志)
|
|
331
|
+
* @returns 规范化后的用户名(小写)
|
|
332
|
+
*/
|
|
333
|
+
function normalizeUsername(username, logger) {
|
|
334
|
+
if (!username) {
|
|
335
|
+
logger?.warn(`[用户名规范化] 收到空用户名`);
|
|
336
|
+
return '';
|
|
337
|
+
}
|
|
338
|
+
// 移除首尾空格
|
|
339
|
+
const trimmed = username.trim();
|
|
340
|
+
// 检查是否为临时用户名,临时用户名不做转换
|
|
341
|
+
if (trimmed.startsWith('_temp_')) {
|
|
342
|
+
return trimmed;
|
|
343
|
+
}
|
|
344
|
+
// 转小写
|
|
345
|
+
const normalized = trimmed.toLowerCase();
|
|
346
|
+
if (normalized !== trimmed) {
|
|
347
|
+
logger?.debug(`[用户名规范化] "${trimmed}" -> "${normalized}"`);
|
|
348
|
+
}
|
|
349
|
+
return normalized;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* 比较两个 Minecraft 用户名是否相同(不区分大小写)
|
|
353
|
+
*
|
|
354
|
+
* @param username1 第一个用户名
|
|
355
|
+
* @param username2 第二个用户名
|
|
356
|
+
* @returns 是否相同
|
|
357
|
+
*/
|
|
358
|
+
function isSameUsername(username1, username2) {
|
|
359
|
+
if (!username1 || !username2)
|
|
360
|
+
return false;
|
|
361
|
+
return normalizeUsername(username1) === normalizeUsername(username2);
|
|
362
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-bind-bot",
|
|
3
3
|
"description": "[WittF自用] BIND-BOT - 账号绑定管理机器人,支持Minecraft账号和B站账号绑定与管理。",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.3",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"lib"
|
|
9
9
|
],
|
|
10
|
-
"license": "
|
|
10
|
+
"license": "CC-BY-NC-SA-4.0",
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc"
|
|
13
13
|
},
|