Commit 1d4feb62 authored by Tristan Cavelier's avatar Tristan Cavelier

Improve ConflictManagerStorage, Adding new tests, all tests are passed.

parent 77635b7a
/*! JIO Storage - v0.1.0 - 2012-06-27
/*! JIO Storage - v0.1.0 - 2012-06-28
* Copyright (c) 2012 Nexedi; Licensed */
(function(LocalOrCookieStorage, $, Base64, sjcl, hex_sha256, Jio) {
......@@ -1142,6 +1142,24 @@ var newConflictManagerStorage = function ( spec, my ) {
}
return newarray;
};
priv.removeConflict = function (conflict_array,conflict_hash) {
var i,tmp = priv.removeValuesFromArrayWhere(
conflict_array,
function (v) { return (v.hash === conflict_hash); });
for (i = 0; i < tmp.length; i+= 1) {
conflict_array[i] = tmp[i];
}
conflict_array.length = tmp.length;
};
priv.addConflict = function (conflict_array,conflict_object) {
var i;
for (i = 0; i < conflict_array.length; i+= 1) {
if (conflict_object.hash === conflict_array[i].hash) {
return;
}
}
conflict_array.push(conflict_object);
};
priv.loadMetadataFromDistant = function (command,path,onDone,onFail) {
var cloned_option = command.cloneOption ();
......@@ -1165,7 +1183,7 @@ var newConflictManagerStorage = function ( spec, my ) {
'saveDocument',{path:path,
content:JSON.stringify (content),
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
......@@ -1253,6 +1271,21 @@ var newConflictManagerStorage = function ( spec, my ) {
});
};
o.checkForConflicts = function () {
var saveAndDone = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
};
var saveAndFail = function (error) {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
am.call(o,'fail',[error]);
};
var updateMetadataCommon = function () {
var original_creation_date;
......@@ -1293,25 +1326,21 @@ var newConflictManagerStorage = function ( spec, my ) {
// if this is a new file
if (is_a_new_file) {
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
saveAndDone();
return;
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_file_metadata.winner.hash ===
command_file_metadata.winner.hash) {
// OK! Now, update distant metadata, store them and save
command_file_metadata.winner.hash && (
!command_file_metadata.owner[priv.username] || (
priv.username === command_file_metadata.winner.owner ||
command_file_metadata.owner[priv.username].
revision < command_file_metadata.owner[
command_file_metadata.winner.owner].revison))) {
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
saveAndDone();
} else {
// if conflict
var conflict_object = {
......@@ -1329,38 +1358,44 @@ var newConflictManagerStorage = function ( spec, my ) {
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i, known_conflict_list =
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
var compare_fun = function (v) {
return (v.hash === conflict_hash);
};
for (i = 0; i < known_conflict_list.length; i+= 1) {
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
command_file_metadata.conflict_list =
priv.removeValuesFromArrayWhere(
command_file_metadata.conflict_list,
compare_fun);
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
return;
saveAndDone();
done = true;
}
for (j = 0; j < command_file_metadata.conflict_list.length;
j+= 1) {
if (known_conflict_list[i].hash ===
command_file_metadata.conflict_list[j].hash) {
// if known other conflict
// it is solved but the current conflict is
// different than this one.
priv.removeConflict(
command_file_metadata.conflict_list,
known_conflict_list[i].hash);
}
}
}
updateCommandMetadataOnConflict();
// if unknown conflict
command_file_metadata.conflict_list.push (conflict_object);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
am.call(o,'fail',[
{status:0,statusText:'Revision Conflict',
message:'Someone has already modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
if (!done) {
updateCommandMetadataOnConflict();
// if unknown conflict
priv.addConflict (command_file_metadata.conflict_list,
conflict_object);
saveAndFail({status:0,statusText:'Revision Conflict',
message:'Someone has already'+
' modified this document.'});
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
}
}
};
o.saveMetadata = function () {
......@@ -1388,7 +1423,7 @@ var newConflictManagerStorage = function ( spec, my ) {
'.' + priv.username,
content:command.getContent(),
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
......@@ -1411,7 +1446,7 @@ var newConflictManagerStorage = function ( spec, my ) {
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
......@@ -1641,6 +1676,7 @@ var newConflictManagerStorage = function ( spec, my ) {
local_file_metadata = {},
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
metadata_object_known = true,
is_a_new_file = false;
o.updateLocalMetadata = function () {
......@@ -1656,6 +1692,7 @@ var newConflictManagerStorage = function ( spec, my ) {
new_owner_object;
}
} else {
metadata_object_known = false;
local_file_metadata = {
winner: {},
owner: {},
......@@ -1686,6 +1723,13 @@ var newConflictManagerStorage = function ( spec, my ) {
});
};
o.checkForConflicts = function () {
var removeAndDone = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
};
var updateMetadataCommon = function () {
if (command_file_metadata.owner[priv.username]) {
previous_revision = command_file_metadata.owner[
......@@ -1702,6 +1746,12 @@ var newConflictManagerStorage = function ( spec, my ) {
var updateCommandMetadataOnConflict = function () {
updateMetadataCommon ();
};
// if we don't known what is will be removed fail.
if (!metadata_object_known) {
return am.call(o,'fail',[{
status:0,statusText:'Unknown Document',
message:'You must load the document before delete it.'}]);
}
// if this is a new file
if (is_a_new_file) {
LocalOrCookieStorage.deleteItem (local_metadata_file_name);
......@@ -1711,14 +1761,15 @@ var newConflictManagerStorage = function ( spec, my ) {
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_file_metadata.winner.hash ===
command_file_metadata.winner.hash) {
command_file_metadata.winner.hash && (
!command_file_metadata.owner[priv.username] || (
priv.username === command_file_metadata.winner.owner ||
command_file_metadata.owner[priv.username].
revision < command_file_metadata.owner[
command_file_metadata.winner.owner].revison))) {
// OK! Now, update distant metadata, store them and remove
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
removeAndDone();
} else {
// if conflict
var conflict_object = {
......@@ -1736,38 +1787,52 @@ var newConflictManagerStorage = function ( spec, my ) {
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i, known_conflict_list =
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
var compare_fun = function (v) {
return (v.hash === conflict_hash);
};
console.log ('1 ' + JSON.stringify (known_conflict_list));
for (i = 0; i < known_conflict_list.length; i+= 1) {
console.log ('2');
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
command_file_metadata.conflict_list =
priv.removeValuesFromArrayWhere(
command_file_metadata.conflict_list,
compare_fun);
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
return;
removeAndDone();
done = true;
}
for (j = 0; j < command_file_metadata.conflict_list.length;
j+= 1) {
console.log ('3');
if (known_conflict_list[i].hash ===
command_file_metadata.conflict_list[j].hash) {
// if known other conflict
// it is solved but the current conflict is
// different than this one.
priv.removeConflict(
command_file_metadata.conflict_list,
known_conflict_list[i].hash);
}
}
}
updateCommandMetadataOnConflict();
// if unknown conflict
command_file_metadata.conflict_list.push (conflict_object);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
// am.call(o,'removeRevision');
am.call(o,'fail',[
{status:0,statusText:'Revision Conflict',
message:'Someone has already modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
if (!done) {
updateCommandMetadataOnConflict();
// if unknown conflict
priv.addConflict (command_file_metadata.conflict_list,
conflict_object);
am.neverCall(o,'done');
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.call(o,'saveMetadata');
// am.call(o,'removeRevision');
am.call(o,'fail',[{status:0,statusText:'Revision Conflict',
message:'Someone has already'+
' modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
}
}
};
o.saveMetadata = function () {
......@@ -1800,7 +1865,7 @@ var newConflictManagerStorage = function ( spec, my ) {
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
......
/*! JIO Storage - v0.1.0 - 2012-06-27
/*! JIO Storage - v0.1.0 - 2012-06-28
* Copyright (c) 2012 Nexedi; Licensed */
(function(a,b,c,d,e,f){var g=function(b,c){var d=f.storage(b,c,"base"),e={};e.username=b.username||"",e.applicationname=b.applicationname||"untitled";var g="jio/local_user_array",h="jio/local_file_name_array/"+e.username+"/"+e.applicationname,i=d.serialized;return d.serialized=function(){var a=i();return a.applicationname=e.applicationname,a.username=e.username,a},d.validateState=function(){return e.username?"":'Need at least one parameter: "username".'},e.getUserArray=function(){return a.getItem(g)||[]},e.addUser=function(b){var c=e.getUserArray();c.push(b),a.setItem(g,c)},e.userExists=function(a){var b=e.getUserArray(),c,d;for(c=0,d=b.length;c<d;c+=1)if(b[c]===a)return!0;return!1},e.getFileNameArray=function(){return a.getItem(h)||[]},e.addFileName=function(b){var c=e.getFileNameArray();c.push(b),a.setItem(h,c)},e.removeFileName=function(b){var c,d,f=e.getFileNameArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c]!==b&&g.push(f[c]);a.setItem(h,g)},d.saveDocument=function(b){setTimeout(function(){var c=null,f="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();c=a.getItem(f),c?(c.last_modified=Date.now(),c.content=b.getContent()):(c={name:b.getPath(),content:b.getContent(),creation_date:Date.now(),last_modified:Date.now()},e.userExists(e.username)||e.addUser(e.username),e.addFileName(b.getPath())),a.setItem(f,c),d.done()},100)},d.loadDocument=function(b){setTimeout(function(){var c=null;c=a.getItem("jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath()),c?(b.getOption("metadata_only")&&delete c.content,d.done(c)):d.fail({status:404,statusText:"Not Found.",message:'Document "'+b.getPath()+'" not found in localStorage.'})},100)},d.getDocumentList=function(b){setTimeout(function(){var c=[],f=[],g,h,i="key",j="jio/local/"+e.username+"/"+e.applicationname,k={};f=e.getFileNameArray();for(g=0,h=f.length;g<h;g+=1)k=a.getItem(j+"/"+f[g]),k&&(b.getOption("metadata_only")?c.push({name:k.name,creation_date:k.creation_date,last_modified:k.last_modified}):c.push({name:k.name,content:k.content,creation_date:k.creation_date,last_modified:k.last_modified}));d.done(c)},100)},d.removeDocument=function(b){setTimeout(function(){var c="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();a.deleteItem(c),e.removeFileName(b.getPath()),d.done()},100)},d};f.addStorageType("local",g);var h=function(a,d){var e=f.storage(a,d,"base"),g={};g.username=a.username||"",g.applicationname=a.applicationname||"untitled",g.url=a.url||"",g.password=a.password||"";var h=e.serialized;return e.serialized=function(){var a=h();return a.username=g.username,a.applicationname=g.applicationname,a.url=g.url,a.password=g.password,a},e.validateState=function(){return g.username&&g.url?"":'Need at least 2 parameters: "username" and "url".'},e.saveDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PUT",data:a.getContent(),async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.done()},error:function(b){b.message='Cannot save "'+a.getPath()+'" into DAVStorage.',e.fail(b)}})},e.loadDocument=function(a){var d={},f=function(){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(a){d.content=a,e.done(d)},error:function(b){b.status===404?b.message='Document "'+a.getPath()+'" not found in localStorage.':b.message='Cannot load "'+a.getPath()+'" from DAVStorage.',e.fail(b)}})};d.name=a.getPath(),b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PROPFIND",async:!0,dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(c){b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){d.last_modified=b(this).text()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){d.creation_date=b(this).text()}),a.getOption("metadata_only")?e.done(d):f()},error:function(b){b.message='Cannot load "'+a.getPath()+'" informations from DAVStorage.',e.fail(b)}})},e.getDocumentList=function(a){var d=[],f={},h=[];b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/",async:!0,type:"PROPFIND",dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password),Depth:"1"},success:function(a){b(a).find("D\\:response, response").each(function(a,c){if(a>0){f={},b(c).find("D\\:href, href").each(function(){h=b(this).text().split("/"),f.name=h[h.length-1]?h[h.length-1]:h[h.length-2]+"/"});if(f.name===".htaccess"||f.name===".htpasswd")return;b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){f.last_modified=b(this).text()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){f.creation_date=b(this).text()}),d.push(f)}}),e.done(d)},error:function(a){a.message="Cannot get a document list from DAVStorage.",e.fail(a)}})},e.removeDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"DELETE",async:!0,headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.done()},error:function(a){a.status===404?e.done():(a.message='Cannot remove "'+e.getFileName()+'" from DAVStorage.',e.fail(a))}})},e};f.addStorageType("dav",h);var i=function(a,b){var c=f.storage(a,b,"handler"),d={};d.return_value_array=[],d.storagelist=a.storagelist||[],d.nb_storage=d.storagelist.length;var e=c.serialized;return c.serialized=function(){var a=e();return a.storagelist=d.storagelist,a},c.validateState=function(){return d.storagelist.length===0?'Need at least one parameter: "storagelist" containing at least one storage.':""},d.isTheLast=function(){return d.return_value_array.length===d.nb_storage},d.doJob=function(a,b){var e=!1,f=[],g,h=function(a){d.return_value_array.push(a)},i=function(a){e||(f.push(a),d.isTheLast()&&c.fail({status:207,statusText:"Multi-Status",message:b,array:f}))},j=function(a){e||(e=!0,c.done(a))};for(g=0;g<d.nb_storage;g+=1){var k=a.clone(),l=c.newStorage(d.storagelist[g]);k.onResponseDo(h),k.onFailDo(i),k.onDoneDo(j),c.addJob(l,k)}a.setMaxRetry(1)},c.saveDocument=function(a){d.doJob(a,'All save "'+a.getPath()+'" requests have failed.'),c.end()},c.loadDocument=function(a){d.doJob(a,'All load "'+a.getPath()+'" requests have failed.'),c.end()},c.getDocumentList=function(a){d.doJob(a,"All get document list requests have failed."),c.end()},c.removeDocument=function(a){d.doJob(a,'All remove "'+a.getPath()+'" requests have failed.'),c.end()},c};f.addStorageType("replicate",i);var j=function(b,c){var d=f.storage(b,c,"handler"),e={},g=b.storage||!1;e.secondstorage_spec=b.storage||{type:"base"},e.secondstorage_string=JSON.stringify(e.secondstorage_spec);var h="jio/indexed_storage_array",i="jio/indexed_file_array/"+e.secondstorage_string,j=d.serialized;return d.serialized=function(){var a=j();return a.storage=e.secondstorage_spec,a},d.validateState=function(){return g?"":'Need at least one parameter: "storage" containing storage specifications.'},e.isStorageArrayIndexed=function(){return a.getItem(h)?!0:!1},e.getIndexedStorageArray=function(){return a.getItem(h)||[]},e.indexStorage=function(b){var c=e.getIndexedStorageArray();c.push(typeof b=="string"?b:JSON.stringify(b)),a.setItem(h,c)},e.isAnIndexedStorage=function(a){var b=typeof a=="string"?a:JSON.stringify(a),c,d,f=e.getIndexedStorageArray();for(c=0,d=f.length;c<d;c+=1)if(JSON.stringify(f[c])===b)return!0;return!1},e.fileArrayExists=function(){return a.getItem(i)?!0:!1},e.getFileArray=function(){return a.getItem(i)||[]},e.setFileArray=function(b){return a.setItem(i,b)},e.isFileIndexed=function(a){var b,c,d=e.getFileArray();for(b=0,c=d.length;b<c;b+=1)if(d[b].name===a)return!0;return!1},e.addFile=function(b){var c=e.getFileArray();c.push(b),a.setItem(i,c)},e.removeFile=function(b){var c,d,f=e.getFileArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c].name!==b&&g.push(f[c]);a.setItem(i,g)},e.update=function(){var a=function(a){e.isAnIndexedStorage(e.secondstorage_string)||e.indexStorage(e.secondstorage_string),e.setFileArray(a)};d.addJob(d.newStorage(e.secondstorage_spec),d.newCommand("getDocumentList",{path:".",option:{onDone:a,max_retry:3}}))},d.saveDocument=function(a){var b=a.clone();b.onResponseDo(function(){}),b.onDoneDo(function(b){e.isFileIndexed(a.getPath())||e.addFile({name:a.getPath(),last_modified:0,creation_date:0}),e.update(),d.done()}),b.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d.loadDocument=function(a){var b,c,f,g,h=function(a){d.done(a)},i=function(a){d.fail(a)},j=function(){var b=a.clone();b.onResponseDo(function(){}),b.onFailDo(i),b.onDoneDo(h),d.addJob(d.newStorage(e.secondstorage_spec),b)};e.update(),a.getOption("metadata_only")?setTimeout(function(){if(e.fileArrayExists()){b=e.getFileArray();for(c=0,f=b.length;c<f;c+=1)if(b[c].name===a.getPath())return d.done(b[c])}else j()},100):j()},d.getDocumentList=function(a){var b,c,f=!1;e.update(),a.getOption("metadata_only")?(b=setInterval(function(){f&&(d.fail({status:0,statusText:"Timeout",message:"The request has timed out."}),clearInterval(b)),e.fileArrayExists()&&(d.done(e.getFileArray()),clearInterval(b))},100),setTimeout(function(){f=!0},1e4)):(c=a.clone(),c.onDoneDo(function(a){d.done(a)}),c.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),c))},d.removeDocument=function(a){var b=a.clone();b.onResponseDo(function(){}),b.onDoneDo(function(b){e.removeFile(a.getPath()),e.update(),d.done()}),b.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d};f.addStorageType("indexed",j);var k=function(a,c){var e=f.storage(a,c,"handler"),g={},h=a.storage||!1;g.username=a.username||"",g.password=a.password||"",g.secondstorage_spec=a.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_string);var i=e.serialized;return e.serialized=function(){var a=i();return a.username=g.username,a.password=g.password,a.storage=g.secondstorage_string,a},e.validateState=function(){return g.username&&h?"":'Need at least two parameters: "username" and "storage".'},g.encrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",v:1,iter:1e3,ks:256,ts:128,mode:"ccm",adata:"",cipher:"aes",salt:"K4bmZG9d704"},g.decrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",ks:256,ts:128,salt:"K4bmZG9d704"},g.encrypt=function(a,b,c){var e=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(e).ct,c)},g.decrypt=function(a,c,e,f){var h,i=b.extend(!0,{},g.decrypt_param_object);i.ct=a||"",i=JSON.stringify(i);try{h=d.decrypt(g.username+":"+g.password,i)}catch(j){c({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."},e,f);return}c(h,e,f)},e.saveDocument=function(a){var b,c,d=function(){g.encrypt(a.getPath(),function(a){b=a,f()})},f=function(){g.encrypt(a.getContent(),function(a){c=a,h()})},h=function(){var d=a.cloneOption(),f;d.onResponse=function(){},d.onDone=function(){e.done()},d.onFail=function(a){e.fail(a)},f=e.newCommand("saveDocument",{path:b,content:c,option:d}),e.addJob(e.newStorage(g.secondstorage_spec),f)};d()},e.loadDocument=function(a){var b,c,d=function(){g.encrypt(a.getPath(),function(a){b=a,f()})},f=function(){var c=a.cloneOption(),d;c.onResponse=function(){},c.onFail=i,c.onDone=h,d=e.newCommand("loadDocument",{path:b,option:c}),e.addJob(e.newStorage(g.secondstorage_spec),d)},h=function(b){b.name=a.getPath(),a.getOption("metadata_only")?e.done(b):g.decrypt(b.content,function(a){typeof a=="object"?e.fail({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt"}):(b.content=a,e.done(b))})},i=function(a){e.fail(a)};d()},e.getDocumentList=function(a){var b,c,d,f=0,h,i=!0,j=function(){var b=a.clone();b.onResponseDo(k),b.onDoneDo(function(){}),b.onFailDo(function(){}),e.addJob(e.newStorage(g.secondstorage_spec),b)},k=function(a){if(a.status.isDone()){h=a.value;for(c=0,d=h.length;c<d;c+=1)g.decrypt(h[c].name,l,c,"name")}else e.fail(a.error)},l=function(a,b,c){var g;f++;if(typeof a=="object"){i&&(i=!1,e.fail({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."})),i=!1;return}h[b][c]=a,f===d&&i&&e.done(h)};j()},e.removeDocument=function(a){var b,c=function(){g.encrypt(a.getPath(),function(a){b=a,d()})},d=function(){var c=a.cloneOption();c.onResponse=f,c.onFail=function(){},c.onDone=function(){},e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("removeDocument",{path:b,option:c}))},f=function(a){a.status.isDone()?e.done():e.fail(a.error)};c()},e};f.addStorageType("crypt",k);var l=function(b,c){var d=f.storage(b,c,"handler"),g={};b=b||{},c=c||{},g.username=b.username||"";var h=b.storage?!0:!1;g.secondstorage_spec=b.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_spec);var i="jio/conflictmanager/"+g.username+"/"+g.secondstorage_string+"/",j=d.serialized;return d.serialized=function(){var a=j();return a.username=g.username,a.storage=g.secondstorage_spec,a},d.validateState=function(){return g.username&&h?"":'Need at least two parameter: "username" and "storage".'},g.removeValuesFromArrayWhere=function(a,b){var c,d=[];for(c=0;c<a.length;c+=1)b(a[c])||d.push(a[c]);return d},g.loadMetadataFromDistant=function(a,b,c,e){var f=a.cloneOption();f.metadata_only=!1,f.onResponse=function(){},f.onFail=e,f.onDone=c;var h=d.newCommand("loadDocument",{path:b,option:f});d.addJob(d.newStorage(g.secondstorage_spec),h)},g.saveMetadataToDistant=function(a,b,c,e,f){var h=a.cloneOption();h.onResponse=function(){},h.onFail=f,h.onDone=e;var i=d.newCommand("saveDocument",{path:b,content:JSON.stringify(c),option:h});i.setMaxRetry(0),d.addJob(d.newStorage(g.secondstorage_spec),i)},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){return a._wait=a._wait||{},a._wait[b]?(a._wait[b]--,function(){}):(c=c||[],a[b].apply(a[b],c))},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},d.saveDocument=function(b){var c={},f=g.newAsyncModule(),h=b.getPath()+".metadata",j=i+h,k={},l={},m=0,n=!1,o=e(b.getContent()),p=new Date;c.updateLocalMetadata=function(){var b={revision:0,hash:"",last_modified:0,creation_date:p.getTime()};k=a.getItem(j),k?k.owner[g.username]||(k.owner[g.username]=b):(k={winner:{},owner:{},conflict_list:[]},k.winner={revision:0,owner:g.username,hash:""},k.owner[g.username]=b),f.call(c,"checkForConflicts")},c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,h,function(a){l=JSON.parse(a.content),f.call(c,"checkForConflicts")},function(a){a.status===404?(l=k,n=!0,f.call(c,"checkForConflicts")):f.call(c,"fail",[a])})},c.checkForConflicts=function(){var d=function(){var a;n||!l.owner[l.winner.owner]?a=p.getTime():a=l.owner[l.winner.owner].creation_date||p.getTime(),l.owner[g.username]?m=l.owner[g.username].revision:l.owner[g.username]={},l.owner[g.username].last_modified=p.getTime(),l.owner[g.username].creation_date=a,l.owner[g.username].hash=o},h=function(){d(),l.winner.owner=g.username,l.winner.revision++,l.winner.hash=o,l.owner[g.username].revision=l.winner.revision},i=function(){d(),l.owner[g.username].revision++};if(n){h(),a.setItem(j,l),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"saveRevision");return}if(k.winner.revision===l.winner.revision&&k.winner.hash===l.winner.hash)h(),a.setItem(j,l),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"saveRevision");else{var q={label:"revision",path:b.getPath(),method:"saveDocument",owner:g.username,conflict_owner:{name:l.winner.owner,revision:l.winner.revision,hash:l.winner.hash}},r=e(JSON.stringify(q));q.hash=r;var s,t=b.getOption("known_conflict_list")||[],u=function(a){return a.hash===r};for(s=0;s<t.length;s+=1)if(t[s].hash===r){l.conflict_list=g.removeValuesFromArrayWhere(l.conflict_list,u),h(),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"saveRevision");return}i(),l.conflict_list.push(q),f.neverCall(c,"done"),f.call(c,"saveMetadata"),f.call(c,"saveRevision"),f.call(c,"fail",[{status:0,statusText:"Revision Conflict",message:"Someone has already modified this document."}]);var v=b.getOption("onConflict")||function(){};v(q)}},c.saveMetadata=function(){g.saveMetadataToDistant(b,h,l,function(){f.call(c,"done")},function(a){f.call(c,"fail",[a])})},c.saveRevision=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a])},a.onDone=function(){f.call(c,"deletePreviousRevision")};var e=d.newCommand("saveDocument",{path:b.getPath()+"."+l.owner[g.username].revision+"."+g.username,content:b.getContent(),option:a});e.setMaxRetry(0),d.addJob(d.newStorage(g.secondstorage_spec),e)},c.deletePreviousRevision=function(){if(m===0||!!l.owner[g.username]&&m===l.owner[g.username].revision)f.call(c,"done");else{var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a])},a.onDone=function(){f.call(c,"done")};var e=d.newCommand("removeDocument",{path:b.getPath()+"."+m+"."+g.username,option:a});e.setMaxRetry(0),d.addJob(d.newStorage(g.secondstorage_spec),e)}},c.fail=function(a){f.neverCall(c,"fail"),f.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){f.neverCall(c,"done"),f.neverCall(c,"fail"),d.done()},f.wait(c,"checkForConflicts",1),f.call(c,"loadMetadataFromDistant"),f.call(c,"updateLocalMetadata")},d.loadDocument=function(b){var c={},e=g.newAsyncModule(),f=b.getPath()+".metadata",h=i+f,j={},k="",l;c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,f,function(a){j=JSON.parse(a.content),k=b.getOption("owner"),e.wait(c,"done",1),k?e.call(c,"loadOwner"):e.call(c,"loadWinner"),e.call(c,"updateLocalMetadata")},function(a){e.end(),e.call(c,"fail",[a])})},c.updateLocalMetadata=function(){a.setItem(h,j),e.call(c,"done")},c.loadWinner=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){e.call(c,"fail",[a]),e.end()},a.onDone=function(a){l=a,l.name=b.getPath(),e.call(c,"done")};var f=d.newCommand("loadDocument",{path:b.getPath()+"."+j.winner.revision+"."+j.winner.owner,option:a});d.addJob(d.newStorage(g.secondstorage_spec),f)},c.loadOwner=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){e.end(),e.call(c,"fail",[a])},a.onDone=function(a){l=a,l.name=b.getPath(),e.call(c,"done")};if(!j.owner[k]){a.onFail({status:404,statusText:"Not Found",message:"Document not found."});return}var f=d.newCommand("loadDocument",{path:b.getPath()+"."+j.owner[k].revision+"."+k,option:a});d.addJob(d.newStorage(g.secondstorage_spec),f)},c.fail=function(a){e.neverCall(c,"fail"),e.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){e.neverCall(c,"done"),e.neverCall(c,"fail"),d.done(l)},e.call(c,"loadMetadataFromDistant")},d.getDocumentList=function(b){var c={},e=g.newAsyncModule(),f=[],h=[],i=0;c.retreiveList=function(){var i=b.cloneOption();i.metadata_only=!1,i.onResponse=function(){},i.onFail=function(a){e.call(c,"fail",[a])},i.onDone=function(g){var i;for(i=0;i<g.length;i+=1){var j=g[i].name.split(".")||[],k,l={};if(j[j.length-1]==="metadata"){try{k=JSON.parse(g[i].content)}catch(m){continue}h.push(k),j.length--,l.name=j.join("."),l.creation_date=k.owner[k.winner.owner].creation_date,l.last_modified=k.owner[k.winner.owner].last_modified,f.push(l)}}if(b.getOption("metadata_only"))e.call(c,"done",[f]);else{if(g.length===0)return d.done([]);e.wait(c,"done",f.length-1);for(i=0;i<f.length;i+=1)a.setItem(f[i].name+".metadata",h[i]),e.call(c,"loadFile",[f[i],h[i].winner.revision,h[i].winner.owner]);d.end()}};var j=d.newCommand("getDocumentList",{path:b.getPath(),option:i});d.addJob(d.newStorage(g.secondstorage_spec),j)},c.loadFile=function(a,h,i){var j=b.cloneOption();j.onResponse=function(){},j.onFail=function(a){e.call(c,"fail",[a]),e.end()},j.onDone=function(b){a.content=b.content,e.call(c,"done",[f])};var k=d.newCommand("loadDocument",{path:a.name+"."+h+"."+i,option:j});d.addJob(d.newStorage(g.secondstorage_spec),k)},c.fail=function(a){e.neverCall(c,"fail"),e.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(a){e.neverCall(c,"done"),e.neverCall(c,"fail"),d.done(a)},e.call(c,"retreiveList")},d.removeDocument=function(b){var c={},f=g.newAsyncModule(),h=b.getPath()+".metadata",j=i+h,k={},l={},m=0,n=!1;c.updateLocalMetadata=function(){var b={revision:0,hash:"",last_modified:0,creation_date:0};k=a.getItem(j),k?k.owner[g.username]||(k.owner[g.username]=b):(k={winner:{},owner:{},conflict_list:[]},k.winner={revision:0,owner:g.username,hash:""},k.owner[g.username]=b),f.call(c,"checkForConflicts")},c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,h,function(a){l=JSON.parse(a.content),f.call(c,"checkForConflicts")},function(a){if(a.status===404){l=k,n=!0,f.call(c,"checkForConflicts");return}f.call(c,"fail",[a]),f.end()})},c.checkForConflicts=function(){var d=function(){l.owner[g.username]&&(m=l.owner[g.username].revision,delete l.owner[g.username])},h=function(){d(),l.winner.owner=g.username,l.winner.revision=0,l.winner.hash=""},i=function(){d()};if(n)return a.deleteItem(j),f.call(c,"done");if(k.winner.revision===l.winner.revision&&k.winner.hash===l.winner.hash)h(),a.setItem(j,l),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"removeRevision");else{var p={label:"revision",path:b.getPath(),method:"removeDocument",owner:g.username,conflict_owner:{name:l.winner.owner,revision:l.winner.revision,hash:l.winner.hash}},q=e(JSON.stringify(p));p.hash=q;var r,s=b.getOption("known_conflict_list")||[],t=function(a){return a.hash===q};for(r=0;r<s.length;r+=1)if(s[r].hash===q){l.conflict_list=g.removeValuesFromArrayWhere(l.conflict_list,t),h(),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"removeRevision");return}i(),l.conflict_list.push(p),f.neverCall(c,"done"),f.call(c,"saveMetadata"),f.call(c,"fail",[{status:0,statusText:"Revision Conflict",message:"Someone has already modified this document."}]);var u=b.getOption("onConflict")||function(){};u(p)}},c.saveMetadata=function(){g.saveMetadataToDistant(b,h,l,function(){f.call(c,"done")},function(a){f.call(c,"fail",[a]),f.end()})},c.removeRevision=function(){if(m===0||!!l.owner[g.username]&&m===l.owner[g.username].revision)f.call(c,"done");else{var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a]),f.end()},a.onDone=function(){f.call(c,"done")};var e=d.newCommand("removeDocument",{path:b.getPath()+"."+m+"."+g.username,option:a});e.setMaxRetry(0),d.addJob(d.newStorage(g.secondstorage_spec),e)}},c.fail=function(a){f.neverCall(c,"fail"),f.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){f.neverCall(c,"done"),f.neverCall(c,"fail"),d.done()},f.wait(c,"checkForConflicts",1),f.call(c,"loadMetadataFromDistant"),f.call(c,"updateLocalMetadata")},d};f.addStorageType("conflictmanager",l)})(LocalOrCookieStorage,jQuery,Base64,sjcl,hex_sha256,jio);
\ No newline at end of file
(function(a,b,c,d,e,f){var g=function(b,c){var d=f.storage(b,c,"base"),e={};e.username=b.username||"",e.applicationname=b.applicationname||"untitled";var g="jio/local_user_array",h="jio/local_file_name_array/"+e.username+"/"+e.applicationname,i=d.serialized;return d.serialized=function(){var a=i();return a.applicationname=e.applicationname,a.username=e.username,a},d.validateState=function(){return e.username?"":'Need at least one parameter: "username".'},e.getUserArray=function(){return a.getItem(g)||[]},e.addUser=function(b){var c=e.getUserArray();c.push(b),a.setItem(g,c)},e.userExists=function(a){var b=e.getUserArray(),c,d;for(c=0,d=b.length;c<d;c+=1)if(b[c]===a)return!0;return!1},e.getFileNameArray=function(){return a.getItem(h)||[]},e.addFileName=function(b){var c=e.getFileNameArray();c.push(b),a.setItem(h,c)},e.removeFileName=function(b){var c,d,f=e.getFileNameArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c]!==b&&g.push(f[c]);a.setItem(h,g)},d.saveDocument=function(b){setTimeout(function(){var c=null,f="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();c=a.getItem(f),c?(c.last_modified=Date.now(),c.content=b.getContent()):(c={name:b.getPath(),content:b.getContent(),creation_date:Date.now(),last_modified:Date.now()},e.userExists(e.username)||e.addUser(e.username),e.addFileName(b.getPath())),a.setItem(f,c),d.done()},100)},d.loadDocument=function(b){setTimeout(function(){var c=null;c=a.getItem("jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath()),c?(b.getOption("metadata_only")&&delete c.content,d.done(c)):d.fail({status:404,statusText:"Not Found.",message:'Document "'+b.getPath()+'" not found in localStorage.'})},100)},d.getDocumentList=function(b){setTimeout(function(){var c=[],f=[],g,h,i="key",j="jio/local/"+e.username+"/"+e.applicationname,k={};f=e.getFileNameArray();for(g=0,h=f.length;g<h;g+=1)k=a.getItem(j+"/"+f[g]),k&&(b.getOption("metadata_only")?c.push({name:k.name,creation_date:k.creation_date,last_modified:k.last_modified}):c.push({name:k.name,content:k.content,creation_date:k.creation_date,last_modified:k.last_modified}));d.done(c)},100)},d.removeDocument=function(b){setTimeout(function(){var c="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();a.deleteItem(c),e.removeFileName(b.getPath()),d.done()},100)},d};f.addStorageType("local",g);var h=function(a,d){var e=f.storage(a,d,"base"),g={};g.username=a.username||"",g.applicationname=a.applicationname||"untitled",g.url=a.url||"",g.password=a.password||"";var h=e.serialized;return e.serialized=function(){var a=h();return a.username=g.username,a.applicationname=g.applicationname,a.url=g.url,a.password=g.password,a},e.validateState=function(){return g.username&&g.url?"":'Need at least 2 parameters: "username" and "url".'},e.saveDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PUT",data:a.getContent(),async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.done()},error:function(b){b.message='Cannot save "'+a.getPath()+'" into DAVStorage.',e.fail(b)}})},e.loadDocument=function(a){var d={},f=function(){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(a){d.content=a,e.done(d)},error:function(b){b.status===404?b.message='Document "'+a.getPath()+'" not found in localStorage.':b.message='Cannot load "'+a.getPath()+'" from DAVStorage.',e.fail(b)}})};d.name=a.getPath(),b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PROPFIND",async:!0,dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(c){b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){d.last_modified=b(this).text()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){d.creation_date=b(this).text()}),a.getOption("metadata_only")?e.done(d):f()},error:function(b){b.message='Cannot load "'+a.getPath()+'" informations from DAVStorage.',e.fail(b)}})},e.getDocumentList=function(a){var d=[],f={},h=[];b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/",async:!0,type:"PROPFIND",dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password),Depth:"1"},success:function(a){b(a).find("D\\:response, response").each(function(a,c){if(a>0){f={},b(c).find("D\\:href, href").each(function(){h=b(this).text().split("/"),f.name=h[h.length-1]?h[h.length-1]:h[h.length-2]+"/"});if(f.name===".htaccess"||f.name===".htpasswd")return;b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){f.last_modified=b(this).text()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){f.creation_date=b(this).text()}),d.push(f)}}),e.done(d)},error:function(a){a.message="Cannot get a document list from DAVStorage.",e.fail(a)}})},e.removeDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"DELETE",async:!0,headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.done()},error:function(a){a.status===404?e.done():(a.message='Cannot remove "'+e.getFileName()+'" from DAVStorage.',e.fail(a))}})},e};f.addStorageType("dav",h);var i=function(a,b){var c=f.storage(a,b,"handler"),d={};d.return_value_array=[],d.storagelist=a.storagelist||[],d.nb_storage=d.storagelist.length;var e=c.serialized;return c.serialized=function(){var a=e();return a.storagelist=d.storagelist,a},c.validateState=function(){return d.storagelist.length===0?'Need at least one parameter: "storagelist" containing at least one storage.':""},d.isTheLast=function(){return d.return_value_array.length===d.nb_storage},d.doJob=function(a,b){var e=!1,f=[],g,h=function(a){d.return_value_array.push(a)},i=function(a){e||(f.push(a),d.isTheLast()&&c.fail({status:207,statusText:"Multi-Status",message:b,array:f}))},j=function(a){e||(e=!0,c.done(a))};for(g=0;g<d.nb_storage;g+=1){var k=a.clone(),l=c.newStorage(d.storagelist[g]);k.onResponseDo(h),k.onFailDo(i),k.onDoneDo(j),c.addJob(l,k)}a.setMaxRetry(1)},c.saveDocument=function(a){d.doJob(a,'All save "'+a.getPath()+'" requests have failed.'),c.end()},c.loadDocument=function(a){d.doJob(a,'All load "'+a.getPath()+'" requests have failed.'),c.end()},c.getDocumentList=function(a){d.doJob(a,"All get document list requests have failed."),c.end()},c.removeDocument=function(a){d.doJob(a,'All remove "'+a.getPath()+'" requests have failed.'),c.end()},c};f.addStorageType("replicate",i);var j=function(b,c){var d=f.storage(b,c,"handler"),e={},g=b.storage||!1;e.secondstorage_spec=b.storage||{type:"base"},e.secondstorage_string=JSON.stringify(e.secondstorage_spec);var h="jio/indexed_storage_array",i="jio/indexed_file_array/"+e.secondstorage_string,j=d.serialized;return d.serialized=function(){var a=j();return a.storage=e.secondstorage_spec,a},d.validateState=function(){return g?"":'Need at least one parameter: "storage" containing storage specifications.'},e.isStorageArrayIndexed=function(){return a.getItem(h)?!0:!1},e.getIndexedStorageArray=function(){return a.getItem(h)||[]},e.indexStorage=function(b){var c=e.getIndexedStorageArray();c.push(typeof b=="string"?b:JSON.stringify(b)),a.setItem(h,c)},e.isAnIndexedStorage=function(a){var b=typeof a=="string"?a:JSON.stringify(a),c,d,f=e.getIndexedStorageArray();for(c=0,d=f.length;c<d;c+=1)if(JSON.stringify(f[c])===b)return!0;return!1},e.fileArrayExists=function(){return a.getItem(i)?!0:!1},e.getFileArray=function(){return a.getItem(i)||[]},e.setFileArray=function(b){return a.setItem(i,b)},e.isFileIndexed=function(a){var b,c,d=e.getFileArray();for(b=0,c=d.length;b<c;b+=1)if(d[b].name===a)return!0;return!1},e.addFile=function(b){var c=e.getFileArray();c.push(b),a.setItem(i,c)},e.removeFile=function(b){var c,d,f=e.getFileArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c].name!==b&&g.push(f[c]);a.setItem(i,g)},e.update=function(){var a=function(a){e.isAnIndexedStorage(e.secondstorage_string)||e.indexStorage(e.secondstorage_string),e.setFileArray(a)};d.addJob(d.newStorage(e.secondstorage_spec),d.newCommand("getDocumentList",{path:".",option:{onDone:a,max_retry:3}}))},d.saveDocument=function(a){var b=a.clone();b.onResponseDo(function(){}),b.onDoneDo(function(b){e.isFileIndexed(a.getPath())||e.addFile({name:a.getPath(),last_modified:0,creation_date:0}),e.update(),d.done()}),b.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d.loadDocument=function(a){var b,c,f,g,h=function(a){d.done(a)},i=function(a){d.fail(a)},j=function(){var b=a.clone();b.onResponseDo(function(){}),b.onFailDo(i),b.onDoneDo(h),d.addJob(d.newStorage(e.secondstorage_spec),b)};e.update(),a.getOption("metadata_only")?setTimeout(function(){if(e.fileArrayExists()){b=e.getFileArray();for(c=0,f=b.length;c<f;c+=1)if(b[c].name===a.getPath())return d.done(b[c])}else j()},100):j()},d.getDocumentList=function(a){var b,c,f=!1;e.update(),a.getOption("metadata_only")?(b=setInterval(function(){f&&(d.fail({status:0,statusText:"Timeout",message:"The request has timed out."}),clearInterval(b)),e.fileArrayExists()&&(d.done(e.getFileArray()),clearInterval(b))},100),setTimeout(function(){f=!0},1e4)):(c=a.clone(),c.onDoneDo(function(a){d.done(a)}),c.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),c))},d.removeDocument=function(a){var b=a.clone();b.onResponseDo(function(){}),b.onDoneDo(function(b){e.removeFile(a.getPath()),e.update(),d.done()}),b.onFailDo(function(a){d.fail(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d};f.addStorageType("indexed",j);var k=function(a,c){var e=f.storage(a,c,"handler"),g={},h=a.storage||!1;g.username=a.username||"",g.password=a.password||"",g.secondstorage_spec=a.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_string);var i=e.serialized;return e.serialized=function(){var a=i();return a.username=g.username,a.password=g.password,a.storage=g.secondstorage_string,a},e.validateState=function(){return g.username&&h?"":'Need at least two parameters: "username" and "storage".'},g.encrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",v:1,iter:1e3,ks:256,ts:128,mode:"ccm",adata:"",cipher:"aes",salt:"K4bmZG9d704"},g.decrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",ks:256,ts:128,salt:"K4bmZG9d704"},g.encrypt=function(a,b,c){var e=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(e).ct,c)},g.decrypt=function(a,c,e,f){var h,i=b.extend(!0,{},g.decrypt_param_object);i.ct=a||"",i=JSON.stringify(i);try{h=d.decrypt(g.username+":"+g.password,i)}catch(j){c({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."},e,f);return}c(h,e,f)},e.saveDocument=function(a){var b,c,d=function(){g.encrypt(a.getPath(),function(a){b=a,f()})},f=function(){g.encrypt(a.getContent(),function(a){c=a,h()})},h=function(){var d=a.cloneOption(),f;d.onResponse=function(){},d.onDone=function(){e.done()},d.onFail=function(a){e.fail(a)},f=e.newCommand("saveDocument",{path:b,content:c,option:d}),e.addJob(e.newStorage(g.secondstorage_spec),f)};d()},e.loadDocument=function(a){var b,c,d=function(){g.encrypt(a.getPath(),function(a){b=a,f()})},f=function(){var c=a.cloneOption(),d;c.onResponse=function(){},c.onFail=i,c.onDone=h,d=e.newCommand("loadDocument",{path:b,option:c}),e.addJob(e.newStorage(g.secondstorage_spec),d)},h=function(b){b.name=a.getPath(),a.getOption("metadata_only")?e.done(b):g.decrypt(b.content,function(a){typeof a=="object"?e.fail({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt"}):(b.content=a,e.done(b))})},i=function(a){e.fail(a)};d()},e.getDocumentList=function(a){var b,c,d,f=0,h,i=!0,j=function(){var b=a.clone();b.onResponseDo(k),b.onDoneDo(function(){}),b.onFailDo(function(){}),e.addJob(e.newStorage(g.secondstorage_spec),b)},k=function(a){if(a.status.isDone()){h=a.value;for(c=0,d=h.length;c<d;c+=1)g.decrypt(h[c].name,l,c,"name")}else e.fail(a.error)},l=function(a,b,c){var g;f++;if(typeof a=="object"){i&&(i=!1,e.fail({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."})),i=!1;return}h[b][c]=a,f===d&&i&&e.done(h)};j()},e.removeDocument=function(a){var b,c=function(){g.encrypt(a.getPath(),function(a){b=a,d()})},d=function(){var c=a.cloneOption();c.onResponse=f,c.onFail=function(){},c.onDone=function(){},e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("removeDocument",{path:b,option:c}))},f=function(a){a.status.isDone()?e.done():e.fail(a.error)};c()},e};f.addStorageType("crypt",k);var l=function(b,c){var d=f.storage(b,c,"handler"),g={};b=b||{},c=c||{},g.username=b.username||"";var h=b.storage?!0:!1;g.secondstorage_spec=b.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_spec);var i="jio/conflictmanager/"+g.username+"/"+g.secondstorage_string+"/",j=d.serialized;return d.serialized=function(){var a=j();return a.username=g.username,a.storage=g.secondstorage_spec,a},d.validateState=function(){return g.username&&h?"":'Need at least two parameter: "username" and "storage".'},g.removeValuesFromArrayWhere=function(a,b){var c,d=[];for(c=0;c<a.length;c+=1)b(a[c])||d.push(a[c]);return d},g.removeConflict=function(a,b){var c,d=g.removeValuesFromArrayWhere(a,function(a){return a.hash===b});for(c=0;c<d.length;c+=1)a[c]=d[c];a.length=d.length},g.addConflict=function(a,b){var c;for(c=0;c<a.length;c+=1)if(b.hash===a[c].hash)return;a.push(b)},g.loadMetadataFromDistant=function(a,b,c,e){var f=a.cloneOption();f.metadata_only=!1,f.onResponse=function(){},f.onFail=e,f.onDone=c;var h=d.newCommand("loadDocument",{path:b,option:f});d.addJob(d.newStorage(g.secondstorage_spec),h)},g.saveMetadataToDistant=function(a,b,c,e,f){var h=a.cloneOption();h.onResponse=function(){},h.onFail=f,h.onDone=e;var i=d.newCommand("saveDocument",{path:b,content:JSON.stringify(c),option:h});d.addJob(d.newStorage(g.secondstorage_spec),i)},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){return a._wait=a._wait||{},a._wait[b]?(a._wait[b]--,function(){}):(c=c||[],a[b].apply(a[b],c))},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},d.saveDocument=function(b){var c={},f=g.newAsyncModule(),h=b.getPath()+".metadata",j=i+h,k={},l={},m=0,n=!1,o=e(b.getContent()),p=new Date;c.updateLocalMetadata=function(){var b={revision:0,hash:"",last_modified:0,creation_date:p.getTime()};k=a.getItem(j),k?k.owner[g.username]||(k.owner[g.username]=b):(k={winner:{},owner:{},conflict_list:[]},k.winner={revision:0,owner:g.username,hash:""},k.owner[g.username]=b),f.call(c,"checkForConflicts")},c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,h,function(a){l=JSON.parse(a.content),f.call(c,"checkForConflicts")},function(a){a.status===404?(l=k,n=!0,f.call(c,"checkForConflicts")):f.call(c,"fail",[a])})},c.checkForConflicts=function(){var d=function(){a.setItem(j,l),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"saveRevision")},h=function(b){a.setItem(j,l),f.neverCall(c,"done"),f.call(c,"saveMetadata"),f.call(c,"saveRevision"),f.call(c,"fail",[b])},i=function(){var a;n||!l.owner[l.winner.owner]?a=p.getTime():a=l.owner[l.winner.owner].creation_date||p.getTime(),l.owner[g.username]?m=l.owner[g.username].revision:l.owner[g.username]={},l.owner[g.username].last_modified=p.getTime(),l.owner[g.username].creation_date=a,l.owner[g.username].hash=o},q=function(){i(),l.winner.owner=g.username,l.winner.revision++,l.winner.hash=o,l.owner[g.username].revision=l.winner.revision},r=function(){i(),l.owner[g.username].revision++};if(n){q(),d();return}if(k.winner.revision===l.winner.revision&&k.winner.hash===l.winner.hash&&(!l.owner[g.username]||g.username===l.winner.owner||l.owner[g.username].revision<l.owner[l.winner.owner].revison))q(),d();else{var s={label:"revision",path:b.getPath(),method:"saveDocument",owner:g.username,conflict_owner:{name:l.winner.owner,revision:l.winner.revision,hash:l.winner.hash}},t=e(JSON.stringify(s));s.hash=t;var u,v,w=!1,x=b.getOption("known_conflict_list")||[];for(u=0;u<x.length;u+=1){x[u].hash===t&&(g.removeConflict(l.conflict_list,t),q(),d(),w=!0);for(v=0;v<l.conflict_list.length;v+=1)x[u].hash===l.conflict_list[v].hash&&g.removeConflict(l.conflict_list,x[u].hash)}if(!w){r(),g.addConflict(l.conflict_list,s),h({status:0,statusText:"Revision Conflict",message:"Someone has already modified this document."});var y=b.getOption("onConflict")||function(){};y(s)}}},c.saveMetadata=function(){g.saveMetadataToDistant(b,h,l,function(){f.call(c,"done")},function(a){f.call(c,"fail",[a])})},c.saveRevision=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a])},a.onDone=function(){f.call(c,"deletePreviousRevision")};var e=d.newCommand("saveDocument",{path:b.getPath()+"."+l.owner[g.username].revision+"."+g.username,content:b.getContent(),option:a});d.addJob(d.newStorage(g.secondstorage_spec),e)},c.deletePreviousRevision=function(){if(m===0||!!l.owner[g.username]&&m===l.owner[g.username].revision)f.call(c,"done");else{var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a])},a.onDone=function(){f.call(c,"done")};var e=d.newCommand("removeDocument",{path:b.getPath()+"."+m+"."+g.username,option:a});d.addJob(d.newStorage(g.secondstorage_spec),e)}},c.fail=function(a){f.neverCall(c,"fail"),f.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){f.neverCall(c,"done"),f.neverCall(c,"fail"),d.done()},f.wait(c,"checkForConflicts",1),f.call(c,"loadMetadataFromDistant"),f.call(c,"updateLocalMetadata")},d.loadDocument=function(b){var c={},e=g.newAsyncModule(),f=b.getPath()+".metadata",h=i+f,j={},k="",l;c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,f,function(a){j=JSON.parse(a.content),k=b.getOption("owner"),e.wait(c,"done",1),k?e.call(c,"loadOwner"):e.call(c,"loadWinner"),e.call(c,"updateLocalMetadata")},function(a){e.end(),e.call(c,"fail",[a])})},c.updateLocalMetadata=function(){a.setItem(h,j),e.call(c,"done")},c.loadWinner=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){e.call(c,"fail",[a]),e.end()},a.onDone=function(a){l=a,l.name=b.getPath(),e.call(c,"done")};var f=d.newCommand("loadDocument",{path:b.getPath()+"."+j.winner.revision+"."+j.winner.owner,option:a});d.addJob(d.newStorage(g.secondstorage_spec),f)},c.loadOwner=function(){var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){e.end(),e.call(c,"fail",[a])},a.onDone=function(a){l=a,l.name=b.getPath(),e.call(c,"done")};if(!j.owner[k]){a.onFail({status:404,statusText:"Not Found",message:"Document not found."});return}var f=d.newCommand("loadDocument",{path:b.getPath()+"."+j.owner[k].revision+"."+k,option:a});d.addJob(d.newStorage(g.secondstorage_spec),f)},c.fail=function(a){e.neverCall(c,"fail"),e.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){e.neverCall(c,"done"),e.neverCall(c,"fail"),d.done(l)},e.call(c,"loadMetadataFromDistant")},d.getDocumentList=function(b){var c={},e=g.newAsyncModule(),f=[],h=[],i=0;c.retreiveList=function(){var i=b.cloneOption();i.metadata_only=!1,i.onResponse=function(){},i.onFail=function(a){e.call(c,"fail",[a])},i.onDone=function(g){var i;for(i=0;i<g.length;i+=1){var j=g[i].name.split(".")||[],k,l={};if(j[j.length-1]==="metadata"){try{k=JSON.parse(g[i].content)}catch(m){continue}h.push(k),j.length--,l.name=j.join("."),l.creation_date=k.owner[k.winner.owner].creation_date,l.last_modified=k.owner[k.winner.owner].last_modified,f.push(l)}}if(b.getOption("metadata_only"))e.call(c,"done",[f]);else{if(g.length===0)return d.done([]);e.wait(c,"done",f.length-1);for(i=0;i<f.length;i+=1)a.setItem(f[i].name+".metadata",h[i]),e.call(c,"loadFile",[f[i],h[i].winner.revision,h[i].winner.owner]);d.end()}};var j=d.newCommand("getDocumentList",{path:b.getPath(),option:i});d.addJob(d.newStorage(g.secondstorage_spec),j)},c.loadFile=function(a,h,i){var j=b.cloneOption();j.onResponse=function(){},j.onFail=function(a){e.call(c,"fail",[a]),e.end()},j.onDone=function(b){a.content=b.content,e.call(c,"done",[f])};var k=d.newCommand("loadDocument",{path:a.name+"."+h+"."+i,option:j});d.addJob(d.newStorage(g.secondstorage_spec),k)},c.fail=function(a){e.neverCall(c,"fail"),e.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(a){e.neverCall(c,"done"),e.neverCall(c,"fail"),d.done(a)},e.call(c,"retreiveList")},d.removeDocument=function(b){var c={},f=g.newAsyncModule(),h=b.getPath()+".metadata",j=i+h,k={},l={},m=0,n=!0,o=!1;c.updateLocalMetadata=function(){var b={revision:0,hash:"",last_modified:0,creation_date:0};k=a.getItem(j),k?k.owner[g.username]||(k.owner[g.username]=b):(n=!1,k={winner:{},owner:{},conflict_list:[]},k.winner={revision:0,owner:g.username,hash:""},k.owner[g.username]=b),f.call(c,"checkForConflicts")},c.loadMetadataFromDistant=function(){g.loadMetadataFromDistant(b,h,function(a){l=JSON.parse(a.content),f.call(c,"checkForConflicts")},function(a){if(a.status===404){l=k,o=!0,f.call(c,"checkForConflicts");return}f.call(c,"fail",[a]),f.end()})},c.checkForConflicts=function(){var d=function(){a.setItem(j,l),f.wait(c,"done",1),f.call(c,"saveMetadata"),f.call(c,"removeRevision")},h=function(){l.owner[g.username]&&(m=l.owner[g.username].revision,delete l.owner[g.username])},i=function(){h(),l.winner.owner=g.username,l.winner.revision=0,l.winner.hash=""},p=function(){h()};if(!n)return f.call(c,"fail",[{status:0,statusText:"Unknown Document",message:"You must load the document before delete it."}]);if(o)return a.deleteItem(j),f.call(c,"done");if(k.winner.revision===l.winner.revision&&k.winner.hash===l.winner.hash&&(!l.owner[g.username]||g.username===l.winner.owner||l.owner[g.username].revision<l.owner[l.winner.owner].revison))i(),d();else{var q={label:"revision",path:b.getPath(),method:"removeDocument",owner:g.username,conflict_owner:{name:l.winner.owner,revision:l.winner.revision,hash:l.winner.hash}},r=e(JSON.stringify(q));q.hash=r;var s,t,u=!1,v=b.getOption("known_conflict_list")||[];console.log("1 "+JSON.stringify(v));for(s=0;s<v.length;s+=1){console.log("2"),v[s].hash===r&&(g.removeConflict(l.conflict_list,r),i(),d(),u=!0);for(t=0;t<l.conflict_list.length;t+=1)console.log("3"),v[s].hash===l.conflict_list[t].hash&&g.removeConflict(l.conflict_list,v[s].hash)}if(!u){p(),g.addConflict(l.conflict_list,q),f.neverCall(c,"done"),a.setItem(j,l),f.call(c,"saveMetadata"),f.call(c,"fail",[{status:0,statusText:"Revision Conflict",message:"Someone has already modified this document."}]);var w=b.getOption("onConflict")||function(){};w(q)}}},c.saveMetadata=function(){g.saveMetadataToDistant(b,h,l,function(){f.call(c,"done")},function(a){f.call(c,"fail",[a]),f.end()})},c.removeRevision=function(){if(m===0||!!l.owner[g.username]&&m===l.owner[g.username].revision)f.call(c,"done");else{var a=b.cloneOption();a.onResponse=function(){},a.onFail=function(a){f.call(c,"fail",[a]),f.end()},a.onDone=function(){f.call(c,"done")};var e=d.newCommand("removeDocument",{path:b.getPath()+"."+m+"."+g.username,option:a});d.addJob(d.newStorage(g.secondstorage_spec),e)}},c.fail=function(a){f.neverCall(c,"fail"),f.neverCall(c,"done"),b.setMaxRetry(1),d.fail(a)},c.done=function(){f.neverCall(c,"done"),f.neverCall(c,"fail"),d.done()},f.wait(c,"checkForConflicts",1),f.call(c,"loadMetadataFromDistant"),f.call(c,"updateLocalMetadata")},d};f.addStorageType("conflictmanager",l)})(LocalOrCookieStorage,jQuery,Base64,sjcl,hex_sha256,jio);
\ No newline at end of file
......@@ -35,6 +35,24 @@ var newConflictManagerStorage = function ( spec, my ) {
}
return newarray;
};
priv.removeConflict = function (conflict_array,conflict_hash) {
var i,tmp = priv.removeValuesFromArrayWhere(
conflict_array,
function (v) { return (v.hash === conflict_hash); });
for (i = 0; i < tmp.length; i+= 1) {
conflict_array[i] = tmp[i];
}
conflict_array.length = tmp.length;
};
priv.addConflict = function (conflict_array,conflict_object) {
var i;
for (i = 0; i < conflict_array.length; i+= 1) {
if (conflict_object.hash === conflict_array[i].hash) {
return;
}
}
conflict_array.push(conflict_object);
};
priv.loadMetadataFromDistant = function (command,path,onDone,onFail) {
var cloned_option = command.cloneOption ();
......@@ -58,7 +76,7 @@ var newConflictManagerStorage = function ( spec, my ) {
'saveDocument',{path:path,
content:JSON.stringify (content),
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
......@@ -146,6 +164,21 @@ var newConflictManagerStorage = function ( spec, my ) {
});
};
o.checkForConflicts = function () {
var saveAndDone = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
};
var saveAndFail = function (error) {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
am.call(o,'fail',[error]);
};
var updateMetadataCommon = function () {
var original_creation_date;
......@@ -186,25 +219,21 @@ var newConflictManagerStorage = function ( spec, my ) {
// if this is a new file
if (is_a_new_file) {
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
saveAndDone();
return;
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_file_metadata.winner.hash ===
command_file_metadata.winner.hash) {
// OK! Now, update distant metadata, store them and save
command_file_metadata.winner.hash && (
!command_file_metadata.owner[priv.username] || (
priv.username === command_file_metadata.winner.owner ||
command_file_metadata.owner[priv.username].
revision < command_file_metadata.owner[
command_file_metadata.winner.owner].revison))) {
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
saveAndDone();
} else {
// if conflict
var conflict_object = {
......@@ -222,38 +251,44 @@ var newConflictManagerStorage = function ( spec, my ) {
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i, known_conflict_list =
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
var compare_fun = function (v) {
return (v.hash === conflict_hash);
};
for (i = 0; i < known_conflict_list.length; i+= 1) {
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
command_file_metadata.conflict_list =
priv.removeValuesFromArrayWhere(
command_file_metadata.conflict_list,
compare_fun);
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
return;
saveAndDone();
done = true;
}
for (j = 0; j < command_file_metadata.conflict_list.length;
j+= 1) {
if (known_conflict_list[i].hash ===
command_file_metadata.conflict_list[j].hash) {
// if known other conflict
// it is solved but the current conflict is
// different than this one.
priv.removeConflict(
command_file_metadata.conflict_list,
known_conflict_list[i].hash);
}
}
}
updateCommandMetadataOnConflict();
// if unknown conflict
command_file_metadata.conflict_list.push (conflict_object);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
am.call(o,'saveRevision');
am.call(o,'fail',[
{status:0,statusText:'Revision Conflict',
message:'Someone has already modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
if (!done) {
updateCommandMetadataOnConflict();
// if unknown conflict
priv.addConflict (command_file_metadata.conflict_list,
conflict_object);
saveAndFail({status:0,statusText:'Revision Conflict',
message:'Someone has already'+
' modified this document.'});
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
}
}
};
o.saveMetadata = function () {
......@@ -281,7 +316,7 @@ var newConflictManagerStorage = function ( spec, my ) {
'.' + priv.username,
content:command.getContent(),
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
......@@ -304,7 +339,7 @@ var newConflictManagerStorage = function ( spec, my ) {
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
......@@ -534,6 +569,7 @@ var newConflictManagerStorage = function ( spec, my ) {
local_file_metadata = {},
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
metadata_object_known = true,
is_a_new_file = false;
o.updateLocalMetadata = function () {
......@@ -549,6 +585,7 @@ var newConflictManagerStorage = function ( spec, my ) {
new_owner_object;
}
} else {
metadata_object_known = false;
local_file_metadata = {
winner: {},
owner: {},
......@@ -579,6 +616,13 @@ var newConflictManagerStorage = function ( spec, my ) {
});
};
o.checkForConflicts = function () {
var removeAndDone = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
};
var updateMetadataCommon = function () {
if (command_file_metadata.owner[priv.username]) {
previous_revision = command_file_metadata.owner[
......@@ -595,6 +639,12 @@ var newConflictManagerStorage = function ( spec, my ) {
var updateCommandMetadataOnConflict = function () {
updateMetadataCommon ();
};
// if we don't known what is will be removed fail.
if (!metadata_object_known) {
return am.call(o,'fail',[{
status:0,statusText:'Unknown Document',
message:'You must load the document before delete it.'}]);
}
// if this is a new file
if (is_a_new_file) {
LocalOrCookieStorage.deleteItem (local_metadata_file_name);
......@@ -604,14 +654,15 @@ var newConflictManagerStorage = function ( spec, my ) {
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_file_metadata.winner.hash ===
command_file_metadata.winner.hash) {
command_file_metadata.winner.hash && (
!command_file_metadata.owner[priv.username] || (
priv.username === command_file_metadata.winner.owner ||
command_file_metadata.owner[priv.username].
revision < command_file_metadata.owner[
command_file_metadata.winner.owner].revison))) {
// OK! Now, update distant metadata, store them and remove
updateCommandMetadataNotOnConflict();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
removeAndDone();
} else {
// if conflict
var conflict_object = {
......@@ -629,38 +680,52 @@ var newConflictManagerStorage = function ( spec, my ) {
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i, known_conflict_list =
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
var compare_fun = function (v) {
return (v.hash === conflict_hash);
};
console.log ('1 ' + JSON.stringify (known_conflict_list));
for (i = 0; i < known_conflict_list.length; i+= 1) {
console.log ('2');
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
command_file_metadata.conflict_list =
priv.removeValuesFromArrayWhere(
command_file_metadata.conflict_list,
compare_fun);
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
am.wait(o,'done',1);
am.call(o,'saveMetadata');
am.call(o,'removeRevision');
return;
removeAndDone();
done = true;
}
for (j = 0; j < command_file_metadata.conflict_list.length;
j+= 1) {
console.log ('3');
if (known_conflict_list[i].hash ===
command_file_metadata.conflict_list[j].hash) {
// if known other conflict
// it is solved but the current conflict is
// different than this one.
priv.removeConflict(
command_file_metadata.conflict_list,
known_conflict_list[i].hash);
}
}
}
updateCommandMetadataOnConflict();
// if unknown conflict
command_file_metadata.conflict_list.push (conflict_object);
am.neverCall(o,'done');
am.call(o,'saveMetadata');
// am.call(o,'removeRevision');
am.call(o,'fail',[
{status:0,statusText:'Revision Conflict',
message:'Someone has already modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
if (!done) {
updateCommandMetadataOnConflict();
// if unknown conflict
priv.addConflict (command_file_metadata.conflict_list,
conflict_object);
am.neverCall(o,'done');
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.call(o,'saveMetadata');
// am.call(o,'removeRevision');
am.call(o,'fail',[{status:0,statusText:'Revision Conflict',
message:'Someone has already'+
' modified this document.'}]);
var onConflict = command.getOption('onConflict') ||
function (){};
onConflict(conflict_object);
}
}
};
o.saveMetadata = function () {
......@@ -693,7 +758,7 @@ var newConflictManagerStorage = function ( spec, my ) {
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
newcommand.setMaxRetry (0); // inf
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
......
......@@ -880,31 +880,6 @@ test ('Remove document', function () {
{type:'dummyall3tries',username:'2'}]});
o.mytest('DummyStorageAllOK,3tries: remove document.','done');
o.jio.stop();
o.jio = JIO.newJio({type:'replicate',storagelist:[
{type:'dummyall3tries',username:'a'},
{type:'dummyall3tries',username:'b'}]});
o.f = function (result) {
if (!result.status.isDone()) {
ok (false, 'Remove failed!');
}
};
o.f2 = function (result) {
if (!result.status.isDone()) {
ok (false, 'Remove failed!');
}
};
o.t.spy(o,'f');
o.t.spy(o,'f2');
o.jio.removeDocument('file',{onResponse:o.f,max_retry:3});
o.jio.removeDocument('memo',{onResponse:o.f2,max_retry:3});
o.clock.tick(5000);
ok (o.f.calledOnce && o.f2.calledOnce,
'DummyStorageAll3tries,3tries: remove document 2 times at once');
if (!(o.f.calledOnce && o.f2.calledOnce)) {
ok (o.f.calledOnce, 'first callback called once');
ok (o.f2.calledOnce, 'second callback called once');
}
});
module ('Jio IndexedStorage');
......@@ -1224,14 +1199,89 @@ test ('Simple methods', function () {
o.jio.stop();
});
test ('Revision Conflicts' , function () {
test ('Remove Errors', function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'true') {
return ok(true,message);
if (res === 'status') {
deepEqual (result.status.getLabel(),value,message);
} else {
deepEqual (result[res],value,message);
}
};
o.t.spy(o,function_name);
};
o.tick = function (tick, function_name) {
function_name = function_name || 'f'
o.clock.tick(tick || 1000);
if (!o[function_name].calledOnce) {
if (o[function_name].called) {
ok(false, 'too much results');
} else {
ok(false, 'no response');
}
}
};
o.jio_1 = JIO.newJio({type:'conflictmanager',
username:'1',
storage:{type:'local',
username:'conflictrevision',
applicationname:'jiotests'}});
o.jio_2 = JIO.newJio({type:'conflictmanager',
username:'2',
storage:{type:'local',
username:'conflictrevision',
applicationname:'jiotests'}});
o.spy ('status','fail','removing unexistant "file.doc" owner "1",'+
' error');
o.jio_1.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','done','saving "file.doc" owner "1",'+
' ok');
o.jio_1.saveDocument('file.doc','content1',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','fail','removing existant "file.doc" owner "2",'+
' error');
o.jio_2.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','fail','removing existant "file.doc" owner "2",'+
' error');
o.jio_2.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','done','removing existant "file.doc" owner "1",'+
' error');
o.jio_1.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','done','saving "file.doc" owner "2",'+
' ok');
o.jio_2.saveDocument('file.doc','content1',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','done','loading "file.doc" owner "1",'+
' ok');
o.jio_1.loadDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy ('status','done','removing "file.doc" owner "1",'+
' ok');
o.jio_1.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.jio_2.stop();
o.jio_1.stop();
});
test ('Revision Conflicts' , function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'status') {
deepEqual (result.status.getLabel(),value,message);
} else {
......@@ -1294,8 +1344,21 @@ test ('Revision Conflicts' , function () {
onResponse:o.f,max_retry:1,onConflict:o.c});
o.tick(undefined,'f');
o.tick(0,'c');
if (!o.co) { return ok(false,'impossible to continue the tests'); }
o.co = undefined;
if (!o.co) { ok(false,'impossible to continue the tests'); }
o.spy('status','fail',"don't solve anything,"+
' save "file.doc" with owner "me", forth revision, conflict!');
o.c = function (conflict_object) {
o.co = conflict_object;
ok (true,'onConflict callback called once');
};
o.t.spy(o,'c');
o.jio_me.saveDocument('file.doc','content4me',{
onResponse:o.f,max_retry:1,onConflict:o.c});
o.tick();
o.tick(0,'c');
if (!o.co) { return ok(false,'impossible to continue the tests'); }
o.spy('status','done','solving conflict and save "file.doc" with owner'+
' "me", forth revision, no conflict.');
......@@ -1305,8 +1368,11 @@ test ('Revision Conflicts' , function () {
o.spy('status','done','removing "file.doc" with owner "me",'+
' no conflict.');
o.jio_me.removeDocument('file.doc',{onResponse:o.f,max_retry:1});
o.c = o.t.spy();
o.jio_me.removeDocument('file.doc',{onResponse:o.f,max_retry:1,
onConflict:o.c});
o.tick();
if (o.c.called) { ok(false, 'conflict callback called!'); }
o.spy('status','fail','saving "file.doc" with owner "him",'+
' any revision, conflict!');
......@@ -1317,13 +1383,108 @@ test ('Revision Conflicts' , function () {
o.t.spy(o,'c');
o.jio_him.saveDocument('file.doc','content4him',{
onResponse:o.f,max_retry:1,onConflict:o.c});
o.tick(undefined,'f');
o.tick();
o.tick(0,'c');
o.jio_me.stop();
o.jio_him.stop();
});
test ('Solving Conflict Conflicts' , function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'status') {
deepEqual (result.status.getLabel(),value,message);
} else {
deepEqual (result[res],value,message);
}
};
o.t.spy(o,function_name);
};
o.tick = function (tick, function_name) {
function_name = function_name || 'f'
o.clock.tick(tick || 1000);
if (!o[function_name].calledOnce) {
if (o[function_name].called) {
ok(false, 'too much results');
} else {
ok(false, 'no response');
}
}
};
o.jio_you = JIO.newJio({type:'conflictmanager',
username:'you',
storage:{type:'local',
username:'conflictrevision',
applicationname:'jiotests'}});
o.jio_her = JIO.newJio({type:'conflictmanager',
username:'her',
storage:{type:'local',
username:'conflictrevision',
applicationname:'jiotests'}});
o.spy('status','done','saving "file.doc" with owner "you",'+
' first revision, no conflict.');
o.jio_you.saveDocument('file.doc','content1you',
{onResponse:o.f,max_retry:1});
o.tick();
o.spy('status','done','loading "file.doc" with owner "her",'+
' last revision, no conflict.');
o.jio_her.loadDocument('file.doc',{onResponse:o.f,max_retry:1});
o.tick();
o.spy('status','done','saving "file.doc" with owner "her",'+
' next revision, no conflict.');
o.jio_her.saveDocument('file.doc','content1her',
{onResponse:o.f,max_retry:1});
o.tick();
o.spy('status','fail','saving "file.doc" with owner "you",'+
' second revision, conflict!');
o.c = function (conflict_object) {
o.co = conflict_object;
ok (true,'onConflict callback called once');
};
o.t.spy(o,'c');
o.jio_you.saveDocument('file.doc','content3you',{
onResponse:o.f,max_retry:1,onConflict:o.c});
o.tick();
o.tick(0,'c');
if (!o.co) { return ok(false,'impossible to continue the tests'); }
o.spy('status','done','saving "file.doc" with owner "her",'+
' next revision, no conflict.');
o.jio_her.saveDocument('file.doc','content2her',
{onResponse:o.f,max_retry:1});
o.tick();
o.spy('status','fail','solving conflict and save "file.doc" with owner'+
' "you", fith revision, conflict!');
o.c = function (conflict_object) {
o.co = conflict_object;
ok (true, 'onConflict callback called once');
};
o.t.spy(o,'c');
o.jio_you.saveDocument('file.doc','content4you',{
onResponse:o.f,max_retry:1,known_conflict_list:[o.co],onConflict:o.c});
o.co = undefined;
o.tick();
o.tick(0,'c');
if (!o.co) { return ok(false,'impossible to continue the tests'); }
o.spy('status','done','solving conflict and save "file.doc" with owner'+
' "you", forth revision, no conflict.');
o.jio_you.saveDocument('file.doc','content5you',{
onResponse:o.f,max_retry:1,known_conflict_list:[o.co]});
o.tick();
o.jio_you.stop();
o.jio_her.stop();
});
}; // end thisfun
if (window.requirejs) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment