core (disco), plugin XEP-0115: client use + capabilities hash improvment:

- modified a couple of method from memory to use client instead of profile
- XEP-0115: don't use unique hash for all clients anymore, as disco can be different between clients/components, and even between clients (different identity for instance).
    hash is now generated per client on each new session.
This commit is contained in:
Goffi 2018-03-24 10:44:37 +01:00
commit 7ffb8efb92
4 changed files with 64 additions and 73 deletions

View file

@ -284,6 +284,9 @@ class Discovery(object):
found_entities = set()
def infosCb(infos, entity):
if entity is None:
log.warning(_(u'received an item without jid'))
return
if identity is not None and identity not in infos.identities:
return
if features.issubset(infos.features):

View file

@ -605,7 +605,8 @@ class Memory(object):
@param profile_key: %(doc_profile_key)s
@return: presence data: key=entity JID, value=presence data for this entity
"""
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
entities_presence = {}
for entity_jid, entity_data in profile_cache.iteritems():
@ -641,14 +642,14 @@ class Memory(object):
## Resources ##
def _getAllResource(self, jid_s, profile_key):
client = self.host.getClient(profile_key)
jid_ = jid.JID(jid_s)
return self.getAllResources(jid_, profile_key)
return self.getAllResources(client, jid_)
def getAllResources(self, entity_jid, profile_key):
def getAllResources(self, client, entity_jid):
"""Return all resource from jid for which we have had data in this session
@param entity_jid: bare jid of the entit
@param profile_key: %(doc_profile_key)s
@param entity_jid: bare jid of the entity
return (list[unicode]): list of resources
@raise exceptions.UnknownEntityError: if entity is not in cache
@ -656,7 +657,7 @@ class Memory(object):
"""
if entity_jid.resource:
raise ValueError("getAllResources must be used with a bare jid (got {})".format(entity_jid))
profile_cache = self._getProfileCache(profile_key)
profile_cache = self._getProfileCache(client)
try:
entity_data = profile_cache[entity_jid.userhostJID()]
except KeyError:
@ -665,22 +666,21 @@ class Memory(object):
resources.discard(None)
return resources
def getAvailableResources(self, entity_jid, profile_key):
def getAvailableResources(self, client, entity_jid):
"""Return available resource for entity_jid
This method differs from getAllResources by returning only available resources
@param entity_jid: bare jid of the entit
@param profile_key: %(doc_profile_key)s
return (list[unicode]): list of available resources
@raise exceptions.UnknownEntityError: if entity is not in cache
"""
available = []
for resource in self.getAllResources(entity_jid, profile_key):
for resource in self.getAllResources(client, entity_jid):
full_jid = copy.copy(entity_jid)
full_jid.resource = resource
try:
presence_data = self.getEntityDatum(full_jid, "presence", profile_key)
presence_data = self.getEntityDatum(full_jid, "presence", client.profile)
except KeyError:
log.debug(u"Can't get presence data for {}".format(full_jid))
else:
@ -707,7 +707,7 @@ class Memory(object):
except KeyError: # plugin not found
pass
try:
resources = self.getAllResources(entity_jid, client.profile)
resources = self.getAllResources(client, entity_jid)
except exceptions.UnknownEntityError:
log.warning(u"Entity is not in cache, we can't find any resource")
return None
@ -729,23 +729,13 @@ class Memory(object):
## Entities data ##
def _getProfileCache(self, profile_key):
def _getProfileCache(self, client):
"""Check profile validity and return its cache
@param profile: %(doc_profile_key)_s
@param client: SatXMPPClient
@return (dict): profile cache
@raise exceptions.ProfileUnknownError: if profile doesn't exist
@raise exceptions.ProfileNotInCacheError: if there is no cache for this profile
"""
profile = self.getProfileName(profile_key)
if not profile:
raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
try:
profile_cache = self._entities_cache[profile]
except KeyError:
raise exceptions.ProfileNotInCacheError
return profile_cache
return self._entities_cache[client.profile]
def setSignalOnUpdate(self, key, signal=True):
"""Set a signal flag on the key
@ -759,14 +749,13 @@ class Memory(object):
else:
self._key_signals.discard(key)
def getAllEntitiesIter(self, with_bare=False, profile_key=C.PROF_KEY_NONE):
def getAllEntitiesIter(self, client, with_bare=False):
"""Return an iterator of full jids of all entities in cache
@param with_bare: if True, include bare jids
@param profile_key: %(doc_profile_key)s
@return (list[unicode]): list of jids
"""
profile_cache = self._getProfileCache(profile_key)
profile_cache = self._getProfileCache(client)
# we construct a list of all known full jids (bare jid of entities x resources)
for bare_jid, entity_data in profile_cache.iteritems():
for resource in entity_data.iterkeys():
@ -787,9 +776,10 @@ class Memory(object):
@param silent(bool): if True, doesn't send signal to frontend, even if there is a signal flag (see setSignalOnUpdate)
@param profile_key: %(doc_profile_key)s
"""
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL):
entities = self.getAllEntitiesIter(entity_jid==C.ENTITY_ALL, profile_key)
entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL)
else:
entities = (entity_jid,)
@ -814,9 +804,10 @@ class Memory(object):
@raise exceptions.UnknownEntityError: if entity is not in cache
@raise KeyError: key is not in cache
"""
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL):
entities = self.getAllEntitiesIter(entity_jid==C.ENTITY_ALL, profile_key)
entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL)
else:
entities = (entity_jid,)
@ -863,7 +854,8 @@ class Memory(object):
continue
return entity_data
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
ret_data = {}
if entities_jids:
for entity in entities_jids:
@ -893,7 +885,8 @@ class Memory(object):
@raise exceptions.UnknownEntityError: if entity is not in cache
"""
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
try:
entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource]
except KeyError:
@ -925,7 +918,8 @@ class Memory(object):
@raise exceptions.UnknownEntityError: if entity is not in cache
"""
profile_cache = self._getProfileCache(profile_key)
client = self.host.getClient(profile_key)
profile_cache = self._getProfileCache(client)
if delete_all_resources:
if entity_jid.resource:
@ -1316,17 +1310,16 @@ class Memory(object):
## Misc ##
def isEntityAvailable(self, entity_jid, profile_key):
def isEntityAvailable(self, client, entity_jid):
"""Tell from the presence information if the given entity is available.
@param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested)
@param profile_key: %(doc_profile_key)s
@return (bool): True if entity is available
"""
if not entity_jid.resource:
return bool(self.getAvailableResources) # is any resource is available, entity is available
return bool(self.getAvailableResources(client, entity_jid)) # is any resource is available, entity is available
try:
presence_data = self.getEntityDatum(entity_jid, "presence", profile_key)
presence_data = self.getEntityDatum(entity_jid, "presence", client.profile)
except KeyError:
log.debug(u"No presence information for {}".format(entity_jid))
return False

