Skip to content

Commit

Permalink
first pass
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelneale committed Nov 27, 2024
1 parent c9c3a0d commit 2fb3cdb
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 85 deletions.
72 changes: 46 additions & 26 deletions ui/desktop/src/goosed.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import path from 'node:path';
import { spawn } from 'child_process';
import { execSync, spawn } from 'child_process';
import { existsSync } from 'fs';
import log from './utils/logger';
import os from 'node:os';
import { createServer } from 'net';
import { loadZshEnv } from './utils/loadEnv';

// Start the goosed binary
export const start = (app) => {
// In development, the binary is in src/bin
// In production, it will be in the resources/bin directory

// Find an available port to start goosed on
export const findAvailablePort = (): Promise<number> => {
return new Promise((resolve, reject) => {
const server = createServer();


server.listen(0, '127.0.0.1', () => {
const { port } = server.address() as { port: number };
server.close(() => {
log.info(`Found available port: ${port}`);
resolve(port);
});
});
});
};

// Goose process manager. Take in the app, port, and directory to start goosed in.
export const startGoosed = async (app, dir=null): Promise<number> => {
// In will use this later to determine if we should start process
const isDev = process.env.NODE_ENV === 'development';

let goosedPath: string;

if (isDev) {
Expand All @@ -18,59 +37,60 @@ export const start = (app) => {
// In production, use the path relative to the app resources
goosedPath = path.join(process.resourcesPath, 'bin', process.platform === 'win32' ? 'goosed.exe' : 'goosed');
}
const port = await findAvailablePort();

log.info(`Starting goosed from: ${goosedPath}`);
// in case we want it
//const isPackaged = app.isPackaged;

// Check if the binary exists
if (!existsSync(goosedPath)) {
log.error(`goosed binary not found at path: ${goosedPath}`);
return;
}

// we default to running goosed in home dir - if not specified
const homeDir = os.homedir();

// Optional: Ensure the home directory exists (it should, but for safety)
if (!existsSync(homeDir)) {
log.error(`Home directory does not exist: ${homeDir}`);
return;
if (!dir) {
dir = homeDir;
}

console.log("Starting goosed in: ", homeDir);

log.info(`Starting goosed from: ${goosedPath} on port ${port} in dir ${dir}` );
// Define additional environment variables
const additionalEnv = {
// Set HOME for UNIX-like systems
HOME: homeDir,
// Set USERPROFILE for Windows
USERPROFILE: homeDir,

// start with the port specified
GOOSE_SERVER__PORT: port,
};

// Merge parent environment with additional environment variables
const env = { ...process.env, ...additionalEnv };

// Spawn the goosed process with the user's home directory as cwd
const goosedProcess = spawn(goosedPath, [], { cwd: homeDir, env: env });

const goosedProcess = spawn(goosedPath, [], { cwd: dir, env: env });

goosedProcess.stdout.on('data', (data) => {
log.info(`goosed stdout: ${data.toString()}`);
log.info(`goosed stdout for port ${port} and dir ${dir}: ${data.toString()}`);
});

goosedProcess.stderr.on('data', (data) => {
log.error(`goosed stderr: ${data.toString()}`);
log.error(`goosed stderr for port ${port} and dir ${dir}: ${data.toString()}`);
});

goosedProcess.on('close', (code) => {
log.info(`goosed process exited with code ${code}`);
log.info(`goosed process exited with code ${code} for port ${port} and dir ${dir}`);
});

goosedProcess.on('error', (err) => {
log.error('Failed to start goosed:', err);
log.error(`Failed to start goosed on port ${port} and dir ${dir}`, err);
});

// Ensure goosed is terminated when the app quits
// TODO will need to do it at tab level next
app.on('will-quit', () => {
log.info('App quitting, terminating goosed server');
goosedProcess.kill();
});
};

return port;
};


33 changes: 10 additions & 23 deletions ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dotenv/config';
import { loadZshEnv } from './utils/loadEnv';
import { app, BrowserWindow, Tray, Menu, globalShortcut, ipcMain, Notification } from 'electron';
import path from 'node:path';
import { start as startGoosed } from './goosed';
import { findAvailablePort, startGoosed } from './goosed';
import started from "electron-squirrel-startup";
import log from './utils/logger';
import { getPort } from './utils/portUtils';
Expand Down Expand Up @@ -30,9 +30,9 @@ const checkApiCredentials = () => {
};

let appConfig = {
GOOSE_SERVER__PORT: 3000,
apiCredsMissing: !checkApiCredentials(),
GOOSE_API_HOST: 'http://127.0.0.1',
apiCredsMissing: !checkApiCredentials()
GOOSE_SERVER__PORT: 0,
};

const createLauncher = () => {
Expand Down Expand Up @@ -81,7 +81,9 @@ const createLauncher = () => {
let windowCounter = 0;
const windowMap = new Map<number, BrowserWindow>();

const createChat = (query?: string) => {
const createChat = async (app, query?: string) => {

const port = await startGoosed(app);
const mainWindow = new BrowserWindow({
titleBarStyle: 'hidden',
trafficLightPosition: { x: 16, y: 18 },
Expand All @@ -94,7 +96,7 @@ const createChat = (query?: string) => {
icon: path.join(__dirname, '../images/icon'),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
additionalArguments: [JSON.stringify(appConfig)],
additionalArguments: [JSON.stringify({ ...appConfig, GOOSE_SERVER__PORT: port })],
},
});

Expand Down Expand Up @@ -195,36 +197,21 @@ const showWindow = () => {

app.whenReady().then(async () => {
// Load zsh environment variables in production mode only
const isProduction = app.isPackaged;
loadZshEnv(isProduction);

// Get the server startup configuration
const shouldStartServer = (process.env.VITE_START_EMBEDDED_SERVER || 'yes').toLowerCase() === 'yes';

if (shouldStartServer) {
log.info('Starting embedded goosed server');
const port = await getPort();
process.env.GOOSE_SERVER__PORT = port.toString();
appConfig = { ...appConfig, GOOSE_SERVER__PORT: process.env.GOOSE_SERVER__PORT };
startGoosed(app);
} else {
log.info('Skipping embedded server startup (disabled by configuration)');
}

createTray();
createChat();
createChat(app);

// Show launcher input on key combo
globalShortcut.register('Control+Alt+Command+G', createLauncher);

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createChat();
createChat(app);
}
});

ipcMain.on('create-chat-window', (_, query) => {
createChat(query);
createChat(app, query);
});

ipcMain.on('notify', (event, data) => {
Expand Down
2 changes: 0 additions & 2 deletions ui/desktop/src/preload.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron')

let windowId = null;


const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}');

Expand Down
34 changes: 0 additions & 34 deletions ui/desktop/src/utils/portUtils.ts

This file was deleted.

0 comments on commit 2fb3cdb

Please sign in to comment.