@fluid-experimental/property-dds 1.1.0 → 1.2.0-77818
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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/propertyTree.d.ts +63 -1
- package/dist/propertyTree.d.ts.map +1 -1
- package/dist/propertyTree.js +87 -11
- package/dist/propertyTree.js.map +1 -1
- package/dist/propertyTreeExt.d.ts +15 -0
- package/dist/propertyTreeExt.d.ts.map +1 -0
- package/dist/propertyTreeExt.js +23 -0
- package/dist/propertyTreeExt.js.map +1 -0
- package/dist/propertyTreeExtFactories.d.ts +11 -0
- package/dist/propertyTreeExtFactories.d.ts.map +1 -0
- package/dist/propertyTreeExtFactories.js +82 -0
- package/dist/propertyTreeExtFactories.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/propertyTree.d.ts +63 -1
- package/lib/propertyTree.d.ts.map +1 -1
- package/lib/propertyTree.js +87 -11
- package/lib/propertyTree.js.map +1 -1
- package/lib/propertyTreeExt.d.ts +15 -0
- package/lib/propertyTreeExt.d.ts.map +1 -0
- package/lib/propertyTreeExt.js +19 -0
- package/lib/propertyTreeExt.js.map +1 -0
- package/lib/propertyTreeExtFactories.d.ts +11 -0
- package/lib/propertyTreeExtFactories.d.ts.map +1 -0
- package/lib/propertyTreeExtFactories.js +78 -0
- package/lib/propertyTreeExtFactories.js.map +1 -0
- package/package.json +17 -16
- package/src/index.ts +2 -0
- package/src/propertyTree.ts +108 -15
- package/src/propertyTreeExt.ts +22 -0
- package/src/propertyTreeExtFactories.ts +104 -0
package/src/propertyTree.ts
CHANGED
|
@@ -69,7 +69,7 @@ interface ISnapshot {
|
|
|
69
69
|
useMH: boolean;
|
|
70
70
|
numChunks: number;
|
|
71
71
|
}
|
|
72
|
-
interface ISnapshotSummary {
|
|
72
|
+
export interface ISnapshotSummary {
|
|
73
73
|
remoteTipView?: SerializedChangeSet;
|
|
74
74
|
remoteChanges?: IPropertyTreeMessage[];
|
|
75
75
|
unrebasedRemoteChanges?: Record<string, IRemotePropertyTreeMessage>;
|
|
@@ -81,6 +81,33 @@ export interface SharedPropertyTreeOptions {
|
|
|
81
81
|
useMH?: boolean;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
export interface ISharedPropertyTreeEncDec {
|
|
85
|
+
messageEncoder: { encode: (IPropertyTreeMessage) => IPropertyTreeMessage;
|
|
86
|
+
decode: (IPropertyTreeMessage) => IPropertyTreeMessage; };
|
|
87
|
+
summaryEncoder: { encode: (ISnapshotSummary) => Buffer; decode: (Buffer) => ISnapshotSummary; };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface IPropertyTreeConfig {
|
|
91
|
+
encDec: ISharedPropertyTreeEncDec;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const defaultEncDec: ISharedPropertyTreeEncDec = {
|
|
95
|
+
messageEncoder: { encode: (msg: IPropertyTreeMessage) => msg,
|
|
96
|
+
decode: (msg: IPropertyTreeMessage) => msg },
|
|
97
|
+
summaryEncoder: {
|
|
98
|
+
encode: (summary: ISnapshotSummary) => {
|
|
99
|
+
const packr = new Packr();
|
|
100
|
+
const serializedSummary = packr.pack(summary);
|
|
101
|
+
return serializedSummary;
|
|
102
|
+
},
|
|
103
|
+
decode: (serializedSummary) => {
|
|
104
|
+
const packr = new Packr();
|
|
105
|
+
const snapshotSummary = packr.unpack(serializedSummary);
|
|
106
|
+
return snapshotSummary as ISnapshotSummary;
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
84
111
|
/**
|
|
85
112
|
* Silly DDS example that models a six sided die.
|
|
86
113
|
*
|
|
@@ -107,12 +134,14 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
107
134
|
skipSequenceNumber: number = -1;
|
|
108
135
|
headCommitGuid: string = "";
|
|
109
136
|
useMH: boolean = false;
|
|
137
|
+
propertyTreeConfig: IPropertyTreeConfig;
|
|
110
138
|
|
|
111
139
|
public constructor(
|
|
112
140
|
id: string,
|
|
113
141
|
runtime: IFluidDataStoreRuntime,
|
|
114
142
|
attributes: IChannelAttributes,
|
|
115
143
|
options: SharedPropertyTreeOptions,
|
|
144
|
+
propertyTreeConfig: IPropertyTreeConfig = { encDec: defaultEncDec },
|
|
116
145
|
) {
|
|
117
146
|
super(id, runtime, attributes, "fluid_propertyTree_");
|
|
118
147
|
|
|
@@ -122,6 +151,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
122
151
|
|
|
123
152
|
// By default, we currently don't use the MH
|
|
124
153
|
this.useMH = options.useMH ?? false;
|
|
154
|
+
this.propertyTreeConfig = propertyTreeConfig;
|
|
125
155
|
}
|
|
126
156
|
|
|
127
157
|
/**
|
|
@@ -203,6 +233,22 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
203
233
|
}
|
|
204
234
|
}
|
|
205
235
|
|
|
236
|
+
/**
|
|
237
|
+
* This method encodes the given message to the transfer form
|
|
238
|
+
* @param change - The message to be encoded.
|
|
239
|
+
*/
|
|
240
|
+
private encodeMessage(change: IPropertyTreeMessage): IPropertyTreeMessage {
|
|
241
|
+
return this.propertyTreeConfig.encDec.messageEncoder.encode(change);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* This method decodes message from the transfer form.
|
|
246
|
+
* @param transferChange - The message to be decoded.
|
|
247
|
+
*/
|
|
248
|
+
private decodeMessage(transferChange: IPropertyTreeMessage): IPropertyTreeMessage {
|
|
249
|
+
return this.propertyTreeConfig.encDec.messageEncoder.decode(transferChange);
|
|
250
|
+
}
|
|
251
|
+
|
|
206
252
|
private applyChangeSet(changeSet: SerializedChangeSet, metadata: Metadata) {
|
|
207
253
|
const _changeSet = new ChangeSet(changeSet);
|
|
208
254
|
_changeSet._toReversibleChangeSet(this.tipView);
|
|
@@ -223,12 +269,12 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
223
269
|
useMH: this.useMH,
|
|
224
270
|
};
|
|
225
271
|
this._applyLocalChangeSet(change);
|
|
226
|
-
|
|
227
272
|
// Queue the op for transmission to the Fluid service.
|
|
273
|
+
const transferChange = this.encodeMessage(cloneDeep(change));
|
|
228
274
|
if (this.transmissionsHaveBeenStopped) {
|
|
229
|
-
this.enqueuedMessages.push(
|
|
275
|
+
this.enqueuedMessages.push(transferChange);
|
|
230
276
|
} else {
|
|
231
|
-
this.submitLocalMessage(
|
|
277
|
+
this.submitLocalMessage(transferChange);
|
|
232
278
|
}
|
|
233
279
|
}
|
|
234
280
|
|
|
@@ -277,7 +323,8 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
277
323
|
*/
|
|
278
324
|
protected processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown) {
|
|
279
325
|
if (message.type === MessageType.Operation && message.sequenceNumber > this.skipSequenceNumber) {
|
|
280
|
-
const
|
|
326
|
+
const change: IPropertyTreeMessage = this.decodeMessage(cloneDeep(message.contents));
|
|
327
|
+
const content: IRemotePropertyTreeMessage = { ...change, sequenceNumber: message.sequenceNumber };
|
|
281
328
|
switch (content.op) {
|
|
282
329
|
case OpKind.ChangeSet:
|
|
283
330
|
// If the op originated locally from this client, we've already accounted for it
|
|
@@ -384,6 +431,53 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
384
431
|
this.remoteChanges = remoteChanges;
|
|
385
432
|
this.unrebasedRemoteChanges = unrebasedRemoteChanges;
|
|
386
433
|
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* This method encodes the local summary (snapshot) object into the serialized form.
|
|
437
|
+
* @param summary - The local summary (snapshot)representation.
|
|
438
|
+
* @returns The serialized summary representation.
|
|
439
|
+
*/
|
|
440
|
+
private encodeSummary(summary: ISnapshotSummary) {
|
|
441
|
+
return this.propertyTreeConfig.encDec.summaryEncoder.encode(summary);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* This method decodes the serialized form of the summary into the local summary (snapshot) object.
|
|
446
|
+
* @param serializedSummary - The serialized summary representation.
|
|
447
|
+
* @returns The local summary (snapshot)representation.
|
|
448
|
+
*/
|
|
449
|
+
private decodeSummary(serializedSummary): ISnapshotSummary {
|
|
450
|
+
return this.propertyTreeConfig.encDec.summaryEncoder.decode(serializedSummary);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* This method writes the log message if the logging is enabled in the extended DDS.
|
|
455
|
+
* The logging is not enabled in the default Property DDS
|
|
456
|
+
* @param message - The message to be logged.
|
|
457
|
+
*/
|
|
458
|
+
protected logIfEnabled(message) {}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* This method encodes the binary representation of the
|
|
462
|
+
* blob.
|
|
463
|
+
* @param blob - The binary representation of the blob.
|
|
464
|
+
* @returns The encoded representation of the blob.
|
|
465
|
+
*/
|
|
466
|
+
private encodeSummaryBlob(blob: ArrayBuffer): any {
|
|
467
|
+
return bufferToString(blob, "base64");
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* This method decodes the encoded representation of the
|
|
472
|
+
* blob.
|
|
473
|
+
* @param blob - The encoded representation of the blob.
|
|
474
|
+
* @returns The binary representation of the blob.
|
|
475
|
+
*/
|
|
476
|
+
private decodeSummaryBlob(encoded: any): ArrayBuffer {
|
|
477
|
+
const buffer = bufferToString(encoded, "utf8");
|
|
478
|
+
return stringToBuffer(buffer, "base64");
|
|
479
|
+
}
|
|
480
|
+
|
|
387
481
|
public summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {
|
|
388
482
|
this.pruneHistory();
|
|
389
483
|
const snapshot: ISnapshot = {
|
|
@@ -403,14 +497,16 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
403
497
|
unrebasedRemoteChanges: this.unrebasedRemoteChanges,
|
|
404
498
|
};
|
|
405
499
|
const chunkSize = 5000 * 1024; // Default limit seems to be 5MB
|
|
406
|
-
|
|
407
|
-
const serializedSummary =
|
|
408
|
-
|
|
500
|
+
let totalBlobsSize = 0;
|
|
501
|
+
const serializedSummary = this.encodeSummary(summary);
|
|
409
502
|
for (let pos = 0, i = 0; pos < serializedSummary.length; pos += chunkSize, i++) {
|
|
410
|
-
|
|
411
|
-
|
|
503
|
+
const summaryBlob = this.encodeSummaryBlob(serializedSummary.slice(pos, pos + chunkSize));
|
|
504
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
505
|
+
totalBlobsSize += summaryBlob["length"];
|
|
506
|
+
builder.addBlob(`summaryChunk_${i}`, summaryBlob);
|
|
412
507
|
snapshot.numChunks++;
|
|
413
508
|
}
|
|
509
|
+
this.logIfEnabled(`Total blobs transfer size: ${totalBlobsSize}`);
|
|
414
510
|
}
|
|
415
511
|
|
|
416
512
|
builder.addBlob("properties", serializer !== undefined
|
|
@@ -432,8 +528,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
432
528
|
// We load all chunks
|
|
433
529
|
const chunks: ArrayBufferLike[] = await Promise.all(
|
|
434
530
|
range(snapshot.numChunks).map(async (i) => {
|
|
435
|
-
|
|
436
|
-
return stringToBuffer(buffer, "base64");
|
|
531
|
+
return this.decodeSummaryBlob(await storage.readBlob(`summaryChunk_${i}`));
|
|
437
532
|
}),
|
|
438
533
|
);
|
|
439
534
|
|
|
@@ -443,9 +538,7 @@ export class SharedPropertyTree extends SharedObject {
|
|
|
443
538
|
serializedSummary.set(new Uint8Array(chunk), offset);
|
|
444
539
|
return offset + chunk.byteLength;
|
|
445
540
|
}, 0);
|
|
446
|
-
|
|
447
|
-
const packr = new Packr();
|
|
448
|
-
const snapshotSummary = packr.unpack(serializedSummary);
|
|
541
|
+
const snapshotSummary = this.decodeSummary(serializedSummary);
|
|
449
542
|
if (
|
|
450
543
|
snapshotSummary.remoteChanges === undefined ||
|
|
451
544
|
snapshotSummary.remoteTipView === undefined ||
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IChannelFactory, IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions";
|
|
7
|
+
import { SharedPropertyTree } from "./propertyTree";
|
|
8
|
+
import { DeflatedPropertyTreeFactory } from "./propertyTreeExtFactories";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This class is the extension of SharedPropertyTree which compresses
|
|
12
|
+
* the deltas and summaries communicated to the server by Deflate.
|
|
13
|
+
*/
|
|
14
|
+
export class DeflatedPropertyTree extends SharedPropertyTree {
|
|
15
|
+
public static create(runtime: IFluidDataStoreRuntime, id?: string, queryString?: string) {
|
|
16
|
+
return runtime.createChannel(id, DeflatedPropertyTreeFactory.Type) as DeflatedPropertyTree;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static getFactory(): IChannelFactory {
|
|
20
|
+
return new DeflatedPropertyTreeFactory();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { deflate, inflate } from "pako";
|
|
6
|
+
import { bufferToString, stringToBuffer } from "@fluidframework/common-utils";
|
|
7
|
+
import {
|
|
8
|
+
IChannelAttributes,
|
|
9
|
+
IFluidDataStoreRuntime,
|
|
10
|
+
IChannelServices,
|
|
11
|
+
IChannelFactory,
|
|
12
|
+
} from "@fluidframework/datastore-definitions";
|
|
13
|
+
import { IPropertyTreeMessage, ISharedPropertyTreeEncDec, ISnapshotSummary, SharedPropertyTreeOptions }
|
|
14
|
+
from "./propertyTree";
|
|
15
|
+
import { DeflatedPropertyTree } from "./propertyTreeExt";
|
|
16
|
+
|
|
17
|
+
function encodeSummary(snapshotSummary: ISnapshotSummary) {
|
|
18
|
+
const summaryStr = JSON.stringify(snapshotSummary);
|
|
19
|
+
const unzipped = new TextEncoder().encode(summaryStr);
|
|
20
|
+
const serializedSummary: Buffer = deflate(unzipped);
|
|
21
|
+
return serializedSummary;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function decodeSummary(serializedSummary): ISnapshotSummary {
|
|
25
|
+
const unzipped = inflate(serializedSummary);
|
|
26
|
+
const summaryStr = new TextDecoder().decode(unzipped);
|
|
27
|
+
const snapshotSummary: ISnapshotSummary = JSON.parse(summaryStr);
|
|
28
|
+
return snapshotSummary;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function encodeMessage(change: IPropertyTreeMessage) {
|
|
32
|
+
const changeSetStr = JSON.stringify(change.changeSet);
|
|
33
|
+
const unzipped = new TextEncoder().encode(changeSetStr);
|
|
34
|
+
const zipped: Buffer = deflate(unzipped);
|
|
35
|
+
const zippedStr = bufferToString(zipped, "base64");
|
|
36
|
+
if (zippedStr.length < changeSetStr.length) {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
38
|
+
change["isZipped"] = "1";
|
|
39
|
+
change.changeSet = zippedStr;
|
|
40
|
+
}
|
|
41
|
+
return change;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function decodeMessage(transferChange: IPropertyTreeMessage) {
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
46
|
+
if (transferChange["isZipped"]) {
|
|
47
|
+
const zipped = stringToBuffer(transferChange.changeSet, "base64");
|
|
48
|
+
const unzipped = inflate(zipped);
|
|
49
|
+
const changeSetStr = new TextDecoder().decode(unzipped);
|
|
50
|
+
transferChange.changeSet = JSON.parse(changeSetStr);
|
|
51
|
+
}
|
|
52
|
+
return transferChange;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const encDec: ISharedPropertyTreeEncDec = {
|
|
56
|
+
messageEncoder: {
|
|
57
|
+
encode: encodeMessage,
|
|
58
|
+
decode: decodeMessage,
|
|
59
|
+
},
|
|
60
|
+
summaryEncoder: {
|
|
61
|
+
encode: encodeSummary,
|
|
62
|
+
decode: decodeSummary,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export class DeflatedPropertyTreeFactory implements IChannelFactory {
|
|
67
|
+
public static readonly Type = "DeflatedPropertyTree:84534a0fe613522101f6";
|
|
68
|
+
|
|
69
|
+
public static readonly Attributes: IChannelAttributes = {
|
|
70
|
+
type: DeflatedPropertyTreeFactory.Type,
|
|
71
|
+
snapshotFormatVersion: "0.1",
|
|
72
|
+
packageVersion: "0.0.1",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
public get type() {
|
|
76
|
+
return DeflatedPropertyTreeFactory.Type;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public get attributes() {
|
|
80
|
+
return DeflatedPropertyTreeFactory.Attributes;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public async load(
|
|
84
|
+
runtime: IFluidDataStoreRuntime,
|
|
85
|
+
id: string,
|
|
86
|
+
services: IChannelServices,
|
|
87
|
+
attributes: IChannelAttributes,
|
|
88
|
+
url?: string,
|
|
89
|
+
): Promise<DeflatedPropertyTree> {
|
|
90
|
+
const options = {};
|
|
91
|
+
const instance = new DeflatedPropertyTree(id, runtime, attributes, options as SharedPropertyTreeOptions
|
|
92
|
+
, { encDec });
|
|
93
|
+
await instance.load(services);
|
|
94
|
+
return instance;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public create(document: IFluidDataStoreRuntime, id: string, requestUrl?: string): DeflatedPropertyTree {
|
|
98
|
+
const options = {};
|
|
99
|
+
const cell = new DeflatedPropertyTree(id, document,
|
|
100
|
+
this.attributes, options as SharedPropertyTreeOptions, { encDec });
|
|
101
|
+
cell.initializeLocal();
|
|
102
|
+
return cell;
|
|
103
|
+
}
|
|
104
|
+
}
|