mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
refactor(daemon): simplify managed Gateway bindings (#162836)
Build native service selectors in the existing discovery loop and reuse the profile naming owner for deduplication. Preserve exact service scope, Startup identity and host environment forwarding. Drop a stale PID-probe count assertion while retaining EPERM/ESRCH behavior and signal-zero checks. Validation: 137 local cases, the Linux-only system-template case, complete selected checks and independent P2 review pass. Production delta: -31 lines.
This commit is contained in:
parent
b66471a26d
commit
1c57a6f9ce
2 changed files with 25 additions and 57 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
/** Bind discovered native service selectors without granting lifecycle authority. */
|
/** Bind discovered native service selectors without granting lifecycle authority. */
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
|
|
||||||
import { hasCommandProcessCleanupError } from "../process/exec-result.js";
|
import { hasCommandProcessCleanupError } from "../process/exec-result.js";
|
||||||
import { listManagedOpenClawGatewayServices, type ExtraGatewayService } from "./inspect.js";
|
import { resolveGatewayProfileSuffix } from "./constants.js";
|
||||||
|
import { listManagedOpenClawGatewayServices } from "./inspect.js";
|
||||||
import type { LoadedLaunchAgentState } from "./launchd-runtime.js";
|
import type { LoadedLaunchAgentState } from "./launchd-runtime.js";
|
||||||
import { resolveTaskName } from "./schtasks-layout.js";
|
import { resolveTaskName } from "./schtasks-layout.js";
|
||||||
import type { GatewayServiceEnv, SystemdServiceReadTarget } from "./service-types.js";
|
import type { GatewayServiceEnv, SystemdServiceReadTarget } from "./service-types.js";
|
||||||
|
|
@ -51,7 +51,7 @@ export async function readManagedGatewayBindingState(
|
||||||
|
|
||||||
function bindingSelectorKey(binding: ManagedGatewayBinding): string {
|
function bindingSelectorKey(binding: ManagedGatewayBinding): string {
|
||||||
return [
|
return [
|
||||||
normalizeDiscoveredProfile(binding.env.OPENCLAW_PROFILE),
|
resolveGatewayProfileSuffix(binding.env.OPENCLAW_PROFILE),
|
||||||
binding.scope ?? binding.systemdReadTarget?.scope ?? "",
|
binding.scope ?? binding.systemdReadTarget?.scope ?? "",
|
||||||
binding.systemdReadTarget?.unitPath ?? "",
|
binding.systemdReadTarget?.unitPath ?? "",
|
||||||
binding.launchAgentPlistPath ?? "",
|
binding.launchAgentPlistPath ?? "",
|
||||||
|
|
@ -64,14 +64,6 @@ function bindingSelectorKey(binding: ManagedGatewayBinding): string {
|
||||||
].join("\0");
|
].join("\0");
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeDiscoveredProfile(value: string | undefined): string {
|
|
||||||
const trimmed = value?.trim();
|
|
||||||
if (!trimmed || normalizeLowercaseStringOrEmpty(trimmed) === "default") {
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
return trimmed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hostBindingEnv(
|
function hostBindingEnv(
|
||||||
env: Record<string, string | undefined>,
|
env: Record<string, string | undefined>,
|
||||||
extras: GatewayServiceEnv,
|
extras: GatewayServiceEnv,
|
||||||
|
|
@ -98,48 +90,6 @@ function profileEnvFields(profile: string): GatewayServiceEnv {
|
||||||
return profile === "default" ? {} : { OPENCLAW_PROFILE: profile };
|
return profile === "default" ? {} : { OPENCLAW_PROFILE: profile };
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindingFromSystemdService(
|
|
||||||
svc: ExtraGatewayService,
|
|
||||||
env: Record<string, string | undefined>,
|
|
||||||
): ManagedGatewayBinding {
|
|
||||||
const unitPath = svc.sourcePath;
|
|
||||||
const unitName = resolveSystemdTemplateInstanceName(svc.label, {
|
|
||||||
OPENCLAW_SYSTEMD_UNIT: svc.label,
|
|
||||||
});
|
|
||||||
const systemdReadTarget = unitPath ? { scope: svc.scope, unitName, unitPath } : undefined;
|
|
||||||
return {
|
|
||||||
scope: svc.scope,
|
|
||||||
...(systemdReadTarget ? { systemdReadTarget } : {}),
|
|
||||||
env: hostBindingEnv(env, { OPENCLAW_SYSTEMD_UNIT: unitName }),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindingFromLaunchdService(
|
|
||||||
svc: ExtraGatewayService,
|
|
||||||
env: Record<string, string | undefined>,
|
|
||||||
): ManagedGatewayBinding {
|
|
||||||
const plistPath = svc.sourcePath;
|
|
||||||
return {
|
|
||||||
scope: svc.scope,
|
|
||||||
...(plistPath ? { launchAgentPlistPath: plistPath } : {}),
|
|
||||||
env: hostBindingEnv(env, { OPENCLAW_LAUNCHD_LABEL: svc.label }),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindingFromWindowsTask(
|
|
||||||
name: string,
|
|
||||||
profile: string,
|
|
||||||
env: Record<string, string | undefined>,
|
|
||||||
): ManagedGatewayBinding {
|
|
||||||
return {
|
|
||||||
scope: "system",
|
|
||||||
env: hostBindingEnv(env, {
|
|
||||||
...profileEnvFields(profile),
|
|
||||||
OPENCLAW_WINDOWS_TASK_NAME: name.replace(/^\\+/, "").trim() || name,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerate installed managed Gateway selectors for runtime mutation checks.
|
* Enumerate installed managed Gateway selectors for runtime mutation checks.
|
||||||
*/
|
*/
|
||||||
|
|
@ -171,11 +121,24 @@ export async function discoverManagedGatewayBindings(
|
||||||
// Best-effort callers retain known bindings; automatic writers require complete discovery.
|
// Best-effort callers retain known bindings; automatic writers require complete discovery.
|
||||||
for (const svc of services) {
|
for (const svc of services) {
|
||||||
if (svc.platform === "linux") {
|
if (svc.platform === "linux") {
|
||||||
push(bindingFromSystemdService(svc, env));
|
const unitName = resolveSystemdTemplateInstanceName(svc.label, {
|
||||||
|
OPENCLAW_SYSTEMD_UNIT: svc.label,
|
||||||
|
});
|
||||||
|
push({
|
||||||
|
scope: svc.scope,
|
||||||
|
...(svc.sourcePath
|
||||||
|
? { systemdReadTarget: { scope: svc.scope, unitName, unitPath: svc.sourcePath } }
|
||||||
|
: {}),
|
||||||
|
env: hostBindingEnv(env, { OPENCLAW_SYSTEMD_UNIT: unitName }),
|
||||||
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (svc.platform === "darwin") {
|
if (svc.platform === "darwin") {
|
||||||
push(bindingFromLaunchdService(svc, env));
|
push({
|
||||||
|
scope: svc.scope,
|
||||||
|
...(svc.sourcePath ? { launchAgentPlistPath: svc.sourcePath } : {}),
|
||||||
|
env: hostBindingEnv(env, { OPENCLAW_LAUNCHD_LABEL: svc.label }),
|
||||||
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (svc.windowsProfile === undefined) {
|
if (svc.windowsProfile === undefined) {
|
||||||
|
|
@ -189,7 +152,13 @@ export async function discoverManagedGatewayBindings(
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
push(bindingFromWindowsTask(svc.label, svc.windowsProfile, env));
|
push({
|
||||||
|
scope: "system",
|
||||||
|
env: hostBindingEnv(env, {
|
||||||
|
...profileEnvFields(svc.windowsProfile),
|
||||||
|
OPENCLAW_WINDOWS_TASK_NAME: svc.label.replace(/^\\+/, "").trim() || svc.label,
|
||||||
|
}),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (options.requireComplete || hasCommandProcessCleanupError(error)) {
|
if (options.requireComplete || hasCommandProcessCleanupError(error)) {
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,6 @@ describe("live-gateway-dist-fence", () => {
|
||||||
runtime: { status: "stopped", state: "inactive", pid: process.pid },
|
runtime: { status: "stopped", state: "inactive", pid: process.pid },
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
expect(kill).toHaveBeenCalledTimes(1);
|
|
||||||
expect(kill).toHaveBeenCalledWith(process.pid, 0);
|
expect(kill).toHaveBeenCalledWith(process.pid, 0);
|
||||||
expect(result.refuse).toBe(refuse);
|
expect(result.refuse).toBe(refuse);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue