From 9452952fdc4c4580a8b984edc88540c31a2b5727 Mon Sep 17 00:00:00 2001 From: Renaud Heluin Date: Wed, 21 Aug 2024 12:55:47 +0200 Subject: [PATCH] feat: continue Nouvelle initialisation de l'application #47 --- .../ecoindex-app/src/class/ConfigData.ts | 4 +- electron-app/ecoindex-app/src/interface.d.ts | 9 +- .../src/main/handlers/Initalization.ts | 53 ++++++ .../handlers/initHandlers/IsNodeInstalled.ts | 56 +++++++ .../handlers/initHandlers/isNodeVersionOK.ts | 36 ++++ electron-app/ecoindex-app/src/main/main.ts | 2 + .../src/renderer/MainWindow/App.tsx | 154 ++++++++++-------- .../src/renderer/MainWindow/preload.ts | 10 ++ .../ecoindex-app/src/shared/constants.ts | 2 + 9 files changed, 254 insertions(+), 72 deletions(-) create mode 100644 electron-app/ecoindex-app/src/main/handlers/Initalization.ts create mode 100644 electron-app/ecoindex-app/src/main/handlers/initHandlers/IsNodeInstalled.ts create mode 100644 electron-app/ecoindex-app/src/main/handlers/initHandlers/isNodeVersionOK.ts diff --git a/electron-app/ecoindex-app/src/class/ConfigData.ts b/electron-app/ecoindex-app/src/class/ConfigData.ts index 88390ad..b8c9ce8 100644 --- a/electron-app/ecoindex-app/src/class/ConfigData.ts +++ b/electron-app/ecoindex-app/src/class/ConfigData.ts @@ -2,7 +2,7 @@ * Object used to transport datas from `Back` to `Front`. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -class ConfigData { +export class ConfigData { static WORKDIR = 'workDir' static HOMEDIR = 'homeDir' static APP_READY = 'appReady' @@ -22,7 +22,7 @@ class ConfigData { /** * The error if fail. */ - error?: string | object | Error + error?: any /** * A message if needed. */ diff --git a/electron-app/ecoindex-app/src/interface.d.ts b/electron-app/ecoindex-app/src/interface.d.ts index ea3fa32..f488012 100644 --- a/electron-app/ecoindex-app/src/interface.d.ts +++ b/electron-app/ecoindex-app/src/interface.d.ts @@ -17,7 +17,6 @@ export interface IElectronAPI { sendLogToFront: (callback) => string sendMessageToFrontLog: (callback) => object sendDatasToFront: (callback) => object - sendConfigDatasToFront: (callback) => ConfigData // Front → Main getInitialTranslations: () => Promise handleSetFolderOuput: () => Promise @@ -40,6 +39,13 @@ export interface IElectronAPI { hideHelloWindow: () => Promise } +export interface IInitalization { + // Front → Main + initializeApplication: () => Promise + // Main → Front + sendConfigDatasToFront: (callback) => ConfigData +} + declare global { export interface IJsonMesureData { 'extra-header': object | null @@ -67,5 +73,6 @@ declare global { versions: IVersionsAPI electronAPI: IElectronAPI store: IStoreAPI + initialisationAPI: IInitalization } } diff --git a/electron-app/ecoindex-app/src/main/handlers/Initalization.ts b/electron-app/ecoindex-app/src/main/handlers/Initalization.ts new file mode 100644 index 0000000..dd1627e --- /dev/null +++ b/electron-app/ecoindex-app/src/main/handlers/Initalization.ts @@ -0,0 +1,53 @@ +import { IpcMainEvent, IpcMainInvokeEvent } from 'electron' + +import Store from 'electron-store' +import { channels } from '../../shared/constants' +import { getMainLog } from '../main' +import { getMainWindow } from '../../shared/memory' +import { initIsNodeInstalled } from './initHandlers/IsNodeInstalled' +import { initIsNodeNodeVersionOK } from './initHandlers/isNodeVersionOK' + +const store = new Store() + +type initializedDatas = { + initIsNodeInstalled?: boolean + initIsNodeNodeVersionOK?: boolean +} + +const readInitalizedDatas = (value: initializedDatas): boolean => { + return value.initIsNodeInstalled && value.initIsNodeNodeVersionOK +} + +export const initialization = async ( + event: IpcMainEvent | IpcMainInvokeEvent +) => { + const mainLog = getMainLog().scope('main/initialization') + const initializedDatas: initializedDatas = {} + try { + mainLog.log(`Initialization start...`) + mainLog.log(`1. Node installed start...`) + // #region Node installed + const isNodeReturned = await initIsNodeInstalled(event) + initializedDatas.initIsNodeInstalled = isNodeReturned.result as boolean + mainLog.log(isNodeReturned.toString()) + getMainWindow().webContents.send( + channels.INITIALIZATION_DATAS, + isNodeReturned + ) + mainLog.log(`2. Node Version upper or equal to 20 start...`) + // #region Node installed + const isNode20Returned = await initIsNodeNodeVersionOK(event) + initializedDatas.initIsNodeNodeVersionOK = + isNode20Returned.result as boolean + mainLog.log(isNode20Returned.toString()) + getMainWindow().webContents.send( + channels.INITIALIZATION_DATAS, + isNode20Returned + ) + + return readInitalizedDatas(initializedDatas) + } catch (error) { + mainLog.error(error) + return false + } +} diff --git a/electron-app/ecoindex-app/src/main/handlers/initHandlers/IsNodeInstalled.ts b/electron-app/ecoindex-app/src/main/handlers/initHandlers/IsNodeInstalled.ts new file mode 100644 index 0000000..fdca3c4 --- /dev/null +++ b/electron-app/ecoindex-app/src/main/handlers/initHandlers/IsNodeInstalled.ts @@ -0,0 +1,56 @@ +import { IpcMainEvent, IpcMainInvokeEvent } from 'electron' +import { getTryNode, setTryNode } from '../../../shared/memory' + +import { ConfigData } from '../../../class/ConfigData' +import { channels } from '../../../shared/constants' +import { getMainLog } from '../../main' +import { handle_CMD_Actions } from '../HandleCMDActions' +import { sleep } from '../../../main/utils/Sleep' + +/** + * + * @param _event + * @returns {string} + */ +const fetchNode = async ( + _event: IpcMainEvent | IpcMainInvokeEvent +): Promise => { + const _nodeDir = await handle_CMD_Actions( + _event, + channels.IS_NODE_INSTALLED + ) + // #region tries read node + // give some tries before return false + if (_nodeDir === '' && getTryNode() > 0) { + await sleep(2000) + setTryNode() + return fetchNode(_event) + } + return _nodeDir as string +} + +export const initIsNodeInstalled = async ( + _event: IpcMainEvent | IpcMainInvokeEvent +) => { + const mainLog = getMainLog().scope( + 'main/initialization/initIsNodeInstalled' + ) + try { + const returned: string = await fetchNode(_event) + + const output = new ConfigData('node_installed') + if (returned === '') { + output.error = `Node not found` + } else { + output.result = true + output.message = `Node is Installed in ${returned}` + } + mainLog.debug(output) + return new Promise((resolve, reject) => { + if (output.error) reject(output) + else resolve(output) + }) + } catch (error) { + mainLog.error(error) + } +} diff --git a/electron-app/ecoindex-app/src/main/handlers/initHandlers/isNodeVersionOK.ts b/electron-app/ecoindex-app/src/main/handlers/initHandlers/isNodeVersionOK.ts new file mode 100644 index 0000000..b46d6d6 --- /dev/null +++ b/electron-app/ecoindex-app/src/main/handlers/initHandlers/isNodeVersionOK.ts @@ -0,0 +1,36 @@ +import { IpcMainEvent, IpcMainInvokeEvent } from 'electron' + +import { ConfigData } from '../../../class/ConfigData' +import { channels } from '../../../shared/constants' +import { getMainLog } from '../../main' +import { handle_CMD_Actions } from '../HandleCMDActions' + +export const initIsNodeNodeVersionOK = async ( + _event: IpcMainEvent | IpcMainInvokeEvent +) => { + const mainLog = getMainLog().scope( + 'main/initialization/initIsNodeNodeVersionOK' + ) + try { + const returned: string = await handle_CMD_Actions( + _event, + channels.GET_NODE_VERSION + ) + const major = returned.replace('v', '').split('.')[0] + + const output = new ConfigData('node_version_is_ok') + if (returned === '') { + output.error = `Node version not found` + } else { + output.result = Number(major) >= 20 + output.message = `Node version is ${returned} and it's upper or equal to 20=${output.result}` + } + mainLog.debug(output) + return new Promise((resolve, reject) => { + if (output.error) reject(output) + else resolve(output) + }) + } catch (error) { + mainLog.error(error) + } +} diff --git a/electron-app/ecoindex-app/src/main/main.ts b/electron-app/ecoindex-app/src/main/main.ts index 1760af7..8cc37ca 100644 --- a/electron-app/ecoindex-app/src/main/main.ts +++ b/electron-app/ecoindex-app/src/main/main.ts @@ -30,6 +30,7 @@ import { handleSelectFolder } from './handlers/HandleSelectFolder' import { handleWorkDir } from './handlers/HandleWorkDir' import { handle_CMD_Actions } from './handlers/HandleCMDActions' import i18n from '../configs/i18next.config' +import { initialization } from './handlers/Initalization' import { isLighthouseEcoindexInstalled } from './handlers/IsLighthouseEcoindexInstalled' import { isPupperteerBrowserInstalled } from './handlers/IsPuppeteerBrowserInstalled' import log from 'electron-log/main' @@ -102,6 +103,7 @@ app.on('ready', () => { ipcMain.handle(channels.READ_RELOAD_JSON_FILE, handleJsonReadAndReload) // communs handlers and getters + ipcMain.handle(channels.INITIALIZATION_APP, initialization) ipcMain.handle(channels.GET_HOMEDIR, handleHomeDir) ipcMain.handle(channels.GET_WORKDIR, handleWorkDir) ipcMain.handle(channels.IS_NODE_INSTALLED, handleNodeInstalled) diff --git a/electron-app/ecoindex-app/src/renderer/MainWindow/App.tsx b/electron-app/ecoindex-app/src/renderer/MainWindow/App.tsx index 4a42dc2..3feb546 100644 --- a/electron-app/ecoindex-app/src/renderer/MainWindow/App.tsx +++ b/electron-app/ecoindex-app/src/renderer/MainWindow/App.tsx @@ -12,6 +12,7 @@ import { useCallback, useEffect, useState } from 'react' import { AlertBox } from '../components/Alert' import { Bug } from 'lucide-react' import { Button } from '@/renderer/ui/button' +import { ConfigData } from '../../class/ConfigData' import { ConsoleApp } from '../components/console' import { DarkModeSwitcher } from '../components/dark-mode-switcher' import { Footer } from '../components/footer' @@ -45,14 +46,14 @@ function TheApp() { const [displayPopin, setDisplayPopin] = useState(true) const [popinText, setPopinText] = useState('Loading... 0/4') const [pluginVersion, setPluginVersion] = useState('loading...') - const [isNodeInstalled, setIsNodeInstalled] = useState(true) - const [isNodeVersionOK, setIsNodeVersionOK] = useState(true) + const [isNodeInstalled, setIsNodeInstalled] = useState(false) + const [isNodeVersionOK, setIsNodeVersionOK] = useState(false) const [isPuppeteerBrowserInstalled, setIsPuppeteerBrowserInstalled] = - useState(true) + useState(false) const [ isLighthouseEcoindexPluginInstalled, setIsLighthouseEcoindexPluginInstalled, - ] = useState(true) + ] = useState(false) const [displayReloadButton, setDisplayReloadButton] = useState(false) @@ -475,21 +476,21 @@ function TheApp() { /** * Launch the mandatory actions at startup, once. */ - fetchHomeDir().then(() => { - fetchWorkDir().then(() => { - fetchNodeInstalled().then(() => { - fetchNodeVersion().then(() => { - fetchIsPuppeteerBrowserInstalled().then(() => { - fetchIsLighthousePluginEcoindexInstalled().then( - () => { - setDisplayReloadButton(false) - } - ) - }) - }) - }) - }) - }) + // fetchHomeDir().then(() => { + // fetchWorkDir().then(() => { + // fetchNodeInstalled().then(() => { + // fetchNodeVersion().then(() => { + // fetchIsPuppeteerBrowserInstalled().then(() => { + // fetchIsLighthousePluginEcoindexInstalled().then( + // () => { + // setDisplayReloadButton(false) + // } + // ) + // }) + // }) + // }) + // }) + // }) /** * Handler (main->front), get data from main @@ -529,46 +530,6 @@ function TheApp() { } }) - window.electronAPI.sendConfigDatasToFront((configData: ConfigData) => { - frontLog.debug(configData.toString()) - // todo - if (configData.error) { - frontLog.error(configData.toString()) - return - } - switch (configData.type) { - case ConfigData.WORKDIR: - setWorkDir(configData.result as string) - break - case ConfigData.HOMEDIR: - setHomeDir(configData.result as string) - break - case ConfigData.NODE_INSTALLED: - setIsNodeInstalled(configData.result as boolean) - break - case ConfigData.NODE_VERSION_IS_OK: - setIsNodeVersionOK(configData.result as boolean) - break - case ConfigData.PLUGIN_INSTALLED: - setIsLighthouseEcoindexPluginInstalled( - configData.result as boolean - ) - break - case ConfigData.PLUGIN_VERSION: - setPluginVersion(configData.result as string) - break - case ConfigData.PUPPETEER_BROWSER_INSTALLED: - setIsPuppeteerBrowserInstalled(configData.result as boolean) - break - case ConfigData.APP_READY: - setAppReady(configData.result as boolean) - break - - default: - throw new Error('ConfigData not handle in App.tsx') - } - }) - const getLanguage = async () => { try { const gettedLng = await window.store.get(`language`) @@ -582,26 +543,81 @@ function TheApp() { getLanguage() }, []) + // #region initialisationAPI + useEffect(() => { + const initalization = async () => { + frontLog.debug(`initializeApplication start 🚀`) + const result = + await window.initialisationAPI.initializeApplication() + frontLog.debug(`initializeApplication ended '${result}' 👍`) + } + initalization() + + window.initialisationAPI.sendConfigDatasToFront( + (configData: ConfigData) => { + frontLog.debug(`sendConfigDatasToFront`, configData) + // todo + if (configData.error) { + frontLog.error(configData) + return + } + switch (configData.type) { + case ConfigData.WORKDIR: + setWorkDir(configData.result as string) + break + case ConfigData.HOMEDIR: + setHomeDir(configData.result as string) + break + case ConfigData.NODE_INSTALLED: + setIsNodeInstalled(configData.result as boolean) + break + case ConfigData.NODE_VERSION_IS_OK: + setIsNodeVersionOK(configData.result as boolean) + break + case ConfigData.PLUGIN_INSTALLED: + setIsLighthouseEcoindexPluginInstalled( + configData.result as boolean + ) + break + case ConfigData.PLUGIN_VERSION: + setPluginVersion(configData.result as string) + break + case ConfigData.PUPPETEER_BROWSER_INSTALLED: + setIsPuppeteerBrowserInstalled( + configData.result as boolean + ) + break + case ConfigData.APP_READY: + setAppReady(configData.result as boolean) + break + + default: + throw new Error('ConfigData not handle in App.tsx') + } + } + ) + }, []) + /** * Detect isNodeInstalled change. */ - useEffect(() => { - logEventAndCheckAppReady(`isNodeInstalled`) - }, [isNodeInstalled, logEventAndCheckAppReady]) + // useEffect(() => { + // logEventAndCheckAppReady(`isNodeInstalled`) + // }, [isNodeInstalled, logEventAndCheckAppReady]) /** * Detect isLighthouseEcoindexPluginInstalled change. */ - useEffect(() => { - logEventAndCheckAppReady(`isLighthouseEcoindexPluginInstalled`) - }, [isLighthouseEcoindexPluginInstalled, logEventAndCheckAppReady]) + // useEffect(() => { + // logEventAndCheckAppReady(`isLighthouseEcoindexPluginInstalled`) + // }, [isLighthouseEcoindexPluginInstalled, logEventAndCheckAppReady]) /** * Detect setIsPuppeteerBrowserInstalled change. */ - useEffect(() => { - logEventAndCheckAppReady(`setIsPuppeteerBrowserInstalled`) - }, [setIsPuppeteerBrowserInstalled, logEventAndCheckAppReady]) + // useEffect(() => { + // logEventAndCheckAppReady(`setIsPuppeteerBrowserInstalled`) + // }, [setIsPuppeteerBrowserInstalled, logEventAndCheckAppReady]) /** * Detect workDir change. @@ -652,7 +668,7 @@ function TheApp() {
- {false && ( + {true && ( <>
appReady: {appReady ? 'true' : 'false'}
diff --git a/electron-app/ecoindex-app/src/renderer/MainWindow/preload.ts b/electron-app/ecoindex-app/src/renderer/MainWindow/preload.ts index 1d163f5..91afd1a 100644 --- a/electron-app/ecoindex-app/src/renderer/MainWindow/preload.ts +++ b/electron-app/ecoindex-app/src/renderer/MainWindow/preload.ts @@ -12,6 +12,16 @@ contextBridge.exposeInMainWorld('versions', { getNodeVersion: () => ipcRenderer.invoke(channels.GET_NODE_VERSION), }) +contextBridge.exposeInMainWorld('initialisationAPI', { + // Front → Main + initializeApplication: () => + ipcRenderer.invoke(channels.INITIALIZATION_APP), + // Main → Front + sendConfigDatasToFront: (callback: any) => + ipcRenderer.on(channels.INITIALIZATION_DATAS, (_event, value) => + callback(value) + ), +}) contextBridge.exposeInMainWorld('electronAPI', { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/electron-app/ecoindex-app/src/shared/constants.ts b/electron-app/ecoindex-app/src/shared/constants.ts index 2faf19a..8455587 100644 --- a/electron-app/ecoindex-app/src/shared/constants.ts +++ b/electron-app/ecoindex-app/src/shared/constants.ts @@ -5,6 +5,8 @@ type IConstants = { } const constants: IConstants = { channels: { + INITIALIZATION_APP: 'initialization-app', + INITIALIZATION_DATAS: 'initialization-datas', ASYNCHRONOUS_LOG: 'asynchronous-log', SIMPLE_MESURES: 'simple-mesures', JSON_MESURES: 'json-mesures',