changeset 86:408738c3cd5d

Added a handle_tick function to coroutine dispatchers.
author Atul Varma <varmaa@toolness.com>
date Fri, 01 May 2009 15:37:57 -0700
parents 7e3b3eb57ec2
children 43d37495e9d4
files cosocket.py openwebchat.py
diffstat 2 files changed, 47 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/cosocket.py	Fri May 01 14:18:06 2009 -0700
+++ b/cosocket.py	Fri May 01 15:37:57 2009 -0700
@@ -5,9 +5,32 @@
 import types
 import traceback
 import time
+import weakref
+
+coroutine_dispatchers = []
+
+def loop(timeout):
+    start_time = time.time()
+    while 1:
+        asyncore.loop(timeout = timeout, count = 1)
+        curr_time = time.time()
+        time_elapsed = curr_time - start_time
+        if time_elapsed > timeout:
+            start_time = curr_time
+            new_coroutine_dispatchers = []
+            for ref in coroutine_dispatchers:
+                dispatcher = ref()
+                if dispatcher:
+                    new_coroutine_dispatchers.append(ref)
+                    try:
+                        dispatcher.handle_tick(time_elapsed)
+                    except:
+                        dispatcher.handle_error()
+            coroutine_dispatchers[:] = new_coroutine_dispatchers
 
 class _AsyncChatCoroutineDispatcher(asynchat.async_chat):
     def __init__(self, coroutine, conn = None):
+        coroutine_dispatchers.append(weakref.ref(self))
         asynchat.async_chat.__init__(self, conn)
         self.set_terminator(None)
         self.__coroutine = coroutine
@@ -58,6 +81,23 @@
         except Exception:
             self.log_info(traceback.format_exc(), 'error')
 
+    def get_coroutine_stack_frames(self):
+        return [coroutine.gi_frame
+                for coroutine in self.__coroutine_stack]
+
+    def get_formatted_coroutine_traceback(self):
+        lines = ['Coroutine traceback (most recent call last):']
+        for frame in self.get_coroutine_stack_frames():
+            name = frame.f_code.co_name
+            filename = frame.f_code.co_filename
+            lineno = frame.f_lineno
+            lines.append('File "%s", line %d, in coroutine %s' %
+                          (filename, lineno, name))
+        return '\n'.join(lines)
+
+    def handle_tick(self, time_elapsed):
+        pass
+
     def handle_close(self):
         if self.__coroutine:
             # Pass an exception back into the coroutine to kick
@@ -73,7 +113,9 @@
         print '%s: %s' % (type, message)
 
     def handle_error(self):
-        self.log_info(traceback.format_exc(), 'error')
+        self.log_info(traceback.format_exc() +
+                      self.get_formatted_coroutine_traceback(),
+                      'error')
 
     def handle_connect(self):
         self.continue_from_yield()
@@ -96,26 +138,16 @@
         self.continue_from_yield(data)
 
 class CoroutineSocketServer(asyncore.dispatcher):
-    TIMEOUT = 1.0
-
-    def __init__(self, addr, coroutineFactory, timeout_func = None):
+    def __init__(self, addr, coroutineFactory):
         asyncore.dispatcher.__init__(self)
-        self.__timeout_func = timeout_func
         self.__coroutineFactory = coroutineFactory
         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
         self.set_reuse_addr()
         self.bind(addr)
         self.listen(1)
 
-    def run(self):
-        start_time = time.time()
-        while 1:
-            asyncore.loop(timeout = self.TIMEOUT, count = 1)
-            curr_time = time.time()
-            time_elapsed = curr_time - start_time
-            if self.__timeout_func and time_elapsed > self.TIMEOUT:
-                start_time = curr_time
-                self.__timeout_func(time_elapsed)
+    def run(self, timeout):
+        loop(timeout)
 
     def handle_accept(self):
         conn, addr = self.accept()
--- a/openwebchat.py	Fri May 01 14:18:06 2009 -0700
+++ b/openwebchat.py	Fri May 01 15:37:57 2009 -0700
@@ -77,7 +77,7 @@
                                              self._server_coroutine)
 
     def run(self):
-        self._server.run()
+        self._server.run(timeout = 5.0)
 
     def _until_http_response_sent(self, msg = '', mimetype = 'text/plain',
                                   length = None, code = 200,