mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
refactor: split gateway port parsing helpers
This commit is contained in:
25
extensions/device-pair/api.test.ts
Normal file
25
extensions/device-pair/api.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { type OpenClawPluginApi, resolveGatewayPort } from "./api.js";
|
||||
|
||||
function envWith(overrides: Record<string, string | undefined>): NodeJS.ProcessEnv {
|
||||
return { ...overrides };
|
||||
}
|
||||
|
||||
describe("device-pair api", () => {
|
||||
it("forwards Compose-style env parsing through the plugin sdk seam", () => {
|
||||
const cfg = { gateway: { port: 19002 } } as OpenClawPluginApi["config"];
|
||||
|
||||
expect(resolveGatewayPort(cfg, envWith({ OPENCLAW_GATEWAY_PORT: "127.0.0.1:18789" }))).toBe(
|
||||
18789,
|
||||
);
|
||||
expect(resolveGatewayPort(cfg, envWith({ OPENCLAW_GATEWAY_PORT: "[::1]:28789" }))).toBe(28789);
|
||||
});
|
||||
|
||||
it("keeps ignoring the legacy env name at the plugin seam", () => {
|
||||
const cfg = { gateway: { port: 19002 } } as OpenClawPluginApi["config"];
|
||||
|
||||
expect(resolveGatewayPort(cfg, envWith({ CLAWDBOT_GATEWAY_PORT: "127.0.0.1:18789" }))).toBe(
|
||||
19002,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -27,7 +27,10 @@ async function readGeneratedProvider(providerKey: string) {
|
||||
return parsed.providers[providerKey];
|
||||
}
|
||||
|
||||
async function expectGeneratedProvider(providerKey: string, params: { ids: string[]; baseUrl?: string }) {
|
||||
async function expectGeneratedProvider(
|
||||
providerKey: string,
|
||||
params: { ids: string[]; baseUrl?: string },
|
||||
) {
|
||||
const provider = await readGeneratedProvider(providerKey);
|
||||
expect(provider?.models?.map((model) => model.id)).toEqual(params.ids);
|
||||
if (params.baseUrl !== undefined) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { coerceSecretRef, resolveSecretInputRef } from "../config/types.secrets.js";
|
||||
import { normalizeGoogleApiBaseUrl } from "../infra/google-api-base-url.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import {
|
||||
buildAnthropicVertexProvider,
|
||||
@@ -17,7 +18,6 @@ import {
|
||||
} from "../plugin-sdk/provider-catalog.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
import { normalizeOptionalSecretInput } from "../utils/normalize-secret-input.js";
|
||||
import { normalizeGoogleApiBaseUrl } from "../infra/google-api-base-url.js";
|
||||
import { hasAnthropicVertexAvailableAuth } from "./anthropic-vertex-provider.js";
|
||||
import { ensureAuthProfileStore, listProfilesForProvider } from "./auth-profiles.js";
|
||||
import { discoverBedrockModels } from "./bedrock-discovery.js";
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Api, Model } from "@mariozechner/pi-ai";
|
||||
import type { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { ModelDefinitionConfig } from "../../config/types.js";
|
||||
import { normalizeGoogleApiBaseUrl } from "../../infra/google-api-base-url.js";
|
||||
import {
|
||||
clearProviderRuntimeHookCache,
|
||||
prepareProviderDynamicModel,
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
shouldSuppressBuiltInModel,
|
||||
} from "../model-suppression.js";
|
||||
import { discoverAuthStorage, discoverModels } from "../pi-model-discovery.js";
|
||||
import { normalizeGoogleApiBaseUrl } from "../../infra/google-api-base-url.js";
|
||||
import { normalizeResolvedProviderModel } from "./model.provider-normalization.js";
|
||||
|
||||
function normalizeGoogleGenerativeAiBaseUrl(baseUrl: string | undefined): string | undefined {
|
||||
|
||||
@@ -256,30 +256,31 @@ function parseGatewayPortEnvValue(raw: string | undefined): number | null {
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
if (/^\d+$/.test(trimmed)) {
|
||||
const parsed = Number.parseInt(trimmed, 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
return parsePositivePort(trimmed) ?? parseComposePublishedPort(trimmed);
|
||||
}
|
||||
|
||||
function parsePositivePort(raw: string): number | null {
|
||||
if (!/^\d+$/.test(raw)) {
|
||||
return null;
|
||||
}
|
||||
const parsed = Number.parseInt(raw, 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
function parseComposePublishedPort(raw: string): number | null {
|
||||
// Docker Compose publish strings can leak into host CLI env loading via repo `.env`,
|
||||
// for example `127.0.0.1:18789` or `[::1]:18789`. Accept only explicit host:port forms.
|
||||
const bracketedIpv6Match = trimmed.match(/^\[[^\]]+\]:(\d+)$/);
|
||||
const bracketedIpv6Match = raw.match(/^\[[^\]]+\]:(\d+)$/);
|
||||
if (bracketedIpv6Match?.[1]) {
|
||||
const parsed = Number.parseInt(bracketedIpv6Match[1], 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
return parsePositivePort(bracketedIpv6Match[1]);
|
||||
}
|
||||
|
||||
const firstColon = trimmed.indexOf(":");
|
||||
const lastColon = trimmed.lastIndexOf(":");
|
||||
const firstColon = raw.indexOf(":");
|
||||
const lastColon = raw.lastIndexOf(":");
|
||||
if (firstColon <= 0 || firstColon !== lastColon) {
|
||||
return null;
|
||||
}
|
||||
const suffix = trimmed.slice(firstColon + 1);
|
||||
if (!/^\d+$/.test(suffix)) {
|
||||
return null;
|
||||
}
|
||||
const parsed = Number.parseInt(suffix, 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
return parsePositivePort(raw.slice(firstColon + 1));
|
||||
}
|
||||
|
||||
export function resolveGatewayPort(
|
||||
|
||||
Reference in New Issue
Block a user