Skip to content

Commit

Permalink
Toggle auto-update and restart app for Electron settings. (#147)
Browse files Browse the repository at this point in the history
* Restart app on change.

* Remove auto update IPC call.

* Add issue for hack.

* Use https git url instead of SSH for CI.
  • Loading branch information
robinjhuang authored Oct 30, 2024
1 parent 44263ae commit f76ffb9
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 99 deletions.
1 change: 0 additions & 1 deletion assets/ComfyUI_electron_adapter/__init__.py

This file was deleted.

39 changes: 0 additions & 39 deletions assets/ComfyUI_electron_adapter/js/electronAdapter.js

This file was deleted.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
"format:fix": "prettier --write .",
"prepare": "husky",
"make": "yarn run vite:compile && electron-builder build --config=builder-debug.config.ts",
"make:assets:amd": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --amd --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && mkdir -p ComfyUI/user/default",
"make:assets:cpu": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --cpu --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && node ../scripts/env.mjs && mkdir -p ComfyUI/user/default",
"make:assets:nvidia": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --nvidia --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && mkdir -p ComfyUI/user/default",
"make:assets:macos": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --m-series --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && mkdir -p ComfyUI/user/default",
"make:assets:amd": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --amd --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && yarn run clone-settings-extension",
"make:assets:cpu": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --cpu --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && node ../scripts/env.mjs && yarn run clone-settings-extension",
"make:assets:nvidia": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --nvidia --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && yarn run clone-settings-extension",
"make:assets:macos": "cd assets && comfy-cli --skip-prompt --here install --fast-deps --m-series --manager-url https://github.com/Comfy-Org/manager-core && comfy-cli --here standalone && yarn run clone-settings-extension",
"vite:compile": "vite build --config vite.renderer.config.ts && vite build --config vite.main.config.ts && vite build --config vite.preload.config.ts ",
"notarize": "node debug/notarize.js",
"clone-settings-extension": "git clone https://github.com/Comfy-Org/DesktopSettingsExtension.git ComfyUI/custom_nodes/DesktopSettingsExtension",
"package": "yarn run vite:compile && todesktop build --code-sign=false --async",
"publish": "yarn run vite:compile && todesktop build --async",
"sign": "node debug/sign.js",
Expand Down
60 changes: 60 additions & 0 deletions src/config/comfySettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as fs from 'fs';
import * as path from 'path';
import log from 'electron-log/main';

interface ComfySettingsData {
'Comfy-Desktop.AutoUpdate'?: boolean;
'Comfy-Desktop.SendCrashStatistics'?: boolean;
[key: string]: any;
}

/**
* ComfySettings is a class that loads settings from the comfy.settings.json file.
*/
export class ComfySettings {
private filePath: string;
private settings: ComfySettingsData;

constructor(settingsPath: string) {
this.filePath = path.join(settingsPath, 'user', 'default', 'comfy.settings.json');
this.settings = this.loadSettings();
}

private loadSettings(): ComfySettingsData {
if (!fs.existsSync(this.filePath)) {
throw new Error(`Settings file ${this.filePath} does not exist`);
}
try {
const fileContent = fs.readFileSync(this.filePath, 'utf-8');
return JSON.parse(fileContent);
} catch (error) {
log.error(`Failed to load settings from ${this.filePath}:`, error);
return {};
}
}

get autoUpdate(): boolean {
return this.settings['Comfy-Desktop.AutoUpdate'] ?? true;
}

get sendCrashStatistics(): boolean {
return this.settings['Comfy-Desktop.SendCrashStatistics'] ?? true;
}

public reload(): void {
this.settings = this.loadSettings();
}

public getAllDesktopSettings(): Record<string, any> {
return Object.entries(this.settings)
.filter(([key]) => key.startsWith('Comfy-Desktop.'))
.reduce(
(acc, [key, value]) => {
const settingName = key.replace('Comfy-Desktop.', '');
acc[settingName] = value;
return acc;
},
{} as Record<string, any>
);
}
}
112 changes: 61 additions & 51 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import todesktop from '@todesktop/runtime';
import { PythonEnvironment } from './pythonEnvironment';
import { DownloadManager } from './models/DownloadManager';
import { getModelsDirectory } from './utils';
import { ComfySettings } from './config/comfySettings';

let comfyServerProcess: ChildProcess | null = null;
let isRestarting: boolean = false; // Prevents double restarts TODO(robinhuang): Remove this once we have a better way to handle restarts. https://github.com/Comfy-Org/electron/issues/149
const host = '127.0.0.1';
let port = 8188;
let mainWindow: BrowserWindow | null = null;
Expand All @@ -37,9 +39,12 @@ let downloadManager: DownloadManager;

log.initialize();

const comfySettings = new ComfySettings(app.getPath('documents'));

todesktop.init({
customLogger: log,
updateReadyAction: { showInstallAndRestartPrompt: 'always', showNotification: 'always' },
autoUpdater: comfySettings.autoUpdate,
});

// Register the quit handlers regardless of single instance lock and before squirrel startup events.
Expand Down Expand Up @@ -93,21 +98,10 @@ if (!gotTheLock) {
});

