添加完整的微信插件测试框架,包含: - 微信插件源码(weixin-plugin/) - TypeScript 类型定义(types.ts) - 插件编译脚本(scripts/build-weixin-plugin.sh) - 简化测试脚本(scripts/test-weixin-simple.js) - 完整测试脚本(scripts/test-weixin-plugin.js) - 项目配置和依赖管理(package.json) - 使用说明文档(README.md) 主要功能: - 支持二维码登录认证 - HTTP 长轮询消息接收 - 文本、图片、视频、文件消息收发 - 自动回复测试 - 运行状态统计 Generated with [Claude Code](https://claude.com/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { logger } from "../util/logger.js";
|
|
|
|
const SESSION_PAUSE_DURATION_MS = 60 * 60 * 1000;
|
|
|
|
/** Error code returned by the server when the bot session has expired. */
|
|
export const SESSION_EXPIRED_ERRCODE = -14;
|
|
|
|
const pauseUntilMap = new Map<string, number>();
|
|
|
|
/** Pause all inbound/outbound API calls for `accountId` for one hour. */
|
|
export function pauseSession(accountId: string): void {
|
|
const until = Date.now() + SESSION_PAUSE_DURATION_MS;
|
|
pauseUntilMap.set(accountId, until);
|
|
logger.info(
|
|
`session-guard: paused accountId=${accountId} until=${new Date(until).toISOString()} (${SESSION_PAUSE_DURATION_MS / 1000}s)`,
|
|
);
|
|
}
|
|
|
|
/** Returns `true` when the bot is still within its one-hour cooldown window. */
|
|
export function isSessionPaused(accountId: string): boolean {
|
|
const until = pauseUntilMap.get(accountId);
|
|
if (until === undefined) return false;
|
|
if (Date.now() >= until) {
|
|
pauseUntilMap.delete(accountId);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Milliseconds remaining until the pause expires (0 when not paused). */
|
|
export function getRemainingPauseMs(accountId: string): number {
|
|
const until = pauseUntilMap.get(accountId);
|
|
if (until === undefined) return 0;
|
|
const remaining = until - Date.now();
|
|
if (remaining <= 0) {
|
|
pauseUntilMap.delete(accountId);
|
|
return 0;
|
|
}
|
|
return remaining;
|
|
}
|
|
|
|
/** Throw if the session is currently paused. Call before any API request. */
|
|
export function assertSessionActive(accountId: string): void {
|
|
if (isSessionPaused(accountId)) {
|
|
const remainingMin = Math.ceil(getRemainingPauseMs(accountId) / 60_000);
|
|
throw new Error(
|
|
`session paused for accountId=${accountId}, ${remainingMin} min remaining (errcode ${SESSION_EXPIRED_ERRCODE})`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset internal state — only for tests.
|
|
* @internal
|
|
*/
|
|
export function _resetForTest(): void {
|
|
pauseUntilMap.clear();
|
|
}
|