@onekeyfe/hd-transport 1.2.0-alpha.11 → 1.2.0-alpha.13
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/__tests__/messages.test.js +21 -9
- package/__tests__/protocol-v2.test.js +100 -27
- package/dist/index.d.ts +83 -47
- package/dist/index.js +82 -174
- package/dist/protocols/index.d.ts +8 -5
- package/dist/protocols/index.d.ts.map +1 -1
- package/dist/protocols/v2/decode.d.ts +1 -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/index.d.ts +0 -1
- package/dist/protocols/v2/index.d.ts.map +1 -1
- package/dist/protocols/v2/session.d.ts.map +1 -1
- package/dist/types/messages.d.ts +49 -7
- package/dist/types/messages.d.ts.map +1 -1
- package/messages-protocol-v2.json +422 -16
- package/package.json +3 -3
- package/scripts/protobuf-build.sh +20 -232
- package/scripts/protobuf-types.js +9 -0
- package/src/protocols/index.ts +15 -38
- package/src/protocols/v2/decode.ts +1 -23
- package/src/protocols/v2/encode.ts +1 -27
- package/src/protocols/v2/index.ts +0 -1
- package/src/protocols/v2/session.ts +19 -147
- package/src/types/messages.ts +50 -7
- 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
|
@@ -5,14 +5,10 @@ set -euxo pipefail
|
|
|
5
5
|
echo $#
|
|
6
6
|
|
|
7
7
|
PARENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
|
8
|
-
PACKAGE_ROOT="$PARENT_PATH/.."
|
|
9
8
|
|
|
10
9
|
SRC="../../submodules/firmware/common/protob"
|
|
11
10
|
DIST="."
|
|
12
11
|
LANG="typescript"
|
|
13
|
-
# Absolute paths — resolved relative to this script's directory
|
|
14
|
-
REPO_ROOT="$PARENT_PATH/../../.."
|
|
15
|
-
CORE_MESSAGES_DIR="$REPO_ROOT/packages/core/src/data/messages"
|
|
16
12
|
|
|
17
13
|
if [[ $# -ne 0 && $# -ne 3 ]]
|
|
18
14
|
then
|
|
@@ -33,238 +29,30 @@ if [[ "$LANG" != "typescript" && "$LANG" != "flow" ]];
|
|
|
33
29
|
exit 1
|
|
34
30
|
fi
|
|
35
31
|
|
|
36
|
-
if [[ "$SRC" = /* ]]; then
|
|
37
|
-
SRC_PATH="$SRC"
|
|
38
|
-
else
|
|
39
|
-
SRC_PATH="$PACKAGE_ROOT/$SRC"
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
if [[ "$DIST" = /* ]]; then
|
|
43
|
-
DIST_PATH="$DIST"
|
|
44
|
-
else
|
|
45
|
-
DIST_PATH="$PACKAGE_ROOT/$DIST"
|
|
46
|
-
fi
|
|
47
|
-
|
|
48
|
-
# Remove temp proto files on any exit, including failure paths
|
|
49
|
-
trap 'rm -f "$DIST_PATH/messages-tmp.proto" "$PARENT_PATH/messages-protocol-v2-tmp.proto"' EXIT
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# ============================================================
|
|
53
|
-
# BUILD Pro1 messages.json (requires firmware submodule)
|
|
54
|
-
# ============================================================
|
|
55
|
-
# Combines all messages*.proto files from firmware submodule into
|
|
56
|
-
# messages.json, then copies to core package.
|
|
57
|
-
if [ -d "$SRC_PATH" ] && ls "$SRC_PATH"/messages*.proto 1>/dev/null 2>&1; then
|
|
58
|
-
echo "=== Building Pro1 (legacy) protobuf messages ==="
|
|
59
|
-
TMP_PROTO="$DIST_PATH/messages-tmp.proto"
|
|
60
|
-
echo 'syntax = "proto2";' > "$TMP_PROTO"
|
|
61
|
-
echo 'import "google/protobuf/descriptor.proto";' >> "$TMP_PROTO"
|
|
62
|
-
echo "Build proto file from $SRC_PATH"
|
|
63
|
-
grep -hv -e '^import ' -e '^syntax' -e '^package' -e 'option java_' "$SRC_PATH"/messages*.proto \
|
|
64
|
-
| sed 's/ hw\.trezor\.messages\.common\./ /' \
|
|
65
|
-
| sed 's/ common\./ /' \
|
|
66
|
-
| sed 's/ ethereum_definitions\./ /' \
|
|
67
|
-
| sed 's/ management\./ /' \
|
|
68
|
-
| sed 's/^option /\/\/ option /' \
|
|
69
|
-
| grep -v ' reserved '>> "$TMP_PROTO"
|
|
70
|
-
|
|
71
|
-
npx pbjs -t json -p "$DIST_PATH" -o "$DIST_PATH/messages.json" --keep-case "$TMP_PROTO"
|
|
72
|
-
rm "$TMP_PROTO"
|
|
73
32
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
33
|
+
# BUILD combined messages.proto file from protobuf files
|
|
34
|
+
# this code was copied from ./submodules/firmware/protob Makekile
|
|
35
|
+
# clear protobuf syntax and remove unknown values to be able to work with proto2js
|
|
36
|
+
echo 'syntax = "proto2";' > $DIST/messages.proto
|
|
37
|
+
echo 'import "google/protobuf/descriptor.proto";' >> $DIST/messages.proto
|
|
38
|
+
echo "Build proto file from $SRC"
|
|
39
|
+
grep -hv -e '^import ' -e '^syntax' -e '^package' -e 'option java_' $SRC/messages*.proto \
|
|
40
|
+
| sed 's/ hw\.trezor\.messages\.common\./ /' \
|
|
41
|
+
| sed 's/ common\./ /' \
|
|
42
|
+
| sed 's/ ethereum_definitions\./ /' \
|
|
43
|
+
| sed 's/ management\./ /' \
|
|
44
|
+
| sed 's/^option /\/\/ option /' \
|
|
45
|
+
| grep -v ' reserved '>> $DIST/messages.proto
|
|
77
46
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# section below, after both schemas are available.
|
|
82
|
-
else
|
|
83
|
-
# Intentional asymmetry with the Protocol V2 section below: the legacy firmware
|
|
84
|
-
# submodule is optional (the committed messages.json stays in use when it is
|
|
85
|
-
# absent), while firmware-pro2 is the only source of the Protocol V2 schema,
|
|
86
|
-
# so its absence is a hard error (exit 1).
|
|
87
|
-
echo "⚠️ firmware submodule not found at $SRC_PATH"
|
|
88
|
-
echo " Skipping Pro1 protobuf build. To enable:"
|
|
89
|
-
echo " git submodule update --init submodules/firmware"
|
|
90
|
-
fi
|
|
47
|
+
# BUILD messages.json from message.proto
|
|
48
|
+
npx pbjs -t json -p $DIST -o $DIST/messages.json --keep-case messages.proto
|
|
49
|
+
rm $DIST/messages.proto
|
|
91
50
|
|
|
51
|
+
echo "generating type definitions for: $LANG"
|
|
92
52
|
|
|
93
|
-
# ============================================================
|
|
94
|
-
# BUILD Protocol V2 messages-protocol-v2.json
|
|
95
|
-
# ============================================================
|
|
96
|
-
# Source of truth: submodules/firmware-pro2/sys/protobuf/onekey_protocol/.
|
|
97
|
-
# Protocol V2 keeps chain/app protocols under legacy/ and system protocols under latest/.
|
|
98
|
-
# The SDK flattens them into one protobuf schema for transport runtime, but it must keep
|
|
99
|
-
# firmware message names and enum values intact. SDK-facing aliases belong in core/API code,
|
|
100
|
-
# not in the protobuf schema.
|
|
101
|
-
# ============================================================
|
|
102
53
|
cd "$PARENT_PATH"
|
|
103
54
|
|
|
104
|
-
|
|
105
|
-
SRC_PRO2_LATEST="$REPO_ROOT/submodules/firmware-pro2/sys/protobuf/onekey_protocol/latest"
|
|
106
|
-
|
|
107
|
-
if [ -d "$SRC_PRO2_LATEST" ] && ls "$SRC_PRO2_LATEST"/messages*.proto 1>/dev/null 2>&1; then
|
|
108
|
-
echo "=== Building Protocol V2 messages from firmware-pro2 legacy + latest protobuf schema ==="
|
|
109
|
-
TMP_PROTO="$PARENT_PATH/messages-protocol-v2-tmp.proto"
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
echo 'syntax = "proto2";'
|
|
113
|
-
echo 'import "google/protobuf/descriptor.proto";'
|
|
114
|
-
echo ''
|
|
115
|
-
|
|
116
|
-
# Pro2 firmware keeps chain/app protocols under legacy/, and Protocol V2
|
|
117
|
-
# device/filesystem/firmware protocols under latest/. Build one flat
|
|
118
|
-
# schema so Protocol V2 framing can also encode legacy public-chain calls.
|
|
119
|
-
grep -hv \
|
|
120
|
-
-e '^import ' -e '^syntax' -e '^package' -e 'option java_' \
|
|
121
|
-
"$SRC_PRO2_LEGACY"/messages*.proto \
|
|
122
|
-
| sed 's/ hw\.onekey\.messages\.[a-zA-Z_]*\./ /g' \
|
|
123
|
-
| sed 's/ crypto\./ /g' \
|
|
124
|
-
| sed 's/ ethereum_definitions\./ /g' \
|
|
125
|
-
| sed 's/ management\./ /g' \
|
|
126
|
-
| sed 's/^option /\/\/ option /' \
|
|
127
|
-
| grep -v ' reserved '
|
|
128
|
-
|
|
129
|
-
echo ''
|
|
130
|
-
echo '// --- Protocol V2 system messages ---'
|
|
131
|
-
grep -hv \
|
|
132
|
-
-e '^import ' -e '^syntax' -e '^package' -e 'option java_' \
|
|
133
|
-
-e '^option ' \
|
|
134
|
-
"$SRC_PRO2_LATEST"/messages*.proto \
|
|
135
|
-
| grep -v ' reserved '
|
|
136
|
-
|
|
137
|
-
} > "$TMP_PROTO"
|
|
138
|
-
|
|
139
|
-
node - "$TMP_PROTO" <<'NODE'
|
|
140
|
-
const fs = require('fs');
|
|
55
|
+
node ./protobuf-types.js $LANG
|
|
141
56
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const removeTopLevelMessage = (source, name) => {
|
|
146
|
-
const pattern = new RegExp(`(^|\\n)message\\s+${name}\\s*\\{`, 'm');
|
|
147
|
-
const match = pattern.exec(source);
|
|
148
|
-
if (!match) return source;
|
|
149
|
-
|
|
150
|
-
const start = match.index + (match[1] ? match[1].length : 0);
|
|
151
|
-
let index = start;
|
|
152
|
-
let depth = 0;
|
|
153
|
-
while (index < source.length) {
|
|
154
|
-
const char = source[index];
|
|
155
|
-
if (char === '{') {
|
|
156
|
-
depth += 1;
|
|
157
|
-
} else if (char === '}') {
|
|
158
|
-
depth -= 1;
|
|
159
|
-
if (depth === 0) {
|
|
160
|
-
index += 1;
|
|
161
|
-
while (index < source.length && /\s/.test(source[index])) index += 1;
|
|
162
|
-
return `${source.slice(0, start)}${source.slice(index)}`;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
index += 1;
|
|
166
|
-
}
|
|
167
|
-
throw new Error(`Unterminated message block: ${name}`);
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
[
|
|
171
|
-
'Initialize',
|
|
172
|
-
'GetFeatures',
|
|
173
|
-
'OnekeyGetFeatures',
|
|
174
|
-
'Features',
|
|
175
|
-
].forEach(name => {
|
|
176
|
-
proto = removeTopLevelMessage(proto, name);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
fs.writeFileSync(protoPath, proto);
|
|
180
|
-
|
|
181
|
-
const messageNames = new Set(
|
|
182
|
-
Array.from(proto.matchAll(/^\s*message\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/gm)).map(
|
|
183
|
-
match => match[1]
|
|
184
|
-
)
|
|
185
|
-
);
|
|
186
|
-
const messageTypeNames = new Set(
|
|
187
|
-
Array.from(proto.matchAll(/^\s*MessageType_([A-Za-z_][A-Za-z0-9_]*)\s*=/gm)).map(
|
|
188
|
-
match => match[1]
|
|
189
|
-
)
|
|
190
|
-
);
|
|
191
|
-
const requiredMessages = [
|
|
192
|
-
'DeviceFactoryInfoSet',
|
|
193
|
-
'DeviceFactoryInfoGet',
|
|
194
|
-
'DeviceFactoryInfo',
|
|
195
|
-
'ProtocolInfoRequest',
|
|
196
|
-
'ProtocolInfo',
|
|
197
|
-
'Ping',
|
|
198
|
-
'Success',
|
|
199
|
-
'Failure',
|
|
200
|
-
'DeviceReboot',
|
|
201
|
-
'DeviceInfoGet',
|
|
202
|
-
'DeviceInfo',
|
|
203
|
-
'DeviceStatusGet',
|
|
204
|
-
'DeviceStatus',
|
|
205
|
-
'DevGetOnboardingStatus',
|
|
206
|
-
'DevOnboardingStatus',
|
|
207
|
-
'DeviceSessionGet',
|
|
208
|
-
'DeviceSession',
|
|
209
|
-
'DeviceSessionAskPin',
|
|
210
|
-
'DeviceSessionPinResult',
|
|
211
|
-
'DeviceFirmwareUpdateRequest',
|
|
212
|
-
'DeviceFirmwareUpdateStatusGet',
|
|
213
|
-
'DeviceFirmwareUpdateStatus',
|
|
214
|
-
'FilesystemPermissionFix',
|
|
215
|
-
'FilesystemPathInfo',
|
|
216
|
-
'FilesystemPathInfoQuery',
|
|
217
|
-
'FilesystemFile',
|
|
218
|
-
'FilesystemFileRead',
|
|
219
|
-
'FilesystemFileWrite',
|
|
220
|
-
'FilesystemFileDelete',
|
|
221
|
-
'FilesystemDir',
|
|
222
|
-
'FilesystemDirList',
|
|
223
|
-
'FilesystemDirMake',
|
|
224
|
-
'FilesystemDirRemove',
|
|
225
|
-
'FilesystemFormat',
|
|
226
|
-
'PortfolioUpdate',
|
|
227
|
-
];
|
|
228
|
-
const missingMessages = requiredMessages.filter(name => !messageNames.has(name));
|
|
229
|
-
const missingMessageTypes = requiredMessages.filter(name => !messageTypeNames.has(name));
|
|
230
|
-
|
|
231
|
-
if (missingMessages.length > 0 || missingMessageTypes.length > 0) {
|
|
232
|
-
throw new Error(
|
|
233
|
-
`Protocol V2 schema missing required entries: messages=[${missingMessages.join(
|
|
234
|
-
', '
|
|
235
|
-
)}], messageTypes=[${missingMessageTypes.join(
|
|
236
|
-
', '
|
|
237
|
-
)}]. Make sure submodules/firmware-pro2 is checked out on branch dev ` +
|
|
238
|
-
'(origin/dev), which contains the latest Protocol V2 Device*/Filesystem* messages.'
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
NODE
|
|
243
|
-
|
|
244
|
-
npx pbjs -t json \
|
|
245
|
-
-p "$PARENT_PATH" \
|
|
246
|
-
-o "$PARENT_PATH/../messages-protocol-v2.json" \
|
|
247
|
-
--keep-case \
|
|
248
|
-
"$(basename "$TMP_PROTO")"
|
|
249
|
-
|
|
250
|
-
rm -f "$TMP_PROTO"
|
|
251
|
-
|
|
252
|
-
cp "$PARENT_PATH/../messages-protocol-v2.json" "$CORE_MESSAGES_DIR/messages-protocol-v2.json"
|
|
253
|
-
echo "Protocol V2 messages-protocol-v2.json generated from firmware-pro2 legacy + latest schema and copied to core"
|
|
254
|
-
|
|
255
|
-
yarn --cwd "$PACKAGE_ROOT" prettier --write "$PARENT_PATH/../messages-protocol-v2.json"
|
|
256
|
-
yarn --cwd "$PACKAGE_ROOT" prettier --write "$CORE_MESSAGES_DIR/messages-protocol-v2.json"
|
|
257
|
-
|
|
258
|
-
echo "generating type definitions for: $LANG"
|
|
259
|
-
node ./protobuf-types.js $LANG
|
|
260
|
-
yarn --cwd "$PACKAGE_ROOT" prettier --write "$PACKAGE_ROOT/src/types/messages.ts"
|
|
261
|
-
echo "=== Protocol V2 messages build complete ==="
|
|
262
|
-
else
|
|
263
|
-
# Unlike the optional Pro1 (legacy) section above, the firmware-pro2 submodule is
|
|
264
|
-
# the only source of the Protocol V2 schema, so a missing checkout is a hard error.
|
|
265
|
-
echo "firmware-pro2 latest protobuf schema not found at $SRC_PRO2_LATEST"
|
|
266
|
-
echo "The Protocol V2 schema requires firmware-pro2 on branch dev."
|
|
267
|
-
echo "Run: git submodule update --init submodules/firmware-pro2"
|
|
268
|
-
echo "Then: git -C submodules/firmware-pro2 fetch origin dev && git -C submodules/firmware-pro2 checkout origin/dev"
|
|
269
|
-
exit 1
|
|
270
|
-
fi
|
|
57
|
+
yarn prettier --write messages.json
|
|
58
|
+
yarn prettier --write **/messages.ts
|
|
@@ -19,6 +19,10 @@ const optionalJsonFiles = ['../messages-protocol-v2.json'];
|
|
|
19
19
|
const OPTIONAL_DUPLICATE_TYPE_ALIASES = {
|
|
20
20
|
DeviceInfo: 'ProtocolV2DeviceInfo',
|
|
21
21
|
};
|
|
22
|
+
const OPTIONAL_NESTED_TYPE_ALIASES = [
|
|
23
|
+
{ parent: 'Failure', name: 'FailureType', alias: 'ProtocolV2FailureType' },
|
|
24
|
+
{ parent: 'Features', name: 'Capability', alias: 'ProtocolV2Capability' },
|
|
25
|
+
];
|
|
22
26
|
const messageTypeAliases = {};
|
|
23
27
|
const skipMessageTypeKeys = new Set(Object.values(OPTIONAL_DUPLICATE_TYPE_ALIASES));
|
|
24
28
|
|
|
@@ -59,6 +63,7 @@ const ENUM_KEYS = [
|
|
|
59
63
|
'ButtonRequestType',
|
|
60
64
|
'PinMatrixRequestType',
|
|
61
65
|
'WordRequestType',
|
|
66
|
+
'ProtocolV2Capability',
|
|
62
67
|
];
|
|
63
68
|
|
|
64
69
|
const parseEnumTypescript = (itemName, item) => {
|
|
@@ -317,6 +322,10 @@ optionalJsonFiles.forEach(jsonFile => {
|
|
|
317
322
|
const jsonPath = path.join(__dirname, jsonFile);
|
|
318
323
|
if (!fs.existsSync(jsonPath)) return;
|
|
319
324
|
const optionalJson = readJson(jsonPath);
|
|
325
|
+
OPTIONAL_NESTED_TYPE_ALIASES.forEach(({ parent, name, alias }) => {
|
|
326
|
+
const definition = optionalJson.nested[parent]?.nested?.[name];
|
|
327
|
+
if (definition) optionalJson.nested[alias] = definition;
|
|
328
|
+
});
|
|
320
329
|
optionalJsons.push(optionalJson);
|
|
321
330
|
Object.keys(optionalJson.nested).forEach(e => {
|
|
322
331
|
if (!json.nested[e]) return; // V2-only type, parsed after the V1 pass below
|
package/src/protocols/index.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { decode as decodeProtobuf } from '../serialization/protobuf/decode';
|
|
|
9
9
|
import { decodeFrame as decodeV2Frame, encodeProtobufFrame, isAckFrame } from './v2';
|
|
10
10
|
|
|
11
11
|
import type { Root } from 'protobufjs/light';
|
|
12
|
-
import type { ProtocolV2DebugLogger } from './v2';
|
|
13
12
|
|
|
14
13
|
export const PROTOCOL_V2_SYS_MESSAGE_THRESHOLD = 60000;
|
|
15
14
|
|
|
@@ -23,9 +22,6 @@ type ProtocolV2FrameOptions = {
|
|
|
23
22
|
router?: number;
|
|
24
23
|
/** Sequence number (1-255). Managed per-session by ProtocolV2Session. */
|
|
25
24
|
seq?: number;
|
|
26
|
-
logger?: ProtocolV2DebugLogger;
|
|
27
|
-
logPrefix?: string;
|
|
28
|
-
context?: string;
|
|
29
25
|
};
|
|
30
26
|
|
|
31
27
|
const resolveProtocolV2EncodeSchema = (name: string, schemas: ProtocolV2Schemas) => {
|
|
@@ -76,6 +72,18 @@ export const ProtocolV1 = {
|
|
|
76
72
|
export const ProtocolV2 = {
|
|
77
73
|
isAckFrame,
|
|
78
74
|
|
|
75
|
+
inspectFrame(schemas: ProtocolV2Schemas, frame: Uint8Array) {
|
|
76
|
+
const { messageTypeId, pbPayload, seq } = decodeV2Frame(frame);
|
|
77
|
+
const { messageName } = createProtocolV2MessageFromType(messageTypeId, schemas);
|
|
78
|
+
return {
|
|
79
|
+
messageName,
|
|
80
|
+
messageTypeId,
|
|
81
|
+
pbPayload,
|
|
82
|
+
seq,
|
|
83
|
+
type: messageName,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
|
|
79
87
|
encodeFrame(
|
|
80
88
|
schemas: ProtocolV2Schemas,
|
|
81
89
|
name: string,
|
|
@@ -89,52 +97,21 @@ export const ProtocolV2 = {
|
|
|
89
97
|
const rawPbBuffer = pbBuffer.toBuffer() as unknown as ArrayBuffer;
|
|
90
98
|
const pbBytes = new Uint8Array(rawPbBuffer);
|
|
91
99
|
|
|
92
|
-
options.logger?.debug?.(`[${options.logPrefix ?? 'ProtocolV2'}] encode protobuf`, {
|
|
93
|
-
context: options.context ?? `encode:${name}`,
|
|
94
|
-
messageName: name,
|
|
95
|
-
messageTypeId,
|
|
96
|
-
pbPayloadLength: pbBytes.length,
|
|
97
|
-
packetSrc: options.packetSrc ?? 0,
|
|
98
|
-
router: options.router ?? 0,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
100
|
return encodeProtobufFrame(
|
|
102
101
|
messageTypeId,
|
|
103
102
|
pbBytes,
|
|
104
103
|
options.packetSrc,
|
|
105
104
|
options.router,
|
|
106
|
-
{
|
|
107
|
-
logger: options.logger,
|
|
108
|
-
logPrefix: options.logPrefix,
|
|
109
|
-
context: options.context ?? `encode:${name}`,
|
|
110
|
-
messageName: name,
|
|
111
|
-
},
|
|
112
105
|
options.seq
|
|
113
106
|
);
|
|
114
107
|
},
|
|
115
108
|
|
|
116
|
-
decodeFrame(
|
|
117
|
-
schemas
|
|
118
|
-
|
|
119
|
-
options: Pick<ProtocolV2FrameOptions, 'logger' | 'logPrefix' | 'context'> = {}
|
|
120
|
-
) {
|
|
121
|
-
const { messageTypeId, pbPayload, seq } = decodeV2Frame(frame, {
|
|
122
|
-
logger: options.logger,
|
|
123
|
-
logPrefix: options.logPrefix,
|
|
124
|
-
context: options.context ?? 'decode',
|
|
125
|
-
});
|
|
126
|
-
const { Message, messageName } = createProtocolV2MessageFromType(messageTypeId, schemas);
|
|
109
|
+
decodeFrame(schemas: ProtocolV2Schemas, frame: Uint8Array) {
|
|
110
|
+
const { messageTypeId, pbPayload, seq, messageName } = this.inspectFrame(schemas, frame);
|
|
111
|
+
const { Message } = createProtocolV2MessageFromType(messageTypeId, schemas);
|
|
127
112
|
const rxByteBuffer = ByteBuffer.wrap(Buffer.from(pbPayload) as unknown as ArrayBuffer);
|
|
128
113
|
const message = decodeProtobuf(Message, rxByteBuffer);
|
|
129
114
|
|
|
130
|
-
options.logger?.debug?.(`[${options.logPrefix ?? 'ProtocolV2'}] decode protobuf`, {
|
|
131
|
-
context: options.context ?? `decode:${messageName}`,
|
|
132
|
-
messageName,
|
|
133
|
-
messageTypeId,
|
|
134
|
-
pbPayloadLength: pbPayload.length,
|
|
135
|
-
seq,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
115
|
return {
|
|
139
116
|
message,
|
|
140
117
|
messageName,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { PROTO_DATA_TYPE_ACK, PROTO_HEAD_CRC_SIZE, PROTO_HEAD_SOF } from './constants';
|
|
2
2
|
import { crc8 } from './crc8';
|
|
3
|
-
import { logProtocolV2Debug } from './debug';
|
|
4
|
-
|
|
5
|
-
import type { ProtocolV2FrameDebugOptions } from './debug';
|
|
6
3
|
|
|
7
4
|
export interface ProtoV2Frame {
|
|
8
5
|
/** Little-endian message type ID */
|
|
@@ -74,13 +71,8 @@ export function isAckFrame(data: Uint8Array): boolean {
|
|
|
74
71
|
*
|
|
75
72
|
* Returns the decoded messageTypeId, raw protobuf payload, and sequence number.
|
|
76
73
|
*/
|
|
77
|
-
export function decodeFrame(
|
|
78
|
-
data: Uint8Array,
|
|
79
|
-
debugOptions?: ProtocolV2FrameDebugOptions
|
|
80
|
-
): ProtoV2Frame {
|
|
74
|
+
export function decodeFrame(data: Uint8Array): ProtoV2Frame {
|
|
81
75
|
const frameLen = validateFrame(data);
|
|
82
|
-
const expectedHeaderCrc = data[3];
|
|
83
|
-
const expectedFrameCrc = data[frameLen - 1];
|
|
84
76
|
|
|
85
77
|
const seq = data[6];
|
|
86
78
|
// Payload spans bytes 7 to frameLen-2 (inclusive), excluding final CRC byte
|
|
@@ -93,19 +85,5 @@ export function decodeFrame(
|
|
|
93
85
|
const messageTypeId = payloadData[0] + payloadData[1] * 256;
|
|
94
86
|
const pbPayload = payloadData.slice(2);
|
|
95
87
|
|
|
96
|
-
logProtocolV2Debug(debugOptions, 'decode raw frame', {
|
|
97
|
-
frameLen,
|
|
98
|
-
dataLength: data.length,
|
|
99
|
-
router: data[4],
|
|
100
|
-
attr: data[5],
|
|
101
|
-
seq,
|
|
102
|
-
headerCrc: data[3],
|
|
103
|
-
expectedHeaderCrc,
|
|
104
|
-
frameCrc: data[frameLen - 1],
|
|
105
|
-
expectedFrameCrc,
|
|
106
|
-
messageTypeId,
|
|
107
|
-
pbPayloadLength: pbPayload.length,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
88
|
return { messageTypeId, pbPayload, seq };
|
|
111
89
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { PROTO_DATA_TYPE_PACKET, PROTO_HEAD_CRC_SIZE, PROTO_HEAD_SOF } from './constants';
|
|
2
2
|
import { crc8 } from './crc8';
|
|
3
|
-
import { logProtocolV2Debug } from './debug';
|
|
4
3
|
import { PROTOCOL_V2_FRAME_MAX_BYTES } from '../../constants';
|
|
5
4
|
|
|
6
|
-
import type { ProtocolV2FrameDebugOptions } from './debug';
|
|
7
|
-
|
|
8
5
|
// Default sequence number when callers do not manage one themselves.
|
|
9
6
|
// Stateful per-session sequencing lives in ProtocolV2Session (session.ts),
|
|
10
7
|
// which advances the counter via nextProtoSeq() and passes it in explicitly.
|
|
@@ -35,7 +32,6 @@ export function encodeFrame(
|
|
|
35
32
|
payload: Uint8Array | null,
|
|
36
33
|
packetSrc?: number,
|
|
37
34
|
router?: number,
|
|
38
|
-
debugOptions?: ProtocolV2FrameDebugOptions,
|
|
39
35
|
seq?: number
|
|
40
36
|
): Uint8Array {
|
|
41
37
|
const resolvedPacketSrc = packetSrc ?? 0;
|
|
@@ -69,17 +65,6 @@ export function encodeFrame(
|
|
|
69
65
|
// CRC8 over entire frame except last byte
|
|
70
66
|
frame[frameLen - 1] = crc8(frame, frameLen - 1);
|
|
71
67
|
|
|
72
|
-
logProtocolV2Debug(debugOptions, 'encode raw frame', {
|
|
73
|
-
frameLen,
|
|
74
|
-
payloadLen,
|
|
75
|
-
packetSrc: resolvedPacketSrc,
|
|
76
|
-
router: frame[4],
|
|
77
|
-
attr: frame[5],
|
|
78
|
-
seq: frame[6],
|
|
79
|
-
headerCrc: frame[3],
|
|
80
|
-
frameCrc: frame[frameLen - 1],
|
|
81
|
-
});
|
|
82
|
-
|
|
83
68
|
return frame;
|
|
84
69
|
}
|
|
85
70
|
|
|
@@ -95,22 +80,11 @@ export function encodeProtobufFrame(
|
|
|
95
80
|
pbPayload: Uint8Array,
|
|
96
81
|
packetSrc?: number,
|
|
97
82
|
router?: number,
|
|
98
|
-
debugOptions?: ProtocolV2FrameDebugOptions,
|
|
99
83
|
seq?: number
|
|
100
84
|
): Uint8Array {
|
|
101
85
|
const payload = new Uint8Array(2 + pbPayload.length);
|
|
102
86
|
payload[0] = messageTypeId % 256;
|
|
103
87
|
payload[1] = Math.floor(messageTypeId / 256) % 256;
|
|
104
88
|
payload.set(pbPayload, 2);
|
|
105
|
-
return encodeFrame(
|
|
106
|
-
payload,
|
|
107
|
-
packetSrc,
|
|
108
|
-
router,
|
|
109
|
-
{
|
|
110
|
-
...debugOptions,
|
|
111
|
-
messageTypeId,
|
|
112
|
-
pbPayloadLength: pbPayload.length,
|
|
113
|
-
},
|
|
114
|
-
seq
|
|
115
|
-
);
|
|
89
|
+
return encodeFrame(payload, packetSrc, router, seq);
|
|
116
90
|
}
|