diff --git a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-download-puppeteer-executable.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-download-puppeteer-executable.ts deleted file mode 100644 index 43723f1..0000000 --- a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-download-puppeteer-executable.ts +++ /dev/null @@ -1,102 +0,0 @@ -import * as path from 'node:path' -import * as os from 'node:os' -import * as fs from 'node:fs' -import type { InstalledBrowser } from '@puppeteer/browsers' -import electron from 'electron' -import { saveLastUsedAndAvailableBrowserInfo, BrowserInfo } from './history-utils' - -export const EXPECT_CHROMIUM_BUILD_ID = '113.0.5672.63' -const cacheDir = path.join( - os.homedir(), - '.geekgeekrun', - 'cache' -) - -const getPuppeteerManagerModule = async () => { - let puppeteerManager - if (process.env.NODE_ENV === 'development') { - puppeteerManager = await import('@puppeteer/browsers') - } else { - puppeteerManager = ( - await import( - 'file://' + - path.resolve( - electron.app.getAppPath(), - '..', - 'external-node-runtime-dependencies/index.mjs' - ) - ) - ).puppeteerManager - } - - return puppeteerManager -} - -export const getExpectCachedPuppeteerExecutable = async (): Promise => { - const puppeteerManager = await getPuppeteerManagerModule() - - const executablePath = puppeteerManager.computeExecutablePath({ - browser: puppeteerManager.Browser.CHROME, - cacheDir, - buildId: EXPECT_CHROMIUM_BUILD_ID - }) - - const browser = puppeteerManager.Browser.CHROME[0].toUpperCase() + puppeteerManager.Browser.CHROME.slice(1) + ' ' + EXPECT_CHROMIUM_BUILD_ID - return { - executablePath, - browser - } -} - -export const checkCachedPuppeteerExecutable = async () => { - try { - const executablePath = (await getExpectCachedPuppeteerExecutable()).executablePath - return fs.existsSync(executablePath) - } catch { - // should limit [ERR_MODULE_NOT_FOUND] - return false - } -} - -const checkAndDownloadPuppeteerExecutable = async ( - options: { - downloadProgressCallback?: (downloadedBytes: number, totalBytes: number) => void - confirmContinuePromise?: Promise - } = {} -) => { - const puppeteerManager = await getPuppeteerManagerModule() - let installedBrowser: InstalledBrowser - if (!(await checkCachedPuppeteerExecutable())) { - try { - await options.confirmContinuePromise - } catch { - throw new Error('USER_CANCEL_DOWNLOAD_PUPPETEER') - } - // maybe the exist installation is broken. - await puppeteerManager.uninstall({ - cacheDir, - buildId: EXPECT_CHROMIUM_BUILD_ID, - browser: puppeteerManager.Browser.CHROME - }) - installedBrowser = await puppeteerManager.install({ - browser: puppeteerManager.Browser.CHROME, - cacheDir, - buildId: EXPECT_CHROMIUM_BUILD_ID, - downloadProgressCallback: options.downloadProgressCallback - }) - } else { - installedBrowser = ( - await puppeteerManager.getInstalledBrowsers({ - cacheDir - }) - ).find((it) => it.buildId === EXPECT_CHROMIUM_BUILD_ID)! - } - await saveLastUsedAndAvailableBrowserInfo({ - executablePath: installedBrowser.executablePath, - browser: installedBrowser.browser[0].toUpperCase() + installedBrowser.browser.slice(1) + ' ' + EXPECT_CHROMIUM_BUILD_ID - }) - - return installedBrowser -} - -export default checkAndDownloadPuppeteerExecutable diff --git a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-locate-existed-chromium-executable.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-locate-existed-chromium-executable.ts deleted file mode 100644 index 201057f..0000000 --- a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-locate-existed-chromium-executable.ts +++ /dev/null @@ -1,65 +0,0 @@ -import electron from 'electron' -import * as os from 'node:os' -import * as fs from 'node:fs' -import path from 'node:path' -import { EXPECT_CHROMIUM_BUILD_ID } from './check-and-download-puppeteer-executable' -import { - getExecutableFileVersion -} from '@geekgeekrun/utils/windows-only/file.mjs' -import { BrowserInfo } from './history-utils' - -export default async function findAndLocateExistedChromiumExecutable(): Promise { - const exceptChromiumMainVersion = Number(EXPECT_CHROMIUM_BUILD_ID.split('.')[0]) - // For windows, try to find Edge(chromium) - if (os.platform() === 'win32') { - // TODO: handle windows - const edgeExecutableLocation = path.join( - process.env['ProgramFiles(x86)']!, - 'Microsoft/Edge/Application', - 'msedge.exe' - ) - if ( - fs.existsSync(edgeExecutableLocation) - ) { - try { - const version = await getExecutableFileVersion(edgeExecutableLocation) - const mainVersion = Number(version.split('.')[0]) - if ( mainVersion >= exceptChromiumMainVersion) { - return { - executablePath: edgeExecutableLocation, - browser: `Edge ${version}` - } - } - } catch(err) { - console.log(err) - } - } - } - - // For other, use findChrome - let findChrome: typeof import('find-chrome-bin').findChrome - if (process.env.NODE_ENV === 'development') { - findChrome = (await import('find-chrome-bin')).findChrome - } else { - findChrome = ( - await import( - 'file://' + - path.resolve( - electron.app.getAppPath(), - '..', - 'external-node-runtime-dependencies/index.mjs' - ) - ) - ).findChromeBin.findChrome - } - const targetBrowser = await findChrome({ - min: exceptChromiumMainVersion - }) - if (!targetBrowser?.executablePath) { - throw new Error('NO_EXPECT_CHROMIUM_FOUND') - } - return { - executablePath: targetBrowser.executablePath, - browser: targetBrowser.browser - } -} diff --git a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index.ts index ab4661f..f2bb775 100644 --- a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index.ts +++ b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index.ts @@ -1,72 +1,14 @@ import { app } from 'electron' -import checkAndDownloadPuppeteerExecutable, { - checkCachedPuppeteerExecutable, - getExpectCachedPuppeteerExecutable -} from './check-and-download-puppeteer-executable' +import { checkAndDownloadPuppeteerExecutable } from './utils/puppeteer-executable/index' import * as fs from 'fs' import { pipeWriteRegardlessError } from '../utils/pipe' -import { - removeLastUsedAndAvailableBrowserPath, - getLastUsedAndAvailableBrowser, - saveLastUsedAndAvailableBrowserInfo, - BrowserInfo -} from './history-utils' -import { type Worker } from 'worker_threads' -import { - sleep -} from '@geekgeekrun/utils/sleep.mjs' - -import CheckAndLocateExistedChromiumExecutableWorker from '../../worker/check-and-locate-existed-chromium-executable?nodeWorker&url' +import { sleep } from '@geekgeekrun/utils/sleep.mjs' export enum DOWNLOAD_ERROR_EXIT_CODE { NO_ERROR = 0, DOWNLOAD_ERROR = 1 } -async function findAndLocateExistedChromiumExecutable(): Promise { - return new Promise((resolve, reject) => { - const worker: Worker = new CheckAndLocateExistedChromiumExecutableWorker() - worker.once('message', (data) => { - if (data.type === 'RESULT') { - resolve(data.data) - } - }) - worker.once('message', (data) => { - if (data.type === 'ERROR') { - reject(data.error) - } - }) - }) -}; - -export const getAnyAvailablePuppeteerExecutable = async (): Promise => { - const lastUsedOne = await getLastUsedAndAvailableBrowser() - if (lastUsedOne) { - return lastUsedOne - } - // find existed browser - the one maybe actively installed by user or ship with os like Edge on windows - try { - const existedOne = (await findAndLocateExistedChromiumExecutable()) - await saveLastUsedAndAvailableBrowserInfo(existedOne) - // save its path - return existedOne - } catch (err) { - console.error(err) - console.log('no existed browser path found') - } - // find existed browser - the fallback one - if (await checkCachedPuppeteerExecutable()) { - const cachedOne = await getExpectCachedPuppeteerExecutable() - await saveLastUsedAndAvailableBrowserInfo(cachedOne) - - return cachedOne - } - - // if no one available, then return null and remove last used browser - await removeLastUsedAndAvailableBrowserPath() - return null -} - export const checkAndDownloadDependenciesForInit = async () => { process.on('disconnect', () => app.exit()) app.dock?.hide() diff --git a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/history-utils.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history.ts similarity index 86% rename from packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/history-utils.ts rename to packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history.ts index 21ff1d1..d8506eb 100644 --- a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/history-utils.ts +++ b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history.ts @@ -4,8 +4,8 @@ import * as fs from 'fs' import * as fsPromise from 'fs/promises' export interface BrowserInfo { - browser: string; - executablePath: string; + browser: string + executablePath: string } const runtimeFolderPath = path.join(os.homedir(), '.geekgeekrun') @@ -27,7 +27,7 @@ export const getLastUsedAndAvailableBrowser = async (): Promise it.trim()) + const [path, browser] = fileContent.split('\n').map((it) => it.trim()) if (!path || !fs.existsSync(path)) { await removeLastUsedAndAvailableBrowserPath() return null @@ -48,10 +48,8 @@ export const saveLastUsedAndAvailableBrowserInfo = async (browserInfo: BrowserIn await fsPromise.mkdir(runtimeFolderPath) } await fsPromise.writeFile( - lastUsedBrowserRecordFilePath, [ - browserInfo.executablePath, - browserInfo.browser - ].join('\n') + lastUsedBrowserRecordFilePath, + [browserInfo.executablePath, browserInfo.browser].join('\n') ) } catch { console.warn('lastUsedBrowserRecordFile write error') diff --git a/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index.ts new file mode 100644 index 0000000..109dcc1 --- /dev/null +++ b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index.ts @@ -0,0 +1,210 @@ +import * as path from 'node:path' +import * as os from 'node:os' +import * as fs from 'node:fs' +import type { InstalledBrowser } from '@puppeteer/browsers' +import electron from 'electron' +import { + saveLastUsedAndAvailableBrowserInfo, + BrowserInfo, + getLastUsedAndAvailableBrowser, + removeLastUsedAndAvailableBrowserPath +} from '../browser-history' +import { getExecutableFileVersion } from '@geekgeekrun/utils/windows-only/file.mjs' +import CheckAndLocateExistedChromiumExecutableWorker from './worker/find-and-locate-existed-chromium-executable?nodeWorker&url' +import { type Worker } from 'worker_threads' + +const getPuppeteerManagerModule = async () => { + let puppeteerManager + if (process.env.NODE_ENV === 'development') { + puppeteerManager = await import('@puppeteer/browsers') + } else { + puppeteerManager = ( + await import( + 'file://' + + path.resolve( + electron.app.getAppPath(), + '..', + 'external-node-runtime-dependencies/index.mjs' + ) + ) + ).puppeteerManager + } + + return puppeteerManager +} + +const EXPECT_CHROMIUM_BUILD_ID = '113.0.5672.63' +const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache') + +const getExpectCachedPuppeteerExecutable = async (): Promise => { + const puppeteerManager = await getPuppeteerManagerModule() + + const executablePath = puppeteerManager.computeExecutablePath({ + browser: puppeteerManager.Browser.CHROME, + cacheDir, + buildId: EXPECT_CHROMIUM_BUILD_ID + }) + + const browser = + puppeteerManager.Browser.CHROME[0].toUpperCase() + + puppeteerManager.Browser.CHROME.slice(1) + + ' ' + + EXPECT_CHROMIUM_BUILD_ID + return { + executablePath, + browser + } +} + +const checkCachedPuppeteerExecutable = async () => { + try { + const executablePath = (await getExpectCachedPuppeteerExecutable()).executablePath + return fs.existsSync(executablePath) + } catch { + // should limit [ERR_MODULE_NOT_FOUND] + return false + } +} + +export const checkAndDownloadPuppeteerExecutable = async ( + options: { + downloadProgressCallback?: (downloadedBytes: number, totalBytes: number) => void + confirmContinuePromise?: Promise + } = {} +) => { + const puppeteerManager = await getPuppeteerManagerModule() + let installedBrowser: InstalledBrowser + if (!(await checkCachedPuppeteerExecutable())) { + try { + await options.confirmContinuePromise + } catch { + throw new Error('USER_CANCEL_DOWNLOAD_PUPPETEER') + } + // maybe the exist installation is broken. + await puppeteerManager.uninstall({ + cacheDir, + buildId: EXPECT_CHROMIUM_BUILD_ID, + browser: puppeteerManager.Browser.CHROME + }) + installedBrowser = await puppeteerManager.install({ + browser: puppeteerManager.Browser.CHROME, + cacheDir, + buildId: EXPECT_CHROMIUM_BUILD_ID, + downloadProgressCallback: options.downloadProgressCallback + }) + } else { + installedBrowser = ( + await puppeteerManager.getInstalledBrowsers({ + cacheDir + }) + ).find((it) => it.buildId === EXPECT_CHROMIUM_BUILD_ID)! + } + await saveLastUsedAndAvailableBrowserInfo({ + executablePath: installedBrowser.executablePath, + browser: + installedBrowser.browser[0].toUpperCase() + + installedBrowser.browser.slice(1) + + ' ' + + EXPECT_CHROMIUM_BUILD_ID + }) + + return installedBrowser +} + +export const getAnyAvailablePuppeteerExecutable = async (): Promise => { + const lastUsedOne = await getLastUsedAndAvailableBrowser() + if (lastUsedOne) { + return lastUsedOne + } + // find existed browser - the one maybe actively installed by user or ship with os like Edge on windows + try { + const existedOne = await findAndLocateExistedChromiumExecutable() + await saveLastUsedAndAvailableBrowserInfo(existedOne) + // save its path + return existedOne + } catch (err) { + console.error(err) + console.log('no existed browser path found') + } + // find existed browser - the fallback one + if (await checkCachedPuppeteerExecutable()) { + const cachedOne = await getExpectCachedPuppeteerExecutable() + await saveLastUsedAndAvailableBrowserInfo(cachedOne) + + return cachedOne + } + + // if no one available, then return null and remove last used browser + await removeLastUsedAndAvailableBrowserPath() + return null +} + +export async function findAndLocateExistedChromiumExecutableSync(): Promise { + const exceptChromiumMainVersion = Number(EXPECT_CHROMIUM_BUILD_ID.split('.')[0]) + // For windows, try to find Edge(chromium) + if (os.platform() === 'win32') { + // TODO: handle windows + const edgeExecutableLocation = path.join( + process.env['ProgramFiles(x86)']!, + 'Microsoft/Edge/Application', + 'msedge.exe' + ) + if (fs.existsSync(edgeExecutableLocation)) { + try { + const version = await getExecutableFileVersion(edgeExecutableLocation) + const mainVersion = Number(version.split('.')[0]) + if (mainVersion >= exceptChromiumMainVersion) { + return { + executablePath: edgeExecutableLocation, + browser: `Edge ${version}` + } + } + } catch (err) { + console.log(err) + } + } + } + + // For other, use findChrome + let findChrome: typeof import('find-chrome-bin').findChrome + if (process.env.NODE_ENV === 'development') { + findChrome = (await import('find-chrome-bin')).findChrome + } else { + findChrome = ( + await import( + 'file://' + + path.resolve( + electron.app.getAppPath(), + '..', + 'external-node-runtime-dependencies/index.mjs' + ) + ) + ).findChromeBin.findChrome + } + const targetBrowser = await findChrome({ + min: exceptChromiumMainVersion + }) + if (!targetBrowser?.executablePath) { + throw new Error('NO_EXPECT_CHROMIUM_FOUND') + } + return { + executablePath: targetBrowser.executablePath, + browser: targetBrowser.browser + } +} + +export async function findAndLocateExistedChromiumExecutable(): Promise { + return new Promise((resolve, reject) => { + const worker: Worker = new CheckAndLocateExistedChromiumExecutableWorker() + worker.once('message', (data) => { + if (data.type === 'RESULT') { + resolve(data.data) + } + }) + worker.once('message', (data) => { + if (data.type === 'ERROR') { + reject(data.error) + } + }) + }) +} diff --git a/packages/ui/src/main/worker/check-and-locate-existed-chromium-executable.ts b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/worker/find-and-locate-existed-chromium-executable.ts similarity index 56% rename from packages/ui/src/main/worker/check-and-locate-existed-chromium-executable.ts rename to packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/worker/find-and-locate-existed-chromium-executable.ts index 3c023df..66a34f9 100644 --- a/packages/ui/src/main/worker/check-and-locate-existed-chromium-executable.ts +++ b/packages/ui/src/main/flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/worker/find-and-locate-existed-chromium-executable.ts @@ -1,8 +1,8 @@ import { parentPort } from 'node:worker_threads' -import findAndLocateExistedChromiumExecutable from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/check-and-locate-existed-chromium-executable' +import { findAndLocateExistedChromiumExecutableSync } from '../index' ;(async () => { try { - const result = await findAndLocateExistedChromiumExecutable() + const result = await findAndLocateExistedChromiumExecutableSync() parentPort?.postMessage({ type: 'RESULT', data: result diff --git a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS.ts b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS.ts index ede306d..005b4d3 100644 --- a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS.ts +++ b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS.ts @@ -4,7 +4,7 @@ import { SyncHook, AsyncSeriesHook } from 'tapable' import { readConfigFile } from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs' import * as fs from 'fs' import { pipeWriteRegardlessError } from './utils/pipe' -import { getAnyAvailablePuppeteerExecutable } from './CHECK_AND_DOWNLOAD_DEPENDENCIES' +import { getAnyAvailablePuppeteerExecutable } from './CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable' const { groupRobotAccessToken: dingTalkAccessToken } = readConfigFile('dingtalk.json') diff --git a/packages/ui/src/main/flow/LAUNCH_BOSS_ZHIPIN_LOGIN_PAGE_WITH_PRELOAD_EXTENSION.ts b/packages/ui/src/main/flow/LAUNCH_BOSS_ZHIPIN_LOGIN_PAGE_WITH_PRELOAD_EXTENSION.ts index 6a0d63b..e8aa9f0 100644 --- a/packages/ui/src/main/flow/LAUNCH_BOSS_ZHIPIN_LOGIN_PAGE_WITH_PRELOAD_EXTENSION.ts +++ b/packages/ui/src/main/flow/LAUNCH_BOSS_ZHIPIN_LOGIN_PAGE_WITH_PRELOAD_EXTENSION.ts @@ -3,11 +3,6 @@ import { main, loginEventBus } from '@geekgeekrun/launch-bosszhipin-login-page-w import { pipeWriteRegardlessError } from './utils/pipe' import fs from "node:fs"; -export enum DOWNLOAD_ERROR_EXIT_CODE { - NO_ERROR = 0, - DOWNLOAD_ERROR = 1 -} - export const launchBossZhipinLoginPageWithPreloadExtension = async () => { process.on('disconnect', () => app.exit()) app.dock?.hide() diff --git a/packages/ui/src/main/window/mainWindow.ts b/packages/ui/src/main/window/mainWindow.ts index 88bec78..c5a47b2 100644 --- a/packages/ui/src/main/window/mainWindow.ts +++ b/packages/ui/src/main/window/mainWindow.ts @@ -14,10 +14,8 @@ import { import { ChildProcess } from 'child_process' import * as JSONStream from 'JSONStream' import { checkCookieListFormat } from '../../common/utils/cookie' -import { - DOWNLOAD_ERROR_EXIT_CODE, - getAnyAvailablePuppeteerExecutable -} from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES' +import { getAnyAvailablePuppeteerExecutable } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index' +import { DOWNLOAD_ERROR_EXIT_CODE } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index' import { sleep } from '@geekgeekrun/utils/sleep.mjs' let mainWindow: BrowserWindow | null = null diff --git a/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue b/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue index eb7dff3..02bc028 100644 --- a/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue +++ b/packages/ui/src/renderer/src/page/BootstrapSplash/index.vue @@ -10,22 +10,25 @@