Mercurial > psgxs
diff storage.js @ 0:9ee956af41e3
Initial commit
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sun, 27 Jun 2010 22:05:12 +0200 |
parents | |
children | c2954a9e5665 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/storage.js @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2010 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> + * + * This file is part of PSĜS, a PubSub server written in JavaScript. + * + * PSĜS is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License. + * + * PSĜS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with PSĜS. If not, see <http://www.gnu.org/licenses/>. + */ + +var sys = require('sys'); +var sha1hex = require('sha1').hex; +require('./iso8601'); +var errors = require('./errors'); +var config = require('./configuration'); +var service_configuration = config.service_configuration; +var Configuration = config.Configuration; +var utils = require('./util'); +var toBareJID = utils.toBareJID; + +var nodes = require('./nodes'); +var Node = nodes.Node; +var Item = nodes.Item; + +var fs = require('fs'); + +var list = {}; + +var storage = exports; +storage.createNode = function(nodeID, params) { + for (var i in list) + if (i == nodeID) + return errors.owner.create.nodeid_already_exists.n; + + list[nodeID] = new Node(params); + storage.save(); + return errors.success; +}; + +storage.getMetadata = function(nodeID) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (!config.enabled('meta-data')) + return {}; + + var md = {}; + for (var i in service_configuration.node_metadata) { + if (i == 'FORM_TYPE') + continue; + + if (node.configuration[i]) + md[i] = node.configuration[i]; + else if (node.metadata[i]) + md[i] = node.metadata[i]; + } + return md; +}; + +storage.getConfiguration = function(nodeID) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (config.enabled('config-node')) + return node.configuration; + + return {}; //FIXME +}; + +storage.configure = function(nodeID, params) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (!config.enabled('config-node')) + return 42; //FIXME + + for (var i in params) + if (service_configuration.node_config[i]) + node.configuration[i] = params[i]; + + storage.save(); + return errors.success; +}; + +storage.configureSubscription = function(nodeID, jid, params) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (!config.enabled('subscription-options')) + return 42; //FIXME + + var options = node.subscribers[jid].options; + if (!options) + return 42; //FIXME + + for (var i in params) + if (service_configuration.subscribe_options[i]) + options[i] = params[i]; + + storage.save(); + return errors.success; +}; + +storage.getChildren = function(node) { + var n; + var items = {}; + if (node) + n = storage.getNode(node).items; + else + n = list; + + for (var i in n) { + var type; + if (n[i].content) + type = 'item'; + else + type = 'node'; + items[i] = type; + } + return items; +}; + +storage.getNode = function(nodeID) { + if (list[nodeID]) + return list[nodeID]; + return errors.sub.subscribe.node_does_not_exist.n; +}; + +storage.existsNode = function(nodeID) { + if (list[nodeID]) + return true; + return false; +}; + +storage.purgeNode = function(nodeID) { + var node = storage.getNode(nodeID); + if (typeof n == 'number') + return node; + + var notifs = storage.getSubscriptionsFromNodeID(nodeID); + + var item = storage.getLastItem(nodeID); + if (typeof item == 'number') { + node.items = {}; + } else { + items = node.items[item]; + node.items = {}; + node.items[item] = items; + } + + storage.save(); + return notifs; +}; + +storage.deleteNodeWithRedirect = function(nodeID, uri) { + var del = storage.deleteNode(nodeID); + if (typeof del == 'number') + return del; + + list[nodeID] = uri; + storage.save(); + return errors.success; +}; + +storage.deleteNode = function(nodeID) { + var node = storage.getNode(nodeID); + if (typeof n == 'number') + return node; + + var notifs = {}; + for (var i in node.subscribers) + notifs[i] = {}; + for (var i in node.owner) + notifs[node.owner[i]] = {}; + if (config.enabled('publisher-affiliation')) + for (var i in node.publisher) + notifs[node.publisher[i]] = {}; + if (config.enabled('publish-only-affiliation')) + for (var i in node.publishOnly) + notifs[node.publishOnly[i]] = {}; + + delete list[nodeID]; + storage.save(); + return notifs; +}; + +storage.setItem = function(nodeID, itemID, content) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (typeof itemID != 'string') + itemID = utils.makeRandomId(); + + i = node.setItem(itemID, content); + if (content) + i.content = content; + + storage.save(); + return storage.getSubscriptionsFromNodeID(nodeID) +}; + +storage.deleteItem = function(nodeID, itemID) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (typeof itemID != 'string') + return errors.pub.retract.item_or_itemid_required.n; + + item = node.setItem(itemID); + if (typeof item == 'number') + return item; + + storage.save(); + return storage.getSubscriptionsFromNodeID(nodeID) +}; + +storage.getItems = function(nodeID) { + var node; + if (typeof nodeID == 'string') + node = storage.getNode(nodeID); + else + node = nodeID; + + if (typeof node == 'number') + return node; + + return node.items; +}; + +storage.getLastItem = function(nodeID, number) { + var items = storage.getItems(nodeID); + if (typeof items == 'number') + return items; + + if (items == {}) + return 42; //FIXME + + if (number) { + var last = []; + var j = 0; + for (var i in items) { + last.push({name: i, date: items[i].date, content: items[i].content}); + j++; + } + if (j < number) + return last; + + var cmp = function(a, b) { + return b.date - a.date; + } + last = last.sort(cmp).slice(0, number); + } else { + var last; + for (var i in items) + if ((typeof last == 'undefined') || (items[i].date >= items[last].date)) + last = i; + } + + if (last) + return last; + return 42; //FIXME +}; + +storage.existsItem = function(nodeID, itemID) { + var items = storage.getItems(nodeID); + if (typeof items == 'number') + return items; + + for (var i in items) + if (i == itemID) + return items[i]; + return false; +}; + +storage.getItem = function(nodeID, itemID) { + if (!storage.existsItem(nodeID, itemID)) + return 42; //FIXME + + var items = storage.existsItem(nodeID, itemID); + if (typeof items == 'number') + return items; + if (items) + return items.content; + return errors.item_not_found; +}; + +storage.getSubscription = function(jid, nodeID) { + var subs = {}; + if (nodeID) { + var node = storage.getNode(nodeID); + for (var sub in node.subscribers) + if (toBareJID(sub) == jid) + return node.subscribers[sub] + } else { + for (var node in list) { + for (var sub in list[node].subscribers) { + if (toBareJID(sub) == jid) + subs[node] = list[node].subscribers[sub]; + } + } + } + return subs; +}; + +storage.getSubscriptionsFromNodeID = function(nodeID) { + var node; + if (typeof nodeID == 'string') { + node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + } else + node = nodeID; + + var subs = {}; + for (var sub in node.subscribers) { + if (typeof sub == 'string') { + var subscription = {subid: node.subscribers[sub].subid, type: node.subscribers[sub].type}; + if (node.subscribers[sub].options) + subscription.options = node.subscribers[sub].options; + subs[sub] = subscription; + } + } + return subs; +}; + +storage.subscribe = function(nodeID, jid, type, params) { + if (!config.enabled('subscribe')) + return errors.sub.subscribe.not_supported.n; + + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (typeof type == 'undefined') + type = 'subscribed'; + + if (type == 'none') { + if (!node.subscribers[jid]) + return errors.sub.unsubscribe.no_such_subscriber.n; + } + + var subid = node.setSubscriber(jid, type, null, params); + storage.save(); + return {subid: subid, type: type}; +}; + +storage.setAffiliation = function(nodeID, jid, affil) { + var node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + + if (affil == 'owner') + node.owner.push(jid); + else if (config.enabled('publisher-affiliation') && affil == 'publisher') + node.publisher.push(jid); + else if (config.enabled('publish-only-affiliation') && affil == 'publish-only') + node.publishOnly.push(jid); + else if (config.enabled('member-affiliation') && affil == 'member') + node.member.push(jid); + else if (config.enabled('outcast-affiliation') && affil == 'outcast') + node.outcast.push(jid); + + storage.save(); + return errors.success; +}; + +storage.getAffiliation = function(jid, nodeID) { + var node; + if (typeof nodeID == 'string') { + node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + } else + node = nodeID; + + for (var affil in node.owner) + if (typeof affil == 'string' && node.owner[affil] == jid) + return 'owner'; + if (config.enabled('publisher-affiliation')) + for (var affil in node.publisher) + if (typeof affil == 'string' && node.publisher[affil] == jid) + return 'publisher'; + if (config.enabled('publish-only-affiliation')) + for (var affil in node.publishOnly) + if (typeof affil == 'string' && node.publishOnly[affil] == jid) + return 'publish-only'; + if (config.enabled('outcast-affiliation')) + for (var affil in node.outcast) + if (typeof affil == 'string' && node.outcast[affil] == jid) + return 'outcast'; + return 'none'; +}; + +storage.getAffiliationsFromJID = function(jid) { + var affils = {}; + for (var node in list) { + var n = list[node]; + for (var affil in n.owner) + if (typeof affil == 'string' && n.owner[affil] == jid) { + affils[node] = 'owner'; + break; + } + if (config.enabled('publisher-affiliation')) + for (var affil in n.publisher) + if (typeof affil == 'string' && n.publisher[affil] == jid) { + affils[node] = 'publisher'; + break; + } + if (config.enabled('publish-only-affiliation')) + for (var affil in n.publishOnly) + if (typeof affil == 'string' && n.publishOnly[affil] == jid) { + affils[node] = 'publish-only'; + break; + } + if (config.enabled('outcast-affiliation')) + for (var affil in n.outcast) + if (typeof affil == 'string' && n.outcast[affil] == jid) { + affils[node] = 'outcast'; + break; + } + } + return affils; +}; + +storage.getAffiliationsFromNodeID = function(nodeID) { + var node; + if (typeof nodeID == 'string') { + node = storage.getNode(nodeID); + if (typeof node == 'number') + return node; + } else + node = nodeID; + + var affils = {}; + for (var jid in node.owner) + if (typeof jid == 'string') + affils[node.owner[jid]] = 'owner'; + if (config.enabled('publisher-affiliation')) + for (var jid in node.publisher) + if (typeof jid == 'string') + affils[node.publisher[jid]] = 'publisher'; + if (config.enabled('publish-only-affiliation')) + for (var jid in node.publishOnly) + if (typeof jid == 'string') + affils[node.publishOnly[jid]] = 'publish-only'; + if (config.enabled('member-affiliation')) + for (var jid in node.member) + if (typeof jid == 'string') + affils[node.member[jid]] = 'member'; + if (config.enabled('outcast-affiliation')) + for (var jid in node.outcast) + if (typeof jid == 'string') + affils[node.outcast[jid]] = 'outcast'; + return affils; +}; + +storage.save = function(file) { + function sanitize(o) { + var n = {}; + for (var i in o) { + if (i == 'content' || o[i].setISO8601) + n[i] = o[i].toString(); + else if (o[i] instanceof Array) + n[i] = o[i]; + else if (typeof o[i] == 'object') + n[i] = sanitize(o[i]); + else if (typeof o[i] == 'function') + ; + else + n[i] = o[i]; + } + return n; + } + + var data = sanitize(list); + + if (!file) + file = 'save.json'; + + fs.writeFile(file, sys.inspect(data, null, null)); +} + +storage.load = function(file) { + var xmpp = require('xmpp'); + function parseStanza(path, content) { + var stanza = null; + var stream = new xmpp.Stream({ + stanza: function (stanza) { + path[content] = stanza; + } + }); + stream.opened = true; + stream.data(path[content]); + } + + function endParsing(o) { + var regexp = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ/; + for (var i in o) { + if (typeof o[i] == 'string' && i == 'content') + parseStanza(o, i); + else if (typeof o[i] == 'string' && regexp(o[i])) { + var today = new Date(); + today.setISO8601(o[i]); + o[i] = today; + } else if (typeof o[i] == 'object') + endParsing(o[i]); + } + return o; + } + + if (!file) + file = 'save.json'; + + var data = fs.readFileSync(file); + var obj = eval('('+data+')'); + list = endParsing(obj); +} + +storage.debug = function() { + sys.puts('\033[1;33m' + sys.inspect(list, null, null) + '\033[0m'); +};