# HG changeset patch # User Goffi # Date 1345038646 -7200 # Node ID 23cbdf0a07774855bebffa10c4ca693e45d17c83 # Parent e0d1eed4a46b23ec46b28057fcbb29110f394b83 core: presence status + last resource refactored and kept in entitiesCache in memory.py, profile cache is purged on disconnection diff -r e0d1eed4a46b -r 23cbdf0a0777 src/core/sat_main.py --- a/src/core/sat_main.py Thu Aug 02 01:08:51 2012 +0200 +++ b/src/core/sat_main.py Wed Aug 15 15:50:46 2012 +0200 @@ -256,6 +256,7 @@ return current.getConnectionDeferred() + self.memory.startProfileSession(profile) return self.memory.loadIndividualParams(profile).addCallback(afterMemoryInit) def disconnect(self, profile_key): @@ -290,7 +291,7 @@ del self.profiles[profile] except KeyError: error(_("Trying to remove reference to a client not referenced")) - self.memory.purgeProfile(profile) + self.memory.purgeProfileSession(profile) def startService(self): info("Salut à toi ô mon frère !") diff -r e0d1eed4a46b -r 23cbdf0a0777 src/core/xmpp.py --- a/src/core/xmpp.py Thu Aug 02 01:08:51 2012 +0200 +++ b/src/core/xmpp.py Wed Aug 15 15:50:46 2012 +0200 @@ -249,7 +249,7 @@ statuses["default"] = statuses[None] del statuses[None] - self.host.memory.addPresenceStatus(entity, show or "", + self.host.memory.setPresenceStatus(entity, show or "", int(priority), statuses, self.parent.profile) #now it's time to notify frontends @@ -265,7 +265,7 @@ if statuses.has_key(None): #we only want string keys statuses["default"] = statuses[None] del statuses[None] - self.host.memory.addPresenceStatus(entity, "unavailable", 0, statuses, self.parent.profile) + self.host.memory.setPresenceStatus(entity, "unavailable", 0, statuses, self.parent.profile) #now it's time to notify frontends self.host.bridge.presenceUpdate(entity.full(), "unavailable", 0, statuses, self.parent.profile) diff -r e0d1eed4a46b -r 23cbdf0a0777 src/memory/memory.py --- a/src/memory/memory.py Thu Aug 02 01:08:51 2012 +0200 +++ b/src/memory/memory.py Wed Aug 15 15:50:46 2012 +0200 @@ -299,7 +299,7 @@ d = self.storage.getIndParam(category, name, profile) return d.addCallback(lambda value: value if value!=None else default) - def __getParam(self, profile, category, name, type='individual', cache=None): + def __getParam(self, profile, category, name, _type='individual', cache=None): """Return the param, or None if it doesn't exist @param profile: the profile name (not profile key, i.e. name and not something like @DEFAULT@) @param category: param category @@ -308,11 +308,11 @@ @param cache: temporary cache, to use when profile is not logged @return: param value or None if it doesn't exist """ - if type == 'general': + if _type == 'general': if self.params_gen.has_key((category, name)): return self.params_gen[(category, name)] return None #This general param has the default value - assert (type == 'individual') + assert (_type == 'individual') if self.params.has_key(profile): cache = self.params[profile] # if profile is in main cache, we use it, # ignoring the temporary cache @@ -420,19 +420,19 @@ d = self.__constructProfileXml(profile) return d.addCallback(returnCategoryXml) - def __getParamNode(self, name, category, type="@ALL@"): #FIXME: is type useful ? + def __getParamNode(self, name, category, _type="@ALL@"): #FIXME: is _type useful ? """Return a node from the param_xml @param name: name of the node @param category: category of the node - @type: keyword for search: + @_type: keyword for search: @ALL@ search everywhere @GENERAL@ only search in general type @INDIVIDUAL@ only search in individual type @return: a tuple with the node type and the the node, or None if not found""" for type_node in self.dom.documentElement.childNodes: - if ( ((type == "@ALL@" or type == "@GENERAL@") and type_node.nodeName == 'general') - or ( (type == "@ALL@" or type == "@INDIVIDUAL@") and type_node.nodeName == 'individual') ): + if ( ((_type == "@ALL@" or _type == "@GENERAL@") and type_node.nodeName == 'general') + or ( (_type == "@ALL@" or _type == "@INDIVIDUAL@") and type_node.nodeName == 'individual') ): for node in type_node.getElementsByTagName('category'): if node.getAttribute("name") == category: params = node.getElementsByTagName("param") @@ -475,8 +475,8 @@ assert (node[0] == 'individual') assert (profile_key != "@NONE@") - type = node[1].getAttribute("type") - if type=="button": + _type = node[1].getAttribute("type") + if _type=="button": print "clique",node.toxml() else: if self.host.isConnected(profile): #key can not exists if profile is not connected @@ -491,8 +491,8 @@ info (_("Memory manager init")) self.initialized = defer.Deferred() self.host = host - self.presenceStatus={} - self.lastResource={} #tmp, will be refactored with bdd integration + self.entitiesCache={} #XXX: keep presence/last resource/other data in cache + # /!\ an entity is not necessarily in roster self.subscriptions={} self.server_features={} #used to store discovery's informations self.server_identities={} @@ -562,10 +562,22 @@ @param profile: %(doc_profile)s""" return self.params.loadIndParams(profile) - def purgeProfile(self, profile): + def startProfileSession(self, profile): + """"Iniatialise session for a profile + @param profile: %(doc_profile)s""" + info(_("[%s] Profile session started" % profile)) + self.entitiesCache[profile] = {} + + def purgeProfileSession(self, profile): """Delete cache of data of profile @param profile: %(doc_profile)s""" + info(_("[%s] Profile session purge" % profile)) self.params.purgeProfile(profile) + try: + del self.entitiesCache[profile] + except KeyError: + error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile) + def save(self): """Save parameters and all memory things to file/db""" @@ -618,29 +630,29 @@ self.server_features[profile] = [] self.server_features[profile].append(feature) - def addServerIdentity(self, category, type, entity, profile): + def addServerIdentity(self, category, _type, entity, profile): """Add an identity discovered from server @param feature: string of the feature @param profile: which profile is using this server ?""" if not self.server_identities.has_key(profile): self.server_identities[profile] = {} - if not self.server_identities[profile].has_key((category, type)): - self.server_identities[profile][(category, type)]=set() - self.server_identities[profile][(category, type)].add(entity) + if not self.server_identities[profile].has_key((category, _type)): + self.server_identities[profile][(category, _type)]=set() + self.server_identities[profile][(category, _type)].add(entity) - def getServerServiceEntities(self, category, type, profile): + def getServerServiceEntities(self, category, _type, profile): """Return all available entities for a service""" if self.server_identities.has_key(profile): - return self.server_identities[profile].get((category, type), set()) + return self.server_identities[profile].get((category, _type), set()) else: return None - def getServerServiceEntity(self, category, type, profile): + def getServerServiceEntity(self, category, _type, profile): """Helper method to get first available entity for a service""" - entities = self.getServerServiceEntities(category, type, profile) + entities = self.getServerServiceEntities(category, _type, profile) if entities == None: warning(_("Entities (%(category)s/%(type)s) not available, maybe they haven't been asked to server yet ?") % {"category":category, - "type":type}) + "type":_type}) return None else: return list(entities)[0] if entities else None @@ -659,38 +671,40 @@ @param contact: contact jid (unicode) @param profile_key: %(doc_profile_key)s""" profile = self.getProfileName(profile_key) - if not profile: - error(_('Asking contacts for a non-existant profile')) + if not profile or not self.host.isConnected(profile): + error(_('Asking contacts for a non-existant or not connected profile')) + return "" + entity = jid.JID(contact).userhost() + if not entity in self.entitiesCache[profile]: + info(_("Entity not in cache")) return "" try: - return self.lastResource[profile][jid.JID(contact).userhost()] - except: + return self.entitiesCache[profile][entity]["last_resource"] + except KeyError: return "" - def addPresenceStatus(self, contact_jid, show, priority, statuses, profile_key): + def setPresenceStatus(self, contact_jid, show, priority, statuses, profile_key): + """Change the presence status of an entity""" profile = self.getProfileName(profile_key) if not profile: error(_('Trying to add presence status to a non-existant profile')) return - if not self.presenceStatus.has_key(profile): - self.presenceStatus[profile] = {} - if not self.lastResource.has_key(profile): - self.lastResource[profile] = {} - if not self.presenceStatus[profile].has_key(contact_jid.userhost()): - self.presenceStatus[profile][contact_jid.userhost()] = {} + entity_data = self.entitiesCache[profile].setdefault(contact_jid.userhost(),{}) resource = jid.parse(contact_jid.full())[2] or '' if resource: - self.lastResource[profile][contact_jid.userhost()] = resource + entity_data["last_resource"] = resource + if not "last_resource" in entity_data: + entity_data["last_resource"] = '' - self.presenceStatus[profile][contact_jid.userhost()][resource] = (show, priority, statuses) + entity_data.setdefault("presence",{})[resource] = (show, priority, statuses) - def addWaitingSub(self, type, contact_jid, profile_key): + def addWaitingSub(self, _type, contact_jid, profile_key): """Called when a subcription request is received""" profile = self.getProfileName(profile_key) assert(profile) if not self.subscriptions.has_key(profile): self.subscriptions[profile] = {} - self.subscriptions[profile][contact_jid] = type + self.subscriptions[profile][contact_jid] = _type def delWaitingSub(self, contact_jid, profile_key): """Called when a subcription request is finished""" @@ -715,10 +729,13 @@ if not profile: error(_('Asking contacts for a non-existant profile')) return {} - if not self.presenceStatus.has_key(profile): - self.presenceStatus[profile] = {} - debug ("Memory getPresenceStatus (%s)", self.presenceStatus[profile]) - return self.presenceStatus[profile] + entities_presence = {} + for entity in self.entitiesCache[profile]: + # if entity exists, "presence" key must exist + entities_presence[entity] = self.entitiesCache[profile][entity]["presence"] + + debug ("Memory getPresenceStatus (%s)", entities_presence) + return entities_presence def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): return self.params.getParamA(name, category, attr, profile_key) diff -r e0d1eed4a46b -r 23cbdf0a0777 src/plugins/plugin_xep_0277.py --- a/src/plugins/plugin_xep_0277.py Thu Aug 02 01:08:51 2012 +0200 +++ b/src/plugins/plugin_xep_0277.py Wed Aug 15 15:50:46 2012 +0200 @@ -92,7 +92,7 @@ microblog_data['author'] = _entry.authors[0].name.text microblog_data['timestamp'] = str(int(_entry.updated.tf)) microblog_data['id'] = item['id'] - except AttributeError, KeyError: + except (AttributeError, KeyError): error(_('Error while parsing atom entry for microblogging event')) return {} diff -r e0d1eed4a46b -r 23cbdf0a0777 src/test/helpers.py --- a/src/test/helpers.py Thu Aug 02 01:08:51 2012 +0200 +++ b/src/test/helpers.py Wed Aug 15 15:50:46 2012 +0200 @@ -66,7 +66,7 @@ def addContact(self, contact_jid, attributes, groups, profile_key='@DEFAULT@'): pass - def addPresenceStatus(self, contact_jid, show, priority, statuses, profile_key='@DEFAULT@'): + def setPresenceStatus(self, contact_jid, show, priority, statuses, profile_key='@DEFAULT@'): pass def addWaitingSub(self, type, contact_jid, profile_key):