mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 11:51:23 +00:00
refactor: unify monitor abort lifecycle handling
This commit is contained in:
33
src/discord/monitor/gateway-error-guard.test.ts
Normal file
33
src/discord/monitor/gateway-error-guard.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { attachEarlyGatewayErrorGuard } from "./gateway-error-guard.js";
|
||||
|
||||
describe("attachEarlyGatewayErrorGuard", () => {
|
||||
it("captures gateway errors until released", () => {
|
||||
const emitter = new EventEmitter();
|
||||
const fallbackErrorListener = vi.fn();
|
||||
emitter.on("error", fallbackErrorListener);
|
||||
const client = {
|
||||
getPlugin: vi.fn(() => ({ emitter })),
|
||||
};
|
||||
|
||||
const guard = attachEarlyGatewayErrorGuard(client as never);
|
||||
emitter.emit("error", new Error("Fatal Gateway error: 4014"));
|
||||
expect(guard.pendingErrors).toHaveLength(1);
|
||||
|
||||
guard.release();
|
||||
emitter.emit("error", new Error("Fatal Gateway error: 4000"));
|
||||
expect(guard.pendingErrors).toHaveLength(1);
|
||||
expect(fallbackErrorListener).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("returns noop guard when gateway emitter is unavailable", () => {
|
||||
const client = {
|
||||
getPlugin: vi.fn(() => undefined),
|
||||
};
|
||||
|
||||
const guard = attachEarlyGatewayErrorGuard(client as never);
|
||||
expect(guard.pendingErrors).toEqual([]);
|
||||
expect(() => guard.release()).not.toThrow();
|
||||
});
|
||||
});
|
||||
36
src/discord/monitor/gateway-error-guard.ts
Normal file
36
src/discord/monitor/gateway-error-guard.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { Client } from "@buape/carbon";
|
||||
import { getDiscordGatewayEmitter } from "../monitor.gateway.js";
|
||||
|
||||
export type EarlyGatewayErrorGuard = {
|
||||
pendingErrors: unknown[];
|
||||
release: () => void;
|
||||
};
|
||||
|
||||
export function attachEarlyGatewayErrorGuard(client: Client): EarlyGatewayErrorGuard {
|
||||
const pendingErrors: unknown[] = [];
|
||||
const gateway = client.getPlugin("gateway");
|
||||
const emitter = getDiscordGatewayEmitter(gateway);
|
||||
if (!emitter) {
|
||||
return {
|
||||
pendingErrors,
|
||||
release: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
let released = false;
|
||||
const onGatewayError = (err: unknown) => {
|
||||
pendingErrors.push(err);
|
||||
};
|
||||
emitter.on("error", onGatewayError);
|
||||
|
||||
return {
|
||||
pendingErrors,
|
||||
release: () => {
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
released = true;
|
||||
emitter.removeListener("error", onGatewayError);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import { createDiscordRetryRunner } from "../../infra/retry-policy.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { createNonExitingRuntime, type RuntimeEnv } from "../../runtime.js";
|
||||
import { resolveDiscordAccount } from "../accounts.js";
|
||||
import { getDiscordGatewayEmitter } from "../monitor.gateway.js";
|
||||
import { fetchDiscordApplicationId } from "../probe.js";
|
||||
import { normalizeDiscordToken } from "../token.js";
|
||||
import { createDiscordVoiceCommand } from "../voice/command.js";
|
||||
@@ -52,6 +51,7 @@ import {
|
||||
} from "./agent-components.js";
|
||||
import { resolveDiscordSlashCommandConfig } from "./commands.js";
|
||||
import { createExecApprovalButton, DiscordExecApprovalHandler } from "./exec-approvals.js";
|
||||
import { attachEarlyGatewayErrorGuard } from "./gateway-error-guard.js";
|
||||
import { createDiscordGatewayPlugin } from "./gateway-plugin.js";
|
||||
import {
|
||||
DiscordMessageListener,
|
||||
@@ -230,33 +230,6 @@ function isDiscordDisallowedIntentsError(err: unknown): boolean {
|
||||
return message.includes(String(DISCORD_DISALLOWED_INTENTS_CODE));
|
||||
}
|
||||
|
||||
type EarlyGatewayErrorGuard = {
|
||||
pendingErrors: unknown[];
|
||||
release: () => void;
|
||||
};
|
||||
|
||||
function attachEarlyGatewayErrorGuard(client: Client): EarlyGatewayErrorGuard {
|
||||
const pendingErrors: unknown[] = [];
|
||||
const gateway = client.getPlugin<GatewayPlugin>("gateway");
|
||||
const emitter = getDiscordGatewayEmitter(gateway);
|
||||
if (!emitter) {
|
||||
return {
|
||||
pendingErrors,
|
||||
release: () => {},
|
||||
};
|
||||
}
|
||||
const onGatewayError = (err: unknown) => {
|
||||
pendingErrors.push(err);
|
||||
};
|
||||
emitter.on("error", onGatewayError);
|
||||
return {
|
||||
pendingErrors,
|
||||
release: () => {
|
||||
emitter.removeListener("error", onGatewayError);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
const cfg = opts.config ?? loadConfig();
|
||||
const account = resolveDiscordAccount({
|
||||
|
||||
Reference in New Issue
Block a user