summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2015-01-03 05:55:17 +0100
committerFlorent Le Coz <louiz@louiz.org>2015-01-03 06:08:03 +0100
commit47fbd4cead2e881b0250dd5f978caf64c6a5952c (patch)
treece556dce5c575c3a1d7067ba6196ba0b68d72265
parent1b9b4199e8ecfdc379a34b74dd9b3b197365d74a (diff)
downloadslixmpp-47fbd4cead2e881b0250dd5f978caf64c6a5952c.tar.gz
slixmpp-47fbd4cead2e881b0250dd5f978caf64c6a5952c.tar.bz2
slixmpp-47fbd4cead2e881b0250dd5f978caf64c6a5952c.tar.xz
slixmpp-47fbd4cead2e881b0250dd5f978caf64c6a5952c.zip
Delay the handling of stanza for when the process is not busy
We use some dirty monkey-patching to add a idle_call() function to the asyncio module. We then use that method to handle each received stanza only when the event loop is not busy with some other IO (mainly, the standard input)
-rw-r--r--slixmpp/xmlstream/asyncio.py32
-rw-r--r--slixmpp/xmlstream/resolver.py2
-rw-r--r--slixmpp/xmlstream/xmlstream.py5
3 files changed, 36 insertions, 3 deletions
diff --git a/slixmpp/xmlstream/asyncio.py b/slixmpp/xmlstream/asyncio.py
new file mode 100644
index 00000000..52610d01
--- /dev/null
+++ b/slixmpp/xmlstream/asyncio.py
@@ -0,0 +1,32 @@
+"""
+A module that monkey patches the standard asyncio module to add an
+idle_call() method to the main loop. This method is used to execute a
+callback whenever the loop is not busy handling anything else. This means
+that it is a callback with lower priority than IO, timer, or even
+call_soon() ones. These callback are called only once each.
+"""
+
+import asyncio
+from asyncio import tasks, events
+
+def idle_call(self, callback):
+ if tasks.iscoroutinefunction(callback):
+ raise TypeError("coroutines cannot be used with idle_call()")
+ handle = events.Handle(callback, [], self)
+ self._idle.append(handle)
+
+def my_run_once(self):
+ if self._idle:
+ self._ready.append(events.Handle(lambda: None, (), self))
+ real_run_once(self)
+ if self._idle:
+ handle = self._idle.pop(0)
+ handle._run()
+
+cls = asyncio.get_event_loop().__class__
+
+cls._idle = []
+cls.idle_call = idle_call
+real_run_once = cls._run_once
+cls._run_once = my_run_once
+
diff --git a/slixmpp/xmlstream/resolver.py b/slixmpp/xmlstream/resolver.py
index a3697d14..f2c3f989 100644
--- a/slixmpp/xmlstream/resolver.py
+++ b/slixmpp/xmlstream/resolver.py
@@ -8,7 +8,7 @@
:license: MIT, see LICENSE for more details
"""
-import asyncio
+from slixmpp.xmlstream.asyncio import asyncio
import socket
import logging
import random
diff --git a/slixmpp/xmlstream/xmlstream.py b/slixmpp/xmlstream/xmlstream.py
index 187bfbc5..f1abfca6 100644
--- a/slixmpp/xmlstream/xmlstream.py
+++ b/slixmpp/xmlstream/xmlstream.py
@@ -12,7 +12,6 @@
:license: MIT, see LICENSE for more details
"""
-import asyncio
import functools
import copy
import logging
@@ -23,6 +22,7 @@ import uuid
import xml.etree.ElementTree
+from slixmpp.xmlstream.asyncio import asyncio
from slixmpp.xmlstream import tostring
from slixmpp.xmlstream.stanzabase import StanzaBase, ElementBase
from slixmpp.xmlstream.resolver import resolve, default_resolver
@@ -377,7 +377,8 @@ class XMLStream(object):
elif self.xml_depth == 1:
# A stanza is an XML element that is a direct child of
# the root element, hence the check of depth == 1
- self.__spawn_event(xml)
+ asyncio.get_event_loop().\
+ idle_call(functools.partial(self.__spawn_event, xml))
if self.xml_root is not None:
# Keep the root element empty of children to
# save on memory use.