Commit 9aff3608 authored by Vincent Bechu's avatar Vincent Bechu

erp5_web_renderjs_ui: Release v3.19.0 Jio

parent 96a9d8c5
...@@ -8428,6 +8428,15 @@ return new Parser; ...@@ -8428,6 +8428,15 @@ return new Parser;
CONFLICT_KEEP_REMOTE = 2, CONFLICT_KEEP_REMOTE = 2,
CONFLICT_CONTINUE = 3; CONFLICT_CONTINUE = 3;
function SkipError(message) {
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Skip some asynchronous code";
}
SkipError.prototype = new Error();
SkipError.prototype.constructor = SkipError;
/**************************************************** /****************************************************
Use a local jIO to read/write/search documents Use a local jIO to read/write/search documents
Synchronize in background those document with a remote jIO. Synchronize in background those document with a remote jIO.
...@@ -8446,20 +8455,33 @@ return new Parser; ...@@ -8446,20 +8455,33 @@ return new Parser;
function ReplicateStorage(spec) { function ReplicateStorage(spec) {
this._query_options = spec.query || {}; this._query_options = spec.query || {};
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage); this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage); this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
if (spec.hasOwnProperty('signature_sub_storage')) {
this._signature_sub_storage = jIO.createJIO(spec.signature_sub_storage);
this._custom_signature_sub_storage = true;
} else {
this._signature_hash = "_replicate_" + generateHash( this._signature_hash = "_replicate_" + generateHash(
stringify(spec.local_sub_storage) + stringify(spec.local_sub_storage) +
stringify(spec.remote_sub_storage) + stringify(spec.remote_sub_storage) +
stringify(this._query_options) stringify(this._query_options)
); );
this._signature_sub_storage = jIO.createJIO({ this._signature_sub_storage = jIO.createJIO({
type: "query",
sub_storage: {
type: "document", type: "document",
document_id: this._signature_hash, document_id: this._signature_hash,
sub_storage: spec.signature_storage || spec.local_sub_storage sub_storage: spec.local_sub_storage
}
}); });
this._custom_signature_sub_storage = false;
}
this._use_remote_post = spec.use_remote_post || false; this._use_remote_post = spec.use_remote_post || false;
// Number of request we allow browser execution for attachments // Number of request we allow browser execution for attachments
...@@ -8602,15 +8624,8 @@ return new Parser; ...@@ -8602,15 +8624,8 @@ return new Parser;
arguments); arguments);
}; };
ReplicateStorage.prototype.repair = function () { function dispatchQueue(context, function_used, argument_list,
var context = this, number_queue) {
argument_list = arguments,
skip_document_dict = {};
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
function dispatchQueue(function_used, argument_list, number_queue) {
var result_promise_list = [], var result_promise_list = [],
i; i;
...@@ -8637,7 +8652,27 @@ return new Parser; ...@@ -8637,7 +8652,27 @@ return new Parser;
return result_promise_list[0]; return result_promise_list[0];
} }
function propagateAttachmentDeletion(skip_attachment_dict, function callAllDocsOnStorage(context, storage, cache, cache_key) {
return new RSVP.Queue()
.push(function () {
if (!cache.hasOwnProperty(cache_key)) {
return storage.allDocs(context._query_options)
.push(function (result) {
var i,
cache_entry = {};
for (i = 0; i < result.data.total_rows; i += 1) {
cache_entry[result.data.rows[i].id] = result.data.rows[i].value;
}
cache[cache_key] = cache_entry;
});
}
})
.push(function () {
return cache[cache_key];
});
}
function propagateAttachmentDeletion(context, skip_attachment_dict,
destination, destination,
id, name) { id, name) {
return destination.removeAttachment(id, name) return destination.removeAttachment(id, name)
...@@ -8649,7 +8684,7 @@ return new Parser; ...@@ -8649,7 +8684,7 @@ return new Parser;
}); });
} }
function propagateAttachmentModification(skip_attachment_dict, function propagateAttachmentModification(context, skip_attachment_dict,
destination, destination,
blob, hash, id, name) { blob, hash, id, name) {
return destination.putAttachment(id, name, blob) return destination.putAttachment(id, name, blob)
...@@ -8664,7 +8699,8 @@ return new Parser; ...@@ -8664,7 +8699,8 @@ return new Parser;
}); });
} }
function checkAndPropagateAttachment(skip_attachment_dict, function checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob, status_hash, local_hash, blob,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8694,7 +8730,7 @@ return new Parser; ...@@ -8694,7 +8730,7 @@ return new Parser;
// Deleted on both side, drop signature // Deleted on both side, drop signature
return context._signature_sub_storage.removeAttachment(id, name) return context._signature_sub_storage.removeAttachment(id, name)
.push(function () { .push(function () {
skip_attachment_dict[id] = null; skip_attachment_dict[name] = null;
}); });
} }
...@@ -8703,7 +8739,7 @@ return new Parser; ...@@ -8703,7 +8739,7 @@ return new Parser;
hash: local_hash hash: local_hash
})) }))
.push(function () { .push(function () {
skip_document_dict[id] = null; skip_attachment_dict[name] = null;
}); });
} }
...@@ -8711,11 +8747,12 @@ return new Parser; ...@@ -8711,11 +8747,12 @@ return new Parser;
// Modified only locally. No conflict or force // Modified only locally. No conflict or force
if (local_hash === null) { if (local_hash === null) {
// Deleted locally // Deleted locally
return propagateAttachmentDeletion(skip_attachment_dict, return propagateAttachmentDeletion(context, skip_attachment_dict,
destination, destination,
id, name); id, name);
} }
return propagateAttachmentModification(skip_attachment_dict, return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob, destination, blob,
local_hash, id, name); local_hash, id, name);
} }
...@@ -8729,10 +8766,11 @@ return new Parser; ...@@ -8729,10 +8766,11 @@ return new Parser;
// Automatically resolve conflict or force revert // Automatically resolve conflict or force revert
if (remote_hash === null) { if (remote_hash === null) {
// Deleted remotely // Deleted remotely
return propagateAttachmentDeletion(skip_attachment_dict, return propagateAttachmentDeletion(context, skip_attachment_dict,
source, id, name); source, id, name);
} }
return propagateAttachmentModification( return propagateAttachmentModification(
context,
skip_attachment_dict, skip_attachment_dict,
source, source,
remote_blob, remote_blob,
...@@ -8745,7 +8783,8 @@ return new Parser; ...@@ -8745,7 +8783,8 @@ return new Parser;
// Minimize conflict if it can be resolved // Minimize conflict if it can be resolved
if (remote_hash === null) { if (remote_hash === null) {
// Copy remote modification remotely // Copy remote modification remotely
return propagateAttachmentModification(skip_attachment_dict, return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob, destination, blob,
local_hash, id, name); local_hash, id, name);
} }
...@@ -8756,7 +8795,8 @@ return new Parser; ...@@ -8756,7 +8795,8 @@ return new Parser;
}); });
} }
function checkAttachmentSignatureDifference(queue, skip_attachment_dict, function checkAttachmentSignatureDifference(queue, context,
skip_attachment_dict,
source, source,
destination, id, name, destination, id, name,
conflict_force, conflict_force,
...@@ -8798,7 +8838,8 @@ return new Parser; ...@@ -8798,7 +8838,8 @@ return new Parser;
local_hash = generateHashFromArrayBuffer(array_buffer); local_hash = generateHashFromArrayBuffer(array_buffer);
if (local_hash !== status_hash) { if (local_hash !== status_hash) {
return checkAndPropagateAttachment(skip_attachment_dict, return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob, status_hash, local_hash, blob,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8807,7 +8848,8 @@ return new Parser; ...@@ -8807,7 +8848,8 @@ return new Parser;
}); });
} }
function checkAttachmentLocalDeletion(queue, skip_attachment_dict, function checkAttachmentLocalDeletion(queue, context,
skip_attachment_dict,
destination, id, name, source, destination, id, name, source,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore) { conflict_ignore) {
...@@ -8819,7 +8861,8 @@ return new Parser; ...@@ -8819,7 +8861,8 @@ return new Parser;
}) })
.push(function (result) { .push(function (result) {
status_hash = result.hash; status_hash = result.hash;
return checkAndPropagateAttachment(skip_attachment_dict, return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, null, null, status_hash, null, null,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8827,24 +8870,13 @@ return new Parser; ...@@ -8827,24 +8870,13 @@ return new Parser;
}); });
} }
function pushDocumentAttachment(skip_attachment_dict, id, source, function pushDocumentAttachment(context,
destination, options) { skip_attachment_dict, id, source,
var queue = new RSVP.Queue(), destination, signature_allAttachments,
local_dict = {}, options) {
var local_dict = {},
signature_dict = {}; signature_dict = {};
return source.allAttachments(id)
return queue
.push(function () {
return RSVP.all([
source.allAttachments(id)
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
}),
context._signature_sub_storage.allAttachments(id)
.push(undefined, function (error) { .push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) && if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) { (error.status_code === 404)) {
...@@ -8852,22 +8884,20 @@ return new Parser; ...@@ -8852,22 +8884,20 @@ return new Parser;
} }
throw error; throw error;
}) })
]); .push(function (source_allAttachments) {
})
.push(function (result_list) {
var is_modification, var is_modification,
is_creation, is_creation,
key, key,
argument_list = []; argument_list = [];
for (key in result_list[0]) { for (key in source_allAttachments) {
if (result_list[0].hasOwnProperty(key)) { if (source_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) { if (!skip_attachment_dict.hasOwnProperty(key)) {
local_dict[key] = null; local_dict[key] = null;
} }
} }
} }
for (key in result_list[1]) { for (key in signature_allAttachments) {
if (result_list[1].hasOwnProperty(key)) { if (signature_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) { if (!skip_attachment_dict.hasOwnProperty(key)) {
signature_dict[key] = null; signature_dict[key] = null;
} }
...@@ -8882,6 +8912,7 @@ return new Parser; ...@@ -8882,6 +8912,7 @@ return new Parser;
&& options.check_creation; && options.check_creation;
if (is_modification === true || is_creation === true) { if (is_modification === true || is_creation === true) {
argument_list.push([undefined, argument_list.push([undefined,
context,
skip_attachment_dict, skip_attachment_dict,
source, source,
destination, id, key, destination, id, key,
...@@ -8894,6 +8925,7 @@ return new Parser; ...@@ -8894,6 +8925,7 @@ return new Parser;
} }
} }
return dispatchQueue( return dispatchQueue(
context,
checkAttachmentSignatureDifference, checkAttachmentSignatureDifference,
argument_list, argument_list,
context._parallel_operation_attachment_amount context._parallel_operation_attachment_amount
...@@ -8906,6 +8938,7 @@ return new Parser; ...@@ -8906,6 +8938,7 @@ return new Parser;
if (signature_dict.hasOwnProperty(key)) { if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) { if (!local_dict.hasOwnProperty(key)) {
argument_list.push([undefined, argument_list.push([undefined,
context,
skip_attachment_dict, skip_attachment_dict,
destination, id, key, destination, id, key,
source, source,
...@@ -8916,6 +8949,7 @@ return new Parser; ...@@ -8916,6 +8949,7 @@ return new Parser;
} }
} }
return dispatchQueue( return dispatchQueue(
context,
checkAttachmentLocalDeletion, checkAttachmentLocalDeletion,
argument_list, argument_list,
context._parallel_operation_attachment_amount context._parallel_operation_attachment_amount
...@@ -8924,19 +8958,38 @@ return new Parser; ...@@ -8924,19 +8958,38 @@ return new Parser;
}); });
} }
function repairDocumentAttachment(context, id) {
function repairDocumentAttachment(id) {
var skip_attachment_dict = {}; var skip_attachment_dict = {};
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if (context._check_local_attachment_modification ||
context._check_local_attachment_creation ||
context._check_local_attachment_deletion ||
context._check_remote_attachment_modification ||
context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) {
return context._signature_sub_storage.allAttachments(id);
}
return {};
})
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
})
.push(function (signature_allAttachments) {
if (context._check_local_attachment_modification || if (context._check_local_attachment_modification ||
context._check_local_attachment_creation || context._check_local_attachment_creation ||
context._check_local_attachment_deletion) { context._check_local_attachment_deletion) {
return pushDocumentAttachment( return pushDocumentAttachment(
context,
skip_attachment_dict, skip_attachment_dict,
id, id,
context._local_sub_storage, context._local_sub_storage,
context._remote_sub_storage, context._remote_sub_storage,
signature_allAttachments,
{ {
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_LOCAL), CONFLICT_KEEP_LOCAL),
...@@ -8949,18 +9002,24 @@ return new Parser; ...@@ -8949,18 +9002,24 @@ return new Parser;
check_creation: context._check_local_attachment_creation, check_creation: context._check_local_attachment_creation,
check_deletion: context._check_local_attachment_deletion check_deletion: context._check_local_attachment_deletion
} }
); )
.push(function () {
return signature_allAttachments;
});
} }
return signature_allAttachments;
}) })
.push(function () { .push(function (signature_allAttachments) {
if (context._check_remote_attachment_modification || if (context._check_remote_attachment_modification ||
context._check_remote_attachment_creation || context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) { context._check_remote_attachment_deletion) {
return pushDocumentAttachment( return pushDocumentAttachment(
context,
skip_attachment_dict, skip_attachment_dict,
id, id,
context._remote_sub_storage, context._remote_sub_storage,
context._local_sub_storage, context._local_sub_storage,
signature_allAttachments,
{ {
use_revert_post: context._use_remote_post, use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
...@@ -8979,16 +9038,35 @@ return new Parser; ...@@ -8979,16 +9038,35 @@ return new Parser;
}); });
} }
function propagateModification(source, destination, doc, hash, id, function propagateModification(context, source, destination, doc, hash, id,
skip_document_dict,
options) { options) {
var result, var result = new RSVP.Queue(),
post_id, post_id,
to_skip = true; to_skip = true;
if (options === undefined) { if (options === undefined) {
options = {}; options = {};
} }
if (doc === null) {
result
.push(function () {
return source.get(id);
})
.push(function (source_doc) {
doc = source_doc;
}, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
throw new SkipError(id);
}
throw error;
});
}
if (options.use_post) { if (options.use_post) {
result = destination.post(doc) result
.push(function () {
return destination.post(doc);
})
.push(function (new_id) { .push(function (new_id) {
to_skip = false; to_skip = false;
post_id = new_id; post_id = new_id;
...@@ -9037,7 +9115,17 @@ return new Parser; ...@@ -9037,7 +9115,17 @@ return new Parser;
skip_document_dict[post_id] = null; skip_document_dict[post_id] = null;
}); });
} else { } else {
result = destination.put(id, doc) result
.push(function () {
// Drop signature if the destination document was empty
// but a signature exists
if (options.create_new_document === true) {
return context._signature_sub_storage.remove(id);
}
})
.push(function () {
return destination.put(id, doc);
})
.push(function () { .push(function () {
return context._signature_sub_storage.put(id, { return context._signature_sub_storage.put(id, {
"hash": hash "hash": hash
...@@ -9049,15 +9137,21 @@ return new Parser; ...@@ -9049,15 +9137,21 @@ return new Parser;
if (to_skip) { if (to_skip) {
skip_document_dict[id] = null; skip_document_dict[id] = null;
} }
})
.push(undefined, function (error) {
if (error instanceof SkipError) {
return;
}
throw error;
}); });
} }
function propagateDeletion(destination, id) { function propagateDeletion(context, destination, id, skip_document_dict) {
// Do not delete a document if it has an attachment // Do not delete a document if it has an attachment
// ie, replication should prevent losing user data // ie, replication should prevent losing user data
// Synchronize attachments before, to ensure // Synchronize attachments before, to ensure
// all of them will be deleted too // all of them will be deleted too
return repairDocumentAttachment(id) return repairDocumentAttachment(context, id)
.push(function () { .push(function () {
return destination.allAttachments(id); return destination.allAttachments(id);
}) })
...@@ -9080,11 +9174,25 @@ return new Parser; ...@@ -9080,11 +9174,25 @@ return new Parser;
}); });
} }
function checkAndPropagate(status_hash, local_hash, doc, function checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
options) { options) {
return new RSVP.Queue()
.push(function () {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
}
return destination.get(id) return destination.get(id)
.push(function (remote_doc) { .push(function (remote_doc) {
return [remote_doc, generateHash(stringify(remote_doc))]; return [remote_doc, generateHash(stringify(remote_doc))];
...@@ -9094,11 +9202,12 @@ return new Parser; ...@@ -9094,11 +9202,12 @@ return new Parser;
return [null, null]; return [null, null];
} }
throw error; throw error;
});
}) })
.push(function (remote_list) { .push(function (remote_list) {
var remote_doc = remote_list[0], var remote_doc = remote_list[0],
remote_hash = remote_list[1]; remote_hash = remote_list[1];
if (local_hash === remote_hash) { if (local_hash === remote_hash) {
// Same modifications on both side // Same modifications on both side
if (local_hash === null) { if (local_hash === null) {
...@@ -9121,12 +9230,17 @@ return new Parser; ...@@ -9121,12 +9230,17 @@ return new Parser;
// Modified only locally. No conflict or force // Modified only locally. No conflict or force
if (local_hash === null) { if (local_hash === null) {
// Deleted locally // Deleted locally
return propagateDeletion(destination, id); return propagateDeletion(context, destination, id,
skip_document_dict);
} }
return propagateModification(source, destination, doc, return propagateModification(context, source, destination, doc,
local_hash, id, local_hash, id, skip_document_dict,
{use_post: ((options.use_post) && {use_post: ((options.use_post) &&
(remote_hash === null))}); (remote_hash === null)),
create_new_document:
((remote_hash === null) &&
(status_hash !== null))
});
} }
// Conflict cases // Conflict cases
...@@ -9138,34 +9252,44 @@ return new Parser; ...@@ -9138,34 +9252,44 @@ return new Parser;
// Automatically resolve conflict or force revert // Automatically resolve conflict or force revert
if (remote_hash === null) { if (remote_hash === null) {
// Deleted remotely // Deleted remotely
return propagateDeletion(source, id); return propagateDeletion(context, source, id, skip_document_dict);
} }
return propagateModification( return propagateModification(
context,
destination, destination,
source, source,
remote_doc, remote_doc,
remote_hash, remote_hash,
id, id,
skip_document_dict,
{use_post: ((options.use_revert_post) && {use_post: ((options.use_revert_post) &&
(local_hash === null))} (local_hash === null)),
create_new_document: ((local_hash === null) &&
(status_hash !== null))}
); );
} }
// Minimize conflict if it can be resolved // Minimize conflict if it can be resolved
if (remote_hash === null) { if (remote_hash === null) {
// Copy remote modification remotely // Copy remote modification remotely
return propagateModification(source, destination, doc, return propagateModification(context, source, destination, doc,
local_hash, id, local_hash, id, skip_document_dict,
{use_post: options.use_post}); {use_post: options.use_post,
} create_new_document:
(status_hash !== null)});
}
doc = doc || local_hash;
remote_doc = remote_doc || remote_hash;
throw new jIO.util.jIOError("Conflict on '" + id + "': " + throw new jIO.util.jIOError("Conflict on '" + id + "': " +
stringify(doc || '') + " !== " + stringify(doc) + " !== " +
stringify(remote_doc || ''), stringify(remote_doc),
409); 409);
}); });
} }
function checkLocalDeletion(queue, destination, id, source, function checkLocalDeletion(queue, context, skip_document_dict,
cache, destination_key,
destination, id, source,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, options) { conflict_ignore, options) {
var status_hash; var status_hash;
...@@ -9175,7 +9299,9 @@ return new Parser; ...@@ -9175,7 +9299,9 @@ return new Parser;
}) })
.push(function (result) { .push(function (result) {
status_hash = result.hash; status_hash = result.hash;
return checkAndPropagate(status_hash, null, null, return checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, null, null,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
...@@ -9183,37 +9309,31 @@ return new Parser; ...@@ -9183,37 +9309,31 @@ return new Parser;
}); });
} }
function checkSignatureDifference(queue, source, destination, id, function checkSignatureDifference(queue, context, skip_document_dict,
cache, destination_key,
source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
is_creation, is_modification, local_hash, status_hash,
getMethod, options) { options) {
queue queue
.push(function () { .push(function () {
// Optimisation to save a get call to signature storage if (local_hash === null) {
if (is_creation === true) { // Hash was not provided by the allDocs query
return RSVP.all([ return source.get(id);
getMethod(id),
{hash: null}
]);
}
if (is_modification === true) {
return RSVP.all([
getMethod(id),
context._signature_sub_storage.get(id)
]);
} }
throw new jIO.util.jIOError("Unexpected call of" return null;
+ " checkSignatureDifference",
409);
}) })
.push(function (result_list) { .push(function (doc) {
var doc = result_list[0], if (local_hash === null) {
local_hash = generateHash(stringify(doc)), // Hash was not provided by the allDocs query
status_hash = result_list[1].hash; local_hash = generateHash(stringify(doc));
}
if (local_hash !== status_hash) { if (local_hash !== status_hash) {
return checkAndPropagate(status_hash, local_hash, doc, return checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
...@@ -9222,47 +9342,11 @@ return new Parser; ...@@ -9222,47 +9342,11 @@ return new Parser;
}); });
} }
function checkBulkSignatureDifference(queue, source, destination, id_list, function pushStorage(context, skip_document_dict,
document_status_list, options, skip_deleted_document_dict,
conflict_force, conflict_revert, cache, source_key, destination_key,
conflict_ignore) { source, destination, signature_allDocs, options) {
queue var argument_list = [],
.push(function () {
return source.bulk(id_list);
})
.push(function (result_list) {
var i,
argument_list = [];
function getResult(j) {
return function (id) {
if (id !== id_list[j].parameter_list[0]) {
throw new Error("Does not access expected ID " + id);
}
return result_list[j];
};
}
for (i = 0; i < result_list.length; i += 1) {
argument_list[i] = [undefined, source, destination,
id_list[i].parameter_list[0],
conflict_force, conflict_revert,
conflict_ignore,
document_status_list[i].is_creation,
document_status_list[i].is_modification,
getResult(i), options];
}
return dispatchQueue(
checkSignatureDifference,
argument_list,
options.operation_amount
);
});
}
function pushStorage(source, destination, options) {
var queue = new RSVP.Queue(),
argument_list = [],
argument_list_deletion = []; argument_list_deletion = [];
if (!options.hasOwnProperty("use_post")) { if (!options.hasOwnProperty("use_post")) {
options.use_post = false; options.use_post = false;
...@@ -9270,127 +9354,155 @@ return new Parser; ...@@ -9270,127 +9354,155 @@ return new Parser;
if (!options.hasOwnProperty("use_revert_post")) { if (!options.hasOwnProperty("use_revert_post")) {
options.use_revert_post = false; options.use_revert_post = false;
} }
return queue return callAllDocsOnStorage(context, source, cache, source_key)
.push(function () { .push(function (source_allDocs) {
return RSVP.all([
source.allDocs(context._query_options),
context._signature_sub_storage.allDocs()
]);
})
.push(function (result_list) {
var i, var i,
local_dict = {}, local_dict = {},
document_list = [],
document_status_list = [],
signature_dict = {}, signature_dict = {},
is_modification, is_modification,
is_creation, is_creation,
key; status_hash,
for (i = 0; i < result_list[0].data.total_rows; i += 1) { local_hash,
key,
queue = new RSVP.Queue();
for (key in source_allDocs) {
if (source_allDocs.hasOwnProperty(key)) {
if (!skip_document_dict.hasOwnProperty(key)) {
local_dict[key] = source_allDocs[key];
}
}
}
/*
for (i = 0; i < source_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty( if (!skip_document_dict.hasOwnProperty(
result_list[0].data.rows[i].id source_allDocs.data.rows[i].id
)) { )) {
local_dict[result_list[0].data.rows[i].id] = i; local_dict[source_allDocs.data.rows[i].id] =
source_allDocs.data.rows[i].value;
} }
} }
for (i = 0; i < result_list[1].data.total_rows; i += 1) { */
for (i = 0; i < signature_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty( if (!skip_document_dict.hasOwnProperty(
result_list[1].data.rows[i].id signature_allDocs.data.rows[i].id
)) { )) {
signature_dict[result_list[1].data.rows[i].id] = i; signature_dict[signature_allDocs.data.rows[i].id] =
signature_allDocs.data.rows[i].value.hash;
} }
} }
i = 0;
for (key in local_dict) { for (key in local_dict) {
if (local_dict.hasOwnProperty(key)) { if (local_dict.hasOwnProperty(key)) {
is_modification = signature_dict.hasOwnProperty(key) is_modification = signature_dict.hasOwnProperty(key)
&& options.check_modification; && options.check_modification;
is_creation = !signature_dict.hasOwnProperty(key) is_creation = !signature_dict.hasOwnProperty(key)
&& options.check_creation; && options.check_creation;
if (is_creation === true) {
status_hash = null;
} else if (is_modification === true) {
status_hash = signature_dict[key];
}
local_hash = null;
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
is_modification = false;
if (local_hash !== status_hash) {
is_modification = true;
}
}
}
if (is_modification === true || is_creation === true) { if (is_modification === true || is_creation === true) {
if (options.use_bulk_get === true) { argument_list.push([undefined, context, skip_document_dict,
document_list.push({ cache, destination_key,
method: "get", source, destination,
parameter_list: [key]
});
document_status_list.push({
is_creation: is_creation,
is_modification: is_modification
});
} else {
argument_list[i] = [undefined, source, destination,
key, key,
options.conflict_force, options.conflict_force,
options.conflict_revert, options.conflict_revert,
options.conflict_ignore, options.conflict_ignore,
is_creation, is_modification, local_hash, status_hash,
source.get.bind(source), options]);
options];
i += 1;
}
} }
} }
} }
queue queue
.push(function () { .push(function () {
return dispatchQueue( return dispatchQueue(
context,
checkSignatureDifference, checkSignatureDifference,
argument_list, argument_list,
options.operation_amount options.operation_amount
); );
}); });
if (options.check_deletion === true) {
i = 0;
for (key in signature_dict) { for (key in signature_dict) {
if (signature_dict.hasOwnProperty(key)) { if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) { if (!local_dict.hasOwnProperty(key)) {
argument_list_deletion[i] = [undefined, if (options.check_deletion === true) {
argument_list_deletion.push([undefined,
context,
skip_document_dict,
cache, destination_key,
destination, key, destination, key,
source, source,
options.conflict_force, options.conflict_force,
options.conflict_revert, options.conflict_revert,
options.conflict_ignore, options.conflict_ignore,
options]; options]);
i += 1; } else {
skip_deleted_document_dict[key] = null;
} }
} }
} }
}
if (argument_list_deletion.length !== 0) {
queue.push(function () { queue.push(function () {
return dispatchQueue( return dispatchQueue(
context,
checkLocalDeletion, checkLocalDeletion,
argument_list_deletion, argument_list_deletion,
options.operation_amount options.operation_amount
); );
}); });
} }
if ((options.use_bulk_get === true) && (document_list.length !== 0)) { return queue;
checkBulkSignatureDifference(queue, source, destination,
document_list, document_status_list,
options,
options.conflict_force,
options.conflict_revert,
options.conflict_ignore);
}
}); });
} }
function repairDocument(queue, id) { function repairDocument(queue, context, id) {
queue.push(function () { queue.push(function () {
return repairDocumentAttachment(id); return repairDocumentAttachment(context, id);
}); });
} }
ReplicateStorage.prototype.repair = function () {
var context = this,
argument_list = arguments,
skip_document_dict = {},
skip_deleted_document_dict = {},
cache = {};
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
// Ensure that the document storage is usable // Ensure that the document storage is usable
return context._signature_sub_storage.__storage._sub_storage.get( if (context._custom_signature_sub_storage === false) {
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.get(
context._signature_hash context._signature_hash
); );
}
}) })
.push(undefined, function (error) { .push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) && if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) { (error.status_code === 404)) {
return context._signature_sub_storage.__storage._sub_storage.put( return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.put(
context._signature_hash, context._signature_hash,
{} {}
); );
...@@ -9417,11 +9529,28 @@ return new Parser; ...@@ -9417,11 +9529,28 @@ return new Parser;
}) })
.push(function () { .push(function () {
if (context._check_local_modification ||
context._check_local_creation ||
context._check_local_deletion ||
context._check_remote_modification ||
context._check_remote_creation ||
context._check_remote_deletion) {
return context._signature_sub_storage.allDocs({
select_list: ['hash']
});
}
})
.push(function (signature_allDocs) {
if (context._check_local_modification || if (context._check_local_modification ||
context._check_local_creation || context._check_local_creation ||
context._check_local_deletion) { context._check_local_deletion) {
return pushStorage(context._local_sub_storage, return pushStorage(context, skip_document_dict,
skip_deleted_document_dict,
cache, 'local', 'remote',
context._local_sub_storage,
context._remote_sub_storage, context._remote_sub_storage,
signature_allDocs,
{ {
use_post: context._use_remote_post, use_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
...@@ -9433,28 +9562,25 @@ return new Parser; ...@@ -9433,28 +9562,25 @@ return new Parser;
check_modification: context._check_local_modification, check_modification: context._check_local_modification,
check_creation: context._check_local_creation, check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion, check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount operation_amount: context._parallel_operation_amount,
}); signature_hash_key: context._signature_hash_key
}
}) })
.push(function () { .push(function () {
// Autoactivate bulk if substorage implements it return signature_allDocs;
// Keep it like this until the bulk API is stabilized });
var use_bulk_get = false;
try {
use_bulk_get = context._remote_sub_storage.hasCapacity("bulk_get");
} catch (error) {
if (!((error instanceof jIO.util.jIOError) &&
(error.status_code === 501))) {
throw error;
}
} }
return signature_allDocs;
})
.push(function (signature_allDocs) {
if (context._check_remote_modification || if (context._check_remote_modification ||
context._check_remote_creation || context._check_remote_creation ||
context._check_remote_deletion) { context._check_remote_deletion) {
return pushStorage(context._remote_sub_storage, return pushStorage(context, skip_document_dict,
context._local_sub_storage, { skip_deleted_document_dict,
use_bulk_get: use_bulk_get, cache, 'remote', 'local',
context._remote_sub_storage,
context._local_sub_storage,
signature_allDocs, {
use_revert_post: context._use_remote_post, use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_REMOTE), CONFLICT_KEEP_REMOTE),
...@@ -9465,7 +9591,8 @@ return new Parser; ...@@ -9465,7 +9591,8 @@ return new Parser;
check_modification: context._check_remote_modification, check_modification: context._check_remote_modification,
check_creation: context._check_remote_creation, check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion, check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount operation_amount: context._parallel_operation_amount,
signature_hash_key: context._signature_hash_key
}); });
} }
}) })
...@@ -9481,17 +9608,25 @@ return new Parser; ...@@ -9481,17 +9608,25 @@ return new Parser;
return context._signature_sub_storage.allDocs() return context._signature_sub_storage.allDocs()
.push(function (result) { .push(function (result) {
var i, var i,
argument_list = [], local_argument_list = [],
id,
len = result.data.total_rows; len = result.data.total_rows;
for (i = 0; i < len; i += 1) { for (i = 0; i < len; i += 1) {
argument_list.push( id = result.data.rows[i].id;
[undefined, result.data.rows[i].id] // Do not synchronize attachment if one version of the document
// is deleted but not pushed to the other storage
if (!skip_deleted_document_dict.hasOwnProperty(id) ||
skip_document_dict.hasOwnProperty(id)) {
local_argument_list.push(
[undefined, context, id]
); );
} }
}
return dispatchQueue( return dispatchQueue(
context,
repairDocument, repairDocument,
argument_list, local_argument_list,
context._parallel_operation_amount context._parallel_operation_amount
); );
}); });
...@@ -11154,56 +11289,6 @@ return new Parser; ...@@ -11154,56 +11289,6 @@ return new Parser;
}); });
}; };
ERP5Storage.prototype.bulk = function (request_list) {
var i,
storage = this,
bulk_list = [];
for (i = 0; i < request_list.length; i += 1) {
if (request_list[i].method !== "get") {
throw new Error("ERP5Storage: not supported " +
request_list[i].method + " in bulk");
}
bulk_list.push({
relative_url: request_list[i].parameter_list[0],
view: storage._default_view_reference
});
}
return getSiteDocument(storage)
.push(function (site_hal) {
var form_data = new FormData();
form_data.append("bulk_list", JSON.stringify(bulk_list));
return jIO.util.ajax({
"type": "POST",
"url": site_hal._actions.bulk.href,
"data": form_data,
// "headers": {
// "Content-Type": "application/json"
// },
"xhrFields": {
withCredentials: true
}
});
})
.push(function (response) {
var result_list = [],
hateoas = JSON.parse(response.target.responseText);
function pushResult(json) {
return extractPropertyFromFormJSON(json)
.push(function (json2) {
return convertJSONToGet(json2);
});
}
for (i = 0; i < hateoas.result_list.length; i += 1) {
result_list.push(pushResult(hateoas.result_list[i]));
}
return RSVP.all(result_list);
});
};
ERP5Storage.prototype.post = function (data) { ERP5Storage.prototype.post = function (data) {
var context = this, var context = this,
new_id; new_id;
...@@ -11430,7 +11515,7 @@ return new Parser; ...@@ -11430,7 +11515,7 @@ return new Parser;
ERP5Storage.prototype.hasCapacity = function (name) { ERP5Storage.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query") || return ((name === "list") || (name === "query") ||
(name === "select") || (name === "limit") || (name === "select") || (name === "limit") ||
(name === "sort")) || (name === "bulk_get"); (name === "sort"));
}; };
function isSingleLocalRoles(parsed_query) { function isSingleLocalRoles(parsed_query) {
...@@ -12588,14 +12673,18 @@ return new Parser; ...@@ -12588,14 +12673,18 @@ return new Parser;
}); });
}; };
function handleGet(request, resolve, reject) { function handleGet(store, id, resolve, reject) {
var request = store.get(id);
request.onerror = reject; request.onerror = reject;
request.onsuccess = function () { request.onsuccess = function () {
if (request.result) { if (request.result) {
resolve(request.result); resolve(request.result);
} else { } else {
// XXX How to get ID reject(new jIO.util.jIOError(
reject(new jIO.util.jIOError("Cannot find document", 404)); "IndexedDB: cannot find object '" + id + "' in the '" +
store.name + "' store",
404
));
} }
}; };
} }
...@@ -12606,7 +12695,8 @@ return new Parser; ...@@ -12606,7 +12695,8 @@ return new Parser;
return new RSVP.Promise(function (resolve, reject) { return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata"], "readonly"); var transaction = openTransaction(db, ["metadata"], "readonly");
handleGet( handleGet(
transaction.objectStore("metadata").get(id), transaction.objectStore("metadata"),
id,
resolve, resolve,
reject reject
); );
...@@ -12639,7 +12729,8 @@ return new Parser; ...@@ -12639,7 +12729,8 @@ return new Parser;
); );
} }
handleGet( handleGet(
transaction.objectStore("metadata").get(id), transaction.objectStore("metadata"),
id,
getAttachments, getAttachments,
reject reject
); );
...@@ -12767,7 +12858,8 @@ return new Parser; ...@@ -12767,7 +12858,8 @@ return new Parser;
result_list.push(result); result_list.push(result);
} }
i += 1; i += 1;
handleGet(store.get(buildKeyPath([id, name, i])), handleGet(store,
buildKeyPath([id, name, i]),
(i <= end_index) ? getPart(i) : resolver, (i <= end_index) ? getPart(i) : resolver,
reject reject
); );
...@@ -12776,8 +12868,8 @@ return new Parser; ...@@ -12776,8 +12868,8 @@ return new Parser;
getPart(start_index - 1)(); getPart(start_index - 1)();
} }
// XXX Should raise if key is not good // XXX Should raise if key is not good
handleGet(transaction.objectStore("attachment") handleGet(transaction.objectStore("attachment"),
.get(buildKeyPath([id, name])), buildKeyPath([id, name]),
getBlob, getBlob,
reject reject
); );
...@@ -13007,12 +13099,12 @@ return new Parser; ...@@ -13007,12 +13099,12 @@ return new Parser;
}) })
.push(function (dataURL) { .push(function (dataURL) {
//string->arraybuffer //string->arraybuffer
var strLen = dataURL.currentTarget.result.length, var strLen = dataURL.target.result.length,
buf = new ArrayBuffer(strLen), buf = new ArrayBuffer(strLen),
bufView = new Uint8Array(buf), bufView = new Uint8Array(buf),
i; i;
dataURL = dataURL.currentTarget.result; dataURL = dataURL.target.result;
for (i = 0; i < strLen; i += 1) { for (i = 0; i < strLen; i += 1) {
bufView[i] = dataURL.charCodeAt(i); bufView[i] = dataURL.charCodeAt(i);
} }
...@@ -13049,7 +13141,7 @@ return new Parser; ...@@ -13049,7 +13141,7 @@ return new Parser;
.push(function (coded) { .push(function (coded) {
var initializaton_vector; var initializaton_vector;
coded = coded.currentTarget.result; coded = coded.target.result;
initializaton_vector = new Uint8Array(coded.slice(0, 12)); initializaton_vector = new Uint8Array(coded.slice(0, 12));
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
...@@ -13268,7 +13360,7 @@ return new Parser; ...@@ -13268,7 +13360,7 @@ return new Parser;
return jIO.util.readBlobAsDataURL(blob); return jIO.util.readBlobAsDataURL(blob);
}) })
.push(function (strBlob) { .push(function (strBlob) {
argument_list[index + 2].push(strBlob.currentTarget.result); argument_list[index + 2].push(strBlob.target.result);
return; return;
}); });
} }
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>959.8888.26905.39645</string> </value> <value> <string>960.25571.62873.4317</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1494334109.43</float> <float>1499172288.9</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
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