mirror of https://github.com/openclaw/openclaw.git
75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
import { z } from "zod";
|
|
import { safeParseJsonWithSchema } from "../utils/zod-parse.js";
|
|
|
|
export type TailscaleStatusCommandResult = {
|
|
code: number | null;
|
|
stdout: string;
|
|
};
|
|
|
|
export type TailscaleStatusCommandRunner = (
|
|
argv: string[],
|
|
opts: { timeoutMs: number },
|
|
) => Promise<TailscaleStatusCommandResult>;
|
|
|
|
const TAILSCALE_STATUS_COMMAND_CANDIDATES = [
|
|
"tailscale",
|
|
"/Applications/Tailscale.app/Contents/MacOS/Tailscale",
|
|
];
|
|
|
|
const TailscaleStatusSchema = z.object({
|
|
Self: z
|
|
.object({
|
|
DNSName: z.string().optional(),
|
|
TailscaleIPs: z.array(z.string()).optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
function parsePossiblyNoisyStatus(raw: string): z.infer<typeof TailscaleStatusSchema> | null {
|
|
const start = raw.indexOf("{");
|
|
const end = raw.lastIndexOf("}");
|
|
if (start === -1 || end <= start) {
|
|
return null;
|
|
}
|
|
return safeParseJsonWithSchema(TailscaleStatusSchema, raw.slice(start, end + 1));
|
|
}
|
|
|
|
function extractTailnetHostFromStatusJson(raw: string): string | null {
|
|
const parsed = parsePossiblyNoisyStatus(raw);
|
|
const dns = parsed?.Self?.DNSName;
|
|
if (dns && dns.length > 0) {
|
|
return dns.replace(/\.$/, "");
|
|
}
|
|
const ips = parsed?.Self?.TailscaleIPs ?? [];
|
|
return ips.length > 0 ? (ips[0] ?? null) : null;
|
|
}
|
|
|
|
export async function resolveTailnetHostWithRunner(
|
|
runCommandWithTimeout?: TailscaleStatusCommandRunner,
|
|
): Promise<string | null> {
|
|
if (!runCommandWithTimeout) {
|
|
return null;
|
|
}
|
|
for (const candidate of TAILSCALE_STATUS_COMMAND_CANDIDATES) {
|
|
try {
|
|
const result = await runCommandWithTimeout([candidate, "status", "--json"], {
|
|
timeoutMs: 5000,
|
|
});
|
|
if (result.code !== 0) {
|
|
continue;
|
|
}
|
|
const raw = result.stdout.trim();
|
|
if (!raw) {
|
|
continue;
|
|
}
|
|
const host = extractTailnetHostFromStatusJson(raw);
|
|
if (host) {
|
|
return host;
|
|
}
|
|
} catch {
|
|
continue;
|
|
}
|
|
}
|
|
return null;
|
|
}
|