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:
parent
9786592b80
commit
916416a019
3 changed files with 103 additions and 3 deletions
|
@ -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')
|
||||
|
|
|
@ -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 ##################################
|
||||
|
||||
|
|
91
src/fixes.py
91
src/fixes.py
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue