summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathieui <mathieui@mathieui.net>2014-05-08 01:37:52 +0200
committermathieui <mathieui@mathieui.net>2014-05-08 01:37:52 +0200
commit916416a019c398a484b6a436ee908808780263f9 (patch)
tree6de5b51968e8113b18251e8dee4131cd681860d9
parent9786592b80f7ddcfefa967ea910f38ba3c02b0b4 (diff)
downloadpoezio-916416a019c398a484b6a436ee908808780263f9.tar.gz
poezio-916416a019c398a484b6a436ee908808780263f9.tar.bz2
poezio-916416a019c398a484b6a436ee908808780263f9.tar.xz
poezio-916416a019c398a484b6a436ee908808780263f9.zip
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.
-rw-r--r--src/connection.py7
-rw-r--r--src/core/core.py8
-rw-r--r--src/fixes.py91
3 files changed, 103 insertions, 3 deletions
diff --git a/src/connection.py b/src/connection.py
index a0e9a395..b06a013b 100644
--- a/src/connection.py
+++ b/src/connection.py
@@ -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')
diff --git a/src/core/core.py b/src/core/core.py
index e340bd5d..74930083 100644
--- a/src/core/core.py
+++ b/src/core/core.py
@@ -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 ##################################
diff --git a/src/fixes.py b/src/fixes.py
index 75ac6343..cb992e88 100644
--- a/src/fixes.py
+++ b/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()