diff --git a/README.md b/README.md index 20f3b0d..0bc0c02 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,7 @@ const Page = () => { return ; }; ``` + +## Reference and Credit + + diff --git a/oggerMiddleware.ts b/loggerMiddleware.ts similarity index 100% rename from oggerMiddleware.ts rename to loggerMiddleware.ts diff --git a/src/main/index.ts b/src/main/index.ts index 45ad40e..c01fb64 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -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([ { @@ -15,7 +15,11 @@ protocol.registerSchemesAsPrivileged([ ]); const onReady = () => { - startApi() + const usePy = true + runPython() + + // startApi(usePy) + runPython() .then(() => { createMainWindow(); console.log('App run successfully'); diff --git a/src/main/start.ts b/src/main/start.ts index 11f21bd..d60e5d6 100644 --- a/src/main/start.ts +++ b/src/main/start.ts @@ -10,12 +10,9 @@ let python: Record = {}; 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} A promise that resolves when the Python script is successfully executed. - */ +const apiPort = 8100; + + export function runPython() { return new Promise((resolve, reject) => { const appFile = path.join(appPath, 'main.py'); @@ -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 @@ -71,7 +68,7 @@ export async function killPython(pid: any = apiPort) { }); } -export const startApi = () => { +export const startApi = (usePy = false) => { console.log('API is starting...', apiPort); @@ -79,6 +76,7 @@ export const startApi = () => { const appFile = path.join(appPath, 'dist', 'main.exe'); isAvailablePromise({ port: apiPort }).then((apiReady) => { + waitOn({ resources: [`tcp:${apiPort}`], }).then(() => { @@ -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) => { + if (err) { + console.error('Failed to start FastAPI server:', err); + reject(err); + return; + } + if (stderr) { + console.error(`stderr: ${stderr}`); + } + console.log(`stdout: ${stdout}`); + resolve(); + }); + + }); }); diff --git a/src/preload/index.ts b/src/preload/index.ts index a31a09d..1e83364 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,4 +1,4 @@ -import { contextBridge, shell } from 'electron'; +import { contextBridge, shell, ipcRenderer } from 'electron'; import i18nSync from './i18n-sync'; const apiKey = '$api'; @@ -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 (methodName: string, options?: unknown): Promise => + ipcRenderer.invoke('api', methodName, options), }; contextBridge.exposeInMainWorld(apiKey, api);