mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-09 01:17:06 +08:00
fix screenshot error when page closed; catch EPIPE globally; rigister gui process
This commit is contained in:
+39
-84
@@ -119,70 +119,36 @@ function handleMessage(socket, message) {
|
|||||||
});
|
});
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (message.type === 'gui-register') {
|
||||||
// 工具进程注册消息
|
// GUI客户端的控制消息
|
||||||
if (message.type === 'worker-register') {
|
// 标记为GUI客户端
|
||||||
const workerId = message.workerId;
|
if (!guiClients.has(socket)) {
|
||||||
|
guiClients.add(socket);
|
||||||
// 检查是否在停止列表中(防止竞态条件)
|
|
||||||
if (stoppedWorkers.has(workerId)) {
|
|
||||||
console.log(`工具进程 ${workerId} 尝试注册,但已被标记为停止,拒绝注册`);
|
|
||||||
sendResponse(socket, _callbackUuid, {
|
|
||||||
error: `工具进程 ${workerId} 已被停止`,
|
|
||||||
shouldExit: true // 通知子进程应该退出
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const workerInfo = workers.get(workerId);
|
|
||||||
if (workerInfo) {
|
|
||||||
workerInfo.socket = socket;
|
|
||||||
console.log(`工具进程 ${workerId} 已注册TCP连接`);
|
|
||||||
sendResponse(socket, _callbackUuid, {
|
|
||||||
success: true,
|
|
||||||
type: 'worker-registered',
|
|
||||||
message: `工具进程 ${workerId} 连接已注册`
|
|
||||||
});
|
|
||||||
// 通知GUI客户端
|
|
||||||
broadcastToGUI({
|
|
||||||
type: 'worker-connected',
|
|
||||||
workerId: workerId,
|
|
||||||
message: `工具进程 ${workerId} 已连接`
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 如果workerInfo不存在,但不在停止列表中,可能是进程启动但还未完全初始化
|
|
||||||
// 这种情况下也拒绝注册,让进程退出
|
|
||||||
if (!stoppedWorkers.has(workerId)) {
|
|
||||||
console.log(`工具进程 ${workerId} 尝试注册,但workerInfo不存在`);
|
|
||||||
}
|
|
||||||
sendResponse(socket, _callbackUuid, {
|
|
||||||
error: `工具进程 ${workerId} 未找到`,
|
|
||||||
shouldExit: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 工具进程查询是否应该退出
|
|
||||||
if (message.type === 'check-should-exit') {
|
|
||||||
const workerId = message.workerId;
|
|
||||||
const shouldExit = stoppedWorkers.has(workerId) || !workers.has(workerId);
|
|
||||||
|
|
||||||
sendResponse(socket, _callbackUuid, {
|
sendResponse(socket, _callbackUuid, {
|
||||||
workerId: workerId,
|
success: true,
|
||||||
shouldExit: shouldExit
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (shouldExit) {
|
|
||||||
console.log(`工具进程 ${workerId} 查询是否应该退出,返回: 是`);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 工具进程发送的消息(数据、心跳、截图等)
|
|
||||||
const workerId = message.workerId;
|
const workerId = message.workerId;
|
||||||
const workerInfo = workers.get(workerId);
|
const workerInfo = workers.get(workerId);
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
|
// 从工具进程发送的消息(数据、心跳、截图等)
|
||||||
|
case 'check-should-exit': {
|
||||||
|
const workerId = message.workerId;
|
||||||
|
const shouldExit = stoppedWorkers.has(workerId) || !workers.has(workerId);
|
||||||
|
|
||||||
|
sendResponse(socket, _callbackUuid, {
|
||||||
|
workerId: workerId,
|
||||||
|
shouldExit: shouldExit
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldExit) {
|
||||||
|
console.log(`工具进程 ${workerId} 查询是否应该退出,返回: 是`);
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
case 'worker-message': {
|
case 'worker-message': {
|
||||||
// 转发工具进程消息到GUI客户端
|
// 转发工具进程消息到GUI客户端
|
||||||
broadcastToGUI({
|
broadcastToGUI({
|
||||||
@@ -191,7 +157,7 @@ function handleMessage(socket, message) {
|
|||||||
data: message.data || message,
|
data: message.data || message,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
});
|
});
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
case 'worker-screenshot': {
|
case 'worker-screenshot': {
|
||||||
if (workerInfo && message.data && message.data.screenshot /* && workerInfo.socket === socket */) {
|
if (workerInfo && message.data && message.data.screenshot /* && workerInfo.socket === socket */) {
|
||||||
@@ -203,24 +169,21 @@ function handleMessage(socket, message) {
|
|||||||
console.error('缓存 worker 截图信息失败:', e);
|
console.error('缓存 worker 截图信息失败:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// GUI客户端的控制消息
|
// 从GUI进程发送的消息(数据、心跳、截图等)
|
||||||
// 标记为GUI客户端
|
case 'start-worker': {
|
||||||
if (!guiClients.has(socket)) {
|
|
||||||
guiClients.add(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message.type) {
|
|
||||||
case 'start-worker':
|
|
||||||
const {
|
const {
|
||||||
workerId,
|
workerId,
|
||||||
command,
|
command,
|
||||||
args,
|
args,
|
||||||
env
|
env
|
||||||
} = message
|
} = message
|
||||||
|
if (workers.has(workerId)) {
|
||||||
|
console.log(`工具进程 ${workerId} 已在运行`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
startWorker({
|
startWorker({
|
||||||
workerId,
|
workerId,
|
||||||
command,
|
command,
|
||||||
@@ -232,36 +195,36 @@ function handleMessage(socket, message) {
|
|||||||
message: `工具进程 ${message.workerId} 已启动`,
|
message: `工具进程 ${message.workerId} 已启动`,
|
||||||
workerId: message.workerId
|
workerId: message.workerId
|
||||||
});
|
});
|
||||||
break;
|
return
|
||||||
|
}
|
||||||
|
|
||||||
case 'stop-worker':
|
case 'stop-worker': {
|
||||||
stopWorker(message.workerId);
|
stopWorker(message.workerId);
|
||||||
sendResponse(socket, _callbackUuid, {
|
sendResponse(socket, _callbackUuid, {
|
||||||
success: true,
|
success: true,
|
||||||
message: `工具进程 ${message.workerId} 已停止`,
|
message: `工具进程 ${message.workerId} 已停止`,
|
||||||
workerId: message.workerId
|
workerId: message.workerId
|
||||||
});
|
});
|
||||||
break;
|
return
|
||||||
|
}
|
||||||
|
|
||||||
case 'get-status':
|
case 'get-status': {
|
||||||
const status = getWorkersStatus();
|
const status = getWorkersStatus();
|
||||||
sendResponse(socket, _callbackUuid, {
|
sendResponse(socket, _callbackUuid, {
|
||||||
success: true,
|
success: true,
|
||||||
workers: status
|
workers: status
|
||||||
});
|
});
|
||||||
break;
|
return
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
sendResponse(socket, _callbackUuid, { error: '未知的消息类型' });
|
sendResponse(socket, _callbackUuid, { error: '未知的消息类型' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动工具进程
|
// 启动工具进程
|
||||||
function startWorker({ workerId, command, args, env }, restartCount = 0) {
|
function startWorker({ workerId, command, args, env }, restartCount = 0) {
|
||||||
if (workers.has(workerId)) {
|
|
||||||
console.log(`工具进程 ${workerId} 已在运行`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const noAutoRestartExitCodeSet = new Set([0]);
|
const noAutoRestartExitCodeSet = new Set([0]);
|
||||||
(env.GEEKGEEKRUND_NO_AUTO_RESTART_EXIT_CODE ?? '')
|
(env.GEEKGEEKRUND_NO_AUTO_RESTART_EXIT_CODE ?? '')
|
||||||
.split(',')
|
.split(',')
|
||||||
@@ -512,11 +475,3 @@ process.on('SIGINT', () => {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 捕获未处理的 EPIPE 错误
|
|
||||||
process.on('uncaughtException', (err) => {
|
|
||||||
if (err.code === 'EPIPE' || err.code === 'ERR_STREAM_DESTROYED') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
throw err
|
|
||||||
});
|
|
||||||
@@ -82,5 +82,13 @@ export function openSettingWindow() {
|
|||||||
needCallback: true
|
needCallback: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
await sendToDaemon(
|
||||||
|
{
|
||||||
|
type: 'gui-register'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needCallback: true
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,21 @@ export const pageMapByName: {
|
|||||||
|
|
||||||
async function periodPushCurrentPageScreenshot () {
|
async function periodPushCurrentPageScreenshot () {
|
||||||
try {
|
try {
|
||||||
await pushCurrentPageScreenshot(pageMapByName.boss)
|
if (pageMapByName.boss?.isClosed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const shouldExit = await checkShouldExit()
|
||||||
|
if (shouldExit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await pushCurrentPageScreenshot(pageMapByName.boss)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err?.message?.includes(`PAGE_CLOSED`)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
setTimeout(periodPushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS)
|
setTimeout(periodPushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS)
|
||||||
}
|
}
|
||||||
catch {}
|
catch {}
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ 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 { connectToDaemon } from './flow/OPEN_SETTING_WINDOW/connect-to-daemon';
|
import { connectToDaemon } from './flow/OPEN_SETTING_WINDOW/connect-to-daemon';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
// 捕获未处理的 EPIPE 错误
|
||||||
|
process.on('uncaughtException', (err) => {
|
||||||
|
if (err?.code === 'EPIPE' || err?.code === 'ERR_STREAM_DESTROYED') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ export async function pushCurrentPageScreenshot (page) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err?.message?.includes('Session closed')) {
|
||||||
|
throw new Error(`PAGE_CLOSED`)
|
||||||
|
}
|
||||||
// 截图失败不应影响主流程
|
// 截图失败不应影响主流程
|
||||||
console.warn('[READ_NO_REPLY_AUTO_REMINDER] pushCurrentPageScreenshot error', err)
|
console.warn('[READ_NO_REPLY_AUTO_REMINDER] pushCurrentPageScreenshot error', err)
|
||||||
}
|
}
|
||||||
@@ -38,9 +41,6 @@ export class PeriodPushCurrentPageScreenshotPlugin {
|
|||||||
(page) => {
|
(page) => {
|
||||||
async function periodPushCurrentPageScreenshot () {
|
async function periodPushCurrentPageScreenshot () {
|
||||||
try {
|
try {
|
||||||
if (!page) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (page.isClosed()) {
|
if (page.isClosed()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,14 @@ export class PeriodPushCurrentPageScreenshotPlugin {
|
|||||||
if (shouldExit) {
|
if (shouldExit) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await pushCurrentPageScreenshot(page)
|
try {
|
||||||
|
await pushCurrentPageScreenshot(page)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err?.message?.includes(`PAGE_CLOSED`)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
setTimeout(periodPushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS)
|
setTimeout(periodPushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS)
|
||||||
}
|
}
|
||||||
catch {}
|
catch {}
|
||||||
|
|||||||
Reference in New Issue
Block a user