mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-13 21:26:47 +00:00
feat: add gateway config/update restart flow
This commit is contained in:
116
src/infra/restart-sentinel.ts
Normal file
116
src/infra/restart-sentinel.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
|
||||
export type RestartSentinelLog = {
|
||||
stdoutTail?: string | null;
|
||||
stderrTail?: string | null;
|
||||
exitCode?: number | null;
|
||||
};
|
||||
|
||||
export type RestartSentinelStep = {
|
||||
name: string;
|
||||
command: string;
|
||||
cwd?: string | null;
|
||||
durationMs?: number | null;
|
||||
log?: RestartSentinelLog | null;
|
||||
};
|
||||
|
||||
export type RestartSentinelStats = {
|
||||
mode?: string;
|
||||
root?: string;
|
||||
before?: Record<string, unknown> | null;
|
||||
after?: Record<string, unknown> | null;
|
||||
steps?: RestartSentinelStep[];
|
||||
reason?: string | null;
|
||||
durationMs?: number | null;
|
||||
};
|
||||
|
||||
export type RestartSentinelPayload = {
|
||||
kind: "config-apply" | "update";
|
||||
status: "ok" | "error" | "skipped";
|
||||
ts: number;
|
||||
sessionKey?: string;
|
||||
message?: string | null;
|
||||
stats?: RestartSentinelStats | null;
|
||||
};
|
||||
|
||||
export type RestartSentinel = {
|
||||
version: 1;
|
||||
payload: RestartSentinelPayload;
|
||||
};
|
||||
|
||||
const SENTINEL_FILENAME = "restart-sentinel.json";
|
||||
|
||||
export function resolveRestartSentinelPath(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string {
|
||||
return path.join(resolveStateDir(env), SENTINEL_FILENAME);
|
||||
}
|
||||
|
||||
export async function writeRestartSentinel(
|
||||
payload: RestartSentinelPayload,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
) {
|
||||
const filePath = resolveRestartSentinelPath(env);
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
||||
const data: RestartSentinel = { version: 1, payload };
|
||||
await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
|
||||
return filePath;
|
||||
}
|
||||
|
||||
export async function readRestartSentinel(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<RestartSentinel | null> {
|
||||
const filePath = resolveRestartSentinelPath(env);
|
||||
try {
|
||||
const raw = await fs.readFile(filePath, "utf-8");
|
||||
let parsed: RestartSentinel | undefined;
|
||||
try {
|
||||
parsed = JSON.parse(raw) as RestartSentinel | undefined;
|
||||
} catch {
|
||||
await fs.unlink(filePath).catch(() => {});
|
||||
return null;
|
||||
}
|
||||
if (!parsed || parsed.version !== 1 || !parsed.payload) {
|
||||
await fs.unlink(filePath).catch(() => {});
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function consumeRestartSentinel(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<RestartSentinel | null> {
|
||||
const filePath = resolveRestartSentinelPath(env);
|
||||
const parsed = await readRestartSentinel(env);
|
||||
if (!parsed) return null;
|
||||
await fs.unlink(filePath).catch(() => {});
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export function formatRestartSentinelMessage(
|
||||
payload: RestartSentinelPayload,
|
||||
): string {
|
||||
return `GatewayRestart:\n${JSON.stringify(payload, null, 2)}`;
|
||||
}
|
||||
|
||||
export function summarizeRestartSentinel(
|
||||
payload: RestartSentinelPayload,
|
||||
): string {
|
||||
const kind = payload.kind;
|
||||
const status = payload.status;
|
||||
const mode = payload.stats?.mode ? ` (${payload.stats.mode})` : "";
|
||||
return `Gateway restart ${kind} ${status}${mode}`.trim();
|
||||
}
|
||||
|
||||
export function trimLogTail(input?: string | null, maxChars = 8000) {
|
||||
if (!input) return null;
|
||||
const text = input.trimEnd();
|
||||
if (text.length <= maxChars) return text;
|
||||
return `…${text.slice(text.length - maxChars)}`;
|
||||
}
|
||||
Reference in New Issue
Block a user