app.isPackaged &&
comfySettings.sendCrashStatistics &&
Sentry.init({
dsn: SENTRY_URL_ENDPOINT,
autoSessionTracking: false,

/* //WIP gather and send log from main
beforeSend(event, hint) {
hint.attachments = [
{
filename: 'main.log',
attachmentType: 'event.attachment',
data: readLogMain(),
},
];
return event;
}, */
integrations: [
Sentry.childProcessIntegration({
breadcrumbs: ['abnormal-exit', 'killed', 'crashed', 'launch-failed', 'oom', 'integrity-failure'],
Expand Down Expand Up @@ -205,7 +199,6 @@ if (!gotTheLock) {
const pythonEnvironment = new PythonEnvironment(pythonInstallPath, appResourcesPath, spawnPythonAsync);
await pythonEnvironment.setup();

installElectronAdapter(appResourcesPath);
SetupTray(
mainWindow,
basePath,
Expand All @@ -224,10 +217,17 @@ if (!gotTheLock) {
sendProgressUpdate(COMFY_ERROR_MESSAGE);
}

ipcMain.on(IPC_CHANNELS.RESTART_APP, () => {
log.info('Received restart app message!');
restartApp();
});
ipcMain.on(
IPC_CHANNELS.RESTART_APP,
(event, { customMessage, delay }: { customMessage?: string; delay?: number }) => {
log.info('Received restart app message!');
if (customMessage) {
restartApp({ customMessage, delay });
} else {
restartApp({ delay });
}
}
);

ipcMain.handle(IPC_CHANNELS.GET_COMFYUI_URL, () => {
return `http://${host}:${port}`;
Expand Down Expand Up @@ -258,10 +258,50 @@ async function loadRendererIntoMainWindow(): Promise<void> {
}
}

function restartApp() {
log.info('Restarting app');
app.relaunch();
app.quit();
function restartApp({ customMessage, delay }: { customMessage?: string; delay?: number } = {}): void {
function relaunchApplication(delay?: number) {
isRestarting = true;
if (delay) {
log.info('Relaunching application in ', delay, 'ms');
setTimeout(() => {
app.relaunch();
app.quit();
}, delay);
} else {
app.relaunch();
app.quit();
}
}

log.info('Attempting to restart app with custom message: ', customMessage);
if (isRestarting) {
log.info('Already quitting, skipping restart');
return;
}

if (!customMessage) {
log.info('Skipping confirmation, restarting immediately');
return relaunchApplication(delay);
}

dialog
.showMessageBox({
type: 'question',
buttons: ['Yes', 'No'],
defaultId: 0,
title: 'Restart ComfyUI',
message: customMessage || 'Are you sure you want to restart ComfyUI?',
detail: 'The application will close and restart automatically.',
})
.then(({ response }) => {
if (response === 0) {
// "Yes" was clicked
log.info('User confirmed restart');
relaunchApplication(delay);
} else {
log.info('User cancelled restart');
}
});
}

function buildMenu(): void {
Expand Down Expand Up @@ -911,33 +951,3 @@ const rotateLogFiles = (logDir: string, baseName: string) => {
fs.renameSync(currentLogPath, newLogPath);
}
};

/**
* Install the Electron adapter into the ComfyUI custom_nodes directory.
* @param appResourcesPath The path to the app resources.
*/
function installElectronAdapter(appResourcesPath: string) {
const electronAdapterPath = path.join(appResourcesPath, 'ComfyUI_electron_adapter');
const comfyUIPath = path.join(appResourcesPath, 'ComfyUI');
const customNodesPath = path.join(comfyUIPath, 'custom_nodes');
const adapterDestPath = path.join(customNodesPath, 'ComfyUI_electron_adapter');

try {
// Ensure the custom_nodes directory exists
if (!fs.existsSync(customNodesPath)) {
fs.mkdirSync(customNodesPath, { recursive: true });
}

// Remove existing adapter folder if it exists
if (fs.existsSync(adapterDestPath)) {
fs.rmSync(adapterDestPath, { recursive: true, force: true });
}

// Copy the adapter folder
fs.cpSync(electronAdapterPath, adapterDestPath, { recursive: true });

log.info('Electron adapter installed successfully');
} catch (error) {
log.error('Failed to install Electron adapter:', error);
}
}
8 changes: 4 additions & 4 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ElectronAPI {
onDefaultInstallLocation: (callback: (location: string) => void) => void;
onComfyUIReady: (callback: (port: number) => void) => void;
sendReady: () => void;
restartApp: () => void;
restartApp: (customMessage?: string, delay?: number) => void;
onOpenDevTools: (callback: () => void) => void;
isPackaged: () => Promise<boolean>;
openDialog: (options: Electron.OpenDialogOptions) => Promise<string[] | undefined>;
Expand Down Expand Up @@ -73,9 +73,9 @@ const electronAPI: ElectronAPI = {
isPackaged: () => {
return ipcRenderer.invoke(IPC_CHANNELS.IS_PACKAGED);
}, //Emulates app.ispackaged in renderer
restartApp: (): void => {
console.log('Sending restarting app message to main process');
ipcRenderer.send(IPC_CHANNELS.RESTART_APP);
restartApp: (customMessage?: string, delay?: number): void => {
console.log('Sending restarting app message to main process with custom message: ', customMessage);
ipcRenderer.send(IPC_CHANNELS.RESTART_APP, { customMessage, delay });
},
onOpenDevTools: (callback: () => void) => {
ipcRenderer.on(IPC_CHANNELS.OPEN_DEVTOOLS, () => callback());
Expand Down

0 comments on commit f76ffb9

Please sign in to comment.