/*jslint indent: 2 nomen: true */ /*global jIO, RSVP, DOMParser, Rusha, Blob, console, btoa, URLSearchParams */ (function (jIO, RSVP, DOMParser, Rusha, Blob, console, btoa, URLSearchParams) { "use strict"; var rusha = new Rusha(), mock_test = true, OPML_ATTACHMENT_NAME = "__opml__", PROMISE_TYPE = "Promise", SOFTWARE_INSTANCE_TYPE = "Software Instance", INSTANCE_TREE_TYPE = "Instance Tree", OPML_PORTAL_TYPE = "Opml", ZONE_LIST = [ "-1200", "-1100", "-1000", "-0900", "-0800", "-0700", "-0600", "-0500", "-0400", "-0300", "-0200", "-0100", "+0000", "+0100", "+0200", "+0300", "+0400", "+0500", "+0600", "+0700", "+0800", "+0900", "+1000", "+1100", "+1200" ]; function generateHash(str) { return rusha.digestFromString(str); } function createStorage(context, storage_spec, key) { var signature; signature = generateHash(JSON.stringify(storage_spec)); if (!context._remote_storage_dict.hasOwnProperty(key) || signature !== context._remote_storage_dict[key].signature) { context._remote_storage_dict[key] = { storage: jIO.createJIO(storage_spec), signature: signature }; } return context._remote_storage_dict[key].storage; } /** * The JIO OPML Tree Replicated Storage extension for monitor * * @class ReplicatedOPMLStorage * @constructor */ function ReplicatedOPMLStorage(spec) { if (typeof spec.type !== 'string') { throw new TypeError( "ReplicatedOPMLStorage 'type' is not a string" ); } if (spec.local_sub_storage === undefined) { throw new TypeError("ReplicatedOPMLStorage 'local_sub_storage' " + "is not defined"); } this._local_sub_storage = jIO.createJIO(spec.local_sub_storage); this._local_sub_storage_spec = spec.local_sub_storage; if (spec.remote_sub_storage !== undefined) { this._remote_sub_storage_spec = spec.remote_sub_storage; this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage); } this._remote_storage_unreachable_status = spec.remote_storage_unreachable_status; this._remote_storage_dict = {}; this._remote_parser_storage_type = spec.remote_parser_storage_type; if (this._remote_parser_storage_type === undefined) { this._remote_parser_storage_type = "parser"; } this._remote_opml_check_time_interval = spec.remote_opml_check_time_interval; if (this._remote_opml_check_time_interval === undefined) { // one day in miliseconds this._remote_opml_check_time_interval = 86400000; } this._request_timeout = spec.request_timeout; if (this._request_timeout === undefined) { this._request_timeout = 0; // no timeout } } ReplicatedOPMLStorage.prototype.get = function () { return this._local_sub_storage.get.apply(this._local_sub_storage, arguments); }; ReplicatedOPMLStorage.prototype.buildQuery = function () { return this._local_sub_storage.buildQuery.apply(this._local_sub_storage, arguments); }; ReplicatedOPMLStorage.prototype.put = function (id, doc) { //allow app configuration types (forms, views, actions, etc) /*if (!doc.hasOwnProperty('portal_type') || doc.portal_type !== 'opml') { throw new TypeError("Cannot put object which portal_type is not 'opml'"); }*/ if (doc.active === undefined) { doc.active = true; } return this._local_sub_storage.put(id, doc); }; ReplicatedOPMLStorage.prototype.hasCapacity = function (capacity) { var this_storage_not_capacity_list = ['post', 'getAttachment', 'putAttachment']; if (this_storage_not_capacity_list.indexOf(capacity) !== -1) { return false; } if (capacity === 'include') { return true; } return this._local_sub_storage.hasCapacity.apply(this._local_sub_storage, arguments); }; ReplicatedOPMLStorage.prototype.allAttachments = function () { return this._local_sub_storage.allAttachments.apply(this._local_sub_storage, arguments); }; ReplicatedOPMLStorage.prototype.remove = function (id) { //the removal of an opml involves to remove the full opml tree asociated //note: if the opml belongs to a slapos master, next sync will restore it var storage = this._local_sub_storage; return storage.get(id) .push(function (doc) { if (doc.portal_type !== OPML_PORTAL_TYPE) { return storage.remove(id); } function removeOPMLTree(url) { var remove_id_list = [], remove_signature_id_list = []; // remove related instance tree remove_id_list.push(generateHash(id)); // removed saved opml content remove_signature_id_list.push({ id: url, name: url }); // remove all related documents return storage.allDocs({ select_list: ["xmlUrl", "url"], query: '(portal_type:"Opml Outline") AND (parent_url:"' + url + '")' }) .push(function (document_result) { var i, query_list = []; for (i = 0; i < document_result.data.total_rows; i += 1) { query_list.push('(parent_id:"' + document_result.data.rows[i].id + '")'); remove_id_list.push(document_result.data.rows[i].id); remove_signature_id_list.push({ id: document_result.data.rows[i].id, name: document_result.data.rows[i].value.xmlUrl }); remove_signature_id_list.push({ id: document_result.data.rows[i].id, name: document_result.data.rows[i].value.url }); } // cleanup all sub opml items if (query_list.length > 0) { return storage.allDocs({query: query_list.join(" OR ")}); } return {data: {total_rows: 0}}; }) .push(function (sub_item_result) { var j, i, k, remove_queue = new RSVP.Queue(); function removeItem(key) { remove_queue .push(function () { return storage.remove(key); }); } function removeAttachmentItem(id, name) { remove_queue .push(function () { return storage.removeAttachment(id, name); }) .push(undefined, function (error) { if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) { return undefined; } throw error; }); } // remove signatures for (k = 0; k < remove_signature_id_list.length; k += 1) { removeAttachmentItem( remove_signature_id_list[k].id, remove_signature_id_list[k].name ); } // remove opml-outline sub-items (rss) for (j = 0; j < sub_item_result.data.total_rows; j += 1) { removeItem(sub_item_result.data.rows[j].id); } // remove opml-outline for (i = 0; i < remove_id_list.length; i += 1) { removeItem(remove_id_list[i]); } return remove_queue; }) .push(function () { return storage.remove(url); }); } return removeOPMLTree(id); }); }; function getStorageUrl(storage_spec) { var spec = storage_spec; while (spec !== undefined) { if (spec.url !== undefined) { return spec.url; } if (spec.document_id !== undefined) { return spec.document_id; } spec = spec.sub_storage; } throw new Error("No url found on sub storage: " + JSON.stringify(storage_spec)); } function getDocumentAsAttachment(context, attachment_id, name) { return context._local_sub_storage.getAttachment(attachment_id, name) .push(undefined, function (error) { if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) { return undefined; } console.error(error); }) .push(function (attachment) { if (attachment) { return jIO.util.readBlobAsText(attachment) .then(function (evt) { return JSON.parse(evt.target.result); }); } return {}; }); } function fixGlobalInstanceDocument(instance) { // Fix some property as backed is old, to keep backward compatibility // XXX - this method should be removed when all backend will be upgraded if (instance._embedded !== undefined) { if (instance._embedded.instance !== undefined) { // set aggregate_reference to the computer reference and make it // searchable instance.aggregate_reference = instance._embedded.instance.computer; } if (instance._embedded.hasOwnProperty('promises')) { // remove useless information from the document delete instance._embedded.promises; } } if (instance.hasOwnProperty('hosting-title')) { // hosting-title should be specialise_title instance.specialise_title = instance['hosting-title']; delete instance['hosting-title']; } // set portal_type is not defined if (!instance.hasOwnProperty('portal_type')) { instance.portal_type = SOFTWARE_INSTANCE_TYPE; } return instance; } function updateSubStorageStatus(context, signature_dict, next_status) { var key, update_status_queue = new RSVP.Queue(); function updateStatus(id) { update_status_queue .push(function () { return context._local_sub_storage.get(id); }) .push(function (doc) { if (doc.portal_type === PROMISE_TYPE) { doc.category = next_status; return context._local_sub_storage.put(id, doc); } if (doc.status !== undefined) { doc.status = next_status; return context._local_sub_storage.put(id, doc); } }); } for (key in signature_dict) { if (signature_dict.hasOwnProperty(key)) { if (signature_dict[key].status !== next_status) { updateStatus(key); signature_dict[key].status = next_status; } } } return update_status_queue .push(function () { return signature_dict; }); } function loadSubStorage(context, storage_spec, parent_id, index, type) { var sub_storage, result_dict, storage_key, url; url = getStorageUrl(storage_spec); storage_key = generateHash(parent_id + url); sub_storage = createStorage(context, storage_spec, storage_key); result_dict = { parent_id: parent_id, type: type || storage_spec.type, current_signature: {}, result: {data: {total_rows: 0}}, url: url, parent_index: index }; return sub_storage.allDocs({include_docs: true}) .push(undefined, function (error) { //throw error; console.error("sub storage error:", error); return undefined; }) .push(function (result) { if (result === undefined) { if (context._remote_storage_unreachable_status !== undefined) { // update status of local documents // and set unreachable status return getDocumentAsAttachment(context, parent_id, url) .push(function (signature_document) { return updateSubStorageStatus( context, signature_document, context._remote_storage_unreachable_status ); }) .push(function (signature_dict) { return signature_dict; }); } return {}; } result_dict.result = result; return getDocumentAsAttachment( context, parent_id, url ); }) .push(function (signature_document) { result_dict.current_signature = signature_document; return result_dict; }); } function updateInstanceTreeState(hosting, element) { var status = element.status.toUpperCase(); if (hosting.instance_amount === 0) { hosting.status_date = fixDateTimezone(element.date); } if (hosting.status === "ERROR") { return; } else if (status === "ERROR") { hosting.status = status; } else if (status === "WARNING") { hosting.status = status; } if (status === "OK" && hosting.status !== status) { hosting.status = status; } } function fixDateTimezone(date_string) { // set default timezone offset to UTC // XXX should be removed later /*if (ZONE_LIST.indexOf(date_string.slice(-5)) === -1) { return date_string + "+0000"; }*/ return date_string; } function getOpmlTree(context, opml_url, opml_spec, basic_login, opml_title, slapos_master_url) { var opml_storage, opml_document_list = [], delete_key_list = [], attachment_document_list = [], opml_result_list, current_signature_dict = {}, fetch_remote_opml = false, instance_tree, id; id = generateHash(opml_url); opml_storage = createStorage(context, opml_spec, id); console.log("creating opml_storage with opml_url and opml_spec:", opml_url, opml_spec); // Instance Tree is build from OPML and it has status instance_tree = { title: opml_title || "", portal_type: INSTANCE_TREE_TYPE, opml_url: opml_url, status: "WARNING", instance_amount: 0, status_date: (new Date()).toUTCString() + "+0000", slapos_master_url: slapos_master_url }; return getDocumentAsAttachment(context, opml_url, OPML_ATTACHMENT_NAME) .push(function (opml_doc) { var current_time = new Date().getTime(); if (opml_doc.expire_time !== undefined) { fetch_remote_opml = (opml_doc.expire_time - current_time) < 0; } else { fetch_remote_opml = true; } if (fetch_remote_opml) { return opml_storage.allDocs({include_docs: true}) .push(undefined, function (error) { console.log("opml_storage.allDocs ERROR:", error); if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) { return {data: {total_rows: 0}}; } //throw error; console.error(error); return {data: {total_rows: 0}}; }) .push(function (opml_result) { if (opml_result.data.rows) { console.log("NO CORS error!"); } opml_result_list = opml_result; if (opml_result.data.total_rows > 0) { attachment_document_list.push({ id: opml_url, name: OPML_ATTACHMENT_NAME, doc: { expire_time: new Date().getTime() + context._remote_opml_check_time_interval, data: opml_result } }); return getDocumentAsAttachment( context, id, opml_url ); } return {}; }) .push(function (signature_dict) { current_signature_dict = signature_dict; }); } opml_result_list = opml_doc.data; }) .push(function () { var i, item, signature, doc_signature_dict = {}, skip_add = false, id_hash, result_list = [], header_dict = {}; if (opml_result_list.data.total_rows > 0) { if (opml_result_list.data.rows[0].doc.title) { instance_tree.title = opml_result_list.data.rows[0] .doc.title; } if (fetch_remote_opml) { header_dict = { dateCreated: opml_result_list.data.rows[0].doc.dateCreated, dateModified: opml_result_list.data.rows[0].doc.dateModified, opml_title: opml_result_list.data.rows[0].doc.title }; } } var iter = opml_result_list.data.total_rows; for (i = 1; i < iter; i += 1) { item = opml_result_list.data.rows[i]; if (item.doc.xmlUrl !== undefined) { id_hash = generateHash(id + item.id); result_list.push(loadSubStorage( context, { type: context._remote_parser_storage_type, document_id: item.doc.xmlUrl, attachment_id: 'enclosure', parser: 'rss', sub_storage: { type: "http", timeout: context._request_timeout } }, id_hash, i, PROMISE_TYPE )); // Load private docs if (item.doc.url !== undefined) { result_list.push(loadSubStorage( context, { type: 'webhttp', url: item.doc.url.replace('jio_private', 'private'), basic_login: basic_login, timeout: context._request_timeout }, id_hash, i )); } if (fetch_remote_opml) { // Append this document signature to the list signature = generateHash(JSON.stringify(item.doc)); doc_signature_dict[id_hash] = { signature: signature }; if (current_signature_dict.hasOwnProperty(id_hash)) { if (current_signature_dict[id_hash].signature === signature) { // remote document was not modified, delete and skip add delete current_signature_dict[id_hash]; skip_add = true; } delete current_signature_dict[id_hash]; } Object.assign(item.doc, { portal_type: "Opml Outline", parent_id: id, parent_url: opml_url, reference: id_hash, active: true, slapos_master_url: slapos_master_url }); Object.assign(item.doc, header_dict); if (!skip_add) { opml_document_list.push({ id: id_hash, doc: item.doc }); } } } } if (fetch_remote_opml && Object.keys(doc_signature_dict).length > 0) { attachment_document_list.push({ id: opml_url, name: opml_url, doc: doc_signature_dict }); delete_key_list.push.apply(delete_key_list, Object.keys(current_signature_dict)); } return RSVP.all(result_list); }) .push(function (result_list) { var i, j, start, extra_dict; function applyItemToTree(item, item_result, extra_dict) { var id_hash, element = item.doc, signature, item_id = item.guid || item.id, status = (element.status || element.category), item_signature_dict = {}; if (element.type === 'global') { updateInstanceTreeState(instance_tree, element); instance_tree.instance_amount += 1; if (element.aggregate_reference === undefined) { // XXX - document need to be updated to keep compatibility element = fixGlobalInstanceDocument(element); } // XXX - fixing date timezone element.date = fixDateTimezone(element.date); } // XXX - fixing date timezone if (element.pubDate !== undefined) { element.pubDate = fixDateTimezone(element.pubDate); } id_hash = generateHash(item_result.parent_id + item_result.url + item_id); if (extra_dict !== undefined) { Object.assign(element, extra_dict); } // Generating document signature signature = generateHash(JSON.stringify(element)); item_signature_dict[id_hash] = { signature: signature, status: status }; if (item_result.current_signature.hasOwnProperty(id_hash)) { if (item_result.current_signature[id_hash].signature === signature) { // the document was not modified return delete item_result.current_signature[id_hash]; return; } // the document exists and has changed delete item_result.current_signature[id_hash]; } Object.assign(element, { parent_id: item_result.parent_id, portal_type: element.portal_type || element.type || item_result.type, status: status, reference: element.reference || id_hash, active: true, slapos_master_url: slapos_master_url }); opml_document_list.push({ id: id_hash, doc: element }); attachment_document_list.push({ id: item_result.parent_id, name: item_result.url, doc: item_signature_dict }); } for (i = 0; i < result_list.length; i += 1) { extra_dict = undefined; start = 0; if (result_list[i].result.data.total_rows > 0) { if (result_list[i].type === PROMISE_TYPE) { // the first element of rss is the header extra_dict = { lastBuildDate: fixDateTimezone(result_list[i].result.data .rows[0].doc.lastBuildDate), channel: result_list[i].result.data.rows[0].doc.description, channel_item: result_list[i].result.data.rows[0].doc.title }; start = 1; } for (j = start; j < result_list[i].result.data.total_rows; j += 1) { applyItemToTree( result_list[i].result.data.rows[j], result_list[i], extra_dict ); } delete_key_list.push.apply( delete_key_list, Object.keys(result_list[i].current_signature) ); } else if (Object.keys(result_list[i].current_signature).length > 0) { // if the remote data is empty and current_signature is not empty, // push to storage in case the status was changed // this help for speed optimisation attachment_document_list.push({ id: result_list[i].parent_id, name: result_list[i].url, doc: result_list[i].current_signature }); } else if (context._remote_storage_unreachable_status !== undefined) { if (result_list[i].type === "webhttp") { // In case it was impossible to get software Instance // Add an empty Software Instance with unreachable status applyItemToTree( { id: "monitor.global", doc: { portal_type: SOFTWARE_INSTANCE_TYPE, status: context._remote_storage_unreachable_status, title: opml_result_list.data.rows[result_list[i] .parent_index].doc.title, date: new Date().toUTCString() + "+0000", specialise_title: opml_result_list.data.rows[result_list[i] .parent_index].doc.opml_title } }, result_list[i], undefined ); } } } opml_document_list.push({ id: id, doc: instance_tree }); return [opml_document_list, delete_key_list, attachment_document_list]; }); } function pushDocumentToStorage(context, document_list, delete_key_list, attachment_document_list) { var document_queue = new RSVP.Queue(), i; function pushDocument(id, element) { document_queue .push(function () { return context._local_sub_storage.put(id, element); }); } for (i = 0; i < document_list.length; i += 1) { pushDocument( document_list[i].id, document_list[i].doc ); } return document_queue .push(function () { var k, remove_queue = new RSVP.Queue(); // remove all document which were not updated function removeDocument(key) { remove_queue .push(function () { return context._local_sub_storage.remove(key); }) .push(undefined, function (error) { if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) { return {}; } throw error; }); } for (k = 0; k < delete_key_list.length; k += 1) { removeDocument(delete_key_list[k]); } return remove_queue; }) .push(function () { var j, signature_queue = new RSVP.Queue(); function pushAttachment(id, name, element) { signature_queue .push(function () { return context._local_sub_storage.putAttachment( id, name, new Blob([JSON.stringify(element)], {type : 'application/json'}) ); }) .push(undefined, function (error) { console.error(error); }); } for (j = 0; j < attachment_document_list.length; j += 1) { pushAttachment( attachment_document_list[j].id, attachment_document_list[j].name, attachment_document_list[j].doc ); } }); } function syncOpmlStorage(context) { return context._local_sub_storage.allDocs({ query: '(portal_type:"' + OPML_PORTAL_TYPE + '") AND (active:true) AND (url:"https://%")', select_list: ["title", "url", "basic_login", "slapos_master_url"] }) .push(function (storage_result) { var i, opml_queue = new RSVP.Queue(); function syncFullOpml(storage_spec) { opml_queue .push(function () { return getOpmlTree( context, storage_spec.url, { type: context._remote_parser_storage_type, document_id: storage_spec.url, attachment_id: 'enclosure', parser: 'opml', sub_storage: { type: "http", timeout: context._request_timeout } }, storage_spec.basic_login, storage_spec.title, storage_spec.slapos_master_url ); }) .push(function (result_list) { return pushDocumentToStorage( context, result_list[0], result_list[1], result_list[2] ); }); } for (i = 0; i < storage_result.data.total_rows; i += 1) { syncFullOpml(storage_result.data.rows[i].value); } return opml_queue; }); } ReplicatedOPMLStorage.prototype.repair = function () { var context = this, has_failed = false, error_msg = "", argument_list = arguments; function getParameterDictFromUrl(uri_param) { if (uri_param.has('url') && uri_param.has('password') && uri_param.has('username') && uri_param.get('url').startsWith('http')) { return { opml_url: uri_param.get('url').trim(), username: uri_param.get('username').trim(), password: uri_param.get('password').trim() }; } } function getParameterFromconnectionDict(connection_dict) { if (connection_dict["monitor-url"] && connection_dict["monitor-url"].startsWith('http') && connection_dict["monitor-user"] && connection_dict["monitor-password"]) { return { opml_url: connection_dict["monitor-url"].trim(), username: connection_dict["monitor-user"].trim(), password: connection_dict["monitor-password"].trim() }; } } function readMonitoringParameter(parmeter_xml) { var parser = new DOMParser(), xml_doc = parser.parseFromString(parmeter_xml, "text/xml"), parameter, uri_param, json_parameter, parameter_dict, monitor_dict = {}; json_parameter = xml_doc.getElementById("_"); if (json_parameter !== undefined && json_parameter !== null) { parameter_dict = JSON.parse(json_parameter.textContent); if (parameter_dict.hasOwnProperty("monitor-setup-url")) { return getParameterDictFromUrl( new URLSearchParams(parameter_dict["monitor-setup-url"]) ); } return getParameterFromconnectionDict(parameter_dict); } parameter = xml_doc.getElementById("monitor-setup-url"); if (parameter !== undefined && parameter !== null) { // monitor-setup-url exists uri_param = new URLSearchParams(parameter.textContent); return getParameterDictFromUrl(uri_param); } parameter = xml_doc.getElementById("monitor-url"); if (parameter !== undefined && parameter !== null) { monitor_dict.url = parameter.textContent.trim(); parameter = xml_doc.getElementById("monitor-user"); if (parameter === undefined && parameter !== null) { return; } monitor_dict.username = parameter.textContent.trim(); parameter = xml_doc.getElementById("monitor-password"); if (parameter === undefined && parameter !== null) { return; } monitor_dict.password = parameter.textContent.trim(); return monitor_dict; } } function getInstanceOPMLList(storage) { if (!storage) { return []; } var instance_tree_list = [], opml_list = [], uid_dict = {}; return storage.allDocs({ query: '(portal_type:"Instance Tree") AND (validation_state:"validated")', select_list: ['title', 'default_successor_uid', 'uid', 'slap_state', 'id'] }) .push(function (result) { if (mock_test) { result.data.total_rows = 1; result.data.rows = [result.data.rows[0]]; } var i, slapos_id, slapos_master_url = "", uid_search_list = []; for (i = 0; i < result.data.total_rows; i += 1) { if (result.data.rows[i].value.slap_state !== "destroy_requested") { //TODO could slapos_id be used to desambiguate identic title //instances trees between different storages? slapos_id = result.data.rows[i].value.title; if (result.data.rows[i].master_url) { slapos_master_url = result.data.rows[i].master_url; } instance_tree_list.push({ title: result.data.rows[i].value.title, relative_url: result.data.rows[i].id, slapos_id: slapos_id, slapos_master_url: slapos_master_url, active: (result.data.rows[i].value.slap_state === "start_requested") ? true : false, state: (result.data.rows[i].value.slap_state === "start_requested") ? "Started" : "Stopped" }); uid_search_list.push(result.data.rows[i].value.uid); if (result.data.rows[i].value.default_successor_uid) { uid_dict[result.data.rows[i].value.default_successor_uid] = i; } } } return storage.allDocs({ query: '(portal_type:"Software Instance") AND ' + '(successor_related_uid:("' + uid_search_list.join('","') + '"))', select_list: ['uid', 'successor_related_uid', 'connection_xml'] }); }) .push(function (result) { var i, tmp_parameter, tmp_uid, slapos_master_url = ""; for (i = 0; i < result.data.total_rows; i += 1) { tmp_uid = result.data.rows[i].value.uid; if (uid_dict.hasOwnProperty(tmp_uid)) { tmp_parameter = readMonitoringParameter(result.data.rows[i].value.connection_xml); if (tmp_parameter === undefined) { tmp_parameter = {username: "", password: "", opml_url: undefined}; } if (mock_test) { tmp_parameter.opml_url = "https://softinst238949.host.vifib.net/public/feeds"; tmp_parameter.password = "C1r796U05Z64QMyk"; //tmp_parameter.opml_url = "https://softinst239780.host.vifib.net/public/feeds"; //tmp_parameter.password = "07b17cifhSKxNdot"; tmp_parameter.username = "admin"; } if (instance_tree_list[uid_dict[tmp_uid]]) { if (result.data.rows[i].master_url) { slapos_master_url = result.data.rows[i].master_url; } opml_list.push({ portal_type: OPML_PORTAL_TYPE, title: instance_tree_list[uid_dict[tmp_uid]] .title, relative_url: instance_tree_list[uid_dict[tmp_uid]] .relative_url, url: tmp_parameter.opml_url || String(tmp_uid) + " NO MONITOR", has_monitor: tmp_parameter.opml_url !== undefined, username: tmp_parameter.username, password: tmp_parameter.password, basic_login: btoa(tmp_parameter.username + ':' + tmp_parameter.password), active: tmp_parameter.opml_url !== undefined && instance_tree_list[uid_dict[tmp_uid]].active, state: instance_tree_list[uid_dict[tmp_uid]].state, slapos_master_url: slapos_master_url }); } } } return opml_list; }); } function cleanOpmlStorage(context) { //TODO use slapos_master_url in the query instead of iterate later return context._local_sub_storage.allDocs({ query: '(portal_type:"' + OPML_PORTAL_TYPE + '")', select_list: ["title", "url", "basic_login", "slapos_master_url", "manually_added"] }) .push(function (result) { function removeAllOPML(remove_opml_list, jio) { var remove_queue = new RSVP.Queue(), i; function remove_opml(id) { remove_queue .push(function () { return jio.remove(id); }); } for (i = 0; i < remove_opml_list.length; i += 1) { remove_opml(remove_opml_list[i].id); } return remove_queue; } var slapos_master_url_list = [], spec_list = context._remote_sub_storage_spec.storage_list, i, remove_opml_list = [], opml_list = result.data.rows; if (spec_list) { for (i = 0; i < spec_list.length; i += 1) { if (spec_list[i].sub_storage && spec_list[i].sub_storage.url) { slapos_master_url_list.push(spec_list[i].sub_storage.url); } } } if (slapos_master_url_list.length > 0) { for (i = 0; i < opml_list.length; i += 1) { if (!opml_list[i].value.manually_added) { if (!slapos_master_url_list.includes(opml_list[i].value.slapos_master_url)) { remove_opml_list.push(opml_list[i]); } } } } return RSVP.all([ removeAllOPML(remove_opml_list, context) ]); }); } return new RSVP.Queue() //repair sub storage layers (local and remote) .push(function () { return context._local_sub_storage.repair.apply( context._local_sub_storage, argument_list ); }) .push(function () { if (context._remote_sub_storage) { return context._remote_sub_storage.repair.apply( context._remote_sub_storage, argument_list ); } }) .push(function () { //delete all opmls trees of no longer present slapos masters //(in case master url list was updated) return cleanOpmlStorage(context); }) .push(function () { //get opml list from remote slapos master(s) return getInstanceOPMLList(context._remote_sub_storage); }) .push(undefined, function (error) { has_failed = true; if (error.target) { if (error.target.status === 401) { error_msg = ": unauthorized access to slapos master"; } if (error.target.status === 404) { error_msg = ": slapos master url not found"; } if (error.target.status - 500 > 0) { error_msg = ": server error on slapos master side - " + error.target.status; } if (error.target.responseURL) { error_msg += ". URL: " + error.target.responseURL; } } else { console.log(error); } throw "Failed to import remote configurations" + error_msg; }) .push(function (opml_list) { console.log(opml_list); //HARDCODED second master /*if (mock_test) { if (context._remote_sub_storage.__storage._storage_list[1]) { if (context._remote_sub_storage.__storage._storage_list[1].__storage._storage_definition.url === "https://softinst239021.host.vifib.net/erp5/web_site_module/slapos_hateoas/") { opml_list[6].slapos_master_url = "https://softinst239021.host.vifib.net/erp5/web_site_module/slapos_hateoas/"; } } else { opml_list.pop(); } }*/ //store opmls in local sub storage var i, push_queue = new RSVP.Queue(); function pushOPML(opml_dict) { push_queue .push(function () { return context._local_sub_storage.put(opml_dict.url, opml_dict); }); } for (i = 0; i < opml_list.length; i += 1) { pushOPML(opml_list[i]); } return push_queue; }) .push(function () { if (!has_failed) { //sync storage using updated opml list return syncOpmlStorage(context); } }); }; jIO.addStorage('replicatedopml', ReplicatedOPMLStorage); }(jIO, RSVP, DOMParser, Rusha, Blob, console, btoa, URLSearchParams));