Mercurial > psgxs
view storage.js @ 1:c2954a9e5665
Add a super-owner that has power over all nodes; add support for
affiliation changes; support pubsub#creator metadata; change
pubsub#digest_frequency default; and use better default config values.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Mon, 28 Jun 2010 21:55:30 +0200 |
parents | 9ee956af41e3 |
children | d8a98540d749 |
line wrap: on
line source
/* * 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 config.owner) if (typeof affil == 'string' && node.owner[affil] == jid) return 'super-owner'; 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 nodeID in list) { var node = list[nodeID]; for (var affil in config.owner) if (typeof affil == 'string' && config.owner[affil] == jid) { affils[nodeID] = 'super-owner'; break; } for (var affil in node.owner) if (typeof affil == 'string' && node.owner[affil] == jid) { affils[nodeID] = 'owner'; break; } if (config.enabled('publisher-affiliation')) for (var affil in node.publisher) if (typeof affil == 'string' && node.publisher[affil] == jid) { affils[nodeID] = 'publisher'; break; } if (config.enabled('publish-only-affiliation')) for (var affil in node.publishOnly) if (typeof affil == 'string' && node.publishOnly[affil] == jid) { affils[nodeID] = 'publish-only'; break; } if (config.enabled('outcast-affiliation')) for (var affil in node.outcast) if (typeof affil == 'string' && node.outcast[affil] == jid) { affils[nodeID] = '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 config.owner) if (typeof jid == 'string') affils[config.owner[jid]] = 'super-owner'; 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'); };