Add configurable OpenClaw origin override
This commit is contained in:
parent
87d573c528
commit
33862d353b
@ -13,6 +13,7 @@ export const dynamic = 'force-dynamic'
|
|||||||
type ProbeBody = {
|
type ProbeBody = {
|
||||||
target?: 'openclaw' | 'vault' | 'apisix'
|
target?: 'openclaw' | 'vault' | 'apisix'
|
||||||
gatewayUrl?: string
|
gatewayUrl?: string
|
||||||
|
gatewayOrigin?: string
|
||||||
gatewayToken?: string
|
gatewayToken?: string
|
||||||
vaultUrl?: string
|
vaultUrl?: string
|
||||||
vaultNamespace?: string
|
vaultNamespace?: string
|
||||||
@ -64,7 +65,21 @@ function formatGatewayError(error: OpenClawGatewayError | null, client: OpenClaw
|
|||||||
return error.message
|
return error.message
|
||||||
}
|
}
|
||||||
|
|
||||||
async function probeOpenClaw(body: ProbeBody): Promise<Response> {
|
function resolveGatewayOrigin(override: string | undefined, request: NextRequest): string {
|
||||||
|
const explicit = override?.trim()
|
||||||
|
if (explicit) {
|
||||||
|
return explicit
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerOrigin = request.headers.get('origin')?.trim()
|
||||||
|
if (headerOrigin) {
|
||||||
|
return headerOrigin
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.nextUrl.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
async function probeOpenClaw(body: ProbeBody, request: NextRequest): Promise<Response> {
|
||||||
const config = await resolveOpenClawGatewayConfig({
|
const config = await resolveOpenClawGatewayConfig({
|
||||||
gatewayUrl: body.gatewayUrl,
|
gatewayUrl: body.gatewayUrl,
|
||||||
gatewayToken: body.gatewayToken,
|
gatewayToken: body.gatewayToken,
|
||||||
@ -84,6 +99,7 @@ async function probeOpenClaw(body: ProbeBody): Promise<Response> {
|
|||||||
try {
|
try {
|
||||||
await client.connect({
|
await client.connect({
|
||||||
gatewayUrl: config.gatewayUrl,
|
gatewayUrl: config.gatewayUrl,
|
||||||
|
gatewayOrigin: resolveGatewayOrigin(body.gatewayOrigin, request),
|
||||||
gatewayToken: config.gatewayToken,
|
gatewayToken: config.gatewayToken,
|
||||||
clientLabel: 'console.svc.plus Probe',
|
clientLabel: 'console.svc.plus Probe',
|
||||||
})
|
})
|
||||||
@ -223,7 +239,7 @@ export async function POST(request: NextRequest): Promise<Response> {
|
|||||||
|
|
||||||
switch (body.target) {
|
switch (body.target) {
|
||||||
case 'openclaw':
|
case 'openclaw':
|
||||||
return probeOpenClaw(body)
|
return probeOpenClaw(body, request)
|
||||||
case 'vault':
|
case 'vault':
|
||||||
return probeVault(body)
|
return probeVault(body)
|
||||||
case 'apisix':
|
case 'apisix':
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const dynamic = 'force-dynamic'
|
|||||||
type BootstrapBody = {
|
type BootstrapBody = {
|
||||||
action: 'bootstrap'
|
action: 'bootstrap'
|
||||||
gatewayUrl?: string
|
gatewayUrl?: string
|
||||||
|
gatewayOrigin?: string
|
||||||
gatewayToken?: string
|
gatewayToken?: string
|
||||||
vaultUrl?: string
|
vaultUrl?: string
|
||||||
vaultNamespace?: string
|
vaultNamespace?: string
|
||||||
@ -31,6 +32,7 @@ type BootstrapBody = {
|
|||||||
type SendBody = {
|
type SendBody = {
|
||||||
action: 'send'
|
action: 'send'
|
||||||
gatewayUrl?: string
|
gatewayUrl?: string
|
||||||
|
gatewayOrigin?: string
|
||||||
gatewayToken?: string
|
gatewayToken?: string
|
||||||
vaultUrl?: string
|
vaultUrl?: string
|
||||||
vaultNamespace?: string
|
vaultNamespace?: string
|
||||||
@ -112,7 +114,21 @@ function resolveSessionKey(params: {
|
|||||||
return makeAgentSessionKey(params.agentId?.trim() ?? '', params.mainSessionKey)
|
return makeAgentSessionKey(params.agentId?.trim() ?? '', params.mainSessionKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleBootstrap(body: BootstrapBody): Promise<Response> {
|
function resolveGatewayOrigin(override: string | undefined, request: NextRequest): string {
|
||||||
|
const explicit = override?.trim()
|
||||||
|
if (explicit) {
|
||||||
|
return explicit
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerOrigin = request.headers.get('origin')?.trim()
|
||||||
|
if (headerOrigin) {
|
||||||
|
return headerOrigin
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.nextUrl.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleBootstrap(body: BootstrapBody, request: NextRequest): Promise<Response> {
|
||||||
const gateway = await resolveOpenClawGatewayConfig({
|
const gateway = await resolveOpenClawGatewayConfig({
|
||||||
gatewayUrl: body.gatewayUrl,
|
gatewayUrl: body.gatewayUrl,
|
||||||
gatewayToken: body.gatewayToken,
|
gatewayToken: body.gatewayToken,
|
||||||
@ -132,6 +148,7 @@ async function handleBootstrap(body: BootstrapBody): Promise<Response> {
|
|||||||
try {
|
try {
|
||||||
const connected = await client.connect({
|
const connected = await client.connect({
|
||||||
gatewayUrl: gateway.gatewayUrl,
|
gatewayUrl: gateway.gatewayUrl,
|
||||||
|
gatewayOrigin: resolveGatewayOrigin(body.gatewayOrigin, request),
|
||||||
gatewayToken: gateway.gatewayToken,
|
gatewayToken: gateway.gatewayToken,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -178,7 +195,7 @@ async function handleBootstrap(body: BootstrapBody): Promise<Response> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSend(body: SendBody): Promise<Response> {
|
async function handleSend(body: SendBody, request: NextRequest): Promise<Response> {
|
||||||
const gateway = await resolveOpenClawGatewayConfig({
|
const gateway = await resolveOpenClawGatewayConfig({
|
||||||
gatewayUrl: body.gatewayUrl,
|
gatewayUrl: body.gatewayUrl,
|
||||||
gatewayToken: body.gatewayToken,
|
gatewayToken: body.gatewayToken,
|
||||||
@ -258,6 +275,7 @@ async function handleSend(body: SendBody): Promise<Response> {
|
|||||||
client = new OpenClawGatewayClient()
|
client = new OpenClawGatewayClient()
|
||||||
const connected = await client.connect({
|
const connected = await client.connect({
|
||||||
gatewayUrl: gateway.gatewayUrl,
|
gatewayUrl: gateway.gatewayUrl,
|
||||||
|
gatewayOrigin: resolveGatewayOrigin(body.gatewayOrigin, request),
|
||||||
gatewayToken: gateway.gatewayToken,
|
gatewayToken: gateway.gatewayToken,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -396,11 +414,11 @@ export async function POST(request: NextRequest): Promise<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (body.action === 'bootstrap') {
|
if (body.action === 'bootstrap') {
|
||||||
return handleBootstrap(body)
|
return handleBootstrap(body, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body.action === 'send') {
|
if (body.action === 'send') {
|
||||||
return handleSend(body)
|
return handleSend(body, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsonError('Unsupported assistant action.', 400, 'UNSUPPORTED_ACTION')
|
return jsonError('Unsupported assistant action.', 400, 'UNSUPPORTED_ACTION')
|
||||||
|
|||||||
@ -30,6 +30,7 @@ export function AskAIDialog({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const resolvedDefaults: IntegrationDefaults = defaults ?? {
|
const resolvedDefaults: IntegrationDefaults = defaults ?? {
|
||||||
openclawUrl: "",
|
openclawUrl: "",
|
||||||
|
openclawOrigin: "",
|
||||||
openclawTokenConfigured: false,
|
openclawTokenConfigured: false,
|
||||||
vaultUrl: "",
|
vaultUrl: "",
|
||||||
vaultNamespace: "",
|
vaultNamespace: "",
|
||||||
|
|||||||
@ -230,6 +230,7 @@ export function OpenClawAssistantPane({
|
|||||||
);
|
);
|
||||||
const applyDefaults = useOpenClawConsoleStore((state) => state.applyDefaults);
|
const applyDefaults = useOpenClawConsoleStore((state) => state.applyDefaults);
|
||||||
const openclawUrl = useOpenClawConsoleStore((state) => state.openclawUrl);
|
const openclawUrl = useOpenClawConsoleStore((state) => state.openclawUrl);
|
||||||
|
const openclawOrigin = useOpenClawConsoleStore((state) => state.openclawOrigin);
|
||||||
const openclawToken = useOpenClawConsoleStore((state) => state.openclawToken);
|
const openclawToken = useOpenClawConsoleStore((state) => state.openclawToken);
|
||||||
const vaultUrl = useOpenClawConsoleStore((state) => state.vaultUrl);
|
const vaultUrl = useOpenClawConsoleStore((state) => state.vaultUrl);
|
||||||
const vaultNamespace = useOpenClawConsoleStore(
|
const vaultNamespace = useOpenClawConsoleStore(
|
||||||
@ -436,6 +437,7 @@ export function OpenClawAssistantPane({
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: "bootstrap",
|
action: "bootstrap",
|
||||||
gatewayUrl: openclawUrl,
|
gatewayUrl: openclawUrl,
|
||||||
|
gatewayOrigin: openclawOrigin,
|
||||||
gatewayToken: openclawToken,
|
gatewayToken: openclawToken,
|
||||||
vaultUrl,
|
vaultUrl,
|
||||||
vaultNamespace,
|
vaultNamespace,
|
||||||
@ -479,6 +481,7 @@ export function OpenClawAssistantPane({
|
|||||||
copy.connectFailed,
|
copy.connectFailed,
|
||||||
copy.serverMissing,
|
copy.serverMissing,
|
||||||
openclawToken,
|
openclawToken,
|
||||||
|
openclawOrigin,
|
||||||
openclawUrl,
|
openclawUrl,
|
||||||
vaultNamespace,
|
vaultNamespace,
|
||||||
vaultSecretKey,
|
vaultSecretKey,
|
||||||
@ -585,6 +588,7 @@ export function OpenClawAssistantPane({
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: "send",
|
action: "send",
|
||||||
gatewayUrl: openclawUrl,
|
gatewayUrl: openclawUrl,
|
||||||
|
gatewayOrigin: openclawOrigin,
|
||||||
gatewayToken: openclawToken,
|
gatewayToken: openclawToken,
|
||||||
vaultUrl,
|
vaultUrl,
|
||||||
vaultNamespace,
|
vaultNamespace,
|
||||||
@ -668,6 +672,7 @@ export function OpenClawAssistantPane({
|
|||||||
isChinese,
|
isChinese,
|
||||||
mainSessionKey,
|
mainSessionKey,
|
||||||
openclawToken,
|
openclawToken,
|
||||||
|
openclawOrigin,
|
||||||
openclawUrl,
|
openclawUrl,
|
||||||
vaultNamespace,
|
vaultNamespace,
|
||||||
vaultSecretKey,
|
vaultSecretKey,
|
||||||
|
|||||||
@ -79,6 +79,7 @@ export type OpenClawStreamEvent =
|
|||||||
|
|
||||||
export type IntegrationDefaults = {
|
export type IntegrationDefaults = {
|
||||||
openclawUrl: string
|
openclawUrl: string
|
||||||
|
openclawOrigin: string
|
||||||
openclawTokenConfigured: boolean
|
openclawTokenConfigured: boolean
|
||||||
vaultUrl: string
|
vaultUrl: string
|
||||||
vaultNamespace: string
|
vaultNamespace: string
|
||||||
|
|||||||
@ -89,6 +89,7 @@ function stringValue(value: unknown): string | undefined {
|
|||||||
|
|
||||||
const EMPTY_DEFAULTS: IntegrationDefaults = {
|
const EMPTY_DEFAULTS: IntegrationDefaults = {
|
||||||
openclawUrl: "",
|
openclawUrl: "",
|
||||||
|
openclawOrigin: "",
|
||||||
openclawTokenConfigured: false,
|
openclawTokenConfigured: false,
|
||||||
vaultUrl: "",
|
vaultUrl: "",
|
||||||
vaultNamespace: "",
|
vaultNamespace: "",
|
||||||
@ -118,6 +119,7 @@ export function IntegrationsConsole({
|
|||||||
|
|
||||||
const applyDefaults = useOpenClawConsoleStore((state) => state.applyDefaults);
|
const applyDefaults = useOpenClawConsoleStore((state) => state.applyDefaults);
|
||||||
const openclawUrl = useOpenClawConsoleStore((state) => state.openclawUrl);
|
const openclawUrl = useOpenClawConsoleStore((state) => state.openclawUrl);
|
||||||
|
const openclawOrigin = useOpenClawConsoleStore((state) => state.openclawOrigin);
|
||||||
const openclawToken = useOpenClawConsoleStore((state) => state.openclawToken);
|
const openclawToken = useOpenClawConsoleStore((state) => state.openclawToken);
|
||||||
const vaultUrl = useOpenClawConsoleStore((state) => state.vaultUrl);
|
const vaultUrl = useOpenClawConsoleStore((state) => state.vaultUrl);
|
||||||
const vaultNamespace = useOpenClawConsoleStore(
|
const vaultNamespace = useOpenClawConsoleStore(
|
||||||
@ -135,6 +137,9 @@ export function IntegrationsConsole({
|
|||||||
const setOpenclawUrl = useOpenClawConsoleStore(
|
const setOpenclawUrl = useOpenClawConsoleStore(
|
||||||
(state) => state.setOpenclawUrl,
|
(state) => state.setOpenclawUrl,
|
||||||
);
|
);
|
||||||
|
const setOpenclawOrigin = useOpenClawConsoleStore(
|
||||||
|
(state) => state.setOpenclawOrigin,
|
||||||
|
);
|
||||||
const setOpenclawToken = useOpenClawConsoleStore(
|
const setOpenclawToken = useOpenClawConsoleStore(
|
||||||
(state) => state.setOpenclawToken,
|
(state) => state.setOpenclawToken,
|
||||||
);
|
);
|
||||||
@ -240,6 +245,7 @@ export function IntegrationsConsole({
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
target,
|
target,
|
||||||
gatewayUrl: openclawUrl,
|
gatewayUrl: openclawUrl,
|
||||||
|
gatewayOrigin: openclawOrigin,
|
||||||
gatewayToken: openclawToken,
|
gatewayToken: openclawToken,
|
||||||
vaultUrl,
|
vaultUrl,
|
||||||
vaultNamespace,
|
vaultNamespace,
|
||||||
@ -382,6 +388,19 @@ export function IntegrationsConsole({
|
|||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
label="Origin Override"
|
||||||
|
hint="可选。留空时自动使用当前页面 origin,例如 https://preview.svc.plus。"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={openclawOrigin}
|
||||||
|
onChange={(event) => setOpenclawOrigin(event.target.value)}
|
||||||
|
className={inputClassName()}
|
||||||
|
placeholder="https://preview.svc.plus"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -83,6 +83,7 @@ function normalizeWsUrl(value?: string): string {
|
|||||||
export function getConsoleIntegrationDefaults(): IntegrationDefaults {
|
export function getConsoleIntegrationDefaults(): IntegrationDefaults {
|
||||||
return {
|
return {
|
||||||
openclawUrl: normalizeWsUrl(readEnvValue(...OPENCLAW_URL_KEYS)),
|
openclawUrl: normalizeWsUrl(readEnvValue(...OPENCLAW_URL_KEYS)),
|
||||||
|
openclawOrigin: '',
|
||||||
openclawTokenConfigured: Boolean(readEnvValue(...OPENCLAW_TOKEN_KEYS)),
|
openclawTokenConfigured: Boolean(readEnvValue(...OPENCLAW_TOKEN_KEYS)),
|
||||||
vaultUrl: normalizeHttpUrl(readEnvValue(...VAULT_URL_KEYS)),
|
vaultUrl: normalizeHttpUrl(readEnvValue(...VAULT_URL_KEYS)),
|
||||||
vaultNamespace: readEnvValue(...VAULT_NAMESPACE_KEYS) ?? '',
|
vaultNamespace: readEnvValue(...VAULT_NAMESPACE_KEYS) ?? '',
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'server-only'
|
import 'server-only'
|
||||||
|
|
||||||
import { randomUUID } from 'node:crypto'
|
import { randomUUID } from 'node:crypto'
|
||||||
|
import WebSocket from 'ws'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
extractMessageText,
|
extractMessageText,
|
||||||
@ -50,6 +51,8 @@ type GatewayEventFrame = {
|
|||||||
payload?: unknown
|
payload?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GatewaySocket = WebSocket
|
||||||
|
|
||||||
function asRecord(value: unknown): Record<string, unknown> {
|
function asRecord(value: unknown): Record<string, unknown> {
|
||||||
return value && typeof value === 'object' && !Array.isArray(value)
|
return value && typeof value === 'object' && !Array.isArray(value)
|
||||||
? (value as Record<string, unknown>)
|
? (value as Record<string, unknown>)
|
||||||
@ -135,13 +138,13 @@ export class OpenClawGatewayError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class OpenClawGatewayClient {
|
export class OpenClawGatewayClient {
|
||||||
private socket: WebSocket | null = null
|
private socket: GatewaySocket | null = null
|
||||||
private currentDeviceId = ''
|
private currentDeviceId = ''
|
||||||
private connectChallengeNonce: string | null = null
|
private connectChallengeNonce: string | null = null
|
||||||
private pending = new Map<string, PendingRequest>()
|
private pending = new Map<string, PendingRequest>()
|
||||||
private listeners = new Set<(event: GatewayEventFrame) => void>()
|
private listeners = new Set<(event: GatewayEventFrame) => void>()
|
||||||
private handleMessageRef = (event: MessageEvent) => {
|
private handleMessageRef = (data: unknown) => {
|
||||||
void this.handleMessage(event)
|
void this.handleMessage(data)
|
||||||
}
|
}
|
||||||
private handleCloseRef = () => {
|
private handleCloseRef = () => {
|
||||||
this.failPending(new OpenClawGatewayError('Gateway connection closed', 'SOCKET_CLOSED'))
|
this.failPending(new OpenClawGatewayError('Gateway connection closed', 'SOCKET_CLOSED'))
|
||||||
@ -152,42 +155,44 @@ export class OpenClawGatewayClient {
|
|||||||
|
|
||||||
async connect(params: {
|
async connect(params: {
|
||||||
gatewayUrl: string
|
gatewayUrl: string
|
||||||
|
gatewayOrigin?: string
|
||||||
gatewayToken: string
|
gatewayToken: string
|
||||||
clientId?: string
|
clientId?: string
|
||||||
clientMode?: string
|
clientMode?: string
|
||||||
clientLabel?: string
|
clientLabel?: string
|
||||||
}): Promise<{ mainSessionKey: string; deviceId: string }> {
|
}): Promise<{ mainSessionKey: string; deviceId: string }> {
|
||||||
const url = resolveGatewayUrl(params.gatewayUrl)
|
const url = resolveGatewayUrl(params.gatewayUrl)
|
||||||
const socket = new WebSocket(url)
|
const origin = params.gatewayOrigin?.trim()
|
||||||
|
const socket = new WebSocket(url, {
|
||||||
|
...(origin
|
||||||
|
? {
|
||||||
|
headers: {
|
||||||
|
Origin: origin,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
})
|
||||||
this.socket = socket
|
this.socket = socket
|
||||||
this.connectChallengeNonce = null
|
this.connectChallengeNonce = null
|
||||||
|
|
||||||
socket.addEventListener('message', this.handleMessageRef)
|
socket.on('message', this.handleMessageRef)
|
||||||
socket.addEventListener('close', this.handleCloseRef)
|
socket.on('close', this.handleCloseRef)
|
||||||
socket.addEventListener('error', this.handleErrorRef)
|
socket.on('error', this.handleErrorRef)
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
reject(new OpenClawGatewayError('Gateway open timeout', 'OPEN_TIMEOUT'))
|
reject(new OpenClawGatewayError('Gateway open timeout', 'OPEN_TIMEOUT'))
|
||||||
}, 8000)
|
}, 8000)
|
||||||
|
|
||||||
socket.addEventListener(
|
socket.once('open', () => {
|
||||||
'open',
|
clearTimeout(timeout)
|
||||||
() => {
|
resolve()
|
||||||
clearTimeout(timeout)
|
})
|
||||||
resolve()
|
|
||||||
},
|
|
||||||
{ once: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
socket.addEventListener(
|
socket.once('error', () => {
|
||||||
'error',
|
clearTimeout(timeout)
|
||||||
() => {
|
reject(new OpenClawGatewayError('Gateway open failed', 'OPEN_FAILED'))
|
||||||
clearTimeout(timeout)
|
})
|
||||||
reject(new OpenClawGatewayError('Gateway open failed', 'OPEN_FAILED'))
|
|
||||||
},
|
|
||||||
{ once: true },
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const clientId = params.clientId ?? OPENCLAW_CLIENT_IDS.assistant
|
const clientId = params.clientId ?? OPENCLAW_CLIENT_IDS.assistant
|
||||||
@ -297,7 +302,7 @@ export class OpenClawGatewayClient {
|
|||||||
return this.currentDeviceId
|
return this.currentDeviceId
|
||||||
}
|
}
|
||||||
|
|
||||||
private async waitForConnectChallenge(socket: WebSocket): Promise<string> {
|
private async waitForConnectChallenge(socket: GatewaySocket): Promise<string> {
|
||||||
if (this.connectChallengeNonce) {
|
if (this.connectChallengeNonce) {
|
||||||
return this.connectChallengeNonce
|
return this.connectChallengeNonce
|
||||||
}
|
}
|
||||||
@ -341,12 +346,12 @@ export class OpenClawGatewayClient {
|
|||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
stopListening()
|
stopListening()
|
||||||
socket.removeEventListener('close', onClose)
|
socket.off('close', onClose)
|
||||||
socket.removeEventListener('error', onError)
|
socket.off('error', onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.addEventListener('close', onClose, { once: true })
|
socket.once('close', onClose)
|
||||||
socket.addEventListener('error', onError, { once: true })
|
socket.once('error', onError)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,17 +514,17 @@ export class OpenClawGatewayClient {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.removeEventListener('message', this.handleMessageRef)
|
socket.off('message', this.handleMessageRef)
|
||||||
socket.removeEventListener('close', this.handleCloseRef)
|
socket.off('close', this.handleCloseRef)
|
||||||
socket.removeEventListener('error', this.handleErrorRef)
|
socket.off('error', this.handleErrorRef)
|
||||||
|
|
||||||
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
||||||
socket.close()
|
socket.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleMessage(event: MessageEvent): Promise<void> {
|
private async handleMessage(data: unknown): Promise<void> {
|
||||||
const text = toText(event.data)
|
const text = toText(data)
|
||||||
let payload: Record<string, unknown>
|
let payload: Record<string, unknown>
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import type { AssistantMode, IntegrationDefaults, ThinkingLevel } from '@/lib/op
|
|||||||
type OpenClawConsoleState = {
|
type OpenClawConsoleState = {
|
||||||
defaultsLoaded: boolean
|
defaultsLoaded: boolean
|
||||||
openclawUrl: string
|
openclawUrl: string
|
||||||
|
openclawOrigin: string
|
||||||
openclawToken: string
|
openclawToken: string
|
||||||
vaultUrl: string
|
vaultUrl: string
|
||||||
vaultNamespace: string
|
vaultNamespace: string
|
||||||
@ -22,6 +23,7 @@ type OpenClawConsoleState = {
|
|||||||
selectedSessionKey: string
|
selectedSessionKey: string
|
||||||
applyDefaults: (defaults: IntegrationDefaults) => void
|
applyDefaults: (defaults: IntegrationDefaults) => void
|
||||||
setOpenclawUrl: (value: string) => void
|
setOpenclawUrl: (value: string) => void
|
||||||
|
setOpenclawOrigin: (value: string) => void
|
||||||
setOpenclawToken: (value: string) => void
|
setOpenclawToken: (value: string) => void
|
||||||
setVaultUrl: (value: string) => void
|
setVaultUrl: (value: string) => void
|
||||||
setVaultNamespace: (value: string) => void
|
setVaultNamespace: (value: string) => void
|
||||||
@ -41,6 +43,7 @@ export const useOpenClawConsoleStore = create<OpenClawConsoleState>()(
|
|||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
defaultsLoaded: false,
|
defaultsLoaded: false,
|
||||||
openclawUrl: '',
|
openclawUrl: '',
|
||||||
|
openclawOrigin: '',
|
||||||
openclawToken: '',
|
openclawToken: '',
|
||||||
vaultUrl: '',
|
vaultUrl: '',
|
||||||
vaultNamespace: '',
|
vaultNamespace: '',
|
||||||
@ -58,6 +61,7 @@ export const useOpenClawConsoleStore = create<OpenClawConsoleState>()(
|
|||||||
set({
|
set({
|
||||||
defaultsLoaded: true,
|
defaultsLoaded: true,
|
||||||
openclawUrl: current.openclawUrl || defaults.openclawUrl,
|
openclawUrl: current.openclawUrl || defaults.openclawUrl,
|
||||||
|
openclawOrigin: current.openclawOrigin || defaults.openclawOrigin,
|
||||||
vaultUrl: current.vaultUrl || defaults.vaultUrl,
|
vaultUrl: current.vaultUrl || defaults.vaultUrl,
|
||||||
vaultNamespace: current.vaultNamespace || defaults.vaultNamespace,
|
vaultNamespace: current.vaultNamespace || defaults.vaultNamespace,
|
||||||
vaultSecretPath: current.vaultSecretPath || defaults.vaultSecretPath,
|
vaultSecretPath: current.vaultSecretPath || defaults.vaultSecretPath,
|
||||||
@ -66,6 +70,7 @@ export const useOpenClawConsoleStore = create<OpenClawConsoleState>()(
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
setOpenclawUrl: (openclawUrl) => set({ openclawUrl }),
|
setOpenclawUrl: (openclawUrl) => set({ openclawUrl }),
|
||||||
|
setOpenclawOrigin: (openclawOrigin) => set({ openclawOrigin }),
|
||||||
setOpenclawToken: (openclawToken) => set({ openclawToken }),
|
setOpenclawToken: (openclawToken) => set({ openclawToken }),
|
||||||
setVaultUrl: (vaultUrl) => set({ vaultUrl }),
|
setVaultUrl: (vaultUrl) => set({ vaultUrl }),
|
||||||
setVaultNamespace: (vaultNamespace) => set({ vaultNamespace }),
|
setVaultNamespace: (vaultNamespace) => set({ vaultNamespace }),
|
||||||
@ -84,6 +89,7 @@ export const useOpenClawConsoleStore = create<OpenClawConsoleState>()(
|
|||||||
storage: createJSONStorage(() => sessionStorage),
|
storage: createJSONStorage(() => sessionStorage),
|
||||||
partialize: (state) => ({
|
partialize: (state) => ({
|
||||||
openclawUrl: state.openclawUrl,
|
openclawUrl: state.openclawUrl,
|
||||||
|
openclawOrigin: state.openclawOrigin,
|
||||||
openclawToken: state.openclawToken,
|
openclawToken: state.openclawToken,
|
||||||
vaultUrl: state.vaultUrl,
|
vaultUrl: state.vaultUrl,
|
||||||
vaultNamespace: state.vaultNamespace,
|
vaultNamespace: state.vaultNamespace,
|
||||||
|
|||||||
40
types/ws.d.ts
vendored
Normal file
40
types/ws.d.ts
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
declare module "ws" {
|
||||||
|
export type MessageData =
|
||||||
|
| string
|
||||||
|
| ArrayBuffer
|
||||||
|
| Buffer
|
||||||
|
| Buffer[]
|
||||||
|
| ArrayBufferView
|
||||||
|
|
||||||
|
export type ClientOptions = {
|
||||||
|
headers?: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class WebSocket {
|
||||||
|
static readonly CONNECTING: number
|
||||||
|
static readonly OPEN: number
|
||||||
|
static readonly CLOSING: number
|
||||||
|
static readonly CLOSED: number
|
||||||
|
|
||||||
|
readonly readyState: number
|
||||||
|
|
||||||
|
constructor(address: string | URL, options?: ClientOptions)
|
||||||
|
|
||||||
|
on(event: "open", listener: () => void): this
|
||||||
|
on(event: "close", listener: () => void): this
|
||||||
|
on(event: "error", listener: (error: Error) => void): this
|
||||||
|
on(event: "message", listener: (data: MessageData) => void): this
|
||||||
|
|
||||||
|
once(event: "open", listener: () => void): this
|
||||||
|
once(event: "close", listener: () => void): this
|
||||||
|
once(event: "error", listener: (error: Error) => void): this
|
||||||
|
|
||||||
|
off(event: "open", listener: () => void): this
|
||||||
|
off(event: "close", listener: () => void): this
|
||||||
|
off(event: "error", listener: (error: Error) => void): this
|
||||||
|
off(event: "message", listener: (data: MessageData) => void): this
|
||||||
|
|
||||||
|
send(data: string): void
|
||||||
|
close(): void
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user