# -*- Mode: Python; tab-width: 4 -*-
# This is an alternative event loop that supports 'schedulable events'.
# You can specify an event callback to take place after <n> seconds.
# Important usage note: The granularity of the time-check is limited
# by the <timeout> argument to 'go()'; if there is little or no
# activity and you specify a 30-second timeout interval, then the
# schedule of events may only be checked at those 30-second intervals.
# In other words, if you need 1-second resolution, you will have to
# poll at 1-second intervals. This facility is more useful for longer
# timeouts ("if the channel doesn't close in 5 minutes, then forcibly
# close it" would be a typical usage).
import asyncore
import bisect
import time
socket_map = asyncore.socket_map
class event_loop:
def __init__ (self):
self.events = []
self.num_channels = 0
self.max_channels = 0
def go (self, timeout=30.0, granularity=15):
global socket_map
last_event_check = 0
while socket_map:
now = int(time.time())
if (now - last_event_check) >= granularity:
last_event_check = now
fired = []
# yuck. i want my lisp.
i = j = 0
while i < len(self.events):
when, what = self.events[i]
if now >= when:
fired.append (what)
j = i + 1
else:
break
i = i + 1
if fired:
self.events = self.events[j:]
for what in fired:
what (self, now)
# sample the number of channels
n = len(asyncore.socket_map)
self.num_channels = n
if n > self.max_channels:
self.max_channels = n
asyncore.poll (timeout)
def schedule (self, delta, callback):
now = int (time.time())
bisect.insort (self.events, (now + delta, callback))
def __len__ (self):
return len(self.events)
class test (asyncore.dispatcher):
def __init__ (self):
asyncore.dispatcher.__init__ (self)
def handle_connect (self):
print 'Connected!'
def writable (self):
return not self.connected
def connect_timeout_callback (self, event_loop, when):
if not self.connected:
print 'Timeout on connect'
self.close()
def periodic_thing_callback (self, event_loop, when):
print 'A Periodic Event has Occurred!'
# re-schedule it.
event_loop.schedule (15, self.periodic_thing_callback)
if __name__ == '__main__':
import socket
el = event_loop()
t = test ()
t.create_socket (socket.AF_INET, socket.SOCK_STREAM)
el.schedule (10, t.connect_timeout_callback)
el.schedule (15, t.periodic_thing_callback)
t.connect (('squirl', 80))
el.go(1.0)
|