@hla4ts/session 0.1.0 → 0.1.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/README.md +377 -377
- package/package.json +3 -3
- package/src/errors.ts +98 -98
- package/src/index.ts +147 -147
- package/src/messages.ts +329 -329
- package/src/sequence-number.ts +200 -200
- package/src/session.ts +976 -976
- package/src/timeout-timer.ts +204 -204
- package/src/types.ts +235 -235
package/src/messages.ts
CHANGED
|
@@ -1,329 +1,329 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Message Encoding/Decoding
|
|
3
|
-
*
|
|
4
|
-
* Handles encoding and decoding of Federate Protocol session control messages.
|
|
5
|
-
* These are the messages used for session management (not HLA calls/callbacks).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
encodeMessage,
|
|
10
|
-
MessageType,
|
|
11
|
-
FEDERATE_PROTOCOL_VERSION,
|
|
12
|
-
NO_SESSION_ID,
|
|
13
|
-
type MessageHeader,
|
|
14
|
-
} from "@hla4ts/transport";
|
|
15
|
-
import {
|
|
16
|
-
INITIAL_SEQUENCE_NUMBER,
|
|
17
|
-
NO_SEQUENCE_NUMBER as SEQ_NO_SEQUENCE_NUMBER,
|
|
18
|
-
} from "./sequence-number.ts";
|
|
19
|
-
|
|
20
|
-
// Size of a 32-bit integer in bytes
|
|
21
|
-
const INT32_SIZE = 4;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Create a CTRL_NEW_SESSION message to initiate a new session.
|
|
25
|
-
*
|
|
26
|
-
* Payload format:
|
|
27
|
-
* - protocolVersion (4 bytes, big-endian)
|
|
28
|
-
*
|
|
29
|
-
* @returns Encoded message ready to send
|
|
30
|
-
*/
|
|
31
|
-
export function createNewSessionMessage(): Uint8Array {
|
|
32
|
-
const payload = new Uint8Array(INT32_SIZE);
|
|
33
|
-
const view = new DataView(payload.buffer);
|
|
34
|
-
view.setUint32(0, FEDERATE_PROTOCOL_VERSION, false); // big-endian
|
|
35
|
-
|
|
36
|
-
return encodeMessage(
|
|
37
|
-
INITIAL_SEQUENCE_NUMBER,
|
|
38
|
-
NO_SESSION_ID,
|
|
39
|
-
SEQ_NO_SEQUENCE_NUMBER,
|
|
40
|
-
MessageType.CTRL_NEW_SESSION,
|
|
41
|
-
payload
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Decode a CTRL_NEW_SESSION_STATUS response.
|
|
47
|
-
*
|
|
48
|
-
* Payload format:
|
|
49
|
-
* - reason (4 bytes, big-endian) - 0 = success
|
|
50
|
-
*
|
|
51
|
-
* @param payload - The message payload
|
|
52
|
-
* @returns Status code (0 = success)
|
|
53
|
-
*/
|
|
54
|
-
export function decodeNewSessionStatus(payload: Uint8Array): number {
|
|
55
|
-
if (payload.length < INT32_SIZE) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
`NewSessionStatus payload too small: ${payload.length} bytes`
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
61
|
-
return view.getUint32(0, false); // big-endian
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Create a CTRL_RESUME_REQUEST message to resume a dropped session.
|
|
66
|
-
*
|
|
67
|
-
* Payload format:
|
|
68
|
-
* - lastReceivedSequenceNumber (4 bytes, big-endian)
|
|
69
|
-
* - oldestAvailableSequenceNumber (4 bytes, big-endian)
|
|
70
|
-
*
|
|
71
|
-
* @param sessionId - The session ID to resume
|
|
72
|
-
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
73
|
-
* @param oldestAvailableSequenceNumber - Oldest message still available for retransmission
|
|
74
|
-
* @returns Encoded message ready to send
|
|
75
|
-
*/
|
|
76
|
-
export function createResumeRequestMessage(
|
|
77
|
-
sessionId: bigint,
|
|
78
|
-
lastReceivedSequenceNumber: number,
|
|
79
|
-
oldestAvailableSequenceNumber: number
|
|
80
|
-
): Uint8Array {
|
|
81
|
-
const payload = new Uint8Array(INT32_SIZE * 2);
|
|
82
|
-
const view = new DataView(payload.buffer);
|
|
83
|
-
view.setUint32(0, lastReceivedSequenceNumber, false);
|
|
84
|
-
view.setUint32(4, oldestAvailableSequenceNumber, false);
|
|
85
|
-
|
|
86
|
-
return encodeMessage(
|
|
87
|
-
SEQ_NO_SEQUENCE_NUMBER,
|
|
88
|
-
sessionId,
|
|
89
|
-
lastReceivedSequenceNumber,
|
|
90
|
-
MessageType.CTRL_RESUME_REQUEST,
|
|
91
|
-
payload
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Decoded resume status response
|
|
97
|
-
*/
|
|
98
|
-
export interface ResumeStatusResult {
|
|
99
|
-
/** Status code (0 = success) */
|
|
100
|
-
status: number;
|
|
101
|
-
/** Last sequence number the server received from us */
|
|
102
|
-
lastReceivedFederateSequenceNumber: number;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Resume status codes
|
|
107
|
-
*/
|
|
108
|
-
export const ResumeStatusCode = {
|
|
109
|
-
/** Resume successful */
|
|
110
|
-
OK_TO_RESUME: 0,
|
|
111
|
-
/** Session not found (expired or invalid) */
|
|
112
|
-
SESSION_NOT_FOUND: 1,
|
|
113
|
-
/** Resume not allowed */
|
|
114
|
-
NOT_ALLOWED: 2,
|
|
115
|
-
} as const;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Decode a CTRL_RESUME_STATUS response.
|
|
119
|
-
*
|
|
120
|
-
* Payload format:
|
|
121
|
-
* - status (4 bytes, big-endian)
|
|
122
|
-
* - lastReceivedFederateSequenceNumber (4 bytes, big-endian)
|
|
123
|
-
*
|
|
124
|
-
* @param payload - The message payload
|
|
125
|
-
* @returns Decoded resume status
|
|
126
|
-
*/
|
|
127
|
-
export function decodeResumeStatus(payload: Uint8Array): ResumeStatusResult {
|
|
128
|
-
if (payload.length < INT32_SIZE * 2) {
|
|
129
|
-
throw new Error(`ResumeStatus payload too small: ${payload.length} bytes`);
|
|
130
|
-
}
|
|
131
|
-
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
132
|
-
return {
|
|
133
|
-
status: view.getUint32(0, false),
|
|
134
|
-
lastReceivedFederateSequenceNumber: view.getUint32(4, false),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Create a CTRL_HEARTBEAT message.
|
|
140
|
-
*
|
|
141
|
-
* No payload - the header contains all necessary information.
|
|
142
|
-
*
|
|
143
|
-
* @param sequenceNumber - Sequence number for this heartbeat
|
|
144
|
-
* @param sessionId - Current session ID
|
|
145
|
-
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
146
|
-
* @returns Encoded message ready to send
|
|
147
|
-
*/
|
|
148
|
-
export function createHeartbeatMessage(
|
|
149
|
-
sequenceNumber: number,
|
|
150
|
-
sessionId: bigint,
|
|
151
|
-
lastReceivedSequenceNumber: number
|
|
152
|
-
): Uint8Array {
|
|
153
|
-
return encodeMessage(
|
|
154
|
-
sequenceNumber,
|
|
155
|
-
sessionId,
|
|
156
|
-
lastReceivedSequenceNumber,
|
|
157
|
-
MessageType.CTRL_HEARTBEAT
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Decode a CTRL_HEARTBEAT_RESPONSE.
|
|
163
|
-
*
|
|
164
|
-
* Payload format:
|
|
165
|
-
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
166
|
-
*
|
|
167
|
-
* @param payload - The message payload
|
|
168
|
-
* @returns The sequence number this is a response to
|
|
169
|
-
*/
|
|
170
|
-
export function decodeHeartbeatResponse(payload: Uint8Array): number {
|
|
171
|
-
if (payload.length < INT32_SIZE) {
|
|
172
|
-
throw new Error(
|
|
173
|
-
`HeartbeatResponse payload too small: ${payload.length} bytes`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
177
|
-
return view.getUint32(0, false);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Create a CTRL_TERMINATE_SESSION message.
|
|
182
|
-
*
|
|
183
|
-
* No payload.
|
|
184
|
-
*
|
|
185
|
-
* @param sequenceNumber - Sequence number for this message
|
|
186
|
-
* @param sessionId - Current session ID
|
|
187
|
-
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
188
|
-
* @returns Encoded message ready to send
|
|
189
|
-
*/
|
|
190
|
-
export function createTerminateSessionMessage(
|
|
191
|
-
sequenceNumber: number,
|
|
192
|
-
sessionId: bigint,
|
|
193
|
-
lastReceivedSequenceNumber: number
|
|
194
|
-
): Uint8Array {
|
|
195
|
-
return encodeMessage(
|
|
196
|
-
sequenceNumber,
|
|
197
|
-
sessionId,
|
|
198
|
-
lastReceivedSequenceNumber,
|
|
199
|
-
MessageType.CTRL_TERMINATE_SESSION
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create an HLA_CALL_REQUEST message.
|
|
205
|
-
*
|
|
206
|
-
* Payload format:
|
|
207
|
-
* - hlaServiceCallWithParams (variable, protobuf-encoded CallRequest)
|
|
208
|
-
*
|
|
209
|
-
* @param sequenceNumber - Sequence number for this message
|
|
210
|
-
* @param sessionId - Current session ID
|
|
211
|
-
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
212
|
-
* @param hlaCallPayload - Protobuf-encoded HLA call request
|
|
213
|
-
* @returns Encoded message ready to send
|
|
214
|
-
*/
|
|
215
|
-
export function createHlaCallRequestMessage(
|
|
216
|
-
sequenceNumber: number,
|
|
217
|
-
sessionId: bigint,
|
|
218
|
-
lastReceivedSequenceNumber: number,
|
|
219
|
-
hlaCallPayload: Uint8Array
|
|
220
|
-
): Uint8Array {
|
|
221
|
-
return encodeMessage(
|
|
222
|
-
sequenceNumber,
|
|
223
|
-
sessionId,
|
|
224
|
-
lastReceivedSequenceNumber,
|
|
225
|
-
MessageType.HLA_CALL_REQUEST,
|
|
226
|
-
hlaCallPayload
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Decoded HLA call response
|
|
232
|
-
*/
|
|
233
|
-
export interface HlaCallResponseResult {
|
|
234
|
-
/** Sequence number this is a response to */
|
|
235
|
-
responseToSequenceNumber: number;
|
|
236
|
-
/** The HLA response payload (protobuf-encoded CallResponse) */
|
|
237
|
-
hlaServiceReturnValueOrException: Uint8Array;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Decode an HLA_CALL_RESPONSE message.
|
|
242
|
-
*
|
|
243
|
-
* Payload format:
|
|
244
|
-
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
245
|
-
* - hlaServiceReturnValueOrException (remaining bytes)
|
|
246
|
-
*
|
|
247
|
-
* @param payload - The message payload
|
|
248
|
-
* @returns Decoded HLA call response
|
|
249
|
-
*/
|
|
250
|
-
export function decodeHlaCallResponse(payload: Uint8Array): HlaCallResponseResult {
|
|
251
|
-
if (payload.length < INT32_SIZE) {
|
|
252
|
-
throw new Error(
|
|
253
|
-
`HlaCallResponse payload too small: ${payload.length} bytes`
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
257
|
-
const responseToSequenceNumber = view.getUint32(0, false);
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
responseToSequenceNumber,
|
|
261
|
-
hlaServiceReturnValueOrException: payload.slice(INT32_SIZE),
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Decoded HLA callback request
|
|
267
|
-
*/
|
|
268
|
-
export interface HlaCallbackRequestResult {
|
|
269
|
-
/** The HLA callback payload (protobuf-encoded CallbackRequest) */
|
|
270
|
-
hlaServiceCallbackWithParams: Uint8Array;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Decode an HLA_CALLBACK_REQUEST message.
|
|
275
|
-
*
|
|
276
|
-
* Payload format:
|
|
277
|
-
* - hlaServiceCallbackWithParams (all bytes, protobuf-encoded CallbackRequest)
|
|
278
|
-
*
|
|
279
|
-
* @param payload - The message payload
|
|
280
|
-
* @returns Decoded HLA callback request
|
|
281
|
-
*/
|
|
282
|
-
export function decodeHlaCallbackRequest(payload: Uint8Array): HlaCallbackRequestResult {
|
|
283
|
-
return {
|
|
284
|
-
hlaServiceCallbackWithParams: payload,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Create an HLA_CALLBACK_RESPONSE message.
|
|
290
|
-
*
|
|
291
|
-
* Payload format:
|
|
292
|
-
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
293
|
-
* - hlaCallbackResponse (remaining bytes, protobuf-encoded CallbackResponse)
|
|
294
|
-
*
|
|
295
|
-
* @param sequenceNumber - Sequence number for this message
|
|
296
|
-
* @param sessionId - Current session ID
|
|
297
|
-
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
298
|
-
* @param responseToSequenceNumber - Sequence number of the callback request
|
|
299
|
-
* @param hlaCallbackResponse - Protobuf-encoded callback response
|
|
300
|
-
* @returns Encoded message ready to send
|
|
301
|
-
*/
|
|
302
|
-
export function createHlaCallbackResponseMessage(
|
|
303
|
-
sequenceNumber: number,
|
|
304
|
-
sessionId: bigint,
|
|
305
|
-
lastReceivedSequenceNumber: number,
|
|
306
|
-
responseToSequenceNumber: number,
|
|
307
|
-
hlaCallbackResponse: Uint8Array
|
|
308
|
-
): Uint8Array {
|
|
309
|
-
const payloadSize = INT32_SIZE + hlaCallbackResponse.length;
|
|
310
|
-
const payload = new Uint8Array(payloadSize);
|
|
311
|
-
const view = new DataView(payload.buffer);
|
|
312
|
-
view.setUint32(0, responseToSequenceNumber, false);
|
|
313
|
-
payload.set(hlaCallbackResponse, INT32_SIZE);
|
|
314
|
-
|
|
315
|
-
return encodeMessage(
|
|
316
|
-
sequenceNumber,
|
|
317
|
-
sessionId,
|
|
318
|
-
lastReceivedSequenceNumber,
|
|
319
|
-
MessageType.HLA_CALLBACK_RESPONSE,
|
|
320
|
-
payload
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Get a human-readable description of a message header
|
|
326
|
-
*/
|
|
327
|
-
export function describeHeader(header: MessageHeader): string {
|
|
328
|
-
return `[seq=${header.sequenceNumber}, session=${header.sessionId}, lastRecv=${header.lastReceivedSequenceNumber}, type=${MessageType[header.messageType] ?? header.messageType}]`;
|
|
329
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Session Message Encoding/Decoding
|
|
3
|
+
*
|
|
4
|
+
* Handles encoding and decoding of Federate Protocol session control messages.
|
|
5
|
+
* These are the messages used for session management (not HLA calls/callbacks).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
encodeMessage,
|
|
10
|
+
MessageType,
|
|
11
|
+
FEDERATE_PROTOCOL_VERSION,
|
|
12
|
+
NO_SESSION_ID,
|
|
13
|
+
type MessageHeader,
|
|
14
|
+
} from "@hla4ts/transport";
|
|
15
|
+
import {
|
|
16
|
+
INITIAL_SEQUENCE_NUMBER,
|
|
17
|
+
NO_SEQUENCE_NUMBER as SEQ_NO_SEQUENCE_NUMBER,
|
|
18
|
+
} from "./sequence-number.ts";
|
|
19
|
+
|
|
20
|
+
// Size of a 32-bit integer in bytes
|
|
21
|
+
const INT32_SIZE = 4;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a CTRL_NEW_SESSION message to initiate a new session.
|
|
25
|
+
*
|
|
26
|
+
* Payload format:
|
|
27
|
+
* - protocolVersion (4 bytes, big-endian)
|
|
28
|
+
*
|
|
29
|
+
* @returns Encoded message ready to send
|
|
30
|
+
*/
|
|
31
|
+
export function createNewSessionMessage(): Uint8Array {
|
|
32
|
+
const payload = new Uint8Array(INT32_SIZE);
|
|
33
|
+
const view = new DataView(payload.buffer);
|
|
34
|
+
view.setUint32(0, FEDERATE_PROTOCOL_VERSION, false); // big-endian
|
|
35
|
+
|
|
36
|
+
return encodeMessage(
|
|
37
|
+
INITIAL_SEQUENCE_NUMBER,
|
|
38
|
+
NO_SESSION_ID,
|
|
39
|
+
SEQ_NO_SEQUENCE_NUMBER,
|
|
40
|
+
MessageType.CTRL_NEW_SESSION,
|
|
41
|
+
payload
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Decode a CTRL_NEW_SESSION_STATUS response.
|
|
47
|
+
*
|
|
48
|
+
* Payload format:
|
|
49
|
+
* - reason (4 bytes, big-endian) - 0 = success
|
|
50
|
+
*
|
|
51
|
+
* @param payload - The message payload
|
|
52
|
+
* @returns Status code (0 = success)
|
|
53
|
+
*/
|
|
54
|
+
export function decodeNewSessionStatus(payload: Uint8Array): number {
|
|
55
|
+
if (payload.length < INT32_SIZE) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`NewSessionStatus payload too small: ${payload.length} bytes`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
61
|
+
return view.getUint32(0, false); // big-endian
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a CTRL_RESUME_REQUEST message to resume a dropped session.
|
|
66
|
+
*
|
|
67
|
+
* Payload format:
|
|
68
|
+
* - lastReceivedSequenceNumber (4 bytes, big-endian)
|
|
69
|
+
* - oldestAvailableSequenceNumber (4 bytes, big-endian)
|
|
70
|
+
*
|
|
71
|
+
* @param sessionId - The session ID to resume
|
|
72
|
+
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
73
|
+
* @param oldestAvailableSequenceNumber - Oldest message still available for retransmission
|
|
74
|
+
* @returns Encoded message ready to send
|
|
75
|
+
*/
|
|
76
|
+
export function createResumeRequestMessage(
|
|
77
|
+
sessionId: bigint,
|
|
78
|
+
lastReceivedSequenceNumber: number,
|
|
79
|
+
oldestAvailableSequenceNumber: number
|
|
80
|
+
): Uint8Array {
|
|
81
|
+
const payload = new Uint8Array(INT32_SIZE * 2);
|
|
82
|
+
const view = new DataView(payload.buffer);
|
|
83
|
+
view.setUint32(0, lastReceivedSequenceNumber, false);
|
|
84
|
+
view.setUint32(4, oldestAvailableSequenceNumber, false);
|
|
85
|
+
|
|
86
|
+
return encodeMessage(
|
|
87
|
+
SEQ_NO_SEQUENCE_NUMBER,
|
|
88
|
+
sessionId,
|
|
89
|
+
lastReceivedSequenceNumber,
|
|
90
|
+
MessageType.CTRL_RESUME_REQUEST,
|
|
91
|
+
payload
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Decoded resume status response
|
|
97
|
+
*/
|
|
98
|
+
export interface ResumeStatusResult {
|
|
99
|
+
/** Status code (0 = success) */
|
|
100
|
+
status: number;
|
|
101
|
+
/** Last sequence number the server received from us */
|
|
102
|
+
lastReceivedFederateSequenceNumber: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resume status codes
|
|
107
|
+
*/
|
|
108
|
+
export const ResumeStatusCode = {
|
|
109
|
+
/** Resume successful */
|
|
110
|
+
OK_TO_RESUME: 0,
|
|
111
|
+
/** Session not found (expired or invalid) */
|
|
112
|
+
SESSION_NOT_FOUND: 1,
|
|
113
|
+
/** Resume not allowed */
|
|
114
|
+
NOT_ALLOWED: 2,
|
|
115
|
+
} as const;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Decode a CTRL_RESUME_STATUS response.
|
|
119
|
+
*
|
|
120
|
+
* Payload format:
|
|
121
|
+
* - status (4 bytes, big-endian)
|
|
122
|
+
* - lastReceivedFederateSequenceNumber (4 bytes, big-endian)
|
|
123
|
+
*
|
|
124
|
+
* @param payload - The message payload
|
|
125
|
+
* @returns Decoded resume status
|
|
126
|
+
*/
|
|
127
|
+
export function decodeResumeStatus(payload: Uint8Array): ResumeStatusResult {
|
|
128
|
+
if (payload.length < INT32_SIZE * 2) {
|
|
129
|
+
throw new Error(`ResumeStatus payload too small: ${payload.length} bytes`);
|
|
130
|
+
}
|
|
131
|
+
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
132
|
+
return {
|
|
133
|
+
status: view.getUint32(0, false),
|
|
134
|
+
lastReceivedFederateSequenceNumber: view.getUint32(4, false),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Create a CTRL_HEARTBEAT message.
|
|
140
|
+
*
|
|
141
|
+
* No payload - the header contains all necessary information.
|
|
142
|
+
*
|
|
143
|
+
* @param sequenceNumber - Sequence number for this heartbeat
|
|
144
|
+
* @param sessionId - Current session ID
|
|
145
|
+
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
146
|
+
* @returns Encoded message ready to send
|
|
147
|
+
*/
|
|
148
|
+
export function createHeartbeatMessage(
|
|
149
|
+
sequenceNumber: number,
|
|
150
|
+
sessionId: bigint,
|
|
151
|
+
lastReceivedSequenceNumber: number
|
|
152
|
+
): Uint8Array {
|
|
153
|
+
return encodeMessage(
|
|
154
|
+
sequenceNumber,
|
|
155
|
+
sessionId,
|
|
156
|
+
lastReceivedSequenceNumber,
|
|
157
|
+
MessageType.CTRL_HEARTBEAT
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Decode a CTRL_HEARTBEAT_RESPONSE.
|
|
163
|
+
*
|
|
164
|
+
* Payload format:
|
|
165
|
+
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
166
|
+
*
|
|
167
|
+
* @param payload - The message payload
|
|
168
|
+
* @returns The sequence number this is a response to
|
|
169
|
+
*/
|
|
170
|
+
export function decodeHeartbeatResponse(payload: Uint8Array): number {
|
|
171
|
+
if (payload.length < INT32_SIZE) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`HeartbeatResponse payload too small: ${payload.length} bytes`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
177
|
+
return view.getUint32(0, false);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Create a CTRL_TERMINATE_SESSION message.
|
|
182
|
+
*
|
|
183
|
+
* No payload.
|
|
184
|
+
*
|
|
185
|
+
* @param sequenceNumber - Sequence number for this message
|
|
186
|
+
* @param sessionId - Current session ID
|
|
187
|
+
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
188
|
+
* @returns Encoded message ready to send
|
|
189
|
+
*/
|
|
190
|
+
export function createTerminateSessionMessage(
|
|
191
|
+
sequenceNumber: number,
|
|
192
|
+
sessionId: bigint,
|
|
193
|
+
lastReceivedSequenceNumber: number
|
|
194
|
+
): Uint8Array {
|
|
195
|
+
return encodeMessage(
|
|
196
|
+
sequenceNumber,
|
|
197
|
+
sessionId,
|
|
198
|
+
lastReceivedSequenceNumber,
|
|
199
|
+
MessageType.CTRL_TERMINATE_SESSION
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Create an HLA_CALL_REQUEST message.
|
|
205
|
+
*
|
|
206
|
+
* Payload format:
|
|
207
|
+
* - hlaServiceCallWithParams (variable, protobuf-encoded CallRequest)
|
|
208
|
+
*
|
|
209
|
+
* @param sequenceNumber - Sequence number for this message
|
|
210
|
+
* @param sessionId - Current session ID
|
|
211
|
+
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
212
|
+
* @param hlaCallPayload - Protobuf-encoded HLA call request
|
|
213
|
+
* @returns Encoded message ready to send
|
|
214
|
+
*/
|
|
215
|
+
export function createHlaCallRequestMessage(
|
|
216
|
+
sequenceNumber: number,
|
|
217
|
+
sessionId: bigint,
|
|
218
|
+
lastReceivedSequenceNumber: number,
|
|
219
|
+
hlaCallPayload: Uint8Array
|
|
220
|
+
): Uint8Array {
|
|
221
|
+
return encodeMessage(
|
|
222
|
+
sequenceNumber,
|
|
223
|
+
sessionId,
|
|
224
|
+
lastReceivedSequenceNumber,
|
|
225
|
+
MessageType.HLA_CALL_REQUEST,
|
|
226
|
+
hlaCallPayload
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Decoded HLA call response
|
|
232
|
+
*/
|
|
233
|
+
export interface HlaCallResponseResult {
|
|
234
|
+
/** Sequence number this is a response to */
|
|
235
|
+
responseToSequenceNumber: number;
|
|
236
|
+
/** The HLA response payload (protobuf-encoded CallResponse) */
|
|
237
|
+
hlaServiceReturnValueOrException: Uint8Array;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Decode an HLA_CALL_RESPONSE message.
|
|
242
|
+
*
|
|
243
|
+
* Payload format:
|
|
244
|
+
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
245
|
+
* - hlaServiceReturnValueOrException (remaining bytes)
|
|
246
|
+
*
|
|
247
|
+
* @param payload - The message payload
|
|
248
|
+
* @returns Decoded HLA call response
|
|
249
|
+
*/
|
|
250
|
+
export function decodeHlaCallResponse(payload: Uint8Array): HlaCallResponseResult {
|
|
251
|
+
if (payload.length < INT32_SIZE) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
`HlaCallResponse payload too small: ${payload.length} bytes`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
const view = new DataView(payload.buffer, payload.byteOffset);
|
|
257
|
+
const responseToSequenceNumber = view.getUint32(0, false);
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
responseToSequenceNumber,
|
|
261
|
+
hlaServiceReturnValueOrException: payload.slice(INT32_SIZE),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Decoded HLA callback request
|
|
267
|
+
*/
|
|
268
|
+
export interface HlaCallbackRequestResult {
|
|
269
|
+
/** The HLA callback payload (protobuf-encoded CallbackRequest) */
|
|
270
|
+
hlaServiceCallbackWithParams: Uint8Array;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Decode an HLA_CALLBACK_REQUEST message.
|
|
275
|
+
*
|
|
276
|
+
* Payload format:
|
|
277
|
+
* - hlaServiceCallbackWithParams (all bytes, protobuf-encoded CallbackRequest)
|
|
278
|
+
*
|
|
279
|
+
* @param payload - The message payload
|
|
280
|
+
* @returns Decoded HLA callback request
|
|
281
|
+
*/
|
|
282
|
+
export function decodeHlaCallbackRequest(payload: Uint8Array): HlaCallbackRequestResult {
|
|
283
|
+
return {
|
|
284
|
+
hlaServiceCallbackWithParams: payload,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Create an HLA_CALLBACK_RESPONSE message.
|
|
290
|
+
*
|
|
291
|
+
* Payload format:
|
|
292
|
+
* - responseToSequenceNumber (4 bytes, big-endian)
|
|
293
|
+
* - hlaCallbackResponse (remaining bytes, protobuf-encoded CallbackResponse)
|
|
294
|
+
*
|
|
295
|
+
* @param sequenceNumber - Sequence number for this message
|
|
296
|
+
* @param sessionId - Current session ID
|
|
297
|
+
* @param lastReceivedSequenceNumber - Last sequence number received from RTI
|
|
298
|
+
* @param responseToSequenceNumber - Sequence number of the callback request
|
|
299
|
+
* @param hlaCallbackResponse - Protobuf-encoded callback response
|
|
300
|
+
* @returns Encoded message ready to send
|
|
301
|
+
*/
|
|
302
|
+
export function createHlaCallbackResponseMessage(
|
|
303
|
+
sequenceNumber: number,
|
|
304
|
+
sessionId: bigint,
|
|
305
|
+
lastReceivedSequenceNumber: number,
|
|
306
|
+
responseToSequenceNumber: number,
|
|
307
|
+
hlaCallbackResponse: Uint8Array
|
|
308
|
+
): Uint8Array {
|
|
309
|
+
const payloadSize = INT32_SIZE + hlaCallbackResponse.length;
|
|
310
|
+
const payload = new Uint8Array(payloadSize);
|
|
311
|
+
const view = new DataView(payload.buffer);
|
|
312
|
+
view.setUint32(0, responseToSequenceNumber, false);
|
|
313
|
+
payload.set(hlaCallbackResponse, INT32_SIZE);
|
|
314
|
+
|
|
315
|
+
return encodeMessage(
|
|
316
|
+
sequenceNumber,
|
|
317
|
+
sessionId,
|
|
318
|
+
lastReceivedSequenceNumber,
|
|
319
|
+
MessageType.HLA_CALLBACK_RESPONSE,
|
|
320
|
+
payload
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get a human-readable description of a message header
|
|
326
|
+
*/
|
|
327
|
+
export function describeHeader(header: MessageHeader): string {
|
|
328
|
+
return `[seq=${header.sequenceNumber}, session=${header.sessionId}, lastRecv=${header.lastReceivedSequenceNumber}, type=${MessageType[header.messageType] ?? header.messageType}]`;
|
|
329
|
+
}
|