included connector type

This commit is contained in:
DadaMonad
2015-02-03 18:55:02 +00:00
parent f835a72151
commit 58a479be9b
22 changed files with 2015 additions and 736 deletions

View File

@@ -1,7 +1,13 @@
var adaptConnector;
var ConnectorClass, adaptConnector;
ConnectorClass = require("./ConnectorClass");
adaptConnector = function(connector, engine, HB, execution_listener) {
var applyHB, encode_state_vector, getHB, getStateVector, parse_state_vector, send_;
var applyHB, encode_state_vector, f, getHB, getStateVector, name, parse_state_vector, send_;
for (name in ConnectorClass) {
f = ConnectorClass[name];
connector[name] = f;
}
send_ = function(o) {
if (o.uid.creator === HB.getUserId() && (typeof o.uid.op_number !== "string")) {
return connector.broadcast(o);
@@ -12,7 +18,7 @@ adaptConnector = function(connector, engine, HB, execution_listener) {
}
execution_listener.push(send_);
encode_state_vector = function(v) {
var name, value, _results;
var value, _results;
_results = [];
for (name in v) {
value = v[name];
@@ -55,6 +61,7 @@ adaptConnector = function(connector, engine, HB, execution_listener) {
connector.getStateVector = getStateVector;
connector.getHB = getHB;
connector.applyHB = applyHB;
connector.receive_handlers = [];
connector.receive_handlers.push(function(sender, op) {
if (op.uid.creator !== HB.getUserId()) {
return engine.applyOp(op);

View File

@@ -0,0 +1,304 @@
module.exports = {
init: function(options) {
var req;
req = (function(_this) {
return function(name, choices) {
if (options[name] != null) {
if ((choices == null) || choices.some(function(c) {
return c === options[name];
})) {
return _this[name] = options[name];
} else {
throw new Error("You can set the '" + name + "' option to one of the following choices: " + JSON.encode(choices));
}
} else {
throw new Error("You must specify " + name + ", when initializing the Connector!");
}
};
})(this);
req("syncMode", ["syncAll", "master-slave"]);
req("role", ["master", "slave"]);
req("user_id");
this.on_user_id_set(this.user_id);
if (this.role === "master") {
this.syncMode = "syncAll";
}
this.is_synced = false;
this.is_syncing = false;
this.connections = {};
this.is_bound_to_y = false;
this.connections = {};
return this.current_sync_target = null;
},
isRoleMaster: function() {
return this.role === "master";
},
isRoleSlave: function() {
return this.role === "slave";
},
findNewSyncTarget: function() {
var c, user, _ref;
this.current_sync_target = null;
if (this.syncMode === "syncAll") {
_ref = this.connections;
for (user in _ref) {
c = _ref[user];
if (!c.is_synced) {
this.performSync(user);
break;
}
}
}
return null;
},
userLeft: function(user) {
delete this.connections[user];
return this.findNewSyncTarget();
},
userJoined: function(user, role) {
if (role == null) {
throw new Error("Internal: You must specify the role of the joined user!");
}
this.connections[user] = {
is_synced: false
};
if ((!this.is_synced) || this.syncMode === "syncAll") {
if (this.syncMode === "syncAll") {
return this.performSync(user);
} else if (role === "master") {
return this.performSyncWithMaster(user);
}
}
},
whenSynced: function(args) {
if (args.constructore === Function) {
args = [args];
}
if (this.is_synced) {
return args[0].apply(this, args.slice(1));
} else {
if (this.compute_when_synced == null) {
this.compute_when_synced = [];
}
return this.compute_when_synced.push(args);
}
},
onReceive: function(f) {
return this.receive_handlers.push(f);
},
/*
* 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!"
*/
performSync: function(user) {
if (this.current_sync_target == null) {
this.current_sync_target = user;
return this.send(user, {
sync_step: "getHB",
data: this.getStateVector()
});
}
},
performSyncWithMaster: function(user) {
var hb, o, _hb, _i, _len;
if (!this.is_syncing) {
this.current_sync_target = user;
this.is_syncing = true;
this.send(user, {
sync_step: "getHB",
send_again: "true",
data: []
});
hb = this.getHB([]).hb;
_hb = [];
for (_i = 0, _len = hb.length; _i < _len; _i++) {
o = hb[_i];
_hb.push(o);
if (_hb.length > 30) {
this.broadcast({
sync_step: "applyHB_",
data: _hb
});
_hb = [];
}
}
return this.broadcast({
sync_step: "applyHB",
data: _hb
});
}
},
setStateSynced: function() {
var f, _i, _len, _ref;
if (!this.is_synced) {
this.is_synced = true;
_ref = this.compute_when_synced;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
f = _ref[_i];
f();
}
delete this.compute_when_synced;
return null;
}
},
receiveMessage: function(sender, res) {
var data, f, hb, o, send_again, _hb, _i, _j, _len, _len1, _ref, _results;
if (res.sync_step == null) {
_ref = this.receive_handlers;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
f = _ref[_i];
_results.push(f(sender, res));
}
return _results;
} else {
if (res.sync_step === "getHB") {
data = this.getHB(res.data);
hb = data.hb;
_hb = [];
for (_j = 0, _len1 = hb.length; _j < _len1; _j++) {
o = hb[_j];
_hb.push(o);
if (_hb.length > 30) {
this.send(sender, {
sync_step: "applyHB_",
data: _hb
});
_hb = [];
}
}
this.send(sender, {
sync_step: "applyHB",
data: _hb
});
if (res.send_again != null) {
send_again = (function(_this) {
return function(sv) {
return function() {
hb = _this.getHB(sv).hb;
return _this.send(sender, {
sync_step: "applyHB",
data: hb,
sent_again: "true"
});
};
};
})(this)(data.state_vector);
return setTimeout(send_again, 3000);
}
} else if (res.sync_step === "applyHB") {
this.applyHB(res.data);
if ((this.syncMode === "syncAll" || (res.sent_again != null)) && !this.is_synced) {
this.setStateSynced();
this.connections[sender].is_synced = true;
return this.findNewSyncTarget();
}
} else if (res.sync_step === "applyHB_") {
return this.applyHB(res.data);
}
}
},
parseMessageFromXml: function(m) {
var parse_array, parse_object;
parse_array = function(node) {
var n, _i, _len, _ref, _results;
_ref = node.children;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
n = _ref[_i];
if (n.getAttribute("isArray") === "true") {
_results.push(parse_array(n));
} else {
_results.push(parse_object(n));
}
}
return _results;
};
parse_object = function(node) {
var int, json, n, name, value, _i, _len, _ref, _ref1;
json = {};
_ref = node.attrs;
for (name in _ref) {
value = _ref[name];
int = parseInt(value);
if (isNaN(int) || ("" + int) !== value) {
json[name] = value;
} else {
json[name] = int;
}
}
_ref1 = node.children;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
n = _ref1[_i];
name = n.name;
if (n.getAttribute("isArray") === "true") {
json[name] = parse_array(n);
} else {
json[name] = parse_object(n);
}
}
return json;
};
return parse_object(m);
},
encodeMessageToXml: function(m, json) {
var encode_array, encode_object;
encode_object = function(m, json) {
var name, value;
for (name in json) {
value = json[name];
if (value == null) {
} else if (value.constructor === Object) {
encode_object(m.c(name), value);
} else if (value.constructor === Array) {
encode_array(m.c(name), value);
} else {
m.setAttribute(name, value);
}
}
return m;
};
encode_array = function(m, array) {
var e, _i, _len;
m.setAttribute("isArray", "true");
for (_i = 0, _len = array.length; _i < _len; _i++) {
e = array[_i];
if (e.constructor === Object) {
encode_object(m.c("array-element"), e);
} else {
encode_array(m.c("array-element"), e);
}
}
return m;
};
if (json.constructor === Object) {
return encode_object(m.c("y", {
xmlns: "http://y.ninja/connector-stanza"
}), json);
} else if (json.constructor === Array) {
return encode_array(m.c("y", {
xmlns: "http://y.ninja/connector-stanza"
}), json);
} else {
throw new Error("I can't encode this json!");
}
},
setIsBoundToY: function() {
if (typeof this.on_bound_to_y === "function") {
this.on_bound_to_y();
}
delete this.when_bound_to_y;
return this.is_bound_to_y = true;
}
};

View File

@@ -30,8 +30,10 @@ HistoryBuffer = (function() {
this.buffer[id] = own;
delete this.buffer[this.user_id];
}
this.operation_counter[id] = this.operation_counter[this.user_id];
delete this.operation_counter[this.user_id];
if (this.operation_counter[this.user_id] != null) {
this.operation_counter[id] = this.operation_counter[this.user_id];
delete this.operation_counter[this.user_id];
}
return this.user_id = id;
};
@@ -221,7 +223,7 @@ HistoryBuffer = (function() {
_results = [];
for (user in state_vector) {
state = state_vector[user];
if ((this.operation_counter[user] == null) || (this.operation_counter[user] < state_vector[user])) {
if (((this.operation_counter[user] == null) || (this.operation_counter[user] < state_vector[user])) && (state_vector[user] != null)) {
_results.push(this.operation_counter[user] = state_vector[user]);
} else {
_results.push(void 0);

View File

@@ -187,7 +187,7 @@ module.exports = function(HB) {
ReplaceManager.prototype.callEventDecorator = function(events) {
var event, name, prop, _i, _len, _ref;
if (!this.isDeleted()) {
if (!(this.isDeleted() || this.getLastOperation().isDeleted())) {
for (_i = 0, _len = events.length; _i < _len; _i++) {
event = events[_i];
_ref = this.event_properties;

View File

@@ -13,14 +13,14 @@ adaptConnector = require("./ConnectorAdapter");
createY = function(connector) {
var HB, Y, type_manager, types, user_id;
user_id = null;
if (connector.id != null) {
user_id = connector.id;
if (connector.user_id != null) {
user_id = connector.user_id;
} else {
user_id = "_temp";
connector.onUserIdSet(function(id) {
connector.on_user_id_set = function(id) {
user_id = id;
return HB.resetUserId(id);
});
};
}
HB = new HistoryBuffer(user_id);
type_manager = json_types_uninitialized(HB);