mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
removed dependency on openapi type client and status
This commit is contained in:
@@ -1,23 +1,39 @@
|
||||
import { status } from './api';
|
||||
import type { Client } from './api/client';
|
||||
|
||||
export interface CheckServerStatusOptions {
|
||||
onEvent?: (name: string, details?: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
export interface CheckBackendStatusParams {
|
||||
baseUrl: string;
|
||||
serverSecret: string;
|
||||
fetch: typeof globalThis.fetch;
|
||||
errorLog?: string[];
|
||||
options?: CheckServerStatusOptions;
|
||||
}
|
||||
|
||||
export const isFatalError = (line: string): boolean => {
|
||||
const fatalPatterns = [/panicked at/, /RUST_BACKTRACE/, /fatal error/i];
|
||||
return fatalPatterns.some((pattern) => pattern.test(line));
|
||||
};
|
||||
|
||||
export const checkServerStatus = async (
|
||||
client: Client,
|
||||
errorLog: string[],
|
||||
options: CheckServerStatusOptions = {}
|
||||
): Promise<boolean> => {
|
||||
const statusUrlFromBase = (baseUrl: string): string => {
|
||||
const url = new URL(baseUrl);
|
||||
url.pathname = `${url.pathname.replace(/\/+$/, '')}/status`;
|
||||
url.search = '';
|
||||
url.hash = '';
|
||||
return url.toString();
|
||||
};
|
||||
|
||||
export const checkBackendStatus = async ({
|
||||
baseUrl,
|
||||
serverSecret,
|
||||
fetch,
|
||||
errorLog = [],
|
||||
options = {},
|
||||
}: CheckBackendStatusParams): Promise<boolean> => {
|
||||
const timeout = 30000;
|
||||
const interval = 100;
|
||||
const maxAttempts = Math.ceil(timeout / interval);
|
||||
const statusUrl = statusUrlFromBase(baseUrl);
|
||||
options.onEvent?.('healthcheck_start', { timeoutMs: timeout, intervalMs: interval });
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
@@ -27,12 +43,20 @@ export const checkServerStatus = async (
|
||||
}
|
||||
|
||||
try {
|
||||
await status({ client, throwOnError: true });
|
||||
options.onEvent?.('healthcheck_success', { attempt });
|
||||
return true;
|
||||
const response = await fetch(statusUrl, {
|
||||
headers: {
|
||||
'X-Secret-Key': serverSecret,
|
||||
},
|
||||
});
|
||||
if (response.ok) {
|
||||
options.onEvent?.('healthcheck_success', { attempt });
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||
// Retry until the backend is ready or the timeout expires.
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||
}
|
||||
|
||||
options.onEvent?.('healthcheck_timeout', { timeoutMs: timeout });
|
||||
|
||||
@@ -4,6 +4,7 @@ import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { createServer } from 'net';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import { status } from './api';
|
||||
import { Client, createClient, createConfig } from './api/client';
|
||||
import {
|
||||
appendTail,
|
||||
@@ -11,7 +12,8 @@ import {
|
||||
type StartupDiagnostics,
|
||||
} from './startupDiagnostics';
|
||||
import { isFatalError } from './backendStatus';
|
||||
export { checkServerStatus, isFatalError, type CheckServerStatusOptions } from './backendStatus';
|
||||
export { isFatalError, type CheckServerStatusOptions } from './backendStatus';
|
||||
import type { CheckServerStatusOptions } from './backendStatus';
|
||||
|
||||
export interface Logger {
|
||||
info: (...args: unknown[]) => void;
|
||||
@@ -36,6 +38,35 @@ export const findAvailablePort = (): Promise<number> => {
|
||||
});
|
||||
};
|
||||
|
||||
export const checkServerStatus = async (
|
||||
client: Client,
|
||||
errorLog: string[],
|
||||
options: CheckServerStatusOptions = {}
|
||||
): Promise<boolean> => {
|
||||
const timeout = 30000;
|
||||
const interval = 100;
|
||||
const maxAttempts = Math.ceil(timeout / interval);
|
||||
options.onEvent?.('healthcheck_start', { timeoutMs: timeout, intervalMs: interval });
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
if (errorLog.some(isFatalError)) {
|
||||
options.onEvent?.('healthcheck_fatal_error', { attempt });
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await status({ client, throwOnError: true });
|
||||
options.onEvent?.('healthcheck_success', { attempt });
|
||||
return true;
|
||||
} catch {
|
||||
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||
}
|
||||
}
|
||||
|
||||
options.onEvent?.('healthcheck_timeout', { timeoutMs: timeout });
|
||||
return false;
|
||||
};
|
||||
|
||||
export interface FindBinaryOptions {
|
||||
isPackaged?: boolean;
|
||||
resourcesPath?: string;
|
||||
|
||||
+6
-19
@@ -25,10 +25,9 @@ import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { execFileSync, spawn, execFile } from 'child_process';
|
||||
import 'dotenv/config';
|
||||
import { checkServerStatus } from './backendStatus';
|
||||
import { checkBackendStatus } from './backendStatus';
|
||||
import { startGooseServe } from './gooseServe';
|
||||
import { GooseServeLeaseRegistry, type GooseServeLease } from './gooseServeLeaseRegistry';
|
||||
import { createClient, createConfig } from './api/client';
|
||||
import { acpWebSocketUrlFromHttpBase, normalizeAcpHttpBaseUrl } from './acp/url';
|
||||
import { expandTilde } from './utils/pathUtils';
|
||||
import log from './utils/logger';
|
||||
@@ -51,7 +50,6 @@ import {
|
||||
} from './utils/autoUpdater';
|
||||
import { UPDATES_ENABLED } from './updates';
|
||||
import './utils/recipeHash';
|
||||
import { Client } from './api/client';
|
||||
import type { GooseApp } from './types/apps';
|
||||
import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer';
|
||||
import { BLOCKED_PROTOCOLS, WEB_PROTOCOLS } from './utils/urlSecurity';
|
||||
@@ -918,18 +916,6 @@ const getExternalBackendForCsp = (settings: Settings) => {
|
||||
};
|
||||
};
|
||||
|
||||
const createMainProcessBackendClient = (baseUrl: string, serverSecret: string): Client =>
|
||||
createClient(
|
||||
createConfig({
|
||||
baseUrl,
|
||||
fetch: net.fetch as unknown as typeof globalThis.fetch,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': serverSecret,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
let appConfig = {
|
||||
GOOSE_DEFAULT_PROVIDER: defaultProvider,
|
||||
GOOSE_DEFAULT_MODEL: defaultModel,
|
||||
@@ -1045,10 +1031,11 @@ const createChat = async (
|
||||
? normalizeFingerprint(externalBackend.certFingerprint)
|
||||
: null;
|
||||
|
||||
const externalBackendReady = await checkServerStatus(
|
||||
createMainProcessBackendClient(externalBaseUrl, serverSecret),
|
||||
[]
|
||||
);
|
||||
const externalBackendReady = await checkBackendStatus({
|
||||
baseUrl: externalBaseUrl,
|
||||
serverSecret,
|
||||
fetch: net.fetch as unknown as typeof globalThis.fetch,
|
||||
});
|
||||
if (!externalBackendReady) {
|
||||
const canDisableExternalBackend = externalBackend.source === 'settings';
|
||||
const response = dialog.showMessageBoxSync({
|
||||
|
||||
Reference in New Issue
Block a user