taro-bluetooth-print 2.3.0 → 2.3.1
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 +57 -203
- package/README.md +129 -386
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/types/core/BluetoothPrinter.d.ts +1 -1
- package/dist/types/core/EventEmitter.d.ts +6 -26
- package/dist/types/core/index.d.ts +6 -0
- package/dist/types/drivers/CpclDriver.d.ts +304 -0
- package/dist/types/drivers/GPrinterDriver.d.ts +63 -0
- package/dist/types/drivers/ZplDriver.d.ts +325 -0
- package/dist/types/drivers/index.d.ts +9 -0
- package/dist/types/encoding/gbk-lite.d.ts +8 -0
- package/dist/types/encoding/gbk-table.d.ts +8 -30
- package/dist/types/index.d.ts +7 -7
- package/dist/types/services/ConnectionManager.d.ts +1 -1
- package/dist/types/services/index.d.ts +8 -0
- package/package.json +24 -6
- package/src/adapters/BaseAdapter.ts +6 -8
- package/src/core/BluetoothPrinter.ts +15 -15
- package/src/core/EventEmitter.ts +15 -15
- package/src/core/index.ts +7 -0
- package/src/drivers/CpclDriver.ts +549 -0
- package/src/drivers/GPrinterDriver.ts +115 -0
- package/src/drivers/TsplDriver.ts +9 -21
- package/src/drivers/ZplDriver.ts +543 -0
- package/src/drivers/index.ts +37 -0
- package/src/encoding/gbk-lite.ts +108 -0
- package/src/encoding/gbk-table.ts +80 -58
- package/src/index.ts +24 -34
- package/src/plugins/PluginManager.ts +3 -1
- package/src/plugins/builtin/LoggingPlugin.ts +4 -2
- package/src/plugins/builtin/RetryPlugin.ts +8 -14
- package/src/services/ConnectionManager.ts +22 -22
- package/src/services/index.ts +16 -0
|
@@ -1,98 +1,120 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GBK Encoding Table
|
|
2
|
+
* GBK Encoding Table - 懒加载版本
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 优化策略:
|
|
5
|
+
* 1. 默认使用精简版编码表 (gbk-lite.ts,约 3500 常用字)
|
|
6
|
+
* 2. 遇到非常用字时动态加载完整编码表
|
|
7
|
+
* 3. 二分查找代替 Map,大幅减少内存占用
|
|
7
8
|
*
|
|
8
|
-
* GBK encoding uses double-byte encoding for Chinese characters:
|
|
9
|
-
* - First byte: 0x81-0xFE
|
|
10
|
-
* - Second byte: 0x40-0xFE (excluding 0x7F)
|
|
11
|
-
*
|
|
12
|
-
* 映射数据存储在 gbk-data.ts 中,运行时解码为 Map。
|
|
13
9
|
* GBK: 23940 个字符映射
|
|
14
10
|
* Big5: 13911 个字符映射
|
|
15
11
|
*/
|
|
16
12
|
|
|
17
|
-
import {
|
|
13
|
+
import { binarySearchGbk, isInCommonRange } from './gbk-lite';
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
// 懒加载完整编码数据
|
|
16
|
+
let GBK_DATA: number[] | null = null;
|
|
17
|
+
let BIG5_DATA: number[] | null = null;
|
|
18
|
+
|
|
19
|
+
function loadFullData() {
|
|
20
|
+
if (!GBK_DATA) {
|
|
21
|
+
const data = require('./gbk-data');
|
|
22
|
+
GBK_DATA = data.GBK_DATA;
|
|
23
|
+
BIG5_DATA = data.BIG5_DATA;
|
|
24
|
+
}
|
|
25
|
+
return { GBK_DATA: GBK_DATA!, BIG5_DATA: BIG5_DATA! };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Unicode to GBK mapping table
|
|
23
29
|
export const unicodeToGbk: Map<number, number> = new Map();
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
* GBK to Unicode mapping table
|
|
27
|
-
* Maps GBK byte pairs to Unicode code points
|
|
28
|
-
*/
|
|
31
|
+
// GBK to Unicode mapping table
|
|
29
32
|
export const gbkToUnicode: Map<number, number> = new Map();
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
* Unicode to Big5 mapping table
|
|
33
|
-
*/
|
|
34
|
+
// Unicode to Big5 mapping table
|
|
34
35
|
export const unicodeToBig5: Map<number, number> = new Map();
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
* Big5 to Unicode mapping table
|
|
38
|
-
*/
|
|
37
|
+
// Big5 to Unicode mapping table
|
|
39
38
|
export const big5ToUnicode: Map<number, number> = new Map();
|
|
40
39
|
|
|
41
|
-
/**
|
|
42
|
-
* Decode flat array mapping data into forward and reverse maps.
|
|
43
|
-
* Array format: [unicode1, encoded1, unicode2, encoded2, ...]
|
|
44
|
-
*/
|
|
45
|
-
function decodeMappings(
|
|
46
|
-
data: number[],
|
|
47
|
-
forwardMap: Map<number, number>,
|
|
48
|
-
reverseMap: Map<number, number>
|
|
49
|
-
): void {
|
|
50
|
-
for (let i = 0; i < data.length; i += 2) {
|
|
51
|
-
const unicode = data[i]!;
|
|
52
|
-
const encoded = data[i + 1]!;
|
|
53
|
-
forwardMap.set(unicode, encoded);
|
|
54
|
-
reverseMap.set(encoded, unicode);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Initialize mappings at module load time
|
|
59
|
-
decodeMappings(GBK_DATA, unicodeToGbk, gbkToUnicode);
|
|
60
|
-
decodeMappings(BIG5_DATA, unicodeToBig5, big5ToUnicode);
|
|
61
|
-
|
|
62
40
|
/**
|
|
63
41
|
* Get GBK bytes for a Unicode character
|
|
64
|
-
*
|
|
65
|
-
* @returns GBK byte pair [high, low] or null if not found
|
|
42
|
+
* 先查精简表,查不到再懒加载完整表
|
|
66
43
|
*/
|
|
67
44
|
export function getGbkBytes(unicode: number): [number, number] | null {
|
|
68
|
-
|
|
69
|
-
if (
|
|
45
|
+
// ASCII 直接返回
|
|
46
|
+
if (unicode >= 0x20 && unicode <= 0x7E) {
|
|
47
|
+
return [0, unicode];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 先查精简表
|
|
51
|
+
const gbk = binarySearchGbk(unicode);
|
|
52
|
+
if (gbk !== null) {
|
|
70
53
|
return [(gbk >> 8) & 0xff, gbk & 0xff];
|
|
71
54
|
}
|
|
55
|
+
|
|
56
|
+
// 非常用字,懒加载完整表
|
|
57
|
+
if (isInCommonRange(unicode)) {
|
|
58
|
+
const { GBK_DATA } = loadFullData();
|
|
59
|
+
for (let i = 0; i < GBK_DATA.length; i += 2) {
|
|
60
|
+
if (GBK_DATA[i] === unicode) {
|
|
61
|
+
const gbkValue = GBK_DATA[i + 1];
|
|
62
|
+
if (gbkValue !== undefined) {
|
|
63
|
+
return [(gbkValue >> 8) & 0xff, gbkValue & 0xff];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
72
69
|
return null;
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
/**
|
|
76
73
|
* Get Unicode character from GBK bytes
|
|
77
|
-
*
|
|
78
|
-
* @param low - Low byte
|
|
79
|
-
* @returns Unicode code point or null if not found
|
|
74
|
+
* 懒加载完整表
|
|
80
75
|
*/
|
|
81
76
|
export function getUnicodeFromGbk(high: number, low: number): number | null {
|
|
82
77
|
const gbk = (high << 8) | low;
|
|
83
|
-
|
|
78
|
+
|
|
79
|
+
// 先查缓存
|
|
80
|
+
const cached = gbkToUnicode.get(gbk);
|
|
81
|
+
if (cached !== undefined) return cached;
|
|
82
|
+
|
|
83
|
+
// 懒加载完整表
|
|
84
|
+
const { GBK_DATA } = loadFullData();
|
|
85
|
+
for (let i = 0; i < GBK_DATA.length; i += 2) {
|
|
86
|
+
if (GBK_DATA[i + 1] === gbk) {
|
|
87
|
+
const result = GBK_DATA[i];
|
|
88
|
+
return result ?? null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null;
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
/**
|
|
87
96
|
* Get Big5 bytes for a Unicode character
|
|
88
|
-
*
|
|
89
|
-
* @returns Big5 byte pair or null if not found
|
|
97
|
+
* 懒加载完整表
|
|
90
98
|
*/
|
|
91
99
|
export function getBig5Bytes(unicode: number): [number, number] | null {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
// 先查缓存
|
|
101
|
+
const cached = unicodeToBig5.get(unicode);
|
|
102
|
+
if (cached !== undefined) {
|
|
103
|
+
const cachedValue = cached;
|
|
104
|
+
return [(cachedValue >> 8) & 0xff, cachedValue & 0xff];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 懒加载完整表
|
|
108
|
+
const { BIG5_DATA } = loadFullData();
|
|
109
|
+
for (let i = 0; i < BIG5_DATA.length; i += 2) {
|
|
110
|
+
if (BIG5_DATA[i] === unicode) {
|
|
111
|
+
const big5 = BIG5_DATA[i + 1];
|
|
112
|
+
if (big5 !== undefined) {
|
|
113
|
+
return [(big5 >> 8) & 0xff, big5 & 0xff];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
95
116
|
}
|
|
117
|
+
|
|
96
118
|
return null;
|
|
97
119
|
}
|
|
98
120
|
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Taro Bluetooth Print Library
|
|
3
|
-
*
|
|
3
|
+
* 轻量级、高性能的蓝牙打印库
|
|
4
4
|
*
|
|
5
5
|
* @packageDocumentation
|
|
6
6
|
*/
|
|
@@ -10,37 +10,27 @@ export { BluetoothPrinter } from './core/BluetoothPrinter';
|
|
|
10
10
|
export type { PrinterEvents } from './core/BluetoothPrinter';
|
|
11
11
|
export { EventEmitter } from './core/EventEmitter';
|
|
12
12
|
|
|
13
|
-
// Drivers
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
LabelSize,
|
|
18
|
-
TextOptions as TsplTextOptions,
|
|
19
|
-
BarcodeOptions as TsplBarcodeOptions,
|
|
20
|
-
QRCodeOptions as TsplQRCodeOptions,
|
|
21
|
-
BoxOptions,
|
|
22
|
-
LineOptions,
|
|
23
|
-
} from './drivers/TsplDriver';
|
|
24
|
-
|
|
25
|
-
// Adapters
|
|
13
|
+
// Drivers - 打印机驱动
|
|
14
|
+
export * from './drivers';
|
|
15
|
+
|
|
16
|
+
// Adapters - 平台适配器
|
|
26
17
|
export { TaroAdapter } from './adapters/TaroAdapter';
|
|
18
|
+
export { AlipayAdapter } from './adapters/AlipayAdapter';
|
|
19
|
+
export { BaiduAdapter } from './adapters/BaiduAdapter';
|
|
20
|
+
export { ByteDanceAdapter } from './adapters/ByteDanceAdapter';
|
|
21
|
+
export { WebBluetoothAdapter } from './adapters/WebBluetoothAdapter';
|
|
27
22
|
export { AdapterFactory } from './adapters/AdapterFactory';
|
|
28
23
|
export { BaseAdapter } from './adapters/BaseAdapter';
|
|
29
|
-
export { WebBluetoothAdapter } from './adapters/WebBluetoothAdapter';
|
|
30
24
|
export type { WebBluetoothRequestOptions } from './adapters/WebBluetoothAdapter';
|
|
31
25
|
|
|
32
|
-
// Services
|
|
33
|
-
export
|
|
34
|
-
export type {
|
|
35
|
-
ConnectionManagerConfig,
|
|
36
|
-
ConnectionManagerEvents,
|
|
37
|
-
} from './services/ConnectionManager';
|
|
26
|
+
// Services - 服务层
|
|
27
|
+
export * from './services';
|
|
38
28
|
|
|
39
|
-
// Device Management
|
|
29
|
+
// Device Management - 设备管理
|
|
40
30
|
export { DeviceManager } from './device/DeviceManager';
|
|
41
31
|
export type { BluetoothDevice, ScanOptions, DeviceManagerEvents } from './device/DeviceManager';
|
|
42
32
|
|
|
43
|
-
// Print Queue
|
|
33
|
+
// Print Queue - 打印队列
|
|
44
34
|
export { PrintQueue } from './queue/PrintQueue';
|
|
45
35
|
export type {
|
|
46
36
|
PrintJob,
|
|
@@ -50,11 +40,11 @@ export type {
|
|
|
50
40
|
PrintQueueEvents,
|
|
51
41
|
} from './queue/PrintQueue';
|
|
52
42
|
|
|
53
|
-
// Offline Cache
|
|
43
|
+
// Offline Cache - 离线缓存
|
|
54
44
|
export { OfflineCache } from './cache/OfflineCache';
|
|
55
45
|
export type { CachedJob, CacheConfig, CacheStats } from './cache/OfflineCache';
|
|
56
46
|
|
|
57
|
-
// Template Engine
|
|
47
|
+
// Template Engine - 模板引擎
|
|
58
48
|
export { TemplateEngine } from './template/TemplateEngine';
|
|
59
49
|
export type {
|
|
60
50
|
TemplateType,
|
|
@@ -65,32 +55,32 @@ export type {
|
|
|
65
55
|
ValidationResult,
|
|
66
56
|
} from './template/TemplateEngine';
|
|
67
57
|
|
|
68
|
-
// Barcode Generator
|
|
58
|
+
// Barcode Generator - 条码生成
|
|
69
59
|
export { BarcodeGenerator, BarcodeFormat } from './barcode/BarcodeGenerator';
|
|
70
60
|
export type { BarcodeOptions } from './barcode/BarcodeGenerator';
|
|
71
61
|
|
|
72
|
-
// Text Formatter
|
|
62
|
+
// Text Formatter - 文本格式化
|
|
73
63
|
export { TextFormatter, TextAlign } from './formatter/TextFormatter';
|
|
74
64
|
export type { TextStyle } from './formatter/TextFormatter';
|
|
75
65
|
|
|
76
|
-
// Preview Renderer
|
|
66
|
+
// Preview Renderer - 打印预览
|
|
77
67
|
export { PreviewRenderer } from './preview/PreviewRenderer';
|
|
78
68
|
export type { PreviewOptions, PreviewResult } from './preview/PreviewRenderer';
|
|
79
69
|
|
|
80
|
-
// Encoding
|
|
70
|
+
// Encoding - 编码服务
|
|
81
71
|
export { EncodingService } from './encoding/EncodingService';
|
|
82
72
|
export type { EncodingConfig } from './encoding/EncodingService';
|
|
83
73
|
|
|
84
|
-
// Utilities
|
|
74
|
+
// Utilities - 工具函数
|
|
85
75
|
export { Logger, LogLevel } from './utils/logger';
|
|
86
76
|
export { Encoding } from './utils/encoding';
|
|
87
77
|
export { ImageProcessing } from './utils/image';
|
|
88
78
|
export { PlatformType, detectPlatform, isPlatformSupported } from './utils/platform';
|
|
89
79
|
|
|
90
|
-
// Error handling
|
|
80
|
+
// Error handling - 错误处理
|
|
91
81
|
export { BluetoothPrintError, ErrorCode } from './errors/BluetoothError';
|
|
92
82
|
|
|
93
|
-
// Configuration
|
|
83
|
+
// Configuration - 配置
|
|
94
84
|
export { DEFAULT_CONFIG, mergeConfig } from './config/PrinterConfig';
|
|
95
85
|
export type {
|
|
96
86
|
PrinterConfig,
|
|
@@ -99,10 +89,10 @@ export type {
|
|
|
99
89
|
LoggingConfig,
|
|
100
90
|
} from './config/PrinterConfig';
|
|
101
91
|
|
|
102
|
-
// Plugin System
|
|
92
|
+
// Plugin System - 插件系统
|
|
103
93
|
export { PluginManager } from './plugins/PluginManager';
|
|
104
94
|
export { createLoggingPlugin, createRetryPlugin } from './plugins';
|
|
105
95
|
export type { Plugin, PluginHooks, PluginOptions, PluginFactory } from './plugins/types';
|
|
106
96
|
|
|
107
|
-
// Types
|
|
97
|
+
// Types - 类型定义
|
|
108
98
|
export * from './types';
|
|
@@ -29,7 +29,9 @@ export class PluginManager {
|
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
this.logger.info(
|
|
32
|
+
this.logger.info(
|
|
33
|
+
`Registering plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ''}`
|
|
34
|
+
);
|
|
33
35
|
|
|
34
36
|
if (plugin.init) {
|
|
35
37
|
await plugin.init(options);
|
|
@@ -65,10 +65,12 @@ export const createLoggingPlugin: PluginFactory = (options?: LoggingPluginOption
|
|
|
65
65
|
afterPrint: (bytesSent: number) => {
|
|
66
66
|
const elapsed = Date.now() - startTime;
|
|
67
67
|
const speed = ((bytesSent / elapsed) * 1000).toFixed(2);
|
|
68
|
-
logger.info(
|
|
68
|
+
logger.info(
|
|
69
|
+
`${formatTime()}Print complete: ${bytesSent} bytes in ${elapsed}ms (${speed} B/s)`
|
|
70
|
+
);
|
|
69
71
|
},
|
|
70
72
|
|
|
71
|
-
onError:
|
|
73
|
+
onError: error => {
|
|
72
74
|
logger.error(`${formatTime()}Error [${error.code}]: ${error.message}`);
|
|
73
75
|
return false; // Don't suppress the error
|
|
74
76
|
},
|
|
@@ -42,10 +42,7 @@ export const createRetryPlugin: PluginFactory = (options?: RetryPluginOptions):
|
|
|
42
42
|
let currentDelay = opts.initialDelay;
|
|
43
43
|
|
|
44
44
|
const shouldRetry = (error: BluetoothPrintError): boolean => {
|
|
45
|
-
return (
|
|
46
|
-
retryCount < opts.maxRetries &&
|
|
47
|
-
opts.retryableErrors.includes(error.code)
|
|
48
|
-
);
|
|
45
|
+
return retryCount < opts.maxRetries && opts.retryableErrors.includes(error.code);
|
|
49
46
|
};
|
|
50
47
|
|
|
51
48
|
const sleep = (ms: number): Promise<void> => {
|
|
@@ -77,14 +74,11 @@ export const createRetryPlugin: PluginFactory = (options?: RetryPluginOptions):
|
|
|
77
74
|
`Retryable error occurred (attempt ${retryCount}/${opts.maxRetries}): ${error.code}`
|
|
78
75
|
);
|
|
79
76
|
logger.info(`Waiting ${currentDelay}ms before retry...`);
|
|
80
|
-
|
|
77
|
+
|
|
81
78
|
await sleep(currentDelay);
|
|
82
|
-
|
|
79
|
+
|
|
83
80
|
// Exponential backoff
|
|
84
|
-
currentDelay = Math.min(
|
|
85
|
-
currentDelay * opts.backoffMultiplier,
|
|
86
|
-
opts.maxDelay
|
|
87
|
-
);
|
|
81
|
+
currentDelay = Math.min(currentDelay * opts.backoffMultiplier, opts.maxDelay);
|
|
88
82
|
|
|
89
83
|
// Note: Returning false means error is not suppressed
|
|
90
84
|
// The actual retry logic would need to be implemented in the printer
|
|
@@ -93,9 +87,7 @@ export const createRetryPlugin: PluginFactory = (options?: RetryPluginOptions):
|
|
|
93
87
|
}
|
|
94
88
|
|
|
95
89
|
if (retryCount > 0) {
|
|
96
|
-
logger.error(
|
|
97
|
-
`Failed after ${retryCount} retries: ${error.code} - ${error.message}`
|
|
98
|
-
);
|
|
90
|
+
logger.error(`Failed after ${retryCount} retries: ${error.code} - ${error.message}`);
|
|
99
91
|
}
|
|
100
92
|
|
|
101
93
|
return false;
|
|
@@ -103,7 +95,9 @@ export const createRetryPlugin: PluginFactory = (options?: RetryPluginOptions):
|
|
|
103
95
|
},
|
|
104
96
|
|
|
105
97
|
init: () => {
|
|
106
|
-
logger.info(
|
|
98
|
+
logger.info(
|
|
99
|
+
`Retry plugin initialized (max: ${opts.maxRetries}, delay: ${opts.initialDelay}ms)`
|
|
100
|
+
);
|
|
107
101
|
},
|
|
108
102
|
};
|
|
109
103
|
};
|
|
@@ -71,7 +71,7 @@ export class ConnectionManager
|
|
|
71
71
|
private adapter: IPrinterAdapter;
|
|
72
72
|
private deviceId: string | null = null;
|
|
73
73
|
private state: PrinterState = PrinterState.DISCONNECTED;
|
|
74
|
-
private readonly
|
|
74
|
+
private readonly connLogger = Logger.scope('ConnectionManager');
|
|
75
75
|
private readonly config: Required<ConnectionManagerConfig>;
|
|
76
76
|
|
|
77
77
|
// Heartbeat state
|
|
@@ -102,7 +102,7 @@ export class ConnectionManager
|
|
|
102
102
|
private handleStateChange(newState: PrinterState): void {
|
|
103
103
|
const previousState = this.state;
|
|
104
104
|
this.state = newState;
|
|
105
|
-
this.
|
|
105
|
+
this.connLogger.debug('State changed:', { from: previousState, to: newState });
|
|
106
106
|
this.emit('state-change', newState);
|
|
107
107
|
|
|
108
108
|
// Handle unexpected disconnection
|
|
@@ -112,7 +112,7 @@ export class ConnectionManager
|
|
|
112
112
|
this.deviceId &&
|
|
113
113
|
!this.isReconnecting
|
|
114
114
|
) {
|
|
115
|
-
this.
|
|
115
|
+
this.connLogger.warn('Unexpected disconnection detected');
|
|
116
116
|
this.emit('disconnected', this.deviceId);
|
|
117
117
|
this.stopHeartbeat();
|
|
118
118
|
|
|
@@ -127,7 +127,7 @@ export class ConnectionManager
|
|
|
127
127
|
* Connects to a Bluetooth device
|
|
128
128
|
*/
|
|
129
129
|
async connect(deviceId: string, options?: { retries?: number; timeout?: number }): Promise<void> {
|
|
130
|
-
this.
|
|
130
|
+
this.connLogger.info('Connecting to device:', deviceId);
|
|
131
131
|
|
|
132
132
|
const { retries = 0, timeout = this.config.connectionTimeout } = options || {};
|
|
133
133
|
let attempts = 0;
|
|
@@ -159,7 +159,7 @@ export class ConnectionManager
|
|
|
159
159
|
this.state = PrinterState.CONNECTED;
|
|
160
160
|
this.emit('state-change', PrinterState.CONNECTED);
|
|
161
161
|
this.emit('connected', deviceId);
|
|
162
|
-
this.
|
|
162
|
+
this.connLogger.info('Connected successfully');
|
|
163
163
|
|
|
164
164
|
// Start heartbeat if enabled
|
|
165
165
|
if (this.config.heartbeatEnabled) {
|
|
@@ -181,11 +181,11 @@ export class ConnectionManager
|
|
|
181
181
|
`Connection failed after ${attempts} attempts`,
|
|
182
182
|
error as Error
|
|
183
183
|
);
|
|
184
|
-
this.
|
|
184
|
+
this.connLogger.error('Connection failed:', printError);
|
|
185
185
|
this.emit('error', printError);
|
|
186
186
|
throw printError;
|
|
187
187
|
}
|
|
188
|
-
this.
|
|
188
|
+
this.connLogger.warn(`Connection attempt ${attempts}/${retries} failed, retrying...`, error);
|
|
189
189
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
190
190
|
}
|
|
191
191
|
}
|
|
@@ -200,12 +200,12 @@ export class ConnectionManager
|
|
|
200
200
|
this.isReconnecting = false;
|
|
201
201
|
|
|
202
202
|
if (!this.deviceId) {
|
|
203
|
-
this.
|
|
203
|
+
this.connLogger.warn('Disconnect called but no device connected');
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
const deviceId = this.deviceId;
|
|
208
|
-
this.
|
|
208
|
+
this.connLogger.info('Disconnecting from device:', deviceId);
|
|
209
209
|
|
|
210
210
|
try {
|
|
211
211
|
await this.adapter.disconnect(deviceId);
|
|
@@ -213,14 +213,14 @@ export class ConnectionManager
|
|
|
213
213
|
this.state = PrinterState.DISCONNECTED;
|
|
214
214
|
this.emit('state-change', PrinterState.DISCONNECTED);
|
|
215
215
|
this.emit('disconnected', deviceId);
|
|
216
|
-
this.
|
|
216
|
+
this.connLogger.info('Disconnected successfully');
|
|
217
217
|
} catch (error) {
|
|
218
218
|
const printError = new BluetoothPrintError(
|
|
219
219
|
ErrorCode.DEVICE_DISCONNECTED,
|
|
220
220
|
'Disconnect failed',
|
|
221
221
|
error as Error
|
|
222
222
|
);
|
|
223
|
-
this.
|
|
223
|
+
this.connLogger.error('Disconnect failed:', printError);
|
|
224
224
|
this.emit('error', printError);
|
|
225
225
|
throw printError;
|
|
226
226
|
}
|
|
@@ -236,7 +236,7 @@ export class ConnectionManager
|
|
|
236
236
|
this.checkHeartbeat();
|
|
237
237
|
}, this.config.heartbeatInterval);
|
|
238
238
|
|
|
239
|
-
this.
|
|
239
|
+
this.connLogger.debug('Heartbeat started with interval:', this.config.heartbeatInterval);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
/**
|
|
@@ -246,7 +246,7 @@ export class ConnectionManager
|
|
|
246
246
|
if (this.heartbeatTimer) {
|
|
247
247
|
clearInterval(this.heartbeatTimer);
|
|
248
248
|
this.heartbeatTimer = null;
|
|
249
|
-
this.
|
|
249
|
+
this.connLogger.debug('Heartbeat stopped');
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
@@ -262,12 +262,12 @@ export class ConnectionManager
|
|
|
262
262
|
const isConnected = this.isConnected();
|
|
263
263
|
|
|
264
264
|
if (isConnected) {
|
|
265
|
-
this.
|
|
265
|
+
this.connLogger.debug('Heartbeat OK');
|
|
266
266
|
} else {
|
|
267
267
|
this.handleHeartbeatLost();
|
|
268
268
|
}
|
|
269
269
|
} catch (error) {
|
|
270
|
-
this.
|
|
270
|
+
this.connLogger.warn('Heartbeat check failed:', error);
|
|
271
271
|
this.handleHeartbeatLost();
|
|
272
272
|
}
|
|
273
273
|
}
|
|
@@ -278,7 +278,7 @@ export class ConnectionManager
|
|
|
278
278
|
private handleHeartbeatLost(): void {
|
|
279
279
|
if (!this.deviceId) return;
|
|
280
280
|
|
|
281
|
-
this.
|
|
281
|
+
this.connLogger.warn('Heartbeat lost for device:', this.deviceId);
|
|
282
282
|
this.emit('heartbeat-lost', this.deviceId);
|
|
283
283
|
this.stopHeartbeat();
|
|
284
284
|
|
|
@@ -317,7 +317,7 @@ export class ConnectionManager
|
|
|
317
317
|
const deviceId = this.deviceId;
|
|
318
318
|
|
|
319
319
|
if (this.reconnectAttempts > this.config.maxReconnectAttempts) {
|
|
320
|
-
this.
|
|
320
|
+
this.connLogger.error('Max reconnect attempts reached');
|
|
321
321
|
this.isReconnecting = false;
|
|
322
322
|
this.emit('reconnect-failed', {
|
|
323
323
|
deviceId,
|
|
@@ -330,7 +330,7 @@ export class ConnectionManager
|
|
|
330
330
|
return;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
this.
|
|
333
|
+
this.connLogger.info(
|
|
334
334
|
`Reconnect attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts}`
|
|
335
335
|
);
|
|
336
336
|
this.emit('reconnecting', {
|
|
@@ -345,7 +345,7 @@ export class ConnectionManager
|
|
|
345
345
|
this.adapter
|
|
346
346
|
.connect(deviceId)
|
|
347
347
|
.then(() => {
|
|
348
|
-
this.
|
|
348
|
+
this.connLogger.info('Reconnected successfully');
|
|
349
349
|
this.isReconnecting = false;
|
|
350
350
|
this.reconnectAttempts = 0;
|
|
351
351
|
this.state = PrinterState.CONNECTED;
|
|
@@ -357,7 +357,7 @@ export class ConnectionManager
|
|
|
357
357
|
}
|
|
358
358
|
})
|
|
359
359
|
.catch(error => {
|
|
360
|
-
this.
|
|
360
|
+
this.connLogger.warn(`Reconnect attempt ${this.reconnectAttempts} failed:`, error);
|
|
361
361
|
|
|
362
362
|
this.reconnectTimer = setTimeout(() => {
|
|
363
363
|
this.attemptReconnect();
|
|
@@ -434,7 +434,7 @@ export class ConnectionManager
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
if (this.isReconnecting) {
|
|
437
|
-
this.
|
|
437
|
+
this.connLogger.warn('Reconnect already in progress');
|
|
438
438
|
return;
|
|
439
439
|
}
|
|
440
440
|
|
|
@@ -448,7 +448,7 @@ export class ConnectionManager
|
|
|
448
448
|
this.clearReconnectTimer();
|
|
449
449
|
this.isReconnecting = false;
|
|
450
450
|
this.reconnectAttempts = 0;
|
|
451
|
-
this.
|
|
451
|
+
this.connLogger.info('Reconnect stopped');
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
/**
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services Module
|
|
3
|
+
* 服务模块 - 提供连接管理、命令构建、任务管理等功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
ConnectionManager,
|
|
8
|
+
type ConnectionManagerConfig,
|
|
9
|
+
type ConnectionManagerEvents,
|
|
10
|
+
} from './ConnectionManager';
|
|
11
|
+
|
|
12
|
+
export { CommandBuilder } from './CommandBuilder';
|
|
13
|
+
|
|
14
|
+
export { PrintJobManager } from './PrintJobManager';
|
|
15
|
+
|
|
16
|
+
export * from './interfaces';
|