Commit 1903b827 authored by Tristan Cavelier's avatar Tristan Cavelier

Updating and Improving Conflict Manager Storage

However, getDocumentList is not complete and do nothing for now.
parent ae343762
/*! JIO Storage - v0.1.0 - 2012-07-25
/*! JIO Storage - v0.1.0 - 2012-08-01
* Copyright (c) 2012 Nexedi; Licensed */
(function(LocalOrCookieStorage, $, Base64, sjcl, hex_sha256, Jio) {
......@@ -137,8 +137,8 @@ var newLocalStorage = function ( spec, my ) {
doc.content = command.getContent();
}
LocalOrCookieStorage.setItem(path, doc);
that.done();
}, 100);
that.success ();
});
}; // end saveDocument
/**
......@@ -160,16 +160,16 @@ var newLocalStorage = function ( spec, my ) {
'jio/local/'+priv.username+'/'+
priv.applicationname+'/'+command.getPath());
if (!doc) {
that.fail({status:404,statusText:'Not Found.',
message:'Document "'+ command.getPath() +
'" not found in localStorage.'});
that.error ({status:404,statusText:'Not Found.',
message:'Document "'+ command.getPath() +
'" not found in localStorage.'});
} else {
if (command.getOption('metadata_only')) {
delete doc.content;
}
that.done(doc);
that.success (doc);
}
}, 100);
});
}; // end loadDocument
/**
......@@ -206,8 +206,8 @@ var newLocalStorage = function ( spec, my ) {
}
}
}
that.done(new_array);
}, 100);
that.success (new_array);
});
}; // end getDocumentList
/**
......@@ -224,8 +224,8 @@ var newLocalStorage = function ( spec, my ) {
// deleting
LocalOrCookieStorage.deleteItem(path);
priv.removeFileName(command.getPath());
that.done();
}, 100);
that.success ();
});
};
return that;
};
......@@ -261,6 +261,32 @@ var newDAVStorage = function ( spec, my ) {
return 'Need at least 2 parameters: "username" and "url".';
};
priv.newAsyncModule = function () {
var async = {};
async.call = function (obj,function_name,arglist) {
obj._wait = obj._wait || {};
if (obj._wait[function_name]) {
obj._wait[function_name]--;
return function () {};
}
// ok if undef or 0
arglist = arglist || [];
return obj[function_name].apply(obj[function_name],arglist);
};
async.neverCall = function (obj,function_name) {
obj._wait = obj._wait || {};
obj._wait[function_name] = -1;
};
async.wait = function (obj,function_name,times) {
obj._wait = obj._wait || {};
obj._wait[function_name] = times;
};
async.end = function () {
async.call = function(){};
};
return async;
};
/**
* Saves a document in the distant dav storage.
* @method saveDocument
......@@ -282,12 +308,12 @@ var newDAVStorage = function ( spec, my ) {
priv.username+':'+priv.password)},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function () {
that.done();
that.success();
},
error: function (type) {
type.message = 'Cannot save "' + command.getPath() +
'" into DAVStorage.';
that.fail(type);
that.retry(type);
}
} );
//// end saving on dav
......@@ -313,19 +339,20 @@ var newDAVStorage = function ( spec, my ) {
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function (content) {
doc.content = content;
that.done(doc);
that.success(doc);
},
error: function (type) {
if (type.status === 404) {
type.message = 'Document "' +
command.getPath() +
'" not found in localStorage.';
that.error(type);
} else {
type.message =
'Cannot load "' + command.getPath() +
'" from DAVStorage.';
that.retry(type);
}
that.fail(type);
}
} );
};
......@@ -357,13 +384,17 @@ var newDAVStorage = function ( spec, my ) {
if (!command.getOption('metadata_only')) {
getContent();
} else {
that.done(doc);
that.success(doc);
}
},
error: function (type) {
type.message = 'Cannot load "' + command.getPath() +
'" informations from DAVStorage.';
that.fail(type);
if (type.status === 404) {
that.error(type);
} else {
that.retry(type);
}
}
} );
};
......@@ -373,96 +404,112 @@ var newDAVStorage = function ( spec, my ) {
* @method getDocumentList
*/
that.getDocumentList = function (command) {
var document_array = [], file = {}, path_array = [];
var document_array = [], file = {}, path_array = [],
am = priv.newAsyncModule(), o = {};
$.ajax ( {
url: priv.url + '/dav/' +
priv.username + '/' +
priv.applicationname + '/',
async: true,
type: 'PROPFIND',
dataType: 'xml',
headers: {'Authorization': 'Basic '+Base64.encode(
priv.username + ':' + priv.password ), Depth: '1'},
success: function (xmlData) {
var wait_for_me = 0;
var getContent = function (file) {
wait_for_me ++;
$.ajax ( {
url: priv.url + '/dav/' +
priv.username + '/' +
priv.applicationname + '/' +
file.name,
type: "GET",
async: true,
dataType: 'text', // TODO : is it necessary ?
headers: {'Authorization':'Basic '+
Base64.encode(priv.username +':'+
priv.password)},
success: function (content) {
file.content = content;
// WARNING : files can be disordered because
// of asynchronous action
document_array.push (file);
wait_for_me --;
},
error: function (type) {
type.message = 'Cannot get a document '+
'content from DAVStorage.';
that.fail(type);
wait_for_me --;
o.getContent = function (file) {
$.ajax ( {
url: priv.url + '/dav/' +
priv.username + '/' +
priv.applicationname + '/' +
file.name,
type: "GET",
async: true,
dataType: 'text', // TODO : is it necessary ?
headers: {'Authorization':'Basic '+
Base64.encode(priv.username +':'+
priv.password)},
success: function (content) {
file.content = content;
// WARNING : files can be disordered because
// of asynchronous action
document_array.push (file);
am.call(o,'success');
},
error: function (type) {
type.message = 'Cannot get a document '+
'content from DAVStorage.';
am.call(o,'error',[type]);
}
});
};
o.getDocumentList = function () {
$.ajax ( {
url: priv.url + '/dav/' +
priv.username + '/' +
priv.applicationname + '/',
async: true,
type: 'PROPFIND',
dataType: 'xml',
headers: {'Authorization': 'Basic '+Base64.encode(
priv.username + ':' + priv.password ), Depth: '1'},
success: function (xmlData) {
var response = $(xmlData).find(
'D\\:response, response'
);
var len = response.length;
am.wait(o,'success',len-2);
response.each( function(i,data){
if(i>0) { // exclude parent folder
file = {};
$(data).find('D\\:href, href').each(function(){
path_array = $(this).text().split('/');
file.name =
(path_array[path_array.length-1] ?
path_array[path_array.length-1] :
path_array[path_array.length-2]+'/');
});
if (file.name === '.htaccess' ||
file.name === '.htpasswd') { return; }
$(data).find(
'lp1\\:getlastmodified, getlastmodified'
).each(function () {
file.last_modified = $(this).text();
});
$(data).find(
'lp1\\:creationdate, creationdate'
).each(function () {
file.creation_date = $(this).text();
});
if (!command.getOption ('metadata_only')) {
am.call(o,'getContent',[file]);
} else {
document_array.push (file);
am.call(o,'success');
}
}
});
};
$(xmlData).find(
'D\\:response, response'
).each( function(i,data){
if(i>0) { // exclude parent folder
file = {};
$(data).find('D\\:href, href').each(function(){
path_array = $(this).text().split('/');
file.name =
(path_array[path_array.length-1] ?
path_array[path_array.length-1] :
path_array[path_array.length-2]+'/');
});
if (file.name === '.htaccess' ||
file.name === '.htpasswd') { return; }
$(data).find(
'lp1\\:getlastmodified, getlastmodified'
).each(function () {
file.last_modified = $(this).text();
});
$(data).find(
'lp1\\:creationdate, creationdate'
).each(function () {
file.creation_date = $(this).text();
});
if (!command.getOption ('metadata_only')) {
getContent(file);
} else {
document_array.push (file);
}
},
error: function (type) {
type.message =
'Cannot get a document list from DAVStorage.';
if (type.status === 404) {
am.call(o,'error',[type]);
} else {
am.call(o,'retry',[type]);
}
});
// wait until all getContent are ended, only if needed
var tmpfun = function () {
setTimeout(function() {
if (wait_for_me) {
tmpfun();
} else {
that.done(document_array);
}
},200);
};
tmpfun();
},
error: function (type) {
type.message =
'Cannot get a document list from DAVStorage.';
that.fail(type);
}
} );
}
} );
};
o.retry = function (error) {
am.neverCall(o,'retry');
am.neverCall(o,'success');
am.neverCall(o,'error');
that.retry(error);
};
o.error = function (error) {
am.neverCall(o,'retry');
am.neverCall(o,'success');
am.neverCall(o,'error');
that.error(error);
};
o.success = function () {
am.neverCall(o,'retry');
am.neverCall(o,'success');
am.neverCall(o,'error');
that.success(document_array);
};
am.call (o,'getDocumentList');
};
/**
......@@ -482,15 +529,15 @@ var newDAVStorage = function ( spec, my ) {
priv.username + ':' + priv.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function () {
that.done();
that.success();
},
error: function (type) {
if (type.status === 404) {
that.done();
that.success();
} else {
type.message = 'Cannot remove "' + that.getFileName() +
'" from DAVStorage.';
that.fail(type);
that.retry(type);
}
}
} );
......@@ -528,14 +575,12 @@ var newReplicateStorage = function ( spec, my ) {
priv.doJob = function (command,errormessage) {
var done = false, error_array = [], i,
onResponseDo = function (result) {
onErrorDo = function (result) {
priv.return_value_array.push(result);
},
onFailDo = function (result) {
if (!done) {
error_array.push(result);
if (priv.isTheLast()) {
that.fail (
that.error (
{status:207,
statusText:'Multi-Status',
message:errormessage,
......@@ -543,21 +588,20 @@ var newReplicateStorage = function ( spec, my ) {
}
}
},
onDoneDo = function (result) {
onSuccessDo = function (result) {
priv.return_value_array.push(result);
if (!done) {
done = true;
that.done (result);
that.success (result);
}
};
for (i = 0; i < priv.nb_storage; i+= 1) {
var newcommand = command.clone();
var newstorage = that.newStorage(priv.storagelist[i]);
newcommand.onResponseDo (onResponseDo);
newcommand.onFailDo (onFailDo);
newcommand.onDoneDo (onDoneDo);
newcommand.onErrorDo (onErrorDo);
newcommand.onSuccessDo (onSuccessDo);
that.addJob (newstorage, newcommand);
}
command.setMaxRetry (1);
};
/**
......@@ -771,7 +815,7 @@ var newIndexStorage = function ( spec, my ) {
*/
priv.update = function () {
// retreive list before, and then retreive all files
var getlist_onDone = function (result) {
var getlist_onSuccess = function (result) {
if (!priv.isAnIndexedStorage(priv.secondstorage_string)) {
priv.indexStorage(priv.secondstorage_string);
}
......@@ -780,7 +824,7 @@ var newIndexStorage = function ( spec, my ) {
that.addJob ( that.newStorage (priv.secondstorage_spec),
that.newCommand ('getDocumentList',
{path:'.',
option:{onDone:getlist_onDone,
option:{success:getlist_onSuccess,
max_retry: 3}}) );
};
......@@ -790,17 +834,16 @@ var newIndexStorage = function ( spec, my ) {
*/
that.saveDocument = function (command) {
var newcommand = command.clone();
newcommand.onResponseDo (function(){});
newcommand.onDoneDo (function (result) {
newcommand.onSuccessDo (function (result) {
if (!priv.isFileIndexed(command.getPath())) {
priv.addFile({name:command.getPath(),
last_modified:0,creation_date:0});
}
priv.update();
that.done();
that.success();
});
newcommand.onFailDo (function (result) {
that.fail(result);
newcommand.onErrorDo (function (result) {
that.error(result);
});
that.addJob ( that.newStorage(priv.secondstorage_spec),
newcommand );
......@@ -812,7 +855,7 @@ var newIndexStorage = function ( spec, my ) {
*/
that.loadDocument = function (command) {
var file_array, i, l, new_job,
loadOnDone = function (result) {
loadOnSuccess = function (result) {
// if (file_array[i].last_modified !==
// result.return_value.last_modified ||
// file_array[i].creation_date !==
......@@ -821,16 +864,15 @@ var newIndexStorage = function ( spec, my ) {
// // the one in the second storage. priv.update will
// // take care of refresh the indexed storage
// }
that.done(result);
that.success(result);
},
loadOnFail = function (result) {
that.fail(result);
loadOnError = function (result) {
that.error(result);
},
secondLoadDocument = function () {
var newcommand = command.clone();
newcommand.onResponseDo (function(){});
newcommand.onFailDo (loadOnFail);
newcommand.onDoneDo (loadOnDone);
newcommand.onErrorDo (loadOnError);
newcommand.onSuccessDo (loadOnSuccess);
that.addJob ( that.newStorage(priv.secondstorage_spec),
newcommand );
};
......@@ -841,7 +883,7 @@ var newIndexStorage = function ( spec, my ) {
file_array = priv.getFileArray();
for (i = 0, l = file_array.length; i < l; i+= 1) {
if (file_array[i].name === command.getPath()) {
return that.done(file_array[i]);
return that.success(file_array[i]);
}
}
} else {
......@@ -863,12 +905,12 @@ var newIndexStorage = function ( spec, my ) {
if (command.getOption('metadata_only')) {
id = setInterval(function () {
if (timeout) {
that.fail({status:0,statusText:'Timeout',
message:'The request has timed out.'});
that.error({status:0,statusText:'Timeout',
message:'The request has timed out.'});
clearInterval(id);
}
if (priv.fileArrayExists()) {
that.done(priv.getFileArray());
that.success(priv.getFileArray());
clearInterval(id);
}
},100);
......@@ -877,11 +919,11 @@ var newIndexStorage = function ( spec, my ) {
}, 10000); // 10 sec
} else {
newcommand = command.clone();
newcommand.onDoneDo (function (result) {
that.done(result);
newcommand.onSuccessDo (function (result) {
that.success(result);
});
newcommand.onFailDo (function (result) {
that.fail(result);
newcommand.onErrorDo (function (result) {
that.error(result);
});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
......@@ -894,14 +936,13 @@ var newIndexStorage = function ( spec, my ) {
*/
that.removeDocument = function (command) {
var newcommand = command.clone();
newcommand.onResponseDo (function(){});
newcommand.onDoneDo (function (result) {
newcommand.onSuccessDo (function (result) {
priv.removeFile(command.getPath());
priv.update();
that.done();
that.success();
});
newcommand.onFailDo (function (result) {
that.fail(result);
newcommand.onErrorDo (function (result) {
that.error(result);
});
that.addJob( that.newStorage(priv.secondstorage_spec),
newcommand );
......@@ -976,7 +1017,7 @@ var newCryptedStorage = function ( spec, my ) {
message:'Unable to decrypt.'});
return;
}
callback(tmp);
callback(undefined,tmp);
};
priv.newAsyncModule = function () {
......@@ -1025,9 +1066,8 @@ var newCryptedStorage = function ( spec, my ) {
};
o.save = function () {
var settings = command.cloneOption(), newcommand;
settings.onResponse = function (){};
settings.onDone = function () { that.done(); };
settings.onFail = function (r) { that.fail(r); };
settings.success = function () { that.success(); };
settings.error = function (r) { that.error(r); };
newcommand = that.newCommand(
'saveDocument',
{path:new_file_name,content:new_file_content,option:settings});
......@@ -1054,39 +1094,37 @@ var newCryptedStorage = function ( spec, my ) {
};
o.loadDocument = function () {
var settings = command.cloneOption(), newcommand;
settings.onResponse = function(){};
settings.onFail = o.loadOnFail;
settings.onDone = o.loadOnDone;
settings.error = o.loadOnError;
settings.success = o.loadOnSuccess;
newcommand = that.newCommand (
'loadDocument',
{path:new_file_name,option:settings});
that.addJob (
that.newStorage ( priv.secondstorage_spec ), newcommand );
};
o.loadOnDone = function (result) {
o.loadOnSuccess = function (result) {
result.name = command.getPath();
if (command.getOption('metadata_only')) {
that.done(result);
that.success(result);
} else {
priv.decrypt (result.content, function(res){
if (typeof res === 'object') {
that.fail({status:0,statusText:'Decrypt Fail',
message:'Unable to decrypt'});
priv.decrypt (result.content, function(err,res){
if (err) {
that.error(err);
} else {
result.content = res;
// content only: the second storage should
// manage content_only option, so it is not
// necessary to manage it.
that.done(result);
that.success(result);
}
});
}
};
o.loadOnFail = function (error) {
o.loadOnError = function (error) {
// NOTE : we can re create an error object instead of
// keep the old ex:status=404,message="document 1y59gyl8g
// not found in localStorage"...
that.fail(error);
that.error(error);
};
am.call(o,'encryptFilePath');
}; // end loadDocument
......@@ -1098,51 +1136,57 @@ var newCryptedStorage = function ( spec, my ) {
that.getDocumentList = function (command) {
var result_array = [], am = priv.newAsyncModule(), o = {};
o.getDocumentList = function () {
var newcommand = command.clone();
newcommand.onResponseDo (function(){});
newcommand.onDoneDo (o.getListOnDone);
newcommand.onFailDo (o.getListOnFail);
var settings = command.cloneOption();
settings.success = o.getListOnSuccess;
settings.error = o.getListOnError;
that.addJob (
that.newStorage ( priv.secondstorage_spec ), newcommand );
that.newStorage ( priv.secondstorage_spec ),
that.newCommand ( 'getDocumentList', {path:command.getPath(),
option:settings}) );
};
o.getListOnDone = function (result) {
o.getListOnSuccess = function (result) {
result_array = result;
var i, fun = function () {
var c = i;
priv.decrypt (result[c].name,function (res) {
am.call(o,'pushResult',[res,c,'name']);
var i, decrypt = function (c) {
priv.decrypt (result_array[c].name,function (err,res) {
if (err) {
am.call(o,'error',[err]);
} else {
am.call(o,'pushResult',[res,c,'name']);
}
});
if (!command.getOption('metadata_only')) {
priv.decrypt (result[c].content,function (res) {
am.call(o,'pushResult',[res,c,'content']);
priv.decrypt (result_array[c].content,function (err,res) {
if (err) {
am.call(o,'error',[err]);
} else {
am.call(o,'pushResult',[res,c,'content']);
}
});
}
};
if (command.getOption('metadata_only')) {
am.wait(o,'done',result.length-1);
am.wait(o,'success',result.length-1);
} else {
am.wait(o,'done',result.length*2-1);
am.wait(o,'success',result.length*2-1);
}
for (i = 0; i < result_array.length; i+= 1) {
decrypt(i);
}
for (i = 0; i < result.length; i+= 1) { fun(); }
};
o.getListOnFail = function (error) {
am.call(o,'fail',[error]);
o.getListOnError = function (error) {
am.call(o,'error',[error]);
};
o.pushResult = function (result,index,key) {
if (typeof result === 'object') {
return am.call(o,'fail',[{status:0,statusText:'Decrypt Fail',
message:'Unable to decrypt.'}]);
}
result_array[index][key] = result;
am.call(o,'done');
am.call(o,'success');
};
o.fail = function (error) {
o.error = function (error) {
am.end();
that.fail(error);
that.error (error);
};
o.done = function () {
o.success = function () {
am.end();
that.done(result_array);
that.success (result_array);
};
am.call(o,'getDocumentList');
}; // end getDocumentList
......@@ -1152,32 +1196,30 @@ var newCryptedStorage = function ( spec, my ) {
* @method removeDocument
*/
that.removeDocument = function (command) {
var new_file_name, am = priv.newAsyncModule(), o = {};
var new_file_name, o = {};
o.encryptFilePath = function () {
priv.encrypt(command.getPath(),function(res) {
new_file_name = res;
am.call(o,'removeDocument');
o.removeDocument();
});
};
o.removeDocument = function () {
var cloned_option = command.cloneOption();
cloned_option.onResponse = o.removeOnResponse;
cloned_option.onFail = function () {};
cloned_option.onDone = function () {};
cloned_option.error = o.removeOnError;
cloned_option.success = o.removeOnSuccess;
that.addJob(that.newStorage(priv.secondstorage_spec),
that.newCommand(
'removeDocument',
{path:new_file_name,
option:cloned_option}));
};
o.removeOnResponse = function (result) {
if (result.status.isDone()) {
that.done();
} else {
that.fail(result.error);
}
o.removeOnSuccess = function (result) {
that.success();
};
am.call(o,'encryptFilePath');
o.removeOnError = function (error) {
that.error (error);
};
o.encryptFilePath();
};
return that;
};
......@@ -1188,64 +1230,35 @@ var newConflictManagerStorage = function ( spec, my ) {
spec = spec || {};
my = my || {};
priv.username = spec.username || '';
var storage_exists = (spec.storage?true:false);
priv.secondstorage_spec = spec.storage || {type:'base'};
priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec);
var local_namespace = 'jio/conflictmanager/'+priv.username+'/'+
var local_namespace = 'jio/conflictmanager/'+
priv.secondstorage_string+'/';
var empty_fun = function (){};
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.username = priv.username;
o.storage = priv.secondstorage_spec;
return o;
};
that.validateState = function () {
if (priv.username && storage_exists) {
if (storage_exists) {
return '';
}
return 'Need at least two parameter: "username" and "storage".';
return 'Need at least one parameter: "storage".';
};
priv.removeValuesFromArrayWhere = function (array,fun) {
var i, newarray = [];
for (i = 0; i < array.length; i+= 1) {
if (!fun(array[i])) {
newarray.push(array[i]);
}
}
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) {
priv.getDistantMetadata = function (command,path,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false;
cloned_option.max_retry = 1; // FIXME : wrong ! (redesign jio & storage)
cloned_option.onResponse = function () {};
cloned_option.onFail = onFail;
cloned_option.onDone = onDone;
cloned_option.max_retry = command.getOption('max_retry') || 3;
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'loadDocument',{path:path,
option:cloned_option});
......@@ -1253,11 +1266,10 @@ var newConflictManagerStorage = function ( spec, my ) {
newcommand );
};
priv.saveMetadataToDistant = function (command,path,content,onDone,onFail) {
priv.saveMetadataToDistant = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = onFail;
cloned_option.onDone = onDone;
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:JSON.stringify (content),
......@@ -1267,17 +1279,204 @@ var newConflictManagerStorage = function ( spec, my ) {
newcommand );
};
priv.saveNewRevision = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:content,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.loadRevision = function (command,path,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand (
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.deleteAFile = function (command,path,success,error) {
var cloned_option = command.cloneOption();
cloned_option.max_retry = 0; // inf
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'removeDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.solveConflict = function (path,content,option) {
var o = {}, am = priv.newAsyncModule(),
command = option.command,
metadata_file_path = path + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = option.previous_revision,
previous_revision_object = option.revision_remove_object || {},
previous_revision_content_object = previous_revision_object[
previous_revision] || {},
now = new Date(),
failerror;
o.getDistantMetadata = function (){
console.log ('c getDistantMetadata');
priv.getDistantMetadata (
command, metadata_file_path,
function (result) {
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + content +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = path + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'previousUpdateMetadata');
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.saveNewRevision = function (){
console.log ('c saveNewRevision ' + current_revision);
priv.saveNewRevision (
command, current_revision_file_path, content,
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.previousUpdateMetadata = function () {
console.log ('c previousUpdateMetadata');
for (var prev_rev in previous_revision_object) {
delete metadata_file_content[prev_rev];
}
am.call(o,'checkForConflicts');
};
o.checkForConflicts = function () {
console.log ('c checkForConflicts');
for (var rev in metadata_file_content) {
var revision_index;
on_conflict = true;
conflict_object =
priv.createConflictObject(
command, metadata_file_content, current_revision
);
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
console.log ('c updateMetadata');
metadata_file_content[current_revision] = {
creation_date: previous_revision_content_object.creation_date ||
now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: false
};
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
console.log ('c saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command, metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deleteAllConflictingRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.deleteAllConflictingRevision = function (){
console.log ('c deleteAllConflictingRevision');
for (var prev_rev in previous_revision_object) {
priv.deleteAFile (
command, path+'.'+prev_rev, empty_fun, empty_fun );
}
};
o.success = function (){
console.log ('c success');
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.success) {option.success(current_revision);}
};
o.error = function (error){
var gooderror = error || failerror || {};
console.log ('c error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.error) {option.error(gooderror);}
};
am.call(o,'getDistantMetadata');
};
priv.createConflictObject = function (command, metadata, revision) {
var cloned_command = command.clone();
var conflict_object = {
path: command.getPath(),
revision: revision,
revision_object: metadata,
getConflictRevisionList: function () {
return this.revision_object;
},
solveConflict: function (content,option) {
option = option || {};
option.previous_revision = this.revision;
option.revision_remove_object = this.revision_object;
option.command = cloned_command;
return priv.solveConflict (
this.path, content, option
);
}
};
return conflict_object;
};
priv.newAsyncModule = function () {
var async = {};
async.call = function (obj,function_name,arglist) {
obj._wait = obj._wait || {};
if (obj._wait[function_name]) {
obj._wait[function_name]--;
return function () {};
return empty_fun;
}
// ok if undef or 0
arglist = arglist || [];
return obj[function_name].apply(obj[function_name],arglist);
setTimeout(function(){
obj[function_name].apply(obj[function_name],arglist);
});
};
async.neverCall = function (obj,function_name) {
obj._wait = obj._wait || {};
......@@ -1288,7 +1487,7 @@ var newConflictManagerStorage = function ( spec, my ) {
obj._wait[function_name] = times;
};
async.end = function () {
async.call = function(){};
async.call = empty_fun;
};
return async;
};
......@@ -1299,259 +1498,162 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.saveDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
local_file_metadata = {}, // local file.metadata
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
is_a_new_file = false,
local_file_hash = hex_sha256 (command.getContent()),
now = new Date();
o.updateLocalMetadata = function () {
var new_owner_object = {revision:0,hash:'',
last_modified:0,
creation_date:now.getTime()};
local_file_metadata =
LocalOrCookieStorage.getItem (local_metadata_file_name);
if ( local_file_metadata ) {
// if metadata already exists
if ( !local_file_metadata.owner[priv.username] ) {
local_file_metadata.owner[priv.username] =
new_owner_object;
}
} else {
local_file_metadata = {
winner: {},
owner: {},
conflict_list: []
};
local_file_metadata.winner = {
revision:0,owner:priv.username,hash:''};
local_file_metadata.owner[priv.username] =
new_owner_object;
}
am.call(o,'checkForConflicts');
};
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('previous_revision'),
previous_revision_file_path = command.getPath() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
console.log ('here');
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){
console.log ('s getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + command.getContent() +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
command_file_metadata = local_file_metadata;
is_a_new_file = true;
am.call(o,'checkForConflicts');
current_revision = '1-' +
hex_sha256 (command.getContent());
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'createMetadata');
} else {
am.call(o,'fail',[error]);
am.call(o,'error',[error]);
}
});
}
);
};
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;
if (is_a_new_file || !command_file_metadata.owner[
command_file_metadata.winner.owner]) {
original_creation_date = now.getTime();
} else {
original_creation_date = command_file_metadata.owner[
command_file_metadata.winner.owner].
creation_date || now.getTime();
o.saveNewRevision = function (){
console.log ('s saveNewRevision ' + current_revision);
priv.saveNewRevision (
command,current_revision_file_path,command.getContent(),
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
if (command_file_metadata.owner[priv.username]) {
previous_revision = command_file_metadata.owner[
priv.username].revision;
} else {
command_file_metadata.owner[priv.username] = {};
);
};
o.checkForConflicts = function () {
for (var rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
command_file_metadata.owner[priv.username].
last_modified = now.getTime();
command_file_metadata.owner[priv.username].
creation_date = original_creation_date;
command_file_metadata.owner[priv.username].hash =
local_file_hash;
};
var updateCommandMetadataNotOnConflict = function () {
updateMetadataCommon ();
command_file_metadata.winner.owner = priv.username;
command_file_metadata.winner.revision ++;
command_file_metadata.winner.hash = local_file_hash;
command_file_metadata.owner[priv.username].revision =
command_file_metadata.winner.revision;
};
var updateCommandMetadataOnConflict = function () {
updateMetadataCommon ();
command_file_metadata.owner[priv.username].revision ++;
}
am.call(o,'updateMetadata');
};
o.createMetadata = function (){
console.log ('s createMetadata');
metadata_file_content = {};
metadata_file_content[current_revision] = {
creation_date: now.getTime(),
last_modified: now.getTime(),
conflict: false,
deleted: false
};
// if this is a new file
if (is_a_new_file) {
updateCommandMetadataNotOnConflict();
saveAndDone();
return;
am.call(o,'saveMetadataOnDistant');
};
o.updateMetadata = function (){
console.log ('s updateMetadata');
var previous_creation_date;
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
delete metadata_file_content[previous_revision];
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_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))) {
updateCommandMetadataNotOnConflict();
saveAndDone();
} else {
// if conflict
var conflict_object = {
label: 'revision',
path: command.getPath(),
method: 'saveDocument',
owner: priv.username,
conflict_owner1: {
name: command_file_metadata.winner.owner,
revision: command_file_metadata.winner.revision,
hash: command_file_metadata.winner.hash
},
conflict_owner2: {
name: priv.username,
revision: 1, // TODO : change it !
hash: local_file_hash
}
},
// gen hash
conflict_hash = hex_sha256 (JSON.stringify (
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
for (i = 0; i < known_conflict_list.length; i+= 1) {
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
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);
}
}
}
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);
}
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: false
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadata = function () {
priv.saveMetadataToDistant (
command,metadata_file_name,command_file_metadata,
function () {
am.call(o,'done');
o.saveMetadataOnDistant = function (){
console.log ('s saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'fail',[error]);
});
};
o.saveRevision = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function () {
am.call(o,'deletePreviousRevision');
};
var newcommand = that.newCommand(
'saveDocument',
{path:command.getPath() + '.' +
command_file_metadata.owner[priv.username].revision +
'.' + priv.username,
content:command.getContent(),
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
am.call(o,'error',[error]);
}
);
};
o.deletePreviousRevision = function () {
if ( previous_revision !== 0 && (
!command_file_metadata.owner[priv.username] ||
previous_revision !==
command_file_metadata.owner[
priv.username].revision ) ) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function () {
am.call(o,'done');
};
var newcommand = that.newCommand(
'removeDocument',
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
am.call(o,'done');
o.deletePreviousRevision = function (){
if (previous_revision !== '0' && !on_conflict) {
console.log ('s deletePreviousRevision ' + previous_revision);
priv.deleteAFile (
command, previous_revision_file_path,
empty_fun,empty_fun);
}
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('s success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(current_revision);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done();
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('s error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.wait(o,'checkForConflicts',1);
am.call(o,'loadMetadataFromDistant');
am.call(o,'updateLocalMetadata');
am.call(o,'getDistantMetadata');
};
/**
......@@ -1561,96 +1663,114 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.loadDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
command_file_metadata = {}, // distant file.metadata
owner = '', loaded_file;
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = command.getOption('revision') || '',
metadata_file_content = null,
metadata_only = command.getOption('metadata_only'),
on_conflict = false, conflict_object = {},
now = new Date(),
doc = {name:command.getPath()},
call404 = function (message) {
am.call(o,'error',[{
status:404,statusText:'Not Found',
message:message
}]);
};
o.getDistantMetadata = function (){
console.log ('l getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
owner = command.getOption('owner');
am.wait(o,'done',1);
// if owner
if (owner) {
am.call(o,'loadOwner');
} else {
// if no owner
am.call(o,'loadWinner');
metadata_file_content = JSON.parse (result.content);
if (!metadata_only) {
am.wait(o,'success',1);
}
am.call(o,'updateLocalMetadata');
am.call(o,'affectMetadata');
am.call(o,'checkForConflicts');
},function (error) {
am.end();
am.call(o,'fail',[error]);
});
am.call(o,'error',[error]);
}
);
};
o.updateLocalMetadata = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.call(o,'done');
o.affectMetadata = function () {
console.log ('l affectMetadata');
var tmp_last_modified = 0;
if (current_revision) {
if (!metadata_file_content[current_revision]) {
return call404('Document revision does not exists.');
}
} else {
for (var rev in metadata_file_content) {
if (tmp_last_modified <
metadata_file_content[rev].last_modified) {
tmp_last_modified =
metadata_file_content[rev].last_modified;
current_revision = rev;
}
}
}
doc.last_modified =
metadata_file_content[current_revision].last_modified;
doc.creation_date =
metadata_file_content[current_revision].creation_date;
doc.revision = current_revision;
doc.revision_object = metadata_file_content;
if (metadata_only) {
am.call(o,'success');
} else {
am.call(o,'loadRevision');
}
};
o.loadWinner = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function (result) {
loaded_file = result;
loaded_file.name = command.getPath();
am.call(o,'done');
};
var newcommand = that.newCommand(
'loadDocument',
{path:command.getPath() + '.' +
command_file_metadata.winner.revision +
'.' + command_file_metadata.winner.owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
o.loadRevision = function (){
console.log ('l loadRevision ' + current_revision);
if (!current_revision ||
metadata_file_content[current_revision].deleted) {
return call404('Document has been removed.');
}
priv.loadRevision (
command, doc.name+'.'+current_revision,
function (result) {
doc.content = result.content;
am.call(o,'success');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.loadOwner = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.end();
am.call(o,'fail',[error]);
};
cloned_option.onDone = function (result) {
loaded_file = result;
loaded_file.name = command.getPath();
am.call(o,'done');
};
if (!command_file_metadata.owner[owner]) {
cloned_option.onFail ({status:404,
statusText:'Not Found',
message:'Document not found.'});
return;
o.checkForConflicts = function () {
console.log ('l checkForConflicts');
if (metadata_file_content[current_revision].conflict) {
on_conflict = true;
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
doc.conflict_object = conflict_object;
}
var newcommand = that.newCommand(
'loadDocument',
{path:command.getPath() + '.' +
command_file_metadata.owner[owner].revision +
'.' + owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
am.call(o,'success');
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('l success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(doc);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done(loaded_file);
o.error = function (error){
var gooderror = error || {status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('l error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.call(o,'loadMetadataFromDistant');
am.call(o,'getDistantMetadata');
};
/**
......@@ -1665,60 +1785,11 @@ var newConflictManagerStorage = function ( spec, my ) {
nb_loaded_file = 0;
o.retreiveList = function () {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false;
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
cloned_option.metadata_only = true;
cloned_option.error = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function (result) {
var i;
for (i = 0; i < result.length; i+= 1) {
if (typeof result[i].content !== 'string') {
return am.call(o,'fail',[{
status:0, statusText:'Invalid content',
message:'Invalid file content, aborting job.'}]);
}
var splitname = result[i].name.split('.') || [];
var content_object;
var doc = {};
if (splitname[splitname.length-1] === 'metadata') {
try {
content_object = JSON.parse (result[i].content);
} catch (e) {
continue;
}
result_list.push(content_object);
splitname.length --;
doc.name = splitname.join('.');
try {
doc.creation_date = content_object.owner[
content_object.winner.owner].creation_date;
doc.last_modified = content_object.owner[
content_object.winner.owner].last_modified;
command_file_metadata_list.push(doc);
} catch (e) {
continue;
}
}
}
if (command.getOption('metadata_only')) {
am.call(o,'done',[command_file_metadata_list]);
} else {
if (result.length === 0) {
return that.done([]);
}
am.wait(o,'done',command_file_metadata_list.length-1);
for (i = 0; i < command_file_metadata_list.length; i+= 1) {
LocalOrCookieStorage.setItem (
command_file_metadata_list[i].name + '.metadata',
result_list[i]);
am.call(o,'loadFile',[
command_file_metadata_list[i],
result_list[i].winner.revision,
result_list[i].winner.owner]);
}
that.end();
}
cloned_option.success = function (result) {
};
var newcommand = that.newCommand(
'getDocumentList',
......@@ -1727,36 +1798,85 @@ var newConflictManagerStorage = function ( spec, my ) {
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
o.loadFile = function (doc,revision,owner) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function (result) {
doc.content = result.content;
o.a = function () { // TODO : find a name
var i;
for (i = 0; i < result.length; i+= 1) {
if (typeof result[i].content !== 'string') {
return am.call(o,'fail',[{
status:0, statusText:'Invalid content',
message:'Invalid file content, aborting job.'}]);
}
var splitname = result[i].name.split('.') || [];
var content_object;
var doc = {};
if (splitname[splitname.length-1] === 'metadata') {
try {
content_object = JSON.parse (result[i].content);
} catch (e) {
continue;
}
result_list.push(content_object);
splitname.length --;
doc.name = splitname.join('.');
try {
doc.creation_date = content_object.owner[
content_object.winner.owner].creation_date;
doc.last_modified = content_object.owner[
content_object.winner.owner].last_modified;
command_file_metadata_list.push(doc);
} catch (e) {
continue;
}
}
}
if (command.getOption('metadata_only')) {
am.call(o,'done',[command_file_metadata_list]);
};
var newcommand = that.newCommand(
'loadDocument',
{path:doc.name + '.' + revision + '.' + owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
};
o.done = function (value) {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done(value);
} else {
if (result.length === 0) {
return that.success([]);
}
am.wait(o,'done',command_file_metadata_list.length-1);
for (i = 0; i < command_file_metadata_list.length; i+= 1) {
LocalOrCookieStorage.setItem (
command_file_metadata_list[i].name + '.metadata',
result_list[i]);
am.call(o,'loadFile',[
command_file_metadata_list[i],
result_list[i].winner.revision,
result_list[i].winner.owner]);
}
that.end();
}
};
am.call(o,'retreiveList');
// o.loadFile = function (doc,revision,owner) {
// var cloned_option = command.cloneOption ();
// cloned_option.error = function (error) {
// am.call(o,'fail',[error]);
// am.end();
// };
// cloned_option.success = function (result) {
// doc.content = result.content;
// am.call(o,'done',[command_file_metadata_list]);
// };
// var newcommand = that.newCommand(
// 'loadDocument',
// {path:doc.name + '.' + revision + '.' + owner,
// option:cloned_option});
// that.addJob ( that.newStorage (priv.secondstorage_spec),
// newcommand );
// };
// o.fail = function (error) {
// am.neverCall(o,'fail');
// am.neverCall(o,'done');
// command.setMaxRetry(1);
// that.error(error);
// };
// o.done = function (value) {
// am.neverCall(o,'done');
// am.neverCall(o,'fail');
// that.success(value);
// };
// am.call(o,'retreiveList');
};
/**
......@@ -1765,218 +1885,130 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.removeDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
local_file_metadata = {},
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
metadata_object_known = true,
is_a_new_file = false;
o.updateLocalMetadata = function () {
var new_owner_object = {revision:0,hash:'',
last_modified:0,
creation_date:0};
local_file_metadata =
LocalOrCookieStorage.getItem (local_metadata_file_name);
if ( local_file_metadata ) {
// if metadata already exists
if ( !local_file_metadata.owner[priv.username] ) {
local_file_metadata.owner[priv.username] =
new_owner_object;
}
} else {
metadata_object_known = false;
local_file_metadata = {
winner: {},
owner: {},
conflict_list: []
};
local_file_metadata.winner = {
revision:0,owner:priv.username,hash:''};
local_file_metadata.owner[priv.username] =
new_owner_object;
}
am.call(o,'checkForConflicts');
};
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('revision'),
previous_revision_file_path = command.getPath() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){
console.log ('r getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
command_file_metadata = local_file_metadata;
is_a_new_file = true;
am.call(o,'checkForConflicts');
return;
am.call(o,'success',['0']);
} else {
am.call(o,'error',[error]);
}
am.call(o,'fail',[error]);
am.end();
});
}
);
};
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[
priv.username].revision;
delete command_file_metadata.owner[priv.username];
for (var rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
};
var updateCommandMetadataNotOnConflict = function () {
updateMetadataCommon();
command_file_metadata.winner.owner = priv.username;
command_file_metadata.winner.revision = 0;
command_file_metadata.winner.hash = '';
};
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);
return am.call(o,'done');
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
console.log ('s updateMetadata');
var previous_creation_date;
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
delete metadata_file_content[previous_revision];
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_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();
removeAndDone();
} else {
// if conflict
var conflict_object = {
label: 'revision',
path: command.getPath(),
method: 'removeDocument',
owner: priv.username,
conflict_owner: {
name: command_file_metadata.winner.owner,
revision: command_file_metadata.winner.revision,
hash: command_file_metadata.winner.hash}
},
// gen hash
conflict_hash = hex_sha256 (JSON.stringify (
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
for (i = 0; i < known_conflict_list.length; i+= 1) {
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
removeAndDone();
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);
}
}
}
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);
}
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: true
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadata = function () {
priv.saveMetadataToDistant (
command,metadata_file_name,command_file_metadata,
function () {
am.call(o,'done');
o.saveMetadataOnDistant = function (){
console.log ('s saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'fail',[error]);
am.end();
});
am.call(o,'error',[error]);
}
);
};
o.removeRevision = function () {
if ( previous_revision !== 0 && (
!command_file_metadata.owner[priv.username] ||
previous_revision !==
command_file_metadata.owner[
priv.username].revision ) ) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function () {
am.call(o,'done');
};
var newcommand = that.newCommand(
'removeDocument',
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
am.call(o,'done');
o.deletePreviousRevision = function (){
if (previous_revision !== '0' && !on_conflict) {
console.log ('s deletePreviousRevision ' + previous_revision);
priv.deleteAFile (
command, previous_revision_file_path,
empty_fun,empty_fun);
}
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('s success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(current_revision);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done();
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('s error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.wait(o,'checkForConflicts',1);
am.call(o,'loadMetadataFromDistant');
am.call(o,'updateLocalMetadata');
am.call(o,'getDistantMetadata');
};
return that;
......
/*! JIO Storage - v0.1.0 - 2012-07-25
/*! JIO Storage - v0.1.0 - 2012-08-01
* 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(i){var j=0,k=function(a){j++,b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.name,type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(b){a.content=b,d.push(a),j--},error:function(a){a.message="Cannot get a document content from DAVStorage.",e.fail(a),j--}})};b(i).find("D\\:response, response").each(function(c,e){if(c>0){f={},b(e).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(e).find("lp1\\:getlastmodified, getlastmodified").each(function(){f.last_modified=b(this).text()}),b(e).find("lp1\\:creationdate, creationdate").each(function(){f.creation_date=b(this).text()}),a.getOption("metadata_only")?d.push(f):k(f)}});var l=function(){setTimeout(function(){j?l():e.done(d)},200)};l()},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?!0:!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){var c=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(c).ct)},g.decrypt=function(a,c){var e,f=b.extend(!0,{},g.decrypt_param_object);f.ct=a||"",f=JSON.stringify(f);try{e=d.decrypt(g.username+":"+g.password,f)}catch(h){c({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."});return}c(e)},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},e.saveDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"save")})},f.encryptFileContent=function(){g.encrypt(a.getContent(),function(a){c=a,d.call(f,"save")})},f.save=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.wait(f,"save",1),d.call(f,"encryptFilePath"),d.call(f,"encryptFileContent")},e.loadDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"loadDocument")})},f.loadDocument=function(){var c=a.cloneOption(),d;c.onResponse=function(){},c.onFail=f.loadOnFail,c.onDone=f.loadOnDone,d=e.newCommand("loadDocument",{path:b,option:c}),e.addJob(e.newStorage(g.secondstorage_spec),d)},f.loadOnDone=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))})},f.loadOnFail=function(a){e.fail(a)},d.call(f,"encryptFilePath")},e.getDocumentList=function(a){var b=[],c=g.newAsyncModule(),d={};d.getDocumentList=function(){var b=a.clone();b.onResponseDo(function(){}),b.onDoneDo(d.getListOnDone),b.onFailDo(d.getListOnFail),e.addJob(e.newStorage(g.secondstorage_spec),b)},d.getListOnDone=function(e){b=e;var f,h=function(){var b=f;g.decrypt(e[b].name,function(a){c.call(d,"pushResult",[a,b,"name"])}),a.getOption("metadata_only")||g.decrypt(e[b].content,function(a){c.call(d,"pushResult",[a,b,"content"])})};a.getOption("metadata_only")?c.wait(d,"done",e.length-1):c.wait(d,"done",e.length*2-1);for(f=0;f<e.length;f+=1)h()},d.getListOnFail=function(a){c.call(d,"fail",[a])},d.pushResult=function(a,e,f){if(typeof a=="object")return c.call(d,"fail",[{status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."}]);b[e][f]=a,c.call(d,"done")},d.fail=function(a){c.end(),e.fail(a)},d.done=function(){c.end(),e.done(b)},c.call(d,"getDocumentList")},e.removeDocument=function(a){var b,c=g.newAsyncModule(),d={};d.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,c.call(d,"removeDocument")})},d.removeDocument=function(){var c=a.cloneOption();c.onResponse=d.removeOnResponse,c.onFail=function(){},c.onDone=function(){},e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("removeDocument",{path:b,option:c}))},d.removeOnResponse=function(a){a.status.isDone()?e.done():e.fail(a.error)},c.call(d,"encryptFilePath")},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.max_retry=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_owner1:{name:l.winner.owner,revision:l.winner.revision,hash:l.winner.hash},conflict_owner2:{name:g.username,revision:1,hash:o}},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){if(typeof g[i].content!="string")return e.call(c,"fail",[{status:0,statusText:"Invalid content",message:"Invalid file content, aborting job."}]);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(".");try{l.creation_date=k.owner[k.winner.owner].creation_date,l.last_modified=k.owner[k.winner.owner].last_modified,f.push(l)}catch(m){continue}}}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")||[];for(s=0;s<v.length;s+=1){v[s].hash===r&&(g.removeConflict(l.conflict_list,r),i(),d(),u=!0);for(t=0;t<l.conflict_list.length;t+=1)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
(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.success()})},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.success(c)):d.error({status:404,statusText:"Not Found.",message:'Document "'+b.getPath()+'" not found in localStorage.'})})},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.success(c)})},d.removeDocument=function(b){setTimeout(function(){var c="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();a.deleteItem(c),e.removeFileName(b.getPath()),d.success()})},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".'},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},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.success()},error:function(b){b.message='Cannot save "'+a.getPath()+'" into DAVStorage.',e.retry(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.success(d)},error:function(b){b.status===404?(b.message='Document "'+a.getPath()+'" not found in localStorage.',e.error(b)):(b.message='Cannot load "'+a.getPath()+'" from DAVStorage.',e.retry(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.success(d):f()},error:function(b){b.message='Cannot load "'+a.getPath()+'" informations from DAVStorage.',b.status===404?e.error(b):e.retry(b)}})},e.getDocumentList=function(a){var d=[],f={},h=[],i=g.newAsyncModule(),j={};j.getContent=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.name,type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(b){a.content=b,d.push(a),i.call(j,"success")},error:function(a){a.message="Cannot get a document content from DAVStorage.",i.call(j,"error",[a])}})},j.getDocumentList=function(){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(c){var e=b(c).find("D\\:response, response"),g=e.length;i.wait(j,"success",g-2),e.each(function(c,e){if(c>0){f={},b(e).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(e).find("lp1\\:getlastmodified, getlastmodified").each(function(){f.last_modified=b(this).text()}),b(e).find("lp1\\:creationdate, creationdate").each(function(){f.creation_date=b(this).text()}),a.getOption("metadata_only")?(d.push(f),i.call(j,"success")):i.call(j,"getContent",[f])}})},error:function(a){a.message="Cannot get a document list from DAVStorage.",a.status===404?i.call(j,"error",[a]):i.call(j,"retry",[a])}})},j.retry=function(a){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.retry(a)},j.error=function(a){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.error(a)},j.success=function(){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.success(d)},i.call(j,"getDocumentList")},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.success()},error:function(a){a.status===404?e.success():(a.message='Cannot remove "'+e.getFileName()+'" from DAVStorage.',e.retry(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),e||(f.push(a),d.isTheLast()&&c.error({status:207,statusText:"Multi-Status",message:b,array:f}))},i=function(a){d.return_value_array.push(a),e||(e=!0,c.success(a))};for(g=0;g<d.nb_storage;g+=1){var j=a.clone(),k=c.newStorage(d.storagelist[g]);j.onErrorDo(h),j.onSuccessDo(i),c.addJob(k,j)}},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:{success:a,max_retry:3}}))},d.saveDocument=function(a){var b=a.clone();b.onSuccessDo(function(b){e.isFileIndexed(a.getPath())||e.addFile({name:a.getPath(),last_modified:0,creation_date:0}),e.update(),d.success()}),b.onErrorDo(function(a){d.error(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d.loadDocument=function(a){var b,c,f,g,h=function(a){d.success(a)},i=function(a){d.error(a)},j=function(){var b=a.clone();b.onErrorDo(i),b.onSuccessDo(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.success(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.error({status:0,statusText:"Timeout",message:"The request has timed out."}),clearInterval(b)),e.fileArrayExists()&&(d.success(e.getFileArray()),clearInterval(b))},100),setTimeout(function(){f=!0},1e4)):(c=a.clone(),c.onSuccessDo(function(a){d.success(a)}),c.onErrorDo(function(a){d.error(a)}),d.addJob(d.newStorage(e.secondstorage_spec),c))},d.removeDocument=function(a){var b=a.clone();b.onSuccessDo(function(b){e.removeFile(a.getPath()),e.update(),d.success()}),b.onErrorDo(function(a){d.error(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?!0:!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){var c=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(c).ct)},g.decrypt=function(a,c){var e,f=b.extend(!0,{},g.decrypt_param_object);f.ct=a||"",f=JSON.stringify(f);try{e=d.decrypt(g.username+":"+g.password,f)}catch(h){c({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."});return}c(undefined,e)},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},e.saveDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"save")})},f.encryptFileContent=function(){g.encrypt(a.getContent(),function(a){c=a,d.call(f,"save")})},f.save=function(){var d=a.cloneOption(),f;d.success=function(){e.success()},d.error=function(a){e.error(a)},f=e.newCommand("saveDocument",{path:b,content:c,option:d}),e.addJob(e.newStorage(g.secondstorage_spec),f)},d.wait(f,"save",1),d.call(f,"encryptFilePath"),d.call(f,"encryptFileContent")},e.loadDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"loadDocument")})},f.loadDocument=function(){var c=a.cloneOption(),d;c.error=f.loadOnError,c.success=f.loadOnSuccess,d=e.newCommand("loadDocument",{path:b,option:c}),e.addJob(e.newStorage(g.secondstorage_spec),d)},f.loadOnSuccess=function(b){b.name=a.getPath(),a.getOption("metadata_only")?e.success(b):g.decrypt(b.content,function(a,c){a?e.error(a):(b.content=c,e.success(b))})},f.loadOnError=function(a){e.error(a)},d.call(f,"encryptFilePath")},e.getDocumentList=function(a){var b=[],c=g.newAsyncModule(),d={};d.getDocumentList=function(){var b=a.cloneOption();b.success=d.getListOnSuccess,b.error=d.getListOnError,e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("getDocumentList",{path:a.getPath(),option:b}))},d.getListOnSuccess=function(e){b=e;var f,h=function(e){g.decrypt(b[e].name,function(a,b){a?c.call(d,"error",[a]):c.call(d,"pushResult",[b,e,"name"])}),a.getOption("metadata_only")||g.decrypt(b[e].content,function(a,b){a?c.call(d,"error",[a]):c.call(d,"pushResult",[b,e,"content"])})};a.getOption("metadata_only")?c.wait(d,"success",e.length-1):c.wait(d,"success",e.length*2-1);for(f=0;f<b.length;f+=1)h(f)},d.getListOnError=function(a){c.call(d,"error",[a])},d.pushResult=function(a,e,f){b[e][f]=a,c.call(d,"success")},d.error=function(a){c.end(),e.error(a)},d.success=function(){c.end(),e.success(b)},c.call(d,"getDocumentList")},e.removeDocument=function(a){var b,c={};c.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,c.removeDocument()})},c.removeDocument=function(){var d=a.cloneOption();d.error=c.removeOnError,d.success=c.removeOnSuccess,e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("removeDocument",{path:b,option:d}))},c.removeOnSuccess=function(a){e.success()},c.removeOnError=function(a){e.error(a)},c.encryptFilePath()},e};f.addStorageType("crypt",k);var l=function(b,c){var d=f.storage(b,c,"handler"),g={};b=b||{},c=c||{};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.secondstorage_string+"/",j=function(){},k=d.serialized;return d.serialized=function(){var a=k();return a.storage=g.secondstorage_spec,a},d.validateState=function(){return h?"":'Need at least one parameter: "storage".'},g.getDistantMetadata=function(a,b,c,e){var f=a.cloneOption();f.metadata_only=!1,f.max_retry=a.getOption("max_retry")||3,f.error=e,f.success=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.error=f,h.success=e;var i=d.newCommand("saveDocument",{path:b,content:JSON.stringify(c),option:h});d.addJob(d.newStorage(g.secondstorage_spec),i)},g.saveNewRevision=function(a,b,c,e,f){var h=a.cloneOption();h.error=f,h.success=e;var i=d.newCommand("saveDocument",{path:b,content:c,option:h});d.addJob(d.newStorage(g.secondstorage_spec),i)},g.loadRevision=function(a,b,c,e){var f=a.cloneOption();f.error=e,f.success=c;var h=d.newCommand("loadDocument",{path:b,option:f});d.addJob(d.newStorage(g.secondstorage_spec),h)},g.deleteAFile=function(a,b,c,e){var f=a.cloneOption();f.max_retry=0,f.error=e,f.success=c;var h=d.newCommand("removeDocument",{path:b,option:f});d.addJob(d.newStorage(g.secondstorage_spec),h)},g.solveConflict=function(a,b,c){var d={},f=g.newAsyncModule(),h=c.command,i=a+".metadata",k="",l="",m=null,n=!1,o={},p=c.previous_revision,q=c.revision_remove_object||{},r=q[p]||{},s=new Date,t;d.getDistantMetadata=function(){console.log("c getDistantMetadata"),g.getDistantMetadata(h,i,function(c){var g=parseInt(p.split("-")[0],10);m=JSON.parse(c.content),k=g+1+"-"+e(""+b+p+JSON.stringify(m)),l=a+"."+k,f.wait(d,"saveMetadataOnDistant",1),f.call(d,"saveNewRevision"),f.call(d,"previousUpdateMetadata")},function(a){f.call(d,"error",[a])})},d.saveNewRevision=function(){console.log("c saveNewRevision "+k),g.saveNewRevision(h,l,b,function(a){f.call(d,"saveMetadataOnDistant")},function(a){f.call(d,"error",[a])})},d.previousUpdateMetadata=function(){console.log("c previousUpdateMetadata");for(var a in q)delete m[a];f.call(d,"checkForConflicts")},d.checkForConflicts=function(){console.log("c checkForConflicts");for(var a in m){var b;n=!0,o=g.createConflictObject(h,m,k),t={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}f.call(d,"updateMetadata")},d.updateMetadata=function(){console.log("c updateMetadata"),m[k]={creation_date:r.creation_date||s.getTime(),last_modified:s.getTime(),conflict:n,deleted:!1},f.call(d,"saveMetadataOnDistant")},d.saveMetadataOnDistant=function(){console.log("c saveMetadataOnDistant on_conflict "+n),g.saveMetadataToDistant(h,i,m,function(a){f.call(d,"deleteAllConflictingRevision"),n?f.call(d,"error"):f.call(d,"success")},function(a){f.call(d,"error",[a])})},d.deleteAllConflictingRevision=function(){console.log("c deleteAllConflictingRevision");for(var b in q)g.deleteAFile(h,a+"."+b,j,j)},d.success=function(){console.log("c success"),f.neverCall(d,"error"),f.neverCall(d,"success"),c.success&&c.success(k)},d.error=function(a){var b=a||t||{};console.log("c error "+JSON.stringify(b)),n&&(b.conflict_object=o),f.neverCall(d,"error"),f.neverCall(d,"success"),c.error&&c.error(b)},f.call(d,"getDistantMetadata")},g.createConflictObject=function(a,b,c){var d=a.clone(),e={path:a.getPath(),revision:c,revision_object:b,getConflictRevisionList:function(){return this.revision_object},solveConflict:function(a,b){return b=b||{},b.previous_revision=this.revision,b.revision_remove_object=this.revision_object,b.command=d,g.solveConflict(this.path,a,b)}};return e},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){a._wait=a._wait||{};if(a._wait[b])return a._wait[b]--,j;c=c||[],setTimeout(function(){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=j},a},d.saveDocument=function(a){var b={},c=g.newAsyncModule(),f=a.getPath()+".metadata",h="",i="",k=null,l=!1,m={},n=a.getOption("previous_revision"),o=a.getPath()+"."+n,p=new Date,q;if(!n)return console.log("here"),setTimeout(function(){d.error({status:0,statusText:"Parameter missing",message:"Need a previous revision."})});b.getDistantMetadata=function(){console.log("s getDistantMetadata"),g.getDistantMetadata(a,f,function(d){var f=parseInt(n.split("-")[0],10);k=JSON.parse(d.content),h=f+1+"-"+e(""+a.getContent()+n+JSON.stringify(k)),i=a.getPath()+"."+h,c.wait(b,"saveMetadataOnDistant",1),c.call(b,"saveNewRevision"),c.call(b,"checkForConflicts")},function(d){d.status===404?(h="1-"+e(a.getContent()),i=a.getPath()+"."+h,c.wait(b,"saveMetadataOnDistant",1),c.call(b,"saveNewRevision"),c.call(b,"createMetadata")):c.call(b,"error",[d])})},b.saveNewRevision=function(){console.log("s saveNewRevision "+h),g.saveNewRevision(a,i,a.getContent(),function(a){c.call(b,"saveMetadataOnDistant")},function(a){c.call(b,"error",[a])})},b.checkForConflicts=function(){for(var a in k)if(a!==n){l=!0,q={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}c.call(b,"updateMetadata")},b.createMetadata=function(){console.log("s createMetadata"),k={},k[h]={creation_date:p.getTime(),last_modified:p.getTime(),conflict:!1,deleted:!1},c.call(b,"saveMetadataOnDistant")},b.updateMetadata=function(){console.log("s updateMetadata");var d;k[n]&&(d=k[n].creation_date,delete k[n]),k[h]={creation_date:d||p.getTime(),last_modified:p.getTime(),conflict:l,deleted:!1},l&&(m=g.createConflictObject(a,k,h)),c.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){console.log("s saveMetadataOnDistant on_conflict "+l),g.saveMetadataToDistant(a,f,k,function(a){c.call(b,"deletePreviousRevision"),l?c.call(b,"error"):c.call(b,"success")},function(a){c.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&!l&&(console.log("s deletePreviousRevision "+n),g.deleteAFile(a,o,j,j))},b.success=function(){console.log("s success"),c.neverCall(b,"error"),c.neverCall(b,"success"),d.success(h)},b.error=function(a){var e=a||q||{status:0,statusText:"Unknown",message:"Unknown error."};console.log("s error "+JSON.stringify(e)),l&&(e.conflict_object=m),c.neverCall(b,"error"),c.neverCall(b,"success"),d.error(e)},c.call(b,"getDistantMetadata")},d.loadDocument=function(a){var b={},c=g.newAsyncModule(),e=a.getPath()+".metadata",f=a.getOption("revision")||"",h=null,i=a.getOption("metadata_only"),j=!1,k={},l=new Date,m={name:a.getPath()},n=function(a){c.call(b,"error",[{status:404,statusText:"Not Found",message:a}])};b.getDistantMetadata=function(){console.log("l getDistantMetadata"),g.getDistantMetadata(a,e,function(a){h=JSON.parse(a.content),i||c.wait(b,"success",1),c.call(b,"affectMetadata"),c.call(b,"checkForConflicts")},function(a){c.call(b,"error",[a])})},b.affectMetadata=function(){console.log("l affectMetadata");var a=0;if(f){if(!h[f])return n("Document revision does not exists.")}else for(var d in h)a<h[d].last_modified&&(a=h[d].last_modified,f=d);m.last_modified=h[f].last_modified,m.creation_date=h[f].creation_date,m.revision=f,m.revision_object=h,i?c.call(b,"success"):c.call(b,"loadRevision")},b.loadRevision=function(){console.log("l loadRevision "+f);if(!f||h[f].deleted)return n("Document has been removed.");g.loadRevision(a,m.name+"."+f,function(a){m.content=a.content,c.call(b,"success")},function(a){c.call(b,"error",[a])})},b.checkForConflicts=function(){console.log("l checkForConflicts"),h[f].conflict&&(j=!0,k=g.createConflictObject(a,h,f),m.conflict_object=k),c.call(b,"success")},b.success=function(){console.log("l success"),c.neverCall(b,"error"),c.neverCall(b,"success"),d.success(m)},b.error=function(a){var e=a||{status:0,statusText:"Unknown",message:"Unknown error."};console.log("l error "+JSON.stringify(e)),j&&(e.conflict_object=k),c.neverCall(b,"error"),c.neverCall(b,"success"),d.error(e)},c.call(b,"getDistantMetadata")},d.getDocumentList=function(b){var c={},e=g.newAsyncModule(),f=[],h=[],i=0;c.retreiveList=function(){var a=b.cloneOption();a.metadata_only=!0,a.error=function(a){e.call(c,"fail",[a])},a.success=function(a){};var f=d.newCommand("getDocumentList",{path:b.getPath(),option:a});d.addJob(d.newStorage(g.secondstorage_spec),f)},c.a=function(g){var i;for(i=0;i<g.length;i+=1){if(typeof g[i].content!="string")return e.call(c,"fail",[{status:0,statusText:"Invalid content",message:"Invalid file content, aborting job."}]);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(".");try{l.creation_date=k.owner[k.winner.owner].creation_date,l.last_modified=k.owner[k.winner.owner].last_modified,f.push(l)}catch(m){continue}}}if(b.getOption("metadata_only"))e.call(c,"done",[f]);else{if(g.length===0)return d.success([]);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()}}},d.removeDocument=function(a){var b={},c=g.newAsyncModule(),f=a.getPath()+".metadata",h="",i="",k=null,l=!1,m={},n=a.getOption("revision"),o=a.getPath()+"."+n,p=new Date,q;if(!n)return setTimeout(function(){d.error({status:0,statusText:"Parameter missing",message:"Need a previous revision."})});b.getDistantMetadata=function(){console.log("r getDistantMetadata"),g.getDistantMetadata(a,f,function(d){var f=parseInt(n.split("-")[0],10);k=JSON.parse(d.content),h=f+1+"-"+e(""+n+JSON.stringify(k)),i=a.getPath()+"."+h,c.call(b,"checkForConflicts")},function(a){a.status===404?c.call(b,"success",["0"]):c.call(b,"error",[a])})},b.checkForConflicts=function(){for(var a in k)if(a!==n){l=!0,q={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}c.call(b,"updateMetadata")},b.updateMetadata=function(){console.log("s updateMetadata");var d;k[n]&&(d=k[n].creation_date,delete k[n]),k[h]={creation_date:d||p.getTime(),last_modified:p.getTime(),conflict:l,deleted:!0},l&&(m=g.createConflictObject(a,k,h)),c.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){console.log("s saveMetadataOnDistant on_conflict "+l),g.saveMetadataToDistant(a,f,k,function(a){c.call(b,"deletePreviousRevision"),l?c.call(b,"error"):c.call(b,"success")},function(a){c.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&!l&&(console.log("s deletePreviousRevision "+n),g.deleteAFile(a,o,j,j))},b.success=function(){console.log("s success"),c.neverCall(b,"error"),c.neverCall(b,"success"),d.success(h)},b.error=function(a){var e=a||q||{status:0,statusText:"Unknown",message:"Unknown error."};console.log("s error "+JSON.stringify(e)),l&&(e.conflict_object=m),c.neverCall(b,"error"),c.neverCall(b,"success"),d.error(e)},c.call(b,"getDistantMetadata")},d};f.addStorageType("conflictmanager",l)})(LocalOrCookieStorage,jQuery,Base64,sjcl,hex_sha256,jio);
\ No newline at end of file
......@@ -3,64 +3,35 @@ var newConflictManagerStorage = function ( spec, my ) {
spec = spec || {};
my = my || {};
priv.username = spec.username || '';
var storage_exists = (spec.storage?true:false);
priv.secondstorage_spec = spec.storage || {type:'base'};
priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec);
var local_namespace = 'jio/conflictmanager/'+priv.username+'/'+
var local_namespace = 'jio/conflictmanager/'+
priv.secondstorage_string+'/';
var empty_fun = function (){};
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.username = priv.username;
o.storage = priv.secondstorage_spec;
return o;
};
that.validateState = function () {
if (priv.username && storage_exists) {
if (storage_exists) {
return '';
}
return 'Need at least two parameter: "username" and "storage".';
return 'Need at least one parameter: "storage".';
};
priv.removeValuesFromArrayWhere = function (array,fun) {
var i, newarray = [];
for (i = 0; i < array.length; i+= 1) {
if (!fun(array[i])) {
newarray.push(array[i]);
}
}
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) {
priv.getDistantMetadata = function (command,path,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false;
cloned_option.max_retry = 1; // FIXME : wrong ! (redesign jio & storage)
cloned_option.onResponse = function () {};
cloned_option.onFail = onFail;
cloned_option.onDone = onDone;
cloned_option.max_retry = command.getOption('max_retry') || 3;
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'loadDocument',{path:path,
option:cloned_option});
......@@ -68,11 +39,10 @@ var newConflictManagerStorage = function ( spec, my ) {
newcommand );
};
priv.saveMetadataToDistant = function (command,path,content,onDone,onFail) {
priv.saveMetadataToDistant = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = onFail;
cloned_option.onDone = onDone;
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:JSON.stringify (content),
......@@ -82,17 +52,204 @@ var newConflictManagerStorage = function ( spec, my ) {
newcommand );
};
priv.saveNewRevision = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:content,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.loadRevision = function (command,path,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand (
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.deleteAFile = function (command,path,success,error) {
var cloned_option = command.cloneOption();
cloned_option.max_retry = 0; // inf
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'removeDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
priv.solveConflict = function (path,content,option) {
var o = {}, am = priv.newAsyncModule(),
command = option.command,
metadata_file_path = path + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = option.previous_revision,
previous_revision_object = option.revision_remove_object || {},
previous_revision_content_object = previous_revision_object[
previous_revision] || {},
now = new Date(),
failerror;
o.getDistantMetadata = function (){
console.log ('c getDistantMetadata');
priv.getDistantMetadata (
command, metadata_file_path,
function (result) {
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + content +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = path + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'previousUpdateMetadata');
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.saveNewRevision = function (){
console.log ('c saveNewRevision ' + current_revision);
priv.saveNewRevision (
command, current_revision_file_path, content,
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.previousUpdateMetadata = function () {
console.log ('c previousUpdateMetadata');
for (var prev_rev in previous_revision_object) {
delete metadata_file_content[prev_rev];
}
am.call(o,'checkForConflicts');
};
o.checkForConflicts = function () {
console.log ('c checkForConflicts');
for (var rev in metadata_file_content) {
var revision_index;
on_conflict = true;
conflict_object =
priv.createConflictObject(
command, metadata_file_content, current_revision
);
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
console.log ('c updateMetadata');
metadata_file_content[current_revision] = {
creation_date: previous_revision_content_object.creation_date ||
now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: false
};
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
console.log ('c saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command, metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deleteAllConflictingRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.deleteAllConflictingRevision = function (){
console.log ('c deleteAllConflictingRevision');
for (var prev_rev in previous_revision_object) {
priv.deleteAFile (
command, path+'.'+prev_rev, empty_fun, empty_fun );
}
};
o.success = function (){
console.log ('c success');
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.success) {option.success(current_revision);}
};
o.error = function (error){
var gooderror = error || failerror || {};
console.log ('c error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.error) {option.error(gooderror);}
};
am.call(o,'getDistantMetadata');
};
priv.createConflictObject = function (command, metadata, revision) {
var cloned_command = command.clone();
var conflict_object = {
path: command.getPath(),
revision: revision,
revision_object: metadata,
getConflictRevisionList: function () {
return this.revision_object;
},
solveConflict: function (content,option) {
option = option || {};
option.previous_revision = this.revision;
option.revision_remove_object = this.revision_object;
option.command = cloned_command;
return priv.solveConflict (
this.path, content, option
);
}
};
return conflict_object;
};
priv.newAsyncModule = function () {
var async = {};
async.call = function (obj,function_name,arglist) {
obj._wait = obj._wait || {};
if (obj._wait[function_name]) {
obj._wait[function_name]--;
return function () {};
return empty_fun;
}
// ok if undef or 0
arglist = arglist || [];
return obj[function_name].apply(obj[function_name],arglist);
setTimeout(function(){
obj[function_name].apply(obj[function_name],arglist);
});
};
async.neverCall = function (obj,function_name) {
obj._wait = obj._wait || {};
......@@ -103,7 +260,7 @@ var newConflictManagerStorage = function ( spec, my ) {
obj._wait[function_name] = times;
};
async.end = function () {
async.call = function(){};
async.call = empty_fun;
};
return async;
};
......@@ -114,253 +271,162 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.saveDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
local_file_metadata = {}, // local file.metadata
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
is_a_new_file = false,
local_file_hash = hex_sha256 (command.getContent()),
now = new Date();
o.updateLocalMetadata = function () {
var new_owner_object = {revision:0,hash:'',
last_modified:0,
creation_date:now.getTime()};
local_file_metadata =
LocalOrCookieStorage.getItem (local_metadata_file_name);
if ( local_file_metadata ) {
// if metadata already exists
if ( !local_file_metadata.owner[priv.username] ) {
local_file_metadata.owner[priv.username] =
new_owner_object;
}
} else {
local_file_metadata = {
winner: {},
owner: {},
conflict_list: []
};
local_file_metadata.winner = {
revision:0,owner:priv.username,hash:''};
local_file_metadata.owner[priv.username] =
new_owner_object;
}
am.call(o,'checkForConflicts');
};
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('previous_revision'),
previous_revision_file_path = command.getPath() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
console.log ('here');
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){
console.log ('s getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + command.getContent() +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
command_file_metadata = local_file_metadata;
is_a_new_file = true;
am.call(o,'checkForConflicts');
current_revision = '1-' +
hex_sha256 (command.getContent());
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'createMetadata');
} else {
am.call(o,'fail',[error]);
am.call(o,'error',[error]);
}
});
}
);
};
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;
if (is_a_new_file || !command_file_metadata.owner[
command_file_metadata.winner.owner]) {
original_creation_date = now.getTime();
} else {
original_creation_date = command_file_metadata.owner[
command_file_metadata.winner.owner].
creation_date || now.getTime();
o.saveNewRevision = function (){
console.log ('s saveNewRevision ' + current_revision);
priv.saveNewRevision (
command,current_revision_file_path,command.getContent(),
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
if (command_file_metadata.owner[priv.username]) {
previous_revision = command_file_metadata.owner[
priv.username].revision;
} else {
command_file_metadata.owner[priv.username] = {};
);
};
o.checkForConflicts = function () {
for (var rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
command_file_metadata.owner[priv.username].
last_modified = now.getTime();
command_file_metadata.owner[priv.username].
creation_date = original_creation_date;
command_file_metadata.owner[priv.username].hash =
local_file_hash;
};
var updateCommandMetadataNotOnConflict = function () {
updateMetadataCommon ();
command_file_metadata.winner.owner = priv.username;
command_file_metadata.winner.revision ++;
command_file_metadata.winner.hash = local_file_hash;
command_file_metadata.owner[priv.username].revision =
command_file_metadata.winner.revision;
};
var updateCommandMetadataOnConflict = function () {
updateMetadataCommon ();
command_file_metadata.owner[priv.username].revision ++;
}
am.call(o,'updateMetadata');
};
o.createMetadata = function (){
console.log ('s createMetadata');
metadata_file_content = {};
metadata_file_content[current_revision] = {
creation_date: now.getTime(),
last_modified: now.getTime(),
conflict: false,
deleted: false
};
// if this is a new file
if (is_a_new_file) {
updateCommandMetadataNotOnConflict();
saveAndDone();
return;
am.call(o,'saveMetadataOnDistant');
};
o.updateMetadata = function (){
console.log ('s updateMetadata');
var previous_creation_date;
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
delete metadata_file_content[previous_revision];
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_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))) {
updateCommandMetadataNotOnConflict();
saveAndDone();
} else {
// if conflict
var conflict_object = {
label: 'revision',
path: command.getPath(),
method: 'saveDocument',
owner: priv.username,
conflict_owner: {
name: command_file_metadata.winner.owner,
revision: command_file_metadata.winner.revision,
hash: command_file_metadata.winner.hash}
},
// gen hash
conflict_hash = hex_sha256 (JSON.stringify (
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
for (i = 0; i < known_conflict_list.length; i+= 1) {
// if known conflict
if (known_conflict_list[i].hash ===
conflict_hash) {
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
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);
}
}
}
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);
}
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: false
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadata = function () {
priv.saveMetadataToDistant (
command,metadata_file_name,command_file_metadata,
function () {
am.call(o,'done');
o.saveMetadataOnDistant = function (){
console.log ('s saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'fail',[error]);
});
};
o.saveRevision = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function () {
am.call(o,'deletePreviousRevision');
};
var newcommand = that.newCommand(
'saveDocument',
{path:command.getPath() + '.' +
command_file_metadata.owner[priv.username].revision +
'.' + priv.username,
content:command.getContent(),
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
am.call(o,'error',[error]);
}
);
};
o.deletePreviousRevision = function () {
if ( previous_revision !== 0 && (
!command_file_metadata.owner[priv.username] ||
previous_revision !==
command_file_metadata.owner[
priv.username].revision ) ) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function () {
am.call(o,'done');
};
var newcommand = that.newCommand(
'removeDocument',
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
am.call(o,'done');
o.deletePreviousRevision = function (){
if (previous_revision !== '0' && !on_conflict) {
console.log ('s deletePreviousRevision ' + previous_revision);
priv.deleteAFile (
command, previous_revision_file_path,
empty_fun,empty_fun);
}
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('s success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(current_revision);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done();
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('s error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.wait(o,'checkForConflicts',1);
am.call(o,'loadMetadataFromDistant');
am.call(o,'updateLocalMetadata');
am.call(o,'getDistantMetadata');
};
/**
......@@ -370,96 +436,114 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.loadDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
command_file_metadata = {}, // distant file.metadata
owner = '', loaded_file;
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = command.getOption('revision') || '',
metadata_file_content = null,
metadata_only = command.getOption('metadata_only'),
on_conflict = false, conflict_object = {},
now = new Date(),
doc = {name:command.getPath()},
call404 = function (message) {
am.call(o,'error',[{
status:404,statusText:'Not Found',
message:message
}]);
};
o.getDistantMetadata = function (){
console.log ('l getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
owner = command.getOption('owner');
am.wait(o,'done',1);
// if owner
if (owner) {
am.call(o,'loadOwner');
} else {
// if no owner
am.call(o,'loadWinner');
metadata_file_content = JSON.parse (result.content);
if (!metadata_only) {
am.wait(o,'success',1);
}
am.call(o,'updateLocalMetadata');
am.call(o,'affectMetadata');
am.call(o,'checkForConflicts');
},function (error) {
am.end();
am.call(o,'fail',[error]);
});
am.call(o,'error',[error]);
}
);
};
o.updateLocalMetadata = function () {
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
am.call(o,'done');
o.affectMetadata = function () {
console.log ('l affectMetadata');
var tmp_last_modified = 0;
if (current_revision) {
if (!metadata_file_content[current_revision]) {
return call404('Document revision does not exists.');
}
} else {
for (var rev in metadata_file_content) {
if (tmp_last_modified <
metadata_file_content[rev].last_modified) {
tmp_last_modified =
metadata_file_content[rev].last_modified;
current_revision = rev;
}
}
}
doc.last_modified =
metadata_file_content[current_revision].last_modified;
doc.creation_date =
metadata_file_content[current_revision].creation_date;
doc.revision = current_revision;
doc.revision_object = metadata_file_content;
if (metadata_only) {
am.call(o,'success');
} else {
am.call(o,'loadRevision');
}
};
o.loadWinner = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function (result) {
loaded_file = result;
loaded_file.name = command.getPath();
am.call(o,'done');
};
var newcommand = that.newCommand(
'loadDocument',
{path:command.getPath() + '.' +
command_file_metadata.winner.revision +
'.' + command_file_metadata.winner.owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
o.loadRevision = function (){
console.log ('l loadRevision ' + current_revision);
if (!current_revision ||
metadata_file_content[current_revision].deleted) {
return call404('Document has been removed.');
}
priv.loadRevision (
command, doc.name+'.'+current_revision,
function (result) {
doc.content = result.content;
am.call(o,'success');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.loadOwner = function () {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.end();
am.call(o,'fail',[error]);
};
cloned_option.onDone = function (result) {
loaded_file = result;
loaded_file.name = command.getPath();
am.call(o,'done');
};
if (!command_file_metadata.owner[owner]) {
cloned_option.onFail ({status:404,
statusText:'Not Found',
message:'Document not found.'});
return;
o.checkForConflicts = function () {
console.log ('l checkForConflicts');
if (metadata_file_content[current_revision].conflict) {
on_conflict = true;
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
doc.conflict_object = conflict_object;
}
var newcommand = that.newCommand(
'loadDocument',
{path:command.getPath() + '.' +
command_file_metadata.owner[owner].revision +
'.' + owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
am.call(o,'success');
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('l success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(doc);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done(loaded_file);
o.error = function (error){
var gooderror = error || {status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('l error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.call(o,'loadMetadataFromDistant');
am.call(o,'getDistantMetadata');
};
/**
......@@ -469,103 +553,100 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.getDocumentList = function (command) {
var o = {}, am = priv.newAsyncModule(),
command_file_metadata_list = [], // distant files metadata
metadata_file_list = [], // distant files metadata
result_list = [],
nb_loaded_file = 0;
o.retreiveList = function () {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false;
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
cloned_option.metadata_only = true;
cloned_option.error = function (error) {
am.call(o,'fail',[error]);
};
cloned_option.onDone = function (result) {
var i;
for (i = 0; i < result.length; i+= 1) {
if (typeof result[i].content !== 'string') {
return am.call(o,'fail',[{
status:0, statusText:'Invalid content',
message:'Invalid file content, aborting job.'}]);
}
var splitname = result[i].name.split('.') || [];
var content_object;
var doc = {};
if (splitname[splitname.length-1] === 'metadata') {
try {
content_object = JSON.parse (result[i].content);
} catch (e) {
continue;
}
result_list.push(content_object);
splitname.length --;
doc.name = splitname.join('.');
try {
doc.creation_date = content_object.owner[
content_object.winner.owner].creation_date;
doc.last_modified = content_object.owner[
content_object.winner.owner].last_modified;
command_file_metadata_list.push(doc);
} catch (e) {
continue;
}
}
}
if (command.getOption('metadata_only')) {
am.call(o,'done',[command_file_metadata_list]);
} else {
if (result.length === 0) {
return that.done([]);
}
am.wait(o,'done',command_file_metadata_list.length-1);
for (i = 0; i < command_file_metadata_list.length; i+= 1) {
LocalOrCookieStorage.setItem (
command_file_metadata_list[i].name + '.metadata',
result_list[i]);
am.call(o,'loadFile',[
command_file_metadata_list[i],
result_list[i].winner.revision,
result_list[i].winner.owner]);
}
that.end();
}
cloned_option.success = function (result) {
am.call(o,'filterTheList',[result]);
};
var newcommand = that.newCommand(
'getDocumentList',
{path:command.getPath(),
option:cloned_option});
'getDocumentList',{
path:command.getPath(),option:cloned_option
});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
o.loadFile = function (doc,revision,owner) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function (result) {
doc.content = result.content;
o.filterTheList = function (result) {
var i;
for (i = 0; i < result.length; i+= 1) {
// TODO : finish to check this function
var splitname = result[i].name.split('.') || [];
var content_object;
var doc = {};
if (splitname[splitname.length-1] === 'metadata') {
try {
content_object = JSON.parse (result[i].content);
} catch (e) {
continue;
}
result_list.push(content_object);
splitname.length --;
doc.name = splitname.join('.');
try {
doc.creation_date = content_object.owner[
content_object.winner.owner].creation_date;
doc.last_modified = content_object.owner[
content_object.winner.owner].last_modified;
command_file_metadata_list.push(doc);
} catch (e) {
continue;
}
}
}
if (command.getOption('metadata_only')) {
am.call(o,'done',[command_file_metadata_list]);
};
var newcommand = that.newCommand(
'loadDocument',
{path:doc.name + '.' + revision + '.' + owner,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
};
o.done = function (value) {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done(value);
} else {
if (result.length === 0) {
return that.success([]);
}
am.wait(o,'done',command_file_metadata_list.length-1);
for (i = 0; i < command_file_metadata_list.length; i+= 1) {
LocalOrCookieStorage.setItem (
command_file_metadata_list[i].name + '.metadata',
result_list[i]);
am.call(o,'loadFile',[
command_file_metadata_list[i],
result_list[i].winner.revision,
result_list[i].winner.owner]);
}
that.end();
}
};
am.call(o,'retreiveList');
// o.loadFile = function (doc,revision,owner) {
// var cloned_option = command.cloneOption ();
// cloned_option.error = function (error) {
// am.call(o,'fail',[error]);
// am.end();
// };
// cloned_option.success = function (result) {
// doc.content = result.content;
// am.call(o,'done',[command_file_metadata_list]);
// };
// var newcommand = that.newCommand(
// 'loadDocument',
// {path:doc.name + '.' + revision + '.' + owner,
// option:cloned_option});
// that.addJob ( that.newStorage (priv.secondstorage_spec),
// newcommand );
// };
// o.fail = function (error) {
// am.neverCall(o,'fail');
// am.neverCall(o,'done');
// command.setMaxRetry(1);
// that.error(error);
// };
// o.done = function (value) {
// am.neverCall(o,'done');
// am.neverCall(o,'fail');
// that.success(value);
// };
// am.call(o,'retreiveList');
};
/**
......@@ -574,221 +655,130 @@ var newConflictManagerStorage = function ( spec, my ) {
*/
that.removeDocument = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_name = command.getPath() + '.metadata',
local_metadata_file_name = local_namespace + metadata_file_name,
local_file_metadata = {},
command_file_metadata = {}, // distant file.metadata
previous_revision = 0,
metadata_object_known = true,
is_a_new_file = false;
o.updateLocalMetadata = function () {
var new_owner_object = {revision:0,hash:'',
last_modified:0,
creation_date:0};
local_file_metadata =
LocalOrCookieStorage.getItem (local_metadata_file_name);
if ( local_file_metadata ) {
// if metadata already exists
if ( !local_file_metadata.owner[priv.username] ) {
local_file_metadata.owner[priv.username] =
new_owner_object;
}
} else {
metadata_object_known = false;
local_file_metadata = {
winner: {},
owner: {},
conflict_list: []
};
local_file_metadata.winner = {
revision:0,owner:priv.username,hash:''};
local_file_metadata.owner[priv.username] =
new_owner_object;
}
am.call(o,'checkForConflicts');
};
o.loadMetadataFromDistant = function () {
priv.loadMetadataFromDistant (
command,metadata_file_name,
metadata_file_path = command.getPath() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('revision'),
previous_revision_file_path = command.getPath() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){
console.log ('r getDistantMetadata');
priv.getDistantMetadata (
command,metadata_file_path,
function (result) {
command_file_metadata = JSON.parse (result.content);
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision;
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
command_file_metadata = local_file_metadata;
is_a_new_file = true;
am.call(o,'checkForConflicts');
return;
am.call(o,'success',['0']);
} else {
am.call(o,'error',[error]);
}
am.call(o,'fail',[error]);
am.end();
});
}
);
};
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[
priv.username].revision;
delete command_file_metadata.owner[priv.username];
for (var rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
};
break;
}
};
var updateCommandMetadataNotOnConflict = function () {
updateMetadataCommon();
command_file_metadata.winner.owner = priv.username;
command_file_metadata.winner.revision = 0;
command_file_metadata.winner.hash = '';
};
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);
return am.call(o,'done');
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
console.log ('s updateMetadata');
var previous_creation_date;
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
delete metadata_file_content[previous_revision];
}
// if no conflict
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_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();
removeAndDone();
} else {
// if conflict
var conflict_object = {
label: 'revision',
path: command.getPath(),
method: 'removeDocument',
owner: priv.username,
conflict_owner: {
name: command_file_metadata.winner.owner,
revision: command_file_metadata.winner.revision,
hash: command_file_metadata.winner.hash}
},
// gen hash
conflict_hash = hex_sha256 (JSON.stringify (
conflict_object));
conflict_object.hash = conflict_hash;
// browse known conflict list
var i,j, done = false, known_conflict_list =
command.getOption('known_conflict_list') || [];
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) {
priv.removeConflict(
command_file_metadata.conflict_list,
conflict_hash);
updateCommandMetadataNotOnConflict();
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);
}
}
}
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);
}
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: true
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadata = function () {
priv.saveMetadataToDistant (
command,metadata_file_name,command_file_metadata,
function () {
am.call(o,'done');
o.saveMetadataOnDistant = function (){
console.log ('s saveMetadataOnDistant on_conflict ' + on_conflict);
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
am.call(o,'error');
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'fail',[error]);
am.end();
});
am.call(o,'error',[error]);
}
);
};
o.removeRevision = function () {
if ( previous_revision !== 0 && (
!command_file_metadata.owner[priv.username] ||
previous_revision !==
command_file_metadata.owner[
priv.username].revision ) ) {
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
am.call(o,'fail',[error]);
am.end();
};
cloned_option.onDone = function () {
am.call(o,'done');
};
var newcommand = that.newCommand(
'removeDocument',
{path:command.getPath() + '.' +
previous_revision + '.' + priv.username,
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
} else {
am.call(o,'done');
o.deletePreviousRevision = function (){
if (previous_revision !== '0' && !on_conflict) {
console.log ('s deletePreviousRevision ' + previous_revision);
priv.deleteAFile (
command, previous_revision_file_path,
empty_fun,empty_fun);
}
};
o.fail = function (error) {
am.neverCall(o,'fail');
am.neverCall(o,'done');
command.setMaxRetry(1);
that.fail(error);
o.success = function (){
console.log ('s success');
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success(current_revision);
};
o.done = function () {
am.neverCall(o,'done');
am.neverCall(o,'fail');
that.done();
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
console.log ('s error ' + JSON.stringify (gooderror));
if (on_conflict) {
gooderror.conflict_object = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
};
am.wait(o,'checkForConflicts',1);
am.call(o,'loadMetadataFromDistant');
am.call(o,'updateLocalMetadata');
am.call(o,'getDistantMetadata');
};
return that;
......
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