@web-auto/webauto 0.1.4 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/desktop-console/default-settings.json +2 -2
- package/apps/desktop-console/dist/main/index.mjs +983 -128
- package/apps/desktop-console/dist/main/preload.mjs +7 -0
- package/apps/desktop-console/dist/renderer/index.html +622 -50
- package/apps/desktop-console/dist/renderer/index.js +2423 -469
- package/apps/desktop-console/dist/renderer/run.mts +6 -5
- package/apps/desktop-console/entry/ui-cli.mjs +672 -0
- package/apps/desktop-console/entry/ui-console.mjs +416 -29
- package/apps/webauto/entry/account.mjs +89 -53
- package/apps/webauto/entry/browser-status.mjs +7 -10
- package/apps/webauto/entry/lib/account-detect.mjs +254 -28
- package/apps/webauto/entry/lib/account-store.mjs +219 -30
- package/apps/webauto/entry/lib/bus-publish.mjs +63 -0
- package/apps/webauto/entry/lib/camo-cli.mjs +93 -0
- package/apps/webauto/entry/lib/profilepool.mjs +14 -5
- package/apps/webauto/entry/lib/quota-status.mjs +23 -0
- package/apps/webauto/entry/lib/schedule-store.mjs +1068 -0
- package/apps/webauto/entry/profilepool.mjs +106 -17
- package/apps/webauto/entry/schedule.mjs +612 -0
- package/apps/webauto/entry/weibo-unified.mjs +134 -0
- package/apps/webauto/entry/xhs-install.mjs +256 -31
- package/apps/webauto/entry/xhs-status.mjs +5 -2
- package/apps/webauto/entry/xhs-unified.mjs +631 -98
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/comment_item/container.json +40 -0
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_expand_button/container.json +38 -0
- package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_list/container.json +37 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/container.json +8 -3
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/login_anchor/container.json +30 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_bar/container.json +47 -0
- package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_button/container.json +39 -0
- package/bin/camoufox-cli.mjs +61 -0
- package/bin/webauto.mjs +301 -54
- package/dist/modules/camo-backend/src/index.js +49 -1
- package/dist/modules/camo-backend/src/internal/BrowserSession.js +572 -3
- package/dist/modules/camo-backend/src/internal/SessionManager.js +13 -1
- package/dist/modules/camo-backend/src/internal/storage-paths.js +6 -0
- package/dist/modules/collection-manager/bloom-filter.js +91 -0
- package/dist/modules/collection-manager/date-utils.js +275 -0
- package/dist/modules/collection-manager/index.js +258 -0
- package/dist/modules/collection-manager/storage.js +195 -0
- package/dist/modules/collection-manager/types.js +47 -0
- package/dist/modules/logging/src/index.js +1 -1
- package/dist/modules/process-registry/index.js +230 -0
- package/dist/modules/rate-limiter/index.js +242 -0
- package/dist/modules/workflow/blocks/ExecuteWeiboSearchBlock.js +128 -0
- package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +7 -3
- package/dist/modules/workflow/blocks/RenderMarkdown.js +4 -1
- package/dist/modules/workflow/blocks/WeiboCollectCommentsBlock.js +282 -0
- package/dist/modules/workflow/blocks/WeiboCollectFromLinksBlock.js +283 -0
- package/dist/modules/workflow/blocks/WeiboCollectSearchLinksBlock.js +208 -0
- package/dist/modules/workflow/blocks/WeiboCollectTimelineListBlock.js +128 -0
- package/dist/modules/workflow/blocks/WeiboCollectUserPostsListBlock.js +127 -0
- package/dist/modules/workflow/blocks/helpers/downloadPaths.js +21 -0
- package/dist/modules/workflow/config/workflowRegistry.js +2 -0
- package/dist/modules/workflow/definitions/weibo-search-workflow-v1.js +47 -0
- package/dist/modules/workflow/src/runner.js +6 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +4 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +2 -2
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +123 -0
- package/dist/modules/xiaohongshu/app/src/container-registry/src/index.d.ts +37 -0
- package/dist/modules/xiaohongshu/app/src/container-registry/src/index.js +184 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.d.ts +31 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.js +71 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.d.ts +48 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.js +259 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.d.ts +28 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.js +319 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.d.ts +36 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.js +162 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.d.ts +36 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.js +301 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.d.ts +29 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.js +195 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.d.ts +25 -0
- package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.js +164 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.d.ts +66 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.d.ts +16 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.d.ts +27 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.d.ts +18 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.d.ts +34 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.d.ts +17 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.d.ts +15 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.d.ts +26 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.d.ts +29 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.d.ts +38 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.d.ts +30 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.d.ts +23 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.d.ts +32 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.d.ts +35 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.d.ts +34 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.d.ts +111 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.d.ts +20 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.d.ts +48 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.d.ts +23 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.d.ts +55 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.d.ts +21 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.d.ts +5 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.d.ts +37 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.js +165 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.d.ts +33 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.d.ts +9 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.js +9 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.d.ts +50 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.js +222 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.d.ts +10 -0
- package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.js +43 -0
- package/dist/services/shared/serviceProcessLogger.js +1 -1
- package/dist/services/unified-api/server.js +105 -11
- package/modules/camo-backend/src/index.ts +46 -1
- package/modules/camo-backend/src/internal/BrowserSession.ts +619 -3
- package/modules/camo-backend/src/internal/SessionManager.ts +12 -1
- package/modules/camo-backend/src/internal/storage-paths.ts +5 -0
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/comments.mjs +38 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/interaction.mjs +47 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +94 -11
- package/modules/camo-runtime/src/autoscript/action-providers/xhs.mjs +208 -2
- package/modules/camo-runtime/src/autoscript/runtime.mjs +7 -1
- package/modules/camo-runtime/src/autoscript/xhs-unified-template.mjs +76 -43
- package/modules/camo-runtime/src/container/runtime-core/operations/index.mjs +75 -1
- package/modules/camo-runtime/src/container/runtime-core/operations/selector-scripts.mjs +71 -4
- package/modules/camo-runtime/src/container/runtime-core/operations/tab-pool.mjs +183 -27
- package/modules/collection-manager/bloom-filter.ts +112 -0
- package/modules/collection-manager/date-utils.ts +316 -0
- package/modules/collection-manager/index.ts +309 -0
- package/modules/collection-manager/package.json +10 -0
- package/modules/collection-manager/storage.ts +174 -0
- package/modules/collection-manager/types.ts +156 -0
- package/modules/logging/src/index.ts +1 -1
- package/modules/process-registry/index.ts +284 -0
- package/modules/rate-limiter/index.ts +322 -0
- package/modules/state/src/paths.ts +9 -1
- package/modules/task-scheduler/index.ts +293 -0
- package/modules/workflow/blocks/ExecuteWeiboSearchBlock.ts +167 -0
- package/modules/workflow/blocks/PersistXhsNoteBlock.ts +7 -3
- package/modules/workflow/blocks/RenderMarkdown.ts +4 -1
- package/modules/workflow/blocks/WeiboCollectCommentsBlock.ts +339 -0
- package/modules/workflow/blocks/WeiboCollectFromLinksBlock.ts +338 -0
- package/modules/workflow/blocks/helpers/downloadPaths.ts +16 -0
- package/modules/workflow/config/workflowRegistry.ts +2 -0
- package/modules/workflow/definitions/weibo-search-workflow-v1.ts +47 -0
- package/modules/workflow/src/runner.ts +6 -0
- package/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.ts +1 -1
- package/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.ts +4 -0
- package/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.ts +2 -3
- package/modules/xiaohongshu/app/src/blocks/helpers/sharding.ts +152 -0
- package/package.json +13 -4
- package/scripts/postinstall-resources.mjs +62 -0
- package/scripts/test/run-coverage.mjs +76 -0
- package/scripts/weibo/search.ts +49 -0
- package/services/shared/serviceProcessLogger.ts +1 -1
- package/services/unified-api/server.ts +98 -12
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* File storage utilities for collection data
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CollectionStorage = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
class CollectionStorage {
|
|
43
|
+
baseDir;
|
|
44
|
+
collectionDir;
|
|
45
|
+
platform;
|
|
46
|
+
env;
|
|
47
|
+
collectionId;
|
|
48
|
+
constructor(baseDir, platform, env, collectionId) {
|
|
49
|
+
this.baseDir = baseDir;
|
|
50
|
+
this.platform = platform;
|
|
51
|
+
this.env = env;
|
|
52
|
+
this.collectionId = collectionId;
|
|
53
|
+
// Directory structure: baseDir/platform/env/collectionId/
|
|
54
|
+
this.collectionDir = path.join(baseDir, platform, env, collectionId);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialize storage directories
|
|
58
|
+
*/
|
|
59
|
+
async init() {
|
|
60
|
+
await fs.promises.mkdir(this.collectionDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get paths for different files
|
|
64
|
+
*/
|
|
65
|
+
getMetaPath() {
|
|
66
|
+
return path.join(this.collectionDir, 'collection-meta.json');
|
|
67
|
+
}
|
|
68
|
+
getPostsPath() {
|
|
69
|
+
return path.join(this.collectionDir, 'posts.jsonl');
|
|
70
|
+
}
|
|
71
|
+
getCommentsPath() {
|
|
72
|
+
return path.join(this.collectionDir, 'comments.jsonl');
|
|
73
|
+
}
|
|
74
|
+
getLinksPath() {
|
|
75
|
+
return path.join(this.collectionDir, 'links.jsonl');
|
|
76
|
+
}
|
|
77
|
+
getRunLogPath() {
|
|
78
|
+
return path.join(this.collectionDir, 'run.log');
|
|
79
|
+
}
|
|
80
|
+
getEventsPath() {
|
|
81
|
+
return path.join(this.collectionDir, 'run-events.jsonl');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read/write meta
|
|
85
|
+
*/
|
|
86
|
+
async readMeta() {
|
|
87
|
+
const metaPath = this.getMetaPath();
|
|
88
|
+
try {
|
|
89
|
+
const data = await fs.promises.readFile(metaPath, 'utf-8');
|
|
90
|
+
return JSON.parse(data);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async writeMeta(meta) {
|
|
97
|
+
const metaPath = this.getMetaPath();
|
|
98
|
+
await fs.promises.writeFile(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Append post to JSONL
|
|
102
|
+
*/
|
|
103
|
+
async appendPost(post) {
|
|
104
|
+
const line = JSON.stringify(post) + '\n';
|
|
105
|
+
await fs.promises.appendFile(this.getPostsPath(), line, 'utf-8');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Append comment to JSONL
|
|
109
|
+
*/
|
|
110
|
+
async appendComment(comment) {
|
|
111
|
+
const line = JSON.stringify(comment) + '\n';
|
|
112
|
+
await fs.promises.appendFile(this.getCommentsPath(), line, 'utf-8');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read all posts
|
|
116
|
+
*/
|
|
117
|
+
async readPosts() {
|
|
118
|
+
try {
|
|
119
|
+
const data = await fs.promises.readFile(this.getPostsPath(), 'utf-8');
|
|
120
|
+
return data.trim().split('\n').map(line => JSON.parse(line));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Read all comments
|
|
128
|
+
*/
|
|
129
|
+
async readComments() {
|
|
130
|
+
try {
|
|
131
|
+
const data = await fs.promises.readFile(this.getCommentsPath(), 'utf-8');
|
|
132
|
+
return data.trim().split('\n').map(line => JSON.parse(line));
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Count lines in JSONL file
|
|
140
|
+
*/
|
|
141
|
+
async countLines(filePath) {
|
|
142
|
+
try {
|
|
143
|
+
const data = await fs.promises.readFile(filePath, 'utf-8');
|
|
144
|
+
return data.trim().split('\n').filter(line => line.length > 0).length;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get collection stats
|
|
152
|
+
*/
|
|
153
|
+
async getStats() {
|
|
154
|
+
return {
|
|
155
|
+
postCount: await this.countLines(this.getPostsPath()),
|
|
156
|
+
commentCount: await this.countLines(this.getCommentsPath())
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Clear all collection data (for fresh mode)
|
|
161
|
+
*/
|
|
162
|
+
async clear() {
|
|
163
|
+
const files = [
|
|
164
|
+
this.getPostsPath(),
|
|
165
|
+
this.getCommentsPath(),
|
|
166
|
+
this.getLinksPath(),
|
|
167
|
+
this.getEventsPath()
|
|
168
|
+
];
|
|
169
|
+
for (const file of files) {
|
|
170
|
+
try {
|
|
171
|
+
await fs.promises.unlink(file);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// File might not exist
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* List all collections for a platform/env
|
|
180
|
+
*/
|
|
181
|
+
static async listCollections(baseDir, platform, env) {
|
|
182
|
+
const dir = path.join(baseDir, platform, env);
|
|
183
|
+
try {
|
|
184
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
185
|
+
return entries
|
|
186
|
+
.filter(e => e.isDirectory())
|
|
187
|
+
.map(e => e.name);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.CollectionStorage = CollectionStorage;
|
|
195
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Collection types for unified data management across platforms */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.buildCollectionId = buildCollectionId;
|
|
5
|
+
exports.parseCollectionId = parseCollectionId;
|
|
6
|
+
/**
|
|
7
|
+
* Build collection ID from spec
|
|
8
|
+
*/
|
|
9
|
+
function buildCollectionId(spec) {
|
|
10
|
+
switch (spec.source) {
|
|
11
|
+
case 'search':
|
|
12
|
+
return `search:${spec.keyword}`;
|
|
13
|
+
case 'timeline':
|
|
14
|
+
return `timeline:${spec.date}`;
|
|
15
|
+
case 'user':
|
|
16
|
+
const safeName = spec.userName?.replace(/[\/\\:*?"<>|]/g, '_') || 'unknown';
|
|
17
|
+
return `user:${spec.userId}:${safeName}`;
|
|
18
|
+
case 'note':
|
|
19
|
+
return `note:${spec.noteId}`;
|
|
20
|
+
case 'product':
|
|
21
|
+
return `product:${spec.keyword}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse collection ID back to spec
|
|
26
|
+
*/
|
|
27
|
+
function parseCollectionId(id) {
|
|
28
|
+
const parts = id.split(':');
|
|
29
|
+
if (parts.length < 2)
|
|
30
|
+
return null;
|
|
31
|
+
const source = parts[0];
|
|
32
|
+
switch (source) {
|
|
33
|
+
case 'search':
|
|
34
|
+
return { source: 'search', keyword: parts.slice(1).join(':') };
|
|
35
|
+
case 'timeline':
|
|
36
|
+
return { source: 'timeline', date: parts[1] };
|
|
37
|
+
case 'user':
|
|
38
|
+
return { source: 'user', userId: parts[1], userName: parts[2] };
|
|
39
|
+
case 'note':
|
|
40
|
+
return { source: 'note', noteId: parts[1] };
|
|
41
|
+
case 'product':
|
|
42
|
+
return { source: 'product', keyword: parts.slice(1).join(':') };
|
|
43
|
+
default:
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProcessRegistry - 进程生命周期管理
|
|
3
|
+
*/
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { promises as fs } from 'node:fs';
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
heartbeatIntervalMs: 30000,
|
|
10
|
+
staleTimeoutMs: 120000,
|
|
11
|
+
cleanupIntervalMs: 60000,
|
|
12
|
+
};
|
|
13
|
+
function resolveRegistryPath() {
|
|
14
|
+
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
15
|
+
return path.join(home, '.webauto', 'process-registry.json');
|
|
16
|
+
}
|
|
17
|
+
export class ProcessRegistry {
|
|
18
|
+
static instance = null;
|
|
19
|
+
entries = new Map();
|
|
20
|
+
registryPath;
|
|
21
|
+
config;
|
|
22
|
+
ownPid;
|
|
23
|
+
heartbeatTimer = null;
|
|
24
|
+
cleanupTimer = null;
|
|
25
|
+
initialized = false;
|
|
26
|
+
shutdownHandlersRegistered = false;
|
|
27
|
+
constructor(config = {}) {
|
|
28
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
29
|
+
this.registryPath = resolveRegistryPath();
|
|
30
|
+
this.ownPid = process.pid;
|
|
31
|
+
}
|
|
32
|
+
static getInstance(config) {
|
|
33
|
+
if (!ProcessRegistry.instance) {
|
|
34
|
+
ProcessRegistry.instance = new ProcessRegistry(config);
|
|
35
|
+
}
|
|
36
|
+
return ProcessRegistry.instance;
|
|
37
|
+
}
|
|
38
|
+
async init() {
|
|
39
|
+
if (this.initialized)
|
|
40
|
+
return;
|
|
41
|
+
try {
|
|
42
|
+
const content = await fs.readFile(this.registryPath, 'utf-8');
|
|
43
|
+
const data = JSON.parse(content);
|
|
44
|
+
for (const entry of Object.values(data)) {
|
|
45
|
+
this.entries.set(entry.pid, entry);
|
|
46
|
+
}
|
|
47
|
+
console.log('[ProcessRegistry] Loaded', this.entries.size, 'entries');
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// 无记录
|
|
51
|
+
}
|
|
52
|
+
this.startCleanupTimer();
|
|
53
|
+
this.initialized = true;
|
|
54
|
+
}
|
|
55
|
+
async register(type, profileId, metadata) {
|
|
56
|
+
await this.init();
|
|
57
|
+
const entry = {
|
|
58
|
+
pid: this.ownPid,
|
|
59
|
+
type,
|
|
60
|
+
profileId,
|
|
61
|
+
keyword: metadata?.keyword,
|
|
62
|
+
startedAt: Date.now(),
|
|
63
|
+
lastHeartbeat: Date.now(),
|
|
64
|
+
status: 'running',
|
|
65
|
+
metadata,
|
|
66
|
+
};
|
|
67
|
+
this.entries.set(this.ownPid, entry);
|
|
68
|
+
await this.persist();
|
|
69
|
+
console.log(`[ProcessRegistry] Registered: pid=${this.ownPid} type=${type} profile=${profileId}`);
|
|
70
|
+
this.startHeartbeat();
|
|
71
|
+
// 注册一次 exit 处理器
|
|
72
|
+
if (!this.shutdownHandlersRegistered) {
|
|
73
|
+
this.registerShutdownHandlers();
|
|
74
|
+
this.shutdownHandlersRegistered = true;
|
|
75
|
+
}
|
|
76
|
+
return this.ownPid;
|
|
77
|
+
}
|
|
78
|
+
registerShutdownHandlers() {
|
|
79
|
+
const handler = async () => {
|
|
80
|
+
await this.unregister();
|
|
81
|
+
};
|
|
82
|
+
process.once('SIGINT', handler);
|
|
83
|
+
process.once('SIGTERM', handler);
|
|
84
|
+
process.once('beforeExit', handler);
|
|
85
|
+
}
|
|
86
|
+
heartbeat() {
|
|
87
|
+
const entry = this.entries.get(this.ownPid);
|
|
88
|
+
if (entry) {
|
|
89
|
+
entry.lastHeartbeat = Date.now();
|
|
90
|
+
entry.status = 'running';
|
|
91
|
+
this.persist().catch(() => { });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async unregister() {
|
|
95
|
+
if (!this.entries.has(this.ownPid))
|
|
96
|
+
return;
|
|
97
|
+
this.stopHeartbeat();
|
|
98
|
+
this.entries.delete(this.ownPid);
|
|
99
|
+
await this.persist();
|
|
100
|
+
console.log(`[ProcessRegistry] Unregistered: pid=${this.ownPid}`);
|
|
101
|
+
}
|
|
102
|
+
getAll() {
|
|
103
|
+
return Array.from(this.entries.values());
|
|
104
|
+
}
|
|
105
|
+
getRunning() {
|
|
106
|
+
return this.getAll().filter(e => e.status === 'running');
|
|
107
|
+
}
|
|
108
|
+
async cleanStale() {
|
|
109
|
+
await this.init();
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const cleaned = [];
|
|
112
|
+
for (const [pid, entry] of this.entries) {
|
|
113
|
+
if (pid === this.ownPid)
|
|
114
|
+
continue;
|
|
115
|
+
if (now - entry.lastHeartbeat > this.config.staleTimeoutMs) {
|
|
116
|
+
entry.status = 'stale';
|
|
117
|
+
const isAlive = this.isProcessAlive(pid);
|
|
118
|
+
if (!isAlive) {
|
|
119
|
+
this.entries.delete(pid);
|
|
120
|
+
cleaned.push(`pid=${pid} (dead)`);
|
|
121
|
+
await this.cleanupBrowserSession(entry.profileId);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(`[ProcessRegistry] Killing stale process: pid=${pid} type=${entry.type}`);
|
|
125
|
+
this.killProcess(pid);
|
|
126
|
+
this.entries.delete(pid);
|
|
127
|
+
cleaned.push(`pid=${pid} (killed)`);
|
|
128
|
+
await this.cleanupBrowserSession(entry.profileId);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (cleaned.length > 0) {
|
|
133
|
+
await this.persist();
|
|
134
|
+
console.log(`[ProcessRegistry] Cleaned ${cleaned.length} stale entries`);
|
|
135
|
+
}
|
|
136
|
+
return { cleaned: cleaned.length, killed: cleaned };
|
|
137
|
+
}
|
|
138
|
+
getStatus() {
|
|
139
|
+
const entry = this.entries.get(this.ownPid);
|
|
140
|
+
if (!entry)
|
|
141
|
+
return null;
|
|
142
|
+
return {
|
|
143
|
+
pid: entry.pid,
|
|
144
|
+
type: entry.type,
|
|
145
|
+
profileId: entry.profileId,
|
|
146
|
+
uptime: Date.now() - entry.startedAt,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
startHeartbeat() {
|
|
150
|
+
if (this.heartbeatTimer)
|
|
151
|
+
return;
|
|
152
|
+
this.heartbeatTimer = setInterval(() => {
|
|
153
|
+
this.heartbeat();
|
|
154
|
+
}, this.config.heartbeatIntervalMs);
|
|
155
|
+
this.heartbeatTimer.unref();
|
|
156
|
+
}
|
|
157
|
+
stopHeartbeat() {
|
|
158
|
+
if (this.heartbeatTimer) {
|
|
159
|
+
clearInterval(this.heartbeatTimer);
|
|
160
|
+
this.heartbeatTimer = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
startCleanupTimer() {
|
|
164
|
+
if (this.cleanupTimer)
|
|
165
|
+
return;
|
|
166
|
+
this.cleanupTimer = setInterval(() => {
|
|
167
|
+
this.cleanStale().catch(() => { });
|
|
168
|
+
}, this.config.cleanupIntervalMs);
|
|
169
|
+
this.cleanupTimer.unref();
|
|
170
|
+
}
|
|
171
|
+
isProcessAlive(pid) {
|
|
172
|
+
try {
|
|
173
|
+
process.kill(pid, 0);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
killProcess(pid) {
|
|
181
|
+
try {
|
|
182
|
+
if (process.platform === 'win32') {
|
|
183
|
+
execSync(`taskkill /PID ${pid} /T /F`, { stdio: 'ignore' });
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
process.kill(pid, 'SIGTERM');
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
if (this.isProcessAlive(pid)) {
|
|
189
|
+
try {
|
|
190
|
+
process.kill(pid, 'SIGKILL');
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
}
|
|
194
|
+
}, 5000);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch { }
|
|
198
|
+
}
|
|
199
|
+
async cleanupBrowserSession(profileId) {
|
|
200
|
+
try {
|
|
201
|
+
execSync(`camo stop ${profileId}`, { stdio: 'ignore', timeout: 10000 });
|
|
202
|
+
console.log(`[ProcessRegistry] Cleaned browser: ${profileId}`);
|
|
203
|
+
}
|
|
204
|
+
catch { }
|
|
205
|
+
}
|
|
206
|
+
async persist() {
|
|
207
|
+
try {
|
|
208
|
+
const dir = path.dirname(this.registryPath);
|
|
209
|
+
await fs.mkdir(dir, { recursive: true });
|
|
210
|
+
const data = {};
|
|
211
|
+
for (const [pid, entry] of this.entries) {
|
|
212
|
+
data[pid] = entry;
|
|
213
|
+
}
|
|
214
|
+
await fs.writeFile(this.registryPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.error('[ProcessRegistry] Failed to persist:', err);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async shutdown() {
|
|
221
|
+
this.stopHeartbeat();
|
|
222
|
+
if (this.cleanupTimer) {
|
|
223
|
+
clearInterval(this.cleanupTimer);
|
|
224
|
+
this.cleanupTimer = null;
|
|
225
|
+
}
|
|
226
|
+
await this.unregister();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
export const processRegistry = ProcessRegistry.getInstance();
|
|
230
|
+
//# sourceMappingURL=index.js.map
|