@hla4ts/hla-api 0.1.0

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.
@@ -0,0 +1,673 @@
1
+ /**
2
+ * Callback Dispatcher
3
+ *
4
+ * This module handles decoding and dispatching of RTI callbacks to the
5
+ * FederateAmbassador implementation.
6
+ */
7
+
8
+ import {
9
+ CallbackRequestCodec,
10
+ CallbackResponseCodec,
11
+ type CallbackRequest,
12
+ type CallbackResponse,
13
+ type CallbackSucceeded,
14
+ } from "@hla4ts/proto";
15
+
16
+ import type { FederateAmbassador } from "./federate-ambassador.ts";
17
+ import {
18
+ convertObjectClassHandle,
19
+ convertAttributeHandle,
20
+ convertInteractionClassHandle,
21
+ convertObjectInstanceHandle,
22
+ convertFederateHandle,
23
+ convertTransportationTypeHandle,
24
+ convertLogicalTime,
25
+ convertMessageRetractionHandle,
26
+ convertAttributeHandleSet,
27
+ convertFederateHandleSet,
28
+ convertAttributeHandleValueMap,
29
+ convertParameterHandleValueMap,
30
+ convertFederationExecutionInformationSet,
31
+ convertFederationExecutionMemberInformationSet,
32
+ convertFederateHandleSaveStatusPairArray,
33
+ convertFederateRestoreStatusArray,
34
+ convertConveyedRegionSet,
35
+ convertOrderType,
36
+ } from "./converters.ts";
37
+ import { FederateInternalError, RTIinternalError } from "./exceptions.ts";
38
+ import type { ExceptionData } from "@hla4ts/proto";
39
+
40
+ /**
41
+ * Result of dispatching a callback.
42
+ */
43
+ export interface CallbackDispatchResult {
44
+ /** Whether the callback was handled successfully */
45
+ success: boolean;
46
+ /** Error if the callback failed */
47
+ error?: Error;
48
+ }
49
+
50
+ /**
51
+ * Callback dispatcher that decodes and dispatches RTI callbacks.
52
+ */
53
+ export class CallbackDispatcher {
54
+ private readonly _federateAmbassador: FederateAmbassador;
55
+
56
+ constructor(federateAmbassador: FederateAmbassador) {
57
+ this._federateAmbassador = federateAmbassador;
58
+ }
59
+
60
+ /**
61
+ * Decode a callback request from raw bytes.
62
+ */
63
+ decodeCallbackRequest(data: Uint8Array): CallbackRequest {
64
+ return CallbackRequestCodec.decode(data);
65
+ }
66
+
67
+ /**
68
+ * Encode a successful callback response.
69
+ */
70
+ encodeSuccessResponse(): Uint8Array {
71
+ const response: CallbackResponse = {
72
+ callbackSucceeded: {} as CallbackSucceeded,
73
+ };
74
+ return CallbackResponseCodec.encode(response).finish();
75
+ }
76
+
77
+ /**
78
+ * Encode a failed callback response.
79
+ */
80
+ encodeFailureResponse(error: Error): Uint8Array {
81
+ const exceptionData: ExceptionData = {
82
+ exceptionName: error.name || "FederateInternalError",
83
+ details: error.message || "Unknown error",
84
+ };
85
+ const response: CallbackResponse = {
86
+ callbackFailed: exceptionData,
87
+ };
88
+ return CallbackResponseCodec.encode(response).finish();
89
+ }
90
+
91
+ /**
92
+ * Dispatch a decoded callback request to the FederateAmbassador.
93
+ *
94
+ * @param callback - The decoded callback request
95
+ * @returns Result indicating success or failure
96
+ */
97
+ dispatchCallback(callback: CallbackRequest): CallbackDispatchResult {
98
+ const fa = this._federateAmbassador;
99
+
100
+ try {
101
+ // Connection Management
102
+ if (callback.connectionLost) {
103
+ fa.connectionLost?.(callback.connectionLost.faultDescription ?? "");
104
+ return { success: true };
105
+ }
106
+
107
+ // Federation Management
108
+ if (callback.reportFederationExecutions) {
109
+ fa.reportFederationExecutions?.(
110
+ convertFederationExecutionInformationSet(callback.reportFederationExecutions.report)
111
+ );
112
+ return { success: true };
113
+ }
114
+
115
+ if (callback.reportFederationExecutionMembers) {
116
+ fa.reportFederationExecutionMembers?.(
117
+ callback.reportFederationExecutionMembers.federationName ?? "",
118
+ convertFederationExecutionMemberInformationSet(callback.reportFederationExecutionMembers.report)
119
+ );
120
+ return { success: true };
121
+ }
122
+
123
+ if (callback.reportFederationExecutionDoesNotExist) {
124
+ fa.reportFederationExecutionDoesNotExist?.(
125
+ callback.reportFederationExecutionDoesNotExist.federationName ?? ""
126
+ );
127
+ return { success: true };
128
+ }
129
+
130
+ if (callback.federateResigned) {
131
+ fa.federateResigned?.(callback.federateResigned.reasonForResignDescription ?? "");
132
+ return { success: true };
133
+ }
134
+
135
+ // Synchronization Points
136
+ if (callback.synchronizationPointRegistrationSucceeded) {
137
+ fa.synchronizationPointRegistrationSucceeded?.(
138
+ callback.synchronizationPointRegistrationSucceeded.synchronizationPointLabel ?? ""
139
+ );
140
+ return { success: true };
141
+ }
142
+
143
+ if (callback.synchronizationPointRegistrationFailed) {
144
+ fa.synchronizationPointRegistrationFailed?.(
145
+ callback.synchronizationPointRegistrationFailed.synchronizationPointLabel ?? "",
146
+ callback.synchronizationPointRegistrationFailed.reason
147
+ );
148
+ return { success: true };
149
+ }
150
+
151
+ if (callback.announceSynchronizationPoint) {
152
+ fa.announceSynchronizationPoint?.(
153
+ callback.announceSynchronizationPoint.synchronizationPointLabel ?? "",
154
+ callback.announceSynchronizationPoint.userSuppliedTag ?? new Uint8Array(0)
155
+ );
156
+ return { success: true };
157
+ }
158
+
159
+ if (callback.federationSynchronized) {
160
+ fa.federationSynchronized?.(
161
+ callback.federationSynchronized.synchronizationPointLabel ?? "",
162
+ convertFederateHandleSet(callback.federationSynchronized.failedToSyncSet)
163
+ );
164
+ return { success: true };
165
+ }
166
+
167
+ // Save Services
168
+ if (callback.initiateFederateSave) {
169
+ fa.initiateFederateSave?.(callback.initiateFederateSave.label ?? "");
170
+ return { success: true };
171
+ }
172
+
173
+ if (callback.initiateFederateSaveWithTime) {
174
+ fa.initiateFederateSaveWithTime?.(
175
+ callback.initiateFederateSaveWithTime.label ?? "",
176
+ convertLogicalTime(callback.initiateFederateSaveWithTime.time)
177
+ );
178
+ return { success: true };
179
+ }
180
+
181
+ if (callback.federationSaved) {
182
+ fa.federationSaved?.();
183
+ return { success: true };
184
+ }
185
+
186
+ if (callback.federationNotSaved) {
187
+ fa.federationNotSaved?.(callback.federationNotSaved.reason);
188
+ return { success: true };
189
+ }
190
+
191
+ if (callback.federationSaveStatusResponse) {
192
+ fa.federationSaveStatusResponse?.(
193
+ convertFederateHandleSaveStatusPairArray(callback.federationSaveStatusResponse.response)
194
+ );
195
+ return { success: true };
196
+ }
197
+
198
+ // Restore Services
199
+ if (callback.requestFederationRestoreSucceeded) {
200
+ fa.requestFederationRestoreSucceeded?.(callback.requestFederationRestoreSucceeded.label ?? "");
201
+ return { success: true };
202
+ }
203
+
204
+ if (callback.requestFederationRestoreFailed) {
205
+ fa.requestFederationRestoreFailed?.(callback.requestFederationRestoreFailed.label ?? "");
206
+ return { success: true };
207
+ }
208
+
209
+ if (callback.federationRestoreBegun) {
210
+ fa.federationRestoreBegun?.();
211
+ return { success: true };
212
+ }
213
+
214
+ if (callback.initiateFederateRestore) {
215
+ fa.initiateFederateRestore?.(
216
+ callback.initiateFederateRestore.label ?? "",
217
+ callback.initiateFederateRestore.federateName ?? "",
218
+ convertFederateHandle(callback.initiateFederateRestore.postRestoreFederateHandle)
219
+ );
220
+ return { success: true };
221
+ }
222
+
223
+ if (callback.federationRestored) {
224
+ fa.federationRestored?.();
225
+ return { success: true };
226
+ }
227
+
228
+ if (callback.federationNotRestored) {
229
+ fa.federationNotRestored?.(callback.federationNotRestored.reason);
230
+ return { success: true };
231
+ }
232
+
233
+ if (callback.federationRestoreStatusResponse) {
234
+ fa.federationRestoreStatusResponse?.(
235
+ convertFederateRestoreStatusArray(callback.federationRestoreStatusResponse.response)
236
+ );
237
+ return { success: true };
238
+ }
239
+
240
+ // Declaration Management
241
+ if (callback.startRegistrationForObjectClass) {
242
+ fa.startRegistrationForObjectClass?.(
243
+ convertObjectClassHandle(callback.startRegistrationForObjectClass.objectClass)
244
+ );
245
+ return { success: true };
246
+ }
247
+
248
+ if (callback.stopRegistrationForObjectClass) {
249
+ fa.stopRegistrationForObjectClass?.(
250
+ convertObjectClassHandle(callback.stopRegistrationForObjectClass.objectClass)
251
+ );
252
+ return { success: true };
253
+ }
254
+
255
+ if (callback.turnInteractionsOn) {
256
+ fa.turnInteractionsOn?.(
257
+ convertInteractionClassHandle(callback.turnInteractionsOn.interactionClass)
258
+ );
259
+ return { success: true };
260
+ }
261
+
262
+ if (callback.turnInteractionsOff) {
263
+ fa.turnInteractionsOff?.(
264
+ convertInteractionClassHandle(callback.turnInteractionsOff.interactionClass)
265
+ );
266
+ return { success: true };
267
+ }
268
+
269
+ // Object Instance Name Reservation
270
+ if (callback.objectInstanceNameReservationSucceeded) {
271
+ fa.objectInstanceNameReservationSucceeded?.(
272
+ callback.objectInstanceNameReservationSucceeded.objectInstanceName ?? ""
273
+ );
274
+ return { success: true };
275
+ }
276
+
277
+ if (callback.objectInstanceNameReservationFailed) {
278
+ fa.objectInstanceNameReservationFailed?.(
279
+ callback.objectInstanceNameReservationFailed.objectInstanceName ?? ""
280
+ );
281
+ return { success: true };
282
+ }
283
+
284
+ if (callback.multipleObjectInstanceNameReservationSucceeded) {
285
+ fa.multipleObjectInstanceNameReservationSucceeded?.(
286
+ callback.multipleObjectInstanceNameReservationSucceeded.objectInstanceNames ?? []
287
+ );
288
+ return { success: true };
289
+ }
290
+
291
+ if (callback.multipleObjectInstanceNameReservationFailed) {
292
+ fa.multipleObjectInstanceNameReservationFailed?.(
293
+ callback.multipleObjectInstanceNameReservationFailed.objectInstanceNames ?? []
294
+ );
295
+ return { success: true };
296
+ }
297
+
298
+ // Object Discovery & Removal
299
+ if (callback.discoverObjectInstance) {
300
+ fa.discoverObjectInstance?.(
301
+ convertObjectInstanceHandle(callback.discoverObjectInstance.objectInstance),
302
+ convertObjectClassHandle(callback.discoverObjectInstance.objectClass),
303
+ callback.discoverObjectInstance.objectInstanceName ?? "",
304
+ convertFederateHandle(callback.discoverObjectInstance.producingFederate)
305
+ );
306
+ return { success: true };
307
+ }
308
+
309
+ if (callback.removeObjectInstance) {
310
+ fa.removeObjectInstance?.(
311
+ convertObjectInstanceHandle(callback.removeObjectInstance.objectInstance),
312
+ callback.removeObjectInstance.userSuppliedTag ?? new Uint8Array(0),
313
+ convertFederateHandle(callback.removeObjectInstance.producingFederate)
314
+ );
315
+ return { success: true };
316
+ }
317
+
318
+ if (callback.removeObjectInstanceWithTime) {
319
+ const cb = callback.removeObjectInstanceWithTime;
320
+ fa.removeObjectInstanceWithTime?.(
321
+ convertObjectInstanceHandle(cb.objectInstance),
322
+ cb.userSuppliedTag ?? new Uint8Array(0),
323
+ convertFederateHandle(cb.producingFederate),
324
+ convertLogicalTime(cb.time),
325
+ convertOrderType(cb.sentOrderType),
326
+ convertOrderType(cb.receivedOrderType),
327
+ cb.optionalRetraction ? convertMessageRetractionHandle(cb.optionalRetraction) : undefined
328
+ );
329
+ return { success: true };
330
+ }
331
+
332
+ // Attribute Updates
333
+ if (callback.reflectAttributeValues) {
334
+ const cb = callback.reflectAttributeValues;
335
+ fa.reflectAttributeValues?.(
336
+ convertObjectInstanceHandle(cb.objectInstance),
337
+ convertAttributeHandleValueMap(cb.attributeValues),
338
+ cb.userSuppliedTag ?? new Uint8Array(0),
339
+ convertTransportationTypeHandle(cb.transportationType),
340
+ convertFederateHandle(cb.producingFederate),
341
+ cb.optionalSentRegions ? convertConveyedRegionSet(cb.optionalSentRegions) : undefined
342
+ );
343
+ return { success: true };
344
+ }
345
+
346
+ if (callback.reflectAttributeValuesWithTime) {
347
+ const cb = callback.reflectAttributeValuesWithTime;
348
+ fa.reflectAttributeValuesWithTime?.(
349
+ convertObjectInstanceHandle(cb.objectInstance),
350
+ convertAttributeHandleValueMap(cb.attributeValues),
351
+ cb.userSuppliedTag ?? new Uint8Array(0),
352
+ convertTransportationTypeHandle(cb.transportationType),
353
+ convertFederateHandle(cb.producingFederate),
354
+ cb.optionalSentRegions ? convertConveyedRegionSet(cb.optionalSentRegions) : undefined,
355
+ convertLogicalTime(cb.time),
356
+ convertOrderType(cb.sentOrderType),
357
+ convertOrderType(cb.receivedOrderType),
358
+ cb.optionalRetraction ? convertMessageRetractionHandle(cb.optionalRetraction) : undefined
359
+ );
360
+ return { success: true };
361
+ }
362
+
363
+ // Interactions
364
+ if (callback.receiveInteraction) {
365
+ const cb = callback.receiveInteraction;
366
+ fa.receiveInteraction?.(
367
+ convertInteractionClassHandle(cb.interactionClass),
368
+ convertParameterHandleValueMap(cb.parameterValues),
369
+ cb.userSuppliedTag ?? new Uint8Array(0),
370
+ convertTransportationTypeHandle(cb.transportationType),
371
+ convertFederateHandle(cb.producingFederate),
372
+ cb.optionalSentRegions ? convertConveyedRegionSet(cb.optionalSentRegions) : undefined
373
+ );
374
+ return { success: true };
375
+ }
376
+
377
+ if (callback.receiveInteractionWithTime) {
378
+ const cb = callback.receiveInteractionWithTime;
379
+ fa.receiveInteractionWithTime?.(
380
+ convertInteractionClassHandle(cb.interactionClass),
381
+ convertParameterHandleValueMap(cb.parameterValues),
382
+ cb.userSuppliedTag ?? new Uint8Array(0),
383
+ convertTransportationTypeHandle(cb.transportationType),
384
+ convertFederateHandle(cb.producingFederate),
385
+ cb.optionalSentRegions ? convertConveyedRegionSet(cb.optionalSentRegions) : undefined,
386
+ convertLogicalTime(cb.time),
387
+ convertOrderType(cb.sentOrderType),
388
+ convertOrderType(cb.receivedOrderType),
389
+ cb.optionalRetraction ? convertMessageRetractionHandle(cb.optionalRetraction) : undefined
390
+ );
391
+ return { success: true };
392
+ }
393
+
394
+ if (callback.receiveDirectedInteraction) {
395
+ const cb = callback.receiveDirectedInteraction;
396
+ fa.receiveDirectedInteraction?.(
397
+ convertInteractionClassHandle(cb.interactionClass),
398
+ convertObjectInstanceHandle(cb.objectInstance),
399
+ convertParameterHandleValueMap(cb.parameterValues),
400
+ cb.userSuppliedTag ?? new Uint8Array(0),
401
+ convertTransportationTypeHandle(cb.transportationType),
402
+ convertFederateHandle(cb.producingFederate)
403
+ );
404
+ return { success: true };
405
+ }
406
+
407
+ if (callback.receiveDirectedInteractionWithTime) {
408
+ const cb = callback.receiveDirectedInteractionWithTime;
409
+ fa.receiveDirectedInteractionWithTime?.(
410
+ convertInteractionClassHandle(cb.interactionClass),
411
+ convertObjectInstanceHandle(cb.objectInstance),
412
+ convertParameterHandleValueMap(cb.parameterValues),
413
+ cb.userSuppliedTag ?? new Uint8Array(0),
414
+ convertTransportationTypeHandle(cb.transportationType),
415
+ convertFederateHandle(cb.producingFederate),
416
+ convertLogicalTime(cb.time),
417
+ convertOrderType(cb.sentOrderType),
418
+ convertOrderType(cb.receivedOrderType),
419
+ cb.optionalRetraction ? convertMessageRetractionHandle(cb.optionalRetraction) : undefined
420
+ );
421
+ return { success: true };
422
+ }
423
+
424
+ // Attribute Value Update Requests
425
+ if (callback.provideAttributeValueUpdate) {
426
+ fa.provideAttributeValueUpdate?.(
427
+ convertObjectInstanceHandle(callback.provideAttributeValueUpdate.objectInstance),
428
+ convertAttributeHandleSet(callback.provideAttributeValueUpdate.attributes),
429
+ callback.provideAttributeValueUpdate.userSuppliedTag ?? new Uint8Array(0)
430
+ );
431
+ return { success: true };
432
+ }
433
+
434
+ if (callback.turnUpdatesOnForObjectInstance) {
435
+ fa.turnUpdatesOnForObjectInstance?.(
436
+ convertObjectInstanceHandle(callback.turnUpdatesOnForObjectInstance.objectInstance),
437
+ convertAttributeHandleSet(callback.turnUpdatesOnForObjectInstance.attributes)
438
+ );
439
+ return { success: true };
440
+ }
441
+
442
+ if (callback.turnUpdatesOnForObjectInstanceWithRate) {
443
+ fa.turnUpdatesOnForObjectInstanceWithRate?.(
444
+ convertObjectInstanceHandle(callback.turnUpdatesOnForObjectInstanceWithRate.objectInstance),
445
+ convertAttributeHandleSet(callback.turnUpdatesOnForObjectInstanceWithRate.attributes),
446
+ callback.turnUpdatesOnForObjectInstanceWithRate.updateRateDesignator ?? ""
447
+ );
448
+ return { success: true };
449
+ }
450
+
451
+ if (callback.turnUpdatesOffForObjectInstance) {
452
+ fa.turnUpdatesOffForObjectInstance?.(
453
+ convertObjectInstanceHandle(callback.turnUpdatesOffForObjectInstance.objectInstance),
454
+ convertAttributeHandleSet(callback.turnUpdatesOffForObjectInstance.attributes)
455
+ );
456
+ return { success: true };
457
+ }
458
+
459
+ // Attribute Scope
460
+ if (callback.attributesInScope) {
461
+ fa.attributesInScope?.(
462
+ convertObjectInstanceHandle(callback.attributesInScope.objectInstance),
463
+ convertAttributeHandleSet(callback.attributesInScope.attributes)
464
+ );
465
+ return { success: true };
466
+ }
467
+
468
+ if (callback.attributesOutOfScope) {
469
+ fa.attributesOutOfScope?.(
470
+ convertObjectInstanceHandle(callback.attributesOutOfScope.objectInstance),
471
+ convertAttributeHandleSet(callback.attributesOutOfScope.attributes)
472
+ );
473
+ return { success: true };
474
+ }
475
+
476
+ // Ownership Management
477
+ if (callback.requestAttributeOwnershipAssumption) {
478
+ fa.requestAttributeOwnershipAssumption?.(
479
+ convertObjectInstanceHandle(callback.requestAttributeOwnershipAssumption.objectInstance),
480
+ convertAttributeHandleSet(callback.requestAttributeOwnershipAssumption.offeredAttributes),
481
+ callback.requestAttributeOwnershipAssumption.userSuppliedTag ?? new Uint8Array(0)
482
+ );
483
+ return { success: true };
484
+ }
485
+
486
+ if (callback.requestDivestitureConfirmation) {
487
+ fa.requestDivestitureConfirmation?.(
488
+ convertObjectInstanceHandle(callback.requestDivestitureConfirmation.objectInstance),
489
+ convertAttributeHandleSet(callback.requestDivestitureConfirmation.releasedAttributes)
490
+ );
491
+ return { success: true };
492
+ }
493
+
494
+ if (callback.attributeOwnershipAcquisitionNotification) {
495
+ fa.attributeOwnershipAcquisitionNotification?.(
496
+ convertObjectInstanceHandle(callback.attributeOwnershipAcquisitionNotification.objectInstance),
497
+ convertAttributeHandleSet(callback.attributeOwnershipAcquisitionNotification.securedAttributes),
498
+ callback.attributeOwnershipAcquisitionNotification.userSuppliedTag ?? new Uint8Array(0)
499
+ );
500
+ return { success: true };
501
+ }
502
+
503
+ if (callback.attributeOwnershipUnavailable) {
504
+ fa.attributeOwnershipUnavailable?.(
505
+ convertObjectInstanceHandle(callback.attributeOwnershipUnavailable.objectInstance),
506
+ convertAttributeHandleSet(callback.attributeOwnershipUnavailable.attributes)
507
+ );
508
+ return { success: true };
509
+ }
510
+
511
+ if (callback.requestAttributeOwnershipRelease) {
512
+ fa.requestAttributeOwnershipRelease?.(
513
+ convertObjectInstanceHandle(callback.requestAttributeOwnershipRelease.objectInstance),
514
+ convertAttributeHandleSet(callback.requestAttributeOwnershipRelease.candidateAttributes),
515
+ callback.requestAttributeOwnershipRelease.userSuppliedTag ?? new Uint8Array(0)
516
+ );
517
+ return { success: true };
518
+ }
519
+
520
+ if (callback.confirmAttributeOwnershipAcquisitionCancellation) {
521
+ fa.confirmAttributeOwnershipAcquisitionCancellation?.(
522
+ convertObjectInstanceHandle(callback.confirmAttributeOwnershipAcquisitionCancellation.objectInstance),
523
+ convertAttributeHandleSet(callback.confirmAttributeOwnershipAcquisitionCancellation.attributes)
524
+ );
525
+ return { success: true };
526
+ }
527
+
528
+ if (callback.informAttributeOwnership) {
529
+ // Note: InformAttributeOwnership in proto has 'attributes' and 'federate' (not single attribute and owner)
530
+ // For simplicity, we take first attribute if the callback expects a single one
531
+ const attrs = convertAttributeHandleSet(callback.informAttributeOwnership.attributes);
532
+ if (attrs.length > 0) {
533
+ fa.informAttributeOwnership?.(
534
+ convertObjectInstanceHandle(callback.informAttributeOwnership.objectInstance),
535
+ attrs[0],
536
+ convertFederateHandle(callback.informAttributeOwnership.federate)
537
+ );
538
+ }
539
+ return { success: true };
540
+ }
541
+
542
+ if (callback.attributeIsNotOwned) {
543
+ // Same note as above
544
+ const attrs = convertAttributeHandleSet(callback.attributeIsNotOwned.attributes);
545
+ if (attrs.length > 0) {
546
+ fa.attributeIsNotOwned?.(
547
+ convertObjectInstanceHandle(callback.attributeIsNotOwned.objectInstance),
548
+ attrs[0]
549
+ );
550
+ }
551
+ return { success: true };
552
+ }
553
+
554
+ if (callback.attributeIsOwnedByRTI) {
555
+ // Same note as above
556
+ const attrs = convertAttributeHandleSet(callback.attributeIsOwnedByRTI.attributes);
557
+ if (attrs.length > 0) {
558
+ fa.attributeIsOwnedByRTI?.(
559
+ convertObjectInstanceHandle(callback.attributeIsOwnedByRTI.objectInstance),
560
+ attrs[0]
561
+ );
562
+ }
563
+ return { success: true };
564
+ }
565
+
566
+ // Time Management
567
+ if (callback.timeRegulationEnabled) {
568
+ fa.timeRegulationEnabled?.(convertLogicalTime(callback.timeRegulationEnabled.time));
569
+ return { success: true };
570
+ }
571
+
572
+ if (callback.timeConstrainedEnabled) {
573
+ fa.timeConstrainedEnabled?.(convertLogicalTime(callback.timeConstrainedEnabled.time));
574
+ return { success: true };
575
+ }
576
+
577
+ if (callback.timeAdvanceGrant) {
578
+ fa.timeAdvanceGrant?.(convertLogicalTime(callback.timeAdvanceGrant.time));
579
+ return { success: true };
580
+ }
581
+
582
+ if (callback.flushQueueGrant) {
583
+ fa.flushQueueGrant?.(convertLogicalTime(callback.flushQueueGrant.time));
584
+ return { success: true };
585
+ }
586
+
587
+ if (callback.requestRetraction) {
588
+ fa.requestRetraction?.(
589
+ convertMessageRetractionHandle(callback.requestRetraction.retraction)
590
+ );
591
+ return { success: true };
592
+ }
593
+
594
+ // Transportation Type Changes
595
+ if (callback.confirmAttributeTransportationTypeChange) {
596
+ fa.confirmAttributeTransportationTypeChange?.(
597
+ convertObjectInstanceHandle(callback.confirmAttributeTransportationTypeChange.objectInstance),
598
+ convertAttributeHandleSet(callback.confirmAttributeTransportationTypeChange.attributes),
599
+ convertTransportationTypeHandle(callback.confirmAttributeTransportationTypeChange.transportationType)
600
+ );
601
+ return { success: true };
602
+ }
603
+
604
+ if (callback.reportAttributeTransportationType) {
605
+ fa.reportAttributeTransportationType?.(
606
+ convertObjectInstanceHandle(callback.reportAttributeTransportationType.objectInstance),
607
+ convertAttributeHandle(callback.reportAttributeTransportationType.attribute),
608
+ convertTransportationTypeHandle(callback.reportAttributeTransportationType.transportationType)
609
+ );
610
+ return { success: true };
611
+ }
612
+
613
+ if (callback.confirmInteractionTransportationTypeChange) {
614
+ fa.confirmInteractionTransportationTypeChange?.(
615
+ convertInteractionClassHandle(callback.confirmInteractionTransportationTypeChange.interactionClass),
616
+ convertTransportationTypeHandle(callback.confirmInteractionTransportationTypeChange.transportationType)
617
+ );
618
+ return { success: true };
619
+ }
620
+
621
+ if (callback.reportInteractionTransportationType) {
622
+ fa.reportInteractionTransportationType?.(
623
+ convertFederateHandle(callback.reportInteractionTransportationType.federate),
624
+ convertInteractionClassHandle(callback.reportInteractionTransportationType.interactionClass),
625
+ convertTransportationTypeHandle(callback.reportInteractionTransportationType.transportationType)
626
+ );
627
+ return { success: true };
628
+ }
629
+
630
+ // Unknown callback type
631
+ console.warn("[CallbackDispatcher] Unknown callback type received");
632
+ return { success: true }; // Don't fail on unknown callbacks
633
+
634
+ } catch (error) {
635
+ if (error instanceof FederateInternalError) {
636
+ return { success: false, error };
637
+ }
638
+ // Wrap other errors
639
+ const wrappedError = new RTIinternalError(
640
+ `Error dispatching callback: ${error instanceof Error ? error.message : String(error)}`
641
+ );
642
+ return { success: false, error: wrappedError };
643
+ }
644
+ }
645
+
646
+ /**
647
+ * Process a raw callback request and return the encoded response.
648
+ *
649
+ * This is the main entry point used by the RTI Ambassador.
650
+ *
651
+ * @param rawCallbackData - The raw protobuf-encoded callback request
652
+ * @returns The encoded callback response
653
+ */
654
+ processCallback(rawCallbackData: Uint8Array): Uint8Array {
655
+ try {
656
+ const callback = this.decodeCallbackRequest(rawCallbackData);
657
+ const result = this.dispatchCallback(callback);
658
+
659
+ if (result.success) {
660
+ return this.encodeSuccessResponse();
661
+ } else {
662
+ return this.encodeFailureResponse(result.error ?? new FederateInternalError("Unknown error"));
663
+ }
664
+ } catch (error) {
665
+ // Decoding error
666
+ return this.encodeFailureResponse(
667
+ new RTIinternalError(
668
+ `Failed to decode callback: ${error instanceof Error ? error.message : String(error)}`
669
+ )
670
+ );
671
+ }
672
+ }
673
+ }