View file

@ -62,53 +62,47 @@ class XEP_0115(object):
def getHandler(self, client):
return XEP_0115_handler(self, client.profile)
def _checkHash(self, disco_d, profile):
client = self.host.getClient(profile)
client.caps_optimize = None
if XEP_0115.cap_hash is None:
disco_d.addCallback(lambda dummy: self.host.hasFeature(client, NS_CAPS_OPTIMIZE))
def updateOptimize(optimize):
client.caps_optimize = optimize
if optimize:
log.info(_("Caps optimisation enabled"))
client.caps_sent = False
else:
log.warning(_("Caps optimisation not available"))
disco_d.addCallback(updateOptimize)
disco_d.addCallback(lambda dummy: self.recalculateHash(profile))
return True
def _presenceTrigger(self, client, obj):
if XEP_0115.cap_hash is not None:
if client.caps_optimize:
if client.caps_sent:
return True
client.caps_sent = True
obj.addChild(XEP_0115.c_elt)
return True
@defer.inlineCallbacks
def recalculateHash(self, profile):
client = self.host.getClient(profile)
def profileConnected(self, client):
# we have to calculate hash for client
# because disco infos/identities may change between clients
# optimize check
client._caps_optimize = yield self.host.hasFeature(client, NS_CAPS_OPTIMIZE)
if client._caps_optimize:
log.info(_(u"Caps optimisation enabled"))
client._caps_sent = False
else:
log.warning(_(u"Caps optimisation not available"))
# hash generation
_infos = yield client.discoHandler.info(client.jid, client.jid, '')
disco_infos = disco.DiscoInfo()
for item in _infos:
disco_infos.append(item)
cap_hash = self.host.memory.disco.generateHash(disco_infos)
log.info("Our capability hash has been generated: [%s]" % cap_hash)
disco_infos = disco.DiscoInfo()
cap_hash = client._caps_hash = self.host.memory.disco.generateHash(disco_infos)
log.info("Our capability hash has been generated: [{cap_hash}]".format(
cap_hash = cap_hash))
log.debug("Generating capability domish.Element")
c_elt = domish.Element((NS_ENTITY_CAPABILITY, 'c'))
c_elt['hash'] = 'sha-1'
c_elt['node'] = C.APP_URL
c_elt['ver'] = cap_hash
XEP_0115.cap_hash = cap_hash
XEP_0115.c_elt = c_elt
if client.caps_optimize:
client.caps_sent = False
client._caps_elt = c_elt
if client._caps_optimize:
client._caps_sent = False
if cap_hash not in self.host.memory.disco.hashes:
self.host.memory.disco.hashes[cap_hash] = disco_infos
self.host.memory.updateEntityData(client.jid, C.ENTITY_CAP_HASH, cap_hash, profile_key=profile)
self.host.memory.updateEntityData(client.jid, C.ENTITY_CAP_HASH, cap_hash, profile_key=client.profile)
def _presenceTrigger(self, client, obj):
if client._caps_optimize:
if client._caps_sent:
return True
client.caps_sent = True
obj.addChild(client._caps_elt)
return True
class XEP_0115_handler(XMPPHandler):

View file

@ -204,6 +204,7 @@ class XEP_0329(object):
host.bridge.addMethod("FISList", ".plugin", in_sign='ssa{ss}s', out_sign='aa{ss}', method=self._listFiles, async=True)
host.bridge.addMethod("FISSharePath", ".plugin", in_sign='ssss', out_sign='s', method=self._sharePath)
host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger)
host.registerNamespace('fis', NS_FIS)
def getHandler(self, client):
return XEP_0329_handler(self)