Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/emdash-desktop/src/main/core/updates/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { EMDASH_RELEASES_URL } from '@shared/urls';
import { formatUpdaterError } from './utils';

export const updateController = createRPCController({
check: async () => {
check: async (args?: { source?: 'background' | 'manual' }) => {
try {
const result = await updateService.checkForUpdates();
const result = await updateService.checkForUpdates(args?.source ?? 'manual');
return { success: true, result: result ?? null };
} catch (error) {
return { success: false, error: formatUpdaterError(error) };
Expand Down
19 changes: 17 additions & 2 deletions apps/emdash-desktop/src/main/core/updates/update-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
const STARTUP_DELAY_MS = 30 * 1000; // 30 seconds
const INSTALL_RESTART_GUARD_TIMEOUT_MS = 2 * 60 * 1000;

type UpdateCheckSource = 'background' | 'manual';

export interface UpdateState {
status: 'idle' | 'checking' | 'available' | 'downloading' | 'downloaded' | 'installing' | 'error';
lastCheck?: Date;
Expand All @@ -50,6 +52,7 @@ class UpdateService implements IInitializable, IDisposable {
private updateState: UpdateState;
private checkTimer?: NodeJS.Timeout;
private currentCheckPromise: Promise<UpdateInfo | null> | null = null;
private currentCheckSource: UpdateCheckSource | null = null;
private initialized = false;
private active = false;
private installRequested = false;
Expand Down Expand Up @@ -126,6 +129,13 @@ class UpdateService implements IInitializable, IDisposable {
return;
}

if (this.updateState.status === 'checking' && this.currentCheckSource === 'background') {
this.updateState.status = 'idle';
this.updateState.error = undefined;
log.warn('Background update check failed; suppressing user-facing error');
return;
}
Comment thread
janburzinski marked this conversation as resolved.

const previousVersion = this.updateState.availableVersion;
const previousInfo = this.updateState.updateInfo;

Expand Down Expand Up @@ -175,12 +185,17 @@ class UpdateService implements IInitializable, IDisposable {
}, delay);
}

async checkForUpdates(): Promise<UpdateInfo | null> {
async checkForUpdates(source: UpdateCheckSource = 'background'): Promise<UpdateInfo | null> {
if (!this.active) return null;
if (this.currentCheckPromise) return this.currentCheckPromise;
if (this.currentCheckPromise) {
if (source === 'manual') this.currentCheckSource = 'manual';
return this.currentCheckPromise;
}

this.currentCheckSource = source;
this.currentCheckPromise = this._performCheck().finally(() => {
this.currentCheckPromise = null;
this.currentCheckSource = null;
this.scheduleNextCheck();
});

Expand Down
9 changes: 4 additions & 5 deletions apps/emdash-desktop/src/renderer/lib/stores/update-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export type UpdateState =
| { status: 'idle' }
| { status: 'checking' }
| { status: 'available'; info?: { version: string } }
| { status: 'not-available' }
| { status: 'downloading'; progress?: DownloadProgress }
| { status: 'downloaded' }
| { status: 'installing' }
Expand Down Expand Up @@ -89,7 +88,7 @@ export class UpdateStore {

events.on(updateNotAvailableEvent, () => {
runInAction(() => {
this.state = { status: 'not-available' };
this.state = { status: 'idle' };
});
});

Expand Down Expand Up @@ -132,18 +131,18 @@ export class UpdateStore {
});

events.on(menuCheckForUpdatesChannel, () => {
rpc.update.check().catch(() => {});
rpc.update.check({ source: 'manual' }).catch(() => {});
});

rpc.update.check().catch(() => {});
rpc.update.check({ source: 'background' }).catch(() => {});
}

async check(): Promise<void> {
runInAction(() => {
this.state = { status: 'checking' };
});
try {
const res = await rpc.update.check();
const res = await rpc.update.check({ source: 'manual' });
if (!res) {
runInAction(() => {
this.state = { status: 'error', message: 'Update API unavailable' };
Expand Down
Loading