Add an ugly fix to avoid endless disco#info queries with each message (with receipts)

We need to check if the remote entity supports 0184, but if it doesn’t
support disco#info, then we will get an iq type="error" and nothing
will be cached, leading to disco#info queries being sent each time.

Keep a cache valid 2 hours of the JIDs which replied with an error.
TODO: check that this the kind of time period we want.
This commit is contained in:
mathieui 2014-05-08 01:37:52 +02:00
parent 9786592b80
commit 916416a019
3 changed files with 103 additions and 3 deletions

View file

@ -16,12 +16,17 @@ log = logging.getLogger(__name__)
import getpass
import sleekxmpp
from sleekxmpp.plugins.xep_0184 import XEP_0184
from sleekxmpp.plugins.xep_0030 import StaticDisco
from sleekxmpp.plugins.xep_0115 import StaticCaps
import common
import fixes
from common import safeJID
from config import config, options
StaticDisco.supports = fixes.xep_30_supports
StaticCaps.supports = fixes.xep_115_supports
class Connection(sleekxmpp.ClientXMPP):
"""
Receives everything from Jabber and emits the
@ -72,8 +77,6 @@ class Connection(sleekxmpp.ClientXMPP):
self.whitespace_keepalive_interval = int(interval)
else:
self.whitespace_keepalive_interval = 300
# Hack to check the sleekxmpp version
# TODO: Remove that when a sufficient time has passed since the move
self.register_plugin('xep_0004')
self.register_plugin('xep_0012')
self.register_plugin('xep_0030')

View file

@ -25,6 +25,7 @@ import bookmark
import connection
import decorators
import events
import fixes
import singleton
import tabs
import theming
@ -297,6 +298,7 @@ class Core(object):
self.on_theme_config_change)
self.add_configuration_handler("", self.on_any_config_change)
self.reset_iq_errors()
def on_any_config_change(self, option, value):
"""
@ -739,6 +741,12 @@ class Core(object):
self.timed_events.remove(event)
break
def reset_iq_errors(self):
"Reset the iq error cache periodically"
fixes.reset_iq_errors()
self.add_timed_event(
timed_events.DelayedEvent(7200, self.reset_iq_errors))
####################### XMPP-related actions ##################################

View file

@ -5,12 +5,15 @@ upstream.
TODO: Check that they are fixed and remove those hacks
"""
from sleekxmpp.stanza import Message
from sleekxmpp.xmlstream import ET
import logging
# used to avoid doing numerous useless disco#info requests
# especially with message receipts
IQ_ERRORS = set()
log = logging.getLogger(__name__)
def has_identity(xmpp, jid, identity):
@ -96,3 +99,89 @@ def _filter_add_receipt_request(self, stanza):
stanza['request_receipt'] = True
return stanza
def xep_30_supports(self, jid, node, ifrom, data):
"""
Check if a JID supports a given feature.
The data parameter may provide:
feature -- The feature to check for support.
local -- If true, then the query is for a JID/node
combination handled by this Sleek instance and
no stanzas need to be sent.
Otherwise, a disco stanza must be sent to the
remove JID to retrieve the info.
cached -- If true, then look for the disco info data from
the local cache system. If no results are found,
send the query as usual. The self.use_cache
setting must be set to true for this option to
be useful. If set to false, then the cache will
be skipped, even if a result has already been
cached. Defaults to false.
"""
feature = data.get('feature', None)
data = {'local': data.get('local', False),
'cached': data.get('cached', True)}
if not feature or jid.full in IQ_ERRORS:
return False
try:
info = self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True)
features = info['disco_info']['features']
return feature in features
except:
IQ_ERRORS.add(jid.full)
log.debug('%s added to the list of entities that do'
'not honor disco#info', jid.full)
return False
def xep_115_supports(self, jid, node, ifrom, data):
"""
Check if a JID supports a given feature.
The data parameter may provide:
feature -- The feature to check for support.
local -- If true, then the query is for a JID/node
combination handled by this Sleek instance and
no stanzas need to be sent.
Otherwise, a disco stanza must be sent to the
remove JID to retrieve the info.
cached -- If true, then look for the disco info data from
the local cache system. If no results are found,
send the query as usual. The self.use_cache
setting must be set to true for this option to
be useful. If set to false, then the cache will
be skipped, even if a result has already been
cached. Defaults to false.
"""
feature = data.get('feature', None)
data = {'local': data.get('local', False),
'cached': data.get('cached', True)}
if not feature or jid.full in IQ_ERRORS:
return False
if node in (None, ''):
info = self.caps.get_caps(jid)
if info and feature in info['features']:
return True
try:
info = self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True)
return feature in info['disco_info']['features']
except:
IQ_ERRORS.add(jid.full)
log.debug('%s added to the list of entities that do'
'not honor disco#info', jid.full)
return False
def reset_iq_errors():
"reset the iq error cache"
IQ_ERRORS.clear()