diff --git a/packages/pm/daemon.js b/packages/pm/daemon.js index 3f54c19..d4a54ef 100644 --- a/packages/pm/daemon.js +++ b/packages/pm/daemon.js @@ -149,10 +149,10 @@ function handleMessage(socket, message) { } return } - case 'worker-message': { + case 'worker-to-gui-message': { // 转发工具进程消息到GUI客户端 broadcastToGUI({ - type: 'worker-message', + type: 'worker-to-gui-message', workerId: workerId, data: message.data || message, timestamp: Date.now() diff --git a/packages/ui/src/common/prerequisite-step-by-step-check.ts b/packages/ui/src/common/prerequisite-step-by-step-check.ts new file mode 100644 index 0000000..b36d9ca --- /dev/null +++ b/packages/ui/src/common/prerequisite-step-by-step-check.ts @@ -0,0 +1,17 @@ +export const getAutoStartChatSteps = () => [{ + id: 'worker-launch', + describe: '启动子进程', +}, +// { +// id: 'basic-cookie-check', +// describe: 'Cookie 格式检查', +// }, +{ + id: 'puppeteer-executable-check', + describe: 'Puppeteer 可执行程序检查', +}, +{ + id: 'login-status-check', + describe: '登录状态检查', +} +] \ No newline at end of file diff --git a/packages/ui/src/main/features/boss-user-info-response-plugin.ts b/packages/ui/src/main/features/boss-user-info-response-plugin.ts new file mode 100644 index 0000000..1498571 --- /dev/null +++ b/packages/ui/src/main/features/boss-user-info-response-plugin.ts @@ -0,0 +1,29 @@ +import { sendToDaemon } from "../flow/OPEN_SETTING_WINDOW/connect-to-daemon" +import minimist from 'minimist' + +const runRecordId = minimist(process.argv.slice(2))['run-record-id'] ?? null +export function pushUserInfoValidStatus (userInfoResponse) { + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'login-status-check', + status: userInfoResponse.code === 0 ? 'fulfilled' : 'rejected' + }, + runRecordId + } + }) +} + +export class UserResponseInfoPlugin { + apply(hooks) { + hooks.userInfoResponse.tapPromise( + "UserResponseInfoPlugin", + (userInfoResponse) => { + pushUserInfoValidStatus(userInfoResponse) + return Promise.resolve() + } + ) + } +} \ No newline at end of file diff --git a/packages/ui/src/main/features/run-common.ts b/packages/ui/src/main/features/run-common.ts index 169ec5f..d3696c5 100644 --- a/packages/ui/src/main/features/run-common.ts +++ b/packages/ui/src/main/features/run-common.ts @@ -3,33 +3,37 @@ import { sendToDaemon } from "../flow/OPEN_SETTING_WINDOW/connect-to-daemon" import { saveAndGetCurrentRunRecord } from "../flow/OPEN_SETTING_WINDOW/utils/db" export async function runCommon ({ mode }) { - const currentRunRecord = (await saveAndGetCurrentRunRecord())?.data - const subProcessEnv = { - ...process.env, - GEEKGEEKRUND_NO_AUTO_RESTART_EXIT_CODE: [ - AUTO_CHAT_ERROR_EXIT_CODE.PUPPETEER_IS_NOT_EXECUTABLE, - AUTO_CHAT_ERROR_EXIT_CODE.LOGIN_STATUS_INVALID, - AUTO_CHAT_ERROR_EXIT_CODE.LLM_UNAVAILABLE - ].join(',') + const currentRunRecord = (await saveAndGetCurrentRunRecord())?.data + const subProcessEnv = { + ...process.env, + GEEKGEEKRUND_NO_AUTO_RESTART_EXIT_CODE: [ + AUTO_CHAT_ERROR_EXIT_CODE.PUPPETEER_IS_NOT_EXECUTABLE, + AUTO_CHAT_ERROR_EXIT_CODE.LOGIN_STATUS_INVALID, + AUTO_CHAT_ERROR_EXIT_CODE.LLM_UNAVAILABLE + ].join(',') + } + const args = process.env.NODE_ENV === 'development' ? [ + process.argv[1], + `--mode=${mode}`, + `--run-record-id=${currentRunRecord?.id || 0}` + ] : [ + `--mode=${mode}`, + `--run-record-id=${currentRunRecord?.id || 0}` + ] + await sendToDaemon( + { + type: 'start-worker', + workerId: mode, + command: process.argv[0], + args, + env: subProcessEnv + }, + { + needCallback: true } - const args = process.env.NODE_ENV === 'development' ? [ - process.argv[1], - `--mode=${mode}`, - `--run-record-id=${currentRunRecord?.id || 0}` - ] : [ - `--mode=${mode}`, - `--run-record-id=${currentRunRecord?.id || 0}` - ] - await sendToDaemon( - { - type: 'start-worker', - workerId: mode, - command: process.argv[0], - args, - env: subProcessEnv - }, - { - needCallback: true - } - ) + ) + + return { + runRecordId: currentRunRecord?.id + } } \ No newline at end of file diff --git a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts index 65fff2a..2fc478b 100644 --- a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts +++ b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts @@ -10,13 +10,14 @@ import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPEND import { sleep } from '@geekgeekrun/utils/sleep.mjs' import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat' import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited' - +import minimist from 'minimist' import SqlitePluginModule from '@geekgeekrun/sqlite-plugin' import gtag from '../../utils/gtag' import GtagPlugin from '../../utils/gtag/GtagPlugin' import { connectToDaemon, sendToDaemon } from '../OPEN_SETTING_WINDOW/connect-to-daemon' import { PeriodPushCurrentPageScreenshotPlugin } from '../../utils/screenshot' import { checkShouldExit } from '../../utils/worker' +import { UserResponseInfoPlugin } from '../../features/boss-user-info-response-plugin' const { default: SqlitePlugin } = SqlitePluginModule const rerunInterval = (() => { @@ -35,15 +36,39 @@ const initPlugins = (hooks) => { new SqlitePlugin(getPublicDbFilePath()).apply(hooks) new GtagPlugin().apply(hooks) new PeriodPushCurrentPageScreenshotPlugin().apply(hooks) + new UserResponseInfoPlugin().apply(hooks) } +const runRecordId = minimist(process.argv.slice(2))['run-record-id'] ?? null const runAutoChat = async () => { app.dock?.hide() const puppeteerExecutable = await getAnyAvailablePuppeteerExecutable() if (!puppeteerExecutable) { + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'puppeteer-executable-check', + status: 'rejected' + }, + runRecordId + } + }) app.exit(AUTO_CHAT_ERROR_EXIT_CODE.PUPPETEER_IS_NOT_EXECUTABLE) return } + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'puppeteer-executable-check', + status: 'fulfilled' + }, + runRecordId + } + }) process.env.PUPPETEER_EXECUTABLE_PATH = puppeteerExecutable.executablePath const { initPuppeteer, mainLoop, closeBrowserWindow, autoStartChatEventBus } = await import( '@geekgeekrun/geek-auto-start-chat-with-boss/index.mjs' @@ -131,6 +156,17 @@ export const waitForProcessHandShakeAndRunAutoChat = async () => { needCallback: true } ) + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'worker-launch', + status: 'fulfilled' + }, + runRecordId + } + }) runAutoChat() } diff --git a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts index 20d237c..cc11b4e 100644 --- a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts +++ b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts @@ -202,7 +202,7 @@ export default function initIpc() { ipcMain.handle('run-geek-auto-start-chat-with-boss', async (ev) => { const mode = 'geekAutoStartWithBossMain' - await runCommon({ mode }) + const { runRecordId } = await runCommon({ mode }) daemonEE.on('message', function handler (message) { if (message.workerId !== mode) { return @@ -226,11 +226,12 @@ export default function initIpc() { } } }) + return { runRecordId } }) ipcMain.handle('run-read-no-reply-auto-reminder', async () => { const mode = 'readNoReplyAutoReminderMain' - await runCommon({ mode }) + const { runRecordId } = await runCommon({ mode }) daemonEE.on('message', function handler (message) { if (message.workerId !== mode) { return @@ -254,6 +255,7 @@ export default function initIpc() { } } }) + return { runRecordId } }) ipcMain.handle('check-dependencies', async () => { diff --git a/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts b/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts index a35b243..e107536 100644 --- a/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts +++ b/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts @@ -28,6 +28,7 @@ import { connectToDaemon, sendToDaemon } from '../OPEN_SETTING_WINDOW/connect-to import { pushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS } from '../../utils/screenshot' import { checkShouldExit } from '../../utils/worker' import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable' +import minimist from 'minimist' const throttleIntervalMinutes = readConfigFile('boss.json').autoReminder?.throttleIntervalMinutes ?? 10 @@ -249,12 +250,34 @@ const mainLoop = async () => { // #region if (currentPageUrl.startsWith('https://www.zhipin.com/web/user/')) { writeStorageFile('boss-cookies.json', []) + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'login-status-check', + status: 'rejected' + }, + runRecordId + } + }) throw new Error('LOGIN_STATUS_INVALID') } if ( currentPageUrl.startsWith('https://www.zhipin.com/web/common/403.html') || currentPageUrl.startsWith('https://www.zhipin.com/web/common/error.html') ) { + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'login-status-check', + status: 'rejected' + }, + runRecordId + } + }) throw new Error('ACCESS_IS_DENIED') } if (currentPageUrl.startsWith('https://www.zhipin.com/web/user/safe/verify-slider')) { @@ -277,9 +300,31 @@ const mainLoop = async () => { }) if (validateRes.code === 0) { await storeStorage(pageMapByName.boss) + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'login-status-check', + status: 'rejected' + }, + runRecordId + } + }) throw new Error('CAPTCHA_PASSED_AND_NEED_RESTART') } } + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'login-status-check', + status: 'fulfilled' + }, + runRecordId + } + }) // #endregion // check set security question tip modal let setSecurityQuestionTipModelProxy = await pageMapByName.boss!.$( @@ -478,19 +523,53 @@ const rerunInterval = (() => { return v })() +const runRecordId = minimist(process.argv.slice(2))['run-record-id'] ?? null export async function runEntry() { app.dock?.hide() - const puppeteerExecutable = await getAnyAvailablePuppeteerExecutable() - if (!puppeteerExecutable) { - throw new Error(`PUPPETEER_IS_NOT_EXECUTABLE`) - } - process.env.PUPPETEER_EXECUTABLE_PATH = puppeteerExecutable.executablePath await connectToDaemon() await sendToDaemon({ type: 'ping' }, { needCallback: true }) + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'worker-launch', + status: 'fulfilled' + }, + runRecordId + } + }) + const puppeteerExecutable = await getAnyAvailablePuppeteerExecutable() + if (!puppeteerExecutable) { + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'puppeteer-executable-check', + status: 'rejected' + }, + runRecordId + } + }) + throw new Error(`PUPPETEER_IS_NOT_EXECUTABLE`) + } + sendToDaemon({ + type: 'worker-to-gui-message', + data: { + type: 'prerequisite-step-by-step-checkstep-by-step-check', + step: { + id: 'puppeteer-executable-check', + status: 'fulfilled' + }, + runRecordId + } + }) + process.env.PUPPETEER_EXECUTABLE_PATH = puppeteerExecutable.executablePath while (true) { try { await mainLoop() diff --git a/packages/ui/src/main/window/mainWindow.ts b/packages/ui/src/main/window/mainWindow.ts index 79797a2..15d2c5c 100644 --- a/packages/ui/src/main/window/mainWindow.ts +++ b/packages/ui/src/main/window/mainWindow.ts @@ -3,6 +3,7 @@ import path from 'path' import { openDevTools } from '../commands' import { createFirstLaunchNoticeWindow } from './firstLaunchNoticeWindow' import { isFirstLaunchNoticeApproveFlagExist } from '../features/first-launch-notice-window' +import { daemonEE } from '../flow/OPEN_SETTING_WINDOW/connect-to-daemon' export let mainWindow: BrowserWindow | null = null export function createMainWindow(): BrowserWindow { @@ -58,5 +59,10 @@ export function createMainWindow(): BrowserWindow { mainWindow!.once('closed', () => { mainWindow = null }) + daemonEE.on('message', (message) => { + if (message.type === 'worker-to-gui-message') { + mainWindow?.webContents?.send('worker-to-gui-message', message) + } + }) return mainWindow! } diff --git a/packages/ui/src/renderer/src/features/RunningOverlay/index.vue b/packages/ui/src/renderer/src/features/RunningOverlay/index.vue index c93b265..2d1be37 100644 --- a/packages/ui/src/renderer/src/features/RunningOverlay/index.vue +++ b/packages/ui/src/renderer/src/features/RunningOverlay/index.vue @@ -6,8 +6,22 @@ :close-on-press-escape="false" :show-close="false" > + +
+ +
-
任务运行中!
+
任务运行中
@@ -17,20 +31,68 @@