@dra2020/baseclient 1.0.122 → 1.0.124
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/LICENSE +433 -21
- package/dist/baseclient.js +105 -77
- package/dist/baseclient.js.map +1 -1
- package/dist/fsm/fsm.d.ts +3 -4
- package/dist/ot-js/otarray.d.ts +2 -0
- package/dist/ot-js/otcomposite.d.ts +2 -0
- package/dist/ot-js/ottypes.d.ts +4 -0
- package/lib/fsm/fsm.ts +80 -124
- package/lib/ot-js/otarray.ts +18 -0
- package/lib/ot-js/otcomposite.ts +30 -0
- package/lib/ot-js/otserverengine.ts +36 -0
- package/lib/ot-js/ottypes.ts +17 -0
- package/package.json +1 -1
package/dist/baseclient.js
CHANGED
|
@@ -1921,12 +1921,12 @@ class FsmManager {
|
|
|
1921
1921
|
this.theId = 0;
|
|
1922
1922
|
this.theEpoch = 0;
|
|
1923
1923
|
this.bTickSet = false;
|
|
1924
|
-
this.theTickList =
|
|
1924
|
+
this.theTickList = new Set();
|
|
1925
1925
|
this.theBusyLoopCount = 0;
|
|
1926
1926
|
this.doTick = this.doTick.bind(this);
|
|
1927
1927
|
}
|
|
1928
1928
|
forceTick(fsm) {
|
|
1929
|
-
this.theTickList
|
|
1929
|
+
this.theTickList.add(fsm);
|
|
1930
1930
|
if (!this.bTickSet) {
|
|
1931
1931
|
this.bTickSet = true;
|
|
1932
1932
|
doLater(this.doTick);
|
|
@@ -1935,18 +1935,13 @@ class FsmManager {
|
|
|
1935
1935
|
doTick() {
|
|
1936
1936
|
this.bTickSet = false;
|
|
1937
1937
|
let nLoops = 0;
|
|
1938
|
-
while (nLoops < 1 &&
|
|
1938
|
+
while (nLoops < 1 && this.theTickList.size > 0) {
|
|
1939
1939
|
nLoops++;
|
|
1940
1940
|
let thisTickList = this.theTickList;
|
|
1941
|
-
this.theTickList =
|
|
1942
|
-
|
|
1943
|
-
if (thisTickList.hasOwnProperty(id)) {
|
|
1944
|
-
let f = thisTickList[id];
|
|
1945
|
-
f.preTick();
|
|
1946
|
-
f.tick();
|
|
1947
|
-
}
|
|
1941
|
+
this.theTickList = new Set();
|
|
1942
|
+
thisTickList.forEach((f) => f.tick());
|
|
1948
1943
|
}
|
|
1949
|
-
if (
|
|
1944
|
+
if (this.theTickList.size == 0)
|
|
1950
1945
|
this.theBusyLoopCount = 0;
|
|
1951
1946
|
else
|
|
1952
1947
|
this.theBusyLoopCount++;
|
|
@@ -1961,49 +1956,28 @@ class Fsm {
|
|
|
1961
1956
|
this.state = exports.FSM_STARTING;
|
|
1962
1957
|
this.dependentError = false;
|
|
1963
1958
|
this.epochDone = -1;
|
|
1964
|
-
this._waitOn =
|
|
1965
|
-
this._waitedOn =
|
|
1959
|
+
this._waitOn = new Set();
|
|
1960
|
+
this._waitedOn = new Set();
|
|
1966
1961
|
this.manager.forceTick(this);
|
|
1967
1962
|
}
|
|
1968
1963
|
get env() { return this._env; }
|
|
1969
1964
|
get manager() { return this.env.fsmManager; }
|
|
1970
|
-
get done() {
|
|
1971
|
-
|
|
1972
|
-
}
|
|
1973
|
-
get
|
|
1974
|
-
|
|
1975
|
-
}
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
}
|
|
1979
|
-
get
|
|
1980
|
-
|
|
1981
|
-
}
|
|
1982
|
-
cancel() {
|
|
1983
|
-
// Override if you need to do more than marking complete
|
|
1984
|
-
this.setState(exports.FSM_CANCEL);
|
|
1985
|
-
}
|
|
1986
|
-
setDependentError() {
|
|
1987
|
-
this.dependentError = true;
|
|
1988
|
-
}
|
|
1989
|
-
clearDependentError() {
|
|
1990
|
-
this.dependentError = false;
|
|
1991
|
-
}
|
|
1992
|
-
get ticked() {
|
|
1993
|
-
return this.done && this.manager.theEpoch > this.epochDone;
|
|
1994
|
-
}
|
|
1995
|
-
get nWaitOn() {
|
|
1996
|
-
return Util.countKeys(this._waitOn);
|
|
1997
|
-
}
|
|
1998
|
-
get nWaitedOn() {
|
|
1999
|
-
return Util.countKeys(this._waitedOn);
|
|
2000
|
-
}
|
|
1965
|
+
get done() { return FsmDone(this.state); }
|
|
1966
|
+
get ready() { return !this.done && this.nWaitOn == 0; }
|
|
1967
|
+
get iserror() { return this.state === exports.FSM_ERROR || this.state === exports.FSM_CANCEL; }
|
|
1968
|
+
get isDependentError() { return this.dependentError; }
|
|
1969
|
+
// Override if you need to do more than marking complete
|
|
1970
|
+
cancel() { this.setState(exports.FSM_CANCEL); }
|
|
1971
|
+
setDependentError() { this.dependentError = true; }
|
|
1972
|
+
clearDependentError() { this.dependentError = false; }
|
|
1973
|
+
get ticked() { return this.done && this.manager.theEpoch > this.epochDone; }
|
|
1974
|
+
get nWaitOn() { return this._waitOn.size; }
|
|
1975
|
+
get nWaitedOn() { return this._waitedOn.size; }
|
|
2001
1976
|
waitOn(fsm) {
|
|
2002
1977
|
if (fsm == null)
|
|
2003
1978
|
return this;
|
|
2004
1979
|
else if (Array.isArray(fsm)) {
|
|
2005
|
-
|
|
2006
|
-
this.waitOn(fsm[i]);
|
|
1980
|
+
fsm.forEach((f) => this.waitOn(f));
|
|
2007
1981
|
}
|
|
2008
1982
|
else {
|
|
2009
1983
|
if (fsm.done) {
|
|
@@ -2015,12 +1989,8 @@ class Fsm {
|
|
|
2015
1989
|
this.setDependentError();
|
|
2016
1990
|
}
|
|
2017
1991
|
else {
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
this._waitOn[fsm.id] = fsm;
|
|
2021
|
-
if (fsm._waitedOn == null)
|
|
2022
|
-
fsm._waitedOn = {};
|
|
2023
|
-
fsm._waitedOn[this.id] = this;
|
|
1992
|
+
this._waitOn.add(fsm);
|
|
1993
|
+
fsm._waitedOn.add(this);
|
|
2024
1994
|
}
|
|
2025
1995
|
}
|
|
2026
1996
|
return this;
|
|
@@ -2028,16 +1998,11 @@ class Fsm {
|
|
|
2028
1998
|
setState(state) {
|
|
2029
1999
|
this.state = state;
|
|
2030
2000
|
if (this.done) {
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
this._waitedOn
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
let f = on[id];
|
|
2037
|
-
if (this.iserror)
|
|
2038
|
-
f.setDependentError();
|
|
2039
|
-
this.manager.forceTick(f);
|
|
2040
|
-
}
|
|
2001
|
+
// Loop because completion might add more to wait list
|
|
2002
|
+
while (this.nWaitedOn) {
|
|
2003
|
+
let waitedOn = this._waitedOn;
|
|
2004
|
+
this._waitedOn = new Set();
|
|
2005
|
+
waitedOn.forEach((f) => { f._completed(this); this.manager.forceTick(f); });
|
|
2041
2006
|
}
|
|
2042
2007
|
this.epochDone = this.manager.theEpoch;
|
|
2043
2008
|
}
|
|
@@ -2047,21 +2012,17 @@ class Fsm {
|
|
|
2047
2012
|
end(state = exports.FSM_DONE) {
|
|
2048
2013
|
this.setState(state);
|
|
2049
2014
|
}
|
|
2050
|
-
//
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
bMore = true;
|
|
2062
|
-
}
|
|
2063
|
-
if (!bMore)
|
|
2064
|
-
this._waitOn = null;
|
|
2015
|
+
// Override if subclass needs to respond to individual items completing rather than waiting
|
|
2016
|
+
// in tick. Useful to avoid O(n^2) if waiting on lots of items and not wanting to do a linear
|
|
2017
|
+
// scan for completed FSMs. Or to not require separate bookkeeping for list of dependents.
|
|
2018
|
+
waitOnCompleted(f) { }
|
|
2019
|
+
_completed(f) {
|
|
2020
|
+
if (f.iserror)
|
|
2021
|
+
this.setDependentError();
|
|
2022
|
+
if (f.done && this._waitOn.has(f)) {
|
|
2023
|
+
this._waitOn.delete(f);
|
|
2024
|
+
this.waitOnCompleted(f);
|
|
2025
|
+
}
|
|
2065
2026
|
}
|
|
2066
2027
|
tick() {
|
|
2067
2028
|
}
|
|
@@ -4366,6 +4327,13 @@ class OTArrayLikeResource extends OT.OTResourceBase {
|
|
|
4366
4327
|
this.edits = newA;
|
|
4367
4328
|
this.coalesce();
|
|
4368
4329
|
}
|
|
4330
|
+
tryCompose(rhs) {
|
|
4331
|
+
if (this.length == 0)
|
|
4332
|
+
return true;
|
|
4333
|
+
else if (rhs.edits.length == 0)
|
|
4334
|
+
return true;
|
|
4335
|
+
return this.finalLength() == rhs.originalLength();
|
|
4336
|
+
}
|
|
4369
4337
|
performTransformReorder(bForceRetainBeforeInsert, newA, iBegin, iEnd) {
|
|
4370
4338
|
if (iBegin < 0 || iBegin > iEnd)
|
|
4371
4339
|
return;
|
|
@@ -4421,6 +4389,11 @@ class OTArrayLikeResource extends OT.OTResourceBase {
|
|
|
4421
4389
|
(newA[i])[0] = exports.OpRetain;
|
|
4422
4390
|
this.edits = newA;
|
|
4423
4391
|
}
|
|
4392
|
+
tryTransform(prior, bPriorIsService) {
|
|
4393
|
+
if (this.length == 0 || prior.length == 0)
|
|
4394
|
+
return true;
|
|
4395
|
+
return this.originalLength() == prior.originalLength();
|
|
4396
|
+
}
|
|
4424
4397
|
transform(prior, bPriorIsService) {
|
|
4425
4398
|
if (this.length == 0 || prior.length == 0)
|
|
4426
4399
|
return;
|
|
@@ -5101,6 +5074,16 @@ class OTCompositeResource extends OT.OTResourceBase {
|
|
|
5101
5074
|
lhsEdit.transform(rhsEdit, bPriorIsService);
|
|
5102
5075
|
}
|
|
5103
5076
|
}
|
|
5077
|
+
tryTransform(rhs, bPriorIsService) {
|
|
5078
|
+
let bSucceed = true;
|
|
5079
|
+
for (let i = 0; bSucceed && i < rhs.length; i++) {
|
|
5080
|
+
let rhsEdit = rhs.edits[i];
|
|
5081
|
+
let lhsEdit = this.findResource(rhsEdit.resourceName, rhsEdit.underlyingType, false);
|
|
5082
|
+
if (lhsEdit)
|
|
5083
|
+
bSucceed = lhsEdit.tryTransform(rhsEdit, bPriorIsService);
|
|
5084
|
+
}
|
|
5085
|
+
return bSucceed;
|
|
5086
|
+
}
|
|
5104
5087
|
// compose two edit actions
|
|
5105
5088
|
compose(rhs) {
|
|
5106
5089
|
for (let i = 0; i < rhs.length; i++) {
|
|
@@ -5112,6 +5095,16 @@ class OTCompositeResource extends OT.OTResourceBase {
|
|
|
5112
5095
|
this.clock = rhs.clock;
|
|
5113
5096
|
this.clientSequenceNo = rhs.clientSequenceNo;
|
|
5114
5097
|
}
|
|
5098
|
+
tryCompose(rhs) {
|
|
5099
|
+
let bSucceed = true;
|
|
5100
|
+
for (let i = 0; bSucceed && i < rhs.length; i++) {
|
|
5101
|
+
let rhsEdit = rhs.edits[i];
|
|
5102
|
+
let lhsEdit = this.findResource(rhsEdit.resourceName, rhsEdit.underlyingType, !rhsEdit.isEmpty());
|
|
5103
|
+
if (lhsEdit)
|
|
5104
|
+
bSucceed = lhsEdit.tryCompose(rhsEdit);
|
|
5105
|
+
}
|
|
5106
|
+
return bSucceed;
|
|
5107
|
+
}
|
|
5115
5108
|
// apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
|
|
5116
5109
|
// For composite, takes array of values, returns array of results, one for each underlying resource.
|
|
5117
5110
|
apply(runningValue) {
|
|
@@ -5718,8 +5711,35 @@ class OTServerEngine extends OTE.OTEngine {
|
|
|
5718
5711
|
let aPrior = this.logServer[i].copy();
|
|
5719
5712
|
for (i++; i < this.logServer.length; i++)
|
|
5720
5713
|
aPrior.compose(this.logServer[i]);
|
|
5714
|
+
if (!a.tryTransform(aPrior, true)) {
|
|
5715
|
+
console.log('otserverengine: rejecting event on transform failure');
|
|
5716
|
+
this.forgetEvents(orig);
|
|
5717
|
+
return OTS.EClockReset;
|
|
5718
|
+
}
|
|
5721
5719
|
a.transform(aPrior, true);
|
|
5722
5720
|
}
|
|
5721
|
+
let bFail = !this.stateServer.tryCompose(a);
|
|
5722
|
+
if (bFail) {
|
|
5723
|
+
console.log('otserverengine: rejecting event on compose failure');
|
|
5724
|
+
if (this.logServer.length) {
|
|
5725
|
+
let newState = this.logServer[0].copy();
|
|
5726
|
+
for (let i = 1; i < this.logServer.length; i++)
|
|
5727
|
+
newState.compose(this.logServer[i]);
|
|
5728
|
+
if (newState.tryCompose(a)) {
|
|
5729
|
+
console.log('otserverengine: actually... rejected event would succeed on composed log, so patching');
|
|
5730
|
+
this.stateServer = newState;
|
|
5731
|
+
bFail = false;
|
|
5732
|
+
}
|
|
5733
|
+
else
|
|
5734
|
+
console.log('otserverengine: and... rejected event also fails on composed log');
|
|
5735
|
+
}
|
|
5736
|
+
else
|
|
5737
|
+
console.log('otserverengine: and... no log to try to patch state with');
|
|
5738
|
+
if (bFail) {
|
|
5739
|
+
this.forgetEvents(orig);
|
|
5740
|
+
return OTS.EClockReset;
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5723
5743
|
a.clock = this.stateServer.clock + 1;
|
|
5724
5744
|
this.stateServer.compose(a);
|
|
5725
5745
|
this.resetCaches();
|
|
@@ -5933,10 +5953,18 @@ class OTResourceBase {
|
|
|
5933
5953
|
transform(rhs, bPriorIsService) {
|
|
5934
5954
|
throw "OTResourceBase.transform must be overridden in subclass";
|
|
5935
5955
|
}
|
|
5956
|
+
// Test if transform would succeed, false on failure
|
|
5957
|
+
tryTransform(rhs, bPriorIsServer) {
|
|
5958
|
+
return true;
|
|
5959
|
+
}
|
|
5936
5960
|
// compose two edit actions
|
|
5937
5961
|
compose(rhs) {
|
|
5938
5962
|
throw "OTResourceBase.compose must be overridden in subclass";
|
|
5939
5963
|
}
|
|
5964
|
+
// test compose
|
|
5965
|
+
tryCompose(rhs) {
|
|
5966
|
+
return true;
|
|
5967
|
+
}
|
|
5940
5968
|
// apply this edit to an existing value, returning new value (if underlying type is mutable, may modify input)
|
|
5941
5969
|
apply(startValue) {
|
|
5942
5970
|
throw "OTResourceBase.apply must be overridden in subclass";
|