cdp-client-tool 1.1.0 → 2.0.0

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/dist/index.cjs CHANGED
@@ -1,12 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var chalk = require('chalk');
4
+ var path = require('node:path');
5
+ var promises = require('node:fs/promises');
4
6
  var axios = require('axios');
5
7
  var puppeteer = require('puppeteer-core');
6
- var promises = require('node:fs/promises');
8
+ var fs = require('node:fs');
9
+ var node_worker_threads = require('node:worker_threads');
7
10
  var socket_ioClient = require('socket.io-client');
8
- var path = require('node:path');
9
- var requireFromString = require('require-from-string');
10
11
 
11
12
  function _interopNamespaceDefault(e) {
12
13
  var n = Object.create(null);
@@ -26,7 +27,7 @@ function _interopNamespaceDefault(e) {
26
27
  }
27
28
 
28
29
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
29
- var requireFromString__namespace = /*#__PURE__*/_interopNamespaceDefault(requireFromString);
30
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
30
31
 
31
32
  const raw = chalk.default ?? chalk;
32
33
  const c = {
@@ -93,7 +94,13 @@ class Logger {
93
94
  this.logMessage(LogLevel.DEBUG, message, ...args);
94
95
  }
95
96
  }
97
+ const logger = new Logger();
96
98
 
99
+ function sleep(timeout) {
100
+ return new Promise((resolve) => {
101
+ setTimeout(resolve, timeout);
102
+ });
103
+ }
97
104
  async function launchBrowser() {
98
105
  const debugUrl = 'http://localhost:9222';
99
106
  const { data } = await axios.get(`${debugUrl}/json/version`);
@@ -104,6 +111,27 @@ async function launchBrowser() {
104
111
  });
105
112
  return browser;
106
113
  }
114
+ async function ensureDir(dirPath, create = true) {
115
+ try {
116
+ const stats = await promises.stat(dirPath);
117
+ if (!stats.isDirectory()) {
118
+ throw new Error(`${dirPath} 存在但不是目录`);
119
+ }
120
+ }
121
+ catch (err) {
122
+ if (err.code === 'ENOENT') {
123
+ if (create) {
124
+ await promises.mkdir(dirPath, { recursive: true });
125
+ }
126
+ else {
127
+ throw new Error(`目录 ${dirPath} 不存在`);
128
+ }
129
+ }
130
+ else {
131
+ throw err;
132
+ }
133
+ }
134
+ }
107
135
 
108
136
  exports.EVENTS = void 0;
109
137
  (function (EVENTS) {
@@ -115,7 +143,17 @@ exports.EVENTS = void 0;
115
143
  EVENTS["EXEC_LOCAL_SCRIPT"] = "exec_local_script";
116
144
  EVENTS["EXEC_REMOTE_SCRIPT"] = "exec_remote_script";
117
145
  EVENTS["SCRIPT_QUEUE"] = "script_queue";
146
+ EVENTS["INTERRUPT_SCRIPT"] = "interrupt_script";
147
+ EVENTS["UNDO_SCRIPT"] = "undo_script";
118
148
  })(exports.EVENTS || (exports.EVENTS = {}));
149
+ var PushJobResult;
150
+ (function (PushJobResult) {
151
+ PushJobResult["SUCCESS"] = "success";
152
+ PushJobResult["SUCCESS_IN_QUEUE"] = "success_in_queue";
153
+ PushJobResult["FAILED"] = "failed";
154
+ PushJobResult["QUEUE_FULL"] = "queue_full";
155
+ PushJobResult["FILE_SAVE_FAILED"] = "file_save_failed";
156
+ })(PushJobResult || (PushJobResult = {}));
119
157
  const ALLOWED_DIRS = ['local_scripts', 'screenshots'];
120
158
  function resolveAndValidate(basePath) {
121
159
  const cwd = process.cwd();
@@ -128,224 +166,480 @@ function resolveAndValidate(basePath) {
128
166
  }
129
167
  return resolved;
130
168
  }
