koishi-plugin-rocom 1.0.6 → 1.0.8
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 +661 -0
- package/lib/client.d.ts +4 -0
- package/lib/client.js +56 -1
- package/lib/commands/account.d.ts +1 -1
- package/lib/commands/account.js +42 -7
- package/lib/commands/merchant.js +1 -1
- package/lib/commands/query.js +648 -14
- package/lib/render-templates/pet-panel/index.html +61 -0
- package/lib/render-templates/pet-panel/style.css +183 -0
- package/lib/render-templates/pet-panel-detail/index.html +123 -0
- package/lib/render-templates/pet-panel-detail/style.css +258 -0
- package/lib/render.d.ts +3 -3
- package/lib/render.js +33 -14
- package/package.json +1 -1
- package/readme.md +51 -519
package/lib/client.js
CHANGED
|
@@ -8,6 +8,7 @@ class RocomClient {
|
|
|
8
8
|
apiKey;
|
|
9
9
|
timeout;
|
|
10
10
|
lastError = '接口异常';
|
|
11
|
+
lastErrorBrief = '接口异常';
|
|
11
12
|
constructor(baseUrl, apiKey, timeout = 15000) {
|
|
12
13
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
13
14
|
this.apiKey = apiKey;
|
|
@@ -53,6 +54,56 @@ class RocomClient {
|
|
|
53
54
|
}
|
|
54
55
|
return err?.message || String(e);
|
|
55
56
|
}
|
|
57
|
+
simplifyErrorMessage(message) {
|
|
58
|
+
const raw = String(message || '').replace(/\s+/g, ' ').trim();
|
|
59
|
+
if (!raw)
|
|
60
|
+
return '接口异常';
|
|
61
|
+
if (/ETIMEDOUT|request timeout|timeout/i.test(raw)) {
|
|
62
|
+
return '请求超时,请稍后重试';
|
|
63
|
+
}
|
|
64
|
+
if (/ENOTFOUND|EAI_AGAIN|ECONNRESET|ECONNREFUSED|socket hang up|fetch failed|network error/i.test(raw)) {
|
|
65
|
+
return '网络连接异常,请稍后重试';
|
|
66
|
+
}
|
|
67
|
+
if (/底层凭证已失效|WeGame 凭证已失效|凭证已失效|token expired|framework token/i.test(raw)) {
|
|
68
|
+
return '登录凭证已失效,请重新登录';
|
|
69
|
+
}
|
|
70
|
+
if (/HTTP\s*5\d\d/i.test(raw)) {
|
|
71
|
+
return '服务暂时不可用,请稍后重试';
|
|
72
|
+
}
|
|
73
|
+
if (/HTTP\s*401/i.test(raw)) {
|
|
74
|
+
return '登录状态失效,请重新登录';
|
|
75
|
+
}
|
|
76
|
+
if (/API[\s_-]*Key/i.test(raw) && /未声明|默认拒绝访问|not declared|not allowed/i.test(raw)) {
|
|
77
|
+
return '接口权限受限,请稍后重试';
|
|
78
|
+
}
|
|
79
|
+
if (/HTTP\s*403/i.test(raw) && !/凭证|登录|token/i.test(raw)) {
|
|
80
|
+
return '权限不足,暂时无法访问该接口';
|
|
81
|
+
}
|
|
82
|
+
const stripped = raw
|
|
83
|
+
.replace(/^HTTP\s*\d+\s*:\s*/i, '')
|
|
84
|
+
.replace(/^(Error|RequestError)\s*:\s*/i, '')
|
|
85
|
+
.trim();
|
|
86
|
+
if (!stripped)
|
|
87
|
+
return '接口异常';
|
|
88
|
+
return stripped.length > 120 ? `${stripped.slice(0, 117)}...` : stripped;
|
|
89
|
+
}
|
|
90
|
+
shouldRetryIngameWithApiKey(errorMessage) {
|
|
91
|
+
if (!this.apiKey)
|
|
92
|
+
return false;
|
|
93
|
+
const message = String(errorMessage || '').trim();
|
|
94
|
+
if (!message)
|
|
95
|
+
return true;
|
|
96
|
+
if (/未声明\s*API\s*Key\s*权限|默认拒绝访问|API\s*Key.*not declared|API\s*Key.*not allowed/i.test(message)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
if (/缺少\s*API\s*Key|API\s*Key.*required|missing\s+api\s*key/i.test(message)) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (/HTTP\s*(401|403)/i.test(message)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
56
107
|
isSensitiveLogKey(key) {
|
|
57
108
|
return /api[-_]?key|authorization|cookie|framework[-_]?token|password|secret|ticket|token/i.test(key);
|
|
58
109
|
}
|
|
@@ -275,7 +326,7 @@ class RocomClient {
|
|
|
275
326
|
let result = await requestOnce(false, Boolean(this.apiKey));
|
|
276
327
|
if (result.status !== null)
|
|
277
328
|
return { ...result, usedApiKey: false };
|
|
278
|
-
if (this.
|
|
329
|
+
if (this.shouldRetryIngameWithApiKey(this.getLastError())) {
|
|
279
330
|
result = await requestOnce(true, false);
|
|
280
331
|
if (result.status !== null)
|
|
281
332
|
return { ...result, usedApiKey: true };
|
|
@@ -339,8 +390,12 @@ class RocomClient {
|
|
|
339
390
|
getLastError(defaultMessage = '接口异常') {
|
|
340
391
|
return this.lastError || defaultMessage;
|
|
341
392
|
}
|
|
393
|
+
getLastErrorBrief(defaultMessage = '接口异常') {
|
|
394
|
+
return this.lastErrorBrief || defaultMessage;
|
|
395
|
+
}
|
|
342
396
|
setLastError(message) {
|
|
343
397
|
this.lastError = message || '接口异常';
|
|
398
|
+
this.lastErrorBrief = this.simplifyErrorMessage(message);
|
|
344
399
|
}
|
|
345
400
|
async getPetSummary(ctx, fwToken, userIdentifier = '') {
|
|
346
401
|
return this.get(ctx, '/api/v1/games/rocom/profile/pet-summary', this.rocomHeaders(fwToken, userIdentifier));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PluginDeps } from '../types';
|
|
2
2
|
export declare function getPrimaryToken(deps: PluginDeps, userId: string): Promise<string>;
|
|
3
3
|
export declare function notLoggedInHint(): string;
|
|
4
|
-
export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string): Promise<void>;
|
|
4
|
+
export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string, preMessageIds?: string[]): Promise<void>;
|
|
5
5
|
export declare function register(deps: PluginDeps): void;
|
package/lib/commands/account.js
CHANGED
|
@@ -7,6 +7,21 @@ exports.register = register;
|
|
|
7
7
|
const koishi_1 = require("koishi");
|
|
8
8
|
const role_token_1 = require("../role-token");
|
|
9
9
|
const send_image_1 = require("../send-image");
|
|
10
|
+
const logger = new koishi_1.Logger('rocom-account');
|
|
11
|
+
async function recallMessages(session, messageIds) {
|
|
12
|
+
if (!session?.bot?.deleteMessage || !session.channelId)
|
|
13
|
+
return;
|
|
14
|
+
for (const id of messageIds) {
|
|
15
|
+
if (!id)
|
|
16
|
+
continue;
|
|
17
|
+
try {
|
|
18
|
+
await session.bot.deleteMessage(session.channelId, id);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
logger.warn(`撤回消息 ${id} 失败:${err}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
10
25
|
async function getPrimaryToken(deps, userId) {
|
|
11
26
|
const token = await (0, role_token_1.getRoleToken)(deps.ctx, userId);
|
|
12
27
|
return token?.fwt || '';
|
|
@@ -29,16 +44,29 @@ function formatLoginType(loginType) {
|
|
|
29
44
|
};
|
|
30
45
|
return typeMap[loginType] || loginType || '未知';
|
|
31
46
|
}
|
|
32
|
-
async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId) {
|
|
47
|
+
async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId, preMessageIds = []) {
|
|
33
48
|
const { ctx, client, userMgr } = deps;
|
|
34
|
-
|
|
49
|
+
const intermediateMessageIds = [...preMessageIds];
|
|
50
|
+
const sendIntermediate = async (content) => {
|
|
51
|
+
const result = await session.send(content);
|
|
52
|
+
if (Array.isArray(result)) {
|
|
53
|
+
for (const id of result) {
|
|
54
|
+
if (id)
|
|
55
|
+
intermediateMessageIds.push(String(id));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (result) {
|
|
59
|
+
intermediateMessageIds.push(String(result));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
await sendIntermediate('登录成功,正在调用绑定接口...');
|
|
35
63
|
const bindRes = await client.createBinding(ctx, fwToken, userId);
|
|
36
64
|
const bindingId = String(bindRes?.binding?.id || fwToken || '').trim();
|
|
37
65
|
if (!bindRes?.binding || !bindingId) {
|
|
38
66
|
await session.send('绑定接口调用失败,请稍后重试。');
|
|
39
67
|
return;
|
|
40
68
|
}
|
|
41
|
-
await
|
|
69
|
+
await sendIntermediate('绑定成功,正在获取角色信息...');
|
|
42
70
|
const roleRes = await client.getRole(ctx, fwToken, undefined, userId);
|
|
43
71
|
if (!roleRes?.role) {
|
|
44
72
|
await session.send('绑定成功,但获取角色信息失败,请尝试重新登录。');
|
|
@@ -61,6 +89,7 @@ async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId
|
|
|
61
89
|
roleId: binding.role_id,
|
|
62
90
|
loginType,
|
|
63
91
|
});
|
|
92
|
+
await recallMessages(session, intermediateMessageIds);
|
|
64
93
|
await session.send(`绑定成功!当前账号:${binding.nickname} (ID: ${binding.role_id})`);
|
|
65
94
|
}
|
|
66
95
|
function register(deps) {
|
|
@@ -75,7 +104,10 @@ function register(deps) {
|
|
|
75
104
|
const fwToken = qrData.frameworkToken;
|
|
76
105
|
const qrB64 = qrData.qr_image;
|
|
77
106
|
const imgData = qrB64.includes(',') ? qrB64.split(',')[1] : qrB64;
|
|
78
|
-
await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
|
|
107
|
+
const qrSendResult = await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
|
|
108
|
+
const qrMessageIds = Array.isArray(qrSendResult)
|
|
109
|
+
? qrSendResult.filter(Boolean).map(String)
|
|
110
|
+
: qrSendResult ? [String(qrSendResult)] : [];
|
|
79
111
|
const startTime = Date.now();
|
|
80
112
|
while (Date.now() - startTime < 115000) {
|
|
81
113
|
await new Promise(r => setTimeout(r, 3000));
|
|
@@ -83,7 +115,7 @@ function register(deps) {
|
|
|
83
115
|
if (!status)
|
|
84
116
|
continue;
|
|
85
117
|
if (status.status === 'done') {
|
|
86
|
-
await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId);
|
|
118
|
+
await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId, qrMessageIds);
|
|
87
119
|
return;
|
|
88
120
|
}
|
|
89
121
|
if (['expired', 'failed', 'canceled'].includes(status.status))
|
|
@@ -100,7 +132,10 @@ function register(deps) {
|
|
|
100
132
|
return '获取微信登录链接失败。';
|
|
101
133
|
const fwToken = qrData.frameworkToken;
|
|
102
134
|
const qrUrl = qrData.qr_image;
|
|
103
|
-
await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
|
|
135
|
+
const qrSendResult = await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
|
|
136
|
+
const qrMessageIds = Array.isArray(qrSendResult)
|
|
137
|
+
? qrSendResult.filter(Boolean).map(String)
|
|
138
|
+
: qrSendResult ? [String(qrSendResult)] : [];
|
|
104
139
|
const startTime = Date.now();
|
|
105
140
|
while (Date.now() - startTime < 115000) {
|
|
106
141
|
await new Promise(r => setTimeout(r, 3000));
|
|
@@ -108,7 +143,7 @@ function register(deps) {
|
|
|
108
143
|
if (!status)
|
|
109
144
|
continue;
|
|
110
145
|
if (status.status === 'done') {
|
|
111
|
-
await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId);
|
|
146
|
+
await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId, qrMessageIds);
|
|
112
147
|
return;
|
|
113
148
|
}
|
|
114
149
|
if (['expired', 'failed'].includes(status.status))
|
package/lib/commands/merchant.js
CHANGED
|
@@ -213,7 +213,7 @@ function register(deps) {
|
|
|
213
213
|
.action(async ({ session }) => {
|
|
214
214
|
const res = await client.getMerchantInfo(ctx, true);
|
|
215
215
|
if (!res)
|
|
216
|
-
return
|
|
216
|
+
return `\u83b7\u53d6\u8fdc\u884c\u5546\u4eba\u6570\u636e\u5931\u8d25\uff1a${client.getLastErrorBrief()}`;
|
|
217
217
|
const { data, fallback } = buildMerchantRenderPayload(res);
|
|
218
218
|
const png = await deps.renderer.renderHtml(ctx, 'yuanxing-shangren', data);
|
|
219
219
|
await (0, send_image_1.sendImageWithFallback)(session, png, fallback, 'merchant:yuanxing-shangren', deps.config);
|