Skip to content

Commit

Permalink
Moving the ui updating in to the main loop to fix the bug that I ment…
Browse files Browse the repository at this point in the history
…ion in the TODO, and fix the client/server communication
  • Loading branch information
fitzgen committed Apr 21, 2011
1 parent fafde50 commit ce05e8e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 58 deletions.
4 changes: 2 additions & 2 deletions apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ define(["./operations"], function (operations) {
if ( doc.indexOf(operations.val(op[i])) !== 0 ) {
throw new TypeError("Expected '" + operations.val(op[i])
+ "' to delete, found '" + doc.slice(0, 10)
+ "...'");
+ "'");
} else {
doc = doc.slice(operations.val(op[i]).length);
break;
}
break;
default:
throw new TypeError("Unknown operation: "
+ operations.type(op[i]));
Expand Down
108 changes: 52 additions & 56 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ define([
msg = outgoing[i];
xform(messages.operation(msg), ops, function (aPrime, bPrime) {
messages.operation(msg, aPrime);
messages.document(msg, apply(messages.document(msg), aPrime));
messages.document(msg, aPrime, apply(aPrime, messages.document(msg)));
messages.revision(msg, messages.revision(msg)+1);
ops = bPrime;
});
Expand All @@ -49,7 +49,30 @@ define([
});
}

function init (outgoing, socket, ui, initialData) {
// Might need to start sending client id's back and forth. Don't really want
// to have to do a deep equality test on every check here.
function isOurOutgoing (msg, outgoing) {
var top = outgoing[0],
topOps = messages.operation(top),
msgOps = messages.operation(msg),
i = 0,
len = msgOps.length;
if ( messages.id(msg) !== messages.id(top) ) {
return false;
}
if ( messages.revision(msg) !== messages.revision(top) ) {
return false;
}
if ( len !== topOps.length ) {
return false;
}
if ( topOps.join() !== msgOps.join() ) {
return false;
}
return true;
}

function init (outgoing, incoming, socket, ui, initialData) {
var previousDoc = messages.document(initialData),
previousRevision = messages.revision(initialData),
id = messages.id(initialData);
Expand All @@ -60,6 +83,7 @@ define([
var msg,
oldOutgoingLength = outgoing.length,
uiDoc = ui.getDocument();

if ( uiDoc !== previousDoc ) {
msg = {};
messages.operation(msg, operations.operation(previousDoc, uiDoc));
Expand All @@ -69,90 +93,62 @@ define([

outgoing.push(msg);
previousDoc = uiDoc;
}

if ( oldOutgoingLength === 0 ) {
socket.send({
type: "update",
data: outgoing[0]
});
while ( (msg = incoming.shift()) ) {
if ( outgoing.length && isOurOutgoing(msg, outgoing) ) {
outgoing.shift();
} else {
// TODO: need to handle cursor selection and index
xformEach(outgoing, messages.operation(msg));
previousRevision++;

// TODO: cursor position
if ( outgoing.length ) {
ui.update(previousDoc = messages.document(outgoing[outgoing.length-1]));
} else {
ui.update(previousDoc = messages.document(msg));
}
}
}

if ( outgoing.length ) {
socket.send({
type: "update",
data: outgoing[0]
});
}

setTimeout(loop, 1000);
}

setTimeout(loop, 10);
}

// Might need to start sending client id's back and forth. Don't really want
// to have to do a deep equality test on every check here.
function isOurOutgoing (msg, outgoing) {
var top = outgoing[0],
topOps = messages.operation(top),
msgOps = messages.operation(msg),
i = 0,
len = msgOps.length;
if ( messages.id(msg) !== messages.id(top) ) {
return false;
}
if ( messages.revision(msg) !== messages.revision(top) ) {
return false;
}
if ( len !== topOps.length ) {
return false;
}
if ( topOps.join() !== msgOps.join() ) {
return false;
}
return true;
}

return {
OTDocument: function (opts) {
var outgoing = [],
incoming = [],
socket = opts.socket || error("socket is required"),
ui = opts.ui || error("ui is required"),
docId = opts.id,
initialized = false;

connect(socket, docId);

// TODO: what happens if we receive an update message from the
// server and we update the client and they lose what they were just
// typeing because we havent saved the operations in the outgoing
// buffer yet? Do I need to merge the main loop and handling of
// socket messages? Maybe just have the socket's receive handler
// queue events in an inbox and have the main loop process one
// change that the client is creating, then one message from the
// inbox.

socket.onMessage(function (event) {
var msg;

switch ( event.type ) {

case "connect":
if ( ! initialized ) {
init(outgoing, socket, ui, event.data);
init(outgoing, incoming, socket, ui, event.data);
} else {
error("Already initialized");
}
break;

case "update":
msg = event.data;
if ( outgoing.length && isOurOutgoing(msg, outgoing) ) {
outgoing.shift();
} else {
// TODO: need to handle cursor selection and index
xformEach(outgoing, messages.operation(msg));

// TODO: cursor position
if ( outgoing.length ) {
ui.update(messages.document(outgoing[outgoing.length-1]));
} else {
ui.update(messages.document(msg));
}
}
incoming.push(event.data);
break;

default:
Expand Down

0 comments on commit ce05e8e

Please sign in to comment.