fixing double late join test fail
This commit is contained in:
parent
f609c22be8
commit
77b83cae2a
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@ adaptConnector = function(connector, engine, HB, execution_listener) {
|
||||
}
|
||||
connector.setIsBoundToY();
|
||||
send_ = function(o) {
|
||||
if ((o.uid.creator === HB.getUserId()) && (typeof o.uid.op_number !== "string") && (o.uid.doSync === "true" || o.uid.doSync === true) && (HB.getUserId() !== "_temp")) {
|
||||
if ((o.uid.creator === HB.getUserId()) && (typeof o.uid.op_number !== "string") && (HB.getUserId() !== "_temp")) {
|
||||
return connector.broadcast(o);
|
||||
}
|
||||
};
|
||||
|
@ -105,13 +105,13 @@ module.exports = {
|
||||
/*
|
||||
* Broadcast a message to all connected peers.
|
||||
* @param message {Object} The message to broadcast.
|
||||
*
|
||||
#
|
||||
broadcast: (message)->
|
||||
throw new Error "You must implement broadcast!"
|
||||
|
||||
*
|
||||
#
|
||||
* Send a message to a peer, or set of peers
|
||||
*
|
||||
#
|
||||
send: (peer_s, message)->
|
||||
throw new Error "You must implement send!"
|
||||
*/
|
||||
|
@ -13,9 +13,9 @@ if (typeof window !== "undefined" && window !== null) {
|
||||
}
|
||||
|
||||
Engine = (function() {
|
||||
function Engine(HB, types) {
|
||||
this.HB = HB;
|
||||
this.types = types;
|
||||
function Engine(_at_HB, _at_types) {
|
||||
this.HB = _at_HB;
|
||||
this.types = _at_types;
|
||||
this.unprocessed_ops = [];
|
||||
}
|
||||
|
||||
@ -73,6 +73,7 @@ Engine = (function() {
|
||||
op_json.fromHB = "true";
|
||||
}
|
||||
o = this.parseOperation(op_json);
|
||||
o.parsed_from_json = op_json;
|
||||
if (op_json.fromHB != null) {
|
||||
o.fromHB = op_json.fromHB;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ var HistoryBuffer,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
HistoryBuffer = (function() {
|
||||
function HistoryBuffer(user_id) {
|
||||
this.user_id = user_id;
|
||||
function HistoryBuffer(_at_user_id) {
|
||||
this.user_id = _at_user_id;
|
||||
this.emptyGarbage = __bind(this.emptyGarbage, this);
|
||||
this.operation_counter = {};
|
||||
this.buffer = {};
|
||||
@ -92,15 +92,14 @@ HistoryBuffer = (function() {
|
||||
return this.garbageCollectTimeoutId = void 0;
|
||||
};
|
||||
|
||||
HistoryBuffer.prototype.setGarbageCollectTimeout = function(garbageCollectTimeout) {
|
||||
this.garbageCollectTimeout = garbageCollectTimeout;
|
||||
HistoryBuffer.prototype.setGarbageCollectTimeout = function(_at_garbageCollectTimeout) {
|
||||
this.garbageCollectTimeout = _at_garbageCollectTimeout;
|
||||
};
|
||||
|
||||
HistoryBuffer.prototype.getReservedUniqueIdentifier = function() {
|
||||
return {
|
||||
creator: '_',
|
||||
op_number: "_" + (this.reserved_identifier_counter++),
|
||||
doSync: false
|
||||
op_number: "_" + (this.reserved_identifier_counter++)
|
||||
};
|
||||
};
|
||||
|
||||
@ -143,9 +142,12 @@ HistoryBuffer = (function() {
|
||||
_ref = this.buffer;
|
||||
for (u_name in _ref) {
|
||||
user = _ref[u_name];
|
||||
if (u_name === "_") {
|
||||
continue;
|
||||
}
|
||||
for (o_number in user) {
|
||||
o = user[o_number];
|
||||
if ((o.uid.noOperation == null) && o.uid.doSync && unknown(u_name, o_number)) {
|
||||
if ((o.uid.noOperation == null) && unknown(u_name, o_number)) {
|
||||
o_json = o._encode();
|
||||
if (o.next_cl != null) {
|
||||
o_next = o.next_cl;
|
||||
@ -177,8 +179,7 @@ HistoryBuffer = (function() {
|
||||
}
|
||||
uid = {
|
||||
'creator': user_id,
|
||||
'op_number': this.operation_counter[user_id],
|
||||
'doSync': true
|
||||
'op_number': this.operation_counter[user_id]
|
||||
};
|
||||
this.operation_counter[user_id]++;
|
||||
return uid;
|
||||
@ -238,15 +239,18 @@ HistoryBuffer = (function() {
|
||||
};
|
||||
|
||||
HistoryBuffer.prototype.addToCounter = function(o) {
|
||||
if (this.operation_counter[o.uid.creator] == null) {
|
||||
this.operation_counter[o.uid.creator] = 0;
|
||||
var _base, _name;
|
||||
if ((_base = this.operation_counter)[_name = o.uid.creator] == null) {
|
||||
_base[_name] = 0;
|
||||
}
|
||||
if (typeof o.uid.op_number === 'number' && o.uid.creator !== this.getUserId()) {
|
||||
if (o.uid.creator !== this.getUserId()) {
|
||||
if (o.uid.op_number === this.operation_counter[o.uid.creator]) {
|
||||
return this.operation_counter[o.uid.creator]++;
|
||||
} else {
|
||||
return this.invokeSync(o.uid.creator);
|
||||
this.operation_counter[o.uid.creator]++;
|
||||
}
|
||||
while (this.buffer[o.uid.creator][this.operation_counter[o.uid.creator]] != null) {
|
||||
this.operation_counter[o.uid.creator]++;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
var __slice = [].slice,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
module.exports = function(HB) {
|
||||
var execution_listener, types;
|
||||
@ -79,8 +79,8 @@ module.exports = function(HB) {
|
||||
return this.deleteAllObservers();
|
||||
};
|
||||
|
||||
Operation.prototype.setParent = function(parent) {
|
||||
this.parent = parent;
|
||||
Operation.prototype.setParent = function(_at_parent) {
|
||||
this.parent = _at_parent;
|
||||
};
|
||||
|
||||
Operation.prototype.getParent = function() {
|
||||
@ -95,7 +95,6 @@ module.exports = function(HB) {
|
||||
if (this.uid.alt != null) {
|
||||
map_uid = this.uid.alt.cloneUid();
|
||||
map_uid.sub = this.uid.sub;
|
||||
map_uid.doSync = false;
|
||||
return map_uid;
|
||||
} else {
|
||||
return void 0;
|
||||
@ -114,10 +113,6 @@ module.exports = function(HB) {
|
||||
return uid;
|
||||
};
|
||||
|
||||
Operation.prototype.dontSync = function() {
|
||||
return this.uid.doSync = false;
|
||||
};
|
||||
|
||||
Operation.prototype.execute = function() {
|
||||
var l, _i, _len;
|
||||
this.is_executed = true;
|
||||
@ -135,7 +130,7 @@ module.exports = function(HB) {
|
||||
};
|
||||
|
||||
Operation.prototype.saveOperation = function(name, op) {
|
||||
if ((op != null ? op.execute : void 0) != null) {
|
||||
if (((op != null ? op.execute : void 0) != null) || typeof op === "string") {
|
||||
return this[name] = op;
|
||||
} else if (op != null) {
|
||||
if (this.unchecked == null) {
|
||||
@ -296,6 +291,8 @@ module.exports = function(HB) {
|
||||
this.prev_cl = this.parent.beginning;
|
||||
}
|
||||
if (this.origin == null) {
|
||||
this.origin = this.prev_cl;
|
||||
} else if (this.origin === "Delimiter") {
|
||||
this.origin = this.parent.beginning;
|
||||
}
|
||||
if (this.next_cl == null) {
|
||||
@ -389,8 +386,8 @@ module.exports = function(HB) {
|
||||
types.ImmutableObject = (function(_super) {
|
||||
__extends(ImmutableObject, _super);
|
||||
|
||||
function ImmutableObject(uid, content) {
|
||||
this.content = content;
|
||||
function ImmutableObject(uid, _at_content) {
|
||||
this.content = _at_content;
|
||||
ImmutableObject.__super__.constructor.call(this, uid);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
var text_types_uninitialized,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
text_types_uninitialized = require("./TextTypes");
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
var basic_types_uninitialized,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
basic_types_uninitialized = require("./BasicTypes");
|
||||
|
||||
@ -159,9 +159,9 @@ module.exports = function(HB) {
|
||||
types.ReplaceManager = (function(_super) {
|
||||
__extends(ReplaceManager, _super);
|
||||
|
||||
function ReplaceManager(event_properties, event_this, uid, beginning, end) {
|
||||
this.event_properties = event_properties;
|
||||
this.event_this = event_this;
|
||||
function ReplaceManager(_at_event_properties, _at_event_this, uid, beginning, end) {
|
||||
this.event_properties = _at_event_properties;
|
||||
this.event_this = _at_event_this;
|
||||
if (this.event_properties['object'] == null) {
|
||||
this.event_properties['object'] = this.event_this;
|
||||
}
|
||||
@ -326,10 +326,14 @@ module.exports = function(HB) {
|
||||
'parent': this.parent.getUid(),
|
||||
'prev': this.prev_cl.getUid(),
|
||||
'next': this.next_cl.getUid(),
|
||||
'origin': this.origin.getUid(),
|
||||
'uid': this.getUid(),
|
||||
'is_deleted': this.is_deleted
|
||||
};
|
||||
if (this.origin.type === "Delimiter") {
|
||||
json.origin = "Delimiter";
|
||||
} else if (this.origin !== this.prev_cl) {
|
||||
json.origin = this.origin.getUid();
|
||||
}
|
||||
if (this.content instanceof types.Operation) {
|
||||
json['content'] = this.content.getUid();
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
var structured_types_uninitialized,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
structured_types_uninitialized = require("./StructuredTypes");
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
var Engine, HistoryBuffer, adaptConnector, createY, json_types_uninitialized,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
json_types_uninitialized = require("./Types/JsonTypes");
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -76,8 +76,8 @@ gulp.task 'build_node', ->
|
||||
|
||||
gulp.task 'build', ['build_node', 'build_browser'], ->
|
||||
|
||||
gulp.task 'watch', ['build_browser'], ->
|
||||
gulp.watch files.all, ['build_browser']
|
||||
gulp.task 'watch', ['build'], ->
|
||||
gulp.watch files.all, ['build']
|
||||
|
||||
gulp.task 'mocha', ->
|
||||
gulp.src files.test, { read: false }
|
||||
|
@ -15,7 +15,6 @@ adaptConnector = (connector, engine, HB, execution_listener)->
|
||||
send_ = (o)->
|
||||
if (o.uid.creator is HB.getUserId()) and
|
||||
(typeof o.uid.op_number isnt "string") and # TODO: i don't think that we need this anymore..
|
||||
(o.uid.doSync is "true" or o.uid.doSync is true) and # TODO: ensure, that only true is valid
|
||||
(HB.getUserId() isnt "_temp")
|
||||
connector.broadcast o
|
||||
|
||||
|
@ -66,9 +66,10 @@ class Engine
|
||||
op_json_array = [op_json_array]
|
||||
for op_json in op_json_array
|
||||
if fromHB
|
||||
op_json.fromHB = "true" # execute immediately, if
|
||||
op_json.fromHB = "true" # execute immediately, if
|
||||
# $parse_and_execute will return false if $o_json was parsed and executed, otherwise the parsed operadion
|
||||
o = @parseOperation op_json
|
||||
o.parsed_from_json = op_json
|
||||
if op_json.fromHB?
|
||||
o.fromHB = op_json.fromHB
|
||||
# @HB.addOperation o
|
||||
|
@ -84,7 +84,6 @@ class HistoryBuffer
|
||||
{
|
||||
creator : '_'
|
||||
op_number : "_#{@reserved_identifier_counter++}"
|
||||
doSync: false
|
||||
}
|
||||
|
||||
#
|
||||
@ -116,8 +115,10 @@ class HistoryBuffer
|
||||
|
||||
for u_name,user of @buffer
|
||||
# TODO next, if @state_vector[user] <= state_vector[user]
|
||||
if u_name is "_"
|
||||
continue
|
||||
for o_number,o of user
|
||||
if (not o.uid.noOperation?) and o.uid.doSync and unknown(u_name, o_number)
|
||||
if (not o.uid.noOperation?) and unknown(u_name, o_number)
|
||||
# its necessary to send it, and not known in state_vector
|
||||
o_json = o._encode()
|
||||
if o.next_cl? # applies for all ops but the most right delimiter!
|
||||
@ -149,7 +150,6 @@ class HistoryBuffer
|
||||
uid =
|
||||
'creator' : user_id
|
||||
'op_number' : @operation_counter[user_id]
|
||||
'doSync' : true
|
||||
@operation_counter[user_id]++
|
||||
uid
|
||||
|
||||
@ -206,14 +206,14 @@ class HistoryBuffer
|
||||
# Increment the operation_counter that defines the current state of the Engine.
|
||||
#
|
||||
addToCounter: (o)->
|
||||
if not @operation_counter[o.uid.creator]?
|
||||
@operation_counter[o.uid.creator] = 0
|
||||
if typeof o.uid.op_number is 'number' and o.uid.creator isnt @getUserId()
|
||||
@operation_counter[o.uid.creator] ?= 0
|
||||
if o.uid.creator isnt @getUserId()
|
||||
# TODO: check if operations are send in order
|
||||
if o.uid.op_number is @operation_counter[o.uid.creator]
|
||||
@operation_counter[o.uid.creator]++
|
||||
else
|
||||
@invokeSync o.uid.creator
|
||||
while @buffer[o.uid.creator][@operation_counter[o.uid.creator]]?
|
||||
@operation_counter[o.uid.creator]++
|
||||
undefined
|
||||
|
||||
#if @operation_counter[o.uid.creator] isnt (o.uid.op_number + 1)
|
||||
#console.log (@operation_counter[o.uid.creator] - (o.uid.op_number + 1))
|
||||
|
@ -114,7 +114,6 @@ module.exports = (HB)->
|
||||
if @uid.alt? # could be (safely) undefined
|
||||
map_uid = @uid.alt.cloneUid()
|
||||
map_uid.sub = @uid.sub
|
||||
map_uid.doSync = false
|
||||
map_uid
|
||||
else
|
||||
undefined
|
||||
@ -125,9 +124,6 @@ module.exports = (HB)->
|
||||
uid[n] = v
|
||||
uid
|
||||
|
||||
dontSync: ()->
|
||||
@uid.doSync = false
|
||||
|
||||
#
|
||||
# @private
|
||||
# If not already done, set the uid
|
||||
@ -172,8 +168,9 @@ module.exports = (HB)->
|
||||
# We use duck-typing to check if op is instantiated since there
|
||||
# could exist multiple classes of $Operation
|
||||
#
|
||||
if op?.execute?
|
||||
# is instantiated
|
||||
if op?.execute? or typeof op is "string"
|
||||
# is instantiated, or op is string. Currently "Delimiter" is saved as string
|
||||
# (in combination with @parent you can retrieve the delimiter..)
|
||||
@[name] = op
|
||||
else if op?
|
||||
# not initialized. Do it when calling $validateSavedOperations()
|
||||
@ -350,6 +347,8 @@ module.exports = (HB)->
|
||||
if not @prev_cl?
|
||||
@prev_cl = @parent.beginning
|
||||
if not @origin?
|
||||
@origin = @prev_cl
|
||||
else if @origin is "Delimiter"
|
||||
@origin = @parent.beginning
|
||||
if not @next_cl?
|
||||
@next_cl = @parent.end
|
||||
|
@ -320,10 +320,14 @@ module.exports = (HB)->
|
||||
'parent' : @parent.getUid()
|
||||
'prev': @prev_cl.getUid()
|
||||
'next': @next_cl.getUid()
|
||||
'origin' : @origin.getUid()
|
||||
'uid' : @getUid()
|
||||
'is_deleted': @is_deleted
|
||||
}
|
||||
if @origin.type is "Delimiter"
|
||||
json.origin = "Delimiter"
|
||||
else if @origin isnt @prev_cl
|
||||
json.origin = @origin.getUid()
|
||||
|
||||
if @content instanceof types.Operation
|
||||
json['content'] = @content.getUid()
|
||||
else
|
||||
|
@ -36,7 +36,7 @@ class JsonTest extends Test
|
||||
return root
|
||||
|
||||
elems = elems.filter (elem)->
|
||||
(elem.type is "Array") or (elem.type is "Object")
|
||||
elem? and ((elem.type is "Array") or (elem.type is "Object"))
|
||||
if elems.length is 0
|
||||
root
|
||||
else
|
||||
@ -110,10 +110,19 @@ describe "JsonFramework", ->
|
||||
u2 = @yTest.users[1]
|
||||
ops1 = u1.HB._encode()
|
||||
ops2 = u2.HB._encode()
|
||||
u1.HB.renewStateVector u2.HB.getOperationCounter()
|
||||
u2.HB.renewStateVector u1.HB.getOperationCounter()
|
||||
u1.engine.applyOps ops2
|
||||
u2.engine.applyOps ops1
|
||||
u1.engine.applyOp ops2, true
|
||||
u2.engine.applyOp ops1, true
|
||||
compare = (o1, o2)->
|
||||
if o1.type? and o1.type isnt o2.type
|
||||
throw new Error "different types"
|
||||
else if o1.type is "Object"
|
||||
for name, val of o1.val()
|
||||
compare(val, o2.val(name))
|
||||
else if o1.type?
|
||||
compare(o1.val(), o2.val())
|
||||
else if o1 isnt o2
|
||||
throw new Error "different values"
|
||||
compare u1, u2
|
||||
expect(test.getContent(0)).to.deep.equal(@yTest.getContent(1))
|
||||
|
||||
it "can handle creaton of complex json (1)", ->
|
||||
|
@ -13,7 +13,7 @@ module.exports = class Test
|
||||
constructor: (@name_suffix = "")->
|
||||
@number_of_test_cases_multiplier = 1
|
||||
@repeat_this = 3 * @number_of_test_cases_multiplier
|
||||
@doSomething_amount = 123 * @number_of_test_cases_multiplier
|
||||
@doSomething_amount = 1230 * @number_of_test_cases_multiplier
|
||||
@number_of_engines = 5 + @number_of_test_cases_multiplier - 1
|
||||
|
||||
@time = 0 # denotes to the time when run was started
|
||||
@ -36,7 +36,7 @@ module.exports = class Test
|
||||
|
||||
# is called by implementing class
|
||||
makeNewUser: (user)->
|
||||
user.HB.setManualGarbageCollect()
|
||||
user.HB.stopGarbageCollection()
|
||||
user
|
||||
|
||||
getSomeUser: ()->
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user