mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:49:35 +00:00
refactor: dedupe daemon exec wrappers
This commit is contained in:
32
src/daemon/exec-file.ts
Normal file
32
src/daemon/exec-file.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { execFile, type ExecFileOptionsWithStringEncoding } from "node:child_process";
|
||||||
|
|
||||||
|
export type ExecResult = { stdout: string; stderr: string; code: number };
|
||||||
|
|
||||||
|
export async function execFileUtf8(
|
||||||
|
command: string,
|
||||||
|
args: string[],
|
||||||
|
options: Omit<ExecFileOptionsWithStringEncoding, "encoding"> = {},
|
||||||
|
): Promise<ExecResult> {
|
||||||
|
return await new Promise<ExecResult>((resolve) => {
|
||||||
|
execFile(command, args, { ...options, encoding: "utf8" }, (error, stdout, stderr) => {
|
||||||
|
if (!error) {
|
||||||
|
resolve({
|
||||||
|
stdout: String(stdout ?? ""),
|
||||||
|
stderr: String(stderr ?? ""),
|
||||||
|
code: 0,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const e = error as { code?: unknown; message?: unknown };
|
||||||
|
const stderrText = String(stderr ?? "");
|
||||||
|
resolve({
|
||||||
|
stdout: String(stdout ?? ""),
|
||||||
|
stderr:
|
||||||
|
stderrText ||
|
||||||
|
(typeof e.message === "string" ? e.message : typeof error === "string" ? error : ""),
|
||||||
|
code: typeof e.code === "number" ? e.code : 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import { execFile } from "node:child_process";
|
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { promisify } from "node:util";
|
|
||||||
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
||||||
import {
|
import {
|
||||||
formatGatewayServiceDescription,
|
formatGatewayServiceDescription,
|
||||||
@@ -9,6 +7,7 @@ import {
|
|||||||
resolveGatewayLaunchAgentLabel,
|
resolveGatewayLaunchAgentLabel,
|
||||||
resolveLegacyGatewayLaunchAgentLabels,
|
resolveLegacyGatewayLaunchAgentLabels,
|
||||||
} from "./constants.js";
|
} from "./constants.js";
|
||||||
|
import { execFileUtf8 } from "./exec-file.js";
|
||||||
import {
|
import {
|
||||||
buildLaunchAgentPlist as buildLaunchAgentPlistImpl,
|
buildLaunchAgentPlist as buildLaunchAgentPlistImpl,
|
||||||
readLaunchAgentProgramArgumentsFromFile,
|
readLaunchAgentProgramArgumentsFromFile,
|
||||||
@@ -17,8 +16,6 @@ import { formatLine, toPosixPath } from "./output.js";
|
|||||||
import { resolveGatewayStateDir, resolveHomeDir } from "./paths.js";
|
import { resolveGatewayStateDir, resolveHomeDir } from "./paths.js";
|
||||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
|
||||||
|
|
||||||
function resolveLaunchAgentLabel(args?: { env?: Record<string, string | undefined> }): string {
|
function resolveLaunchAgentLabel(args?: { env?: Record<string, string | undefined> }): string {
|
||||||
const envLabel = args?.env?.OPENCLAW_LAUNCHD_LABEL?.trim();
|
const envLabel = args?.env?.OPENCLAW_LAUNCHD_LABEL?.trim();
|
||||||
if (envLabel) {
|
if (envLabel) {
|
||||||
@@ -98,30 +95,10 @@ export function buildLaunchAgentPlist({
|
|||||||
async function execLaunchctl(
|
async function execLaunchctl(
|
||||||
args: string[],
|
args: string[],
|
||||||
): Promise<{ stdout: string; stderr: string; code: number }> {
|
): Promise<{ stdout: string; stderr: string; code: number }> {
|
||||||
try {
|
|
||||||
const isWindows = process.platform === "win32";
|
const isWindows = process.platform === "win32";
|
||||||
const file = isWindows ? (process.env.ComSpec ?? "cmd.exe") : "launchctl";
|
const file = isWindows ? (process.env.ComSpec ?? "cmd.exe") : "launchctl";
|
||||||
const fileArgs = isWindows ? ["/d", "/s", "/c", "launchctl", ...args] : args;
|
const fileArgs = isWindows ? ["/d", "/s", "/c", "launchctl", ...args] : args;
|
||||||
const { stdout, stderr } = await execFileAsync(file, fileArgs, { encoding: "utf8" });
|
return await execFileUtf8(file, fileArgs, isWindows ? { windowsHide: true } : {});
|
||||||
return {
|
|
||||||
stdout: String(stdout ?? ""),
|
|
||||||
stderr: String(stderr ?? ""),
|
|
||||||
code: 0,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
const e = error as {
|
|
||||||
stdout?: unknown;
|
|
||||||
stderr?: unknown;
|
|
||||||
code?: unknown;
|
|
||||||
message?: unknown;
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
||||||
stderr:
|
|
||||||
typeof e.stderr === "string" ? e.stderr : typeof e.message === "string" ? e.message : "",
|
|
||||||
code: typeof e.code === "number" ? e.code : 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveGuiDomain(): string {
|
function resolveGuiDomain(): string {
|
||||||
|
|||||||
@@ -1,33 +1,7 @@
|
|||||||
import { execFile } from "node:child_process";
|
import { execFileUtf8 } from "./exec-file.js";
|
||||||
import { promisify } from "node:util";
|
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
|
||||||
|
|
||||||
export async function execSchtasks(
|
export async function execSchtasks(
|
||||||
args: string[],
|
args: string[],
|
||||||
): Promise<{ stdout: string; stderr: string; code: number }> {
|
): Promise<{ stdout: string; stderr: string; code: number }> {
|
||||||
try {
|
return await execFileUtf8("schtasks", args, { windowsHide: true });
|
||||||
const { stdout, stderr } = await execFileAsync("schtasks", args, {
|
|
||||||
encoding: "utf8",
|
|
||||||
windowsHide: true,
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
stdout: String(stdout ?? ""),
|
|
||||||
stderr: String(stderr ?? ""),
|
|
||||||
code: 0,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
const e = error as {
|
|
||||||
stdout?: unknown;
|
|
||||||
stderr?: unknown;
|
|
||||||
code?: unknown;
|
|
||||||
message?: unknown;
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
||||||
stderr:
|
|
||||||
typeof e.stderr === "string" ? e.stderr : typeof e.message === "string" ? e.message : "",
|
|
||||||
code: typeof e.code === "number" ? e.code : 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { execFile } from "node:child_process";
|
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { promisify } from "node:util";
|
|
||||||
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
||||||
import {
|
import {
|
||||||
formatGatewayServiceDescription,
|
formatGatewayServiceDescription,
|
||||||
LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES,
|
LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES,
|
||||||
resolveGatewaySystemdServiceName,
|
resolveGatewaySystemdServiceName,
|
||||||
} from "./constants.js";
|
} from "./constants.js";
|
||||||
|
import { execFileUtf8 } from "./exec-file.js";
|
||||||
import { formatLine, toPosixPath } from "./output.js";
|
import { formatLine, toPosixPath } from "./output.js";
|
||||||
import { resolveHomeDir } from "./paths.js";
|
import { resolveHomeDir } from "./paths.js";
|
||||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||||
@@ -22,8 +21,6 @@ import {
|
|||||||
parseSystemdExecStart,
|
parseSystemdExecStart,
|
||||||
} from "./systemd-unit.js";
|
} from "./systemd-unit.js";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
|
||||||
|
|
||||||
function resolveSystemdUnitPathForName(
|
function resolveSystemdUnitPathForName(
|
||||||
env: Record<string, string | undefined>,
|
env: Record<string, string | undefined>,
|
||||||
name: string,
|
name: string,
|
||||||
@@ -142,29 +139,7 @@ export function parseSystemdShow(output: string): SystemdServiceInfo {
|
|||||||
async function execSystemctl(
|
async function execSystemctl(
|
||||||
args: string[],
|
args: string[],
|
||||||
): Promise<{ stdout: string; stderr: string; code: number }> {
|
): Promise<{ stdout: string; stderr: string; code: number }> {
|
||||||
try {
|
return await execFileUtf8("systemctl", args);
|
||||||
const { stdout, stderr } = await execFileAsync("systemctl", args, {
|
|
||||||
encoding: "utf8",
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
stdout: String(stdout ?? ""),
|
|
||||||
stderr: String(stderr ?? ""),
|
|
||||||
code: 0,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
const e = error as {
|
|
||||||
stdout?: unknown;
|
|
||||||
stderr?: unknown;
|
|
||||||
code?: unknown;
|
|
||||||
message?: unknown;
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
||||||
stderr:
|
|
||||||
typeof e.stderr === "string" ? e.stderr : typeof e.message === "string" ? e.message : "",
|
|
||||||
code: typeof e.code === "number" ? e.code : 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isSystemdUserServiceAvailable(): Promise<boolean> {
|
export async function isSystemdUserServiceAvailable(): Promise<boolean> {
|
||||||
|
|||||||
Reference in New Issue
Block a user