core (memory): entities cache improvments:
- entities cache is no more limited to bare jid
- resources are now automatically updated in bare jid cache
This commit is contained in:
parent
2dcca42c19
commit
382d49a628
5 changed files with 118 additions and 70 deletions
|
|
@ -320,8 +320,8 @@ class DbusObject(dbus.service.Object):
|
|||
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
|
||||
in_signature='s', out_signature='a{sa{s(sia{ss})}}',
|
||||
async_callbacks=None)
|
||||
def getPresenceStatus(self, profile_key="@DEFAULT@"):
|
||||
return self._callback("getPresenceStatus", unicode(profile_key))
|
||||
def getPresenceStatuses(self, profile_key="@DEFAULT@"):
|
||||
return self._callback("getPresenceStatuses", unicode(profile_key))
|
||||
|
||||
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
|
||||
in_signature='s', out_signature='s',
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ doc_param_0=contact_jid: jid of the contact
|
|||
doc_param_1=%(doc_profile_key)s
|
||||
doc_return=the last resource connected of the contact, or ""
|
||||
|
||||
[getPresenceStatus]
|
||||
[getPresenceStatuses]
|
||||
type=method
|
||||
category=core
|
||||
sig_in=s
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class Const(object):
|
|||
PROF_KEY_NONE = '@NONE@'
|
||||
PROF_KEY_DEFAULT = '@DEFAULT@'
|
||||
ENTITY_ALL = '@ALL@'
|
||||
ENTITY_LAST_RESOURCE = 'last_resource'
|
||||
|
||||
|
||||
## Configuration ##
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class SAT(service.Service):
|
|||
self.bridge.register("getContacts", self.getContacts)
|
||||
self.bridge.register("getContactsFromGroup", self.getContactsFromGroup)
|
||||
self.bridge.register("getLastResource", self.memory._getLastResource)
|
||||
self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus)
|
||||
self.bridge.register("getPresenceStatuses", self.memory._getPresenceStatuses)
|
||||
self.bridge.register("getWaitingSub", self.memory.getWaitingSub)
|
||||
self.bridge.register("getWaitingConf", self.getWaitingConf)
|
||||
self.bridge.register("sendMessage", self._sendMessage)
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ class Memory(object):
|
|||
info(_("Memory manager init"))
|
||||
self.initialized = defer.Deferred()
|
||||
self.host = host
|
||||
self.entitiesCache = {} # XXX: keep presence/last resource/other data in cache
|
||||
# /!\ an entity is not necessarily in roster
|
||||
self._entities_cache = {} # 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 = {}
|
||||
|
|
@ -220,7 +220,7 @@ class Memory(object):
|
|||
""""Iniatialise session for a profile
|
||||
@param profile: %(doc_profile)s"""
|
||||
info(_("[%s] Profile session started" % profile))
|
||||
self.entitiesCache[profile] = {}
|
||||
self._entities_cache[profile] = {}
|
||||
|
||||
def purgeProfileSession(self, profile):
|
||||
"""Delete cache of data of profile
|
||||
|
|
@ -228,7 +228,7 @@ class Memory(object):
|
|||
info(_("[%s] Profile session purge" % profile))
|
||||
self.params.purgeProfile(profile)
|
||||
try:
|
||||
del self.entitiesCache[profile]
|
||||
del self._entities_cache[profile]
|
||||
except KeyError:
|
||||
error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile)
|
||||
|
||||
|
|
@ -369,80 +369,118 @@ class Memory(object):
|
|||
|
||||
def _getLastResource(self, jid_s, profile_key):
|
||||
jid_ = jid.JID(jid_s)
|
||||
return self.getLastResource(jid_, profile_key)
|
||||
return self.getLastResource(jid_, profile_key) or ""
|
||||
|
||||
|
||||
def getLastResource(self, jid_, profile_key):
|
||||
"""Return the last resource used by a jid_
|
||||
@param jid_: bare jid
|
||||
def getLastResource(self, entity_jid, profile_key):
|
||||
"""Return the last resource used by an entity
|
||||
@param entity_jid: entity jid
|
||||
@param profile_key: %(doc_profile_key)s"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile or not self.host.isConnected(profile):
|
||||
error(_('Asking jid_s for a non-existant or not connected profile'))
|
||||
return ""
|
||||
entity = jid_.userhost()
|
||||
if not entity in self.entitiesCache[profile]:
|
||||
info(_("Entity not in cache"))
|
||||
return ""
|
||||
data = self.getEntityData(entity_jid.userhostJID(), [C.ENTITY_LAST_RESOURCE], profile_key)
|
||||
try:
|
||||
return self.entitiesCache[profile][entity]["last_resource"]
|
||||
return data[C.ENTITY_LAST_RESOURCE]
|
||||
except KeyError:
|
||||
return ""
|
||||
return None
|
||||
|
||||
def getPresenceStatus(self, profile_key):
|
||||
def _getPresenceStatuses(self, profile_key):
|
||||
ret = self.getPresenceStatuses(profile_key)
|
||||
return {entity.full():data for entity, data in ret.iteritems()}
|
||||
|
||||
def getPresenceStatuses(self, profile_key):
|
||||
"""Get all the presence status of a profile
|
||||
@param profile_key: %(doc_profile_key)s
|
||||
@return: presence data: key=entity JID, value=presence data for this entity
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
error(_('Asking contacts for a non-existant profile'))
|
||||
return {}
|
||||
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
|
||||
entities_presence = {}
|
||||
for entity in self.entitiesCache[profile]:
|
||||
if "presence" in self.entitiesCache[profile][entity]:
|
||||
entities_presence[entity] = self.entitiesCache[profile][entity]["presence"]
|
||||
for entity in self._entities_cache[profile]:
|
||||
if "presence" in self._entities_cache[profile][entity]:
|
||||
entities_presence[entity] = self._entities_cache[profile][entity]["presence"]
|
||||
|
||||
debug("Memory getPresenceStatus (%s)", entities_presence)
|
||||
return entities_presence
|
||||
|
||||
def setPresenceStatus(self, entity_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
|
||||
entity_data = self.entitiesCache[profile].setdefault(entity_jid.userhost(), {})
|
||||
resource = jid.parse(entity_jid.full())[2] or ''
|
||||
if resource:
|
||||
entity_data["last_resource"] = resource
|
||||
if not "last_resource" in entity_data:
|
||||
entity_data["last_resource"] = ''
|
||||
|
||||
entity_data.setdefault("presence", {})[resource] = (show, priority, statuses)
|
||||
|
||||
def updateEntityData(self, entity_jid, key, value, profile_key):
|
||||
"""Set a misc data for an entity
|
||||
@param entity_jid: JID of the entity, or '@ALL@' to update all entities)
|
||||
@param key: key to set (eg: "type")
|
||||
@param value: value for this key (eg: "chatroom"), or C.PROF_KEY_NONE to delete
|
||||
"""Change the presence status of an entity
|
||||
@param entity_jid: jid.JID of the entity
|
||||
@param show: show status
|
||||
@param priotity: priotity
|
||||
@param statuses: dictionary of statuses
|
||||
@param profile_key: %(doc_profile_key)s
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
|
||||
if not profile in self.entitiesCache:
|
||||
entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid]
|
||||
resource = entity_jid.resource
|
||||
if resource:
|
||||
entity_data[C.ENTITY_LAST_RESOURCE] = resource
|
||||
entity_data.setdefault("presence", {})[resource or ''] = (show, priority, statuses)
|
||||
|
||||
def _getEntitiesData(self, entity_jid, profile):
|
||||
"""Get data dictionary for entities
|
||||
@param entity_jid: JID of the entity, or C.ENTITY_ALL for all entities)
|
||||
@param profile: %(doc_profile)s
|
||||
@return: entities_data (key=jid, value=entity_data)
|
||||
@raise: exceptions.ProfileNotInCacheError if profile is not in cache
|
||||
"""
|
||||
if not profile in self._entities_cache:
|
||||
raise exceptions.ProfileNotInCacheError
|
||||
if entity_jid == "@ALL@":
|
||||
entities_map = self.entitiesCache[profile]
|
||||
if entity_jid == C.ENTITY_ALL:
|
||||
entities_data = self._entities_cache[profile]
|
||||
else:
|
||||
entity = entity_jid.userhost()
|
||||
self.entitiesCache[profile].setdefault(entity, {})
|
||||
entities_map = {entity: self.entitiesCache[profile][entity]}
|
||||
for entity in entities_map:
|
||||
entity_map = entities_map[entity]
|
||||
if value == C.PROF_KEY_NONE and key in entity_map:
|
||||
del entity_map[key]
|
||||
entity_data = self._entities_cache[profile].setdefault(entity_jid, {})
|
||||
entities_data = {entity_jid: entity_data}
|
||||
return entities_data
|
||||
|
||||
def _updateEntityResources(self, entity_jid, profile):
|
||||
"""Add a known resource to bare entity_jid cache
|
||||
@param entity_jid: full entity_jid (with resource)
|
||||
@param profile: %(doc_profile)s
|
||||
"""
|
||||
assert(entity_jid.resource)
|
||||
entity_data = self._getEntitiesData(entity_jid.userhostJID(), profile)[entity_jid.userhostJID()]
|
||||
resources = entity_data.setdefault('resources', set())
|
||||
resources.add(entity_jid.resource)
|
||||
|
||||
def updateEntityData(self, entity_jid, key, value, profile_key):
|
||||
"""Set a misc data for an entity
|
||||
@param entity_jid: JID of the entity, or C.ENTITY_ALL to update all entities)
|
||||
@param key: key to set (eg: "type")
|
||||
@param value: value for this key (eg: "chatroom")
|
||||
@param profile_key: %(doc_profile_key)s
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
|
||||
entities_data = self._getEntitiesData(entity_jid, profile)
|
||||
if entity_jid.resource and entity_jid != C.ENTITY_ALL:
|
||||
self._updateEntityResources(entity_jid, profile)
|
||||
|
||||
for jid_ in entities_data:
|
||||
entity_data = entities_data[jid_]
|
||||
if value == C.PROF_KEY_NONE and key in entity_data:
|
||||
del entity_data[key]
|
||||
else:
|
||||
entity_map[key] = value
|
||||
entity_data[key] = value
|
||||
if isinstance(value, basestring):
|
||||
self.host.bridge.entityDataUpdated(entity, key, value, profile)
|
||||
self.host.bridge.entityDataUpdated(jid_.full(), key, value, profile)
|
||||
|
||||
def delEntityData(self, entity_jid, key, profile_key):
|
||||
"""Delete data for an entity
|
||||
@param entity_jid: JID of the entity, or C.ENTITY_ALL to delete data from all entities)
|
||||
@param key: key to delete (eg: "type")
|
||||
@param profile_key: %(doc_profile_key)s
|
||||
"""
|
||||
entities_data = self._getEntitiesData(entity_jid, profile_key)
|
||||
for entity_jid in entities_data:
|
||||
entity_data = entities_data[entity_jid]
|
||||
try:
|
||||
del entity_data[key]
|
||||
except KeyError:
|
||||
debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full()))
|
||||
|
||||
def getEntityData(self, entity_jid, keys_list, profile_key):
|
||||
"""Get a list of cached values for entity
|
||||
|
|
@ -453,16 +491,11 @@ class Memory(object):
|
|||
if there is no value of a given key, resulting dict will
|
||||
have nothing with that key nether
|
||||
@raise: exceptions.UnknownEntityError if entity is not in cache
|
||||
exceptions.ProfileNotInCacheError if profile is not in cache
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
if not profile:
|
||||
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
|
||||
if not profile in self.entitiesCache:
|
||||
raise exceptions.ProfileNotInCacheError
|
||||
if not entity_jid.userhost() in self.entitiesCache[profile]:
|
||||
raise exceptions.UnknownEntityError(entity_jid.userhost())
|
||||
entity_data = self.entitiesCache[profile][entity_jid.userhost()]
|
||||
entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid]
|
||||
if not keys_list:
|
||||
return entity_data
|
||||
ret = {}
|
||||
|
|
@ -471,15 +504,29 @@ class Memory(object):
|
|||
ret[key] = entity_data[key]
|
||||
return ret
|
||||
|
||||
def delEntityCache(self, entity_jid, profile_key):
|
||||
def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE):
|
||||
"""Remove cached data for entity
|
||||
@param entity_jid: JID of the entity
|
||||
@param entity_jid: JID of the entity to delete
|
||||
@param delete_all_resources: if True also delete all known resources form cache
|
||||
@param profile_key: %(doc_profile_key)s
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
try:
|
||||
del self.entitiesCache[profile][entity_jid.userhost()]
|
||||
except KeyError:
|
||||
pass
|
||||
if not profile:
|
||||
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
|
||||
to_delete = set([entity_jid])
|
||||
|
||||
if delete_all_resources:
|
||||
if entity_jid.resource:
|
||||
raise ValueError(_("Need a bare jid to delete all resources"))
|
||||
entity_data = self._getEntitiesData(entity_jid, profile)[entity_jid]
|
||||
resources = entity_data.setdefault('resources', set())
|
||||
to_delete.update([jid.JID("%s/%s" % (entity_jid.userhost(), resource)) for resource in resources])
|
||||
|
||||
for entity in to_delete:
|
||||
try:
|
||||
del self._entities_cache[profile][entity]
|
||||
except KeyError:
|
||||
debug("Can't delete entity [%s]: not in cache" % entity.full())
|
||||
|
||||
def addWaitingSub(self, type_, entity_jid, profile_key):
|
||||
"""Called when a subcription request is received"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue