Mercurial > libervia-backend
view tools/memory.py @ 59:3e5abe3bbead
Added tag SàT v0.0.2 for changeset d660d1e5cee4
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 10 Jan 2010 18:40:45 +1100 |
parents | a5b5fb5fc9fd |
children | 9764e027ecc0 |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- """ SAT: a jabber client Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ from __future__ import with_statement import os.path import time import pickle from xml.dom import minidom from logging import debug, info, error import pdb from twisted.internet import defer from twisted.words.protocols.jabber import jid SAVEFILE_PARAM="/param" SAVEFILE_HISTORY="/history" SAVEFILE_PRIVATE="/private" #file used to store misc values (mainly for plugins) class Param(): """This class manage parameter with xml""" ### TODO: add desciption in params #TODO: mettre Watched dans un plugin default_xml = u""" <params> <category name="Connection"> <param name="JabberID" value="goffi@necton2.int/TestScript" type="string" /> <param name="Password" value="toto" type="password" /> <param name="Server" value="necton2.int" type="string" /> <param name="NewAccount" value="Register new account" type="button" callback="registerNewAccount"/> </category> <category name="Misc"> <param name="Watched" value="test@Jabber.goffi.int" type="string" /> </category> </params> """ def load_default_params(self): self.dom = minidom.parseString(Param.default_xml.encode('utf-8')) def load(self, file): """Load parameters from file""" self.dom = minidom.parse(file) def save(self, file): """Save parameters to xml file""" with open(file, 'wb') as xml_file: self.dom.writexml(xml_file) def __init__(self, host): debug("Parameters init") self.host = host host.set_const('savefile_param', SAVEFILE_PARAM) host.set_const('savefile_history', SAVEFILE_HISTORY) host.set_const('savefile_private', SAVEFILE_PRIVATE) host.registerGeneralCB("registerNewAccount", host.registerNewAccountCB) def __get_unique_node(self, parent, tag, name): """return node with given tag, create a new one if the node doesn't exist @param parent: parent of nodes to check (e.g. documentElement) @param tag: tag to check (e.g. "category") @param name: name to check (e.g. "JID") @return: node if it exist or None """ for node in parent.childNodes: if node.nodeName == tag and node.getAttribute("name") == name: #the node already exists return node #the node is new return None def importParams(self, xml): """import xml in parameters, do nothing if the param already exist @param xml: parameters in xml form""" src_dom = minidom.parseString(xml.encode('utf-8')) def import_node(tgt_parent, src_parent): for child in src_parent.childNodes: if child.nodeName == '#text': continue node = self.__get_unique_node(tgt_parent, child.nodeName, child.getAttribute("name")) if not node: #The node is new tgt_parent.appendChild(child) else: import_node(node, child) import_node(self.dom.documentElement, src_dom.documentElement) def __default_ok(self, value, name, category): self.setParam(name, value, category) def __default_ko(self, failure, name, category): error ("Can't determine default value for [%s/%s]: %s" % (category, name, str(failure.value))) def setDefault(self, name, category, callback, errback=None): """Set default value of parameter 'default_cb' attibute of parameter must be set to 'yes' @param name: name of the parameter @param category: category of the parameter @param callback: must return a string with the value (use deferred if needed) @param errback: must manage the error with args failure, name, category """ #TODO: send signal param update if value changed node = self.__getParamNode(name, category) if not node: error("Requested param [%s] in category [%s] doesn't exist !" , name, category) return if node.getAttribute('default_cb') == 'yes': del node.attributes['default_cb'] d = defer.maybeDeferred(callback) d.addCallback(self.__default_ok, name, category) d.addErrback(errback or self.__default_ko, name, category) def getParamA(self, name, category, attr="value"): """Helper method to get a specific attribute @param name: name of the parameter @param category: category of the parameter @param attr: name of the attribute (default: "value") @return: attribute""" node = self.__getParamNode(name, category) if not node: error("Requested param [%s] in category [%s] doesn't exist !" , name, category) return None return node.getAttribute(attr) def getParams(self): """Return the whole params XML""" return self.dom.toxml() def getParamsForCategory(self, category): """Return node's xml for selected category""" for node in self.dom.documentElement.childNodes: if node.nodeName == "category" and node.getAttribute("name") == category: return node.toxml() return "<category />" def __getParamNode(self, name, category): for node in self.dom.documentElement.childNodes: if node.nodeName == "category" and node.getAttribute("name") == category: params = node.getElementsByTagName("param") for param in params: if param.getAttribute("name") == name: return param return None def getParamsCategories(self): """return the categories availables""" categories=[] for cat in self.dom.getElementsByTagName("category"): categories.append(cat.getAttribute("name")) return categories def setParam(self, name, value, category): node = self.__getParamNode(name, category) if not node: return #TODO: throw an error type = node.getAttribute("type") if type=="button": print "clique",node.toxml() else: node.setAttribute("value", value) self.host.bridge.paramUpdate(name, value, category) class Memory: """This class manage all persistent informations""" def __init__(self, host): info ("Memory manager init") self.host = host self.contacts={} self.presenceStatus={} self.subscriptions={} self.params=Param(host) self.history={} #used to store chat history (key: short jid) self.private={} #used to store private value self.disco={} #XXX: maybe best in a separate class self.features={} self.load() def load(self): """Load parameters and all memory things from file/db""" param_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_param')) history_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_history')) private_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_private')) #parameters if os.path.exists(param_file): try: self.params.load(param_file) debug("params loaded") except: error ("Can't load params !") self.params.load_default_params() else: error ("No params, using default parameters") self.params.load_default_params() #history if os.path.exists(history_file): try: with open(history_file, 'r') as history_pickle: self.history=pickle.load(history_pickle) debug("history loaded") except: error ("Can't load history !") #private if os.path.exists(private_file): try: with open(private_file, 'r') as private_pickle: self.private=pickle.load(private_pickle) debug("private values loaded") except: error ("Can't load private values !") def save(self): """Save parameters and all memory things to file/db""" #TODO: need to encrypt files (at least passwords !) and set permissions param_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_param')) history_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_history')) private_file = os.path.expanduser(self.host.get_const('local_dir')+ self.host.get_const('savefile_private')) self.params.save(param_file) debug("params saved") with open(history_file, 'w') as history_pickle: pickle.dump(self.history, history_pickle) debug("history saved") with open(private_file, 'w') as private_pickle: pickle.dump(self.private, private_pickle) debug("private values saved") def addToHistory(self, me_jid, from_jid, to_jid, type, message): me_short=me_jid.userhost() from_short=from_jid.userhost() to_short=to_jid.userhost() if from_jid==me_jid: key=to_short else: key=from_short if not self.history.has_key(me_short): self.history[me_short]={} if not self.history[me_short].has_key(key): self.history[me_short][key]={} self.history[me_short][key][int(time.time())] = (from_short, message) def getHistory(self, from_jid, to_jid, size): ret={} if not self.history.has_key(from_jid): error("source JID not found !") #TODO: throw an error here return {} if not self.history[from_jid].has_key(to_jid): error("dest JID not found !") #TODO: throw an error here return {} stamps=self.history[from_jid][to_jid].keys() stamps.sort() for stamp in stamps[-size:]: ret[stamp]=self.history[from_jid][to_jid][stamp] return ret def setPrivate(self, key, value): """Save a misc private value (mainly useful for plugins)""" self.private[key] = value def getPrivate(self, key): """return a private value @param key: name of wanted value @return: value or None if value don't exist""" if self.private.has_key(key): return self.private[key] return None def addContact(self, contact_jid, attributes, groups): debug("Memory addContact: %s",contact_jid.userhost()) assert(isinstance(attributes,dict)) assert(isinstance(groups,set)) self.contacts[contact_jid.userhost()]=[attributes, groups] def delContact(self, contact_jid): debug("Memory delContact: %s",contact_jid.userhost()) if self.contacts.has_key(contact_jid.userhost()): del self.contacts[contact_jid.userhost()] def getContact(self, contact_jid): if self.contacts.has_key(contact_jid.userhost()): self.contacts[contact_jid.userhost()] else: return None def getContacts(self): debug ("Memory getContact OK (%s)", self.contacts) ret=[] for contact in self.contacts: attr, groups = self.contacts[contact] ret.append([contact, attr, groups ]) return ret def addPresenceStatus(self, contact_jid, show, priority, statuses): if not self.presenceStatus.has_key(contact_jid.userhost()): self.presenceStatus[contact_jid.userhost()] = {} resource = jid.parse(contact_jid.full())[2] or '' self.presenceStatus[contact_jid.userhost()][resource] = (show, priority, statuses) def addWaitingSub(self, type, contact_jid): """Called when a subcription request is received""" self.subscriptions[contact_jid] = type def delWaitingSub(self, contact_jid): """Called when a subcription request is finished""" if self.subscriptions.has_key(contact_jid): del self.subscriptions[contact_jid] def getWaitingSub(self): """Called to get a list of currently waiting subscription requests""" return self.subscriptions def getPresenceStatus(self): debug ("Memory getPresenceStatus (%s)", self.presenceStatus) return self.presenceStatus def getParamA(self, name, category, attr="value"): return self.params.getParamA(name, category, attr) def getParams(self): return self.params.getParams() def getParamsForCategory(self, category): return self.params.getParamsForCategory(category) def getParamsCategories(self): return self.params.getParamsCategories() def setParam(self, name, value, category): return self.params.setParam(name, value, category) def importParams(self, xml): return self.params.importParams(xml) def setDefault(self, name, category, callback, errback=None): return self.params.setDefault(name, category, callback, errback)