@fluidframework/shared-object-base 2.21.0 → 2.22.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.
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/shared-object-base";
9
- export const pkgVersion = "2.21.0";
9
+ export const pkgVersion = "2.22.1";
@@ -33,6 +33,7 @@ import {
33
33
  blobCountPropertyName,
34
34
  totalBlobSizePropertyName,
35
35
  type IRuntimeMessageCollection,
36
+ type IRuntimeMessagesContent,
36
37
  } from "@fluidframework/runtime-definitions/internal";
37
38
  import {
38
39
  toDeltaManagerInternal,
@@ -161,6 +162,20 @@ export abstract class SharedObjectCore<
161
162
  const { opProcessingHelper, callbacksHelper } = this.setUpSampledTelemetryHelpers();
162
163
  this.opProcessingHelper = opProcessingHelper;
163
164
  this.callbacksHelper = callbacksHelper;
165
+
166
+ const processMessagesCore = this.processMessagesCore?.bind(this);
167
+ this.processMessagesHelper =
168
+ processMessagesCore === undefined
169
+ ? (messagesCollection: IRuntimeMessageCollection) =>
170
+ processHelper(messagesCollection, this.process.bind(this))
171
+ : (messagesCollection: IRuntimeMessageCollection) => {
172
+ processMessagesCoreHelper(
173
+ messagesCollection,
174
+ this.opProcessingHelper,
175
+ this.emitInternal.bind(this),
176
+ processMessagesCore,
177
+ );
178
+ };
164
179
  }
165
180
 
166
181
  /**
@@ -384,6 +399,8 @@ export abstract class SharedObjectCore<
384
399
  * @param local - True if the shared object is local
385
400
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
386
401
  * For messages from a remote client, this will be undefined.
402
+ *
403
+ * @deprecated Replaced by {@link SharedObjectCore.processMessagesCore}.
387
404
  */
388
405
  protected abstract processCore(
389
406
  message: ISequencedDocumentMessage,
@@ -391,6 +408,34 @@ export abstract class SharedObjectCore<
391
408
  localOpMetadata: unknown,
392
409
  ): void;
393
410
 
411
+ /* eslint-disable jsdoc/check-indentation */
412
+ /**
413
+ * Process a 'bunch' of messages for this shared object.
414
+ *
415
+ * @remarks
416
+ * A 'bunch' is a group of messages that have the following properties:
417
+ * - They are all part of the same grouped batch, which entails:
418
+ * - They are contiguous in sequencing order.
419
+ * - They are all from the same client.
420
+ * - They are all based on the same reference sequence number.
421
+ * - They are not interleaved with messages from other clients.
422
+ * - They are not interleaved with messages from other DDS in the container.
423
+ * Derived classes should override this if they need to do custom processing on a 'bunch' of remote messages.
424
+ * @param messageCollection - The collection of messages to process.
425
+ *
426
+ */
427
+ /* eslint-enable jsdoc/check-indentation */
428
+ protected processMessagesCore?(messagesCollection: IRuntimeMessageCollection): void;
429
+
430
+ /**
431
+ * Calls {@link SharedObjectCore.processCore} or {@link SharedObjectCore.processMessagesCore} depending on whether
432
+ * processMessagesCore is defined. This helper is used to keep the code cleaner while we have to support both these
433
+ * function.
434
+ */
435
+ private readonly processMessagesHelper: (
436
+ messagesCollection: IRuntimeMessageCollection,
437
+ ) => void;
438
+
394
439
  /**
395
440
  * Called when the object has disconnected from the delta stream.
396
441
  */
@@ -557,6 +602,8 @@ export abstract class SharedObjectCore<
557
602
  * @param local - Whether the message originated from the local client
558
603
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
559
604
  * For messages from a remote client, this will be undefined.
605
+ *
606
+ * @deprecated Replaced by {@link SharedObjectCore.processMessages}.
560
607
  */
561
608
  private process(
562
609
  message: ISequencedDocumentMessage,
@@ -582,23 +629,42 @@ export abstract class SharedObjectCore<
582
629
  this.emitInternal("op", message, local, this);
583
630
  }
584
631
 
632
+ /* eslint-disable jsdoc/check-indentation */
585
633
  /**
586
- * Process messages for this shared object. The messages here are contiguous messages for this object in a batch.
634
+ * Process a bunch of messages for this shared object. A bunch is group of messages that have the following properties:
635
+ * - They are all part of the same grouped batch, which entails:
636
+ * - They are contiguous in sequencing order.
637
+ * - They are all from the same client.
638
+ * - They are all based on the same reference sequence number.
639
+ * - They are not interleaved with messages from other clients.
640
+ * - They are not interleaved with messages from other DDS in the container.
587
641
  * @param messageCollection - The collection of messages to process.
642
+ *
588
643
  */
