Commit 090573c4 authored by Sven Franck's avatar Sven Franck

jslint pass conflictmanagerstorage.js

parent 531ca1e8
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, hex_sha256: true, setTimeout: true */
jIO.addStorageType('conflictmanager', function (spec, my) { jIO.addStorageType('conflictmanager', function (spec, my) {
spec = spec || {}; var that, priv, storage_exists, local_namespace, empty_fun,
var that = my.basicStorage( spec, my ), priv = {}; super_serialized;
var storage_exists = (spec.storage?true:false); spec = spec || {};
priv.sub_storage_spec = spec.storage || {type:'base'}; that = my.basicStorage(spec, my);
priv.sub_storage_string = JSON.stringify (priv.sub_storage_spec); priv = {};
storage_exists = (spec.storage ? true : false);
priv.sub_storage_spec = spec.storage || {
type: 'base'
};
priv.sub_storage_string = JSON.stringify(priv.sub_storage_spec);
var local_namespace = 'jio/conflictmanager/'+ local_namespace = 'jio/conflictmanager/' + priv.sub_storage_string + '/';
priv.sub_storage_string+'/';
var empty_fun = function (){}; empty_fun = function () {};
var super_serialized = that.serialized; super_serialized = that.serialized;
that.serialized = function () { that.serialized = function () {
var o = super_serialized(); var o = super_serialized();
o.storage = priv.sub_storage_spec; o.storage = priv.sub_storage_spec;
return o; return o;
}; };
that.validateState = function () { that.validateState = function () {
if (storage_exists) { if (storage_exists) {
return ''; return '';
} }
return 'Need at least one parameter: "storage".'; return 'Need at least one parameter: "storage".';
}; };
priv.getDistantMetadata = function (command,path,success,error) { priv.getDistantMetadata = function (command, path, success, error) {
var cloned_option = command.cloneOption (); var cloned_option = command.cloneOption();
cloned_option.metadata_only = false; cloned_option.metadata_only = false;
that.addJob ('get',priv.sub_storage_spec,path,cloned_option, that.addJob('get', priv.sub_storage_spec, path, cloned_option,
success, error); success, error);
}; };
priv.saveMetadataToDistant = function (command,path,content,success,error) { priv.saveMetadataToDistant = function (command, path, content, success,
that.addJob ('put',priv.sub_storage_spec, error) {
{_id:path,content:JSON.stringify (content)}, that.addJob('put', priv.sub_storage_spec, {
command.cloneOption(),success,error); _id: path,
}; content: JSON.stringify(content)
},
command.cloneOption(), success, error);
};
priv.saveNewRevision = function (command,path,content,success,error) { priv.saveNewRevision = function (command, path, content, success, error) {
that.addJob ('post',priv.sub_storage_spec,{_id:path,content:content}, that.addJob('post', priv.sub_storage_spec, {
command.cloneOption(),success,error); _id: path,
}; content: content
},
command.cloneOption(), success, error);
};
priv.loadRevision = function (command,path,success,error) { priv.loadRevision = function (command, path, success, error) {
that.addJob('get',priv.sub_storage_spec,path,command.cloneOption(), that.addJob('get', priv.sub_storage_spec, path, command.cloneOption(),
success, error); success, error);
}; };
priv.deleteAFile = function (command,path,success,error) { priv.deleteAFile = function (command, path, success, error) {
var cloned_option = command.cloneOption(); that.addJob('remove', priv.sub_storage_spec, {
that.addJob ('remove',priv.sub_storage_spec,{_id:path}, _id: path
command.cloneOption(), success, error); },
}; command.cloneOption(), success, error);
};
priv.chooseARevision = function (metadata) { priv.chooseARevision = function (metadata) {
var tmp_last_modified = 0, ret_rev = '', rev; var tmp_last_modified = 0,
for (rev in metadata) { ret_rev = '',
if (tmp_last_modified < rev;
metadata[rev]._last_modified) { for (rev in metadata) {
tmp_last_modified = if (metadata.hasOwnProperty(rev)) {
metadata[rev]._last_modified; if (tmp_last_modified < metadata[rev]._last_modified) {
ret_rev = rev; tmp_last_modified = metadata[rev]._last_modified;
} ret_rev = rev;
} }
return ret_rev; }
}; }
return ret_rev;
};
priv._revs = function (metadata,revision) { priv._revs = function (metadata, revision) {
if (!(metadata && revision)) { return null; } if (!(metadata && revision)) {
if (metadata[revision]) { return null;
return {start:metadata[revision]._revisions.length, }
ids:metadata[revision]._revisions}; if (metadata[revision]) {
} else { return {
return null; start: metadata[revision]._revisions.length,
} ids: metadata[revision]._revisions
}; };
}
return null;
};
priv._revs_info = function (metadata) { priv._revs_info = function (metadata) {
if (!metadata) { return null; } if (!metadata) {
var k, l = []; return null;
for (k in metadata) { }
l.push({ var k, l = [];
rev:k,status:(metadata[k]?( for (k in metadata) {
metadata[k]._deleted?'deleted':'available'):'missing') if (metadata.hasOwnProperty(k)) {
}); l.push({
} rev: k,
return l; status: (
}; metadata[k] ? (
metadata[k]._deleted ? 'deleted' : 'available'
priv.solveConflict = function (doc,option,param) { ) : 'missing'
var o = {}, am = priv.newAsyncModule(), )
});
}
}
return l;
};
command = param.command, priv.solveConflict = function (doc, option, param) {
metadata_file_path = param.docid + '.metadata', var o = {}, am = priv.newAsyncModule(),
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {total_rows:0,rows:[]},
on_remove = param._deleted,
previous_revision = param.previous_revision,
previous_revision_content_object = null,
now = new Date(),
failerror;
o.getDistantMetadata = function (){ command = param.command,
priv.getDistantMetadata ( metadata_file_path = param.docid + '.metadata',
command, metadata_file_path, current_revision = '',
function (result) { current_revision_file_path = '',
var previous_revision_number = metadata_file_content = null,
parseInt(previous_revision.split('-')[0],10); on_conflict = false,
metadata_file_content = JSON.parse (result.content); conflict_object = {
// set current revision total_rows: 0,
current_revision = (previous_revision_number + 1) + '-' + rows: []
hex_sha256 ('' + doc.content + },
previous_revision + on_remove = param._deleted,
JSON.stringify (metadata_file_content)); previous_revision = param.previous_revision,
current_revision_file_path = param.docid + '.' + previous_revision_content_object = null,
current_revision; now = new Date(),
previous_revision_content_object = metadata_file_content[ failerror;
previous_revision] || {};
if (!on_remove) {
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
}
am.call(o,'previousUpdateMetadata');
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.saveNewRevision = function (){
priv.saveNewRevision (
command, current_revision_file_path, doc.content,
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.previousUpdateMetadata = function () {
var i;
for (i = 0; i < param.key.length; i+= 1) {
delete metadata_file_content[param.key[i]];
}
am.call(o,'checkForConflicts');
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
var revision_index;
on_conflict = true;
failerror = {
status:409,error:'conflict',
statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts'
};
break;
}
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
var revision_history, id = '';
id = current_revision.split('-'); id.shift(); id = id.join('-');
revision_history = previous_revision_content_object._revisions;
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date:previous_revision_content_object._creation_date||
now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: on_remove
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
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 (){
var i;
for (i = 0; i < param.key.length; i+= 1) {
priv.deleteAFile (
command, param.docid+'.'+param.key[i], empty_fun,empty_fun);
}
};
o.success = function (){
var a = {ok:true,id:param.docid,rev:current_revision};
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.revs) {
a.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (option.revs_info) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
a.conflicts = conflict_object;
}
param.success(a);
};
o.error = function (error){
var err = error || failerror ||
{status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.',reason:'unknown error'};
if (current_revision) {
err.rev = current_revision;
}
if (option.revs) {
err.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (option.revs_info) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
err.conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
param.error(err);
};
am.call(o,'getDistantMetadata');
};
priv.createConflictObject = function (command, metadata, revision) { o.getDistantMetadata = function () {
return { priv.getDistantMetadata(
total_rows:1, command,
rows:[priv.createConflictRow(command,command.getDocId(), metadata_file_path,
metadata,revision)] function (result) {
}; var previous_revision_number =
parseInt(previous_revision.split('-')[0], 10);
metadata_file_content = JSON.parse(result.content);
// set current revision
// jslint: removed '' in hex_sha256(''...
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256(doc.content + previous_revision +
JSON.stringify(metadata_file_content));
current_revision_file_path = param.docid + '.' + current_revision;
previous_revision_content_object = metadata_file_content[
previous_revision
] || {};
if (!on_remove) {
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
}
am.call(o, 'previousUpdateMetadata');
},
function (error) {
am.call(o, 'error', [error]);
}
);
}; };
o.saveNewRevision = function () {
priv.getParam = function (list) { priv.saveNewRevision(
var param = {}, i = 0; command,
if (typeof list[i] === 'string') { current_revision_file_path,
param.content = list[i]; doc.content,
i ++; function () {
am.call(o, 'saveMetadataOnDistant');
},
function (error) {
am.call(o, 'error', [error]);
} }
if (typeof list[i] === 'object') { );
param.options = list[i]; };
i ++; o.previousUpdateMetadata = function () {
} else { var i;
param.options = {}; for (i = 0; i < param.key.length; i += 1) {
delete metadata_file_content[param.key[i]];
}
am.call(o, 'checkForConflicts');
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (metadata_file_content.hasOwnProperty(rev)) {
on_conflict = true;
failerror = {
status: 409,
error: 'conflict',
statusText: 'Conflict',
reason: 'document update conflict',
message: 'There is one or more conflicts'
};
break;
} }
param.callback = function (err,val){}; }
param.success = function (val) { am.call(o, 'updateMetadata');
param.callback(undefined,val); };
}; o.updateMetadata = function () {
param.error = function (err) { var revision_history, id = '';
param.callback(err,undefined); id = current_revision.split('-');
}; id.shift();
if (typeof list[i] === 'function') { id = id.join('-');
if (typeof list[i+1] === 'function') { revision_history = previous_revision_content_object._revisions;
param.success = list[i]; revision_history.unshift(id);
param.error = list[i+1]; metadata_file_content[current_revision] = {
} else { _creation_date: previous_revision_content_object._creation_date ||
param.callback = list[i]; now.getTime(),
} _last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: on_remove
};
if (on_conflict) {
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function () {
priv.saveMetadataToDistant(
command,
metadata_file_path,
metadata_file_content,
function () {
am.call(o, 'deleteAllConflictingRevision');
if (on_conflict) {
am.call(o, 'error');
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
} }
return param; );
};
o.deleteAllConflictingRevision = function () {
var i;
for (i = 0; i < param.key.length; i += 1) {
priv.deleteAFile(
command,
param.docid + '.' + param.key[i],
empty_fun,
empty_fun
);
}
}; };
o.success = function () {
var a = {
ok: true,
id: param.docid,
rev: current_revision
};
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (option.revs) {
a.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (option.revs_info) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
a.conflicts = conflict_object;
}
param.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (option.revs) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (option.revs_info) {
err.revs_info = priv._revs_info(
metadata_file_content
);
}
if (option.conflicts) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
param.error(err);
};
am.call(o, 'getDistantMetadata');
};
priv.createConflictRow = function (command, docid, metadata, revision) { priv.createConflictObject = function (command, metadata, revision) {
var row = {id:docid,key:[],value:{ return {
_solveConflict: function (/*content, option, success, error*/) { total_rows: 1,
var param = {}, got = priv.getParam(arguments); rows: [priv.createConflictRow(
if (got.content === undefined) { command,
param._deleted = true; command.getDocId(),
} else { metadata,
param._deleted = false; revision
} )]
param.success = got.success;
param.error = got.error;
param.previous_revision = revision;
param.docid = docid;
param.key = row.key;
param.command = command.clone();
return priv.solveConflict (
{_id:docid,content:got.content,_rev:revision},
got.options,param
);
}
}}, k;
for (k in metadata) {
row.key.push(k);
}
return row;
}; };
};
priv.newAsyncModule = function () { priv.getParam = function (list) {
var async = {}; var param = {}, i = 0;
async.call = function (obj,function_name,arglist) { if (typeof list[i] === 'string') {
obj._wait = obj._wait || {}; param.content = list[i];
if (obj._wait[function_name]) { i += 1;
obj._wait[function_name]--; }
return empty_fun; if (typeof list[i] === 'object') {
} param.options = list[i];
// ok if undef or 0 i += 1;
arglist = arglist || []; } else {
setTimeout(function(){ param.options = {};
obj[function_name].apply(obj[function_name],arglist); }
}); param.callback = function () {};
}; param.success = function (val) {
async.neverCall = function (obj,function_name) { param.callback(undefined, val);
obj._wait = obj._wait || {}; };
obj._wait[function_name] = -1; param.error = function (err) {
}; param.callback(err, undefined);
async.wait = function (obj,function_name,times) {
obj._wait = obj._wait || {};
obj._wait[function_name] = times;
};
async.end = function () {
async.call = empty_fun;
};
return async;
}; };
if (typeof list[i] === 'function') {
if (typeof list[i + 1] === 'function') {
param.success = list[i];
param.error = list[i + 1];
} else {
param.callback = list[i];
}
}
return param;
};
that.post = function (command) { priv.createConflictRow = function (command, docid, metadata, revision) {
that.put (command); var row = {
id: docid,
key: [],
value: {
// jslint: removed params /* content, option, success, error */
_solveConflict: function () {
var param = {}, got = priv.getParam(arguments);
if (got.content === undefined) {
param._deleted = true;
} else {
param._deleted = false;
}
param.success = got.success;
param.error = got.error;
param.previous_revision = revision;
param.docid = docid;
param.key = row.key;
param.command = command.clone();
return priv.solveConflict({
_id: docid,
content: got.content,
_rev: revision
},
got.options, param);
}
}
}, k;
for (k in metadata) {
if (metadata.hasOwnProperty(k)) {
row.key.push(k);
}
}
return row;
};
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] -= 1;
return empty_fun;
}
// ok if undef or 0
arglist = arglist || [];
setTimeout(function () {
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 = empty_fun;
};
return async;
};
/** that.post = function (command) {
* Save a document and can manage conflicts. that.put(command);
* @method put };
*/
that.put = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getDocId() + '.metadata', /**
current_revision = '', * Save a document and can manage conflicts.
current_revision_file_path = '', * @method put
metadata_file_content = null, */
on_conflict = false, conflict_object = {total_rows:0,rows:[]}, that.put = function (command) {
previous_revision = command.getDocInfo('_rev') || '0', var o = {}, am = priv.newAsyncModule(),
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
o.getDistantMetadata = function (){ metadata_file_path = command.getDocId() + '.metadata',
priv.getDistantMetadata ( current_revision = '',
command,metadata_file_path, current_revision_file_path = '',
function (result) { metadata_file_content = null,
var previous_revision_number = on_conflict = false,
parseInt(previous_revision.split('-')[0],10); conflict_object = {
metadata_file_content = JSON.parse (result.content); total_rows: 0,
// set current revision rows: []
current_revision = (previous_revision_number + 1) + '-' + },
hex_sha256 ('' + command.getDocContent() + previous_revision = command.getDocInfo('_rev') || '0',
previous_revision + previous_revision_file_path = command.getDocId() + '.' +
JSON.stringify (metadata_file_content)); previous_revision,
current_revision_file_path = command.getDocId() + '.' + now = new Date(),
current_revision; failerror;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
current_revision = '1-' +
hex_sha256 (command.getDocContent());
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
am.call(o,'createMetadata');
} else {
am.call(o,'error',[error]);
}
}
);
};
o.saveNewRevision = function (){
priv.saveNewRevision (
command,current_revision_file_path,command.getDocContent(),
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
am.call(o,'error',[error]);
}
);
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:409,error:'conflict',
statusText:'Conflict',reason:'document update conflict',
message:'Document update conflict.'
};
break;
}
}
am.call(o,'updateMetadata');
};
o.createMetadata = function (){
var id = current_revision;
id = id.split('-'); id.shift(); id = id.join('-');
metadata_file_content = {};
metadata_file_content[current_revision] = {
_creation_date: now.getTime(),
_last_modified: now.getTime(),
_revisions: [id],
_conflict: false,
_deleted: false
};
am.call(o,'saveMetadataOnDistant');
};
o.updateMetadata = function (){
var previous_creation_date, revision_history = [], id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision]._creation_date;
revision_history = metadata_file_content[
previous_revision]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision.split('-'); id.shift(); id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: false
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
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,'error',[error]);
}
);
};
o.deletePreviousRevision = function (){
if (previous_revision !== '0' /*&& !on_conflict*/) {
priv.deleteAFile (
command, previous_revision_file_path,
empty_fun,empty_fun);
}
};
o.success = function () {
var a = {ok:true,id:command.getDocId(),rev:current_revision};
am.neverCall(o,'error');
am.neverCall(o,'success');
if (command.getOption('revs')) {
a.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error) {
var err = error || failerror ||
{status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.',reason:'unknown error'};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(err);
};
am.call(o,'getDistantMetadata');
}; // end put
/** o.getDistantMetadata = function () {
* Load a document from several storages, and send the first retreived priv.getDistantMetadata(
* document. command,
* @method get metadata_file_path,
*/ function (result) {
that.get = function (command) { var previous_revision_number =
var o = {}, am = priv.newAsyncModule(), parseInt(previous_revision.split('-')[0], 10);
metadata_file_content = JSON.parse(result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
// jslint: removed hex_sha256(''+...
hex_sha256(command.getDocContent() + previous_revision +
JSON.stringify(metadata_file_content));
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
am.call(o, 'checkForConflicts');
},
function (error) {
if (error.status === 404) {
current_revision = '1-' + hex_sha256(command.getDocContent());
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
am.call(o, 'createMetadata');
} else {
am.call(o, 'error', [error]);
}
}
);
};
o.saveNewRevision = function () {
priv.saveNewRevision(
command,
current_revision_file_path,
command.getDocContent(),
function () {
am.call(o, 'saveMetadataOnDistant');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (metadata_file_content.hasOwnProperty(rev) &&
rev !== previous_revision) {
on_conflict = true;
failerror = {
status: 409,
error: 'conflict',
statusText: 'Conflict',
reason: 'document update conflict',
message: 'Document update conflict.'
};
break;
}
}
am.call(o, 'updateMetadata');
};
o.createMetadata = function () {
var id = current_revision;
id = id.split('-');
id.shift();
id = id.join('-');
metadata_file_content = {};
metadata_file_content[current_revision] = {
_creation_date: now.getTime(),
_last_modified: now.getTime(),
_revisions: [id],
_conflict: false,
_deleted: false
};
am.call(o, 'saveMetadataOnDistant');
};
o.updateMetadata = function () {
var previous_creation_date, revision_history = [],
id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision
]._creation_date;
revision_history = metadata_file_content[
previous_revision
]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision.split('-');
id.shift();
id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: false
};
if (on_conflict) {
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function () {
priv.saveMetadataToDistant(
command,
metadata_file_path,
metadata_file_content,
function () {
am.call(o, 'deletePreviousRevision');
if (on_conflict) {
am.call(o, 'error');
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.deletePreviousRevision = function () {
// jslint: removed /*&& !on_conflict*/
if (previous_revision !== '0') {
priv.deleteAFile(
command,
previous_revision_file_path,
empty_fun,
empty_fun
);
}
};
o.success = function () {
var a = {
ok: true,
id: command.getDocId(),
rev: current_revision
};
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (command.getOption('revs')) {
a.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
}; // end put
metadata_file_path = command.getDocId() + '.metadata', /**
current_revision = command.getOption('rev') || '', * Load a document from several storages, and send the first retreived
metadata_file_content = null, * document.
metadata_only = command.getOption('metadata_only'), * @method get
on_conflict = false, conflict_object = {total_rows:0,rows:[]}, */
now = new Date(), that.get = function (command) {
doc = {_id:command.getDocId()}, var o = {}, am = priv.newAsyncModule(),
call404 = function (message) { metadata_file_path = command.getDocId() + '.metadata',
am.call(o,'error',[{ current_revision = command.getOption('rev') || '',
status:404,statusText:'Not Found',error:'not_found', metadata_file_content = null,
message:message,reason:message metadata_only = command.getOption('metadata_only'),
}]); on_conflict = false,
}; conflict_object = {
total_rows: 0,
rows: []
},
doc = {
_id: command.getDocId()
},
call404 = function (message) {
am.call(o, 'error', [{
status: 404,
statusText: 'Not Found',
error: 'not_found',
message: message,
reason: message
}]);
};
o.getDistantMetadata = function (){ o.getDistantMetadata = function () {
priv.getDistantMetadata ( priv.getDistantMetadata(
command,metadata_file_path, command,
function (result) { metadata_file_path,
metadata_file_content = JSON.parse (result.content); function (result) {
if (!metadata_only) { metadata_file_content = JSON.parse(result.content);
am.wait(o,'success',1); if (!metadata_only) {
} am.wait(o, 'success', 1);
am.call(o,'affectMetadata'); }
am.call(o,'checkForConflicts'); am.call(o, 'affectMetadata');
},function (error) { am.call(o, 'checkForConflicts');
am.call(o,'error',[error]); },
} function (error) {
); am.call(o, 'error', [error]);
}; }
o.affectMetadata = function () { );
if (current_revision) { };
if (!metadata_file_content[current_revision]) { o.affectMetadata = function () {
return call404('Document revision does not exists.'); if (current_revision) {
} if (!metadata_file_content[current_revision]) {
} else { return call404('Document revision does not exists.');
current_revision = priv.chooseARevision(metadata_file_content); }
} } else {
doc._last_modified = current_revision = priv.chooseARevision(metadata_file_content);
metadata_file_content[current_revision]._last_modified; }
doc._creation_date = doc._last_modified =
metadata_file_content[current_revision]._creation_date; metadata_file_content[current_revision]._last_modified;
doc._rev = current_revision; doc._creation_date =
if (metadata_only) { metadata_file_content[current_revision]._creation_date;
am.call(o,'success'); doc._rev = current_revision;
} else { if (metadata_only) {
am.call(o,'loadRevision'); am.call(o, 'success');
} } else {
}; am.call(o, 'loadRevision');
o.loadRevision = function (){ }
if (!current_revision || };
metadata_file_content[current_revision]._deleted) { o.loadRevision = function () {
return call404('Document has been removed.'); if (!current_revision ||
} metadata_file_content[current_revision]._deleted) {
priv.loadRevision ( return call404('Document has been removed.');
command, doc._id+'.'+current_revision, }
function (result) { priv.loadRevision(
doc.content = result.content; command,
am.call(o,'success'); doc._id + '.' + current_revision,
}, function (error) { function (result) {
am.call(o,'error',[error]); doc.content = result.content;
} am.call(o, 'success');
); },
}; function (error) {
o.checkForConflicts = function () { am.call(o, 'error', [error]);
if (metadata_file_content[current_revision]._conflict) { }
on_conflict = true; );
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o,'success');
};
o.success = function (){
am.neverCall(o,'error');
am.neverCall(o,'success');
if (command.getOption('revs')) {
doc._revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
doc._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
doc._conflicts = conflict_object;
}
that.success(doc);
};
o.error = function (error) {
var err = error || {status:0,statusText:'Unknown',
message:'Unknown error.'};
if (command.getOption('revs')) {
err._revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
err._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err._conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(err);
};
am.call(o,'getDistantMetadata');
}; };
o.checkForConflicts = function () {
if (metadata_file_content[current_revision]._conflict) {
on_conflict = true;
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'success');
};
o.success = function () {
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (command.getOption('revs')) {
doc._revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
doc._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
doc._conflicts = conflict_object;
}
that.success(doc);
};
o.error = function (error) {
var err = error || {
status: 0,
statusText: 'Unknown',
message: 'Unknown error.'
};
if (command.getOption('revs')) {
err._revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err._conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
};
/** /**
* Get a document list from several storages, and returns the first * Get a document list from several storages, and returns the first
* retreived document list. * retreived document list.
* @method allDocs * @method allDocs
*/ */
that.allDocs = function (command) { that.allDocs = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_only = command.getOption('metadata_only'), metadata_only = command.getOption('metadata_only'),
result_list = [], conflict_object = {total_rows:0,rows:[]}, result_list = [],
nb_loaded_file = 0, conflict_object = {
success_count = 0, success_max = 0; total_rows: 0,
o.retreiveList = function () { rows: []
var cloned_option = command.cloneOption (), },
success = function (result) { success_count = 0,
am.call(o,'filterTheList',[result]); success_max = 0;
},error = function (error) { o.retreiveList = function () {
am.call(o,'error',[error]); var cloned_option = command.cloneOption(),
}; success = function (result) {
cloned_option.metadata_only = true; am.call(o, 'filterTheList', [result]);
that.addJob ('allDocs',priv.sub_storage_spec,null,cloned_option, },
success,error); error = function (error) {
}; am.call(o, 'error', [error]);
o.filterTheList = function (result) {
var i;
success_max ++;
for (i = 0; i < result.total_rows; i+= 1) {
var splitname = result.rows[i].id.split('.') || [];
if (splitname.length > 0 &&
splitname[splitname.length-1] === 'metadata') {
success_max ++;
splitname.length --;
am.call(o,'loadMetadataFile',[splitname.join('.')]);
}
}
am.call(o,'success');
};
o.loadMetadataFile = function (path) {
priv.getDistantMetadata (
command, path+'.metadata',
function (data) {
data = JSON.parse (data.content);
var revision = priv.chooseARevision(data);
if (!data[revision]._deleted) {
am.call(
o,'loadFile',[path,revision,data]
);
} else {
am.call(o,'success');
}
},function (error) {
am.call(o,'error',[error]);
}
);
};
o.loadFile = function (path,revision,data) {
var doc = {
id: path,key: path,value:{
_last_modified:data[revision]._last_modified,
_creation_date:data[revision]._creation_date,
_rev:revision
}
};
if (command.getOption('revs')) {
doc.value._revisions = priv._revs(data,revision);
}
if (command.getOption('revs_info')) {
doc.value._revs_info = priv._revs_info(data,revision);
}
if (command.getOption('conflicts')) {
if (data[revision]._conflict) {
conflict_object.total_rows ++;
conflict_object.rows.push(priv.createConflictRow(
command, path, data, revision
));
}
}
if (!metadata_only) {
priv.loadRevision (
command,path+'.'+revision,
function (data) {
doc.content = data.content;
result_list.push(doc);
am.call(o,'success');
},function (error) {
am.call(o,'error',[error]);
});
} else {
result_list.push(doc);
am.call(o,'success');
}
};
o.success = function (){
var obj;
success_count ++;
if (success_count >= success_max) {
am.end();
obj = {total_rows:result_list.length,rows:result_list};
if (command.getOption('conflicts')) {
obj.conflicts = conflict_object;
}
that.success(obj);
}
}; };
o.error = function (error){ cloned_option.metadata_only = true;
am.end(); that.addJob('allDocs', priv.sub_storage_spec, null, cloned_option,
that.error(error); success, error
);
};
o.filterTheList = function (result) {
var i, splitname;
success_max += 1;
for (i = 0; i < result.total_rows; i += 1) {
splitname = result.rows[i].id.split('.') || [];
if (splitname.length > 0 && splitname[splitname.length - 1] ===
'metadata') {
success_max += 1;
splitname.length -= 1;
am.call(o, 'loadMetadataFile', [splitname.join('.')]);
}
}
am.call(o, 'success');
};
o.loadMetadataFile = function (path) {
priv.getDistantMetadata(
command,
path + '.metadata',
function (data) {
data = JSON.parse(data.content);
var revision = priv.chooseARevision(data);
if (!data[revision]._deleted) {
am.call(o, 'loadFile', [path, revision, data]);
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.loadFile = function (path, revision, data) {
var doc = {
id: path,
key: path,
value: {
_last_modified: data[revision]._last_modified,
_creation_date: data[revision]._creation_date,
_rev: revision
}
};
if (command.getOption('revs')) {
doc.value._revisions = priv._revs(data, revision);
}
if (command.getOption('revs_info')) {
doc.value._revs_info = priv._revs_info(data, revision);
}
if (command.getOption('conflicts')) {
if (data[revision]._conflict) {
conflict_object.total_rows += 1;
conflict_object.rows.push(
priv.createConflictRow(command, path, data, revision)
);
}
}
if (!metadata_only) {
priv.loadRevision(
command,
path + '.' + revision,
function (data) {
doc.content = data.content;
result_list.push(doc);
am.call(o, 'success');
},
function (error) {
am.call(o, 'error', [error]);
}
);
} else {
result_list.push(doc);
am.call(o, 'success');
}
};
o.success = function () {
var obj;
success_count += 1;
if (success_count >= success_max) {
am.end();
obj = {
total_rows: result_list.length,
rows: result_list
}; };
am.call(o,'retreiveList'); if (command.getOption('conflicts')) {
}; // end allDocs obj.conflicts = conflict_object;
}
that.success(obj);
}
};
o.error = function (error) {
am.end();
that.error(error);
};
am.call(o, 'retreiveList');
}; // end allDocs
/** /**
* Remove a document from several storages. * Remove a document from several storages.
* @method remove * @method remove
*/ */
that.remove = function (command) { that.remove = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getDocId() + '.metadata', metadata_file_path = command.getDocId() + '.metadata',
current_revision = '', current_revision = '',
current_revision_file_path = '', current_revision_file_path = '',
metadata_file_content = null, metadata_file_content = null,
on_conflict = false, conflict_object = {total_rows:0,rows:[]}, on_conflict = false,
previous_revision = command.getOption('rev') || '0', conflict_object = {
previous_revision_file_path = command.getDocId() + '.' + total_rows: 0,
previous_revision, rows: []
now = new Date(), },
failerror; previous_revision = command.getOption('rev') || '0',
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
o.getDistantMetadata = function (){ o.getDistantMetadata = function () {
priv.getDistantMetadata ( priv.getDistantMetadata(
command,metadata_file_path, command,
function (result) { metadata_file_path,
metadata_file_content = JSON.parse (result.content); function (result) {
if (previous_revision === 'last') { metadata_file_content = JSON.parse(result.content);
previous_revision = if (previous_revision === 'last') {
priv.chooseARevision (metadata_file_content); previous_revision = priv.chooseARevision(metadata_file_content);
previous_revision_file_path = command.getDocId() + '.' + previous_revision_file_path = command.getDocId() + '.' +
previous_revision; previous_revision;
} }
var previous_revision_number = var previous_revision_number =
parseInt(previous_revision.split('-')[0],10) || 0; parseInt(previous_revision.split('-')[0], 10) || 0;
// set current revision // set current revision
current_revision = (previous_revision_number + 1) + '-' + current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + previous_revision + //jslint: removed hex_sha256(''...
JSON.stringify (metadata_file_content)); hex_sha256(previous_revision +
current_revision_file_path = command.getDocId() + '.' + JSON.stringify(metadata_file_content)
current_revision; );
am.call(o,'checkForConflicts'); current_revision_file_path = command.getDocId() + '.' +
},function (error) { current_revision;
if (error.status === 404) { am.call(o, 'checkForConflicts');
am.call(o,'error',[{ },
status:404,statusText:'Not Found', function (error) {
error:'not_found',reason:'missing', if (error.status === 404) {
message:'Document not found.' am.call(o, 'error', [{
}]); status: 404,
} else { statusText: 'Not Found',
am.call(o,'error',[error]); error: 'not_found',
} reason: 'missing',
} message: 'Document not found.'
); }]);
}; } else {
o.checkForConflicts = function () { am.call(o, 'error', [error]);
var rev; }
for (rev in metadata_file_content) { }
if (rev !== previous_revision) { );
on_conflict = true; };
failerror = { o.checkForConflicts = function () {
status:409,error:'conflict', var rev;
statusText:'Conflict',reason:'document update conflict', for (rev in metadata_file_content) {
message:'There is one or more conflicts' if (metadata_file_content.hasOwnProperty(rev) &&
}; rev !== previous_revision) {
break; on_conflict = true;
} failerror = {
} status: 409,
am.call(o,'updateMetadata'); error: 'conflict',
}; statusText: 'Conflict',
o.updateMetadata = function (){ reason: 'document update conflict',
var previous_creation_date, revision_history = [], id = ''; message: 'There is one or more conflicts'
if (metadata_file_content[previous_revision]) { };
previous_creation_date = metadata_file_content[ break;
previous_revision]._creation_date; }
revision_history = metadata_file_content[ }
previous_revision]._revisions; am.call(o, 'updateMetadata');
delete metadata_file_content[previous_revision]; };
} o.updateMetadata = function () {
id = current_revision; var previous_creation_date, revision_history = [],
id = id.split('-'); id.shift(); id = id.join('-'); id = '';
revision_history.unshift(id); if (metadata_file_content[previous_revision]) {
metadata_file_content[current_revision] = { previous_creation_date = metadata_file_content[
_creation_date: previous_creation_date || now.getTime(), previous_revision
_last_modified: now.getTime(), ]._creation_date;
_revisions: revision_history, revision_history = metadata_file_content[
_conflict: on_conflict, previous_revision
_deleted: true ]._revisions;
}; delete metadata_file_content[previous_revision];
if (on_conflict) { }
conflict_object = id = current_revision;
priv.createConflictObject( id = id.split('-');
command, metadata_file_content, current_revision id.shift();
); id = id.join('-');
} revision_history.unshift(id);
am.call(o,'saveMetadataOnDistant'); metadata_file_content[current_revision] = {
}; _creation_date: previous_creation_date || now.getTime(),
o.saveMetadataOnDistant = function (){ _last_modified: now.getTime(),
priv.saveMetadataToDistant( _revisions: revision_history,
command, metadata_file_path, metadata_file_content, _conflict: on_conflict,
function (result) { _deleted: true
am.call(o,'deletePreviousRevision'); };
if (on_conflict) { if (on_conflict) {
am.call(o,'error'); conflict_object = priv.createConflictObject(
} else { command,
am.call(o,'success'); metadata_file_content,
} current_revision
},function (error) { );
am.call(o,'error',[error]); }
} am.call(o, 'saveMetadataOnDistant');
); };
}; o.saveMetadataOnDistant = function () {
o.deletePreviousRevision = function (){ priv.saveMetadataToDistant(
if (previous_revision !== '0' /*&& !on_conflict*/) { command,
priv.deleteAFile ( metadata_file_path,
command, previous_revision_file_path, metadata_file_content,
empty_fun,empty_fun); function () {
} am.call(o, 'deletePreviousRevision');
}; if (on_conflict) {
o.success = function (revision){ am.call(o, 'error');
var a = {ok:true,id:command.getDocId(), } else {
rev:revision || current_revision}; am.call(o, 'success');
am.neverCall(o,'error'); }
am.neverCall(o,'success'); },
if (command.getOption('revs')) { function (error) {
a.revisions = priv._revs(metadata_file_content, am.call(o, 'error', [error]);
current_revision); }
} );
if (command.getOption('revs_info')) { };
a.revs_info = priv._revs_info(metadata_file_content); o.deletePreviousRevision = function () {
} // jslint: removed /*&& !on_conflict*/
if (command.getOption('conflicts')) { if (previous_revision !== '0') {
a.conflicts = conflict_object; priv.deleteAFile(
} command,
that.success(a); previous_revision_file_path,
}; empty_fun,
o.error = function (error){ empty_fun
var err = error || failerror || );
{status:0,statusText:'Unknown',error:'unknown_error', }
message:'Unknown error.',reason:'unknown error'}; };
if (current_revision) { o.success = function (revision) {
err.rev = current_revision; var a = {
} ok: true,
if (command.getOption('revs')) { id: command.getDocId(),
err.revisions = priv._revs(metadata_file_content, rev: revision || current_revision
current_revision); };
} am.neverCall(o, 'error');
if (command.getOption('revs_info')) { am.neverCall(o, 'success');
err.revs_info = priv._revs_info(metadata_file_content); if (command.getOption('revs')) {
} a.revisions = priv._revs(
if (command.getOption('conflicts')) { metadata_file_content,
err.conflicts = conflict_object; current_revision
} );
am.neverCall(o,'error'); }
am.neverCall(o,'success'); if (command.getOption('revs_info')) {
that.error(err); a.revs_info = priv._revs_info(metadata_file_content);
}; }
am.call(o,'getDistantMetadata'); if (command.getOption('conflicts')) {
}; // end remove a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
}; // end remove
return that; return that;
}; });
\ No newline at end of file
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