mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-14 03:20:49 +00:00
105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
/**
|
|
* Global Plugin Hook Runner
|
|
*
|
|
* Singleton hook runner that's initialized when plugins are loaded
|
|
* and can be called from anywhere in the codebase.
|
|
*/
|
|
|
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
import { createHookRunner, type HookRunner } from "./hooks.js";
|
|
import type { PluginRegistry } from "./registry.js";
|
|
import type { PluginHookGatewayContext, PluginHookGatewayStopEvent } from "./types.js";
|
|
|
|
const log = createSubsystemLogger("plugins");
|
|
|
|
type HookRunnerGlobalState = {
|
|
hookRunner: HookRunner | null;
|
|
registry: PluginRegistry | null;
|
|
};
|
|
|
|
const hookRunnerGlobalStateKey = Symbol.for("openclaw.plugins.hook-runner-global-state");
|
|
|
|
function getHookRunnerGlobalState(): HookRunnerGlobalState {
|
|
const globalStore = globalThis as typeof globalThis & {
|
|
[hookRunnerGlobalStateKey]?: HookRunnerGlobalState;
|
|
};
|
|
return (globalStore[hookRunnerGlobalStateKey] ??= {
|
|
hookRunner: null,
|
|
registry: null,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize the global hook runner with a plugin registry.
|
|
* Called once when plugins are loaded during gateway startup.
|
|
*/
|
|
export function initializeGlobalHookRunner(registry: PluginRegistry): void {
|
|
const state = getHookRunnerGlobalState();
|
|
state.registry = registry;
|
|
state.hookRunner = createHookRunner(registry, {
|
|
logger: {
|
|
debug: (msg) => log.debug(msg),
|
|
warn: (msg) => log.warn(msg),
|
|
error: (msg) => log.error(msg),
|
|
},
|
|
catchErrors: true,
|
|
});
|
|
|
|
const hookCount = registry.hooks.length;
|
|
if (hookCount > 0) {
|
|
log.info(`hook runner initialized with ${hookCount} registered hooks`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the global hook runner.
|
|
* Returns null if plugins haven't been loaded yet.
|
|
*/
|
|
export function getGlobalHookRunner(): HookRunner | null {
|
|
return getHookRunnerGlobalState().hookRunner;
|
|
}
|
|
|
|
/**
|
|
* Get the global plugin registry.
|
|
* Returns null if plugins haven't been loaded yet.
|
|
*/
|
|
export function getGlobalPluginRegistry(): PluginRegistry | null {
|
|
return getHookRunnerGlobalState().registry;
|
|
}
|
|
|
|
/**
|
|
* Check if any hooks are registered for a given hook name.
|
|
*/
|
|
export function hasGlobalHooks(hookName: Parameters<HookRunner["hasHooks"]>[0]): boolean {
|
|
return getHookRunnerGlobalState().hookRunner?.hasHooks(hookName) ?? false;
|
|
}
|
|
|
|
export async function runGlobalGatewayStopSafely(params: {
|
|
event: PluginHookGatewayStopEvent;
|
|
ctx: PluginHookGatewayContext;
|
|
onError?: (err: unknown) => void;
|
|
}): Promise<void> {
|
|
const hookRunner = getGlobalHookRunner();
|
|
if (!hookRunner?.hasHooks("gateway_stop")) {
|
|
return;
|
|
}
|
|
try {
|
|
await hookRunner.runGatewayStop(params.event, params.ctx);
|
|
} catch (err) {
|
|
if (params.onError) {
|
|
params.onError(err);
|
|
return;
|
|
}
|
|
log.warn(`gateway_stop hook failed: ${String(err)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset the global hook runner (for testing).
|
|
*/
|
|
export function resetGlobalHookRunner(): void {
|
|
const state = getHookRunnerGlobalState();
|
|
state.hookRunner = null;
|
|
state.registry = null;
|
|
}
|