mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
refactor(device-pair): reduce duplicated gateway parsing
This commit is contained in:
@@ -37,45 +37,49 @@ type ResolveAuthResult = {
|
||||
};
|
||||
|
||||
function normalizeUrl(raw: string, schemeFallback: "ws" | "wss"): string | null {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) {
|
||||
const candidate = raw.trim();
|
||||
if (!candidate) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const parsed = new URL(trimmed);
|
||||
const scheme = parsed.protocol.replace(":", "");
|
||||
if (!scheme) {
|
||||
return null;
|
||||
}
|
||||
const resolvedScheme = scheme === "http" ? "ws" : scheme === "https" ? "wss" : scheme;
|
||||
if (resolvedScheme !== "ws" && resolvedScheme !== "wss") {
|
||||
return null;
|
||||
}
|
||||
const host = parsed.hostname;
|
||||
if (!host) {
|
||||
return null;
|
||||
}
|
||||
const port = parsed.port ? `:${parsed.port}` : "";
|
||||
return `${resolvedScheme}://${host}${port}`;
|
||||
} catch {
|
||||
// Fall through to host:port parsing.
|
||||
const parsedUrl = parseNormalizedGatewayUrl(candidate);
|
||||
if (parsedUrl) {
|
||||
return parsedUrl;
|
||||
}
|
||||
const hostPort = candidate.split("/", 1)[0]?.trim() ?? "";
|
||||
return hostPort ? `${schemeFallback}://${hostPort}` : null;
|
||||
}
|
||||
|
||||
const withoutPath = trimmed.split("/")[0] ?? "";
|
||||
if (!withoutPath) {
|
||||
function parseNormalizedGatewayUrl(raw: string): string | null {
|
||||
try {
|
||||
const parsed = new URL(raw);
|
||||
const scheme = parsed.protocol.slice(0, -1);
|
||||
const normalizedScheme = scheme === "http" ? "ws" : scheme === "https" ? "wss" : scheme;
|
||||
if (!(normalizedScheme === "ws" || normalizedScheme === "wss")) {
|
||||
return null;
|
||||
}
|
||||
if (!parsed.hostname) {
|
||||
return null;
|
||||
}
|
||||
return `${normalizedScheme}://${parsed.hostname}${parsed.port ? `:${parsed.port}` : ""}`;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return `${schemeFallback}://${withoutPath}`;
|
||||
}
|
||||
|
||||
function parsePositiveInteger(raw: string | undefined): number | null {
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
const parsed = Number.parseInt(raw, 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
function resolveGatewayPort(cfg: OpenClawPluginApi["config"]): number {
|
||||
const envRaw =
|
||||
process.env.OPENCLAW_GATEWAY_PORT?.trim() || process.env.CLAWDBOT_GATEWAY_PORT?.trim();
|
||||
if (envRaw) {
|
||||
const parsed = Number.parseInt(envRaw, 10);
|
||||
if (Number.isFinite(parsed) && parsed > 0) {
|
||||
return parsed;
|
||||
}
|
||||
const envPort =
|
||||
parsePositiveInteger(process.env.OPENCLAW_GATEWAY_PORT?.trim()) ??
|
||||
parsePositiveInteger(process.env.CLAWDBOT_GATEWAY_PORT?.trim());
|
||||
if (envPort) {
|
||||
return envPort;
|
||||
}
|
||||
const configPort = cfg.gateway?.port;
|
||||
if (typeof configPort === "number" && Number.isFinite(configPort) && configPort > 0) {
|
||||
@@ -215,25 +219,20 @@ function parsePossiblyNoisyJsonObject(raw: string): Record<string, unknown> {
|
||||
function resolveAuth(cfg: OpenClawPluginApi["config"]): ResolveAuthResult {
|
||||
const mode = cfg.gateway?.auth?.mode;
|
||||
const token =
|
||||
process.env.OPENCLAW_GATEWAY_TOKEN?.trim() ||
|
||||
process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() ||
|
||||
cfg.gateway?.auth?.token?.trim();
|
||||
pickFirstDefined([
|
||||
process.env.OPENCLAW_GATEWAY_TOKEN,
|
||||
process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||
cfg.gateway?.auth?.token,
|
||||
]) ?? undefined;
|
||||
const password =
|
||||
process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() ||
|
||||
process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() ||
|
||||
cfg.gateway?.auth?.password?.trim();
|
||||
pickFirstDefined([
|
||||
process.env.OPENCLAW_GATEWAY_PASSWORD,
|
||||
process.env.CLAWDBOT_GATEWAY_PASSWORD,
|
||||
cfg.gateway?.auth?.password,
|
||||
]) ?? undefined;
|
||||
|
||||
if (mode === "password") {
|
||||
if (!password) {
|
||||
return { error: "Gateway auth is set to password, but no password is configured." };
|
||||
}
|
||||
return { password, label: "password" };
|
||||
}
|
||||
if (mode === "token") {
|
||||
if (!token) {
|
||||
return { error: "Gateway auth is set to token, but no token is configured." };
|
||||
}
|
||||
return { token, label: "token" };
|
||||
if (mode === "token" || mode === "password") {
|
||||
return resolveRequiredAuth(mode, { token, password });
|
||||
}
|
||||
if (token) {
|
||||
return { token, label: "token" };
|
||||
@@ -244,6 +243,30 @@ function resolveAuth(cfg: OpenClawPluginApi["config"]): ResolveAuthResult {
|
||||
return { error: "Gateway auth is not configured (no token or password)." };
|
||||
}
|
||||
|
||||
function pickFirstDefined(candidates: Array<string | undefined>): string | null {
|
||||
for (const value of candidates) {
|
||||
const trimmed = value?.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveRequiredAuth(
|
||||
mode: "token" | "password",
|
||||
values: { token?: string; password?: string },
|
||||
): ResolveAuthResult {
|
||||
if (mode === "token") {
|
||||
return values.token
|
||||
? { token: values.token, label: "token" }
|
||||
: { error: "Gateway auth is set to token, but no token is configured." };
|
||||
}
|
||||
return values.password
|
||||
? { password: values.password, label: "password" }
|
||||
: { error: "Gateway auth is set to password, but no password is configured." };
|
||||
}
|
||||
|
||||
async function resolveGatewayUrl(api: OpenClawPluginApi): Promise<ResolveUrlResult> {
|
||||
const cfg = api.config;
|
||||
const pluginCfg = (api.pluginConfig ?? {}) as DevicePairPluginConfig;
|
||||
|
||||
Reference in New Issue
Block a user