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,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print History Service
|
|
3
|
+
*
|
|
4
|
+
* Tracks all print jobs with timestamps, status, and metadata.
|
|
5
|
+
* Provides querying and analytics capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const history = new PrintHistory();
|
|
10
|
+
* history.addJob({ data, status: 'completed' });
|
|
11
|
+
* const recentJobs = history.getRecent(10);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { Logger } from '@/utils/logger';
|
|
16
|
+
import { PrintJobStatus, PrintJobPriority } from '@/queue/PrintQueue';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Print history entry
|
|
20
|
+
*/
|
|
21
|
+
export interface PrintHistoryEntry {
|
|
22
|
+
/** Unique entry ID */
|
|
23
|
+
id: string;
|
|
24
|
+
/** Job ID from PrintJobManager */
|
|
25
|
+
jobId?: string;
|
|
26
|
+
/** Print data size in bytes */
|
|
27
|
+
dataSize: number;
|
|
28
|
+
/** Job status */
|
|
29
|
+
status: PrintJobStatus | 'unknown';
|
|
30
|
+
/** Priority */
|
|
31
|
+
priority: PrintJobPriority;
|
|
32
|
+
/** Creation timestamp */
|
|
33
|
+
createdAt: number;
|
|
34
|
+
/** Start timestamp */
|
|
35
|
+
startedAt?: number;
|
|
36
|
+
/** Completion timestamp */
|
|
37
|
+
completedAt?: number;
|
|
38
|
+
/** Duration in milliseconds */
|
|
39
|
+
duration?: number;
|
|
40
|
+
/** Error message if failed */
|
|
41
|
+
error?: string;
|
|
42
|
+
/** Device ID */
|
|
43
|
+
deviceId?: string;
|
|
44
|
+
/** Device name */
|
|
45
|
+
deviceName?: string;
|
|
46
|
+
/** Metadata */
|
|
47
|
+
metadata?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* History statistics
|
|
52
|
+
*/
|
|
53
|
+
export interface PrintHistoryStats {
|
|
54
|
+
/** Total jobs */
|
|
55
|
+
total: number;
|
|
56
|
+
/** Completed jobs */
|
|
57
|
+
completed: number;
|
|
58
|
+
/** Failed jobs */
|
|
59
|
+
failed: number;
|
|
60
|
+
/** Cancelled jobs */
|
|
61
|
+
cancelled: number;
|
|
62
|
+
/** Average duration in ms */
|
|
63
|
+
avgDuration: number;
|
|
64
|
+
/** Total bytes printed */
|
|
65
|
+
totalBytes: number;
|
|
66
|
+
/** Success rate */
|
|
67
|
+
successRate: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Query options for history
|
|
72
|
+
*/
|
|
73
|
+
export interface HistoryQueryOptions {
|
|
74
|
+
/** Start date filter */
|
|
75
|
+
startDate?: number;
|
|
76
|
+
/** End date filter */
|
|
77
|
+
endDate?: number;
|
|
78
|
+
/** Status filter */
|
|
79
|
+
status?: PrintJobStatus | PrintJobStatus[];
|
|
80
|
+
/** Device ID filter */
|
|
81
|
+
deviceId?: string;
|
|
82
|
+
/** Limit results */
|
|
83
|
+
limit?: number;
|
|
84
|
+
/** Offset for pagination */
|
|
85
|
+
offset?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Print History Service
|
|
90
|
+
*/
|
|
91
|
+
export class PrintHistory {
|
|
92
|
+
private readonly logger = Logger.scope('PrintHistory');
|
|
93
|
+
private readonly entries: Map<string, PrintHistoryEntry> = new Map();
|
|
94
|
+
private counter = 0;
|
|
95
|
+
private readonly maxEntries: number;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Creates a new PrintHistory instance
|
|
99
|
+
* @param maxEntries - Maximum number of entries to keep (default: 1000)
|
|
100
|
+
*/
|
|
101
|
+
constructor(maxEntries = 1000) {
|
|
102
|
+
this.maxEntries = maxEntries;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Add a new print job to history
|
|
107
|
+
*/
|
|
108
|
+
addJob(params: {
|
|
109
|
+
jobId?: string;
|
|
110
|
+
data: Uint8Array;
|
|
111
|
+
status: PrintJobStatus | 'unknown';
|
|
112
|
+
priority?: PrintJobPriority;
|
|
113
|
+
deviceId?: string;
|
|
114
|
+
deviceName?: string;
|
|
115
|
+
metadata?: Record<string, unknown>;
|
|
116
|
+
}): string {
|
|
117
|
+
const id = this.generateId();
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
|
|
120
|
+
const entry: PrintHistoryEntry = {
|
|
121
|
+
id,
|
|
122
|
+
jobId: params.jobId,
|
|
123
|
+
dataSize: params.data.length,
|
|
124
|
+
status: params.status,
|
|
125
|
+
priority: params.priority ?? PrintJobPriority.NORMAL,
|
|
126
|
+
createdAt: now,
|
|
127
|
+
deviceId: params.deviceId,
|
|
128
|
+
deviceName: params.deviceName,
|
|
129
|
+
metadata: params.metadata,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.entries.set(id, entry);
|
|
133
|
+
this.enforceMaxEntries();
|
|
134
|
+
|
|
135
|
+
this.logger.debug(`History entry added: ${id}`);
|
|
136
|
+
return id;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Update job status
|
|
141
|
+
*/
|
|
142
|
+
updateJob(id: string, updates: Partial<{
|
|
143
|
+
status: PrintJobStatus | 'unknown';
|
|
144
|
+
startedAt: number;
|
|
145
|
+
completedAt: number;
|
|
146
|
+
error: string;
|
|
147
|
+
}>): void {
|
|
148
|
+
const entry = this.entries.get(id);
|
|
149
|
+
if (!entry) {
|
|
150
|
+
this.logger.warn(`History entry not found: ${id}`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Object.assign(entry, updates);
|
|
155
|
+
|
|
156
|
+
if (updates.startedAt) {
|
|
157
|
+
entry.startedAt = updates.startedAt;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (updates.completedAt) {
|
|
161
|
+
entry.completedAt = updates.completedAt;
|
|
162
|
+
if (entry.startedAt) {
|
|
163
|
+
entry.duration = updates.completedAt - entry.startedAt;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (updates.error) {
|
|
168
|
+
entry.error = updates.error;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (updates.status) {
|
|
172
|
+
entry.status = updates.status;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.logger.debug(`History entry updated: ${id}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get entry by ID
|
|
180
|
+
*/
|
|
181
|
+
getEntry(id: string): PrintHistoryEntry | undefined {
|
|
182
|
+
return this.entries.get(id);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get recent jobs
|
|
187
|
+
*/
|
|
188
|
+
getRecent(count = 10): PrintHistoryEntry[] {
|
|
189
|
+
return Array.from(this.entries.values())
|
|
190
|
+
.sort((a, b) => b.createdAt - a.createdAt)
|
|
191
|
+
.slice(0, count);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Query history with filters
|
|
196
|
+
*/
|
|
197
|
+
query(options: HistoryQueryOptions = {}): PrintHistoryEntry[] {
|
|
198
|
+
let results = Array.from(this.entries.values());
|
|
199
|
+
|
|
200
|
+
if (options.startDate) {
|
|
201
|
+
results = results.filter(e => e.createdAt >= options.startDate!);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (options.endDate) {
|
|
205
|
+
results = results.filter(e => e.createdAt <= options.endDate!);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (options.status) {
|
|
209
|
+
const statuses = Array.isArray(options.status) ? options.status : [options.status];
|
|
210
|
+
results = results.filter(e => statuses.includes(e.status as PrintJobStatus));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (options.deviceId) {
|
|
214
|
+
results = results.filter(e => e.deviceId === options.deviceId);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Sort by creation date descending
|
|
218
|
+
results.sort((a, b) => b.createdAt - a.createdAt);
|
|
219
|
+
|
|
220
|
+
// Pagination
|
|
221
|
+
if (options.offset) {
|
|
222
|
+
results = results.slice(options.offset);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (options.limit) {
|
|
226
|
+
results = results.slice(0, options.limit);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return results;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get statistics
|
|
234
|
+
*/
|
|
235
|
+
getStats(options?: { days?: number }): PrintHistoryStats {
|
|
236
|
+
let entries = Array.from(this.entries.values());
|
|
237
|
+
|
|
238
|
+
// Filter by days if specified
|
|
239
|
+
if (options?.days) {
|
|
240
|
+
const cutoff = Date.now() - options.days * 24 * 60 * 60 * 1000;
|
|
241
|
+
entries = entries.filter(e => e.createdAt >= cutoff);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const completed = entries.filter(e => e.status === PrintJobStatus.COMPLETED);
|
|
245
|
+
const failed = entries.filter(e =>
|
|
246
|
+
e.status === PrintJobStatus.FAILED || e.error
|
|
247
|
+
);
|
|
248
|
+
const cancelled = entries.filter(e => e.status === PrintJobStatus.CANCELLED);
|
|
249
|
+
|
|
250
|
+
const totalDuration = completed
|
|
251
|
+
.filter(e => e.duration !== undefined)
|
|
252
|
+
.reduce((sum, e) => sum + (e.duration || 0), 0);
|
|
253
|
+
|
|
254
|
+
const totalBytes = entries.reduce((sum, e) => sum + e.dataSize, 0);
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
total: entries.length,
|
|
258
|
+
completed: completed.length,
|
|
259
|
+
failed: failed.length,
|
|
260
|
+
cancelled: cancelled.length,
|
|
261
|
+
avgDuration: completed.length > 0 ? totalDuration / completed.length : 0,
|
|
262
|
+
totalBytes,
|
|
263
|
+
successRate: entries.length > 0 ? (completed.length / entries.length) * 100 : 0,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Clear all history
|
|
269
|
+
*/
|
|
270
|
+
clear(): void {
|
|
271
|
+
this.entries.clear();
|
|
272
|
+
this.logger.info('Print history cleared');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Export history as JSON
|
|
277
|
+
*/
|
|
278
|
+
export(): string {
|
|
279
|
+
return JSON.stringify(Array.from(this.entries.values()), null, 2);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Import history from JSON
|
|
284
|
+
*/
|
|
285
|
+
import(json: string): number {
|
|
286
|
+
try {
|
|
287
|
+
const data = JSON.parse(json) as PrintHistoryEntry[];
|
|
288
|
+
let imported = 0;
|
|
289
|
+
|
|
290
|
+
for (const entry of data) {
|
|
291
|
+
if (entry.id && entry.dataSize) {
|
|
292
|
+
this.entries.set(entry.id, entry);
|
|
293
|
+
imported++;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.enforceMaxEntries();
|
|
298
|
+
this.logger.info(`Imported ${imported} history entries`);
|
|
299
|
+
return imported;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
this.logger.error('Failed to import history:', error);
|
|
302
|
+
return 0;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Generate unique ID
|
|
308
|
+
*/
|
|
309
|
+
private generateId(): string {
|
|
310
|
+
this.counter++;
|
|
311
|
+
return `history_${Date.now()}_${this.counter}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Enforce maximum entries limit
|
|
316
|
+
*/
|
|
317
|
+
private enforceMaxEntries(): void {
|
|
318
|
+
if (this.entries.size <= this.maxEntries) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Remove oldest entries
|
|
323
|
+
const sorted = Array.from(this.entries.entries())
|
|
324
|
+
.sort((a, b) => a[1].createdAt - b[1].createdAt);
|
|
325
|
+
|
|
326
|
+
const toRemove = sorted.slice(0, this.entries.size - this.maxEntries);
|
|
327
|
+
for (const [id] of toRemove) {
|
|
328
|
+
this.entries.delete(id);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.logger.debug(`Pruned ${toRemove.length} old history entries`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Export singleton instance
|
|
336
|
+
export const printHistory = new PrintHistory();
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Print Job Manager Service
|
|
3
3
|
*
|
|
4
|
-
* Manages print jobs, including pause/resume/cancel functionality
|
|
4
|
+
* Manages print jobs, including pause/resume/cancel functionality.
|
|
5
|
+
* Supports job state persistence for resume capability.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import type { IPrinterAdapter } from '@/types';
|
|
@@ -37,8 +38,19 @@ interface SavedJobState {
|
|
|
37
38
|
* Print Job Manager implementation
|
|
38
39
|
*/
|
|
39
40
|
export class PrintJobManager implements IPrintJobManager {
|
|
40
|
-
/**
|
|
41
|
-
private
|
|
41
|
+
/** Instance-level job state storage (per-printer support) */
|
|
42
|
+
private instanceJobStateStore: Map<string, SavedJobState> = new Map();
|
|
43
|
+
|
|
44
|
+
/** Static job state store for backward compatibility */
|
|
45
|
+
private static _jobStateStore: Map<string, SavedJobState> = new Map();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the static job state store (for backward compatibility)
|
|
49
|
+
* @deprecated Use instance-level store instead for multi-printer support
|
|
50
|
+
*/
|
|
51
|
+
private static get jobStateStore(): Map<string, SavedJobState> {
|
|
52
|
+
return PrintJobManager._jobStateStore;
|
|
53
|
+
}
|
|
42
54
|
private adapter: IPrinterAdapter;
|
|
43
55
|
private connectionManager: IConnectionManager;
|
|
44
56
|
private jobBuffer: Uint8Array | null = null;
|
|
@@ -221,8 +233,8 @@ export class PrintJobManager implements IPrintJobManager {
|
|
|
221
233
|
/**
|
|
222
234
|
* Saves the current job state for resume later.
|
|
223
235
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
236
|
+
* Uses instance-level storage by default. Falls back to static store
|
|
237
|
+
* for backward compatibility.
|
|
226
238
|
*/
|
|
227
239
|
private saveJobState(): void {
|
|
228
240
|
if (!this.jobBuffer || !this.jobId) {
|
|
@@ -230,14 +242,16 @@ export class PrintJobManager implements IPrintJobManager {
|
|
|
230
242
|
}
|
|
231
243
|
|
|
232
244
|
try {
|
|
233
|
-
const state = {
|
|
245
|
+
const state: SavedJobState = {
|
|
234
246
|
jobId: this.jobId,
|
|
235
247
|
jobBuffer: Array.from(this.jobBuffer),
|
|
236
248
|
jobOffset: this.jobOffset,
|
|
237
|
-
adapterOptions: this.adapterOptions,
|
|
249
|
+
adapterOptions: { ...this.adapterOptions },
|
|
238
250
|
timestamp: Date.now(),
|
|
239
251
|
};
|
|
240
252
|
|
|
253
|
+
// Save to both instance and static store for backward compatibility
|
|
254
|
+
this.instanceJobStateStore.set(this.jobId, state);
|
|
241
255
|
PrintJobManager.jobStateStore.set(this.jobId, state);
|
|
242
256
|
|
|
243
257
|
this.logger.debug(
|
|
@@ -257,13 +271,17 @@ export class PrintJobManager implements IPrintJobManager {
|
|
|
257
271
|
try {
|
|
258
272
|
this.logger.debug(`Loading job state for ${jobId}`);
|
|
259
273
|
|
|
260
|
-
|
|
274
|
+
// Try instance store first, then fall back to static store
|
|
275
|
+
let savedState = this.instanceJobStateStore.get(jobId);
|
|
276
|
+
if (!savedState) {
|
|
277
|
+
savedState = PrintJobManager.jobStateStore.get(jobId);
|
|
278
|
+
}
|
|
261
279
|
|
|
262
280
|
if (savedState) {
|
|
263
281
|
this.jobId = savedState.jobId;
|
|
264
282
|
this.jobBuffer = new Uint8Array(savedState.jobBuffer);
|
|
265
283
|
this.jobOffset = savedState.jobOffset;
|
|
266
|
-
this.adapterOptions = savedState.adapterOptions;
|
|
284
|
+
this.adapterOptions = { ...savedState.adapterOptions };
|
|
267
285
|
this._isPaused = true;
|
|
268
286
|
this._isInProgress = true;
|
|
269
287
|
this.logger.info(
|
|
@@ -288,6 +306,8 @@ export class PrintJobManager implements IPrintJobManager {
|
|
|
288
306
|
private clearJobState(): void {
|
|
289
307
|
if (this.jobId) {
|
|
290
308
|
this.logger.debug(`Clearing job state for ${this.jobId}`);
|
|
309
|
+
// Clear from both stores
|
|
310
|
+
this.instanceJobStateStore.delete(this.jobId);
|
|
291
311
|
PrintJobManager.jobStateStore.delete(this.jobId);
|
|
292
312
|
}
|
|
293
313
|
|
|
@@ -297,6 +317,46 @@ export class PrintJobManager implements IPrintJobManager {
|
|
|
297
317
|
this.adapterOptions = {};
|
|
298
318
|
}
|
|
299
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Cleanup resources and clear all job state.
|
|
322
|
+
* Call this when the printer is no longer needed.
|
|
323
|
+
*/
|
|
324
|
+
destroy(): void {
|
|
325
|
+
this.cancel();
|
|
326
|
+
this.instanceJobStateStore.clear();
|
|
327
|
+
this.onProgress = undefined;
|
|
328
|
+
this.onJobStateChange = undefined;
|
|
329
|
+
this.logger.info('PrintJobManager destroyed');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Clean up expired job states from static store.
|
|
334
|
+
* Call this periodically to prevent memory leaks.
|
|
335
|
+
*
|
|
336
|
+
* @param maxAge - Maximum age in ms (default: 1 hour)
|
|
337
|
+
*/
|
|
338
|
+
static cleanupExpiredJobs(maxAge = 3600000): number {
|
|
339
|
+
const now = Date.now();
|
|
340
|
+
let cleaned = 0;
|
|
341
|
+
|
|
342
|
+
for (const [jobId, state] of PrintJobManager.jobStateStore.entries()) {
|
|
343
|
+
if (now - state.timestamp > maxAge) {
|
|
344
|
+
PrintJobManager.jobStateStore.delete(jobId);
|
|
345
|
+
cleaned++;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return cleaned;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Get count of pending job states in static store.
|
|
354
|
+
* Useful for debugging memory usage.
|
|
355
|
+
*/
|
|
356
|
+
static getStaticStoreSize(): number {
|
|
357
|
+
return PrintJobManager.jobStateStore.size;
|
|
358
|
+
}
|
|
359
|
+
|
|
300
360
|
/**
|
|
301
361
|
* Emits job state change event
|
|
302
362
|
*
|