Created
January 27, 2012 18:15
-
-
Save rla/1690113 to your computer and use it in GitHub Desktop.
Syncing data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Server() { | |
this.rev = 0; | |
this.data = {}; | |
this.changes = []; // { id, rev } | |
} | |
/** | |
* Finds changes after given revision. Returns array of {id, op, rev}. | |
*/ | |
Server.prototype.changesAfter = function(rev) { | |
var changes = []; | |
var server = this; | |
this.changes.forEach(function(change) { | |
if (change.rev > rev) { | |
changes.push({ | |
id: change.id, | |
op: server.data[change.id] === undefined ? 'D' : 'U', | |
rev: change.rev | |
}); | |
} | |
}); | |
return changes; | |
}; | |
function Client() { | |
this.rev = 0; | |
this.data = {}; | |
this.changes = []; // { id, rev } | |
} | |
Client.prototype.add = function(id, data) { | |
this.data[id] = data; | |
this.changes.push({ id: id, rev: this.rev }); | |
}; | |
Client.prototype.remove = function(id) { | |
delete this.data[id]; | |
this.changes.push({ id: id, rev: this.rev }); | |
}; | |
Client.prototype.update = function(id, data) { | |
this.data[id] = data; | |
this.changes.push({ id: id, rev: this.rev }); | |
}; | |
/** | |
* Finds current changes. Returns array of {id, op, rev}. | |
*/ | |
Client.prototype.currentChanges = function() { | |
var changes = []; | |
var client = this; | |
this.changes.forEach(function(change) { | |
changes.push({ | |
id: change.id, | |
op: client.data[change.id] === undefined ? 'D' : 'U', | |
rev: change.rev | |
}); | |
}); | |
return changes; | |
}; | |
Client.prototype.sync = function(server) { | |
var schanges = server.changesAfter(this.rev); | |
var cchanges = this.currentChanges(); | |
// Apply server changes first. | |
// XXX must apply at the same time by pairing by id? | |
var client = this; | |
schanges.forEach(function(change) { | |
if (change.op === 'U') { | |
client.data[change.id] = server.data[change.id]; | |
} else if (change.op === 'D') { | |
delete client.data[change.id]; | |
} | |
}); | |
// Apply client changes. | |
cchanges.forEach(function(change) { | |
if (change.op === 'U') { | |
server.data[change.id] = client.data[change.id]; | |
} else if (change.op === 'D') { | |
delete server.data[change.id]; | |
} | |
}); | |
// Push rev. | |
server.rev += 1; | |
this.rev = server.rev; | |
// Transfer client changes with increased revision number. | |
cchanges.forEach(function(change) { | |
server.changes.push({ id: change.id, rev: client.rev }); | |
}); | |
// Cleanup. | |
this.changes = []; | |
}; | |
function report(party, title) { | |
console.log(title); | |
console.log('\tRevision: ' + party.rev); | |
console.log('\tData:'); | |
for (id in party.data) { | |
console.log('\t\t' + id + ': ' + party.data[id]); | |
} | |
console.log('\tChanges:'); | |
party.changes.forEach(function(change) { | |
console.log('\t\tr' + change.rev + ' ' + change.id); | |
}); | |
}; | |
var s = new Server(); | |
var c1 = new Client(); | |
c1.add(1, 'd1-1.0'); | |
c1.add(2, 'd2-2.0'); | |
report(c1, 'Client 1 data before 1st sync'); | |
c1.sync(s); | |
report(c1, 'Client 1 data after 1st sync'); | |
report(s, 'Server data after 1st sync'); | |
var c2 = new Client(); | |
c2.sync(s); | |
report(c2, 'Client 2 data after 2nd sync'); | |
c2.remove(1); | |
c2.add(3, 'd3-1.0'); | |
report(c2, 'Client 2 data before 3rd sync'); | |
c2.sync(s); | |
report(c2, 'Client 2 data after 3rd sync'); | |
report(s, 'Server data after 3rd sync'); | |
c1.sync(s); | |
report(c1, 'Client 1 data after 4th sync'); | |
var c3 = new Client(); | |
c3.sync(s); | |
report(c3, 'Client 3 data after 5th sync'); | |
report(s, 'Server data after 5th sync'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment