mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-08 08:57:24 +08:00
add browserDownloadProgress relevant logic
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
import path from 'node:path'
|
||||||
|
import os from 'node:os'
|
||||||
|
|
||||||
|
export const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { ipcMain } from 'electron'
|
||||||
|
import {
|
||||||
|
createBrowserDownloadProgressWindow,
|
||||||
|
browserDownloadProgressWindow
|
||||||
|
} from '../window/browserDownloadProgressWindow'
|
||||||
|
|
||||||
|
export async function openBrowserDownloadWindow({ windowOption } = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
createBrowserDownloadProgressWindow({ ...windowOption })
|
||||||
|
|
||||||
|
let processDone = false
|
||||||
|
let pathOfDownloadedBrowser = null
|
||||||
|
function handler(_, executablePath) {
|
||||||
|
pathOfDownloadedBrowser = executablePath
|
||||||
|
processDone = true
|
||||||
|
browserDownloadProgressWindow.close()
|
||||||
|
}
|
||||||
|
ipcMain.once('browser-download-done', handler)
|
||||||
|
browserDownloadProgressWindow.once('closed', () => {
|
||||||
|
ipcMain.off('browser-download-done', handler)
|
||||||
|
if (processDone) {
|
||||||
|
resolve(pathOfDownloadedBrowser)
|
||||||
|
} else {
|
||||||
|
reject(new Error('USER_CANCELLED_CONFIG_BROWSER'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
+7
-5
@@ -9,7 +9,7 @@ export enum DOWNLOAD_ERROR_EXIT_CODE {
|
|||||||
DOWNLOAD_ERROR = 80
|
DOWNLOAD_ERROR = 80
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkAndDownloadDependenciesForInit = async () => {
|
export const downloadDependenciesForInit = async () => {
|
||||||
process.on('disconnect', () => app.exit())
|
process.on('disconnect', () => app.exit())
|
||||||
process.on('uncaughtException', () => app.exit(DOWNLOAD_ERROR_EXIT_CODE.DOWNLOAD_ERROR))
|
process.on('uncaughtException', () => app.exit(DOWNLOAD_ERROR_EXIT_CODE.DOWNLOAD_ERROR))
|
||||||
app.dock?.hide()
|
app.dock?.hide()
|
||||||
@@ -50,7 +50,7 @@ export const checkAndDownloadDependenciesForInit = async () => {
|
|||||||
timeoutTimer = setTimeout(() => {
|
timeoutTimer = setTimeout(() => {
|
||||||
// will encounter this when network disconnected when downloading
|
// will encounter this when network disconnected when downloading
|
||||||
promiseWithResolver.reject(new Error('PROGRESS_NOT_CHANGED_TOO_LONG'))
|
promiseWithResolver.reject(new Error('PROGRESS_NOT_CHANGED_TOO_LONG'))
|
||||||
}, 5 * 1000)
|
}, 10 * 1000)
|
||||||
} else {
|
} else {
|
||||||
clearTimeout(throttleProgressTimer)
|
clearTimeout(throttleProgressTimer)
|
||||||
throttleProgressTimer = null
|
throttleProgressTimer = null
|
||||||
@@ -73,7 +73,7 @@ export const checkAndDownloadDependenciesForInit = async () => {
|
|||||||
)
|
)
|
||||||
throttleProgressTimer = setTimeout(() => {
|
throttleProgressTimer = setTimeout(() => {
|
||||||
throttleProgressTimer = null
|
throttleProgressTimer = null
|
||||||
}, 2500)
|
}, 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -94,11 +94,13 @@ export const checkAndDownloadDependenciesForInit = async () => {
|
|||||||
pipe,
|
pipe,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR',
|
type: 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR',
|
||||||
...err instanceof Error ? {
|
...(err instanceof Error
|
||||||
|
? {
|
||||||
name: err.name,
|
name: err.name,
|
||||||
message: err.message,
|
message: err.message,
|
||||||
stack: err.stack
|
stack: err.stack
|
||||||
} : null
|
}
|
||||||
|
: null)
|
||||||
}) + '\r\n'
|
}) + '\r\n'
|
||||||
)
|
)
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
+1
-3
@@ -1,5 +1,3 @@
|
|||||||
import * as path from 'node:path'
|
|
||||||
import * as os from 'node:os'
|
|
||||||
import * as fs from 'node:fs'
|
import * as fs from 'node:fs'
|
||||||
import type { InstalledBrowser } from '@puppeteer/browsers'
|
import type { InstalledBrowser } from '@puppeteer/browsers'
|
||||||
import {
|
import {
|
||||||
@@ -10,6 +8,7 @@ import {
|
|||||||
} from '../browser-history'
|
} from '../browser-history'
|
||||||
import gtag from '../../../../utils/gtag'
|
import gtag from '../../../../utils/gtag'
|
||||||
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../../common/constant'
|
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../../common/constant'
|
||||||
|
import { cacheDir } from '../../../../constant'
|
||||||
|
|
||||||
const getPuppeteerManagerModule = async () => {
|
const getPuppeteerManagerModule = async () => {
|
||||||
const puppeteerManager = await import('@puppeteer/browsers')
|
const puppeteerManager = await import('@puppeteer/browsers')
|
||||||
@@ -17,7 +16,6 @@ const getPuppeteerManagerModule = async () => {
|
|||||||
return puppeteerManager
|
return puppeteerManager
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')
|
|
||||||
|
|
||||||
const getExpectCachedPuppeteerExecutable = async (): Promise<BrowserInfo> => {
|
const getExpectCachedPuppeteerExecutable = async (): Promise<BrowserInfo> => {
|
||||||
const puppeteerManager = await getPuppeteerManagerModule()
|
const puppeteerManager = await getPuppeteerManagerModule()
|
||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
getPublicDbFilePath
|
getPublicDbFilePath
|
||||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||||
// import { pipeWriteRegardlessError } from '../utils/pipe'
|
// import { pipeWriteRegardlessError } from '../utils/pipe'
|
||||||
import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
import { getAnyAvailablePuppeteerExecutable } from '../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
||||||
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
||||||
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat'
|
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat'
|
||||||
import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited'
|
import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited'
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { ChildProcess } from 'child_process'
|
import { ChildProcess } from 'child_process'
|
||||||
import * as JSONStream from 'JSONStream'
|
import * as JSONStream from 'JSONStream'
|
||||||
import { checkCookieListFormat } from '../../../../common/utils/cookie'
|
import { checkCookieListFormat } from '../../../../common/utils/cookie'
|
||||||
import { getAnyAvailablePuppeteerExecutable } from '../../../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index'
|
import { getAnyAvailablePuppeteerExecutable } from '../../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index'
|
||||||
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../../common/enums/auto-start-chat'
|
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../../common/enums/auto-start-chat'
|
||||||
import { mainWindow } from '../../../window/mainWindow'
|
import { mainWindow } from '../../../window/mainWindow'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import cheerio from 'cheerio'
|
|||||||
import { connectToDaemon, sendToDaemon } from '../OPEN_SETTING_WINDOW/connect-to-daemon'
|
import { connectToDaemon, sendToDaemon } from '../OPEN_SETTING_WINDOW/connect-to-daemon'
|
||||||
// import { pushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS } from '../../utils/screenshot'
|
// import { pushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS } from '../../utils/screenshot'
|
||||||
import { checkShouldExit } from '../../utils/worker'
|
import { checkShouldExit } from '../../utils/worker'
|
||||||
import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
import { getAnyAvailablePuppeteerExecutable } from '../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
||||||
import minimist from 'minimist'
|
import minimist from 'minimist'
|
||||||
import { checkCookieListFormat } from '../../../common/utils/cookie'
|
import { checkCookieListFormat } from '../../../common/utils/cookie'
|
||||||
import { loginWithCookieAssistant } from '../../features/login-with-cookie-assistant'
|
import { loginWithCookieAssistant } from '../../features/login-with-cookie-assistant'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import minimist from 'minimist'
|
import minimist from 'minimist'
|
||||||
import { runCommon } from './features/run-common';
|
import { runCommon } from './features/run-common'
|
||||||
import { launchDaemon } from './flow/OPEN_SETTING_WINDOW/launch-daemon';
|
import { launchDaemon } from './flow/OPEN_SETTING_WINDOW/launch-daemon'
|
||||||
import { app } from 'electron';
|
import { app } from 'electron'
|
||||||
|
|
||||||
// 捕获未处理的 EPIPE 错误
|
// 捕获未处理的 EPIPE 错误
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
@@ -9,13 +9,13 @@ process.on('uncaughtException', (err) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
throw err
|
throw err
|
||||||
});
|
})
|
||||||
|
|
||||||
const isUiDev = process.env.NODE_ENV === 'development'
|
const isUiDev = process.env.NODE_ENV === 'development'
|
||||||
const commandlineArgs = minimist(isUiDev ? process.argv.slice(2) : process.argv.slice(1))
|
const commandlineArgs = minimist(isUiDev ? process.argv.slice(2) : process.argv.slice(1))
|
||||||
console.log(commandlineArgs)
|
console.log(commandlineArgs)
|
||||||
|
|
||||||
const runMode = commandlineArgs['mode'];
|
const runMode = commandlineArgs['mode']
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
switch (runMode) {
|
switch (runMode) {
|
||||||
@@ -27,11 +27,9 @@ const runMode = commandlineArgs['mode'];
|
|||||||
waitForProcessHandShakeAndRunAutoChat()
|
waitForProcessHandShakeAndRunAutoChat()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'checkAndDownloadDependenciesForInit': {
|
case 'downloadDependenciesForInit': {
|
||||||
const { checkAndDownloadDependenciesForInit } = await import(
|
const { downloadDependenciesForInit } = await import('./flow/DOWNLOAD_DEPENDENCIES/index')
|
||||||
'./flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index'
|
downloadDependenciesForInit()
|
||||||
)
|
|
||||||
checkAndDownloadDependenciesForInit()
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'launchBossZhipinLoginPageWithPreloadExtension': {
|
case 'launchBossZhipinLoginPageWithPreloadExtension': {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { ChildProcess } from 'child_process'
|
|
||||||
import { BrowserWindow, ipcMain } from 'electron'
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getAnyAvailablePuppeteerExecutable } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
import { getAnyAvailablePuppeteerExecutable } from '../flow/DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
||||||
import * as childProcess from 'node:child_process'
|
|
||||||
import * as JSONStream from 'JSONStream'
|
|
||||||
import {
|
import {
|
||||||
getLastUsedAndAvailableBrowser,
|
getLastUsedAndAvailableBrowser,
|
||||||
saveLastUsedAndAvailableBrowserInfo
|
saveLastUsedAndAvailableBrowserInfo
|
||||||
} from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history'
|
} from '../flow/DOWNLOAD_DEPENDENCIES/utils/browser-history'
|
||||||
|
import { openBrowserDownloadWindow } from '../features/open-browser-download-window'
|
||||||
|
|
||||||
export let browserAssistantWindow: BrowserWindow | null = null
|
export let browserAssistantWindow: BrowserWindow | null = null
|
||||||
|
|
||||||
@@ -83,67 +81,15 @@ export function createBrowserAssistantWindow(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let subProcessOfCheckAndDownloadDependencies: ChildProcess | null = null
|
registerHandleWithWindow(browserAssistantWindow, 'download-browser-with-downloader', async () => {
|
||||||
registerHandleWithWindow(browserAssistantWindow, 'setup-dependencies', async () => {
|
return await openBrowserDownloadWindow({
|
||||||
if (subProcessOfCheckAndDownloadDependencies) {
|
windowOption: {
|
||||||
return
|
parent: browserAssistantWindow!,
|
||||||
|
modal: true,
|
||||||
|
show: true
|
||||||
}
|
}
|
||||||
subProcessOfCheckAndDownloadDependencies = childProcess.spawn(
|
|
||||||
process.argv[0],
|
|
||||||
[process.argv[1], `--mode=checkAndDownloadDependenciesForInit`],
|
|
||||||
{
|
|
||||||
stdio: [null, null, null, 'pipe', 'ipc']
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
subProcessOfCheckAndDownloadDependencies!.stdio[3]!.pipe(JSONStream.parse()).on(
|
|
||||||
'data',
|
|
||||||
(raw) => {
|
|
||||||
const data = raw
|
|
||||||
switch (data.type) {
|
|
||||||
case 'NEED_RESETUP_DEPENDENCIES':
|
|
||||||
case 'PUPPETEER_DOWNLOAD_PROGRESS': {
|
|
||||||
browserAssistantWindow?.webContents.send(data.type, data)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR': {
|
|
||||||
console.error(data)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
subProcessOfCheckAndDownloadDependencies!.once('exit', (exitCode) => {
|
|
||||||
switch (exitCode) {
|
|
||||||
case 0: {
|
|
||||||
resolve(exitCode)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
reject('PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR')
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subProcessOfCheckAndDownloadDependencies = null
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
const killHandler = async () => {
|
|
||||||
try {
|
|
||||||
subProcessOfCheckAndDownloadDependencies?.kill()
|
|
||||||
} catch {
|
|
||||||
//
|
|
||||||
} finally {
|
|
||||||
subProcessOfCheckAndDownloadDependencies = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
browserAssistantWindow.once('closed', () => {
|
|
||||||
killHandler()
|
|
||||||
})
|
|
||||||
|
|
||||||
return browserAssistantWindow!
|
return browserAssistantWindow!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { ChildProcess } from 'child_process'
|
||||||
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
|
import path from 'path'
|
||||||
|
import * as childProcess from 'node:child_process'
|
||||||
|
import * as JSONStream from 'JSONStream'
|
||||||
|
import * as fs from 'node:fs'
|
||||||
|
import { cacheDir } from '../constant'
|
||||||
|
import { EXPECT_CHROMIUM_BUILD_ID } from '../../common/constant'
|
||||||
|
import * as puppeteerManager from '@puppeteer/browsers'
|
||||||
|
|
||||||
|
export let browserDownloadProgressWindow: BrowserWindow | null = null
|
||||||
|
|
||||||
|
const registerHandleWithWindow = (
|
||||||
|
win: BrowserWindow,
|
||||||
|
...args: Parameters<typeof ipcMain.handle>
|
||||||
|
) => {
|
||||||
|
const [channel, handler] = args
|
||||||
|
ipcMain.handle(channel, handler)
|
||||||
|
win.once('closed', () => ipcMain.removeHandler(channel))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBrowserDownloadProgressWindow(
|
||||||
|
opt?: Electron.BrowserWindowConstructorOptions
|
||||||
|
): BrowserWindow {
|
||||||
|
// Create the browser window.
|
||||||
|
if (browserDownloadProgressWindow) {
|
||||||
|
browserDownloadProgressWindow!.close()
|
||||||
|
}
|
||||||
|
browserDownloadProgressWindow = new BrowserWindow({
|
||||||
|
width: 600,
|
||||||
|
height: 200,
|
||||||
|
resizable: false,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, '../preload/index.js'),
|
||||||
|
sandbox: false
|
||||||
|
},
|
||||||
|
...opt
|
||||||
|
})
|
||||||
|
|
||||||
|
browserDownloadProgressWindow.on('ready-to-show', () => {
|
||||||
|
browserDownloadProgressWindow!.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
// HMR for renderer base on electron-vite cli.
|
||||||
|
// Load the remote URL for development or the local html file for production.
|
||||||
|
if (process.env.NODE_ENV === 'development' && process.env['ELECTRON_RENDERER_URL']) {
|
||||||
|
browserDownloadProgressWindow.loadURL(
|
||||||
|
process.env['ELECTRON_RENDERER_URL'] + '#/browserDownloadProgress'
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
browserDownloadProgressWindow.loadURL(
|
||||||
|
'file://' + path.join(__dirname, '../renderer/index.html') + '#/browserDownloadProgress'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let subProcessOfCheckAndDownloadDependencies: ChildProcess | null = null
|
||||||
|
registerHandleWithWindow(browserDownloadProgressWindow, 'setup-dependencies', async () => {
|
||||||
|
if (subProcessOfCheckAndDownloadDependencies) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subProcessOfCheckAndDownloadDependencies = childProcess.spawn(
|
||||||
|
process.argv[0],
|
||||||
|
[process.argv[1], `--mode=downloadDependenciesForInit`],
|
||||||
|
{
|
||||||
|
stdio: [null, null, null, 'pipe', 'ipc']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
subProcessOfCheckAndDownloadDependencies!.stdio[3]!.pipe(JSONStream.parse()).on(
|
||||||
|
'data',
|
||||||
|
(raw) => {
|
||||||
|
const data = raw
|
||||||
|
switch (data.type) {
|
||||||
|
case 'NEED_RESETUP_DEPENDENCIES':
|
||||||
|
case 'PUPPETEER_DOWNLOAD_PROGRESS': {
|
||||||
|
browserDownloadProgressWindow?.webContents.send(data.type, data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR': {
|
||||||
|
console.error(data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
subProcessOfCheckAndDownloadDependencies!.once('exit', (exitCode) => {
|
||||||
|
const executablePath = puppeteerManager.computeExecutablePath({
|
||||||
|
browser: puppeteerManager.Browser.CHROME,
|
||||||
|
cacheDir,
|
||||||
|
buildId: EXPECT_CHROMIUM_BUILD_ID
|
||||||
|
})
|
||||||
|
if (exitCode === 0 && fs.existsSync(executablePath)) {
|
||||||
|
resolve(executablePath)
|
||||||
|
} else {
|
||||||
|
reject('PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR')
|
||||||
|
}
|
||||||
|
subProcessOfCheckAndDownloadDependencies = null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const killHandler = async () => {
|
||||||
|
try {
|
||||||
|
subProcessOfCheckAndDownloadDependencies?.kill()
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
} finally {
|
||||||
|
subProcessOfCheckAndDownloadDependencies = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
browserDownloadProgressWindow.once('closed', () => {
|
||||||
|
killHandler()
|
||||||
|
})
|
||||||
|
browserDownloadProgressWindow.once('closed', () => {
|
||||||
|
browserDownloadProgressWindow = null
|
||||||
|
})
|
||||||
|
|
||||||
|
return browserDownloadProgressWindow!
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ChildProcess } from 'child_process'
|
import { ChildProcess } from 'child_process'
|
||||||
import { BrowserWindow, ipcMain } from 'electron'
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getAnyAvailablePuppeteerExecutable } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
import { getAnyAvailablePuppeteerExecutable } from '../flow/DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
|
||||||
import * as childProcess from 'node:child_process'
|
import * as childProcess from 'node:child_process'
|
||||||
import * as JSONStream from 'JSONStream'
|
import * as JSONStream from 'JSONStream'
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,11 @@
|
|||||||
<li>
|
<li>
|
||||||
方案一:通过本程序下载 Google Chrome for Testing
|
方案一:通过本程序下载 Google Chrome for Testing
|
||||||
{{ EXPECT_CHROMIUM_BUILD_ID }} -
|
{{ EXPECT_CHROMIUM_BUILD_ID }} -
|
||||||
<a href="javascript:;">点击此处</a
|
<a href="javascript:;" @click="handleClickLaunchBrowserDownloader">点击此处</a
|
||||||
>即可下载;这个浏览器由本程序独占,不会影响到当前的 Google Chrome
|
>即可下载;这个浏览器仅供本程序使用,不会影响到当前 Google Chrome
|
||||||
安装。本程序开发过程中主要是使用这个浏览器测试的,<span color-orange
|
安装。本程序开发过程中主要是使用这个浏览器测试的,<span color-orange
|
||||||
>可以保证兼容性</span
|
>可以保证兼容性</span
|
||||||
>。但网络波动,有一定概率下载失败。如多次尝试后确实不能下载成功,请尝试方案二。<span
|
>。网络波动,有一定概率下载失败;如多次尝试后确实不能下载成功,请尝试方案二。<span
|
||||||
color-orange
|
color-orange
|
||||||
>(推荐)</span
|
>(推荐)</span
|
||||||
>
|
>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
>浏览器升级后某些功能不兼容导致本程序不能正确运行</span
|
>浏览器升级后某些功能不兼容导致本程序不能正确运行</span
|
||||||
>的问题。您可以<a href="javascript:;" @click="handleFeedbackClick"
|
>的问题。您可以<a href="javascript:;" @click="handleFeedbackClick"
|
||||||
>提交 Issue</a
|
>提交 Issue</a
|
||||||
>来反馈新版本浏览器不能正常运行的问题,同时请再尝试方法一。
|
>来反馈新版本浏览器不能正常运行的问题,同时请再尝试方案一。
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,13 +142,19 @@ async function autoDetectPuppeteerExecutable() {
|
|||||||
noSave: true
|
noSave: true
|
||||||
})
|
})
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ElMessage.warning({
|
ElMessage({
|
||||||
message: '未检测到可用浏览器的可执行文件',
|
message: '未检测到可用浏览器的可执行文件',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
|
grouping: true
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
formData.value.browserPath = result.executablePath
|
formData.value.browserPath = result.executablePath
|
||||||
|
ElMessage({
|
||||||
|
message: '已找到可用浏览器,可执行文件路径已填入输入框',
|
||||||
|
type: 'success',
|
||||||
|
grouping: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function browserExecutableFile() {
|
async function browserExecutableFile() {
|
||||||
@@ -177,7 +183,9 @@ function handleCancel() {
|
|||||||
gtagRenderer('cancel_clicked')
|
gtagRenderer('cancel_clicked')
|
||||||
window.close()
|
window.close()
|
||||||
}
|
}
|
||||||
|
const formRef = ref()
|
||||||
async function handleSave() {
|
async function handleSave() {
|
||||||
|
await formRef.value.validate()
|
||||||
await ipcRenderer.invoke('save-last-used-and-available-browser-info', {
|
await ipcRenderer.invoke('save-last-used-and-available-browser-info', {
|
||||||
executablePath: formData.value.browserPath,
|
executablePath: formData.value.browserPath,
|
||||||
browser: ''
|
browser: ''
|
||||||
@@ -188,6 +196,18 @@ const handleFeedbackClick = () => {
|
|||||||
gtagRenderer('goto_feedback_for_ba_clicked')
|
gtagRenderer('goto_feedback_for_ba_clicked')
|
||||||
electron.ipcRenderer.send('send-feed-back-to-github-issue')
|
electron.ipcRenderer.send('send-feed-back-to-github-issue')
|
||||||
}
|
}
|
||||||
|
const handleClickLaunchBrowserDownloader = async () => {
|
||||||
|
gtagRenderer('launch_browser_downloader_clicked')
|
||||||
|
const downloadedBrowserPath = await electron.ipcRenderer.invoke('download-browser-with-downloader')
|
||||||
|
if (downloadedBrowserPath) {
|
||||||
|
formData.value.browserPath = downloadedBrowserPath
|
||||||
|
ElMessage({
|
||||||
|
message: '浏览器下载成功,可执行文件路径已填入输入框',
|
||||||
|
type: 'success',
|
||||||
|
grouping: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex flex-col flex-items-start flex-justify-start" v-if="!dependenciesStatus.puppeteerExecutableAvailable">
|
|
||||||
<div mb14px>正在下载兼容的浏览器</div>
|
|
||||||
<el-progress
|
|
||||||
:percentage="browserDownloadPercentage"
|
|
||||||
:format="(n) => `${n.toFixed(1)}%`"
|
|
||||||
:stroke-width="10"
|
|
||||||
class="w400px"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, onUnmounted, PropType, h } from 'vue'
|
|
||||||
import { ElMessageBox } from 'element-plus'
|
|
||||||
import { gtagRenderer } from '@renderer/utils/gtag'
|
|
||||||
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
|
||||||
import FailMessage from './FailMessage.vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
dependenciesStatus: {
|
|
||||||
type: Object as PropType<Record<string, boolean>>,
|
|
||||||
default: () => ({})
|
|
||||||
},
|
|
||||||
processWaitee: Object
|
|
||||||
})
|
|
||||||
|
|
||||||
const browserDownloadPercentage = ref(0)
|
|
||||||
const handleBrowserDownloadProgress = (ev, { downloadedBytes, totalBytes }) => {
|
|
||||||
browserDownloadPercentage.value = (downloadedBytes / totalBytes) * 100
|
|
||||||
}
|
|
||||||
electron.ipcRenderer.on('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
|
|
||||||
onUnmounted(() =>
|
|
||||||
electron.ipcRenderer.removeListener('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
|
|
||||||
)
|
|
||||||
const downloadProcessExitCode = ref(0)
|
|
||||||
|
|
||||||
const processDownloadBrowser = async () => {
|
|
||||||
downloadProcessExitCode.value = 0
|
|
||||||
browserDownloadPercentage.value = 0
|
|
||||||
let restRetriedTime = 2
|
|
||||||
while (restRetriedTime > 0) {
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
await electron.ipcRenderer.invoke('setup-dependencies')
|
|
||||||
browserDownloadPercentage.value = 100
|
|
||||||
} catch (err) {
|
|
||||||
downloadProcessExitCode.value = 1
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} catch (err) {
|
|
||||||
restRetriedTime--
|
|
||||||
if (restRetriedTime === 0) {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
await sleep(5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const promiseList: Array<Promise<void>> = []
|
|
||||||
const processTasks = async () => {
|
|
||||||
if (!props.dependenciesStatus.puppeteerExecutableAvailable) {
|
|
||||||
gtagRenderer('start_download_puppeteer')
|
|
||||||
const p = processDownloadBrowser()
|
|
||||||
promiseList.push(p)
|
|
||||||
p.then(() => {
|
|
||||||
gtagRenderer('puppeteer_download_success')
|
|
||||||
props.dependenciesStatus.puppeteerExecutableAvailable = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
while (promiseList.length) {
|
|
||||||
const p = promiseList.shift()!
|
|
||||||
try {
|
|
||||||
p.then(() => {
|
|
||||||
if (!promiseList.length) {
|
|
||||||
props.processWaitee?.resolve?.()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await p
|
|
||||||
} catch {
|
|
||||||
gtagRenderer('encounter_error_when_download_deps')
|
|
||||||
await ElMessageBox.confirm(h(FailMessage), {
|
|
||||||
closeOnClickModal: false,
|
|
||||||
closeOnPressEscape: false,
|
|
||||||
showClose: false,
|
|
||||||
type: 'error',
|
|
||||||
cancelButtonText: '退出程序',
|
|
||||||
confirmButtonText: '重试'
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
gtagRenderer('start_retry_download_deps')
|
|
||||||
processTasks()
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
gtagRenderer('cancel_download_deps_and_exit')
|
|
||||||
promiseList.length = 0
|
|
||||||
electron.ipcRenderer.invoke('exit-app-immediately')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processTasks()
|
|
||||||
</script>
|
|
||||||
+14
-14
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>核心组件下载失败,请重试。</p>
|
<p>浏览器下载失败,请重试,或使用其他方式下载</p>
|
||||||
<br />
|
<!-- <br />
|
||||||
<br />
|
<br />
|
||||||
<p>
|
<p>
|
||||||
<b text-orange>提示:</b>由于网络颠簸,如果多次重试仍然失败,请 <el-button
|
<b text-orange>提示:</b>由于网络颠簸,如果多次重试仍然失败,请 <el-button
|
||||||
@@ -12,23 +12,23 @@
|
|||||||
>点击此处</el-button
|
>点击此处</el-button
|
||||||
> 下载最新版本 Google Chrome
|
> 下载最新版本 Google Chrome
|
||||||
浏览器,安装完毕后,重新打开本程序,程序会自动检测该浏览器并使用它。
|
浏览器,安装完毕后,重新打开本程序,程序会自动检测该浏览器并使用它。
|
||||||
</p>
|
</p> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { gtagRenderer } from '@renderer/utils/gtag'
|
// import { gtagRenderer } from '@renderer/utils/gtag'
|
||||||
import debounce from 'lodash/debounce'
|
// import debounce from 'lodash/debounce'
|
||||||
const { ipcRenderer } = electron
|
// const { ipcRenderer } = electron
|
||||||
|
|
||||||
const handleOpenChromeDownloadPage = debounce(
|
// const handleOpenChromeDownloadPage = debounce(
|
||||||
async () => {
|
// async () => {
|
||||||
gtagRenderer('open_chrome_download_page_clicked')
|
// gtagRenderer('open_chrome_download_page_clicked')
|
||||||
ipcRenderer.send('open-external-link', 'https://www.google.cn/chrome/')
|
// ipcRenderer.send('open-external-link', 'https://www.google.cn/chrome/')
|
||||||
},
|
// },
|
||||||
1000,
|
// 1000,
|
||||||
{ leading: true, trailing: false }
|
// { leading: true, trailing: false }
|
||||||
)
|
// )
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<!-- flex-items- -->
|
||||||
|
<div class="flex flex-col flex-justify-center w500px h-full ml-auto mr-auto">
|
||||||
|
<div font-size-14px>正在下载 Google Chrome for Testing {{ EXPECT_CHROMIUM_BUILD_ID }}</div>
|
||||||
|
<el-progress
|
||||||
|
:percentage="browserDownloadPercentage"
|
||||||
|
:format="(n) => `${n.toFixed(1)}%`"
|
||||||
|
:stroke-width="10"
|
||||||
|
class="w500px"
|
||||||
|
mt10px
|
||||||
|
/>
|
||||||
|
<div mt10px>
|
||||||
|
<el-button @click="handleCancelDownload">取消下载</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onUnmounted, h } from 'vue'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { gtagRenderer } from '@renderer/utils/gtag'
|
||||||
|
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
||||||
|
import FailMessage from './FailMessage.vue'
|
||||||
|
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../common/constant'
|
||||||
|
|
||||||
|
const browserDownloadPercentage = ref(0)
|
||||||
|
const handleBrowserDownloadProgress = (ev, { downloadedBytes, totalBytes }) => {
|
||||||
|
browserDownloadPercentage.value = (downloadedBytes / totalBytes) * 100
|
||||||
|
}
|
||||||
|
electron.ipcRenderer.on('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
|
||||||
|
onUnmounted(() =>
|
||||||
|
electron.ipcRenderer.removeListener('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
|
||||||
|
)
|
||||||
|
const downloadProcessExitCode = ref(0)
|
||||||
|
|
||||||
|
let executablePath
|
||||||
|
const processDownloadBrowser = async () => {
|
||||||
|
downloadProcessExitCode.value = 0
|
||||||
|
browserDownloadPercentage.value = 0
|
||||||
|
let restRetriedTime = 2
|
||||||
|
while (restRetriedTime > 0) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
executablePath = await electron.ipcRenderer.invoke('setup-dependencies')
|
||||||
|
browserDownloadPercentage.value = 100
|
||||||
|
} catch (err) {
|
||||||
|
downloadProcessExitCode.value = 1
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} catch (err) {
|
||||||
|
restRetriedTime--
|
||||||
|
if (restRetriedTime === 0) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
await sleep(5000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processTasks = async () => {
|
||||||
|
try {
|
||||||
|
await processDownloadBrowser()
|
||||||
|
electron.ipcRenderer.send('browser-download-done', executablePath)
|
||||||
|
} catch (err) {
|
||||||
|
gtagRenderer('encounter_error_when_download_deps')
|
||||||
|
await ElMessageBox.confirm(h(FailMessage), {
|
||||||
|
closeOnClickModal: false,
|
||||||
|
closeOnPressEscape: false,
|
||||||
|
showClose: false,
|
||||||
|
type: 'error',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
confirmButtonText: '重试'
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
gtagRenderer('start_retry_download_deps')
|
||||||
|
processTasks()
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
gtagRenderer('cancel_download_deps_from_err_dialog')
|
||||||
|
window.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processTasks()
|
||||||
|
|
||||||
|
function handleCancelDownload() {
|
||||||
|
gtagRenderer('cancel_download_deps_from_cancel_btn')
|
||||||
|
window.close()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -22,16 +22,14 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('@renderer/page/BrowserAssistant/index.vue'),
|
component: () => import('@renderer/page/BrowserAssistant/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '浏览器助手'
|
title: '浏览器助手'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
children: [
|
|
||||||
{
|
{
|
||||||
path: '/downloadingDependencies',
|
path: '/browserDownloadProgress',
|
||||||
component: () => import('@renderer/page/BrowserAssistant/page/DownloadingDependencies.vue'),
|
component: () => import('@renderer/page/BrowserDownloadProgress/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '正在下载核心组件'
|
title: '正在下载浏览器'
|
||||||
}
|
}
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/llmConfig',
|
path: '/llmConfig',
|
||||||
|
|||||||
Reference in New Issue
Block a user