@tencent-weixin/openclaw-weixin 2.1.9 → 2.1.10
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/api/api.ts +34 -0
- package/src/api/types.ts +22 -0
- package/src/channel.ts +32 -0
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/api/api.ts
CHANGED
|
@@ -13,6 +13,8 @@ import type {
|
|
|
13
13
|
GetUploadUrlResp,
|
|
14
14
|
GetUpdatesReq,
|
|
15
15
|
GetUpdatesResp,
|
|
16
|
+
NotifyStopResp,
|
|
17
|
+
NotifyStartResp,
|
|
16
18
|
SendMessageReq,
|
|
17
19
|
SendTypingReq,
|
|
18
20
|
GetConfigResp,
|
|
@@ -316,3 +318,35 @@ export async function sendTyping(
|
|
|
316
318
|
label: "sendTyping",
|
|
317
319
|
});
|
|
318
320
|
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Notify Weixin that this channel client is stopping (gateway shutdown / channel stop).
|
|
324
|
+
* Uses a standalone timeout (not the gateway abort signal) so the request can finish
|
|
325
|
+
* after OpenClaw has already aborted the long-poll.
|
|
326
|
+
*/
|
|
327
|
+
export async function notifyStop(params: WeixinApiOptions): Promise<NotifyStopResp> {
|
|
328
|
+
const rawText = await apiPostFetch({
|
|
329
|
+
baseUrl: params.baseUrl,
|
|
330
|
+
endpoint: "ilink/bot/msg/notifystop",
|
|
331
|
+
body: JSON.stringify({ base_info: buildBaseInfo() }),
|
|
332
|
+
token: params.token,
|
|
333
|
+
timeoutMs: params.timeoutMs ?? DEFAULT_CONFIG_TIMEOUT_MS,
|
|
334
|
+
label: "notifyStop",
|
|
335
|
+
});
|
|
336
|
+
return JSON.parse(rawText) as NotifyStopResp;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Notify Weixin that this channel client is starting (gateway startup / channel start).
|
|
341
|
+
*/
|
|
342
|
+
export async function notifyStart(params: WeixinApiOptions): Promise<NotifyStartResp> {
|
|
343
|
+
const rawText = await apiPostFetch({
|
|
344
|
+
baseUrl: params.baseUrl,
|
|
345
|
+
endpoint: "ilink/bot/msg/notifystart",
|
|
346
|
+
body: JSON.stringify({ base_info: buildBaseInfo() }),
|
|
347
|
+
token: params.token,
|
|
348
|
+
timeoutMs: params.timeoutMs ?? DEFAULT_CONFIG_TIMEOUT_MS,
|
|
349
|
+
label: "notifyStart",
|
|
350
|
+
});
|
|
351
|
+
return JSON.parse(rawText) as NotifyStartResp;
|
|
352
|
+
}
|
package/src/api/types.ts
CHANGED
|
@@ -224,3 +224,25 @@ export interface GetConfigResp {
|
|
|
224
224
|
/** Base64-encoded typing ticket for sendTyping. */
|
|
225
225
|
typing_ticket?: string;
|
|
226
226
|
}
|
|
227
|
+
|
|
228
|
+
/** proto: NotifyStopReq — notify server when the channel client is stopping. */
|
|
229
|
+
export interface NotifyStopReq {
|
|
230
|
+
base_info?: BaseInfo;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** proto: NotifyStopResp */
|
|
234
|
+
export interface NotifyStopResp {
|
|
235
|
+
ret?: number;
|
|
236
|
+
errmsg?: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** proto: NotifyStartReq — notify server when the channel client is starting. */
|
|
240
|
+
export interface NotifyStartReq {
|
|
241
|
+
base_info?: BaseInfo;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** proto: NotifyStartResp */
|
|
245
|
+
export interface NotifyStartResp {
|
|
246
|
+
ret?: number;
|
|
247
|
+
errmsg?: string;
|
|
248
|
+
}
|
package/src/channel.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
DEFAULT_BASE_URL,
|
|
16
16
|
} from "./auth/accounts.js";
|
|
17
17
|
import type { ResolvedWeixinAccount } from "./auth/accounts.js";
|
|
18
|
+
import { notifyStop, notifyStart } from "./api/api.js";
|
|
18
19
|
import { assertSessionActive } from "./api/session-guard.js";
|
|
19
20
|
import { getContextToken, findAccountIdsByContextToken, restoreContextTokens, clearContextTokensForAccount } from "./messaging/inbound.js";
|
|
20
21
|
import { logger } from "./util/logger.js";
|
|
@@ -427,6 +428,18 @@ export const weixinPlugin: ChannelPlugin<ResolvedWeixinAccount> = {
|
|
|
427
428
|
|
|
428
429
|
ctx.log?.info?.(`[${account.accountId}] starting weixin provider (${DEFAULT_BASE_URL})`);
|
|
429
430
|
|
|
431
|
+
try {
|
|
432
|
+
const resp = await notifyStart({
|
|
433
|
+
baseUrl: account.baseUrl,
|
|
434
|
+
token: account.token,
|
|
435
|
+
});
|
|
436
|
+
if (resp.ret !== undefined && resp.ret !== 0) {
|
|
437
|
+
aLog.warn(`notifyStart: ret=${resp.ret} errmsg=${resp.errmsg ?? ""}`);
|
|
438
|
+
}
|
|
439
|
+
} catch (err) {
|
|
440
|
+
aLog.warn(`notifyStart failed during startup (ignored): ${String(err)}`);
|
|
441
|
+
}
|
|
442
|
+
|
|
430
443
|
const logPath = aLog.getLogFilePath();
|
|
431
444
|
ctx.log?.info?.(`[${account.accountId}] weixin logs: ${logPath}`);
|
|
432
445
|
|
|
@@ -442,6 +455,25 @@ export const weixinPlugin: ChannelPlugin<ResolvedWeixinAccount> = {
|
|
|
442
455
|
setStatus: ctx.setStatus,
|
|
443
456
|
});
|
|
444
457
|
},
|
|
458
|
+
stopAccount: async (ctx) => {
|
|
459
|
+
const account = ctx.account;
|
|
460
|
+
const aLog = logger.withAccount(account.accountId);
|
|
461
|
+
if (!account.configured || !account.token?.trim()) {
|
|
462
|
+
aLog.debug(`gateway.stopAccount: skip notifyStop (not configured or no token)`);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
try {
|
|
466
|
+
const resp = await notifyStop({
|
|
467
|
+
baseUrl: account.baseUrl,
|
|
468
|
+
token: account.token,
|
|
469
|
+
});
|
|
470
|
+
if (resp.ret !== undefined && resp.ret !== 0) {
|
|
471
|
+
aLog.warn(`notifyStop: ret=${resp.ret} errmsg=${resp.errmsg ?? ""}`);
|
|
472
|
+
}
|
|
473
|
+
} catch (err) {
|
|
474
|
+
aLog.warn(`notifyStop failed during shutdown (ignored): ${String(err)}`);
|
|
475
|
+
}
|
|
476
|
+
},
|
|
445
477
|
loginWithQrStart: async ({ accountId, force, timeoutMs, verbose }) => {
|
|
446
478
|
// For re-login: use saved baseUrl from account data; fall back to default for new accounts.
|
|
447
479
|
const savedBaseUrl = accountId ? loadWeixinAccount(accountId)?.baseUrl?.trim() : "";
|