@dra2020/baseclient 1.0.122 → 1.0.123

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.
@@ -91,8 +91,10 @@ export declare class OTArrayLikeResource extends OT.OTResourceBase {
91
91
  alignEdges(rhs: OTArrayLikeResource, st: OTalignEdgesType): void;
92
92
  getCursorCache(): any;
93
93
  compose(rhs: OTArrayLikeResource): void;
94
+ tryCompose(rhs: OTArrayLikeResource): boolean;
94
95
  performTransformReorder(bForceRetainBeforeInsert: boolean, newA: OTEdits, iBegin: number, iEnd: number): void;
95
96
  normalizeNewRetainsAfterTransform(bForceRetainBeforeInsert: boolean): void;
97
+ tryTransform(prior: OTArrayLikeResource, bPriorIsService: boolean): boolean;
96
98
  transform(prior: OTArrayLikeResource, bPriorIsService: boolean): void;
97
99
  generateRandom(nInitial: number, clientID: string): void;
98
100
  }
@@ -26,7 +26,9 @@ export declare class OTCompositeResource extends OT.OTResourceBase {
26
26
  copy(): OTCompositeResource;
27
27
  effectivelyEqual(rhs: OTCompositeResource): boolean;
28
28
  transform(rhs: OTCompositeResource, bPriorIsService: boolean): void;
29
+ tryTransform(rhs: OTCompositeResource, bPriorIsService: boolean): boolean;
29
30
  compose(rhs: OTCompositeResource): void;
31
+ tryCompose(rhs: OTCompositeResource): boolean;
30
32
  apply(runningValue: any): any;
31
33
  toPartialValue(resourceName: string): any;
32
34
  toValue(): any;
@@ -8,7 +8,9 @@ export interface IOTResource {
8
8
  copy(): IOTResource;
9
9
  effectivelyEqual(rhs: IOTResource): boolean;
10
10
  transform(rhs: IOTResource, bPriorIsService: boolean): void;
11
+ tryTransform(rhs: IOTResource, bPriorIsService: boolean): boolean;
11
12
  compose(rhs: IOTResource): void;
13
+ tryCompose(rhs: IOTResource): boolean;
12
14
  apply(startValue: any): any;
13
15
  minimize(): void;
14
16
  }
@@ -23,7 +25,9 @@ export declare class OTResourceBase implements IOTResource {
23
25
  copy(): OTResourceBase;
24
26
  effectivelyEqual(rhs: OTResourceBase): boolean;
25
27
  transform(rhs: OTResourceBase, bPriorIsService: boolean): void;
28
+ tryTransform(rhs: OTResourceBase, bPriorIsServer: boolean): boolean;
26
29
  compose(rhs: OTResourceBase): void;
30
+ tryCompose(rhs: OTResourceBase): boolean;
27
31
  apply(startValue: any): any;
28
32
  minimize(): void;
29
33
  }
@@ -770,6 +770,16 @@ export class OTArrayLikeResource extends OT.OTResourceBase
770
770
  this.coalesce();
771
771
  }
772
772
 
773
+ tryCompose(rhs: OTArrayLikeResource): boolean
774
+ {
775
+ if (this.length == 0)
776
+ return true;
777
+ else if (rhs.edits.length == 0)
778
+ return true;
779
+
780
+ return this.finalLength() == rhs.originalLength();
781
+ }
782
+
773
783
  performTransformReorder(bForceRetainBeforeInsert: boolean, newA: OTEdits, iBegin: number, iEnd: number): void
774
784
  {
775
785
  if (iBegin < 0 || iBegin > iEnd) return;
@@ -835,6 +845,14 @@ export class OTArrayLikeResource extends OT.OTResourceBase
835
845
  this.edits = newA;
836
846
  }
837
847
 
848
+ tryTransform(prior: OTArrayLikeResource, bPriorIsService: boolean): boolean
849
+ {
850
+ if (this.length == 0 || prior.length == 0)
851
+ return true;
852
+
853
+ return this.originalLength() == prior.originalLength();
854
+ }
855
+
838
856
  transform(prior: OTArrayLikeResource, bPriorIsService: boolean): void
839
857
  {
840
858
  if (this.length == 0 || prior.length == 0)
@@ -133,6 +133,21 @@ export class OTCompositeResource extends OT.OTResourceBase
133
133
  }
134
134
  }
135
135
 
136
+ tryTransform(rhs: OTCompositeResource, bPriorIsService: boolean): boolean
137
+ {
138
+ let bSucceed = true;
139
+
140
+ for (let i: number = 0; bSucceed && i < rhs.length; i++)
141
+ {
142
+ let rhsEdit: OT.IOTResource = rhs.edits[i];
143
+ let lhsEdit: OT.IOTResource = this.findResource(rhsEdit.resourceName, rhsEdit.underlyingType, false);
144
+ if (lhsEdit)
145
+ bSucceed = lhsEdit.tryTransform(rhsEdit, bPriorIsService);
146
+ }
147
+
148
+ return bSucceed;
149
+ }
150
+
136
151
  // compose two edit actions
