@onekeyfe/hd-transport 1.2.0-alpha.3 → 1.2.0-alpha.30
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/README.md +1 -1
- package/__tests__/messages.test.js +142 -0
- package/__tests__/protocol-v2-ble-frame-writer.test.js +119 -0
- package/__tests__/protocol-v2-link-manager.test.js +389 -0
- package/__tests__/protocol-v2-usb-transport-base.test.js +330 -0
- package/__tests__/protocol-v2.test.js +555 -119
- package/dist/constants.d.ts +6 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +981 -278
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +759 -247
- package/dist/protocols/index.d.ts +14 -5
- package/dist/protocols/index.d.ts.map +1 -1
- package/dist/protocols/v2/ble-frame-writer.d.ts +15 -0
- package/dist/protocols/v2/ble-frame-writer.d.ts.map +1 -0
- package/dist/protocols/v2/constants.d.ts +1 -0
- package/dist/protocols/v2/constants.d.ts.map +1 -1
- package/dist/protocols/v2/decode.d.ts +13 -2
- package/dist/protocols/v2/decode.d.ts.map +1 -1
- package/dist/protocols/v2/encode.d.ts +2 -3
- package/dist/protocols/v2/encode.d.ts.map +1 -1
- package/dist/protocols/v2/errors.d.ts +8 -0
- package/dist/protocols/v2/errors.d.ts.map +1 -0
- package/dist/protocols/v2/frame-assembler.d.ts.map +1 -1
- package/dist/protocols/v2/index.d.ts +2 -1
- package/dist/protocols/v2/index.d.ts.map +1 -1
- package/dist/protocols/v2/link-manager.d.ts +38 -0
- package/dist/protocols/v2/link-manager.d.ts.map +1 -0
- package/dist/protocols/v2/sequence-cursor.d.ts +5 -0
- package/dist/protocols/v2/sequence-cursor.d.ts.map +1 -0
- package/dist/protocols/v2/session.d.ts +19 -5
- package/dist/protocols/v2/session.d.ts.map +1 -1
- package/dist/protocols/v2/usb-transport-base.d.ts +32 -0
- package/dist/protocols/v2/usb-transport-base.d.ts.map +1 -0
- package/dist/serialization/protobuf/decode.d.ts.map +1 -1
- package/dist/types/messages.d.ts +523 -158
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/transport.d.ts +13 -3
- package/dist/types/transport.d.ts.map +1 -1
- package/messages-protocol-v2.json +796 -620
- package/package.json +3 -3
- package/scripts/protobuf-build.sh +96 -310
- package/scripts/protobuf-patches/index.js +1 -0
- package/scripts/protobuf-types.js +19 -1
- package/src/constants.ts +29 -15
- package/src/index.ts +11 -1
- package/src/protocols/index.ts +39 -40
- package/src/protocols/v2/ble-frame-writer.ts +77 -0
- package/src/protocols/v2/constants.ts +1 -0
- package/src/protocols/v2/crc8.ts +1 -1
- package/src/protocols/v2/decode.ts +71 -37
- package/src/protocols/v2/encode.ts +2 -28
- package/src/protocols/v2/errors.ts +25 -0
- package/src/protocols/v2/frame-assembler.ts +6 -4
- package/src/protocols/v2/index.ts +2 -1
- package/src/protocols/v2/link-manager.ts +186 -0
- package/src/protocols/v2/sequence-cursor.ts +10 -0
- package/src/protocols/v2/session.ts +157 -201
- package/src/protocols/v2/usb-transport-base.ts +213 -0
- package/src/serialization/protobuf/decode.ts +4 -1
- package/src/types/messages.ts +623 -181
- package/src/types/transport.ts +13 -3
- package/dist/protocols/v2/debug.d.ts +0 -13
- package/dist/protocols/v2/debug.d.ts.map +0 -1
- package/src/protocols/v2/debug.ts +0 -26
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { ProtocolV2FrameAssembler } from './frame-assembler';
|
|
2
|
+
import { ProtocolV2LinkError, isProtocolV2LinkError } from './errors';
|
|
3
|
+
import { ProtocolV2LinkManager } from './link-manager';
|
|
4
|
+
import { getErrorMessage } from './session';
|
|
5
|
+
|
|
6
|
+
import type { MessageFromOneKey, TransportCallOptions } from '../../types';
|
|
7
|
+
import type { ProtocolV2CallContext, ProtocolV2Schemas, ProtocolV2SessionOptions } from './session';
|
|
8
|
+
|
|
9
|
+
export type ProtocolV2UsbTransportBaseOptions = {
|
|
10
|
+
router: number;
|
|
11
|
+
maxFrameBytes: number;
|
|
12
|
+
logPrefix: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type ProtocolV2UsbCancellation = {
|
|
16
|
+
generation: number;
|
|
17
|
+
reason?: string;
|
|
18
|
+
promise: Promise<string>;
|
|
19
|
+
cancel: (reason: string) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export abstract class ProtocolV2UsbTransportBase<Key> {
|
|
23
|
+
private readonly protocolV2UsbLinks: ProtocolV2LinkManager<Key>;
|
|
24
|
+
|
|
25
|
+
private readonly protocolV2UsbAssemblers = new Map<Key, ProtocolV2FrameAssembler>();
|
|
26
|
+
|
|
27
|
+
private readonly protocolV2UsbGenerations = new Map<Key, number>();
|
|
28
|
+
|
|
29
|
+
private readonly protocolV2UsbCancellations = new Map<Key, ProtocolV2UsbCancellation>();
|
|
30
|
+
|
|
31
|
+
private readonly protocolV2UsbOptions: ProtocolV2UsbTransportBaseOptions;
|
|
32
|
+
|
|
33
|
+
protected constructor(options: ProtocolV2UsbTransportBaseOptions) {
|
|
34
|
+
this.protocolV2UsbOptions = options;
|
|
35
|
+
this.protocolV2UsbLinks = new ProtocolV2LinkManager<Key>({
|
|
36
|
+
getSchemas: () => this.getProtocolV2UsbSchemas(),
|
|
37
|
+
classifyError: error => (isProtocolV2LinkError(error) ? 'link-fatal' : 'recoverable'),
|
|
38
|
+
onLinkInvalidated: async (key, reason) => {
|
|
39
|
+
this.protocolV2UsbAssemblers.get(key)?.reset();
|
|
40
|
+
await this.resetProtocolV2UsbNativeLink(key, reason);
|
|
41
|
+
await this.onProtocolV2UsbLinkInvalidated(key, reason);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected abstract getProtocolV2UsbSchemas(): ProtocolV2Schemas;
|
|
47
|
+
|
|
48
|
+
protected abstract getProtocolV2UsbLogger(): ProtocolV2SessionOptions['logger'];
|
|
49
|
+
|
|
50
|
+
protected abstract writeProtocolV2UsbPacket(
|
|
51
|
+
key: Key,
|
|
52
|
+
frame: Uint8Array,
|
|
53
|
+
context: ProtocolV2CallContext
|
|
54
|
+
): Promise<void>;
|
|
55
|
+
|
|
56
|
+
protected abstract readProtocolV2UsbPacket(
|
|
57
|
+
key: Key,
|
|
58
|
+
context: ProtocolV2CallContext
|
|
59
|
+
): Promise<Uint8Array>;
|
|
60
|
+
|
|
61
|
+
protected abstract resetProtocolV2UsbNativeLink(key: Key, reason: string): Promise<void>;
|
|
62
|
+
|
|
63
|
+
protected abstract createProtocolV2UsbTimeoutError(name: string, timeoutMs: number): Error;
|
|
64
|
+
|
|
65
|
+
protected onProtocolV2UsbLinkInvalidated(_key: Key, _reason: string): Promise<void> | void {
|
|
66
|
+
// Subclasses may clear protocol caches or emit platform-specific diagnostics.
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
protected async rotateProtocolV2UsbGeneration(key: Key, reason: string): Promise<number> {
|
|
70
|
+
await this.protocolV2UsbLinks.invalidateLink(key, reason);
|
|
71
|
+
const generation = (this.protocolV2UsbGenerations.get(key) ?? 0) + 1;
|
|
72
|
+
this.protocolV2UsbGenerations.set(key, generation);
|
|
73
|
+
this.protocolV2UsbCancellations.set(key, this.createProtocolV2UsbCancellation(generation));
|
|
74
|
+
this.protocolV2UsbAssemblers.set(
|
|
75
|
+
key,
|
|
76
|
+
new ProtocolV2FrameAssembler(this.protocolV2UsbOptions.maxFrameBytes)
|
|
77
|
+
);
|
|
78
|
+
return generation;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected callProtocolV2Usb(
|
|
82
|
+
key: Key,
|
|
83
|
+
name: string,
|
|
84
|
+
data: Record<string, unknown>,
|
|
85
|
+
options?: TransportCallOptions
|
|
86
|
+
): Promise<MessageFromOneKey> {
|
|
87
|
+
return this.protocolV2UsbLinks.call(
|
|
88
|
+
key,
|
|
89
|
+
() => this.createProtocolV2UsbAdapter(key),
|
|
90
|
+
name,
|
|
91
|
+
data,
|
|
92
|
+
options
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected invalidateProtocolV2UsbLink(key: Key, reason: string): Promise<void> {
|
|
97
|
+
return this.protocolV2UsbLinks.invalidateLink(key, reason);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected invalidateAllProtocolV2UsbLinks(reason: string): Promise<void> {
|
|
101
|
+
return this.protocolV2UsbLinks.invalidateAllLinks(reason);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected async disposeProtocolV2UsbLinks(reason: string): Promise<void> {
|
|
105
|
+
await this.protocolV2UsbLinks.dispose(reason);
|
|
106
|
+
this.protocolV2UsbAssemblers.clear();
|
|
107
|
+
this.protocolV2UsbGenerations.clear();
|
|
108
|
+
this.protocolV2UsbCancellations.clear();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private createProtocolV2UsbAdapter(key: Key) {
|
|
112
|
+
const generation = this.protocolV2UsbGenerations.get(key);
|
|
113
|
+
if (generation === undefined) {
|
|
114
|
+
throw new Error('Protocol V2 USB generation has not been initialized');
|
|
115
|
+
}
|
|
116
|
+
const cancellation = this.protocolV2UsbCancellations.get(key);
|
|
117
|
+
if (!cancellation || cancellation.generation !== generation) {
|
|
118
|
+
throw new Error('Protocol V2 USB cancellation state has not been initialized');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const assertCurrentGeneration = () => {
|
|
122
|
+
if (cancellation.reason) {
|
|
123
|
+
throw new ProtocolV2LinkError('generation', cancellation.reason);
|
|
124
|
+
}
|
|
125
|
+
if (this.protocolV2UsbGenerations.get(key) !== generation) {
|
|
126
|
+
throw new ProtocolV2LinkError(
|
|
127
|
+
'generation',
|
|
128
|
+
'Protocol V2 USB connection generation changed'
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
router: this.protocolV2UsbOptions.router,
|
|
135
|
+
maxFrameBytes: this.protocolV2UsbOptions.maxFrameBytes,
|
|
136
|
+
generation,
|
|
137
|
+
prepareCall: () => {
|
|
138
|
+
assertCurrentGeneration();
|
|
139
|
+
},
|
|
140
|
+
writeFrame: async (frame: Uint8Array, context: ProtocolV2CallContext) => {
|
|
141
|
+
assertCurrentGeneration();
|
|
142
|
+
try {
|
|
143
|
+
await this.writeProtocolV2UsbPacket(key, frame, context);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw this.createProtocolV2UsbIoError('write', error);
|
|
146
|
+
}
|
|
147
|
+
assertCurrentGeneration();
|
|
148
|
+
},
|
|
149
|
+
readFrame: async (context: ProtocolV2CallContext) => {
|
|
150
|
+
assertCurrentGeneration();
|
|
151
|
+
const assembler = this.getProtocolV2UsbAssembler(key);
|
|
152
|
+
let frame = assembler.push(new Uint8Array(0));
|
|
153
|
+
while (!frame) {
|
|
154
|
+
const packetRead = this.readProtocolV2UsbPacket(key, context)
|
|
155
|
+
.then(packet => ({ packet }))
|
|
156
|
+
.catch(error => {
|
|
157
|
+
throw this.createProtocolV2UsbIoError('read', error);
|
|
158
|
+
});
|
|
159
|
+
const cancelled = cancellation.promise.then(reason => ({ reason }));
|
|
160
|
+
const result = await Promise.race([packetRead, cancelled]);
|
|
161
|
+
if ('reason' in result) {
|
|
162
|
+
throw new ProtocolV2LinkError('generation', result.reason);
|
|
163
|
+
}
|
|
164
|
+
assertCurrentGeneration();
|
|
165
|
+
frame = assembler.push(result.packet);
|
|
166
|
+
}
|
|
167
|
+
assertCurrentGeneration();
|
|
168
|
+
return frame;
|
|
169
|
+
},
|
|
170
|
+
reset: (reason: string) => {
|
|
171
|
+
cancellation.cancel(reason);
|
|
172
|
+
this.protocolV2UsbAssemblers.get(key)?.reset();
|
|
173
|
+
},
|
|
174
|
+
logger: this.getProtocolV2UsbLogger(),
|
|
175
|
+
logPrefix: this.protocolV2UsbOptions.logPrefix,
|
|
176
|
+
createTimeoutError: (messageName: string, timeoutMs: number) =>
|
|
177
|
+
this.createProtocolV2UsbTimeoutError(messageName, timeoutMs),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private getProtocolV2UsbAssembler(key: Key): ProtocolV2FrameAssembler {
|
|
182
|
+
const assembler = this.protocolV2UsbAssemblers.get(key);
|
|
183
|
+
if (!assembler) {
|
|
184
|
+
throw new Error('Protocol V2 USB assembler has not been initialized');
|
|
185
|
+
}
|
|
186
|
+
return assembler;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private createProtocolV2UsbCancellation(generation: number): ProtocolV2UsbCancellation {
|
|
190
|
+
let resolveCancellation: (reason: string) => void = () => undefined;
|
|
191
|
+
const cancellation: ProtocolV2UsbCancellation = {
|
|
192
|
+
generation,
|
|
193
|
+
promise: new Promise(resolve => {
|
|
194
|
+
resolveCancellation = resolve;
|
|
195
|
+
}),
|
|
196
|
+
cancel: reason => {
|
|
197
|
+
if (cancellation.reason) return;
|
|
198
|
+
cancellation.reason = reason;
|
|
199
|
+
resolveCancellation(reason);
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
return cancellation;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private createProtocolV2UsbIoError(operation: 'read' | 'write', error: unknown) {
|
|
206
|
+
if (isProtocolV2LinkError(error)) return error;
|
|
207
|
+
return new ProtocolV2LinkError(
|
|
208
|
+
'io',
|
|
209
|
+
`Protocol V2 USB ${operation} failed: ${getErrorMessage(error) || 'unknown error'}`,
|
|
210
|
+
error
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -70,7 +70,10 @@ function messageToJSON(Message: Message<Record<string, unknown>>, fields: Type['
|
|
|
70
70
|
}
|
|
71
71
|
// message type
|
|
72
72
|
else if (field.resolvedType!.fields) {
|
|
73
|
-
|
|
73
|
+
// [compatibility]: absent optional sub-messages are not own properties
|
|
74
|
+
// of the decoded instance, so value is undefined here; decode them to
|
|
75
|
+
// null, matching the optional primitive-field convention above.
|
|
76
|
+
res[key] = value == null ? null : messageToJSON(value, (field.resolvedType as Type).fields);
|
|
74
77
|
} else {
|
|
75
78
|
throw new Error(`case not handled: ${key}`);
|
|
76
79
|
}
|