Commit 45ed5ca3 authored by Tristan Cavelier's avatar Tristan Cavelier

Adding conflictmanagerstorage.

Only saveDocument is implemented yet, but it is not complete.
parent 184405dc
...@@ -20,6 +20,7 @@ module.exports = function(grunt) { ...@@ -20,6 +20,7 @@ module.exports = function(grunt) {
'<file_strip_banner:../../src/<%= pkg.name %>/replicatestorage.js>', '<file_strip_banner:../../src/<%= pkg.name %>/replicatestorage.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/indexstorage.js>', '<file_strip_banner:../../src/<%= pkg.name %>/indexstorage.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/cryptstorage.js>', '<file_strip_banner:../../src/<%= pkg.name %>/cryptstorage.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/conflictmanagerstorage.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/outro.js>'], '<file_strip_banner:../../src/<%= pkg.name %>/outro.js>'],
dest: '../../lib/jio/<%= pkg.name %>.js' dest: '../../lib/jio/<%= pkg.name %>.js'
} }
...@@ -59,6 +60,7 @@ module.exports = function(grunt) { ...@@ -59,6 +60,7 @@ module.exports = function(grunt) {
sjcl: true, sjcl: true,
LocalOrCookieStorage: true, LocalOrCookieStorage: true,
Base64: true, Base64: true,
MD5: true,
jio: true, jio: true,
console: true, console: true,
unescape: true, unescape: true,
......
This diff is collapsed.
This diff is collapsed.
var newConflictManagerStorage = function ( spec, my ) {
var that = Jio.storage( spec, my, 'handler' ), priv = {};
var local_namespace = 'jio/conflictmanager/';
priv.username = spec.username || '';
var storage_exists = (spec.storage?true:false);
priv.secondstorage_spec = spec.storage || {type:'base'};
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.storage = priv.secondstorage_spec;
return o;
};
that.validateState = function () {
if (!priv.username || storage_exists) {
return 'Need at least two parameter: "owner" and "storage" '+
'.';
}
return '';
};
priv.isTheLatestVersion = function (local,distant) {
var k;
if (!distant.owner) {
return true;
}
for (k in distant.owner) {
if (k !== priv.username) {
if (local.winner.version <= distant.owner[k].last_version) {
return false;
}
}
}
return true;
};
priv.conflictResearch = function () {
// TODO : ;
};
/**
* Save a document and can manage conflicts.
* @method saveDocument
*/
that.saveDocument = function (command) {
var metadata_file_name = command.getPath() + '.metadata',
now = new Date(),
local_metadata_file_name = local_namespace + metadata_file_name,
local_file_metadata = {}, // local file.metadata
command_file_metadata = {}, // distant file.metadata
run_index = 0,
end = false, is_a_new_file = false,
previous_revision = 0,
local_file_hash = MD5 (command.getContent()),
run = function (index) {
switch (index) {
case 0:
run_index = 3;
run (2);
run (1);
break;
case 1: // update local metadata
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;
}
run_index ++; run (run_index);
break;
case 2: // load metadata from distant
var cloned_option = command.cloneOption ();
cloned_option.onResponse = function () {};
cloned_option.onFail = function (error) {
if (error.status === 404) {
command_file_metadata = local_file_metadata;
run_index ++; run (run_index);
} else {
run_index = (-10);
that.fail(error);
end = true;
}
};
cloned_option.onDone = function (result) {
command_file_metadata = JSON.parse (result.content);
run_index ++; run (run_index);
};
var newcommand = that.newCommand(
'loadDocument',{path:metadata_file_name,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
break;
// wait for 1 and 2
case 5: // check conflicts
var updateCommandMetadata = function () {
var original_creation_date;
original_creation_date = command_file_metadata.owner[
command_file_metadata.winner.owner].
creation_date || now.getTime();
if (command_file_metadata.owner[priv.username]) {
previous_revision = command_file_metadata.owner[
priv.username].revision;
} else {
command_file_metadata.owner[priv.username] = {};
}
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;
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;
};
// if this is a new file
if (is_a_new_file) {
updateCommandMetadata();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
run_index = (98);
run (6); // save metadata
run (7); // save document revision
break;
}
if (local_file_metadata.winner.revision ===
command_file_metadata.winner.revision &&
local_file_metadata.winner.hash ===
command_file_metadata.winner.hash) {
// OK! Now, update distant metadata, store them and save
updateCommandMetadata();
LocalOrCookieStorage.setItem (local_metadata_file_name,
command_file_metadata);
run_index = 98;
run (6); // save metadata
run (7); // save document revision
} else {
// var conflict_hash = '';
// // gen hash
// conflict_hash = MD5 (JSON.stringify ({
// path: command.getPath()
// // TODO : ;
// }));
// // TODO : ;
// command_file_metadata.conflict_list.push ({
// label:'revision',
// hash: conflict_hash,
// path: command.getPath(),
// local_owner: {
// name: priv.username,
// revision: local_file_metadata.owner[
// priv.username].revision + 1,
// hash: local_file_hash
// },
// conflict_owner: {
// name: command_file_metadata.winner.owner,
// revision: command_file_metadata.winner.revision,
// hash: command_file_metadata.winner.hash
// }
// });
command.getOption('onConflict')();
run_index = (-10);
end = true;
that.fail(); // TODO
}
break;
case 6: // save metadata
console.log ('save metadata');
break;
case 7: // save document revision
console.log ('save document revision');
break;
case 100:
if (!end) {
end = true;
that.done();
return;
}
break;
default:
break;
}
};
run (0);
command.setMaxRetry (1);
};
/**
* Load a document from several storages, and send the first retreived
* document.
* @method loadDocument
*/
that.loadDocument = function (command) {
that.fail({message:'NIY'});
};
/**
* Get a document list from several storages, and returns the first
* retreived document list.
* @method getDocumentList
*/
that.getDocumentList = function (command) {
that.fail({message:'NIY'});
};
/**
* Remove a document from several storages.
* @method removeDocument
*/
that.removeDocument = function (command) {
that.fail({message:'NIY'});
};
return that;
};
Jio.addStorageType('replicate', newReplicateStorage);
var newCryptedStorage = function ( spec, my ) {
var that = Jio.storage( spec, my, 'handler' ), priv = {};
priv.username = spec.username || '';
priv.password = spec.password || '';
priv.secondstorage_spec = spec.storage || {type:'base'};
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.username = priv.username;
o.password = priv.password;
return o;
};
that.validateState = function () {
if (priv.username &&
JSON.stringify (priv.secondstorage_spec) ===
JSON.stringify ({type:'base'})) {
return '';
}
return 'Need at least two parameters: "username" and "storage".';
};
// TODO : IT IS NOT SECURE AT ALL!
// WE MUST REWORK CRYPTED STORAGE!
priv.encrypt_param_object = {
"iv":"kaprWwY/Ucr7pumXoTHbpA",
"v":1,
"iter":1000,
"ks":256,
"ts":128,
"mode":"ccm",
"adata":"",
"cipher":"aes",
"salt":"K4bmZG9d704"
};
priv.decrypt_param_object = {
"iv":"kaprWwY/Ucr7pumXoTHbpA",
"ks":256,
"ts":128,
"salt":"K4bmZG9d704"
};
priv.encrypt = function (data,callback,index) {
// end with a callback in order to improve encrypt to an
// asynchronous encryption.
var tmp = sjcl.encrypt (that.getStorageUserName()+':'+
that.getStoragePassword(), data,
priv.encrypt_param_object);
callback(JSON.parse(tmp).ct,index);
};
priv.decrypt = function (data,callback,index,key) {
var tmp, param = $.extend(true,{},priv.decrypt_param_object);
param.ct = data || '';
param = JSON.stringify (param);
try {
tmp = sjcl.decrypt (that.getStorageUserName()+':'+
that.getStoragePassword(),
param);
} catch (e) {
callback({status:0,statusText:'Decrypt Fail',
message:'Unable to decrypt.'},index,key);
return;
}
callback(tmp,index,key);
};
/**
* Saves a document.
* @method saveDocument
*/
that.saveDocument = function (command) {
var new_file_name, newfilecontent,
_1 = function () {
priv.encrypt(command.getPath(),function(res) {
new_file_name = res;
_2();
});
},
_2 = function () {
priv.encrypt(command.getContent(),function(res) {
newfilecontent = res;
_3();
});
},
_3 = function () {
var settings = that.cloneOption(), newcommand, newstorage;
settings.onResponse = function (){};
settings.onDone = function () { that.done(); };
settings.onFail = function (r) { that.fail(r); };
newcommand = that.newCommand(
{path:new_file_name,
content:newfilecontent,
option:settings});
newstorage = that.newStorage( priv.secondstorage_spec );
that.addJob ( newstorage, newcommand );
};
_1();
}; // end saveDocument
/**
* Loads a document.
* @method loadDocument
*/
that.loadDocument = function (command) {
var new_file_name, option,
_1 = function () {
priv.encrypt(command.getPath(),function(res) {
new_file_name = res;
_2();
});
},
_2 = function () {
var settings = command.cloneOption(), newcommand, newstorage;
settings.onResponse = function(){};
settings.onFail = loadOnFail;
settings.onDone = loadOnDone;
newcommand = that.newCommand (
{path:new_file_name,
option:settings});
newstorage = that.newStorage ( priv.secondstorage_spec );
that.addJob ( newstorage, newcommand );
},
loadOnDone = function (result) {
result.name = command.getPath();
if (command.getOption('metadata_only')) {
that.done(result);
} else {
priv.decrypt (result.content,function(res){
if (typeof res === 'object') {
that.fail({status:0,statusText:'Decrypt Fail',
message:'Unable to decrypt'});
} 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);
}
});
}
},
loadOnFail = function (result) {
// 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(result);
};
_1();
}; // end loadDocument
/**
* Gets a document list.
* @method getDocumentList
*/
that.getDocumentList = function (command) {
var new_job, i, l, cpt = 0, array, ok = true,
_1 = function () {
var newcommand = command.clone(),
newstorage = that.newStorage ( priv.secondstorage_spec );
newcommand.onResponseDo (getListOnResponse);
newcommand.onDoneDo (function(){});
newcommand.onFailDo (function(){});
that.addJob ( new_job );
},
getListOnResponse = function (result) {
if (result.status.isDone()) {
array = result.return_value;
for (i = 0, l = array.length; i < l; i+= 1) {
// cpt--;
priv.decrypt (array[i].name,
lastOnResponse,i,'name');
// priv.decrypt (array[i].content,
// lastOnResponse,i,'content');
}
} else {
that.fail(result.error);
}
},
lastOnResponse = function (res,index,key) {
var tmp;
cpt++;
if (typeof res === 'object') {
if (ok) {
that.fail({status:0,statusText:'Decrypt Fail',
message:'Unable to decrypt.'});
}
ok = false;
return;
}
array[index][key] = res;
if (cpt === l && ok) {
// this is the last callback
that.done(array);
}
};
_1();
}; // end getDocumentList
/**
* Removes a document.
* @method removeDocument
*/
that.removeDocument = function () {
var new_job, new_file_name,
_1 = function () {
priv.encrypt(that.getFileName(),function(res) {
new_file_name = res;
_2();
});
},
_2 = function () {
new_job = that.cloneJob();
new_job.name = new_file_name;
new_job.storage = that.getSecondStorage();
new_job.onResponse = removeOnResponse;
that.addJob(new_job);
},
removeOnResponse = function (result) {
if (result.status === 'done') {
that.done();
} else {
that.fail(result.error);
}
};
_1();
};
return that;
};
Jio.addStorageType('crypt', newCryptedStorage);
var newIndexStorage = function ( spec, my ) { var newIndexStorage = function ( spec, my ) {
var that = Jio.storage( spec, my, 'handler' ), priv = {}; var that = Jio.storage( spec, my, 'handler' ), priv = {};
var validatestate_secondstorage = spec.storage || false;
priv.secondstorage_spec = spec.storage || {type:'base'}; priv.secondstorage_spec = spec.storage || {type:'base'};
priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec); priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec);
...@@ -16,7 +17,7 @@ var newIndexStorage = function ( spec, my ) { ...@@ -16,7 +17,7 @@ var newIndexStorage = function ( spec, my ) {
}; };
that.validateState = function () { that.validateState = function () {
if (priv.secondstorage_string === JSON.stringify ({type:'base'})) { if (!validatestate_secondstorage) {
return 'Need at least one parameter: "storage" '+ return 'Need at least one parameter: "storage" '+
'containing storage specifications.'; 'containing storage specifications.';
} }
......
/** /**
* Adds 5 storages to JIO. * Adds 6 storages to JIO.
* - LocalStorage ('local') * - LocalStorage ('local')
* - DAVStorage ('dav') * - DAVStorage ('dav')
* - ReplicateStorage ('replicate') * - ReplicateStorage ('replicate')
* - IndexedStorage ('indexed') * - IndexedStorage ('indexed')
* - CryptedStorage ('crypted') * - CryptedStorage ('crypted')
* - ConflictManagerStorage ('conflictmanager')
* *
* @module JIOStorages * @module JIOStorages
*/ */
(function(LocalOrCookieStorage, $, Base64, sjcl, Jio) { (function(LocalOrCookieStorage, $, Base64, sjcl, MD5, Jio) {
}( LocalOrCookieStorage, jQuery, Base64, sjcl, jio )); }( LocalOrCookieStorage, jQuery, Base64, sjcl, MD5, jio ));
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