perf: Health snapshot changes
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
getDesktopUpdateState,
|
||||
handleDesktopSettingsChanged,
|
||||
restartToApplyUpdate,
|
||||
readDesktopUpdateServerHealth,
|
||||
type DesktopUpdateServerContext
|
||||
} from '../update/desktop-updater';
|
||||
import { consumePendingDeepLink } from '../app/deep-links';
|
||||
@@ -317,6 +318,10 @@ export function setupSystemHandlers(): void {
|
||||
|
||||
ipcMain.handle('get-auto-update-state', () => getDesktopUpdateState());
|
||||
|
||||
ipcMain.handle('get-auto-update-server-health', async (_event, serverUrl: string) => {
|
||||
return await readDesktopUpdateServerHealth(serverUrl);
|
||||
});
|
||||
|
||||
ipcMain.handle('configure-auto-update-context', async (_event, context: Partial<DesktopUpdateServerContext>) => {
|
||||
return await configureDesktopUpdaterContext(context);
|
||||
});
|
||||
|
||||
@@ -50,6 +50,12 @@ export interface DesktopUpdateServerContext {
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateServerHealthSnapshot {
|
||||
manifestUrl: string | null;
|
||||
serverVersion: string | null;
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateState {
|
||||
autoUpdateMode: 'auto' | 'off' | 'version';
|
||||
availableVersions: string[];
|
||||
@@ -127,6 +133,7 @@ export interface ElectronAPI {
|
||||
restartRequired: boolean;
|
||||
}>;
|
||||
getAutoUpdateState: () => Promise<DesktopUpdateState>;
|
||||
getAutoUpdateServerHealth: (serverUrl: string) => Promise<DesktopUpdateServerHealthSnapshot>;
|
||||
configureAutoUpdateContext: (context: Partial<DesktopUpdateServerContext>) => Promise<DesktopUpdateState>;
|
||||
checkForAppUpdates: () => Promise<DesktopUpdateState>;
|
||||
restartToApplyUpdate: () => Promise<boolean>;
|
||||
@@ -207,6 +214,7 @@ const electronAPI: ElectronAPI = {
|
||||
consumePendingDeepLink: () => ipcRenderer.invoke('consume-pending-deep-link'),
|
||||
getDesktopSettings: () => ipcRenderer.invoke('get-desktop-settings'),
|
||||
getAutoUpdateState: () => ipcRenderer.invoke('get-auto-update-state'),
|
||||
getAutoUpdateServerHealth: (serverUrl) => ipcRenderer.invoke('get-auto-update-server-health', serverUrl),
|
||||
configureAutoUpdateContext: (context) => ipcRenderer.invoke('configure-auto-update-context', context),
|
||||
checkForAppUpdates: () => ipcRenderer.invoke('check-for-app-updates'),
|
||||
restartToApplyUpdate: () => ipcRenderer.invoke('restart-to-apply-update'),
|
||||
|
||||
@@ -18,6 +18,11 @@ interface ReleaseManifestEntry {
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface ServerHealthResponse {
|
||||
releaseManifestUrl?: string;
|
||||
serverVersion?: string;
|
||||
}
|
||||
|
||||
interface UpdateVersionInfo {
|
||||
version: string;
|
||||
}
|
||||
@@ -53,6 +58,12 @@ export interface DesktopUpdateServerContext {
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateServerHealthSnapshot {
|
||||
manifestUrl: string | null;
|
||||
serverVersion: string | null;
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateState {
|
||||
autoUpdateMode: AutoUpdateMode;
|
||||
availableVersions: string[];
|
||||
@@ -78,6 +89,8 @@ export interface DesktopUpdateState {
|
||||
|
||||
export const AUTO_UPDATE_STATE_CHANGED_CHANNEL = 'auto-update-state-changed';
|
||||
|
||||
const SERVER_HEALTH_TIMEOUT_MS = 5_000;
|
||||
|
||||
let currentCheckPromise: Promise<void> | null = null;
|
||||
let currentContext: DesktopUpdateServerContext = {
|
||||
manifestUrls: [],
|
||||
@@ -388,6 +401,47 @@ async function loadReleaseManifest(manifestUrl: string): Promise<ReleaseManifest
|
||||
return parseReleaseManifest(payload);
|
||||
}
|
||||
|
||||
function createUnavailableServerHealthSnapshot(): DesktopUpdateServerHealthSnapshot {
|
||||
return {
|
||||
manifestUrl: null,
|
||||
serverVersion: null,
|
||||
serverVersionStatus: 'unavailable'
|
||||
};
|
||||
}
|
||||
|
||||
async function loadServerHealth(serverUrl: string): Promise<DesktopUpdateServerHealthSnapshot> {
|
||||
const sanitizedServerUrl = sanitizeHttpUrl(serverUrl);
|
||||
|
||||
if (!sanitizedServerUrl) {
|
||||
return createUnavailableServerHealthSnapshot();
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await net.fetch(`${sanitizedServerUrl}/api/health`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
},
|
||||
signal: AbortSignal.timeout(SERVER_HEALTH_TIMEOUT_MS)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return createUnavailableServerHealthSnapshot();
|
||||
}
|
||||
|
||||
const payload = await response.json() as ServerHealthResponse;
|
||||
const serverVersion = normalizeSemanticVersion(payload.serverVersion);
|
||||
|
||||
return {
|
||||
manifestUrl: sanitizeHttpUrl(payload.releaseManifestUrl),
|
||||
serverVersion,
|
||||
serverVersionStatus: serverVersion ? 'reported' : 'missing'
|
||||
};
|
||||
} catch {
|
||||
return createUnavailableServerHealthSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
function formatManifestLoadErrors(errors: string[]): string {
|
||||
if (errors.length === 0) {
|
||||
return 'No valid release manifest could be loaded.';
|
||||
@@ -724,6 +778,12 @@ export async function checkForDesktopUpdates(): Promise<DesktopUpdateState> {
|
||||
return desktopUpdateState;
|
||||
}
|
||||
|
||||
export async function readDesktopUpdateServerHealth(
|
||||
serverUrl: string
|
||||
): Promise<DesktopUpdateServerHealthSnapshot> {
|
||||
return await loadServerHealth(serverUrl);
|
||||
}
|
||||
|
||||
export function restartToApplyUpdate(): boolean {
|
||||
if (!desktopUpdateState.restartRequired) {
|
||||
return false;
|
||||
|
||||
@@ -57,6 +57,12 @@ export interface DesktopUpdateServerContext {
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateServerHealthSnapshot {
|
||||
manifestUrl: string | null;
|
||||
serverVersion: string | null;
|
||||
serverVersionStatus: DesktopUpdateServerVersionStatus;
|
||||
}
|
||||
|
||||
export interface DesktopUpdateState {
|
||||
autoUpdateMode: AutoUpdateMode;
|
||||
availableVersions: string[];
|
||||
@@ -127,6 +133,7 @@ export interface ElectronApi {
|
||||
consumePendingDeepLink: () => Promise<string | null>;
|
||||
getDesktopSettings: () => Promise<DesktopSettingsSnapshot>;
|
||||
getAutoUpdateState: () => Promise<DesktopUpdateState>;
|
||||
getAutoUpdateServerHealth: (serverUrl: string) => Promise<DesktopUpdateServerHealthSnapshot>;
|
||||
configureAutoUpdateContext: (context: Partial<DesktopUpdateServerContext>) => Promise<DesktopUpdateState>;
|
||||
checkForAppUpdates: () => Promise<DesktopUpdateState>;
|
||||
restartToApplyUpdate: () => Promise<boolean>;
|
||||
|
||||
@@ -10,17 +10,13 @@ import { type ServerEndpoint, ServerDirectoryFacade } from '../../domains/server
|
||||
import {
|
||||
type AutoUpdateMode,
|
||||
type DesktopUpdateServerContext,
|
||||
type DesktopUpdateServerHealthSnapshot,
|
||||
type DesktopUpdateServerVersionStatus,
|
||||
type DesktopUpdateState,
|
||||
type ElectronApi
|
||||
} from '../platform/electron/electron-api.models';
|
||||
import { ElectronBridgeService } from '../platform/electron/electron-bridge.service';
|
||||
|
||||
interface ServerHealthResponse {
|
||||
releaseManifestUrl?: string;
|
||||
serverVersion?: string;
|
||||
}
|
||||
|
||||
interface ServerHealthSnapshot {
|
||||
endpointId: string;
|
||||
manifestUrl: string | null;
|
||||
@@ -29,7 +25,6 @@ interface ServerHealthSnapshot {
|
||||
}
|
||||
|
||||
const SERVER_CONTEXT_REFRESH_INTERVAL_MS = 5 * 60_000;
|
||||
const SERVER_CONTEXT_TIMEOUT_MS = 5_000;
|
||||
|
||||
function createInitialState(): DesktopUpdateState {
|
||||
return {
|
||||
@@ -292,30 +287,23 @@ export class DesktopAppUpdateService {
|
||||
|
||||
private async readServerHealth(endpoint: ServerEndpoint): Promise<ServerHealthSnapshot> {
|
||||
const sanitizedServerUrl = endpoint.url.replace(/\/+$/, '');
|
||||
const api = this.getElectronApi();
|
||||
|
||||
if (!api?.getAutoUpdateServerHealth) {
|
||||
return {
|
||||
endpointId: endpoint.id,
|
||||
manifestUrl: null,
|
||||
serverVersion: null,
|
||||
serverVersionStatus: 'unavailable'
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${sanitizedServerUrl}/api/health`, {
|
||||
method: 'GET',
|
||||
signal: AbortSignal.timeout(SERVER_CONTEXT_TIMEOUT_MS)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
endpointId: endpoint.id,
|
||||
manifestUrl: null,
|
||||
serverVersion: null,
|
||||
serverVersionStatus: 'unavailable'
|
||||
};
|
||||
}
|
||||
|
||||
const payload = await response.json() as ServerHealthResponse;
|
||||
const serverVersion = normalizeOptionalString(payload.serverVersion);
|
||||
const payload = await api.getAutoUpdateServerHealth(sanitizedServerUrl);
|
||||
|
||||
return {
|
||||
endpointId: endpoint.id,
|
||||
manifestUrl: normalizeOptionalHttpUrl(payload.releaseManifestUrl),
|
||||
serverVersion,
|
||||
serverVersionStatus: serverVersion ? 'reported' : 'missing'
|
||||
...this.normalizeHealthSnapshot(payload)
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
@@ -327,6 +315,22 @@ export class DesktopAppUpdateService {
|
||||
}
|
||||
}
|
||||
|
||||
private normalizeHealthSnapshot(
|
||||
snapshot: DesktopUpdateServerHealthSnapshot
|
||||
): Omit<ServerHealthSnapshot, 'endpointId'> {
|
||||
const serverVersion = normalizeOptionalString(snapshot.serverVersion);
|
||||
|
||||
return {
|
||||
manifestUrl: normalizeOptionalHttpUrl(snapshot.manifestUrl),
|
||||
serverVersion,
|
||||
serverVersionStatus: serverVersion
|
||||
? snapshot.serverVersionStatus
|
||||
: snapshot.serverVersionStatus === 'reported'
|
||||
? 'missing'
|
||||
: snapshot.serverVersionStatus
|
||||
};
|
||||
}
|
||||
|
||||
private async pushContext(context: Partial<DesktopUpdateServerContext>): Promise<void> {
|
||||
const api = this.getElectronApi();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user