@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/types.ts
CHANGED
|
@@ -1,235 +1,235 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Types and State Machine
|
|
3
|
-
*
|
|
4
|
-
* Defines the session state machine, options, and event types for
|
|
5
|
-
* the HLA 4 Federate Protocol session layer.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Session states following the IEEE 1516-2025 specification.
|
|
10
|
-
*
|
|
11
|
-
* States can be divided into two categories:
|
|
12
|
-
* - **Stable states**: NEW, RUNNING, DROPPED, TERMINATED
|
|
13
|
-
* - **Transitory states**: STARTING, RESUMING, TERMINATING
|
|
14
|
-
*
|
|
15
|
-
* When in a transitory state, the thread that initiated the transition
|
|
16
|
-
* has exclusive access to the session.
|
|
17
|
-
*/
|
|
18
|
-
export enum SessionState {
|
|
19
|
-
/**
|
|
20
|
-
* Session instance created but not yet started.
|
|
21
|
-
* Initial state after construction.
|
|
22
|
-
*/
|
|
23
|
-
NEW = "NEW",
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Session start() has been called, establishing connection with RTI.
|
|
27
|
-
* Transitory state - caller has exclusive access.
|
|
28
|
-
*/
|
|
29
|
-
STARTING = "STARTING",
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Session is connected and running normally.
|
|
33
|
-
* HLA calls and callbacks can be exchanged.
|
|
34
|
-
*/
|
|
35
|
-
RUNNING = "RUNNING",
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Session has experienced a connection loss.
|
|
39
|
-
* Can be resumed with resume() or terminated.
|
|
40
|
-
*/
|
|
41
|
-
DROPPED = "DROPPED",
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Session is attempting to resume after a connection loss.
|
|
45
|
-
* Transitory state - caller has exclusive access.
|
|
46
|
-
*/
|
|
47
|
-
RESUMING = "RESUMING",
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Session termination has been requested.
|
|
51
|
-
* Waiting for server acknowledgment.
|
|
52
|
-
*/
|
|
53
|
-
TERMINATING = "TERMINATING",
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Session is terminated and can no longer be used.
|
|
57
|
-
* Final state - session cannot be restarted.
|
|
58
|
-
*/
|
|
59
|
-
TERMINATED = "TERMINATED",
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Valid state transitions for the session state machine.
|
|
64
|
-
* Maps from current state to array of valid next states.
|
|
65
|
-
*/
|
|
66
|
-
export const VALID_TRANSITIONS: Record<SessionState, SessionState[]> = {
|
|
67
|
-
[SessionState.NEW]: [SessionState.STARTING],
|
|
68
|
-
[SessionState.STARTING]: [SessionState.RUNNING, SessionState.TERMINATED],
|
|
69
|
-
[SessionState.RUNNING]: [SessionState.DROPPED, SessionState.TERMINATING],
|
|
70
|
-
[SessionState.DROPPED]: [
|
|
71
|
-
SessionState.RESUMING,
|
|
72
|
-
SessionState.TERMINATING,
|
|
73
|
-
SessionState.RUNNING, // Direct transition when resume succeeds quickly
|
|
74
|
-
],
|
|
75
|
-
[SessionState.RESUMING]: [
|
|
76
|
-
SessionState.RUNNING,
|
|
77
|
-
SessionState.DROPPED,
|
|
78
|
-
SessionState.TERMINATED,
|
|
79
|
-
],
|
|
80
|
-
[SessionState.TERMINATING]: [SessionState.TERMINATED],
|
|
81
|
-
[SessionState.TERMINATED]: [], // Terminal state
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Check if a state transition is valid
|
|
86
|
-
*/
|
|
87
|
-
export function isValidTransition(
|
|
88
|
-
from: SessionState,
|
|
89
|
-
to: SessionState
|
|
90
|
-
): boolean {
|
|
91
|
-
return VALID_TRANSITIONS[from].includes(to);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Check if a state allows operations (sending messages)
|
|
96
|
-
*/
|
|
97
|
-
export function isOperationalState(state: SessionState): boolean {
|
|
98
|
-
return (
|
|
99
|
-
state === SessionState.RUNNING ||
|
|
100
|
-
state === SessionState.DROPPED ||
|
|
101
|
-
state === SessionState.RESUMING
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Session configuration options
|
|
107
|
-
*/
|
|
108
|
-
export interface SessionOptions {
|
|
109
|
-
/**
|
|
110
|
-
* Timeout for initial connection response (milliseconds).
|
|
111
|
-
* @default 30000
|
|
112
|
-
*/
|
|
113
|
-
connectionTimeout?: number;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Timeout for responses from the server (milliseconds).
|
|
117
|
-
* The session will be considered lost if no response is received within this time.
|
|
118
|
-
* @default 180000 (3 minutes)
|
|
119
|
-
*/
|
|
120
|
-
responseTimeout?: number;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Maximum number of connection retry attempts.
|
|
124
|
-
* @default 3
|
|
125
|
-
*/
|
|
126
|
-
maxRetryAttempts?: number;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Size of the message queue for outgoing messages.
|
|
130
|
-
* @default 1000
|
|
131
|
-
*/
|
|
132
|
-
messageQueueSize?: number;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Enable rate limiting for outgoing messages.
|
|
136
|
-
* @default false
|
|
137
|
-
*/
|
|
138
|
-
rateLimitEnabled?: boolean;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Interval between heartbeat checks (milliseconds).
|
|
142
|
-
* @default 10000 (10 seconds)
|
|
143
|
-
*/
|
|
144
|
-
heartbeatInterval?: number;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Default session options
|
|
149
|
-
*/
|
|
150
|
-
export const DEFAULT_SESSION_OPTIONS: Required<SessionOptions> = {
|
|
151
|
-
connectionTimeout: 30000,
|
|
152
|
-
responseTimeout: 180000,
|
|
153
|
-
maxRetryAttempts: 3,
|
|
154
|
-
messageQueueSize: 1000,
|
|
155
|
-
rateLimitEnabled: false,
|
|
156
|
-
heartbeatInterval: 10000,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Callback invoked when an HLA callback request is received from the RTI
|
|
161
|
-
*/
|
|
162
|
-
export interface HlaCallbackRequestListener {
|
|
163
|
-
/**
|
|
164
|
-
* Handle an incoming HLA callback from the RTI.
|
|
165
|
-
*
|
|
166
|
-
* @param sequenceNumber - The sequence number of the callback request
|
|
167
|
-
* @param hlaCallback - The encoded callback data (protobuf CallbackRequest)
|
|
168
|
-
*/
|
|
169
|
-
onHlaCallbackRequest(sequenceNumber: number, hlaCallback: Uint8Array): void;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Callback invoked when the session state changes
|
|
174
|
-
*/
|
|
175
|
-
export interface SessionStateListener {
|
|
176
|
-
/**
|
|
177
|
-
* Handle a session state transition.
|
|
178
|
-
*
|
|
179
|
-
* @param oldState - The previous session state
|
|
180
|
-
* @param newState - The new session state
|
|
181
|
-
* @param reason - Description of why the transition occurred
|
|
182
|
-
*/
|
|
183
|
-
onStateTransition(
|
|
184
|
-
oldState: SessionState,
|
|
185
|
-
newState: SessionState,
|
|
186
|
-
reason: string
|
|
187
|
-
): void;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Callback invoked when a message is sent
|
|
192
|
-
*/
|
|
193
|
-
export interface MessageSentListener {
|
|
194
|
-
/**
|
|
195
|
-
* Called when a message has been sent to the server.
|
|
196
|
-
* Can be used to implement heartbeat logic.
|
|
197
|
-
*/
|
|
198
|
-
onMessageSent(): void;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Session statistics
|
|
203
|
-
*/
|
|
204
|
-
export interface SessionStats {
|
|
205
|
-
/** Total HLA calls sent */
|
|
206
|
-
hlaCallCount: number;
|
|
207
|
-
/** Total HLA callbacks received */
|
|
208
|
-
hlaCallbackCount: number;
|
|
209
|
-
/** Number of times the session was resumed */
|
|
210
|
-
resumeCount: number;
|
|
211
|
-
/** Number of messages in the call request queue */
|
|
212
|
-
callRequestQueueLength: number;
|
|
213
|
-
/** Number of messages in the callback response queue */
|
|
214
|
-
callbackResponseQueueLength: number;
|
|
215
|
-
/** Number of HLA calls awaiting response */
|
|
216
|
-
pendingRequestCount: number;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* New session status message payload structure
|
|
221
|
-
*/
|
|
222
|
-
export interface NewSessionStatusPayload {
|
|
223
|
-
/** Status code (0 = success) */
|
|
224
|
-
status: number;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Resume status message payload structure
|
|
229
|
-
*/
|
|
230
|
-
export interface ResumeStatusPayload {
|
|
231
|
-
/** Status code (0 = success) */
|
|
232
|
-
status: number;
|
|
233
|
-
/** Last sequence number received by the server */
|
|
234
|
-
lastReceivedFederateSequenceNumber: number;
|
|
235
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Session Types and State Machine
|
|
3
|
+
*
|
|
4
|
+
* Defines the session state machine, options, and event types for
|
|
5
|
+
* the HLA 4 Federate Protocol session layer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Session states following the IEEE 1516-2025 specification.
|
|
10
|
+
*
|
|
11
|
+
* States can be divided into two categories:
|
|
12
|
+
* - **Stable states**: NEW, RUNNING, DROPPED, TERMINATED
|
|
13
|
+
* - **Transitory states**: STARTING, RESUMING, TERMINATING
|
|
14
|
+
*
|
|
15
|
+
* When in a transitory state, the thread that initiated the transition
|
|
16
|
+
* has exclusive access to the session.
|
|
17
|
+
*/
|
|
18
|
+
export enum SessionState {
|
|
19
|
+
/**
|
|
20
|
+
* Session instance created but not yet started.
|
|
21
|
+
* Initial state after construction.
|
|
22
|
+
*/
|
|
23
|
+
NEW = "NEW",
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Session start() has been called, establishing connection with RTI.
|
|
27
|
+
* Transitory state - caller has exclusive access.
|
|
28
|
+
*/
|
|
29
|
+
STARTING = "STARTING",
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Session is connected and running normally.
|
|
33
|
+
* HLA calls and callbacks can be exchanged.
|
|
34
|
+
*/
|
|
35
|
+
RUNNING = "RUNNING",
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Session has experienced a connection loss.
|
|
39
|
+
* Can be resumed with resume() or terminated.
|
|
40
|
+
*/
|
|
41
|
+
DROPPED = "DROPPED",
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Session is attempting to resume after a connection loss.
|
|
45
|
+
* Transitory state - caller has exclusive access.
|
|
46
|
+
*/
|
|
47
|
+
RESUMING = "RESUMING",
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Session termination has been requested.
|
|
51
|
+
* Waiting for server acknowledgment.
|
|
52
|
+
*/
|
|
53
|
+
TERMINATING = "TERMINATING",
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Session is terminated and can no longer be used.
|
|
57
|
+
* Final state - session cannot be restarted.
|
|
58
|
+
*/
|
|
59
|
+
TERMINATED = "TERMINATED",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Valid state transitions for the session state machine.
|
|
64
|
+
* Maps from current state to array of valid next states.
|
|
65
|
+
*/
|
|
66
|
+
export const VALID_TRANSITIONS: Record<SessionState, SessionState[]> = {
|
|
67
|
+
[SessionState.NEW]: [SessionState.STARTING],
|
|
68
|
+
[SessionState.STARTING]: [SessionState.RUNNING, SessionState.TERMINATED],
|
|
69
|
+
[SessionState.RUNNING]: [SessionState.DROPPED, SessionState.TERMINATING],
|
|
70
|
+
[SessionState.DROPPED]: [
|
|
71
|
+
SessionState.RESUMING,
|
|
72
|
+
SessionState.TERMINATING,
|
|
73
|
+
SessionState.RUNNING, // Direct transition when resume succeeds quickly
|
|
74
|
+
],
|
|
75
|
+
[SessionState.RESUMING]: [
|
|
76
|
+
SessionState.RUNNING,
|
|
77
|
+
SessionState.DROPPED,
|
|
78
|
+
SessionState.TERMINATED,
|
|
79
|
+
],
|
|
80
|
+
[SessionState.TERMINATING]: [SessionState.TERMINATED],
|
|
81
|
+
[SessionState.TERMINATED]: [], // Terminal state
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check if a state transition is valid
|
|
86
|
+
*/
|
|
87
|
+
export function isValidTransition(
|
|
88
|
+
from: SessionState,
|
|
89
|
+
to: SessionState
|
|
90
|
+
): boolean {
|
|
91
|
+
return VALID_TRANSITIONS[from].includes(to);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if a state allows operations (sending messages)
|
|
96
|
+
*/
|
|
97
|
+
export function isOperationalState(state: SessionState): boolean {
|
|
98
|
+
return (
|
|
99
|
+
state === SessionState.RUNNING ||
|
|
100
|
+
state === SessionState.DROPPED ||
|
|
101
|
+
state === SessionState.RESUMING
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Session configuration options
|
|
107
|
+
*/
|
|
108
|
+
export interface SessionOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Timeout for initial connection response (milliseconds).
|
|
111
|
+
* @default 30000
|
|
112
|
+
*/
|
|
113
|
+
connectionTimeout?: number;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Timeout for responses from the server (milliseconds).
|
|
117
|
+
* The session will be considered lost if no response is received within this time.
|
|
118
|
+
* @default 180000 (3 minutes)
|
|
119
|
+
*/
|
|
120
|
+
responseTimeout?: number;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Maximum number of connection retry attempts.
|
|
124
|
+
* @default 3
|
|
125
|
+
*/
|
|
126
|
+
maxRetryAttempts?: number;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Size of the message queue for outgoing messages.
|
|
130
|
+
* @default 1000
|
|
131
|
+
*/
|
|
132
|
+
messageQueueSize?: number;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Enable rate limiting for outgoing messages.
|
|
136
|
+
* @default false
|
|
137
|
+
*/
|
|
138
|
+
rateLimitEnabled?: boolean;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Interval between heartbeat checks (milliseconds).
|
|
142
|
+
* @default 10000 (10 seconds)
|
|
143
|
+
*/
|
|
144
|
+
heartbeatInterval?: number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Default session options
|
|
149
|
+
*/
|
|
150
|
+
export const DEFAULT_SESSION_OPTIONS: Required<SessionOptions> = {
|
|
151
|
+
connectionTimeout: 30000,
|
|
152
|
+
responseTimeout: 180000,
|
|
153
|
+
maxRetryAttempts: 3,
|
|
154
|
+
messageQueueSize: 1000,
|
|
155
|
+
rateLimitEnabled: false,
|
|
156
|
+
heartbeatInterval: 10000,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Callback invoked when an HLA callback request is received from the RTI
|
|
161
|
+
*/
|
|
162
|
+
export interface HlaCallbackRequestListener {
|
|
163
|
+
/**
|
|
164
|
+
* Handle an incoming HLA callback from the RTI.
|
|
165
|
+
*
|
|
166
|
+
* @param sequenceNumber - The sequence number of the callback request
|
|
167
|
+
* @param hlaCallback - The encoded callback data (protobuf CallbackRequest)
|
|
168
|
+
*/
|
|
169
|
+
onHlaCallbackRequest(sequenceNumber: number, hlaCallback: Uint8Array): void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Callback invoked when the session state changes
|
|
174
|
+
*/
|
|
175
|
+
export interface SessionStateListener {
|
|
176
|
+
/**
|
|
177
|
+
* Handle a session state transition.
|
|
178
|
+
*
|
|
179
|
+
* @param oldState - The previous session state
|
|
180
|
+
* @param newState - The new session state
|
|
181
|
+
* @param reason - Description of why the transition occurred
|
|
182
|
+
*/
|
|
183
|
+
onStateTransition(
|
|
184
|
+
oldState: SessionState,
|
|
185
|
+
newState: SessionState,
|
|
186
|
+
reason: string
|
|
187
|
+
): void;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Callback invoked when a message is sent
|
|
192
|
+
*/
|
|
193
|
+
export interface MessageSentListener {
|
|
194
|
+
/**
|
|
195
|
+
* Called when a message has been sent to the server.
|
|
196
|
+
* Can be used to implement heartbeat logic.
|
|
197
|
+
*/
|
|
198
|
+
onMessageSent(): void;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Session statistics
|
|
203
|
+
*/
|
|
204
|
+
export interface SessionStats {
|
|
205
|
+
/** Total HLA calls sent */
|
|
206
|
+
hlaCallCount: number;
|
|
207
|
+
/** Total HLA callbacks received */
|
|
208
|
+
hlaCallbackCount: number;
|
|
209
|
+
/** Number of times the session was resumed */
|
|
210
|
+
resumeCount: number;
|
|
211
|
+
/** Number of messages in the call request queue */
|
|
212
|
+
callRequestQueueLength: number;
|
|
213
|
+
/** Number of messages in the callback response queue */
|
|
214
|
+
callbackResponseQueueLength: number;
|
|
215
|
+
/** Number of HLA calls awaiting response */
|
|
216
|
+
pendingRequestCount: number;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* New session status message payload structure
|
|
221
|
+
*/
|
|
222
|
+
export interface NewSessionStatusPayload {
|
|
223
|
+
/** Status code (0 = success) */
|
|
224
|
+
status: number;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Resume status message payload structure
|
|
229
|
+
*/
|
|
230
|
+
export interface ResumeStatusPayload {
|
|
231
|
+
/** Status code (0 = success) */
|
|
232
|
+
status: number;
|
|
233
|
+
/** Last sequence number received by the server */
|
|
234
|
+
lastReceivedFederateSequenceNumber: number;
|
|
235
|
+
}
|