137
152
  compose(rhs: OTCompositeResource): void // throws on error
138
153
  {
@@ -149,6 +164,21 @@ export class OTCompositeResource extends OT.OTResourceBase
149
164
  this.clientSequenceNo = rhs.clientSequenceNo;
150
165
  }
151
166
 
167
+ tryCompose(rhs: OTCompositeResource): boolean
168
+ {
169
+ let bSucceed = true;
170
+ for (let i: number = 0; bSucceed && i < rhs.length; i++)
171
+ {
172
+ let rhsEdit: OT.IOTResource = rhs.edits[i];
173
+
174
+ let lhsEdit: OT.IOTResource = this.findResource(rhsEdit.resourceName, rhsEdit.underlyingType, !rhsEdit.isEmpty());
175
+ if (lhsEdit)
176
+ bSucceed = lhsEdit.tryCompose(rhsEdit);
177
+ }
178
+
179
+ return bSucceed;
180
+ }
181
+
152
182
  // apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
153
183
  // For composite, takes array of values, returns array of results, one for each underlying resource.
154
184
  apply(runningValue: any): any
@@ -245,11 +245,47 @@ export class OTServerEngine extends OTE.OTEngine
245
245
  for (i++; i < this.logServer.length; i++)
246
246
  aPrior.compose(this.logServer[i]);
247
247
 
248
+ if (! a.tryTransform(aPrior, true))
249
+ {
250
+ console.log('otserverengine: rejecting event on transform failure');
251
+ this.forgetEvents(orig);
252
+ return OTS.EClockReset;
253
+ }
254
+
248
255
  a.transform(aPrior, true);
249
256
  }
250
257
 
258
+ let bFail = ! this.stateServer.tryCompose(a);
259
+ if (bFail)
260
+ {
261
+ console.log('otserverengine: rejecting event on compose failure');
262
+ if (this.logServer.length)
263
+ {
264
+ let newState = this.logServer[0].copy();
265
+ for (let i = 1; i < this.logServer.length; i++)
266
+ newState.compose(this.logServer[i]);
267
+ if (newState.tryCompose(a))
268
+ {
269
+ console.log('otserverengine: actually... rejected event would succeed on composed log, so patching');
270
+ this.stateServer = newState;
271
+ bFail = false;
272
+ }
273
+ else
274
+ console.log('otserverengine: and... rejected event also fails on composed log');
275
+ }
276
+ else
277
+ console.log('otserverengine: and... no log to try to patch state with');
278
+
279
+ if (bFail)
280
+ {
281
+ this.forgetEvents(orig);
282
+ return OTS.EClockReset;
283
+ }
284
+ }
285
+
251
286
  a.clock = this.stateServer.clock + 1;
252
287
  this.stateServer.compose(a);
288
+
253
289
  this.resetCaches();
254
290
  this.emit('state');
255
291
  this.logServer.push(a.copy());
@@ -20,9 +20,14 @@ export interface IOTResource
20
20
  // Core OT algorithm for this type
21
21
  transform(rhs: IOTResource, bPriorIsService: boolean): void; // throws on error
22
22
 
23
+ tryTransform(rhs: IOTResource, bPriorIsService: boolean): boolean;
24
+
23
25
  // compose two edit actions
24
26
  compose(rhs: IOTResource): void; // throws on error
25
27
 
28
+ // tests if compose would succeed, false on failure to prevent throwing during compose and leaving in partial state
29
+ tryCompose(rhs: IOTResource): boolean
30
+
26
31
  // apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
27
32
  apply(startValue: any): any;
28
33
 
@@ -79,12 +84,24 @@ export class OTResourceBase implements IOTResource
79
84
  throw "OTResourceBase.transform must be overridden in subclass";
80
85
  }
81
86
 
87
+ // Test if transform would succeed, false on failure
88
+ tryTransform(rhs: OTResourceBase, bPriorIsServer: boolean): boolean
89
+ {
90
+ return true;
91
+ }
92
+
82
93
  // compose two edit actions
83
94
  compose(rhs: OTResourceBase): void
84
95
  {
85
96
  throw "OTResourceBase.compose must be overridden in subclass";
86
97
  }
87
98
 
99
+ // test compose
100
+ tryCompose(rhs: OTResourceBase): boolean
101
+ {
102
+ return true;
103
+ }
104
+
88
105
  // apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
89
106
  apply(startValue: any): any
90
107
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.122",
3
+ "version": "1.0.123",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",