summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2014-08-01 01:22:59 +0200
committerFlorent Le Coz <louiz@louiz.org>2014-08-01 01:22:59 +0200
commit87cf38995a283e4a476fd124fcc55e0f80edf1ad (patch)
tree54e434be6a56ae5d501d4c2e769dd7ca1cbb4009
parent55daf9d49df4a0e0774b27acd33735abf80f80dd (diff)
downloadpoezio-87cf38995a283e4a476fd124fcc55e0f80edf1ad.tar.gz
poezio-87cf38995a283e4a476fd124fcc55e0f80edf1ad.tar.bz2
poezio-87cf38995a283e4a476fd124fcc55e0f80edf1ad.tar.xz
poezio-87cf38995a283e4a476fd124fcc55e0f80edf1ad.zip
Make the TimedEvents work with asyncio
Improvements: events now occur precisely at the specified date. You don’t need to stop touching your keyboard to execute them.
-rw-r--r--src/core/core.py22
-rw-r--r--src/tabs/basetabs.py22
-rw-r--r--src/timed_events.py82
3 files changed, 32 insertions, 94 deletions
diff --git a/src/core/core.py b/src/core/core.py
index 446cc9f0..b2951aea 100644
--- a/src/core/core.py
+++ b/src/core/core.py
@@ -262,8 +262,6 @@ class Core(object):
self.initial_joins = []
- self.timed_events = set()
-
self.connected_events = {}
self.pending_invites = {}
@@ -749,22 +747,13 @@ class Core(object):
def remove_timed_event(self, event):
"""Remove an existing timed event"""
- if event and event in self.timed_events:
- self.timed_events.remove(event)
+ event.handler.cancel()
def add_timed_event(self, event):
"""Add a new timed event"""
- self.timed_events.add(event)
-
- def check_timed_events(self):
- """Check for the execution of timed events"""
- now = datetime.now()
- for event in self.timed_events:
- if event.has_timed_out(now):
- res = event()
- if not res:
- self.timed_events.remove(event)
- break
+ event.handler = asyncio.get_event_loop().call_later(event.delay,
+ event.callback,
+ *event.args)
####################### XMPP-related actions ##################################
@@ -1628,9 +1617,6 @@ class Core(object):
a non-None value), but we check for timed events instead.
"""
res = self.keyboard.get_user_input(self.stdscr)
- while res is None:
- self.check_timed_events()
- res = self.keyboard.get_user_input(self.stdscr)
return res
def escape_next_key(self):
diff --git a/src/tabs/basetabs.py b/src/tabs/basetabs.py
index c2efc9bc..95e47e4e 100644
--- a/src/tabs/basetabs.py
+++ b/src/tabs/basetabs.py
@@ -624,17 +624,12 @@ class ChatTab(Tab):
"""
if not config.get_by_tabname('send_chat_states', True, self.general_jid, True):
return
- if self.timed_event_paused:
- # check the weakref
- event = self.timed_event_paused()
- if event:
- # the event already exists: we just update
- # its date
- event.change_date(datetime.now() + timedelta(seconds=4))
- return
+ # First, cancel the delay if it already exists, before rescheduling
+ # it at a new date
+ self.cancel_paused_delay()
new_event = timed_events.DelayedEvent(4, self.send_chat_state, 'paused')
self.core.add_timed_event(new_event)
- self.timed_event_paused = weakref.ref(new_event)
+ self.timed_event_paused = new_event
def cancel_paused_delay(self):
"""
@@ -642,12 +637,9 @@ class ChatTab(Tab):
Called for example when the input is emptied, or when the message
is sent
"""
- if self.timed_event_paused:
- event = self.timed_event_paused()
- if event:
- self.core.remove_timed_event(event)
- del event
- self.timed_event_paused = None
+ if self.timed_event_paused is not None:
+ self.core.remove_timed_event(self.timed_event_paused)
+ self.timed_event_paused = None
def command_correct(self, line):
"""
diff --git a/src/timed_events.py b/src/timed_events.py
index a922ee03..6160645b 100644
--- a/src/timed_events.py
+++ b/src/timed_events.py
@@ -13,87 +13,47 @@ Once created, they must be added to the list of checked events with
:py:func:`.PluginAPI.add_timed_event` (within a plugin).
"""
+import asyncio
import logging
log = logging.getLogger(__name__)
import datetime
-class TimedEvent(object):
+class DelayedEvent(object):
"""
- An event with a callback that is called when the specified time is passed.
-
- Note that these events can NOT be used for very small delay or a very
- precise date, since the check for events is done once per second, as
- a maximum.
-
- The callback and its arguments should be passed as the lasts arguments.
+ A TimedEvent, but with the date calculated from now + a delay in seconds.
+ Use it if you want an event to happen in, e.g. 6 seconds.
"""
- def __init__(self, date, callback, *args):
+ def __init__(self, delay, callback, *args):
"""
- Create a new timed event.
+ Create a new DelayedEvent.
- :param datetime.datetime date: Time at which the callback must be run.
+ :param int delay: The number of seconds.
:param function callback: The handler that will be executed.
:param \*args: Optional arguments passed to the handler.
"""
- self._callback = callback
+ self.callback = callback
self.args = args
self.repetive = False
- self.next_call_date = date
-
- def __call__(self):
- """
- the call should return False if this event should be remove from
- the events list.
- If it’s true, the date should be updated beforehand to a later date,
- or else it will be called every second
- """
- self._callback(*self.args)
- return self.repetive
+ self.delay = delay
+ # An asyncio handler, as returned by call_later() or call_at()
+ self.handler = None
- def has_timed_out(self, current_date):
- """
- Check if the event has timed out.
-
- :param datetime.datetime current_date: The current date.
- :returns: True if the callback should be called
- :rtype: bool
- """
- if self.next_call_date < current_date:
- return True
- else:
- return False
-
- def change_date(self, date):
- """
- Simply change the date of the event.
-
- :param datetime.datetime date: Next date.
- """
- self.next_call_date = date
-
- def add_delay(self, delay):
- """
- Add a delay (in seconds) to the date.
-
- :param int delay: The delay to add.
- """
- self.next_call_date += datetime.timedelta(seconds=delay)
-
-class DelayedEvent(TimedEvent):
+class TimedEvent(DelayedEvent):
"""
- A TimedEvent, but with the date calculated from now + a delay in seconds.
- Use it if you want an event to happen in, e.g. 6 seconds.
+ An event with a callback that is called when the specified time is passed.
+
+ The callback and its arguments should be passed as the lasts arguments.
"""
- def __init__(self, delay, callback, *args):
+ def __init__(self, date, callback, *args):
"""
- Create a new DelayedEvent.
+ Create a new timed event.
- :param int delay: The number of seconds.
+ :param datetime.datetime date: Time at which the callback must be run.
:param function callback: The handler that will be executed.
:param \*args: Optional arguments passed to the handler.
"""
- date = datetime.datetime.now() + datetime.timedelta(seconds=delay)
- TimedEvent.__init__(self, date, callback, *args)
-
+ delta = date - datetime.datetime.now()
+ delay = delta.total_seconds()
+ DelayedEvent.__init__(self, delay, callback, *args)