taro-bluetooth-print 2.3.1 → 2.4.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/CHANGELOG.md +24 -0
- package/README.md +6 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/types/config/PrinterConfigManager.d.ts +206 -0
- package/dist/types/config/index.d.ts +8 -0
- package/dist/types/device/MultiPrinterManager.d.ts +164 -0
- package/dist/types/device/index.d.ts +2 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/services/BatchPrintManager.d.ts +205 -0
- package/dist/types/services/PrintHistory.d.ts +142 -0
- package/dist/types/services/PrintJobManager.d.ts +28 -4
- package/dist/types/services/PrinterStatus.d.ts +97 -0
- package/dist/types/services/index.d.ts +3 -0
- package/package.json +2 -2
- package/src/adapters/AlipayAdapter.ts +1 -0
- package/src/adapters/BaiduAdapter.ts +1 -0
- package/src/adapters/ByteDanceAdapter.ts +1 -0
- package/src/adapters/TaroAdapter.ts +1 -0
- package/src/adapters/WebBluetoothAdapter.ts +1 -1
- package/src/config/PrinterConfigManager.ts +519 -0
- package/src/config/index.ts +15 -0
- package/src/device/MultiPrinterManager.ts +470 -0
- package/src/device/index.ts +8 -0
- package/src/encoding/gbk-lite.ts +81 -76
- package/src/encoding/gbk-table.ts +14 -14
- package/src/index.ts +16 -1
- package/src/services/BatchPrintManager.ts +500 -0
- package/src/services/ConnectionManager.ts +4 -1
- package/src/services/PrintHistory.ts +336 -0
- package/src/services/PrintJobManager.ts +69 -9
- package/src/services/PrinterStatus.ts +267 -0
- package/src/services/index.ts +6 -0
- package/src/template/TemplateEngine.ts +4 -1
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch Print Manager
|
|
3
|
+
*
|
|
4
|
+
* Optimizes printing multiple jobs by:
|
|
5
|
+
* - Merging small jobs into larger chunks
|
|
6
|
+
* - Reducing Bluetooth communication overhead
|
|
7
|
+
* - Prioritizing urgent jobs
|
|
8
|
+
* - Batching similar content for efficiency
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const batchManager = new BatchPrintManager();
|
|
13
|
+
*
|
|
14
|
+
* // Add print jobs
|
|
15
|
+
* batchManager.addJob({ data: buffer1, priority: 1 });
|
|
16
|
+
* batchManager.addJob({ data: buffer2, priority: 2 });
|
|
17
|
+
*
|
|
18
|
+
* // Process batch when ready
|
|
19
|
+
* await batchManager.processBatch();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { Logger } from '@/utils/logger';
|
|
24
|
+
import { BluetoothPrintError, ErrorCode } from '@/errors/BluetoothError';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Batch job entry
|
|
28
|
+
*/
|
|
29
|
+
export interface BatchJob {
|
|
30
|
+
/** Unique job ID */
|
|
31
|
+
id: string;
|
|
32
|
+
/** Print data */
|
|
33
|
+
data: Uint8Array;
|
|
34
|
+
/** Priority (higher = more urgent) */
|
|
35
|
+
priority: number;
|
|
36
|
+
/** Timestamp when added */
|
|
37
|
+
addedAt: number;
|
|
38
|
+
/** Metadata */
|
|
39
|
+
metadata?: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Batch configuration
|
|
44
|
+
*/
|
|
45
|
+
export interface BatchConfig {
|
|
46
|
+
/** Maximum batch size in bytes */
|
|
47
|
+
maxBatchSize: number;
|
|
48
|
+
/** Maximum wait time before processing in ms */
|
|
49
|
+
maxWaitTime: number;
|
|
50
|
+
/** Minimum jobs before batching */
|
|
51
|
+
minBatchSize: number;
|
|
52
|
+
/** Merge similar content */
|
|
53
|
+
enableMerging: boolean;
|
|
54
|
+
/** Auto-process interval in ms (0 = disabled) */
|
|
55
|
+
autoProcessInterval: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Batch statistics
|
|
60
|
+
*/
|
|
61
|
+
export interface BatchStats {
|
|
62
|
+
/** Total jobs added */
|
|
63
|
+
totalJobs: number;
|
|
64
|
+
/** Total bytes processed */
|
|
65
|
+
totalBytes: number;
|
|
66
|
+
/** Batches processed */
|
|
67
|
+
batchesProcessed: number;
|
|
68
|
+
/** Average batch size */
|
|
69
|
+
avgBatchSize: number;
|
|
70
|
+
/** Merged jobs count */
|
|
71
|
+
mergedJobs: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Batch events
|
|
76
|
+
*/
|
|
77
|
+
export interface BatchEvents {
|
|
78
|
+
'batch-ready': (data: BatchJob[]) => void;
|
|
79
|
+
'batch-processed': (data: { jobCount: number; bytes: number }) => void;
|
|
80
|
+
'job-added': (data: BatchJob) => void;
|
|
81
|
+
'job-rejected': (data: { reason: string }) => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Event handler map type
|
|
86
|
+
*/
|
|
87
|
+
type BatchEventHandlerMap = {
|
|
88
|
+
[K in keyof BatchEvents]: Set<BatchEvents[K]>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Default batch configuration
|
|
93
|
+
*/
|
|
94
|
+
const DEFAULT_CONFIG: BatchConfig = {
|
|
95
|
+
maxBatchSize: 1024 * 50, // 50KB max per batch
|
|
96
|
+
maxWaitTime: 1000, // 1 second max wait
|
|
97
|
+
minBatchSize: 1, // Process even single jobs
|
|
98
|
+
enableMerging: true, // Enable content merging
|
|
99
|
+
autoProcessInterval: 500, // Check every 500ms
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Batch Print Manager
|
|
104
|
+
*
|
|
105
|
+
* Collects print jobs and processes them in optimized batches.
|
|
106
|
+
* Reduces Bluetooth communication overhead by combining small jobs.
|
|
107
|
+
*/
|
|
108
|
+
export class BatchPrintManager {
|
|
109
|
+
private readonly logger = Logger.scope('BatchPrintManager');
|
|
110
|
+
private readonly jobs: BatchJob[] = [];
|
|
111
|
+
private readonly listeners: BatchEventHandlerMap = {
|
|
112
|
+
'batch-ready': new Set(),
|
|
113
|
+
'batch-processed': new Set(),
|
|
114
|
+
'job-added': new Set(),
|
|
115
|
+
'job-rejected': new Set(),
|
|
116
|
+
};
|
|
117
|
+
private config: BatchConfig;
|
|
118
|
+
private isProcessing = false;
|
|
119
|
+
private waitTimer: ReturnType<typeof setTimeout> | null = null;
|
|
120
|
+
private autoProcessTimer: ReturnType<typeof setInterval> | null = null;
|
|
121
|
+
private stats: BatchStats = {
|
|
122
|
+
totalJobs: 0,
|
|
123
|
+
totalBytes: 0,
|
|
124
|
+
batchesProcessed: 0,
|
|
125
|
+
avgBatchSize: 0,
|
|
126
|
+
mergedJobs: 0,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a new BatchPrintManager instance
|
|
131
|
+
*/
|
|
132
|
+
constructor(config: Partial<BatchConfig> = {}) {
|
|
133
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Register event listener
|
|
138
|
+
*/
|
|
139
|
+
on<K extends keyof BatchEvents>(
|
|
140
|
+
event: K,
|
|
141
|
+
callback: BatchEvents[K]
|
|
142
|
+
): void {
|
|
143
|
+
this.listeners[event].add(callback);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Remove event listener
|
|
148
|
+
*/
|
|
149
|
+
off<K extends keyof BatchEvents>(
|
|
150
|
+
event: K,
|
|
151
|
+
callback: BatchEvents[K]
|
|
152
|
+
): void {
|
|
153
|
+
this.listeners[event].delete(callback);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Emit an event
|
|
158
|
+
*/
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
private emit<K extends keyof BatchEvents>(event: K, data: any): void {
|
|
161
|
+
this.listeners[event].forEach(handler => {
|
|
162
|
+
try {
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
164
|
+
(handler as any)(data);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
this.logger.error(`Error in event handler for "${event}":`, error);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Add a job to the batch queue
|
|
173
|
+
*
|
|
174
|
+
* @param data - Print data
|
|
175
|
+
* @param priority - Job priority (higher = more urgent)
|
|
176
|
+
* @param metadata - Optional metadata
|
|
177
|
+
* @returns Job ID
|
|
178
|
+
*/
|
|
179
|
+
addJob(
|
|
180
|
+
data: Uint8Array,
|
|
181
|
+
priority = 1,
|
|
182
|
+
metadata?: Record<string, unknown>
|
|
183
|
+
): string {
|
|
184
|
+
const id = this.generateId();
|
|
185
|
+
const job: BatchJob = {
|
|
186
|
+
id,
|
|
187
|
+
data,
|
|
188
|
+
priority,
|
|
189
|
+
addedAt: Date.now(),
|
|
190
|
+
metadata,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
this.jobs.push(job);
|
|
194
|
+
this.stats.totalJobs++;
|
|
195
|
+
|
|
196
|
+
// Sort by priority (descending)
|
|
197
|
+
this.jobs.sort((a, b) => b.priority - a.priority);
|
|
198
|
+
|
|
199
|
+
this.emit('job-added', job);
|
|
200
|
+
this.logger.debug(`Job added: ${id} (priority: ${priority}, queue size: ${this.jobs.length})`);
|
|
201
|
+
|
|
202
|
+
// Start/restart wait timer
|
|
203
|
+
this.startWaitTimer();
|
|
204
|
+
|
|
205
|
+
// Check if we should process immediately
|
|
206
|
+
if (this.shouldProcessImmediately()) {
|
|
207
|
+
this.emit('batch-ready', [...this.jobs]);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Start auto-process if enabled
|
|
211
|
+
this.startAutoProcess();
|
|
212
|
+
|
|
213
|
+
return id;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Add multiple jobs at once
|
|
218
|
+
*/
|
|
219
|
+
addJobs(jobs: Array<{ data: Uint8Array; priority?: number; metadata?: Record<string, unknown> }>): string[] {
|
|
220
|
+
return jobs.map(job => this.addJob(job.data, job.priority, job.metadata));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Cancel a job by ID
|
|
225
|
+
*/
|
|
226
|
+
cancelJob(id: string): boolean {
|
|
227
|
+
const index = this.jobs.findIndex(j => j.id === id);
|
|
228
|
+
if (index === -1) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.jobs.splice(index, 1);
|
|
233
|
+
this.logger.debug(`Job cancelled: ${id}`);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Cancel all jobs
|
|
239
|
+
*/
|
|
240
|
+
cancelAll(): void {
|
|
241
|
+
const count = this.jobs.length;
|
|
242
|
+
this.jobs.length = 0;
|
|
243
|
+
this.clearTimers();
|
|
244
|
+
this.logger.info(`Cancelled ${count} jobs`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get pending job count
|
|
249
|
+
*/
|
|
250
|
+
get pendingCount(): number {
|
|
251
|
+
return this.jobs.length;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get pending jobs
|
|
256
|
+
*/
|
|
257
|
+
getPendingJobs(): BatchJob[] {
|
|
258
|
+
return [...this.jobs];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get current statistics
|
|
263
|
+
*/
|
|
264
|
+
getStats(): BatchStats {
|
|
265
|
+
return { ...this.stats };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Update configuration
|
|
270
|
+
*/
|
|
271
|
+
updateConfig(updates: Partial<BatchConfig>): void {
|
|
272
|
+
this.config = { ...this.config, ...updates };
|
|
273
|
+
this.logger.debug('Configuration updated');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Process the current batch
|
|
278
|
+
*
|
|
279
|
+
* @param processor - Function to send batch data to printer
|
|
280
|
+
* @returns Number of jobs processed
|
|
281
|
+
*/
|
|
282
|
+
async processBatch(
|
|
283
|
+
processor: (data: Uint8Array) => Promise<void>
|
|
284
|
+
): Promise<number> {
|
|
285
|
+
if (this.isProcessing) {
|
|
286
|
+
throw new BluetoothPrintError(
|
|
287
|
+
ErrorCode.PRINT_JOB_IN_PROGRESS,
|
|
288
|
+
'Batch processing already in progress'
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (this.jobs.length === 0) {
|
|
293
|
+
this.logger.debug('No jobs to process');
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.isProcessing = true;
|
|
298
|
+
this.clearTimers();
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
// Get jobs for this batch
|
|
302
|
+
const batchJobs = this.prepareBatch();
|
|
303
|
+
const mergedData = this.mergeJobs(batchJobs);
|
|
304
|
+
|
|
305
|
+
this.logger.info(`Processing batch: ${batchJobs.length} jobs, ${mergedData.length} bytes`);
|
|
306
|
+
|
|
307
|
+
// Emit batch ready event
|
|
308
|
+
this.emit('batch-ready', batchJobs);
|
|
309
|
+
|
|
310
|
+
// Process the merged data
|
|
311
|
+
await processor(mergedData);
|
|
312
|
+
|
|
313
|
+
// Update stats
|
|
314
|
+
this.stats.totalBytes += mergedData.length;
|
|
315
|
+
this.stats.batchesProcessed++;
|
|
316
|
+
this.stats.avgBatchSize =
|
|
317
|
+
(this.stats.avgBatchSize * (this.stats.batchesProcessed - 1) + mergedData.length) /
|
|
318
|
+
this.stats.batchesProcessed;
|
|
319
|
+
|
|
320
|
+
// Remove processed jobs
|
|
321
|
+
this.jobs.splice(0, batchJobs.length);
|
|
322
|
+
|
|
323
|
+
this.emit('batch-processed', { jobCount: batchJobs.length, bytes: mergedData.length });
|
|
324
|
+
this.logger.info(`Batch processed: ${batchJobs.length} jobs`);
|
|
325
|
+
|
|
326
|
+
return batchJobs.length;
|
|
327
|
+
} finally {
|
|
328
|
+
this.isProcessing = false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Prepare batch from pending jobs
|
|
334
|
+
*/
|
|
335
|
+
private prepareBatch(): BatchJob[] {
|
|
336
|
+
const batch: BatchJob[] = [];
|
|
337
|
+
let totalSize = 0;
|
|
338
|
+
|
|
339
|
+
for (const job of this.jobs) {
|
|
340
|
+
// Check if adding this job would exceed max batch size
|
|
341
|
+
if (batch.length > 0 && totalSize + job.data.length > this.config.maxBatchSize) {
|
|
342
|
+
// Don't add if it would exceed, and we already have some jobs
|
|
343
|
+
if (batch.length >= this.config.minBatchSize) {
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
batch.push(job);
|
|
349
|
+
totalSize += job.data.length;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return batch;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Merge multiple jobs into a single buffer
|
|
357
|
+
*/
|
|
358
|
+
private mergeJobs(jobs: BatchJob[]): Uint8Array {
|
|
359
|
+
if (!this.config.enableMerging || jobs.length === 1) {
|
|
360
|
+
return jobs[0]?.data ?? new Uint8Array(0);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Calculate total size
|
|
364
|
+
let totalSize = 0;
|
|
365
|
+
for (const job of jobs) {
|
|
366
|
+
totalSize += job.data.length;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Merge into single buffer
|
|
370
|
+
const result = new Uint8Array(totalSize);
|
|
371
|
+
let offset = 0;
|
|
372
|
+
|
|
373
|
+
for (const job of jobs) {
|
|
374
|
+
result.set(job.data, offset);
|
|
375
|
+
offset += job.data.length;
|
|
376
|
+
this.stats.mergedJobs++;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
this.logger.debug(`Merged ${jobs.length} jobs into ${totalSize} bytes`);
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Check if we should process immediately
|
|
385
|
+
*/
|
|
386
|
+
private shouldProcessImmediately(): boolean {
|
|
387
|
+
if (this.jobs.length === 0) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Large single job
|
|
392
|
+
const firstJob = this.jobs[0];
|
|
393
|
+
if (this.jobs.length === 1 && firstJob && firstJob.data.length >= this.config.maxBatchSize * 0.8) {
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Queue is full
|
|
398
|
+
const totalSize = this.jobs.reduce((sum, j) => sum + j.data.length, 0);
|
|
399
|
+
if (totalSize >= this.config.maxBatchSize) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Start the wait timer
|
|
408
|
+
*/
|
|
409
|
+
private startWaitTimer(): void {
|
|
410
|
+
this.clearWaitTimer();
|
|
411
|
+
|
|
412
|
+
if (this.config.maxWaitTime <= 0) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
this.waitTimer = setTimeout(() => {
|
|
417
|
+
this.logger.debug('Wait timer expired, batch ready');
|
|
418
|
+
this.emit('batch-ready', [...this.jobs]);
|
|
419
|
+
}, this.config.maxWaitTime);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Clear wait timer
|
|
424
|
+
*/
|
|
425
|
+
private clearWaitTimer(): void {
|
|
426
|
+
if (this.waitTimer) {
|
|
427
|
+
clearTimeout(this.waitTimer);
|
|
428
|
+
this.waitTimer = null;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Start auto-process timer
|
|
434
|
+
*/
|
|
435
|
+
private startAutoProcess(): void {
|
|
436
|
+
if (this.autoProcessTimer || this.config.autoProcessInterval <= 0) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
this.autoProcessTimer = setInterval(() => {
|
|
441
|
+
// Check if batch is ready
|
|
442
|
+
if (this.shouldProcessImmediately()) {
|
|
443
|
+
this.emit('batch-ready', [...this.jobs]);
|
|
444
|
+
}
|
|
445
|
+
}, this.config.autoProcessInterval);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Stop auto-process timer
|
|
450
|
+
*/
|
|
451
|
+
private stopAutoProcess(): void {
|
|
452
|
+
if (this.autoProcessTimer) {
|
|
453
|
+
clearInterval(this.autoProcessTimer);
|
|
454
|
+
this.autoProcessTimer = null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Clear all timers
|
|
460
|
+
*/
|
|
461
|
+
private clearTimers(): void {
|
|
462
|
+
this.clearWaitTimer();
|
|
463
|
+
this.stopAutoProcess();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Generate unique job ID
|
|
468
|
+
*/
|
|
469
|
+
private generateId(): string {
|
|
470
|
+
return `batch_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Reset statistics
|
|
475
|
+
*/
|
|
476
|
+
resetStats(): void {
|
|
477
|
+
this.stats = {
|
|
478
|
+
totalJobs: 0,
|
|
479
|
+
totalBytes: 0,
|
|
480
|
+
batchesProcessed: 0,
|
|
481
|
+
avgBatchSize: 0,
|
|
482
|
+
mergedJobs: 0,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Destroy the manager
|
|
488
|
+
*/
|
|
489
|
+
destroy(): void {
|
|
490
|
+
this.cancelAll();
|
|
491
|
+
// Clear all listeners
|
|
492
|
+
for (const key of Object.keys(this.listeners) as (keyof BatchEventHandlerMap)[]) {
|
|
493
|
+
this.listeners[key].clear();
|
|
494
|
+
}
|
|
495
|
+
this.logger.info('BatchPrintManager destroyed');
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Export singleton for convenience
|
|
500
|
+
export const batchPrintManager = new BatchPrintManager();
|
|
@@ -185,7 +185,10 @@ export class ConnectionManager
|
|
|
185
185
|
this.emit('error', printError);
|
|
186
186
|
throw printError;
|
|
187
187
|
}
|
|
188
|
-
this.connLogger.warn(
|
|
188
|
+
this.connLogger.warn(
|
|
189
|
+
`Connection attempt ${attempts}/${retries} failed, retrying...`,
|
|
190
|
+
error
|
|
191
|
+
);
|
|
189
192
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
190
193
|
}
|
|
191
194
|
}
|