octoparse-cli 0.1.14
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/README.md +271 -0
- package/RUNTIME_SECURITY_NOTICE.txt +41 -0
- package/SECURITY.md +24 -0
- package/dist/cli/args.js +34 -0
- package/dist/cli/help.js +214 -0
- package/dist/cli/output.js +39 -0
- package/dist/commands/auth.js +283 -0
- package/dist/commands/capabilities.js +118 -0
- package/dist/commands/cloud.js +241 -0
- package/dist/commands/data.js +220 -0
- package/dist/commands/doctor.js +73 -0
- package/dist/commands/env.js +63 -0
- package/dist/commands/local.js +251 -0
- package/dist/commands/run.js +622 -0
- package/dist/commands/runs.js +171 -0
- package/dist/commands/task.js +101 -0
- package/dist/index.js +133 -0
- package/dist/runtime/account-capabilities.js +71 -0
- package/dist/runtime/api-client.js +290 -0
- package/dist/runtime/artifacts.js +33 -0
- package/dist/runtime/auth.js +94 -0
- package/dist/runtime/bridge-hub.js +173 -0
- package/dist/runtime/client-headers.js +23 -0
- package/dist/runtime/cloud-data.js +75 -0
- package/dist/runtime/config.js +48 -0
- package/dist/runtime/data-exporter.js +267 -0
- package/dist/runtime/engine-host.js +449 -0
- package/dist/runtime/local-runs.js +92 -0
- package/dist/runtime/naming.js +13 -0
- package/dist/runtime/run-control.js +363 -0
- package/dist/runtime/run-services.js +380 -0
- package/dist/runtime/security-notice.js +78 -0
- package/dist/runtime/task-definition-provider.js +282 -0
- package/dist/types.js +4 -0
- package/examples/minimal-task.json +6 -0
- package/examples/navigate-example-task.json +6 -0
- package/node_modules/@octopus/bpmn/index.js +3 -0
- package/node_modules/@octopus/bpmn/lib/Context.js +245 -0
- package/node_modules/@octopus/bpmn/lib/Definition.js +258 -0
- package/node_modules/@octopus/bpmn/lib/Engine.js +275 -0
- package/node_modules/@octopus/bpmn/lib/PrematureStopError.js +7 -0
- package/node_modules/@octopus/bpmn/lib/activities/Activity.js +202 -0
- package/node_modules/@octopus/bpmn/lib/activities/BaseProcess.js +308 -0
- package/node_modules/@octopus/bpmn/lib/activities/BaseTask.js +145 -0
- package/node_modules/@octopus/bpmn/lib/activities/BoundaryEvent.js +12 -0
- package/node_modules/@octopus/bpmn/lib/activities/Dummy.js +10 -0
- package/node_modules/@octopus/bpmn/lib/activities/EventDefinition.js +99 -0
- package/node_modules/@octopus/bpmn/lib/activities/Flow.js +52 -0
- package/node_modules/@octopus/bpmn/lib/activities/Form.js +67 -0
- package/node_modules/@octopus/bpmn/lib/activities/InputOutput.js +53 -0
- package/node_modules/@octopus/bpmn/lib/activities/IntermediateCatchEvent.js +12 -0
- package/node_modules/@octopus/bpmn/lib/activities/MessageFlow.js +19 -0
- package/node_modules/@octopus/bpmn/lib/activities/MultiInstanceLoopCharacteristics.js +160 -0
- package/node_modules/@octopus/bpmn/lib/activities/Properties.js +27 -0
- package/node_modules/@octopus/bpmn/lib/activities/SequenceFlow.js +56 -0
- package/node_modules/@octopus/bpmn/lib/activities/ServiceConnector.js +71 -0
- package/node_modules/@octopus/bpmn/lib/context-helper.js +198 -0
- package/node_modules/@octopus/bpmn/lib/events/EndEvent.js +22 -0
- package/node_modules/@octopus/bpmn/lib/events/ErrorEvent.js +41 -0
- package/node_modules/@octopus/bpmn/lib/events/MessageEvent.js +19 -0
- package/node_modules/@octopus/bpmn/lib/events/StartEvent.js +55 -0
- package/node_modules/@octopus/bpmn/lib/events/TimerEvent.js +75 -0
- package/node_modules/@octopus/bpmn/lib/expressions.js +41 -0
- package/node_modules/@octopus/bpmn/lib/gateways/ExclusiveGateway.js +86 -0
- package/node_modules/@octopus/bpmn/lib/gateways/InclusiveGateway.js +56 -0
- package/node_modules/@octopus/bpmn/lib/gateways/ParallelGateway.js +195 -0
- package/node_modules/@octopus/bpmn/lib/getPropertyValue.js +83 -0
- package/node_modules/@octopus/bpmn/lib/index.js +6 -0
- package/node_modules/@octopus/bpmn/lib/mapper.js +55 -0
- package/node_modules/@octopus/bpmn/lib/parameter.js +119 -0
- package/node_modules/@octopus/bpmn/lib/script-helper.js +45 -0
- package/node_modules/@octopus/bpmn/lib/tasks/ManualTask.js +31 -0
- package/node_modules/@octopus/bpmn/lib/tasks/ReceiveTask.js +31 -0
- package/node_modules/@octopus/bpmn/lib/tasks/ScriptTask.js +35 -0
- package/node_modules/@octopus/bpmn/lib/tasks/SendTask.js +16 -0
- package/node_modules/@octopus/bpmn/lib/tasks/ServiceTask.js +68 -0
- package/node_modules/@octopus/bpmn/lib/tasks/SubProcess.js +17 -0
- package/node_modules/@octopus/bpmn/lib/tasks/Task.js +16 -0
- package/node_modules/@octopus/bpmn/lib/tasks/UserTask.js +47 -0
- package/node_modules/@octopus/bpmn/lib/transformer.js +13 -0
- package/node_modules/@octopus/bpmn/lib/validation.js +111 -0
- package/node_modules/@octopus/bpmn/package.json +17 -0
- package/node_modules/@octopus/bpmn/types/bpmn.d.ts +85 -0
- package/node_modules/@octopus/engine/README.md +370 -0
- package/node_modules/@octopus/engine/dist/actions/BackPreWebPageAction.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/actions/BackPreWebPageAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/BaseAction.d.ts +339 -0
- package/node_modules/@octopus/engine/dist/actions/BaseAction.js +1559 -0
- package/node_modules/@octopus/engine/dist/actions/BranchAction.d.ts +9 -0
- package/node_modules/@octopus/engine/dist/actions/BranchAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/ClickAction.d.ts +22 -0
- package/node_modules/@octopus/engine/dist/actions/ClickAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/ConditionAction.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/actions/ConditionAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/EmptyAction.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/actions/EmptyAction.js +12 -0
- package/node_modules/@octopus/engine/dist/actions/EnterCaptchaAction.d.ts +28 -0
- package/node_modules/@octopus/engine/dist/actions/EnterCaptchaAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/EnterTextAction.d.ts +20 -0
- package/node_modules/@octopus/engine/dist/actions/EnterTextAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/ExtractDataAction.d.ts +40 -0
- package/node_modules/@octopus/engine/dist/actions/ExtractDataAction.js +1 -0
- package/node_modules/@octopus/engine/dist/actions/LoopAction.d.ts +41 -0
- package/node_modules/@octopus/engine/dist/actions/LoopAction.js +526 -0
- package/node_modules/@octopus/engine/dist/actions/LoopStartAction.d.ts +47 -0
- package/node_modules/@octopus/engine/dist/actions/LoopStartAction.js +607 -0
- package/node_modules/@octopus/engine/dist/actions/MouseOverAction.d.ts +8 -0
- package/node_modules/@octopus/engine/dist/actions/MouseOverAction.js +34 -0
- package/node_modules/@octopus/engine/dist/actions/NavigateAction.d.ts +38 -0
- package/node_modules/@octopus/engine/dist/actions/NavigateAction.js +535 -0
- package/node_modules/@octopus/engine/dist/actions/SwitchComboAction.d.ts +13 -0
- package/node_modules/@octopus/engine/dist/actions/SwitchComboAction.js +69 -0
- package/node_modules/@octopus/engine/dist/browser.d.ts +17 -0
- package/node_modules/@octopus/engine/dist/browser.js +157 -0
- package/node_modules/@octopus/engine/dist/browserProxy.d.ts +90 -0
- package/node_modules/@octopus/engine/dist/browserProxy.js +1 -0
- package/node_modules/@octopus/engine/dist/configs/BaseConfig.d.ts +20 -0
- package/node_modules/@octopus/engine/dist/configs/BaseConfig.js +88 -0
- package/node_modules/@octopus/engine/dist/configs/BranchConfig.d.ts +7 -0
- package/node_modules/@octopus/engine/dist/configs/BranchConfig.js +1 -0
- package/node_modules/@octopus/engine/dist/configs/ClickConfig.d.ts +36 -0
- package/node_modules/@octopus/engine/dist/configs/ClickConfig.js +65 -0
- package/node_modules/@octopus/engine/dist/configs/EnterCaptchaConfig.d.ts +19 -0
- package/node_modules/@octopus/engine/dist/configs/EnterCaptchaConfig.js +25 -0
- package/node_modules/@octopus/engine/dist/configs/EnterTextConfig.d.ts +24 -0
- package/node_modules/@octopus/engine/dist/configs/EnterTextConfig.js +36 -0
- package/node_modules/@octopus/engine/dist/configs/ExtractDataConfig.d.ts +12 -0
- package/node_modules/@octopus/engine/dist/configs/ExtractDataConfig.js +1 -0
- package/node_modules/@octopus/engine/dist/configs/LoopConfig.d.ts +25 -0
- package/node_modules/@octopus/engine/dist/configs/LoopConfig.js +40 -0
- package/node_modules/@octopus/engine/dist/configs/LoopStartConfig.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/configs/LoopStartConfig.js +12 -0
- package/node_modules/@octopus/engine/dist/configs/MouseOverConfig.d.ts +8 -0
- package/node_modules/@octopus/engine/dist/configs/MouseOverConfig.js +15 -0
- package/node_modules/@octopus/engine/dist/configs/NavigateConfig.d.ts +41 -0
- package/node_modules/@octopus/engine/dist/configs/NavigateConfig.js +121 -0
- package/node_modules/@octopus/engine/dist/configs/SwitchComboConfig.d.ts +8 -0
- package/node_modules/@octopus/engine/dist/configs/SwitchComboConfig.js +15 -0
- package/node_modules/@octopus/engine/dist/enums/index.d.ts +419 -0
- package/node_modules/@octopus/engine/dist/enums/index.js +314 -0
- package/node_modules/@octopus/engine/dist/extension/BrowserWebSocketTransport-D_zAGZMQ.js +1 -0
- package/node_modules/@octopus/engine/dist/extension/LaunchOptions-DxvePrV4.js +6 -0
- package/node_modules/@octopus/engine/dist/extension/NodeWebSocketTransport-BTgRVB7Z.js +6 -0
- package/node_modules/@octopus/engine/dist/extension/background.js +396 -0
- package/node_modules/@octopus/engine/dist/extension/bidi-C_GIZ8Uz.js +131 -0
- package/node_modules/@octopus/engine/dist/extension/manifest.json +27 -0
- package/node_modules/@octopus/engine/dist/extension/src/content/anti-detection.js +1 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/BaseExtensionBridge.d.ts +21 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/BaseExtensionBridge.js +117 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/SessionExtensionBridge.d.ts +17 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/SessionExtensionBridge.js +29 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/index.d.ts +2 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/index.js +5 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/types.d.ts +159 -0
- package/node_modules/@octopus/engine/dist/extension-bridge/types.js +5 -0
- package/node_modules/@octopus/engine/dist/extensions/ublock-origin/uBlock0.chromium.tar.xz +0 -0
- package/node_modules/@octopus/engine/dist/extensions/ublock-origin-lite/uBOLite.chromium.tar.xz +0 -0
- package/node_modules/@octopus/engine/dist/index.d.ts +169 -0
- package/node_modules/@octopus/engine/dist/index.js +1 -0
- package/node_modules/@octopus/engine/dist/models/actionItem.d.ts +16 -0
- package/node_modules/@octopus/engine/dist/models/actionItem.js +15 -0
- package/node_modules/@octopus/engine/dist/models/conditionCheckArgs.d.ts +11 -0
- package/node_modules/@octopus/engine/dist/models/conditionCheckArgs.js +11 -0
- package/node_modules/@octopus/engine/dist/models/customizeCookie.d.ts +14 -0
- package/node_modules/@octopus/engine/dist/models/customizeCookie.js +6 -0
- package/node_modules/@octopus/engine/dist/models/downloadFileConfig.d.ts +17 -0
- package/node_modules/@octopus/engine/dist/models/downloadFileConfig.js +26 -0
- package/node_modules/@octopus/engine/dist/models/elementNotFoundArgs.d.ts +8 -0
- package/node_modules/@octopus/engine/dist/models/elementNotFoundArgs.js +12 -0
- package/node_modules/@octopus/engine/dist/models/elementNotFoundError.d.ts +2 -0
- package/node_modules/@octopus/engine/dist/models/elementNotFoundError.js +6 -0
- package/node_modules/@octopus/engine/dist/models/extractItem.d.ts +37 -0
- package/node_modules/@octopus/engine/dist/models/extractItem.js +35 -0
- package/node_modules/@octopus/engine/dist/models/extractTemplate.d.ts +11 -0
- package/node_modules/@octopus/engine/dist/models/extractTemplate.js +48 -0
- package/node_modules/@octopus/engine/dist/models/extractTextItem.d.ts +10 -0
- package/node_modules/@octopus/engine/dist/models/extractTextItem.js +17 -0
- package/node_modules/@octopus/engine/dist/models/globalConfig.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/models/globalConfig.js +1 -0
- package/node_modules/@octopus/engine/dist/models/httpHeader.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/models/httpHeader.js +10 -0
- package/node_modules/@octopus/engine/dist/models/operation.d.ts +27 -0
- package/node_modules/@octopus/engine/dist/models/operation.js +242 -0
- package/node_modules/@octopus/engine/dist/models/retryCondition.d.ts +7 -0
- package/node_modules/@octopus/engine/dist/models/retryCondition.js +10 -0
- package/node_modules/@octopus/engine/dist/models/task.d.ts +89 -0
- package/node_modules/@octopus/engine/dist/models/task.js +120 -0
- package/node_modules/@octopus/engine/dist/models/trigger.d.ts +66 -0
- package/node_modules/@octopus/engine/dist/models/trigger.js +117 -0
- package/node_modules/@octopus/engine/dist/package.json +26 -0
- package/node_modules/@octopus/engine/dist/public-types.d.ts +13 -0
- package/node_modules/@octopus/engine/dist/public-types.js +2 -0
- package/node_modules/@octopus/engine/dist/settings.d.ts +41 -0
- package/node_modules/@octopus/engine/dist/settings.js +20 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/ClickCaptchaSolver.d.ts +6 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/ClickCaptchaSolver.js +1 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/HCaptchaSolver.d.ts +4 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/HCaptchaSolver.js +73 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/ImageCaptchaSolver.d.ts +2 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/ImageCaptchaSolver.js +74 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/RecaptchaSolver.d.ts +9 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/RecaptchaSolver.js +371 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/SliderCaptchaSolver.d.ts +6 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/SliderCaptchaSolver.js +184 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/SlidingTrajectory.d.ts +50 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/SlidingTrajectory.js +125 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/types.d.ts +68 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/types.js +34 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/utils.d.ts +2 -0
- package/node_modules/@octopus/engine/dist/solvers/captcha/utils.js +15 -0
- package/node_modules/@octopus/engine/dist/translator/actionFactory.d.ts +6 -0
- package/node_modules/@octopus/engine/dist/translator/actionFactory.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/activityTypeEnum.d.ts +22 -0
- package/node_modules/@octopus/engine/dist/translator/activityTypeEnum.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/backPreWebPageAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/backPreWebPageAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/baseAction.d.ts +31 -0
- package/node_modules/@octopus/engine/dist/translator/baseAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/breakActivity.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/breakActivity.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/clickAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/clickAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/completeWF.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/completeWF.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/conditionAction.d.ts +6 -0
- package/node_modules/@octopus/engine/dist/translator/conditionAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/emptyAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/emptyAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/enterCapachaAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/enterCapachaAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/enterTextAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/enterTextAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/extractDataAction.d.ts +13 -0
- package/node_modules/@octopus/engine/dist/translator/extractDataAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/loopAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/loopAction.js +1 -0
- package/node_modules/@octopus/engine/dist/translator/mouseOverAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/mouseOverAction.js +19 -0
- package/node_modules/@octopus/engine/dist/translator/navigateAction.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/navigateAction.js +117 -0
- package/node_modules/@octopus/engine/dist/translator/rootAction.d.ts +6 -0
- package/node_modules/@octopus/engine/dist/translator/rootAction.js +80 -0
- package/node_modules/@octopus/engine/dist/translator/switchCombo2Action.d.ts +5 -0
- package/node_modules/@octopus/engine/dist/translator/switchCombo2Action.js +19 -0
- package/node_modules/@octopus/engine/dist/translator/translator.d.ts +1 -0
- package/node_modules/@octopus/engine/dist/translator/translator.js +36 -0
- package/node_modules/@octopus/engine/dist/type.d.ts +25 -0
- package/node_modules/@octopus/engine/dist/type.js +2 -0
- package/node_modules/@octopus/engine/dist/types/browser.d.ts +191 -0
- package/node_modules/@octopus/engine/dist/types/browser.js +1 -0
- package/node_modules/@octopus/engine/dist/types/browserManager.d.ts +41 -0
- package/node_modules/@octopus/engine/dist/types/browserManager.js +1 -0
- package/node_modules/@octopus/engine/dist/types/index.d.ts +40 -0
- package/node_modules/@octopus/engine/dist/types/index.js +2 -0
- package/node_modules/@octopus/engine/dist/types/plugin.d.ts +29 -0
- package/node_modules/@octopus/engine/dist/types/plugin.js +2 -0
- package/node_modules/@octopus/engine/dist/utils/AsyncEmitter.d.ts +15 -0
- package/node_modules/@octopus/engine/dist/utils/AsyncEmitter.js +1 -0
- package/node_modules/@octopus/engine/dist/utils/DataStore.d.ts +58 -0
- package/node_modules/@octopus/engine/dist/utils/DataStore.js +1 -0
- package/node_modules/@octopus/engine/dist/utils/DateTimeFormatHelper.d.ts +22 -0
- package/node_modules/@octopus/engine/dist/utils/DateTimeFormatHelper.js +173 -0
- package/node_modules/@octopus/engine/dist/utils/FileDownloader.d.ts +108 -0
- package/node_modules/@octopus/engine/dist/utils/FileDownloader.js +1 -0
- package/node_modules/@octopus/engine/dist/utils/HttpRequester.d.ts +43 -0
- package/node_modules/@octopus/engine/dist/utils/HttpRequester.js +174 -0
- package/node_modules/@octopus/engine/dist/utils/JsonParser.d.ts +95 -0
- package/node_modules/@octopus/engine/dist/utils/JsonParser.js +439 -0
- package/node_modules/@octopus/engine/dist/utils/Operations.d.ts +27 -0
- package/node_modules/@octopus/engine/dist/utils/Operations.js +115 -0
- package/node_modules/@octopus/engine/dist/utils/index.d.ts +28 -0
- package/node_modules/@octopus/engine/dist/utils/index.js +356 -0
- package/node_modules/@octopus/engine/package.json +58 -0
- package/package.json +79 -0
- package/schemas/capabilities-v1.schema.json +234 -0
- package/schemas/detached-bootstrap-v1.schema.json +42 -0
- package/schemas/json-envelope-v1.schema.json +39 -0
- package/schemas/run-event-v1.schema.json +47 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, readdir, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { createServer, createConnection } from 'node:net';
|
|
5
|
+
import { homedir, tmpdir } from 'node:os';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
export async function startRunControlServer(options) {
|
|
8
|
+
const socketPath = join(tmpdir(), `octo-${process.pid}-${shortHash(options.runId)}.sock`);
|
|
9
|
+
await unlink(socketPath).catch(() => undefined);
|
|
10
|
+
let state = {
|
|
11
|
+
runId: options.runId,
|
|
12
|
+
lotId: options.lotId,
|
|
13
|
+
taskId: options.taskId,
|
|
14
|
+
taskName: options.taskName,
|
|
15
|
+
pid: process.pid,
|
|
16
|
+
socketPath,
|
|
17
|
+
status: 'running',
|
|
18
|
+
outputDir: options.outputDir,
|
|
19
|
+
updatedAt: new Date().toISOString()
|
|
20
|
+
};
|
|
21
|
+
const writeState = async () => {
|
|
22
|
+
await mkdir(dirname(controlFilePath(options.runDir)), { recursive: true });
|
|
23
|
+
await writeFile(controlFilePath(options.runDir), `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
24
|
+
await mkdir(dirname(taskControlFilePath(options.taskId)), { recursive: true });
|
|
25
|
+
await writeFile(taskControlFilePath(options.taskId), `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
26
|
+
};
|
|
27
|
+
const server = createServer((socket) => {
|
|
28
|
+
void handleSocket(socket, async (command) => {
|
|
29
|
+
const status = await options.onCommand(command, state);
|
|
30
|
+
state = { ...state, status, updatedAt: new Date().toISOString() };
|
|
31
|
+
await writeState().catch(() => undefined);
|
|
32
|
+
return { ok: true, data: state };
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
server.once('error', reject);
|
|
37
|
+
server.listen(socketPath, () => {
|
|
38
|
+
server.off('error', reject);
|
|
39
|
+
resolve();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
await writeState();
|
|
43
|
+
return {
|
|
44
|
+
socketPath,
|
|
45
|
+
async updateStatus(status) {
|
|
46
|
+
state = { ...state, status, updatedAt: new Date().toISOString() };
|
|
47
|
+
await writeState();
|
|
48
|
+
},
|
|
49
|
+
async close() {
|
|
50
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
51
|
+
await unlink(socketPath).catch(() => undefined);
|
|
52
|
+
await unlinkTaskControlFile(options.taskId, socketPath);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export async function sendTaskControlCommand(taskId, command) {
|
|
57
|
+
const state = await readTaskControlState(taskId);
|
|
58
|
+
if (!state) {
|
|
59
|
+
throw new Error(`Task ${taskId} has no active local extraction`);
|
|
60
|
+
}
|
|
61
|
+
const socketPath = resolveSocketPath(state.socketPath);
|
|
62
|
+
if (!socketPath) {
|
|
63
|
+
await cleanupStaleTaskState(state);
|
|
64
|
+
throw new Error(`The local control channel for task ${taskId} is unavailable; stale run state was cleaned up. Restart the task.`);
|
|
65
|
+
}
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
response = await requestControl(socketPath, command);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
await cleanupStaleTaskState(state);
|
|
72
|
+
throw new Error(`The local control channel for task ${taskId} is unavailable; stale run state was cleaned up. Restart the task.`);
|
|
73
|
+
}
|
|
74
|
+
if (!response.ok || !response.data) {
|
|
75
|
+
throw new Error(response.error || `Failed to control task ${taskId}`);
|
|
76
|
+
}
|
|
77
|
+
return response.data;
|
|
78
|
+
}
|
|
79
|
+
export async function sendRunControlCommand(outputDir, runId, command) {
|
|
80
|
+
const state = await readRunControlState(outputDir, runId);
|
|
81
|
+
if (!state) {
|
|
82
|
+
throw new Error(`Run ${runId} has no available local control channel; it may have ended, or --output does not match`);
|
|
83
|
+
}
|
|
84
|
+
const socketPath = resolveSocketPath(state.socketPath);
|
|
85
|
+
if (!socketPath) {
|
|
86
|
+
await cleanupStaleRunState(outputDir, runId, state);
|
|
87
|
+
throw new Error(`The control channel for run ${runId} is unavailable; stale run state was cleaned up. Restart the task.`);
|
|
88
|
+
}
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await requestControl(socketPath, command);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
await cleanupStaleRunState(outputDir, runId, state);
|
|
95
|
+
throw new Error(`The control channel for run ${runId} is unavailable; stale run state was cleaned up. Restart the task.`);
|
|
96
|
+
}
|
|
97
|
+
if (!response.ok || !response.data) {
|
|
98
|
+
throw new Error(response.error || `Failed to control run ${runId}`);
|
|
99
|
+
}
|
|
100
|
+
return response.data;
|
|
101
|
+
}
|
|
102
|
+
export async function readTaskControlState(taskId) {
|
|
103
|
+
return readControlStateFile(taskControlFilePath(taskId), dirname(taskControlFilePath(taskId)));
|
|
104
|
+
}
|
|
105
|
+
export async function cleanupTaskControlState(taskId) {
|
|
106
|
+
const state = await readTaskControlState(taskId);
|
|
107
|
+
if (state)
|
|
108
|
+
await cleanupStaleTaskState(state);
|
|
109
|
+
return state;
|
|
110
|
+
}
|
|
111
|
+
export async function listActiveTaskControlStates() {
|
|
112
|
+
const dir = taskControlDir();
|
|
113
|
+
let entries = [];
|
|
114
|
+
try {
|
|
115
|
+
entries = await readdir(dir);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
const states = [];
|
|
121
|
+
for (const entry of entries) {
|
|
122
|
+
if (!entry.endsWith('.json'))
|
|
123
|
+
continue;
|
|
124
|
+
const state = await readControlStateFile(join(dir, entry), dir);
|
|
125
|
+
if (state && await isRunControlReachable(state))
|
|
126
|
+
states.push(state);
|
|
127
|
+
}
|
|
128
|
+
return states;
|
|
129
|
+
}
|
|
130
|
+
export async function readRunControlState(outputDir, runId) {
|
|
131
|
+
return readControlStateFile(controlFilePath(join(outputDir, runId)), outputDir);
|
|
132
|
+
}
|
|
133
|
+
export function isRunControlAlive(state) {
|
|
134
|
+
return Boolean(state?.socketPath && resolveSocketPath(state.socketPath));
|
|
135
|
+
}
|
|
136
|
+
export async function isRunControlReachable(state) {
|
|
137
|
+
const socketPath = state?.socketPath ? resolveSocketPath(state.socketPath) : null;
|
|
138
|
+
if (!socketPath)
|
|
139
|
+
return false;
|
|
140
|
+
try {
|
|
141
|
+
const response = await requestControl(socketPath, 'status', 500);
|
|
142
|
+
return response.ok && Boolean(response.data);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function resolveRunControlSocketPath(state) {
|
|
149
|
+
return resolveSocketPath(state.socketPath);
|
|
150
|
+
}
|
|
151
|
+
export async function cleanupTaskControlStates() {
|
|
152
|
+
const dir = taskControlDir();
|
|
153
|
+
let entries = [];
|
|
154
|
+
try {
|
|
155
|
+
entries = await readdir(dir);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return { checked: 0, alive: 0, removed: 0, orphaned: [] };
|
|
159
|
+
}
|
|
160
|
+
const result = { checked: 0, alive: 0, removed: 0, orphaned: [] };
|
|
161
|
+
for (const entry of entries) {
|
|
162
|
+
if (!entry.endsWith('.json'))
|
|
163
|
+
continue;
|
|
164
|
+
const filePath = join(dir, entry);
|
|
165
|
+
const state = await readControlStateFile(filePath, dirname(filePath));
|
|
166
|
+
await cleanupControlFile(filePath, state, result);
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
export async function cleanupRunControlStates(outputDir) {
|
|
171
|
+
let entries = [];
|
|
172
|
+
try {
|
|
173
|
+
entries = await readdir(outputDir);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return { checked: 0, alive: 0, removed: 0, orphaned: [] };
|
|
177
|
+
}
|
|
178
|
+
const result = { checked: 0, alive: 0, removed: 0, orphaned: [] };
|
|
179
|
+
for (const entry of entries) {
|
|
180
|
+
const filePath = controlFilePath(join(outputDir, entry));
|
|
181
|
+
if (!existsSync(filePath))
|
|
182
|
+
continue;
|
|
183
|
+
const state = await readControlStateFile(filePath, outputDir);
|
|
184
|
+
await cleanupControlFile(filePath, state, result);
|
|
185
|
+
if (state && !(await isRunControlReachable(state))) {
|
|
186
|
+
await unlinkTaskControlFile(state.taskId, state.socketPath).catch(() => undefined);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
async function readControlStateFile(filePath, fallbackOutputDir) {
|
|
192
|
+
try {
|
|
193
|
+
const raw = await readFile(filePath, 'utf8');
|
|
194
|
+
const parsed = JSON.parse(raw);
|
|
195
|
+
if (!parsed.runId || !parsed.lotId || !parsed.taskId || !parsed.socketPath || !parsed.status)
|
|
196
|
+
return null;
|
|
197
|
+
return {
|
|
198
|
+
runId: parsed.runId,
|
|
199
|
+
lotId: parsed.lotId,
|
|
200
|
+
taskId: parsed.taskId,
|
|
201
|
+
taskName: typeof parsed.taskName === 'string' ? parsed.taskName : undefined,
|
|
202
|
+
pid: typeof parsed.pid === 'number' ? parsed.pid : 0,
|
|
203
|
+
socketPath: parsed.socketPath,
|
|
204
|
+
status: parsed.status,
|
|
205
|
+
outputDir: typeof parsed.outputDir === 'string' ? parsed.outputDir : fallbackOutputDir,
|
|
206
|
+
updatedAt: typeof parsed.updatedAt === 'string' ? parsed.updatedAt : ''
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
export function controlStateToSummary(state) {
|
|
214
|
+
return {
|
|
215
|
+
runId: state.runId,
|
|
216
|
+
lotId: state.lotId,
|
|
217
|
+
taskId: state.taskId,
|
|
218
|
+
taskName: state.taskName,
|
|
219
|
+
status: state.status,
|
|
220
|
+
total: 0,
|
|
221
|
+
outputDir: join(state.outputDir, state.runId),
|
|
222
|
+
startedAt: state.updatedAt
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function controlFilePath(runDir) {
|
|
226
|
+
return join(runDir, 'control.json');
|
|
227
|
+
}
|
|
228
|
+
function taskControlFilePath(taskId) {
|
|
229
|
+
return join(taskControlDir(), `${safeSocketName(taskId)}.json`);
|
|
230
|
+
}
|
|
231
|
+
function taskControlDir() {
|
|
232
|
+
return join(homedir(), '.octoparse', 'active-local');
|
|
233
|
+
}
|
|
234
|
+
async function cleanupControlFile(filePath, state, result) {
|
|
235
|
+
result.checked += 1;
|
|
236
|
+
if (await isRunControlReachable(state)) {
|
|
237
|
+
result.alive += 1;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
result.removed += 1;
|
|
241
|
+
result.orphaned.push({
|
|
242
|
+
filePath,
|
|
243
|
+
taskId: state?.taskId,
|
|
244
|
+
runId: state?.runId,
|
|
245
|
+
socketPath: state?.socketPath,
|
|
246
|
+
lastStatus: state?.status
|
|
247
|
+
});
|
|
248
|
+
await unlink(filePath).catch(() => undefined);
|
|
249
|
+
}
|
|
250
|
+
async function unlinkTaskControlFile(taskId, socketPath) {
|
|
251
|
+
const filePath = taskControlFilePath(taskId);
|
|
252
|
+
const state = await readControlStateFile(filePath, dirname(filePath));
|
|
253
|
+
if (state?.socketPath === socketPath) {
|
|
254
|
+
await unlink(filePath).catch(() => undefined);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function cleanupStaleTaskState(state) {
|
|
258
|
+
await unlinkTaskControlFile(state.taskId, state.socketPath).catch(() => undefined);
|
|
259
|
+
await unlink(state.socketPath).catch(() => undefined);
|
|
260
|
+
await unlink(controlFilePath(join(state.outputDir, state.runId))).catch(() => undefined);
|
|
261
|
+
}
|
|
262
|
+
async function cleanupStaleRunState(outputDir, runId, state) {
|
|
263
|
+
await unlink(controlFilePath(join(outputDir, runId))).catch(() => undefined);
|
|
264
|
+
await unlinkTaskControlFile(state.taskId, state.socketPath).catch(() => undefined);
|
|
265
|
+
await unlink(state.socketPath).catch(() => undefined);
|
|
266
|
+
}
|
|
267
|
+
function safeSocketName(runId) {
|
|
268
|
+
return runId.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 60);
|
|
269
|
+
}
|
|
270
|
+
function shortHash(value) {
|
|
271
|
+
return createHash('sha1').update(value).digest('hex').slice(0, 12);
|
|
272
|
+
}
|
|
273
|
+
function resolveSocketPath(socketPath) {
|
|
274
|
+
if (existsSync(socketPath))
|
|
275
|
+
return socketPath;
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
async function handleSocket(socket, handler) {
|
|
279
|
+
let raw = '';
|
|
280
|
+
let handled = false;
|
|
281
|
+
socket.setEncoding('utf8');
|
|
282
|
+
const respond = (response) => {
|
|
283
|
+
socket.end(`${JSON.stringify(response)}\n`);
|
|
284
|
+
};
|
|
285
|
+
const handleRequest = () => {
|
|
286
|
+
if (handled || !raw.trim())
|
|
287
|
+
return;
|
|
288
|
+
handled = true;
|
|
289
|
+
void (async () => {
|
|
290
|
+
try {
|
|
291
|
+
const parsed = JSON.parse(raw.trim());
|
|
292
|
+
if (!isControlCommand(parsed.command)) {
|
|
293
|
+
respond({ ok: false, error: 'invalid command' });
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
respond(await handler(parsed.command));
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
respond({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
300
|
+
}
|
|
301
|
+
})();
|
|
302
|
+
};
|
|
303
|
+
socket.on('data', (chunk) => {
|
|
304
|
+
raw += chunk;
|
|
305
|
+
if (raw.includes('\n'))
|
|
306
|
+
handleRequest();
|
|
307
|
+
});
|
|
308
|
+
socket.on('end', handleRequest);
|
|
309
|
+
}
|
|
310
|
+
function requestControl(socketPath, command, timeoutMs = 10_000) {
|
|
311
|
+
return new Promise((resolve, reject) => {
|
|
312
|
+
let raw = '';
|
|
313
|
+
let settled = false;
|
|
314
|
+
const socket = createConnection(socketPath);
|
|
315
|
+
const timeout = setTimeout(() => {
|
|
316
|
+
finish(new Error('Control channel response timed out'));
|
|
317
|
+
socket.destroy();
|
|
318
|
+
}, timeoutMs);
|
|
319
|
+
const finish = (result) => {
|
|
320
|
+
if (settled)
|
|
321
|
+
return;
|
|
322
|
+
settled = true;
|
|
323
|
+
clearTimeout(timeout);
|
|
324
|
+
if (result instanceof Error)
|
|
325
|
+
reject(result);
|
|
326
|
+
else
|
|
327
|
+
resolve(result);
|
|
328
|
+
};
|
|
329
|
+
socket.setEncoding('utf8');
|
|
330
|
+
socket.on('connect', () => {
|
|
331
|
+
socket.write(`${JSON.stringify({ command })}\n`);
|
|
332
|
+
});
|
|
333
|
+
socket.on('data', (chunk) => {
|
|
334
|
+
raw += chunk;
|
|
335
|
+
});
|
|
336
|
+
socket.on('error', (error) => finish(error));
|
|
337
|
+
socket.on('end', () => {
|
|
338
|
+
try {
|
|
339
|
+
finish(JSON.parse(raw.trim()));
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
finish(new Error(`Control channel response is not valid JSON${raw ? `: ${raw.slice(0, 200)}` : ''}`));
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
socket.on('close', () => {
|
|
346
|
+
if (settled)
|
|
347
|
+
return;
|
|
348
|
+
if (!raw.trim()) {
|
|
349
|
+
finish(new Error('Control channel did not respond'));
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
finish(JSON.parse(raw.trim()));
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
finish(new Error(`Control channel response is not valid JSON: ${raw.slice(0, 200)}`));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function isControlCommand(value) {
|
|
362
|
+
return value === 'status' || value === 'pause' || value === 'resume' || value === 'stop';
|
|
363
|
+
}
|