mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 08:51:42 +00:00
chore: Enable "curly" rule to avoid single-statement if confusion/errors.
This commit is contained in:
@@ -36,7 +36,9 @@ function decodeDnsSdEscapes(value: string): string {
|
||||
let pending = "";
|
||||
|
||||
const flush = () => {
|
||||
if (!pending) return;
|
||||
if (!pending) {
|
||||
return;
|
||||
}
|
||||
bytes.push(...Buffer.from(pending, "utf8"));
|
||||
pending = "";
|
||||
};
|
||||
@@ -61,16 +63,22 @@ function decodeDnsSdEscapes(value: string): string {
|
||||
pending += ch;
|
||||
}
|
||||
|
||||
if (!decoded) return value;
|
||||
if (!decoded) {
|
||||
return value;
|
||||
}
|
||||
flush();
|
||||
return Buffer.from(bytes).toString("utf8");
|
||||
}
|
||||
|
||||
function isTailnetIPv4(address: string): boolean {
|
||||
const parts = address.split(".");
|
||||
if (parts.length !== 4) return false;
|
||||
if (parts.length !== 4) {
|
||||
return false;
|
||||
}
|
||||
const octets = parts.map((p) => Number.parseInt(p, 10));
|
||||
if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) return false;
|
||||
if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) {
|
||||
return false;
|
||||
}
|
||||
// Tailscale IPv4 range: 100.64.0.0/10
|
||||
const [a, b] = octets;
|
||||
return a === 100 && b >= 64 && b <= 127;
|
||||
@@ -89,7 +97,9 @@ function parseDigTxt(stdout: string): string[] {
|
||||
const tokens: string[] = [];
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trim();
|
||||
if (!line) continue;
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
const matches = Array.from(line.matchAll(/"([^"]*)"/g), (m) => m[1] ?? "");
|
||||
for (const m of matches) {
|
||||
const unescaped = m.replaceAll("\\\\", "\\").replaceAll('\\"', '"').replaceAll("\\n", "\n");
|
||||
@@ -105,14 +115,22 @@ function parseDigSrv(stdout: string): { host: string; port: number } | null {
|
||||
.split("\n")
|
||||
.map((l) => l.trim())
|
||||
.find(Boolean);
|
||||
if (!line) return null;
|
||||
if (!line) {
|
||||
return null;
|
||||
}
|
||||
const parts = line.split(/\s+/).filter(Boolean);
|
||||
if (parts.length < 4) return null;
|
||||
if (parts.length < 4) {
|
||||
return null;
|
||||
}
|
||||
const port = Number.parseInt(parts[2] ?? "", 10);
|
||||
const hostRaw = parts[3] ?? "";
|
||||
if (!Number.isFinite(port) || port <= 0) return null;
|
||||
if (!Number.isFinite(port) || port <= 0) {
|
||||
return null;
|
||||
}
|
||||
const host = hostRaw.replace(/\.$/, "");
|
||||
if (!host) return null;
|
||||
if (!host) {
|
||||
return null;
|
||||
}
|
||||
return { host, port };
|
||||
}
|
||||
|
||||
@@ -121,13 +139,21 @@ function parseTailscaleStatusIPv4s(stdout: string): string[] {
|
||||
const out: string[] = [];
|
||||
|
||||
const addIps = (value: unknown) => {
|
||||
if (!value || typeof value !== "object") return;
|
||||
if (!value || typeof value !== "object") {
|
||||
return;
|
||||
}
|
||||
const ips = (value as { TailscaleIPs?: unknown }).TailscaleIPs;
|
||||
if (!Array.isArray(ips)) return;
|
||||
if (!Array.isArray(ips)) {
|
||||
return;
|
||||
}
|
||||
for (const ip of ips) {
|
||||
if (typeof ip !== "string") continue;
|
||||
if (typeof ip !== "string") {
|
||||
continue;
|
||||
}
|
||||
const trimmed = ip.trim();
|
||||
if (trimmed && isTailnetIPv4(trimmed)) out.push(trimmed);
|
||||
if (trimmed && isTailnetIPv4(trimmed)) {
|
||||
out.push(trimmed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,7 +170,9 @@ function parseTailscaleStatusIPv4s(stdout: string): string[] {
|
||||
}
|
||||
|
||||
function parseIntOrNull(value: string | undefined): number | undefined {
|
||||
if (!value) return undefined;
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
const parsed = Number.parseInt(value, 10);
|
||||
return Number.isFinite(parsed) ? parsed : undefined;
|
||||
}
|
||||
@@ -153,10 +181,14 @@ function parseTxtTokens(tokens: string[]): Record<string, string> {
|
||||
const txt: Record<string, string> = {};
|
||||
for (const token of tokens) {
|
||||
const idx = token.indexOf("=");
|
||||
if (idx <= 0) continue;
|
||||
if (idx <= 0) {
|
||||
continue;
|
||||
}
|
||||
const key = token.slice(0, idx).trim();
|
||||
const value = decodeDnsSdEscapes(token.slice(idx + 1).trim());
|
||||
if (!key) continue;
|
||||
if (!key) {
|
||||
continue;
|
||||
}
|
||||
txt[key] = value;
|
||||
}
|
||||
return txt;
|
||||
@@ -166,8 +198,12 @@ function parseDnsSdBrowse(stdout: string): string[] {
|
||||
const instances = new Set<string>();
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trim();
|
||||
if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) continue;
|
||||
if (!line.includes("Add")) continue;
|
||||
if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) {
|
||||
continue;
|
||||
}
|
||||
if (!line.includes("Add")) {
|
||||
continue;
|
||||
}
|
||||
const match = line.match(/_openclaw-gw\._tcp\.?\s+(.+)$/);
|
||||
if (match?.[1]) {
|
||||
instances.add(decodeDnsSdEscapes(match[1].trim()));
|
||||
@@ -182,7 +218,9 @@ function parseDnsSdResolve(stdout: string, instanceName: string): GatewayBonjour
|
||||
let txt: Record<string, string> = {};
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trim();
|
||||
if (!line) continue;
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.includes("can be reached at")) {
|
||||
const match = line.match(/can be reached at\s+([^\s:]+):(\d+)/i);
|
||||
@@ -202,21 +240,37 @@ function parseDnsSdResolve(stdout: string, instanceName: string): GatewayBonjour
|
||||
}
|
||||
|
||||
beacon.txt = Object.keys(txt).length ? txt : undefined;
|
||||
if (txt.displayName) beacon.displayName = decodeDnsSdEscapes(txt.displayName);
|
||||
if (txt.lanHost) beacon.lanHost = txt.lanHost;
|
||||
if (txt.tailnetDns) beacon.tailnetDns = txt.tailnetDns;
|
||||
if (txt.cliPath) beacon.cliPath = txt.cliPath;
|
||||
if (txt.displayName) {
|
||||
beacon.displayName = decodeDnsSdEscapes(txt.displayName);
|
||||
}
|
||||
if (txt.lanHost) {
|
||||
beacon.lanHost = txt.lanHost;
|
||||
}
|
||||
if (txt.tailnetDns) {
|
||||
beacon.tailnetDns = txt.tailnetDns;
|
||||
}
|
||||
if (txt.cliPath) {
|
||||
beacon.cliPath = txt.cliPath;
|
||||
}
|
||||
beacon.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
||||
beacon.sshPort = parseIntOrNull(txt.sshPort);
|
||||
if (txt.gatewayTls) {
|
||||
const raw = txt.gatewayTls.trim().toLowerCase();
|
||||
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txt.gatewayTlsSha256) beacon.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
||||
if (txt.role) beacon.role = txt.role;
|
||||
if (txt.transport) beacon.transport = txt.transport;
|
||||
if (txt.gatewayTlsSha256) {
|
||||
beacon.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
||||
}
|
||||
if (txt.role) {
|
||||
beacon.role = txt.role;
|
||||
}
|
||||
if (txt.transport) {
|
||||
beacon.transport = txt.transport;
|
||||
}
|
||||
|
||||
if (!beacon.displayName) beacon.displayName = decodedInstanceName;
|
||||
if (!beacon.displayName) {
|
||||
beacon.displayName = decodedInstanceName;
|
||||
}
|
||||
return beacon;
|
||||
}
|
||||
|
||||
@@ -235,7 +289,9 @@ async function discoverViaDnsSd(
|
||||
timeoutMs,
|
||||
});
|
||||
const parsed = parseDnsSdResolve(resolved.stdout, instance);
|
||||
if (parsed) results.push({ ...parsed, domain });
|
||||
if (parsed) {
|
||||
results.push({ ...parsed, domain });
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -245,7 +301,9 @@ async function discoverWideAreaViaTailnetDns(
|
||||
timeoutMs: number,
|
||||
run: typeof runCommandWithTimeout,
|
||||
): Promise<GatewayBonjourBeacon[]> {
|
||||
if (!domain || domain === "local.") return [];
|
||||
if (!domain || domain === "local.") {
|
||||
return [];
|
||||
}
|
||||
const startedAt = Date.now();
|
||||
const remainingMs = () => timeoutMs - (Date.now() - startedAt);
|
||||
|
||||
@@ -257,13 +315,19 @@ async function discoverWideAreaViaTailnetDns(
|
||||
timeoutMs: Math.max(1, Math.min(700, remainingMs())),
|
||||
});
|
||||
ips = parseTailscaleStatusIPv4s(res.stdout);
|
||||
if (ips.length > 0) break;
|
||||
if (ips.length > 0) {
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (ips.length === 0) return [];
|
||||
if (remainingMs() <= 0) return [];
|
||||
if (ips.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (remainingMs() <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Keep scans bounded: this is a fallback and should not block long.
|
||||
ips = ips.slice(0, 40);
|
||||
@@ -278,19 +342,27 @@ async function discoverWideAreaViaTailnetDns(
|
||||
const worker = async () => {
|
||||
while (nameserver === null) {
|
||||
const budget = remainingMs();
|
||||
if (budget <= 0) return;
|
||||
if (budget <= 0) {
|
||||
return;
|
||||
}
|
||||
const i = nextIndex;
|
||||
nextIndex += 1;
|
||||
if (i >= ips.length) return;
|
||||
if (i >= ips.length) {
|
||||
return;
|
||||
}
|
||||
const ip = ips[i] ?? "";
|
||||
if (!ip) continue;
|
||||
if (!ip) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const probe = await run(
|
||||
["dig", "+short", "+time=1", "+tries=1", `@${ip}`, probeName, "PTR"],
|
||||
{ timeoutMs: Math.max(1, Math.min(250, budget)) },
|
||||
);
|
||||
const lines = parseDigShortLines(probe.stdout);
|
||||
if (lines.length === 0) continue;
|
||||
if (lines.length === 0) {
|
||||
continue;
|
||||
}
|
||||
nameserver = ip;
|
||||
ptrs = lines;
|
||||
return;
|
||||
@@ -302,23 +374,33 @@ async function discoverWideAreaViaTailnetDns(
|
||||
|
||||
await Promise.all(Array.from({ length: Math.min(concurrency, ips.length) }, () => worker()));
|
||||
|
||||
if (!nameserver || ptrs.length === 0) return [];
|
||||
if (remainingMs() <= 0) return [];
|
||||
if (!nameserver || ptrs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (remainingMs() <= 0) {
|
||||
return [];
|
||||
}
|
||||
const nameserverArg = `@${String(nameserver)}`;
|
||||
|
||||
const results: GatewayBonjourBeacon[] = [];
|
||||
for (const ptr of ptrs) {
|
||||
const budget = remainingMs();
|
||||
if (budget <= 0) break;
|
||||
if (budget <= 0) {
|
||||
break;
|
||||
}
|
||||
const ptrName = ptr.trim().replace(/\.$/, "");
|
||||
if (!ptrName) continue;
|
||||
if (!ptrName) {
|
||||
continue;
|
||||
}
|
||||
const instanceName = ptrName.replace(/\.?_openclaw-gw\._tcp\..*$/, "");
|
||||
|
||||
const srv = await run(["dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV"], {
|
||||
timeoutMs: Math.max(1, Math.min(350, budget)),
|
||||
}).catch(() => null);
|
||||
const srvParsed = srv ? parseDigSrv(srv.stdout) : null;
|
||||
if (!srvParsed) continue;
|
||||
if (!srvParsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const txtBudget = remainingMs();
|
||||
if (txtBudget <= 0) {
|
||||
@@ -354,9 +436,15 @@ async function discoverWideAreaViaTailnetDns(
|
||||
const raw = txtMap.gatewayTls.trim().toLowerCase();
|
||||
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txtMap.gatewayTlsSha256) beacon.gatewayTlsFingerprintSha256 = txtMap.gatewayTlsSha256;
|
||||
if (txtMap.role) beacon.role = txtMap.role;
|
||||
if (txtMap.transport) beacon.transport = txtMap.transport;
|
||||
if (txtMap.gatewayTlsSha256) {
|
||||
beacon.gatewayTlsFingerprintSha256 = txtMap.gatewayTlsSha256;
|
||||
}
|
||||
if (txtMap.role) {
|
||||
beacon.role = txtMap.role;
|
||||
}
|
||||
if (txtMap.transport) {
|
||||
beacon.transport = txtMap.transport;
|
||||
}
|
||||
|
||||
results.push(beacon);
|
||||
}
|
||||
@@ -370,9 +458,13 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] {
|
||||
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trimEnd();
|
||||
if (!line) continue;
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("=") && line.includes(GATEWAY_SERVICE_TYPE)) {
|
||||
if (current) results.push(current);
|
||||
if (current) {
|
||||
results.push(current);
|
||||
}
|
||||
const marker = ` ${GATEWAY_SERVICE_TYPE}`;
|
||||
const idx = line.indexOf(marker);
|
||||
const left = idx >= 0 ? line.slice(0, idx).trim() : line;
|
||||
@@ -385,18 +477,24 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!current) continue;
|
||||
if (!current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith("hostname =")) {
|
||||
const match = trimmed.match(/hostname\s*=\s*\[([^\]]+)\]/);
|
||||
if (match?.[1]) current.host = match[1];
|
||||
if (match?.[1]) {
|
||||
current.host = match[1];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith("port =")) {
|
||||
const match = trimmed.match(/port\s*=\s*\[(\d+)\]/);
|
||||
if (match?.[1]) current.port = parseIntOrNull(match[1]);
|
||||
if (match?.[1]) {
|
||||
current.port = parseIntOrNull(match[1]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -404,23 +502,39 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] {
|
||||
const tokens = Array.from(trimmed.matchAll(/"([^"]*)"/g), (m) => m[1]);
|
||||
const txt = parseTxtTokens(tokens);
|
||||
current.txt = Object.keys(txt).length ? txt : undefined;
|
||||
if (txt.displayName) current.displayName = txt.displayName;
|
||||
if (txt.lanHost) current.lanHost = txt.lanHost;
|
||||
if (txt.tailnetDns) current.tailnetDns = txt.tailnetDns;
|
||||
if (txt.cliPath) current.cliPath = txt.cliPath;
|
||||
if (txt.displayName) {
|
||||
current.displayName = txt.displayName;
|
||||
}
|
||||
if (txt.lanHost) {
|
||||
current.lanHost = txt.lanHost;
|
||||
}
|
||||
if (txt.tailnetDns) {
|
||||
current.tailnetDns = txt.tailnetDns;
|
||||
}
|
||||
if (txt.cliPath) {
|
||||
current.cliPath = txt.cliPath;
|
||||
}
|
||||
current.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
||||
current.sshPort = parseIntOrNull(txt.sshPort);
|
||||
if (txt.gatewayTls) {
|
||||
const raw = txt.gatewayTls.trim().toLowerCase();
|
||||
current.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txt.gatewayTlsSha256) current.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
||||
if (txt.role) current.role = txt.role;
|
||||
if (txt.transport) current.transport = txt.transport;
|
||||
if (txt.gatewayTlsSha256) {
|
||||
current.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
|
||||
}
|
||||
if (txt.role) {
|
||||
current.role = txt.role;
|
||||
}
|
||||
if (txt.transport) {
|
||||
current.transport = txt.transport;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current) results.push(current);
|
||||
if (current) {
|
||||
results.push(current);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user