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)
This commit is contained in:
parent
1b9b4199e8
commit
47fbd4cead
3 changed files with 36 additions and 3 deletions
32
slixmpp/xmlstream/asyncio.py
Normal file
32
slixmpp/xmlstream/asyncio.py
Normal file
|
@ -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
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
:license: MIT, see LICENSE for more details
|
:license: MIT, see LICENSE for more details
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
from slixmpp.xmlstream.asyncio import asyncio
|
||||||
import socket
|
import socket
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
:license: MIT, see LICENSE for more details
|
:license: MIT, see LICENSE for more details
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import functools
|
import functools
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
@ -23,6 +22,7 @@ import uuid
|
||||||
|
|
||||||
import xml.etree.ElementTree
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
|
from slixmpp.xmlstream.asyncio import asyncio
|
||||||
from slixmpp.xmlstream import tostring
|
from slixmpp.xmlstream import tostring
|
||||||
from slixmpp.xmlstream.stanzabase import StanzaBase, ElementBase
|
from slixmpp.xmlstream.stanzabase import StanzaBase, ElementBase
|
||||||
from slixmpp.xmlstream.resolver import resolve, default_resolver
|
from slixmpp.xmlstream.resolver import resolve, default_resolver
|
||||||
|
@ -377,7 +377,8 @@ class XMLStream(object):
|
||||||
elif self.xml_depth == 1:
|
elif self.xml_depth == 1:
|
||||||
# A stanza is an XML element that is a direct child of
|
# A stanza is an XML element that is a direct child of
|
||||||
# the root element, hence the check of depth == 1
|
# 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:
|
if self.xml_root is not None:
|
||||||
# Keep the root element empty of children to
|
# Keep the root element empty of children to
|
||||||
# save on memory use.
|
# save on memory use.
|
||||||
|
|
Loading…
Reference in a new issue