Skip to content

Runtime issues: monitorServerLogs() hangs, and appData is undefined in layout (likely due to SvelteKit plugin bug) #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
AmesianX opened this issue Apr 4, 2025 · 0 comments

Comments

@AmesianX
Copy link

AmesianX commented Apr 4, 2025

The monitorServerLogs function has a bug that causes it to hang without returning a value.
After modifying the source code as shown below, the application initially works correctly, but then it halts again, stating that the appData variable is undefined in the layout. Accessing the app directly through the browser works as expected, so this appears to be a serious issue with the SvelteKit plugin.

src\utils\index.ts

/**
 * Spawn the Open-WebUI server process.
 */
export async function startServer(
	installationPath?: string,
	expose = false,
	port = 8080
): Promise<string> {
	installationPath = path.normalize(installationPath || getBundledPythonInstallationPath());

	if (!(await validateInstallation(installationPath))) {
		console.error('Failed to validate installation');
		logEmitter.emit('log', 'Failed to validate installation'); // Emit log
		return;
	}

	try {
		const bundledPythonPath = getBundledPythonPath();

		// Execute the Python binary to print the version
		const pythonVersion = execFileSync(bundledPythonPath, ['--version'], {
			encoding: 'utf-8'
		});
		console.log('Installed Python Version:', pythonVersion.trim());
		logEmitter.emit('log', `Installed Python Version: ${pythonVersion.trim()}`); // Emit log
	} catch (error) {
		log.error('Failed to execute Python binary', error);
	}

	const host = expose ? '0.0.0.0' : '127.0.0.1';

	// Windows HATES Typer-CLI used to create the CLI for Open-WebUI
	// So we have to manually create the command to start the server
	let startCommand =
		process.platform === 'win32'
			? `"${installationPath}\\Scripts\\activate.bat" && uvicorn open_webui.main:app --host "${host}" --forwarded-allow-ips '*'`
			: `source "${installationPath}/bin/activate" && open-webui serve --host "${host}"`;

	if (process.platform === 'win32') {
		process.env.FROM_INIT_PY = 'true';
	}

	// Set environment variables in a platform-agnostic way
	process.env.DATA_DIR = path.join(app.getPath('userData'), 'data');
	process.env.WEBUI_SECRET_KEY = getSecretKey();

	port = port || 8080;
	while (await portInUse(port)) {
		port++;
	}

	startCommand += ` --port ${port}`;

	console.log('Starting Open-WebUI server...', startCommand);
	logEmitter.emit('log', `${startCommand}`); // Emit log
	logEmitter.emit('log', 'Starting Open-WebUI server...'); // Emit log

	const childProcess = spawn(startCommand, {
		shell: true,
		detached: process.platform !== 'win32', // Detach the child process on Unix-like platforms
		stdio: ['ignore', 'pipe', 'pipe'] // Let us capture logs via stdout/stderr
	});

	let detectedURL: string | null = null;

	detectedURL = 'http://' + host + ':' + port;

	console.log(`Server is now running at ${detectedURL}`);
	logEmitter.emit('log', `Server is now running at ${detectedURL}`); // Emit server URL log
	return detectedURL; // Return the detected URL
}

src\main.ts

import {
	app,
	nativeImage,
	desktopCapturer,
	session,
	clipboard,
	shell,
	Tray,
	Menu,
	MenuItem,
	BrowserWindow,
	globalShortcut,
	Notification,
	ipcMain,
	ipcRenderer
} from 'electron';
// import 'net'
import net from 'net';
import path from 'path';
import started from 'electron-squirrel-startup';
	const startServerHandler = async () => {
		SERVER_STATUS = 'starting';
		mainWindow.webContents.send('main:data', {
			type: 'server:status',
			data: SERVER_STATUS
		});
		updateTrayMenu('Open WebUI: Starting...', null);

		try {
			SERVER_URL = await startServer();
			// SERVER_URL = 'http://localhost:5050';

			SERVER_STATUS = 'started';
			mainWindow.webContents.send('main:data', {
				type: 'server:status',
				data: SERVER_STATUS
			});

			function waitForServerReady(port: number, host = '127.0.0.1', timeout = 10000): Promise<void>
			{
				const start = Date.now();
			    return new Promise((resolve, reject) => {
			        const tryConnect = () => {
			            const socket = new net.Socket();
			            socket
			                .setTimeout(1000)
			                .once('connect', () => {
			                    socket.destroy();
			                    resolve();
			                })
			                .once('timeout', () => {
			                    socket.destroy();
			                    if (Date.now() - start > timeout) reject(new Error('Timeout'));
			                    else setTimeout(tryConnect, 300);
			                })
			                .once('error', () => {
			                    socket.destroy();
			                    if (Date.now() - start > timeout) reject(new Error('Timeout'));
			                    else setTimeout(tryConnect, 300);
			                })
			                .connect(port, host);
			        };

			        tryConnect();
			    });
			}

            // 사용 예:
            await waitForServerReady(8080);

			mainWindow.loadURL(SERVER_URL);
			mainWindow;

			const urlObj = new URL(SERVER_URL);
			const port = urlObj.port || '8080'; // Fallback to port 8080 if not provided
			updateTrayMenu(`Open WebUI: Running on port ${port}`, SERVER_URL); // Update tray menu with running status
		} catch (error) {
			console.error('Failed to start server:', error);
			SERVER_STATUS = 'failed';
			mainWindow.webContents.send('main:data', {
				type: 'server:status',
				data: SERVER_STATUS
			});

			mainWindow.webContents.send('main:log', `Failed to start server: ${error}`);
			updateTrayMenu('Open WebUI: Failed to Start', null); // Update tray menu with failure status
		}
	};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant