From 3a31f7d1863042dc78b245d2c6c65d101f5559c1 Mon Sep 17 00:00:00 2001 From: geekgeekrun Date: Sun, 24 Mar 2024 13:36:27 +0800 Subject: [PATCH] add suicide timer in auto chat main for parent and child process don't have any communication after child process spawned in 10s. --- .../ui/src/common/enums/auto-start-chat.ts | 3 +- .../index.ts | 24 +++++++-- .../index.ts | 50 ++++++++++++++++++- packages/ui/src/main/index.ts | 6 ++- packages/ui/src/main/window/mainWindow.ts | 2 +- 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/packages/ui/src/common/enums/auto-start-chat.ts b/packages/ui/src/common/enums/auto-start-chat.ts index 5be6e34..a0e001a 100644 --- a/packages/ui/src/common/enums/auto-start-chat.ts +++ b/packages/ui/src/common/enums/auto-start-chat.ts @@ -5,5 +5,6 @@ export enum AUTO_CHAT_ERROR_EXIT_CODE { ERR_INTERNET_DISCONNECTED = 83, ACCESS_IS_DENIED = 84, PUPPETEER_IS_NOT_EXECUTABLE = 85, - DAEMON_PROCESS_SUICIDE = 86 + AUTO_START_CHAT_DAEMON_PROCESS_SUICIDE = 86, + AUTO_START_CHAT_MAIN_PROCESS_SUICIDE = 87, } diff --git a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_DAEMON/index.ts b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_DAEMON/index.ts index 35cc3bc..a98aae4 100644 --- a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_DAEMON/index.ts +++ b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_DAEMON/index.ts @@ -2,7 +2,7 @@ import { sleep } from '@geekgeekrun/utils/sleep.mjs' import childProcess from 'node:child_process' import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat' import { app } from 'electron' -import fs from 'node:fs' +import fs, { WriteStream } from 'node:fs' import { pipeWriteRegardlessError } from '../utils/pipe' import * as JSONStream from 'JSONStream' @@ -23,6 +23,24 @@ function runWithDaemon() { } }) + subProcessOfCore!.stdio[3]!.pipe(JSONStream.parse()).on('data', async (raw) => { + const data = raw + switch (data.type) { + case 'AUTO_START_CHAT_MAIN_PROCESS_STARTUP': { + pipeWriteRegardlessError( + subProcessOfCore!.stdio[3]! as WriteStream, + JSON.stringify({ + type: 'GEEK_AUTO_START_CHAT_CAN_BE_RUN' + }) + ) + break + } + default: { + return + } + } + }) + subProcessOfCore.once('exit', async (exitCode: number) => { if ( [...Object.values(AUTO_CHAT_ERROR_EXIT_CODE)] @@ -47,7 +65,7 @@ function runWithDaemon() { let suicideTimer: NodeJS.Timeout | null = null const setSuicideTimer = () => (suicideTimer = setTimeout(() => { - app.exit(AUTO_CHAT_ERROR_EXIT_CODE.DAEMON_PROCESS_SUICIDE) + app.exit(AUTO_CHAT_ERROR_EXIT_CODE.AUTO_START_CHAT_DAEMON_PROCESS_SUICIDE) }, 10000)) const clearSuicideTimer = () => { if (suicideTimer) { @@ -90,7 +108,7 @@ export function runAutoChatWithDaemon() { pipeWriteRegardlessError( pipe, JSON.stringify({ - type: 'DAEMON_PROCESS_STARTUP' + type: 'AUTO_START_CHAT_DAEMON_PROCESS_STARTUP' }) ) } 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 42cbdbc..f0db5f4 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 @@ -11,6 +11,7 @@ import { pipeWriteRegardlessError } from '../utils/pipe' import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable' import { sleep } from '@geekgeekrun/utils/sleep.mjs' import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat' +import * as JSONStream from 'JSONStream' import SqlitePluginModule from '@geekgeekrun/sqlite-plugin' const { default: SqlitePlugin } = SqlitePluginModule @@ -32,13 +33,15 @@ const initPlugins = (hooks) => { } let isParentProcessDisconnect = false +process.once('disconnect', () => { + isParentProcessDisconnect = true +}) -export const runAutoChat = async () => { +const runAutoChat = async () => { const { initPuppeteer, mainLoop, closeBrowserWindow, autoStartChatEventBus } = await import( '@geekgeekrun/geek-auto-start-chat-with-boss/index.mjs' ) process.on('disconnect', () => { - isParentProcessDisconnect = true closeBrowserWindow() app.exit() }) @@ -130,3 +133,46 @@ export const runAutoChat = async () => { } } } +// suicide timer for parent and child process don't have any communication after child process spawned. +let suicideTimer: NodeJS.Timeout | null = null +const setSuicideTimer = () => + (suicideTimer = setTimeout(() => { + app.exit(AUTO_CHAT_ERROR_EXIT_CODE.AUTO_START_CHAT_MAIN_PROCESS_SUICIDE) + }, 10000)) +const clearSuicideTimer = () => { + if (suicideTimer) { + clearTimeout(suicideTimer) + } + suicideTimer = null +} + +export const waitForProcessHandShakeAndRunAutoChat = () => { + setSuicideTimer() + + const pipeForRead: fs.ReadStream = fs.createReadStream(null, { fd: 3 }) + const pipeForReadWithJsonParser = pipeForRead.pipe(JSONStream.parse()) + pipeForReadWithJsonParser?.on('data', function waitForCanRun(data) { + if (data.type === 'GEEK_AUTO_START_CHAT_CAN_BE_RUN') { + pipeForReadWithJsonParser.off('data', waitForCanRun) + clearSuicideTimer() + runAutoChat() + + // if don't call close, when kill child process, child process will ANR. + pipeForRead.close() + } + }) + + let pipe: null | fs.WriteStream = null + try { + pipe = fs.createWriteStream(null, { fd: 3 }) + } catch { + console.error('pipe is not available') + app.exit(1) + } + pipeWriteRegardlessError( + pipe, + JSON.stringify({ + type: 'AUTO_START_CHAT_MAIN_PROCESS_STARTUP' + }) + ) +} diff --git a/packages/ui/src/main/index.ts b/packages/ui/src/main/index.ts index e5f00a0..942bd62 100644 --- a/packages/ui/src/main/index.ts +++ b/packages/ui/src/main/index.ts @@ -3,8 +3,10 @@ const runMode = process.env.MAIN_BOSSGEEKGO_UI_RUN_MODE ;(async () => { switch (runMode) { case 'geekAutoStartWithBossMain': { - const { runAutoChat } = await import('./flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index') - runAutoChat() + const { waitForProcessHandShakeAndRunAutoChat } = await import( + './flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index' + ) + waitForProcessHandShakeAndRunAutoChat() break } case 'geekAutoStartWithBossDaemon': { diff --git a/packages/ui/src/main/window/mainWindow.ts b/packages/ui/src/main/window/mainWindow.ts index 6850a2d..9076ea7 100644 --- a/packages/ui/src/main/window/mainWindow.ts +++ b/packages/ui/src/main/window/mainWindow.ts @@ -135,7 +135,7 @@ export function createMainWindow(): void { subProcessOfPuppeteer!.stdio[3]!.pipe(JSONStream.parse()).on('data', async (raw) => { const data = raw switch (data.type) { - case 'DAEMON_PROCESS_STARTUP': { + case 'AUTO_START_CHAT_DAEMON_PROCESS_STARTUP': { subProcessOfPuppeteer!.stdio[3]!.write( JSON.stringify({ type: 'GEEK_AUTO_START_CHAT_CAN_BE_RUN'