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