644
+ /* eslint-enable jsdoc/check-indentation */
589
645
  private processMessages(messagesCollection: IRuntimeMessageCollection): void {
590
- const { envelope, messagesContent, local } = messagesCollection;
591
- for (const { contents, localOpMetadata, clientSequenceNumber } of messagesContent) {
592
- this.process(
593
- {
594
- ...envelope,
595
- clientSequenceNumber,
596
- contents: parseHandles(contents, this.serializer),
597
- },
598
- local,
646
+ this.verifyNotClosed(); // This will result in container closure.
647
+
648
+ // Decode any handles in the contents before processing the messages.
649
+ const decodedMessagesContent: IRuntimeMessagesContent[] = [];
650
+ for (const {
651
+ contents,
652
+ localOpMetadata,
653
+ clientSequenceNumber,
654
+ } of messagesCollection.messagesContent) {
655
+ const decodedMessageContent: IRuntimeMessagesContent = {
656
+ contents: parseHandles(contents, this.serializer),
599
657
  localOpMetadata,
600
- );
658
+ clientSequenceNumber,
659
+ };
660
+ decodedMessagesContent.push(decodedMessageContent);
601
661
  }
662
+
663
+ const decodedMessagesCollection: IRuntimeMessageCollection = {
664
+ ...messagesCollection,
665
+ messagesContent: decodedMessagesContent,
666
+ };
667
+ this.processMessagesHelper(decodedMessagesCollection);
602
668
  }
603
669
 
604
670
  /**
@@ -943,3 +1009,75 @@ function isChannel(loadable: IFluidLoadable): loadable is IChannel {
943
1009
  // This assumes no other IFluidLoadable has an `attributes` field, and thus may not be fully robust.
944
1010
  return (loadable as IChannel).attributes !== undefined;
945
1011
  }
1012
+
1013
+ /**
1014
+ * Utility that processes the given messages in the message collection together by calling `processMessagesCore`.
1015
+ * This will be called when {@link SharedObjectCore.processMessagesCore} is defined.
1016
+ */
1017
+ function processMessagesCoreHelper(
1018
+ messagesCollection: IRuntimeMessageCollection,
1019
+ opProcessingHelper: SampledTelemetryHelper<void, ProcessTelemetryProperties>,
1020
+ emitInternal: (
1021
+ event: "pre-op" | "op",
1022
+ op: ISequencedDocumentMessage,
1023
+ local: boolean,
1024
+ ) => void,
1025
+ processMessagesCore: (messagesCollection: IRuntimeMessageCollection) => void,
1026
+ ): void {
1027
+ const { envelope, local, messagesContent } = messagesCollection;
1028
+
1029
+ const emitEvents = (
1030
+ event: "pre-op" | "op",
1031
+ messagesContentForEvent: readonly IRuntimeMessagesContent[],
1032
+ ): void => {
1033
+ for (const { contents, clientSequenceNumber } of messagesContentForEvent) {
1034
+ const message: ISequencedDocumentMessage = {
1035
+ ...envelope,
1036
+ contents,
1037
+ clientSequenceNumber,
1038
+ };
1039
+ emitInternal(event, message, local);
1040
+ }
1041
+ };
1042
+
1043
+ emitEvents("pre-op", messagesContent);
1044
+ opProcessingHelper.measure(
1045
+ (): ICustomData<ProcessTelemetryProperties> => {
1046
+ processMessagesCore(messagesCollection);
1047
+ const telemetryProperties: ProcessTelemetryProperties = {
1048
+ sequenceDifference: envelope.sequenceNumber - envelope.referenceSequenceNumber,
1049
+ };
1050
+ return {
1051
+ customData: telemetryProperties,
1052
+ };
1053
+ },
1054
+ local ? "local" : "remote",
1055
+ );
1056
+ emitEvents("op", messagesContent);
1057
+ }
1058
+
1059
+ /**
1060
+ * Utility that processes the given messages in the message collection one by one by calling `process`. This will
1061
+ * be called when {@link SharedObjectCore.processMessagesCore} is not defined.
1062
+ */
1063
+ function processHelper(
1064
+ messagesCollection: IRuntimeMessageCollection,
1065
+ process: (
1066
+ message: ISequencedDocumentMessage,
1067
+ local: boolean,
1068
+ localOpMetadata: unknown,
1069
+ ) => void,
1070
+ ): void {
1071
+ const { envelope, local, messagesContent } = messagesCollection;
1072
+ for (const { contents, localOpMetadata, clientSequenceNumber } of messagesContent) {
1073
+ process(
1074
+ {
1075
+ ...envelope,
1076
+ contents,
1077
+ clientSequenceNumber,
1078
+ },
1079
+ local,
1080
+ localOpMetadata,
1081
+ );
1082
+ }
1083
+ }