mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 19:38:28 +00:00
chore: remove dead macos relay and daemon code
This commit is contained in:
@@ -1,279 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import process from "node:process";
|
||||
import type { GatewayLockHandle } from "../infra/gateway-lock.js";
|
||||
import { restartGatewayProcessWithFreshPid } from "../infra/process-respawn.js";
|
||||
|
||||
declare const __OPENCLAW_VERSION__: string | undefined;
|
||||
|
||||
const BUNDLED_VERSION =
|
||||
(typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) ||
|
||||
process.env.OPENCLAW_BUNDLED_VERSION ||
|
||||
"0.0.0";
|
||||
|
||||
function argValue(args: string[], flag: string): string | undefined {
|
||||
const idx = args.indexOf(flag);
|
||||
if (idx < 0) {
|
||||
return undefined;
|
||||
}
|
||||
const value = args[idx + 1];
|
||||
return value && !value.startsWith("-") ? value : undefined;
|
||||
}
|
||||
|
||||
function hasFlag(args: string[], flag: string): boolean {
|
||||
return args.includes(flag);
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
type GatewayWsLogStyle = "auto" | "full" | "compact";
|
||||
|
||||
async function main() {
|
||||
if (hasFlag(args, "--version") || hasFlag(args, "-v")) {
|
||||
// Match `openclaw --version` behavior for Swift env/version checks.
|
||||
// Keep output a single line.
|
||||
console.log(BUNDLED_VERSION);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Bun runtime ships a global `Long` that protobufjs detects, but it does not
|
||||
// implement the long.js API that Baileys/WAProto expects (fromBits, ...).
|
||||
// Ensure we use long.js so the embedded gateway doesn't crash at startup.
|
||||
if (typeof process.versions.bun === "string") {
|
||||
const mod = await import("long");
|
||||
const Long = (mod as unknown as { default?: unknown }).default ?? mod;
|
||||
(globalThis as unknown as { Long?: unknown }).Long = Long;
|
||||
}
|
||||
|
||||
const [
|
||||
{ loadConfig },
|
||||
{ startGatewayServer },
|
||||
{ setGatewayWsLogStyle },
|
||||
{ setVerbose },
|
||||
{ acquireGatewayLock, GatewayLockError },
|
||||
{
|
||||
consumeGatewaySigusr1RestartAuthorization,
|
||||
isGatewaySigusr1RestartExternallyAllowed,
|
||||
markGatewaySigusr1RestartHandled,
|
||||
},
|
||||
{ defaultRuntime },
|
||||
{ enableConsoleCapture, setConsoleTimestampPrefix },
|
||||
commandQueueMod,
|
||||
{ createRestartIterationHook },
|
||||
] = await Promise.all([
|
||||
import("../config/config.js"),
|
||||
import("../gateway/server.js"),
|
||||
import("../gateway/ws-logging.js"),
|
||||
import("../globals.js"),
|
||||
import("../infra/gateway-lock.js"),
|
||||
import("../infra/restart.js"),
|
||||
import("../runtime.js"),
|
||||
import("../logging.js"),
|
||||
import("../process/command-queue.js"),
|
||||
import("../process/restart-recovery.js"),
|
||||
] as const);
|
||||
|
||||
enableConsoleCapture();
|
||||
setConsoleTimestampPrefix(true);
|
||||
setVerbose(hasFlag(args, "--verbose"));
|
||||
|
||||
const wsLogRaw = hasFlag(args, "--compact") ? "compact" : argValue(args, "--ws-log");
|
||||
const wsLogStyle: GatewayWsLogStyle =
|
||||
wsLogRaw === "compact" ? "compact" : wsLogRaw === "full" ? "full" : "auto";
|
||||
setGatewayWsLogStyle(wsLogStyle);
|
||||
|
||||
const cfg = loadConfig();
|
||||
const portRaw =
|
||||
argValue(args, "--port") ??
|
||||
process.env.OPENCLAW_GATEWAY_PORT ??
|
||||
process.env.CLAWDBOT_GATEWAY_PORT ??
|
||||
(typeof cfg.gateway?.port === "number" ? String(cfg.gateway.port) : "") ??
|
||||
"18789";
|
||||
const port = Number.parseInt(portRaw, 10);
|
||||
if (Number.isNaN(port) || port <= 0) {
|
||||
defaultRuntime.error(`Invalid --port (${portRaw})`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const bindRaw =
|
||||
argValue(args, "--bind") ??
|
||||
process.env.OPENCLAW_GATEWAY_BIND ??
|
||||
process.env.CLAWDBOT_GATEWAY_BIND ??
|
||||
cfg.gateway?.bind ??
|
||||
"loopback";
|
||||
const bind =
|
||||
bindRaw === "loopback" ||
|
||||
bindRaw === "lan" ||
|
||||
bindRaw === "auto" ||
|
||||
bindRaw === "custom" ||
|
||||
bindRaw === "tailnet"
|
||||
? bindRaw
|
||||
: null;
|
||||
if (!bind) {
|
||||
defaultRuntime.error('Invalid --bind (use "loopback", "lan", "tailnet", "auto", or "custom")');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const token = argValue(args, "--token");
|
||||
if (token) {
|
||||
process.env.OPENCLAW_GATEWAY_TOKEN = token;
|
||||
}
|
||||
|
||||
let server: Awaited<ReturnType<typeof startGatewayServer>> | null = null;
|
||||
let lock: GatewayLockHandle | null = null;
|
||||
let shuttingDown = false;
|
||||
let forceExitTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let restartResolver: (() => void) | null = null;
|
||||
|
||||
const cleanupSignals = () => {
|
||||
process.removeListener("SIGTERM", onSigterm);
|
||||
process.removeListener("SIGINT", onSigint);
|
||||
process.removeListener("SIGUSR1", onSigusr1);
|
||||
};
|
||||
|
||||
const request = (action: "stop" | "restart", signal: string) => {
|
||||
if (shuttingDown) {
|
||||
defaultRuntime.log(`gateway: received ${signal} during shutdown; ignoring`);
|
||||
return;
|
||||
}
|
||||
shuttingDown = true;
|
||||
const isRestart = action === "restart";
|
||||
defaultRuntime.log(
|
||||
`gateway: received ${signal}; ${isRestart ? "restarting" : "shutting down"}`,
|
||||
);
|
||||
|
||||
const DRAIN_TIMEOUT_MS = 30_000;
|
||||
const SHUTDOWN_TIMEOUT_MS = 5_000;
|
||||
const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;
|
||||
forceExitTimer = setTimeout(() => {
|
||||
defaultRuntime.error("gateway: shutdown timed out; exiting without full cleanup");
|
||||
cleanupSignals();
|
||||
process.exit(0);
|
||||
}, forceExitMs);
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
if (isRestart) {
|
||||
const activeTasks = commandQueueMod.getActiveTaskCount();
|
||||
if (activeTasks > 0) {
|
||||
defaultRuntime.log(
|
||||
`gateway: draining ${activeTasks} active task(s) before restart (timeout ${DRAIN_TIMEOUT_MS}ms)`,
|
||||
);
|
||||
const { drained } = await commandQueueMod.waitForActiveTasks(DRAIN_TIMEOUT_MS);
|
||||
if (drained) {
|
||||
defaultRuntime.log("gateway: all active tasks drained");
|
||||
} else {
|
||||
defaultRuntime.log("gateway: drain timeout reached; proceeding with restart");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await server?.close({
|
||||
reason: isRestart ? "gateway restarting" : "gateway stopping",
|
||||
restartExpectedMs: isRestart ? 1500 : null,
|
||||
});
|
||||
} catch (err) {
|
||||
defaultRuntime.error(`gateway: shutdown error: ${String(err)}`);
|
||||
} finally {
|
||||
if (forceExitTimer) {
|
||||
clearTimeout(forceExitTimer);
|
||||
}
|
||||
server = null;
|
||||
if (isRestart) {
|
||||
const respawn = restartGatewayProcessWithFreshPid();
|
||||
if (respawn.mode === "spawned" || respawn.mode === "supervised") {
|
||||
const modeLabel =
|
||||
respawn.mode === "spawned"
|
||||
? `spawned pid ${respawn.pid ?? "unknown"}`
|
||||
: "supervisor restart";
|
||||
defaultRuntime.log(`gateway: restart mode full process restart (${modeLabel})`);
|
||||
cleanupSignals();
|
||||
process.exit(0);
|
||||
} else {
|
||||
if (respawn.mode === "failed") {
|
||||
defaultRuntime.log(
|
||||
`gateway: full process restart failed (${respawn.detail ?? "unknown error"}); falling back to in-process restart`,
|
||||
);
|
||||
} else {
|
||||
defaultRuntime.log("gateway: restart mode in-process restart (OPENCLAW_NO_RESPAWN)");
|
||||
}
|
||||
shuttingDown = false;
|
||||
restartResolver?.();
|
||||
}
|
||||
} else {
|
||||
cleanupSignals();
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const onSigterm = () => {
|
||||
defaultRuntime.log("gateway: signal SIGTERM received");
|
||||
request("stop", "SIGTERM");
|
||||
};
|
||||
const onSigint = () => {
|
||||
defaultRuntime.log("gateway: signal SIGINT received");
|
||||
request("stop", "SIGINT");
|
||||
};
|
||||
const onSigusr1 = () => {
|
||||
defaultRuntime.log("gateway: signal SIGUSR1 received");
|
||||
const authorized = consumeGatewaySigusr1RestartAuthorization();
|
||||
if (!authorized && !isGatewaySigusr1RestartExternallyAllowed()) {
|
||||
defaultRuntime.log(
|
||||
"gateway: SIGUSR1 restart ignored (not authorized; commands.restart=false or use gateway tool).",
|
||||
);
|
||||
return;
|
||||
}
|
||||
markGatewaySigusr1RestartHandled();
|
||||
request("restart", "SIGUSR1");
|
||||
};
|
||||
|
||||
process.on("SIGTERM", onSigterm);
|
||||
process.on("SIGINT", onSigint);
|
||||
process.on("SIGUSR1", onSigusr1);
|
||||
|
||||
try {
|
||||
try {
|
||||
lock = await acquireGatewayLock();
|
||||
} catch (err) {
|
||||
if (err instanceof GatewayLockError) {
|
||||
defaultRuntime.error(`Gateway start blocked: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
const onIteration = createRestartIterationHook(() => {
|
||||
// After an in-process restart (SIGUSR1), reset command-queue lane state.
|
||||
// Interrupted tasks from the previous lifecycle may have left `active`
|
||||
// counts elevated (their finally blocks never ran), permanently blocking
|
||||
// new work from draining.
|
||||
commandQueueMod.resetAllLanes();
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
onIteration();
|
||||
try {
|
||||
server = await startGatewayServer(port, { bind });
|
||||
} catch (err) {
|
||||
cleanupSignals();
|
||||
defaultRuntime.error(`Gateway failed to start: ${String(err)}`);
|
||||
process.exit(1);
|
||||
}
|
||||
await new Promise<void>((resolve) => {
|
||||
restartResolver = resolve;
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await lock?.release();
|
||||
cleanupSignals();
|
||||
}
|
||||
}
|
||||
|
||||
void main().catch((err) => {
|
||||
console.error(
|
||||
"[openclaw] Gateway daemon failed:",
|
||||
err instanceof Error ? (err.stack ?? err.message) : err,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,54 +0,0 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { parseRelaySmokeTest, runRelaySmokeTest } from "./relay-smoke.js";
|
||||
|
||||
vi.mock("../web/qr-image.js", () => ({
|
||||
renderQrPngBase64: vi.fn(async () => "base64"),
|
||||
}));
|
||||
|
||||
describe("parseRelaySmokeTest", () => {
|
||||
it("parses --smoke qr", () => {
|
||||
expect(parseRelaySmokeTest(["--smoke", "qr"], {})).toBe("qr");
|
||||
});
|
||||
|
||||
it("rejects --smoke without a value", () => {
|
||||
expect(() => parseRelaySmokeTest(["--smoke"], {})).toThrow(
|
||||
"Missing value for --smoke (expected: qr)",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects --smoke when the next arg is another flag", () => {
|
||||
expect(() => parseRelaySmokeTest(["--smoke", "--smoke-qr"], {})).toThrow(
|
||||
"Missing value for --smoke (expected: qr)",
|
||||
);
|
||||
});
|
||||
|
||||
it("parses --smoke-qr", () => {
|
||||
expect(parseRelaySmokeTest(["--smoke-qr"], {})).toBe("qr");
|
||||
});
|
||||
|
||||
it("parses env var smoke mode only when no args", () => {
|
||||
expect(parseRelaySmokeTest([], { OPENCLAW_SMOKE_QR: "1" })).toBe("qr");
|
||||
expect(parseRelaySmokeTest(["send"], { OPENCLAW_SMOKE_QR: "1" })).toBe(null);
|
||||
});
|
||||
|
||||
it("supports OPENCLAW_SMOKE=qr only when no args", () => {
|
||||
expect(parseRelaySmokeTest([], { OPENCLAW_SMOKE: "qr" })).toBe("qr");
|
||||
expect(parseRelaySmokeTest(["send"], { OPENCLAW_SMOKE: "qr" })).toBe(null);
|
||||
});
|
||||
|
||||
it("rejects unknown smoke values", () => {
|
||||
expect(() => parseRelaySmokeTest(["--smoke", "nope"], {})).toThrow("Unknown smoke test");
|
||||
});
|
||||
|
||||
it("prefers explicit --smoke over env vars", () => {
|
||||
expect(parseRelaySmokeTest(["--smoke", "qr"], { OPENCLAW_SMOKE: "nope" })).toBe("qr");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runRelaySmokeTest", () => {
|
||||
it("runs qr smoke test", async () => {
|
||||
await runRelaySmokeTest("qr");
|
||||
const mod = await import("../web/qr-image.js");
|
||||
expect(mod.renderQrPngBase64).toHaveBeenCalledWith("smoke-test");
|
||||
});
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
export type RelaySmokeTest = "qr";
|
||||
|
||||
export function parseRelaySmokeTest(args: string[], env: NodeJS.ProcessEnv): RelaySmokeTest | null {
|
||||
const smokeIdx = args.indexOf("--smoke");
|
||||
if (smokeIdx !== -1) {
|
||||
const value = args[smokeIdx + 1];
|
||||
if (!value || value.startsWith("-")) {
|
||||
throw new Error("Missing value for --smoke (expected: qr)");
|
||||
}
|
||||
if (value === "qr") {
|
||||
return "qr";
|
||||
}
|
||||
throw new Error(`Unknown smoke test: ${value}`);
|
||||
}
|
||||
|
||||
if (args.includes("--smoke-qr")) {
|
||||
return "qr";
|
||||
}
|
||||
|
||||
// Back-compat: only run env-based smoke mode when no CLI args are present,
|
||||
// to avoid surprising early-exit when users set env vars globally.
|
||||
if (args.length === 0 && (env.OPENCLAW_SMOKE_QR === "1" || env.OPENCLAW_SMOKE === "qr")) {
|
||||
return "qr";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function runRelaySmokeTest(test: RelaySmokeTest): Promise<void> {
|
||||
switch (test) {
|
||||
case "qr": {
|
||||
const { renderQrPngBase64 } = await import("../web/qr-image.js");
|
||||
await renderQrPngBase64("smoke-test");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import process from "node:process";
|
||||
|
||||
declare const __OPENCLAW_VERSION__: string | undefined;
|
||||
|
||||
const BUNDLED_VERSION =
|
||||
(typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) ||
|
||||
process.env.OPENCLAW_BUNDLED_VERSION ||
|
||||
"0.0.0";
|
||||
|
||||
function hasFlag(args: string[], flag: string): boolean {
|
||||
return args.includes(flag);
|
||||
}
|
||||
|
||||
async function patchBunLongForProtobuf(): Promise<void> {
|
||||
// Bun ships a global `Long` that protobufjs detects, but it is not long.js and
|
||||
// misses critical APIs (fromBits, ...). Baileys WAProto expects long.js.
|
||||
if (typeof process.versions.bun !== "string") {
|
||||
return;
|
||||
}
|
||||
const mod = await import("long");
|
||||
const Long = (mod as unknown as { default?: unknown }).default ?? mod;
|
||||
(globalThis as unknown as { Long?: unknown }).Long = Long;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// Swift side expects `--version` to return a plain semver string.
|
||||
if (hasFlag(args, "--version") || hasFlag(args, "-V") || hasFlag(args, "-v")) {
|
||||
console.log(BUNDLED_VERSION);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const { parseRelaySmokeTest, runRelaySmokeTest } = await import("./relay-smoke.js");
|
||||
const smokeTest = parseRelaySmokeTest(args, process.env);
|
||||
if (smokeTest) {
|
||||
try {
|
||||
await runRelaySmokeTest(smokeTest);
|
||||
process.exit(0);
|
||||
} catch (err) {
|
||||
console.error(`Relay smoke test failed (${smokeTest}):`, err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
await patchBunLongForProtobuf();
|
||||
|
||||
const { loadDotEnv } = await import("../infra/dotenv.js");
|
||||
loadDotEnv({ quiet: true });
|
||||
|
||||
const { ensureOpenClawCliOnPath } = await import("../infra/path-env.js");
|
||||
ensureOpenClawCliOnPath();
|
||||
|
||||
const { enableConsoleCapture } = await import("../logging.js");
|
||||
enableConsoleCapture();
|
||||
|
||||
const { assertSupportedRuntime } = await import("../infra/runtime-guard.js");
|
||||
assertSupportedRuntime();
|
||||
const { formatUncaughtError } = await import("../infra/errors.js");
|
||||
const { installUnhandledRejectionHandler } = await import("../infra/unhandled-rejections.js");
|
||||
|
||||
const { buildProgram } = await import("../cli/program.js");
|
||||
const program = buildProgram();
|
||||
|
||||
installUnhandledRejectionHandler();
|
||||
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error("[openclaw] Uncaught exception:", formatUncaughtError(error));
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
await program.parseAsync(process.argv);
|
||||
}
|
||||
|
||||
void main().catch((err) => {
|
||||
console.error(
|
||||
"[openclaw] Relay failed:",
|
||||
err instanceof Error ? (err.stack ?? err.message) : err,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user