169
+ async function saveScriptFile(filename, script) {
170
+ await ensureDir(path__namespace.resolve(process.cwd(), 'local_scripts'));
171
+ fs__namespace.writeFileSync(path__namespace.resolve(process.cwd(), 'local_scripts', filename), script);
172
+ }
131
173
 
132
- const handlers = {
133
- async [exports.EVENTS.EXEC_REMOTE_SCRIPT]({ data, callback }) {
134
- const { payload } = data;
135
- const res = this.enqueueRemoteScript(payload.raw);
136
- callback(res);
137
- },
138
- async [exports.EVENTS.EXEC_LOCAL_SCRIPT]({ data, callback }) {
139
- const { payload } = data;
140
- const res = this.enqueueLocalScript(payload.filename);
141
- callback(res);
142
- },
143
- async [exports.EVENTS.WRITE_FILE]({ data, callback }) {
144
- const { payload } = data;
145
- const { filename, content } = payload;
146
- resolveAndValidate(filename);
147
- callback({ ok: true });
148
- },
149
- async [exports.EVENTS.READ_DIR]({ data, callback }) {
150
- const { payload } = data;
151
- const dirPath = resolveAndValidate(payload.path);
152
- const run = this.runCatchFunction(async () => {
153
- const list = await promises.readdir(dirPath, { withFileTypes: true });
154
- return list.map(d => ({ name: d.name, type: d.isDirectory() ? 'dir' : 'file' }));
174
+ class ScriptWorker {
175
+ constructor(options) {
176
+ this.options = options;
177
+ }
178
+ terminate() {
179
+ if (this.timeoutTimer) {
180
+ clearTimeout(this.timeoutTimer);
181
+ this.timeoutTimer = undefined;
182
+ }
183
+ this.worker?.terminate();
184
+ }
185
+ run() {
186
+ if (this.options.job.type === 'local') {
187
+ const { filename, params } = this.options.job;
188
+ this.worker = new node_worker_threads.Worker(filename, {
189
+ workerData: {
190
+ params,
191
+ },
192
+ });
193
+ }
194
+ else {
195
+ const { script, params } = this.options.job;
196
+ this.worker = new node_worker_threads.Worker(script, {
197
+ eval: true,
198
+ workerData: {
199
+ params,
200
+ },
201
+ });
202
+ }
203
+ return new Promise((resolve, reject) => {
204
+ let settled = false;
205
+ const settle = (fn) => {
206
+ if (settled)
207
+ return;
208
+ settled = true;
209
+ fn();
210
+ };
211
+ this.timeoutTimer = setTimeout(() => {
212
+ this.timeoutTimer = undefined;
213
+ this.worker.terminate();
214
+ settle(() => reject(new Error('Worker timeout')));
215
+ }, this.options.timeout);
216
+ this.worker.on('error', (error) => {
217
+ if (this.timeoutTimer) {
218
+ clearTimeout(this.timeoutTimer);
219
+ this.timeoutTimer = undefined;
220
+ }
221
+ logger.error('Worker error', error);
222
+ settle(() => reject(error));
223
+ });
224
+ this.worker.on('exit', (code) => {
225
+ if (this.timeoutTimer) {
226
+ clearTimeout(this.timeoutTimer);
227
+ this.timeoutTimer = undefined;
228
+ }
229
+ if (code === 0) {
230
+ logger.success('Worker exit', code);
231
+ settle(() => resolve());
232
+ }
233
+ else {
234
+ logger.error('Worker exit', code);
235
+ settle(() => reject(new Error(`Worker exited with code ${code}`)));
236
+ }
237
+ });
155
238
  });
156
- const entries = await run();
157
- callback(entries ?? []);
158
- },
159
- async [exports.EVENTS.READ_FILE]({ data, callback }) {
160
- const { payload } = data;
161
- const filePath = resolveAndValidate(payload.path);
162
- const run = this.runCatchFunction(async () => await promises.readFile(filePath));
163
- const content = await run();
164
- callback(content ?? null);
165
- },
166
- async [exports.EVENTS.RM]({ data, callback }) {
167
- const { payload } = data;
168
- const filePath = resolveAndValidate(payload.path);
169
- const run = this.runCatchFunction(async () => await promises.rm(filePath, { force: true }));
170
- await run();
171
- callback({ ok: true });
172
- },
173
- async [exports.EVENTS.SCRIPT_QUEUE]({ callback }) {
174
- const snapshot = this.getScriptQueueSnapshot();
175
- callback(snapshot);
176
- },
177
- };
239
+ }
240
+ }
178
241
 
179
- const defaultOptions = {
180
- deviceName: 'default',
181
- gateways: []
182
- };
183
- class Client {
184
- constructor(options = defaultOptions) {
242
+ class Runner {
243
+ constructor(ctx, options) {
244
+ this.ctx = ctx;
185
245
  this.options = options;
186
- this.logger = new Logger();
187
- this.running = false;
188
- this.scriptQueue = [];
189
- this.runningJob = null;
190
- this.queueCapacity = 10;
246
+ this.queue = [];
191
247
  this.jobIdSeq = 0;
192
- this.init();
248
+ this.queue = [];
193
249
  }
194
250
  nextJobId() {
195
251
  return `job-${Date.now()}-${this.jobIdSeq++}`;
196
252
  }
197
- runCatchFunction(func) {
198
- const that = this;
199
- return async function (...args) {
253
+ getQueueLength() {
254
+ return this.queue.length;
255
+ }
256
+ interruptJob(jobId) {
257
+ const idx = this.queue.findIndex((j) => j.id === jobId);
258
+ if (idx >= 0) {
259
+ this.queue.splice(idx, 1);
260
+ return { ok: true };
261
+ }
262
+ if (this.worker) {
263
+ const job = this.worker.options?.job;
264
+ if (job?.id === jobId) {
265
+ this.worker.terminate();
266
+ return { ok: true };
267
+ }
268
+ }
269
+ return { ok: false, reason: `job not found: ${jobId}` };
270
+ }
271
+ getScriptQueueSnapshot() {
272
+ const running = this.worker ? this.worker.options?.job : null;
273
+ return {
274
+ running,
275
+ pending: [...this.queue],
276
+ capacity: this.options.capacity,
277
+ };
278
+ }
279
+ async execJob(job) {
280
+ if (this.queue.length >= this.options.capacity) {
281
+ return PushJobResult.QUEUE_FULL;
282
+ }
283
+ if (job.type === 'local' && !job.filename) {
284
+ job.filename = this.nextJobId();
200
285
  try {
201
- return await func(...args);
286
+ await saveScriptFile(job.filename, job.script);
202
287
  }
203
288
  catch (error) {
204
- that.logger.error('runCatchFunction error', error);
205
- that.options.onError && that.options.onError(error);
289
+ return PushJobResult.FILE_SAVE_FAILED;
206
290
  }
207
- };
291
+ }
292
+ this.queue.push(job);
293
+ if (!this.worker) {
294
+ const jobToRun = this.queue.shift();
295
+ if (this.last_finished_at && Date.now() - this.last_finished_at < this.options.minInterval) {
296
+ console.log('冷却时间');
297
+ await sleep(this.options.minInterval - (Date.now() - this.last_finished_at));
298
+ }
299
+ this.worker = new ScriptWorker({
300
+ job: jobToRun,
301
+ timeout: this.options.timeout,
302
+ });
303
+ try {
304
+ const res = await this.worker.run();
305
+ console.log('res 执行完了', res);
306
+ return PushJobResult.SUCCESS;
307
+ }
308
+ catch (e) {
309
+ console.log('res 执行失败', e);
310
+ return PushJobResult.FAILED;
311
+ }
312
+ finally {
313
+ this.worker = undefined;
314
+ this.last_finished_at = Date.now();
315
+ console.log('next', this.queue);
316
+ const next = this.queue.shift();
317
+ if (next) {
318
+ console.log('next!', next);
319
+ return this.execJob(next);
320
+ }
321
+ }
322
+ }
323
+ else {
324
+ return PushJobResult.SUCCESS_IN_QUEUE;
325
+ }
208
326
  }
209
- async init() {
210
- this.browser = await this.runCatchFunction(launchBrowser)();
211
- this.options.onInit && this.options.onInit(this.ctx);
327
+ }
328
+
329
+ /******************************************************************************
330
+ Copyright (c) Microsoft Corporation.
331
+
332
+ Permission to use, copy, modify, and/or distribute this software for any
333
+ purpose with or without fee is hereby granted.
334
+
335
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
336
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
337
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
338
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
339
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
340
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
341
+ PERFORMANCE OF THIS SOFTWARE.
342
+ ***************************************************************************** */
343
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
344
+
345
+
346
+ function __decorate(decorators, target, key, desc) {
347
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
348
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
349
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
350
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
351
+ }
352
+
353
+ function __metadata(metadataKey, metadataValue) {
354
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
355
+ }
356
+
357
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
358
+ var e = new Error(message);
359
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
360
+ };
361
+
362
+ const HANDLER_REGISTRY = Symbol("handler:registry");
363
+ function getHandlerRegistry(instance) {
364
+ const ctor = instance.constructor;
365
+ return ctor[HANDLER_REGISTRY] ?? [];
366
+ }
367
+ function Handler(eventName) {
368
+ return function (target, propertyKey, _descriptor) {
369
+ const ctor = typeof target === "function" ? target : target.constructor;
370
+ const registry = ctor[HANDLER_REGISTRY] ?? [];
371
+ registry.push({ event: eventName, key: propertyKey });
372
+ ctor[HANDLER_REGISTRY] = registry;
373
+ };
374
+ }
375
+
376
+ class WsHandler {
377
+ constructor(ctx, options) {
378
+ this.ctx = ctx;
379
+ this.options = options;
380
+ this.init();
381
+ }
382
+ init() {
383
+ this.options.onInit?.(this.ctx);
212
384
  for (const gateway of this.options.gateways) {
213
- const warpHandler = (fn) => {
214
- return (data, callback) => {
215
- return fn.call(this, {
216
- data,
217
- callback,
218
- gateway,
219
- ctx: this.ctx
220
- });
221
- };
222
- };
223
385
  const socket = socket_ioClient.io(gateway.uri, {
224
386
  ...gateway.opts,
225
- query: { ...gateway.opts?.query, deviceName: this.options.deviceName },
387
+ query: {
388
+ ...gateway.opts?.query,
389
+ deviceName: this.options.deviceName ?? "default",
390
+ },
226
391
  });
227
- socket.on('connect', () => {
228
- this.logger.success(`[${gateway.name}]: socketio 连接成功`);
392
+ socket.on("connect", () => {
393
+ logger.success(`[${gateway.name}]: socketio 连接成功`);
229
394
  });
230
- socket.on('disconnect', () => {
231
- this.logger.warn(`[${gateway.name}]: socketio 断开连接`);
395
+ socket.on("disconnect", () => {
396
+ logger.warn(`[${gateway.name}]: socketio 断开连接`);
232
397
  });
233
- socket.on('connect_error', (err) => {
234
- this.logger.error(`[${gateway.name}]: connect_error 错误`, err);
398
+ socket.on("connect_error", (err) => {
399
+ logger.error(`[${gateway.name}]: connect_error 错误`, err);
235
400
  });
236
- socket.on('error', (err) => {
237
- this.logger.error(`[[${gateway.name}]]: socketio 错误`, err);
401
+ socket.on("error", (err) => {
402
+ logger.error(`[${gateway.name}]: socketio 错误`, err);
238
403
  });
239
- for (const eventName in handlers) {
240
- socket.on(eventName, warpHandler(handlers[eventName]));
241
- }
242
- gateway.onSocketInit && gateway.onSocketInit(socket);
404
+ this.attachHandlers(socket, gateway);
405
+ gateway.onSocketInit?.(socket);
243
406
  }
244
407
  }
245
- getLocalModule(filename) {
246
- const req = require;
247
- return req(path__namespace.resolve(process.cwd(), 'local_scripts', filename));
248
- }
249
- getStringModule(moduleString) {
250
- const module = requireFromString__namespace(moduleString);
251
- return module;
408
+ attachHandlers(socket, gateway) {
409
+ const warpHandler = (fn) => (data, callback) => fn.call(this, { data, callback, gateway, ctx: this.ctx });
410
+ for (const { event, key } of getHandlerRegistry(this)) {
411
+ const method = this[key];
412
+ if (typeof method === "function") {
413
+ socket.on(event, warpHandler(method.bind(this)));
414
+ }
415
+ }
252
416
  }
253
- get ctx() {
254
- return {
255
- greeting: 'hello, remote script',
256
- browser: this.browser,
257
- logger: this.logger
258
- };
417
+ async readDir({ data, callback }) {
418
+ try {
419
+ const dirPath = resolveAndValidate(data.payload.path);
420
+ const list = await promises.readdir(dirPath, { withFileTypes: true });
421
+ callback(list.map((d) => ({
422
+ name: d.name,
423
+ type: d.isDirectory() ? "dir" : "file",
424
+ })));
425
+ }
426
+ catch (e) {
427
+ logger.error("read_dir 失败", e);
428
+ callback([]);
429
+ }
259
430
  }
260
- getScriptQueueSnapshot() {
261
- return {
262
- running: this.runningJob,
263
- pending: [...this.scriptQueue],
264
- capacity: this.queueCapacity,
265
- };
431
+ async readFile({ data, callback }) {
432
+ try {
433
+ const filePath = resolveAndValidate(data.payload.path);
434
+ const content = await promises.readFile(filePath);
435
+ callback(content);
436
+ }
437
+ catch (e) {
438
+ logger.error("read_file 失败", e);
439
+ callback(null);
440
+ }
266
441
  }
267
- enqueueRemoteScript(raw) {
268
- const job = {
269
- id: this.nextJobId(),
270
- type: 'remote',
271
- description: 'remote_script',
272
- createdAt: Date.now(),
273
- status: 'pending',
274
- };
275
- return this.enqueueJob(job, async () => {
276
- const script = this.getStringModule(raw.toString());
277
- const run = this.runCatchFunction(async () => await script(this.ctx));
278
- await run();
279
- });
442
+ async writeFile({ data, callback }) {
443
+ try {
444
+ const { filename, content, flags } = data.payload;
445
+ const filePath = resolveAndValidate(filename);
446
+ await ensureDir(path.dirname(filePath));
447
+ const buf = Buffer.isBuffer(content) ? content : typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
448
+ await promises.writeFile(filePath, buf, { flag: flags ?? "w" });
449
+ callback({ ok: true });
450
+ }
451
+ catch (e) {
452
+ logger.error("write_file 失败", e);
453
+ callback({ ok: false });
454
+ }
280
455
  }
281
- enqueueLocalScript(filename) {
282
- const job = {
283
- id: this.nextJobId(),
284
- type: 'local',
285
- filename,
286
- description: filename,
287
- createdAt: Date.now(),
288
- status: 'pending',
289
- };
290
- return this.enqueueJob(job, async () => {
291
- const script = this.getLocalModule(filename);
292
- const run = this.runCatchFunction(() => script(this.ctx));
293
- await run();
294
- });
456
+ async rm({ data, callback }) {
457
+ try {
458
+ const filePath = resolveAndValidate(data.payload.path);
459
+ await promises.rm(filePath, { force: true });
460
+ callback({ ok: true });
461
+ }
462
+ catch (e) {
463
+ logger.error("rm 失败", e);
464
+ callback({ ok: false });
465
+ }
295
466
  }
296
- enqueueJob(job, runner) {
297
- const total = this.scriptQueue.length + (this.runningJob ? 1 : 0);
298
- if (total >= this.queueCapacity) {
299
- return {
300
- status: 'overflow',
301
- reason: `queue is full (${this.queueCapacity})`,
467
+ async execLocalScript({ data, callback }) {
468
+ try {
469
+ const { filename, params } = data.payload;
470
+ const base = filename.includes("/") ? filename : path.join("local_scripts", filename);
471
+ const filePath = resolveAndValidate(base);
472
+ const job = {
473
+ id: `job-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
474
+ type: "local",
475
+ filename: filePath,
476
+ params,
302
477
  };
478
+ const result = await this.ctx.runner.execJob(job);
479
+ console.log('handler:', result);
480
+ callback(this.mapExecResult(result, job.id));
303
481
  }
304
- job._runner = runner;
305
- if (!this.runningJob) {
306
- job.status = 'running';
307
- job.startedAt = Date.now();
308
- this.runningJob = job;
309
- this.runJob(job);
310
- return { status: 'executing', jobId: job.id };
482
+ catch (e) {
483
+ logger.error("exec_local_script 失败", e);
484
+ callback({ status: "overflow", reason: e?.message ?? "执行失败" });
311
485
  }
312
- else {
313
- job.status = 'pending';
314
- this.scriptQueue.push(job);
315
- return {
316
- status: 'queued',
317
- jobId: job.id,
318
- position: this.scriptQueue.length,
486
+ }
487
+ async execRemoteScript({ data, callback }) {
488
+ try {
489
+ const { raw, params } = data.payload;
490
+ const job = {
491
+ id: `job-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
492
+ type: "remote",
493
+ script: raw.toString("utf8"),
494
+ params,
319
495
  };
496
+ const result = await this.ctx.runner.execJob(job);
497
+ callback(this.mapExecResult(result, job.id));
498
+ }
499
+ catch (e) {
500
+ logger.error("exec_remote_script 失败", e);
501
+ callback({ status: "overflow", reason: e?.message ?? "执行失败" });
502
+ }
503
+ }
504
+ mapExecResult(result, jobId) {
505
+ switch (result) {
506
+ case PushJobResult.SUCCESS:
507
+ return { status: "executing", jobId };
508
+ case PushJobResult.SUCCESS_IN_QUEUE:
509
+ return {
510
+ status: "queued",
511
+ jobId,
512
+ position: this.ctx.runner.getQueueLength(),
513
+ };
514
+ case PushJobResult.QUEUE_FULL:
515
+ return { status: "overflow", reason: "queue is full" };
516
+ case PushJobResult.FAILED:
517
+ return { status: "overflow", reason: "execution failed" };
518
+ case PushJobResult.FILE_SAVE_FAILED:
519
+ return { status: "overflow", reason: "file save failed" };
520
+ default:
521
+ return { status: "overflow", reason: "unknown" };
320
522
  }
321
523
  }
322
- async runJob(job) {
323
- const runner = job._runner;
324
- if (!runner)
325
- return;
524
+ async interruptScript({ data, callback }) {
326
525
  try {
327
- await runner();
328
- job.status = 'success';
526
+ const { jobId } = data.payload;
527
+ const result = this.ctx.runner.interruptJob(jobId);
528
+ callback(result);
329
529
  }
330
530
  catch (e) {
331
- job.status = 'failed';
332
- job.errorMessage = e?.message || String(e);
333
- this.logger.error('脚本执行失败', e);
334
- }
335
- finally {
336
- job.finishedAt = Date.now();
337
- this.runningJob = null;
338
- const next = this.scriptQueue.shift();
339
- if (next) {
340
- next.status = 'running';
341
- next.startedAt = Date.now();
342
- this.runningJob = next;
343
- this.runJob(next);
344
- }
531
+ logger.error("interrupt_script 失败", e);
532
+ callback({ ok: false, reason: e?.message ?? "取消失败" });
533
+ }
534
+ }
535
+ async undoScript({ data, callback }) {
536
+ try {
537
+ const { jobId } = data.payload;
538
+ const result = this.ctx.runner.interruptJob(jobId);
539
+ callback(result);
540
+ }
541
+ catch (e) {
542
+ logger.error("undo_script 失败", e);
543
+ callback({ ok: false, reason: e?.message ?? "撤销失败" });
544
+ }
545
+ }
546
+ async scriptQueue({ callback }) {
547
+ try {
548
+ const snapshot = this.ctx.runner.getScriptQueueSnapshot();
549
+ callback(snapshot);
345
550
  }
551
+ catch (e) {
552
+ logger.error("script_queue 失败", e);
553
+ callback({ running: null, pending: [], capacity: 10 });
554
+ }
555
+ }
556
+ }
557
+ __decorate([
558
+ Handler(exports.EVENTS.READ_DIR),
559
+ __metadata("design:type", Function),
560
+ __metadata("design:paramtypes", [Object]),
561
+ __metadata("design:returntype", Promise)
562
+ ], WsHandler.prototype, "readDir", null);
563
+ __decorate([
564
+ Handler(exports.EVENTS.READ_FILE),
565
+ __metadata("design:type", Function),
566
+ __metadata("design:paramtypes", [Object]),
567
+ __metadata("design:returntype", Promise)
568
+ ], WsHandler.prototype, "readFile", null);
569
+ __decorate([
570
+ Handler(exports.EVENTS.WRITE_FILE),
571
+ __metadata("design:type", Function),
572
+ __metadata("design:paramtypes", [Object]),
573
+ __metadata("design:returntype", Promise)
574
+ ], WsHandler.prototype, "writeFile", null);
575
+ __decorate([
576
+ Handler(exports.EVENTS.RM),
577
+ __metadata("design:type", Function),
578
+ __metadata("design:paramtypes", [Object]),
579
+ __metadata("design:returntype", Promise)
580
+ ], WsHandler.prototype, "rm", null);
581
+ __decorate([
582
+ Handler(exports.EVENTS.EXEC_LOCAL_SCRIPT),
583
+ __metadata("design:type", Function),
584
+ __metadata("design:paramtypes", [Object]),
585
+ __metadata("design:returntype", Promise)
586
+ ], WsHandler.prototype, "execLocalScript", null);
587
+ __decorate([
588
+ Handler(exports.EVENTS.EXEC_REMOTE_SCRIPT),
589
+ __metadata("design:type", Function),
590
+ __metadata("design:paramtypes", [Object]),
591
+ __metadata("design:returntype", Promise)
592
+ ], WsHandler.prototype, "execRemoteScript", null);
593
+ __decorate([
594
+ Handler(exports.EVENTS.INTERRUPT_SCRIPT),
595
+ __metadata("design:type", Function),
596
+ __metadata("design:paramtypes", [Object]),
597
+ __metadata("design:returntype", Promise)
598
+ ], WsHandler.prototype, "interruptScript", null);
599
+ __decorate([
600
+ Handler(exports.EVENTS.UNDO_SCRIPT),
601
+ __metadata("design:type", Function),
602
+ __metadata("design:paramtypes", [Object]),
603
+ __metadata("design:returntype", Promise)
604
+ ], WsHandler.prototype, "undoScript", null);
605
+ __decorate([
606
+ Handler(exports.EVENTS.SCRIPT_QUEUE),
607
+ __metadata("design:type", Function),
608
+ __metadata("design:paramtypes", [Object]),
609
+ __metadata("design:returntype", Promise)
610
+ ], WsHandler.prototype, "scriptQueue", null);
611
+
612
+ const defaultOptions = {
613
+ capacity: 10,
614
+ timeout: 1000 * 60 * 5,
615
+ minInterval: 1000 * 5};
616
+ class Client {
617
+ get deps() {
618
+ return {
619
+ runner: this.runner,
620
+ ws: this.ws,
621
+ };
622
+ }
623
+ constructor(options) {
624
+ const runner = new Runner(this.deps, {
625
+ capacity: options.capacity ?? defaultOptions.capacity,
626
+ minInterval: options.minInterval ?? defaultOptions.minInterval,
627
+ timeout: options.timeout ?? defaultOptions.timeout,
628
+ });
629
+ this.runner = runner;
630
+ const ws = new WsHandler(this.deps, {
631
+ gateways: options.gateways,
632
+ deviceName: options.deviceName,
633
+ });
634
+ this.ws = ws;
346
635
  }
347
636
  }
348
637
 
349
638
  exports.Client = Client;
350
- exports.Logger = Logger;
639
+ exports.Handler = Handler;
640
+ exports.Runner = Runner;
641
+ exports.WsHandler = WsHandler;
642
+ exports.launchBrowser = launchBrowser;
643
+ exports.logger = logger;
644
+ exports.sleep = sleep;
351
645
  //# sourceMappingURL=index.cjs.map