Mercurial > libervia-backend
comparison src/memory/memory.py @ 484:23cbdf0a0777
core: presence status + last resource refactored and kept in entitiesCache in memory.py, profile cache is purged on disconnection
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 15 Aug 2012 15:50:46 +0200 |
parents | 2a072735e459 |
children | 0d9908ac775e |
comparison
equal
deleted
inserted
replaced
482:e0d1eed4a46b | 484:23cbdf0a0777 |
---|---|
297 except ProfileNotInCacheError: | 297 except ProfileNotInCacheError: |
298 #We have to ask data to the storage manager | 298 #We have to ask data to the storage manager |
299 d = self.storage.getIndParam(category, name, profile) | 299 d = self.storage.getIndParam(category, name, profile) |
300 return d.addCallback(lambda value: value if value!=None else default) | 300 return d.addCallback(lambda value: value if value!=None else default) |
301 | 301 |
302 def __getParam(self, profile, category, name, type='individual', cache=None): | 302 def __getParam(self, profile, category, name, _type='individual', cache=None): |
303 """Return the param, or None if it doesn't exist | 303 """Return the param, or None if it doesn't exist |
304 @param profile: the profile name (not profile key, i.e. name and not something like @DEFAULT@) | 304 @param profile: the profile name (not profile key, i.e. name and not something like @DEFAULT@) |
305 @param category: param category | 305 @param category: param category |
306 @param name: param name | 306 @param name: param name |
307 @param type: "general" or "individual" | 307 @param type: "general" or "individual" |
308 @param cache: temporary cache, to use when profile is not logged | 308 @param cache: temporary cache, to use when profile is not logged |
309 @return: param value or None if it doesn't exist | 309 @return: param value or None if it doesn't exist |
310 """ | 310 """ |
311 if type == 'general': | 311 if _type == 'general': |
312 if self.params_gen.has_key((category, name)): | 312 if self.params_gen.has_key((category, name)): |
313 return self.params_gen[(category, name)] | 313 return self.params_gen[(category, name)] |
314 return None #This general param has the default value | 314 return None #This general param has the default value |
315 assert (type == 'individual') | 315 assert (_type == 'individual') |
316 if self.params.has_key(profile): | 316 if self.params.has_key(profile): |
317 cache = self.params[profile] # if profile is in main cache, we use it, | 317 cache = self.params[profile] # if profile is in main cache, we use it, |
318 # ignoring the temporary cache | 318 # ignoring the temporary cache |
319 elif cache == None: #else we use the temporary cache if it exists, or raise an exception | 319 elif cache == None: #else we use the temporary cache if it exists, or raise an exception |
320 raise ProfileNotInCacheError | 320 raise ProfileNotInCacheError |
418 return "<category />" | 418 return "<category />" |
419 | 419 |
420 d = self.__constructProfileXml(profile) | 420 d = self.__constructProfileXml(profile) |
421 return d.addCallback(returnCategoryXml) | 421 return d.addCallback(returnCategoryXml) |
422 | 422 |
423 def __getParamNode(self, name, category, type="@ALL@"): #FIXME: is type useful ? | 423 def __getParamNode(self, name, category, _type="@ALL@"): #FIXME: is _type useful ? |
424 """Return a node from the param_xml | 424 """Return a node from the param_xml |
425 @param name: name of the node | 425 @param name: name of the node |
426 @param category: category of the node | 426 @param category: category of the node |
427 @type: keyword for search: | 427 @_type: keyword for search: |
428 @ALL@ search everywhere | 428 @ALL@ search everywhere |
429 @GENERAL@ only search in general type | 429 @GENERAL@ only search in general type |
430 @INDIVIDUAL@ only search in individual type | 430 @INDIVIDUAL@ only search in individual type |
431 @return: a tuple with the node type and the the node, or None if not found""" | 431 @return: a tuple with the node type and the the node, or None if not found""" |
432 | 432 |
433 for type_node in self.dom.documentElement.childNodes: | 433 for type_node in self.dom.documentElement.childNodes: |
434 if ( ((type == "@ALL@" or type == "@GENERAL@") and type_node.nodeName == 'general') | 434 if ( ((_type == "@ALL@" or _type == "@GENERAL@") and type_node.nodeName == 'general') |
435 or ( (type == "@ALL@" or type == "@INDIVIDUAL@") and type_node.nodeName == 'individual') ): | 435 or ( (_type == "@ALL@" or _type == "@INDIVIDUAL@") and type_node.nodeName == 'individual') ): |
436 for node in type_node.getElementsByTagName('category'): | 436 for node in type_node.getElementsByTagName('category'): |
437 if node.getAttribute("name") == category: | 437 if node.getAttribute("name") == category: |
438 params = node.getElementsByTagName("param") | 438 params = node.getElementsByTagName("param") |
439 for param in params: | 439 for param in params: |
440 if param.getAttribute("name") == name: | 440 if param.getAttribute("name") == name: |
473 return | 473 return |
474 | 474 |
475 assert (node[0] == 'individual') | 475 assert (node[0] == 'individual') |
476 assert (profile_key != "@NONE@") | 476 assert (profile_key != "@NONE@") |
477 | 477 |
478 type = node[1].getAttribute("type") | 478 _type = node[1].getAttribute("type") |
479 if type=="button": | 479 if _type=="button": |
480 print "clique",node.toxml() | 480 print "clique",node.toxml() |
481 else: | 481 else: |
482 if self.host.isConnected(profile): #key can not exists if profile is not connected | 482 if self.host.isConnected(profile): #key can not exists if profile is not connected |
483 self.params[profile][(category, name)] = value | 483 self.params[profile][(category, name)] = value |
484 self.host.bridge.paramUpdate(name, value, category, profile) | 484 self.host.bridge.paramUpdate(name, value, category, profile) |
489 | 489 |
490 def __init__(self, host): | 490 def __init__(self, host): |
491 info (_("Memory manager init")) | 491 info (_("Memory manager init")) |
492 self.initialized = defer.Deferred() | 492 self.initialized = defer.Deferred() |
493 self.host = host | 493 self.host = host |
494 self.presenceStatus={} | 494 self.entitiesCache={} #XXX: keep presence/last resource/other data in cache |
495 self.lastResource={} #tmp, will be refactored with bdd integration | 495 # /!\ an entity is not necessarily in roster |
496 self.subscriptions={} | 496 self.subscriptions={} |
497 self.server_features={} #used to store discovery's informations | 497 self.server_features={} #used to store discovery's informations |
498 self.server_identities={} | 498 self.server_identities={} |
499 self.config = self.parseMainConf() | 499 self.config = self.parseMainConf() |
500 host.set_const('savefile_database', SAVEFILE_DATABASE) | 500 host.set_const('savefile_database', SAVEFILE_DATABASE) |
560 def loadIndividualParams(self, profile): | 560 def loadIndividualParams(self, profile): |
561 """Load individual parameters for a profile | 561 """Load individual parameters for a profile |
562 @param profile: %(doc_profile)s""" | 562 @param profile: %(doc_profile)s""" |
563 return self.params.loadIndParams(profile) | 563 return self.params.loadIndParams(profile) |
564 | 564 |
565 def purgeProfile(self, profile): | 565 def startProfileSession(self, profile): |
566 """"Iniatialise session for a profile | |
567 @param profile: %(doc_profile)s""" | |
568 info(_("[%s] Profile session started" % profile)) | |
569 self.entitiesCache[profile] = {} | |
570 | |
571 def purgeProfileSession(self, profile): | |
566 """Delete cache of data of profile | 572 """Delete cache of data of profile |
567 @param profile: %(doc_profile)s""" | 573 @param profile: %(doc_profile)s""" |
574 info(_("[%s] Profile session purge" % profile)) | |
568 self.params.purgeProfile(profile) | 575 self.params.purgeProfile(profile) |
576 try: | |
577 del self.entitiesCache[profile] | |
578 except KeyError: | |
579 error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile) | |
580 | |
569 | 581 |
570 def save(self): | 582 def save(self): |
571 """Save parameters and all memory things to file/db""" | 583 """Save parameters and all memory things to file/db""" |
572 #TODO: need to encrypt files (at least passwords !) and set permissions | 584 #TODO: need to encrypt files (at least passwords !) and set permissions |
573 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+ | 585 param_file_xml = os.path.expanduser(self.getConfig('','local_dir')+ |
616 @param profile: which profile is using this server ?""" | 628 @param profile: which profile is using this server ?""" |
617 if not self.server_features.has_key(profile): | 629 if not self.server_features.has_key(profile): |
618 self.server_features[profile] = [] | 630 self.server_features[profile] = [] |
619 self.server_features[profile].append(feature) | 631 self.server_features[profile].append(feature) |
620 | 632 |
621 def addServerIdentity(self, category, type, entity, profile): | 633 def addServerIdentity(self, category, _type, entity, profile): |
622 """Add an identity discovered from server | 634 """Add an identity discovered from server |
623 @param feature: string of the feature | 635 @param feature: string of the feature |
624 @param profile: which profile is using this server ?""" | 636 @param profile: which profile is using this server ?""" |
625 if not self.server_identities.has_key(profile): | 637 if not self.server_identities.has_key(profile): |
626 self.server_identities[profile] = {} | 638 self.server_identities[profile] = {} |
627 if not self.server_identities[profile].has_key((category, type)): | 639 if not self.server_identities[profile].has_key((category, _type)): |
628 self.server_identities[profile][(category, type)]=set() | 640 self.server_identities[profile][(category, _type)]=set() |
629 self.server_identities[profile][(category, type)].add(entity) | 641 self.server_identities[profile][(category, _type)].add(entity) |
630 | 642 |
631 def getServerServiceEntities(self, category, type, profile): | 643 def getServerServiceEntities(self, category, _type, profile): |
632 """Return all available entities for a service""" | 644 """Return all available entities for a service""" |
633 if self.server_identities.has_key(profile): | 645 if self.server_identities.has_key(profile): |
634 return self.server_identities[profile].get((category, type), set()) | 646 return self.server_identities[profile].get((category, _type), set()) |
635 else: | 647 else: |
636 return None | 648 return None |
637 | 649 |
638 def getServerServiceEntity(self, category, type, profile): | 650 def getServerServiceEntity(self, category, _type, profile): |
639 """Helper method to get first available entity for a service""" | 651 """Helper method to get first available entity for a service""" |
640 entities = self.getServerServiceEntities(category, type, profile) | 652 entities = self.getServerServiceEntities(category, _type, profile) |
641 if entities == None: | 653 if entities == None: |
642 warning(_("Entities (%(category)s/%(type)s) not available, maybe they haven't been asked to server yet ?") % {"category":category, | 654 warning(_("Entities (%(category)s/%(type)s) not available, maybe they haven't been asked to server yet ?") % {"category":category, |
643 "type":type}) | 655 "type":_type}) |
644 return None | 656 return None |
645 else: | 657 else: |
646 return list(entities)[0] if entities else None | 658 return list(entities)[0] if entities else None |
647 | 659 |
648 def hasServerFeature(self, feature, profile_key): | 660 def hasServerFeature(self, feature, profile_key): |
657 def getLastResource(self, contact, profile_key): | 669 def getLastResource(self, contact, profile_key): |
658 """Return the last resource used by a contact | 670 """Return the last resource used by a contact |
659 @param contact: contact jid (unicode) | 671 @param contact: contact jid (unicode) |
660 @param profile_key: %(doc_profile_key)s""" | 672 @param profile_key: %(doc_profile_key)s""" |
661 profile = self.getProfileName(profile_key) | 673 profile = self.getProfileName(profile_key) |
662 if not profile: | 674 if not profile or not self.host.isConnected(profile): |
663 error(_('Asking contacts for a non-existant profile')) | 675 error(_('Asking contacts for a non-existant or not connected profile')) |
676 return "" | |
677 entity = jid.JID(contact).userhost() | |
678 if not entity in self.entitiesCache[profile]: | |
679 info(_("Entity not in cache")) | |
664 return "" | 680 return "" |
665 try: | 681 try: |
666 return self.lastResource[profile][jid.JID(contact).userhost()] | 682 return self.entitiesCache[profile][entity]["last_resource"] |
667 except: | 683 except KeyError: |
668 return "" | 684 return "" |
669 | 685 |
670 def addPresenceStatus(self, contact_jid, show, priority, statuses, profile_key): | 686 def setPresenceStatus(self, contact_jid, show, priority, statuses, profile_key): |
687 """Change the presence status of an entity""" | |
671 profile = self.getProfileName(profile_key) | 688 profile = self.getProfileName(profile_key) |
672 if not profile: | 689 if not profile: |
673 error(_('Trying to add presence status to a non-existant profile')) | 690 error(_('Trying to add presence status to a non-existant profile')) |
674 return | 691 return |
675 if not self.presenceStatus.has_key(profile): | 692 entity_data = self.entitiesCache[profile].setdefault(contact_jid.userhost(),{}) |
676 self.presenceStatus[profile] = {} | |
677 if not self.lastResource.has_key(profile): | |
678 self.lastResource[profile] = {} | |
679 if not self.presenceStatus[profile].has_key(contact_jid.userhost()): | |
680 self.presenceStatus[profile][contact_jid.userhost()] = {} | |
681 resource = jid.parse(contact_jid.full())[2] or '' | 693 resource = jid.parse(contact_jid.full())[2] or '' |
682 if resource: | 694 if resource: |
683 self.lastResource[profile][contact_jid.userhost()] = resource | 695 entity_data["last_resource"] = resource |
684 | 696 if not "last_resource" in entity_data: |
685 self.presenceStatus[profile][contact_jid.userhost()][resource] = (show, priority, statuses) | 697 entity_data["last_resource"] = '' |
686 | 698 |
687 def addWaitingSub(self, type, contact_jid, profile_key): | 699 entity_data.setdefault("presence",{})[resource] = (show, priority, statuses) |
700 | |
701 def addWaitingSub(self, _type, contact_jid, profile_key): | |
688 """Called when a subcription request is received""" | 702 """Called when a subcription request is received""" |
689 profile = self.getProfileName(profile_key) | 703 profile = self.getProfileName(profile_key) |
690 assert(profile) | 704 assert(profile) |
691 if not self.subscriptions.has_key(profile): | 705 if not self.subscriptions.has_key(profile): |
692 self.subscriptions[profile] = {} | 706 self.subscriptions[profile] = {} |
693 self.subscriptions[profile][contact_jid] = type | 707 self.subscriptions[profile][contact_jid] = _type |
694 | 708 |
695 def delWaitingSub(self, contact_jid, profile_key): | 709 def delWaitingSub(self, contact_jid, profile_key): |
696 """Called when a subcription request is finished""" | 710 """Called when a subcription request is finished""" |
697 profile = self.getProfileName(profile_key) | 711 profile = self.getProfileName(profile_key) |
698 assert(profile) | 712 assert(profile) |
713 def getPresenceStatus(self, profile_key): | 727 def getPresenceStatus(self, profile_key): |
714 profile = self.getProfileName(profile_key) | 728 profile = self.getProfileName(profile_key) |
715 if not profile: | 729 if not profile: |
716 error(_('Asking contacts for a non-existant profile')) | 730 error(_('Asking contacts for a non-existant profile')) |
717 return {} | 731 return {} |
718 if not self.presenceStatus.has_key(profile): | 732 entities_presence = {} |
719 self.presenceStatus[profile] = {} | 733 for entity in self.entitiesCache[profile]: |
720 debug ("Memory getPresenceStatus (%s)", self.presenceStatus[profile]) | 734 # if entity exists, "presence" key must exist |
721 return self.presenceStatus[profile] | 735 entities_presence[entity] = self.entitiesCache[profile][entity]["presence"] |
736 | |
737 debug ("Memory getPresenceStatus (%s)", entities_presence) | |
738 return entities_presence | |
722 | 739 |
723 def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): | 740 def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): |
724 return self.params.getParamA(name, category, attr, profile_key) | 741 return self.params.getParamA(name, category, attr, profile_key) |
725 | 742 |
726 def asyncGetParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): | 743 def asyncGetParamA(self, name, category, attr="value", profile_key='@DEFAULT@'): |