RSS Git Download  Clone
Raw Blame History
(async () => {
try {
const {ipcRenderer, shell} = require('electron');
const http = require('node:http');

let domReady = false
let loadingOverlay
let hasSuccessfulUiLoad = false

const setLoadingOverlayVisible = (visible) => {
    if (!loadingOverlay) {
        return
    }
    if (visible) {
        loadingOverlay.classList.remove('p3xre-hidden')
    } else {
        loadingOverlay.classList.add('p3xre-hidden')
    }
}

const setLoadingState = (loading) => {
    setLoadingOverlayVisible(loading)
    if (!global.p3xre || !global.p3xre.iframe) {
        return
    }
    if (loading) {
        global.p3xre.iframe.classList.add('p3xre-webview-loading')
    } else {
        global.p3xre.iframe.classList.remove('p3xre-webview-loading')
    }
}

let p3xSetLanguageWaiter
ipcRenderer.on('p3x-set-language', (event, data) => {
    const callMe = async () => {
        if (domReady === false) {
            clearTimeout(p3xSetLanguageWaiter)
            setTimeout(callMe, 250)
            return;
        }
        const translation = data.translation
        const stringsModule = await import(`../../../strings/${translation}/index.mjs`)
        global.p3xre.strings = stringsModule.default
        global.p3xre.iframe.contentWindow.postMessage({ type: 'p3x-set-language', translation: translation }, '*')
    }
    callMe()
})


ipcRenderer.on('p3x-menu', function (event, data) {
    global.p3xre.iframe.contentWindow.postMessage({ type: 'p3x-menu', action: data.action }, '*')
})

ipcRenderer.on('p3x-new-window', function (event, data) {
    shell.openExternal(data.url)
})

// Listen for theme changes from the Angular app (iframe) to sync dark mode on the shell
window.addEventListener('message', (event) => {
    if (event.data?.type === 'p3x-theme-change') {
        document.body.classList.remove('p3xr-theme-dark', 'p3xr-theme-light')
        document.body.classList.add(event.data.dark ? 'p3xr-theme-dark' : 'p3xr-theme-light')
    }
})


const pkg = require('../../../../package.json')
const enStrings = await import('../../../strings/en/index.mjs')

global.p3xre = {
    iframe: undefined,
    pkg: pkg,
    strings: enStrings.default
}

const { p3xToast } = await import('./ui.mjs')
global.p3xre.toast = p3xToast

ipcRenderer.on('p3x-action', function (event, data) {
    switch (data.action) {
        case 'toast':
            p3xre.toast.action(data.message)
            break;
    }
})

const isLocalHttpAvailable = (port, timeoutMs = 800, host = '127.0.0.1') => {
    return new Promise((resolve) => {
        let settled = false
        const done = (value) => {
            if (settled) {
                return
            }
            settled = true
            resolve(value)
        }

        const request = http.request({
            host: host,
            port: port,
            path: '/',
            method: 'GET',
        }, () => {
            done(true)
            request.destroy()
        })

        request.on('error', () => {
            done(false)
        })

        request.setTimeout(timeoutMs, () => {
            request.destroy()
            done(false)
        })

        request.end()
    })
}

window.p3xreRun = async function () {

    document.title = `${p3xre.strings.title} v${p3xre.pkg.version}`
    try {
        global.p3xre.iframe = document.getElementById("p3xre-redis-ui-electron");
        loadingOverlay = document.getElementById('p3xre-loading-overlay')
        setLoadingState(true)

        const urlParams = new URLSearchParams(global.location.search)
        const port = urlParams.get('port')
        const localServerHosts = ['127.0.0.1', 'localhost']
        const getLocalServerUrl = (host) => `http://${host}:${port}`
        let currentLocalServerHostIndex = 0
        const getCurrentLocalServerUrl = () => getLocalServerUrl(localServerHosts[currentLocalServerHostIndex])
        const devServerUrl = 'http://localhost:8080'
        const isDev = process.env.hasOwnProperty('NODE_ENV') && process.env.NODE_ENV === 'development'
        const maxWaitRetries = 120
        const waitRetryDelayMs = 500

        // Wait for the local HTTP server to become available before loading the iframe.
        const waitForServer = async (targetUrl) => {
            for (let i = 0; i < maxWaitRetries; i++) {
                for (const host of localServerHosts) {
                    const available = await isLocalHttpAvailable(port, 800, host)
                    if (available) {
                        currentLocalServerHostIndex = localServerHosts.indexOf(host)
                        return getCurrentLocalServerUrl()
                    }
                }
                await new Promise((r) => setTimeout(r, waitRetryDelayMs))
            }
            // Fall back to the target even if not confirmed available
            return targetUrl
        }

        global.p3xre.iframe.addEventListener('load', function () {
            domReady = true
            const iframeSrc = global.p3xre.iframe.src || ''
            if (iframeSrc === 'about:blank') {
                return
            }
            hasSuccessfulUiLoad = true
            setLoadingState(false)
        })

        let serverUrl
        if (isDev) {
            console.log('development mode')
            const devServerAvailable = await isLocalHttpAvailable(8080)
            if (devServerAvailable) {
                serverUrl = devServerUrl
            } else {
                console.warn('Dev server http://localhost:8080 is not running, waiting for local server...')
                serverUrl = await waitForServer(getCurrentLocalServerUrl())
            }
        } else {
            serverUrl = await waitForServer(getCurrentLocalServerUrl())
        }

        global.p3xre.iframe.src = serverUrl

    } catch (e) {
        console.error(e);
        alert(e.message);
    }
}

if (document.readyState === 'complete') {
    window.p3xreRun()
} else {
    window.addEventListener('load', () => {
        window.p3xreRun()
    })
}

} catch(e) {
    console.error('p3xre: fatal error in onload.mjs', e)
}
})();