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:
Florent Le Coz 2015-01-03 05:55:17 +01:00
parent 1b9b4199e8
commit 47fbd4cead
3 changed files with 36 additions and 3 deletions

View 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

View file

@ -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

View file

@ -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.