mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-05-06 20:02:47 +08:00
Merge branch 'feature/ui'
This commit is contained in:
@@ -699,7 +699,7 @@ async function toRecommendPage (hooks) {
|
||||
hooks.pageLoaded?.call()
|
||||
|
||||
let userInfoResponse = await userInfoPromise
|
||||
await hooks.userInfoResponse?.promise(userInfoResponse)
|
||||
await hooks.userInfoResponse?.promise({ userInfoResponse, browser })
|
||||
if (userInfoResponse?.code !== 0) {
|
||||
autoStartChatEventBus.emit('LOGIN_STATUS_INVALID', {
|
||||
userInfoResponse
|
||||
@@ -1713,7 +1713,7 @@ export async function mainLoop (hooks) {
|
||||
//set cookies
|
||||
const bossCookies = readStorageFile('boss-cookies.json')
|
||||
const bossLocalStorage = readStorageFile('boss-local-storage.json')
|
||||
await hooks.cookieWillSet?.promise(bossCookies)
|
||||
await hooks.cookieWillSet?.promise({ cookies: bossCookies, browser })
|
||||
for(let i = 0; i < bossCookies.length; i++){
|
||||
if (Object.hasOwn(bossCookies[i], 'sameSite')) {
|
||||
bossCookies[i].sameSite = 'unspecified'
|
||||
|
||||
@@ -1,125 +1,134 @@
|
||||
"use strict";
|
||||
|
||||
const { PuppeteerExtraPlugin } = require("puppeteer-extra-plugin");
|
||||
async function handle(p) {
|
||||
await p.evaluateOnNewDocument(() => {
|
||||
(() => {
|
||||
"use strict";
|
||||
/* -------------------------------------------------------
|
||||
* 1. 保存原生 Function.prototype.toString
|
||||
* ----------------------------------------------------- */
|
||||
const nativeFunctionToString = Function.prototype.toString;
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 2. WeakMap:函数 → 伪原生源码
|
||||
* ----------------------------------------------------- */
|
||||
const nativeSourceMap = new WeakMap();
|
||||
// 定义脚本内容,避免重复定义
|
||||
const stealthScript = () => {
|
||||
"use strict";
|
||||
/* -------------------------------------------------------
|
||||
* 1. 保存原生 Function.prototype.toString
|
||||
* ----------------------------------------------------- */
|
||||
const nativeFunctionToString = Function.prototype.toString;
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 3. 注册伪原生源码
|
||||
* ----------------------------------------------------- */
|
||||
const registerNativeSource = (fn, source) => {
|
||||
try {
|
||||
nativeSourceMap.set(fn, source);
|
||||
} catch (_) {}
|
||||
};
|
||||
/* -------------------------------------------------------
|
||||
* 2. WeakMap:函数 → 伪原生源码
|
||||
* ----------------------------------------------------- */
|
||||
const nativeSourceMap = new WeakMap();
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 4. 劫持 Function.prototype.toString
|
||||
* ----------------------------------------------------- */
|
||||
Object.defineProperty(Function.prototype, "toString", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function toString() {
|
||||
if (nativeSourceMap.has(this)) {
|
||||
return nativeSourceMap.get(this);
|
||||
}
|
||||
return nativeFunctionToString.call(this);
|
||||
},
|
||||
});
|
||||
/* -------------------------------------------------------
|
||||
* 3. 注册伪原生源码
|
||||
* ----------------------------------------------------- */
|
||||
const registerNativeSource = (fn, source) => {
|
||||
try {
|
||||
nativeSourceMap.set(fn, source);
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 5. 伪装 Function.prototype.toString 自身
|
||||
* ----------------------------------------------------- */
|
||||
registerNativeSource(
|
||||
Function.prototype.toString,
|
||||
nativeFunctionToString.toString(),
|
||||
);
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 6. stealthify:包装函数但保持“原生外观”
|
||||
* ----------------------------------------------------- */
|
||||
const stealthify = (obj, prop, handler) => {
|
||||
const original = obj[prop];
|
||||
if (typeof original !== "function") return;
|
||||
|
||||
const wrapped = function (...args) {
|
||||
return handler.call(this, original, args);
|
||||
};
|
||||
const namePropertyDescriptor = Object.getOwnPropertyDescriptor(
|
||||
wrapped,
|
||||
"name",
|
||||
);
|
||||
// 处理函数 name 属性
|
||||
Object.defineProperty(wrapped, "name", {
|
||||
...namePropertyDescriptor,
|
||||
value: prop,
|
||||
});
|
||||
// 保留 prototype(某些函数有)
|
||||
try {
|
||||
Object.setPrototypeOf(wrapped, Object.getPrototypeOf(original));
|
||||
} catch (_) {}
|
||||
|
||||
// 注册伪原生源码(直接复用原函数的 native 表现)
|
||||
registerNativeSource(wrapped, nativeFunctionToString.call(original));
|
||||
|
||||
// 用 defineProperty 保持 descriptor 接近原生
|
||||
const desc = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
Object.defineProperty(obj, prop, {
|
||||
...desc,
|
||||
value: wrapped,
|
||||
});
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 7. 示例:stealth console.log / debug / info
|
||||
* ----------------------------------------------------- */
|
||||
const filterConsoleArgs = (args) =>
|
||||
args.map((arg) => {
|
||||
if (arg && typeof arg === "object") {
|
||||
// 防止 getter / Proxy / 大对象触发
|
||||
return {};
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
|
||||
[
|
||||
"log",
|
||||
"debug",
|
||||
"info",
|
||||
"warn",
|
||||
"error",
|
||||
"dir",
|
||||
"table",
|
||||
"debug",
|
||||
].forEach((name) => {
|
||||
stealthify(console, name, (original, args) => {
|
||||
// ❗不传递原始对象,避免 DevTools / CDP 展开
|
||||
return original.apply(console, filterConsoleArgs(args));
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 8. 防御性补丁(可选但强烈建议)
|
||||
* ----------------------------------------------------- */
|
||||
|
||||
// 防止检测 toString 被替换
|
||||
registerNativeSource(
|
||||
registerNativeSource,
|
||||
"function registerNativeSource() { [native code] }",
|
||||
);
|
||||
})();
|
||||
/* -------------------------------------------------------
|
||||
* 4. 劫持 Function.prototype.toString
|
||||
* ----------------------------------------------------- */
|
||||
Object.defineProperty(Function.prototype, "toString", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function toString() {
|
||||
if (nativeSourceMap.has(this)) {
|
||||
return nativeSourceMap.get(this);
|
||||
}
|
||||
return nativeFunctionToString.call(this);
|
||||
},
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 5. 伪装 Function.prototype.toString 自身
|
||||
* ----------------------------------------------------- */
|
||||
registerNativeSource(
|
||||
Function.prototype.toString,
|
||||
nativeFunctionToString.toString(),
|
||||
);
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 6. stealthify:包装函数但保持"原生外观"
|
||||
* ----------------------------------------------------- */
|
||||
const stealthify = (obj, prop, handler) => {
|
||||
const original = obj[prop];
|
||||
if (typeof original !== "function") return;
|
||||
|
||||
const wrapped = function (...args) {
|
||||
return handler.call(this, original, args);
|
||||
};
|
||||
const namePropertyDescriptor = Object.getOwnPropertyDescriptor(
|
||||
wrapped,
|
||||
"name",
|
||||
);
|
||||
// 处理函数 name 属性
|
||||
Object.defineProperty(wrapped, "name", {
|
||||
...namePropertyDescriptor,
|
||||
value: prop,
|
||||
});
|
||||
// 保留 prototype(某些函数有)
|
||||
try {
|
||||
Object.setPrototypeOf(wrapped, Object.getPrototypeOf(original));
|
||||
} catch (_) {}
|
||||
|
||||
// 注册伪原生源码(直接复用原函数的 native 表现)
|
||||
registerNativeSource(wrapped, nativeFunctionToString.call(original));
|
||||
|
||||
// 用 defineProperty 保持 descriptor 接近原生
|
||||
const desc = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
Object.defineProperty(obj, prop, {
|
||||
...desc,
|
||||
value: wrapped,
|
||||
});
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 7. 示例:stealth console.log / debug / info
|
||||
* ----------------------------------------------------- */
|
||||
const filterConsoleArgs = (args) =>
|
||||
args.map((arg) => {
|
||||
if (arg && typeof arg === "object") {
|
||||
// 防止 getter / Proxy / 大对象触发
|
||||
return {};
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
|
||||
[
|
||||
"log",
|
||||
"debug",
|
||||
"info",
|
||||
"warn",
|
||||
"error",
|
||||
"dir",
|
||||
"table",
|
||||
"debug",
|
||||
].forEach((name) => {
|
||||
stealthify(console, name, (original, args) => {
|
||||
// ❗不传递原始对象,避免 DevTools / CDP 展开
|
||||
return original.apply(console, filterConsoleArgs(args));
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------
|
||||
* 8. 防御性补丁(可选但强烈建议)
|
||||
* ----------------------------------------------------- */
|
||||
|
||||
// 防止检测 toString 被替换
|
||||
registerNativeSource(
|
||||
registerNativeSource,
|
||||
"function registerNativeSource() { [native code] }",
|
||||
);
|
||||
};
|
||||
|
||||
async function handle(p) {
|
||||
// 1. 立即执行一次(针对当前已有的文档,防止错过)
|
||||
try {
|
||||
await p.evaluate(stealthScript);
|
||||
} catch (e) {
|
||||
// 如果当前页面还没准备好,忽略错误
|
||||
}
|
||||
// 2. 注册为新文档脚本(针对未来的导航)
|
||||
await p.evaluateOnNewDocument(stealthScript);
|
||||
}
|
||||
|
||||
class Plugin extends PuppeteerExtraPlugin {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@geekgeekrun/puppeteer-extra-plugin-laodeng",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"description": "laodeng",
|
||||
"main": "./index.js",
|
||||
"author": "geekgeekrun",
|
||||
|
||||
@@ -103,7 +103,7 @@ const server = net.createServer((socket) => {
|
||||
|
||||
// 处理消息
|
||||
function handleMessage(socket, message) {
|
||||
console.log('收到消息:', message);
|
||||
message.type !== 'get-status' && console.log('收到消息:', message);
|
||||
const _callbackUuid = message._callbackUuid
|
||||
if (message.type === 'ping') {
|
||||
sendResponse(socket, _callbackUuid, {
|
||||
@@ -143,6 +143,23 @@ function handleMessage(socket, message) {
|
||||
return
|
||||
}
|
||||
case 'worker-to-gui-message': {
|
||||
// 将 prerequisite step 状态写入 worker 的 runtimeStorage
|
||||
if (
|
||||
workerInfo &&
|
||||
message.data?.type === 'prerequisite-step-by-step-check' &&
|
||||
message.data?.step?.id
|
||||
) {
|
||||
workerInfo.runtimeStorage = workerInfo.runtimeStorage || {}
|
||||
workerInfo.runtimeStorage.stepStatusMapByStepId =
|
||||
workerInfo.runtimeStorage.stepStatusMapByStepId || {}
|
||||
workerInfo.runtimeStorage.stepStatusMapByStepId[
|
||||
message.data.step.id
|
||||
] = {
|
||||
step: message.data.step,
|
||||
runRecordId: message.data.runRecordId
|
||||
}
|
||||
}
|
||||
|
||||
// 转发工具进程消息到GUI客户端
|
||||
broadcastToGUI({
|
||||
type: 'worker-to-gui-message',
|
||||
@@ -329,6 +346,9 @@ function startWorker({ workerId, command, args, env }, restartCount = 0) {
|
||||
status: 'running',
|
||||
startTime: Date.now(),
|
||||
restartCount, // 使用传入的重启次数
|
||||
runtimeStorage: {
|
||||
stepStatusMapByStepId: {}
|
||||
},
|
||||
// socket: null, // 工具进程的TCP连接,稍后由工具进程注册
|
||||
// lastHeartbeat: null,
|
||||
command,
|
||||
@@ -390,6 +410,7 @@ function getWorkersStatus() {
|
||||
status: workerInfo.status,
|
||||
uptime: Date.now() - workerInfo.startTime,
|
||||
restartCount: workerInfo.restartCount || 0,
|
||||
runtimeStorage: workerInfo.runtimeStorage || {},
|
||||
// connected: workerInfo.socket !== null && !workerInfo.socket.destroyed,
|
||||
// lastHeartbeat: workerInfo.lastHeartbeat,
|
||||
command: workerInfo.command,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { AUTO_CHAT_ERROR_EXIT_CODE } from './enums.mjs'
|
||||
const rerunInterval = (() => {
|
||||
let v = Number(process.env.MAIN_BOSSGEEKGO_RERUN_INTERVAL)
|
||||
if (isNaN(v)) {
|
||||
v = 3000
|
||||
v = 5000
|
||||
}
|
||||
|
||||
return v
|
||||
|
||||
@@ -22,7 +22,7 @@ const {
|
||||
const rerunInterval = (() => {
|
||||
let v = Number(process.env.MAIN_BOSSGEEKGO_RERUN_INTERVAL)
|
||||
if (isNaN(v)) {
|
||||
v = 3000
|
||||
v = 5000
|
||||
}
|
||||
|
||||
return v
|
||||
|
||||
@@ -116,7 +116,7 @@ export default class SqlitePlugin {
|
||||
)
|
||||
hooks.userInfoResponse.tapPromise(
|
||||
"SqlitePlugin",
|
||||
async (userInfoResponse) => {
|
||||
async ({ userInfoResponse } = {}) => {
|
||||
if (!userInfoResponse || userInfoResponse.code !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,14 +63,16 @@ export default defineConfig({
|
||||
rollupOptions: {
|
||||
external: []
|
||||
},
|
||||
minify: process.env.NODE_ENV === 'development' ? undefined : 'terser'
|
||||
minify: process.env.NODE_ENV === 'development' ? undefined : 'terser',
|
||||
watch: process.env.NODE_ENV === 'development' ? {} : undefined
|
||||
},
|
||||
plugins: mainPlugins
|
||||
},
|
||||
preload: {
|
||||
plugins: preloadPlugins,
|
||||
build: {
|
||||
minify: process.env.NODE_ENV === 'development' ? undefined : 'terser'
|
||||
minify: process.env.NODE_ENV === 'development' ? undefined : 'terser',
|
||||
watch: process.env.NODE_ENV === 'development' ? {} : undefined
|
||||
}
|
||||
},
|
||||
renderer: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "geekgeekrun-ui",
|
||||
"version": "0.17.3",
|
||||
"version": "0.17.4",
|
||||
"description": "BOSS 炸弹 - 自动开聊BOSS,助力每位打工人求职!",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "geekgeekrun",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "0.17.3",
|
||||
"buildVersion": 40,
|
||||
"buildTime": 1775201731866,
|
||||
"buildHash": "09a1b4b91804ebc8202c16d3e2976a91ab89d09d",
|
||||
"version": "0.17.4",
|
||||
"buildVersion": 41,
|
||||
"buildTime": 1777732024939,
|
||||
"buildHash": "9d3408d1f3fd5bba0e44736233408e2be2e48536",
|
||||
"name": "geekgeekrun-ui"
|
||||
}
|
||||
@@ -3,17 +3,37 @@ import minimist from 'minimist'
|
||||
import { loginWithCookieAssistant } from './login-with-cookie-assistant'
|
||||
import { checkCookieListFormat } from '../../common/utils/cookie'
|
||||
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
||||
import { readStorageFile } from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
import {
|
||||
readStorageFile,
|
||||
writeStorageFile
|
||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
|
||||
const runRecordId = minimist(process.argv.slice(2))['run-record-id'] ?? null
|
||||
export class CookieInvalidHandlePlugin {
|
||||
apply(hooks) {
|
||||
hooks.cookieWillSet.tapPromise('CookieInvalidHandlePlugin', async (cookies) => {
|
||||
hooks.cookieWillSet.tapPromise('CookieInvalidHandlePlugin', async ({ cookies, browser } = {}) => {
|
||||
let isValid = checkCookieListFormat(cookies)
|
||||
while (!isValid) {
|
||||
try {
|
||||
browser && (await browser.close())
|
||||
} catch (err) {
|
||||
console.log(`close browser failed`, err)
|
||||
}
|
||||
try {
|
||||
// popup login dialog, then update login status
|
||||
await loginWithCookieAssistant()
|
||||
let app
|
||||
try {
|
||||
app = (await import('electron')).app
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
// popup login dialog, then update login status
|
||||
try {
|
||||
await app?.dock?.show()
|
||||
await loginWithCookieAssistant()
|
||||
} finally {
|
||||
await app?.dock?.hide()
|
||||
}
|
||||
await sleep(2000)
|
||||
const newCookies = readStorageFile('boss-cookies.json')
|
||||
isValid = checkCookieListFormat(newCookies)
|
||||
@@ -27,8 +47,9 @@ export class CookieInvalidHandlePlugin {
|
||||
if (e?.message === 'USER_CANCELLED_LOGIN') {
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'basic-cookie-check',
|
||||
status: 'rejected'
|
||||
@@ -42,8 +63,9 @@ export class CookieInvalidHandlePlugin {
|
||||
}
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'basic-cookie-check',
|
||||
status: 'fulfilled'
|
||||
@@ -52,12 +74,13 @@ export class CookieInvalidHandlePlugin {
|
||||
}
|
||||
})
|
||||
})
|
||||
hooks.userInfoResponse.tapPromise('CookieInvalidHandlePlugin', async (userInfoResponse) => {
|
||||
hooks.userInfoResponse.tapPromise('CookieInvalidHandlePlugin', async ({ userInfoResponse, browser } = {}) => {
|
||||
if (userInfoResponse.code === 0) {
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'fulfilled'
|
||||
@@ -67,15 +90,34 @@ export class CookieInvalidHandlePlugin {
|
||||
})
|
||||
return
|
||||
}
|
||||
try {
|
||||
browser && (await browser.close())
|
||||
} catch (err) {
|
||||
console.log(`close browser failed`, err)
|
||||
}
|
||||
await writeStorageFile('boss-cookies.json', [])
|
||||
try {
|
||||
// popup login dialog, then update login status
|
||||
await loginWithCookieAssistant()
|
||||
let app
|
||||
try {
|
||||
app = (await import('electron')).app
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
// popup login dialog, then update login status
|
||||
try {
|
||||
await app?.dock?.show()
|
||||
await loginWithCookieAssistant()
|
||||
} finally {
|
||||
await app?.dock?.hide()
|
||||
}
|
||||
} catch (e) {
|
||||
if (e?.message === 'USER_CANCELLED_LOGIN') {
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'rejected'
|
||||
|
||||
@@ -30,7 +30,7 @@ process.on('SIGTERM', () => {
|
||||
const rerunInterval = (() => {
|
||||
let v = Number(process.env.MAIN_BOSSGEEKGO_RERUN_INTERVAL)
|
||||
if (isNaN(v)) {
|
||||
v = 3000
|
||||
v = 5000
|
||||
}
|
||||
|
||||
return v
|
||||
@@ -66,8 +66,9 @@ const runAutoChat = async () => {
|
||||
})
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'puppeteer-executable-check',
|
||||
status: 'rejected'
|
||||
@@ -80,8 +81,9 @@ const runAutoChat = async () => {
|
||||
}
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'puppeteer-executable-check',
|
||||
status: 'fulfilled'
|
||||
@@ -183,8 +185,9 @@ export const waitForProcessHandShakeAndRunAutoChat = async () => {
|
||||
)
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'worker-launch',
|
||||
status: 'fulfilled'
|
||||
|
||||
@@ -89,7 +89,9 @@ const onlyRemindBossWithoutBlockCompanyName =
|
||||
readConfigFile('boss.json').autoReminder?.onlyRemindBossWithoutBlockCompanyName ??
|
||||
!!blockCompanyNameRegExp
|
||||
|
||||
const openContentSource = readConfigFile('boss.json').autoReminder?.openContentSource ?? OPEN_CONTENT_SOURCE.CONSTANT_CONTENT
|
||||
const openContentSource =
|
||||
readConfigFile('boss.json').autoReminder?.openContentSource ??
|
||||
OPEN_CONTENT_SOURCE.CONSTANT_CONTENT
|
||||
const constantOpenContent = (() => {
|
||||
let constantOpenContent = readConfigFile('boss.json').autoReminder?.constantOpenContent ?? ''
|
||||
if (constantOpenContent?.trim?.()) {
|
||||
@@ -303,7 +305,17 @@ const mainLoop = async () => {
|
||||
let cookieCheckResult = checkCookieListFormat(bossCookies)
|
||||
while (!cookieCheckResult) {
|
||||
try {
|
||||
await loginWithCookieAssistant()
|
||||
browser && (await browser.close())
|
||||
} catch (err) {
|
||||
console.log(`close browser failed`, err)
|
||||
}
|
||||
try {
|
||||
try {
|
||||
await app.dock?.show()
|
||||
await loginWithCookieAssistant()
|
||||
} finally {
|
||||
await app.dock?.hide()
|
||||
}
|
||||
bossCookies = readStorageFile('boss-cookies.json')
|
||||
cookieCheckResult = checkCookieListFormat(bossCookies)
|
||||
} catch (err) {
|
||||
@@ -314,8 +326,9 @@ const mainLoop = async () => {
|
||||
})
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'basic-cookie-check',
|
||||
status: 'rejected'
|
||||
@@ -328,8 +341,9 @@ const mainLoop = async () => {
|
||||
}
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'basic-cookie-check',
|
||||
status: 'fulfilled'
|
||||
@@ -356,8 +370,17 @@ const mainLoop = async () => {
|
||||
if (currentPageUrl.startsWith('https://www.zhipin.com/web/user/')) {
|
||||
writeStorageFile('boss-cookies.json', [])
|
||||
try {
|
||||
// popup login dialog, then update login status
|
||||
await loginWithCookieAssistant()
|
||||
browser && (await browser.close())
|
||||
} catch (err) {
|
||||
console.log(`close browser failed`, err)
|
||||
}
|
||||
try {
|
||||
try {
|
||||
await app.dock?.show()
|
||||
await loginWithCookieAssistant()
|
||||
} finally {
|
||||
await app.dock?.hide()
|
||||
}
|
||||
} catch (err) {
|
||||
await dialog.showMessageBox({
|
||||
type: `error`,
|
||||
@@ -366,8 +389,9 @@ const mainLoop = async () => {
|
||||
})
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'rejected'
|
||||
@@ -385,8 +409,9 @@ const mainLoop = async () => {
|
||||
) {
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'rejected'
|
||||
@@ -418,8 +443,9 @@ const mainLoop = async () => {
|
||||
await storeStorage(pageMapByName.boss)
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'rejected'
|
||||
@@ -432,8 +458,9 @@ const mainLoop = async () => {
|
||||
}
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'login-status-check',
|
||||
status: 'fulfilled'
|
||||
@@ -656,7 +683,7 @@ const mainLoop = async () => {
|
||||
const rerunInterval = (() => {
|
||||
let v = Number(process.env.MAIN_BOSSGEEKGO_RERUN_INTERVAL)
|
||||
if (isNaN(v)) {
|
||||
v = 3000
|
||||
v = 5000
|
||||
}
|
||||
|
||||
return v
|
||||
@@ -681,8 +708,9 @@ export async function runEntry() {
|
||||
)
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'worker-launch',
|
||||
status: 'fulfilled'
|
||||
@@ -707,8 +735,9 @@ export async function runEntry() {
|
||||
})
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'puppeteer-executable-check',
|
||||
status: 'rejected'
|
||||
@@ -720,8 +749,9 @@ export async function runEntry() {
|
||||
}
|
||||
sendToDaemon({
|
||||
type: 'worker-to-gui-message',
|
||||
workerId: process.env.GEEKGEEKRUND_WORKER_ID,
|
||||
data: {
|
||||
type: 'prerequisite-step-by-step-checkstep-by-step-check',
|
||||
type: 'prerequisite-step-by-step-check',
|
||||
step: {
|
||||
id: 'puppeteer-executable-check',
|
||||
status: 'fulfilled'
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// import { useTaskManagerStore } from '@renderer/store'
|
||||
import { useTaskManagerStore } from '@renderer/store'
|
||||
import { getAutoStartChatSteps } from '../../../../common/prerequisite-step-by-step-check'
|
||||
import { computed, onUnmounted, ref, watch } from 'vue'
|
||||
import {
|
||||
@@ -71,12 +71,12 @@ const props = defineProps({
|
||||
type: Number
|
||||
}
|
||||
})
|
||||
// const taskManagerStore = useTaskManagerStore()
|
||||
// const runningTaskInfo = computed(() => {
|
||||
// return taskManagerStore.runningTasks?.find((it) => {
|
||||
// return it.workerId === props.workerId
|
||||
// })
|
||||
// })
|
||||
const taskManagerStore = useTaskManagerStore()
|
||||
const runningTaskInfo = computed(() => {
|
||||
return taskManagerStore.runningTasks?.find((it) => {
|
||||
return it.workerId === props.workerId
|
||||
})
|
||||
})
|
||||
const steps = ref([])
|
||||
const stepsForRender = computed(() => {
|
||||
const clonedSteps = JSON.parse(JSON.stringify(steps.value))
|
||||
@@ -101,9 +101,43 @@ function fillEmptySteps() {
|
||||
steps.value = arr
|
||||
currentRunningStatus.value = RUNNING_STATUS_ENUM.RUNNING
|
||||
}
|
||||
watch(() => props.runRecordId, fillEmptySteps, {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
function applyRuntimeStepStatus() {
|
||||
const task = runningTaskInfo.value
|
||||
if (!task?.runtimeStorage?.stepStatusMapByStepId) {
|
||||
return
|
||||
}
|
||||
const stepMap = task.runtimeStorage.stepStatusMapByStepId
|
||||
steps.value = getAutoStartChatSteps().map((step) => {
|
||||
const saved = stepMap[step.id]
|
||||
if (!saved || !saved.step) {
|
||||
return step
|
||||
}
|
||||
return {
|
||||
...step,
|
||||
status: saved.step.status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.runRecordId,
|
||||
() => {
|
||||
fillEmptySteps()
|
||||
applyRuntimeStepStatus()
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => taskManagerStore.runningTasks,
|
||||
() => {
|
||||
applyRuntimeStepStatus()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
watch(
|
||||
() => stepsForRender.value,
|
||||
(v) => {
|
||||
@@ -121,10 +155,7 @@ watch(
|
||||
|
||||
const { ipcRenderer } = electron
|
||||
function messageHandler(ev, { data }) {
|
||||
if (
|
||||
data.type !== 'prerequisite-step-by-step-checkstep-by-step-check' ||
|
||||
data.runRecordId !== props.runRecordId
|
||||
) {
|
||||
if (data.type !== 'prerequisite-step-by-step-check' || data.runRecordId !== props.runRecordId) {
|
||||
return
|
||||
}
|
||||
const { id: stepId, status: stepStatus } = data.step
|
||||
|
||||
@@ -1681,7 +1681,7 @@
|
||||
>
|
||||
<RunningOverlay
|
||||
ref="runningOverlayRef"
|
||||
worker-id="geekAutoStartWithBossMain"
|
||||
:worker-id="CURRENT_WORKER_ID"
|
||||
:run-record-id="runRecordId"
|
||||
>
|
||||
<template #op-buttons="{ currentRunningStatus }">
|
||||
@@ -1714,7 +1714,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, ref, watch, nextTick, onUnmounted } from 'vue'
|
||||
import { computed, onBeforeUnmount, ref, watch, onUnmounted, onMounted } from 'vue'
|
||||
import { ElForm, ElMessage } from 'element-plus'
|
||||
import { QuestionFilled, ArrowDown } from '@element-plus/icons-vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
@@ -1742,6 +1742,7 @@ import JobSourceDragOrderer from '../../../features/JobSourceDragOrderer/index.v
|
||||
import expectJobFilterTemplateList from './expectJobFilterTemplateList'
|
||||
import RunningOverlay from '@renderer/features/RunningOverlay/index.vue'
|
||||
import { RUNNING_STATUS_ENUM } from '../../../../../common/enums/auto-start-chat'
|
||||
import { useTaskManagerStore } from '@renderer/store'
|
||||
import {
|
||||
getJobDetailRegExpMatchLogicConfig,
|
||||
isJobDetailRegExpEmpty,
|
||||
@@ -2084,6 +2085,24 @@ const formRules = {
|
||||
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||
const runRecordId = ref(null)
|
||||
const runningOverlayRef = ref(null)
|
||||
const taskManagerStore = useTaskManagerStore()
|
||||
const CURRENT_WORKER_ID = 'geekAutoStartWithBossMain'
|
||||
|
||||
onMounted(async () => {
|
||||
await taskManagerStore.getRunningTasks()
|
||||
const existingWorker = taskManagerStore.runningTasks?.find(
|
||||
(it) => it.workerId === CURRENT_WORKER_ID
|
||||
)
|
||||
if (existingWorker) {
|
||||
runRecordId.value = existingWorker.runtimeStorage?.stepStatusMapByStepId
|
||||
? Object.values(existingWorker.runtimeStorage.stepStatusMapByStepId)[0]?.runRecordId
|
||||
: null
|
||||
if (runRecordId.value) {
|
||||
runningOverlayRef.value?.show()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
gtagRenderer('save_config_and_launch_clicked', {
|
||||
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken,
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
>
|
||||
<RunningOverlay
|
||||
ref="runningOverlayRef"
|
||||
worker-id="readNoReplyAutoReminderMain"
|
||||
:worker-id="CURRENT_WORKER_ID"
|
||||
:run-record-id="runRecordId"
|
||||
>
|
||||
<template #op-buttons="{ currentRunningStatus }">
|
||||
@@ -351,7 +351,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { dayjs, ElForm, ElMessage, ElMessageBox, ElSelect, ElOption } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import {
|
||||
@@ -366,6 +366,7 @@ import mittBus from '../../utils/mitt'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
import RunningOverlay from '@renderer/features/RunningOverlay/index.vue'
|
||||
import { DEFAULT_CONSTANT_OPEN_CONTENT_SEGS } from '../../../../common/constant'
|
||||
import { useTaskManagerStore } from '@renderer/store'
|
||||
const gtagRenderer = (name, params?: object) => {
|
||||
return baseGtagRenderer(name, {
|
||||
scene: 'rnrr-config',
|
||||
@@ -607,6 +608,24 @@ async function checkIsCanRun() {
|
||||
}
|
||||
const runRecordId = ref(null)
|
||||
const runningOverlayRef = ref(null)
|
||||
const taskManagerStore = useTaskManagerStore()
|
||||
const CURRENT_WORKER_ID = 'readNoReplyAutoReminderMain'
|
||||
|
||||
onMounted(async () => {
|
||||
await taskManagerStore.getRunningTasks()
|
||||
const existingWorker = taskManagerStore.runningTasks?.find(
|
||||
(it) => it.workerId === CURRENT_WORKER_ID
|
||||
)
|
||||
if (existingWorker) {
|
||||
runRecordId.value = existingWorker.runtimeStorage?.stepStatusMapByStepId
|
||||
? Object.values(existingWorker.runtimeStorage.stepStatusMapByStepId)[0]?.runRecordId
|
||||
: null
|
||||
if (runRecordId.value) {
|
||||
runningOverlayRef.value?.show()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
gtagRenderer('run_read_no_reply_reminder_clicked', {
|
||||
throttle_interval_minutes: formContent.value.autoReminder.throttleIntervalMinutes,
|
||||
|
||||
@@ -22,13 +22,13 @@ export const useUpdateStore = defineStore('update', () => {
|
||||
|
||||
export const useTaskManagerStore = defineStore('taskManager', () => {
|
||||
const runningTasks = ref<unknown[]>([])
|
||||
function getRunningTasks() {
|
||||
async function getRunningTasks() {
|
||||
const { ipcRenderer } = electron
|
||||
ipcRenderer.invoke('get-task-manager-list').then(res => {
|
||||
runningTasks.value = res.workers ?? []
|
||||
})
|
||||
const res = await ipcRenderer.invoke('get-task-manager-list')
|
||||
runningTasks.value = res.workers ?? []
|
||||
}
|
||||
const throttledGetRunningTasks = throttle(getRunningTasks, 2000)
|
||||
setInterval(throttledGetRunningTasks, 2 * 1000)
|
||||
getRunningTasks()
|
||||
return { runningTasks, getRunningTasks: throttledGetRunningTasks }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user