Add conflict resolution to the browser example
This commit is contained in:
parent
0deb161400
commit
86f581466e
|
@ -3512,6 +3512,18 @@ Change.getCheckpointModel = function() {
|
|||
return checkpointModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model instance.
|
||||
* @callback {Function} callback
|
||||
* @param {Error} err
|
||||
* @param {Model} model The Model instance
|
||||
*/
|
||||
|
||||
Change.prototype.getModelInst = function(callback) {
|
||||
var Model = this.getModelCtor();
|
||||
assert(Model, 'unkown model + ', this.modelName);
|
||||
Model.findById(this.modelId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* When two changes conflict a conflict is created.
|
||||
|
@ -3538,8 +3550,8 @@ Conflict.prototype.fetch = function(cb) {
|
|||
|
||||
async.parallel(tasks, cb);
|
||||
|
||||
function getSourceModel(change, cb) {
|
||||
conflict.sourceModel.getModel(function(err, model) {
|
||||
function getSourceModel(cb) {
|
||||
conflict.sourceChange.getModelInst(function(err, model) {
|
||||
if(err) return cb(err);
|
||||
conflict.source = model;
|
||||
cb();
|
||||
|
@ -3547,7 +3559,7 @@ Conflict.prototype.fetch = function(cb) {
|
|||
}
|
||||
|
||||
function getTargetModel(cb) {
|
||||
conflict.targetModel.getModel(function(err, model) {
|
||||
conflict.targetChange.getModelInst(function(err, model) {
|
||||
if(err) return cb(err);
|
||||
conflict.target = model;
|
||||
cb();
|
||||
|
|
|
@ -13,6 +13,17 @@ app.dataSource('local', {
|
|||
connector: loopback.Memory
|
||||
});
|
||||
|
||||
var network = {
|
||||
available: true,
|
||||
toggle: function() {
|
||||
this.available = !this.available;
|
||||
replicate();
|
||||
replicateFromRemote();
|
||||
},
|
||||
status: function() {
|
||||
return this.available ? 'on' : 'off';
|
||||
}
|
||||
};
|
||||
var Color = loopback.getModel('Color');
|
||||
var LocalColor = app.model('LocalColor', {
|
||||
dataSource: 'local',
|
||||
|
@ -24,36 +35,79 @@ LocalColor.beforeCreate = function(next, color) {
|
|||
next();
|
||||
}
|
||||
|
||||
function replicate() {
|
||||
LocalColor.currentCheckpoint(function(err, cp) {
|
||||
setTimeout(function() {
|
||||
LocalColor.replicate(cp, Color, {}, function() {
|
||||
console.log('replicated local to remote');
|
||||
var localConflicts = [];
|
||||
|
||||
function ReplicationCtlr($scope) {
|
||||
var interval = 1000;
|
||||
$scope.replicate = replicate;
|
||||
$scope.replicateFromRemote = replicate;
|
||||
$scope.conflicts = [];
|
||||
|
||||
$scope.resolveUsingRemote = function(conflict) {
|
||||
conflict.source.name = conflict.target.name;
|
||||
conflict.source.save(function() {
|
||||
conflict.source.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
LocalColor.on('deleted', replicate);
|
||||
LocalColor.on('changed', replicate);
|
||||
LocalColor.on('deletedAll', replicate);
|
||||
|
||||
setInterval(replicateFromRemote, interval);
|
||||
setInterval(replicate, interval);
|
||||
|
||||
function replicate() {
|
||||
// reset the conflicts array
|
||||
while($scope.conflicts.shift());
|
||||
|
||||
if(network.available) {
|
||||
LocalColor.currentCheckpoint(function(err, cp) {
|
||||
setTimeout(function() {
|
||||
LocalColor.replicate(cp, Color, {}, function(err, conflicts) {
|
||||
// console.log('replicated local to remote');
|
||||
conflicts.forEach(function(conflict) {
|
||||
conflict.fetch(function() {
|
||||
var local = conflict.source.name;
|
||||
var remote = conflict.target.name;
|
||||
if(local !== remote) {
|
||||
$scope.conflicts.push(conflict)
|
||||
}
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function replicateFromRemote() {
|
||||
if(network.available) {
|
||||
Color.currentCheckpoint(function(err, cp) {
|
||||
Color.replicate(0, LocalColor, {}, function() {
|
||||
// console.log('replicated remote to local');
|
||||
});
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalColor.on('deleted', replicate);
|
||||
LocalColor.on('changed', replicate);
|
||||
LocalColor.on('deletedAll', replicate);
|
||||
function NetworkCtrl($scope) {
|
||||
$scope.network = network;
|
||||
}
|
||||
|
||||
setInterval(function() {
|
||||
Color.currentCheckpoint(function(err, cp) {
|
||||
Color.replicate(cp, LocalColor, {}, function() {
|
||||
console.log('replicated remote to local');
|
||||
});
|
||||
});
|
||||
}, 1000);
|
||||
function ConflictCtrl($scope) {
|
||||
$scope.conflicts = localConflicts;
|
||||
}
|
||||
|
||||
function ListCtrl($scope) {
|
||||
LocalColor.on('changed', update);
|
||||
LocalColor.on('deleted', update);
|
||||
|
||||
function update() {
|
||||
LocalColor.find({sort: 'name'}, function(err, colors) {
|
||||
LocalColor.find({order: 'name ASC'}, function(err, colors) {
|
||||
$scope.colors = colors;
|
||||
console.log(colors);
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,10 +9,21 @@
|
|||
<style>
|
||||
body {font-size: 24px;}
|
||||
</style>
|
||||
<h1 ng-controller="NetworkCtrl">
|
||||
<input style="font-size: 48px;" type="checkbox" ng-model="network.available" />Enable Network
|
||||
</h1>
|
||||
<ul ng-controller="ReplicationCtlr">
|
||||
<h2 ng-show="conflicts.length">Conflicts:</h2>
|
||||
<li ng-repeat="conflict in conflicts">
|
||||
<button ng-click="conflict.resolve()">Use local {{conflict.source.name}}</button>
|
||||
<button ng-click="resolveUsingRemote(conflict)">Use remote {{conflict.target.name}}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul ng-controller="ListCtrl">
|
||||
<li ng-repeat="color in colors" style="color: {{color.name}}">
|
||||
<form ng-submit="color.save()">
|
||||
<input placeholder="{{color.name}}" ng-model="color.name" />
|
||||
{{color.conflict}}
|
||||
<a href="#" ng-click="del(color)">delete</a>
|
||||
</form>
|
||||
</li>
|
||||
|
|
|
@ -399,6 +399,18 @@ Change.getCheckpointModel = function() {
|
|||
return checkpointModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model instance.
|
||||
* @callback {Function} callback
|
||||
* @param {Error} err
|
||||
* @param {Model} model The Model instance
|
||||
*/
|
||||
|
||||
Change.prototype.getModelInst = function(callback) {
|
||||
var Model = this.getModelCtor();
|
||||
assert(Model, 'unkown model + ', this.modelName);
|
||||
Model.findById(this.modelId, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* When two changes conflict a conflict is created.
|
||||
|
@ -425,8 +437,8 @@ Conflict.prototype.fetch = function(cb) {
|
|||
|
||||
async.parallel(tasks, cb);
|
||||
|
||||
function getSourceModel(change, cb) {
|
||||
conflict.sourceModel.getModel(function(err, model) {
|
||||
function getSourceModel(cb) {
|
||||
conflict.sourceChange.getModelInst(function(err, model) {
|
||||
if(err) return cb(err);
|
||||
conflict.source = model;
|
||||
cb();
|
||||
|
@ -434,7 +446,7 @@ Conflict.prototype.fetch = function(cb) {
|
|||
}
|
||||
|
||||
function getTargetModel(cb) {
|
||||
conflict.targetModel.getModel(function(err, model) {
|
||||
conflict.targetChange.getModelInst(function(err, model) {
|
||||
if(err) return cb(err);
|
||||
conflict.target = model;
|
||||
cb();
|
||||
|
|
Loading…
Reference in New Issue