Skip to content

Commit

Permalink
load py server on start
Browse files Browse the repository at this point in the history
  • Loading branch information
rimsila committed Oct 30, 2024
1 parent 3780077 commit 0ca9513
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 31 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ const Page = () => {
return <Button onClick={() => hello('ElectronJS')}>Hello </Button>;
};
```

## Reference and Credit

<https://github.com/dieharders/ai-text-server>
File renamed without changes.
8 changes: 6 additions & 2 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createMainWindow } from '@/main-window';
import { app, dialog, protocol } from 'electron';
import { startApi } from './start';
import { startApi, runPython } from './start';

protocol.registerSchemesAsPrivileged([
{
Expand All @@ -15,7 +15,11 @@ protocol.registerSchemesAsPrivileged([
]);

const onReady = () => {
startApi()
const usePy = true
runPython()

// startApi(usePy)
runPython()
.then(() => {
createMainWindow();
console.log('App run successfully');
Expand Down
74 changes: 46 additions & 28 deletions src/main/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ let python: Record<string, any> = {};

const appPath = path.resolve(__dirname, '..', '..', '../api');

/**
* Runs a Python script asynchronously and resolves upon successful execution.
* Uses a child process to spawn the Python interpreter and run the script.
*
* @returns {Promise<void>} A promise that resolves when the Python script is successfully executed.
*/
const apiPort = 8100;


export function runPython() {
return new Promise<void>((resolve, reject) => {
const appFile = path.join(appPath, 'main.py');
Expand All @@ -28,20 +25,20 @@ export function runPython() {
console.log(`stdout: ${data}`);
});

python.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
if (data.includes('Application startup complete.')) {
resolve();
} else {
reject(new Error(`Python error: ${data}`));
}
waitOn({
resources: [`tcp:${apiPort}`],
}).then(() => {
console.log('API is ready');
resolve();
}).catch((err) => {
console.log('API is not ready', err);
reject(err);
});

console.log('appFile', appFile);
});
}

const apiPort = 8100;

export async function killPython(pid: any = apiPort) {
// Usage with promises
Expand Down Expand Up @@ -71,14 +68,15 @@ export async function killPython(pid: any = apiPort) {
});
}

export const startApi = () => {
export const startApi = (usePy = false) => {

console.log('API is starting...', apiPort);

return new Promise<void>((resolve, reject) => {
const appFile = path.join(appPath, 'dist', 'main.exe');

isAvailablePromise({ port: apiPort }).then((apiReady) => {

waitOn({
resources: [`tcp:${apiPort}`],
}).then(() => {
Expand All @@ -90,24 +88,44 @@ export const startApi = () => {

if (apiReady) {
console.log('API is ready');

resolve();
} else {
console.log('API is not ready');
python = exec(appFile, (err, stdout, stderr) => {
if (err) {
console.error('Failed to start FastAPI server:', err);
reject(err);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
console.log(`stdout: ${stdout}`);
return
}

// for py file
if (usePy) {
console.log('Python is starting...', apiPort);

python = child_process.spawn('env\\scripts\\python.exe', ['main.py'], {
cwd: appPath,
});

python.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});

python.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
resolve();
});
return
}

// for exec file
python = exec(appFile, (err, stdout, stderr) => {

Check warning

Code scanning / CodeQL

Shell command built from environment values Medium

This shell command depends on an uncontrolled
absolute path
.
This shell command depends on an uncontrolled
absolute path
.
if (err) {
console.error('Failed to start FastAPI server:', err);
reject(err);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
console.log(`stdout: ${stdout}`);
resolve();
});


});

});
Expand Down
17 changes: 16 additions & 1 deletion src/preload/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { contextBridge, shell } from 'electron';
import { contextBridge, shell, ipcRenderer } from 'electron';
import i18nSync from './i18n-sync';

const apiKey = '$api';
Expand All @@ -7,11 +7,26 @@ const hello = (name: string) => {
return `Welcome ${name}`;
};

/**
* This allows the renderer (frontend) to communicate with main process (electron/node).
* You can also create and provide an api layer for the frontend and main process.
* Anything exposed here is duplicated and attached to window object.
* No promises, funcs can be directly attached.
*/
const api = {
versions: process.versions,
i18nSync,
showItemInFolder: shell.showItemInFolder,
hello,
// Communicate between renderer and main process
message: {
send: (payload: unknown) => ipcRenderer.send('message', payload),
on: (handler: (event: Electron.IpcRendererEvent, ...args: unknown[]) => void) => ipcRenderer.on('message', handler),
off: (handler: (event: Electron.IpcRendererEvent, ...args: unknown[]) => void) => ipcRenderer.off('message', handler),
},
// Call an electron api command
api: async <T>(methodName: string, options?: unknown): Promise<T> =>
ipcRenderer.invoke('api', methodName, options),
};

contextBridge.exposeInMainWorld(apiKey, api);
Expand Down

0 comments on commit 0ca9513

Please sign in to comment.