Phyo Arkar Lwin
Phyo Arkar Lwin

Reputation: 6901

Tornado Chatdemo to work with Coroutines

I am trying to make coroutine version of tornado chat demo and i am having trouble understanding it. As i am new to coroutine style of programming and i really hate Callbacks since javascript.

I want to change MessageUpdateHandler to truly use coroutine.

class MessageBuffer(object):
    def __init__(self):
        self.waiters = set()
        self.cache = []
        self.cache_size = 200

    def wait_for_messages(self, callback, cursor=None):
        if cursor:
            new_count = 0
            for msg in reversed(self.cache):
                if msg["id"] == cursor:
                    break
                new_count += 1
            if new_count:
                callback(self.cache[-new_count:])
                return
        self.waiters.add(callback)

    def cancel_wait(self, callback):
        self.waiters.remove(callback)

    def new_messages(self, messages):
        logging.info("Sending new message to %r listeners", len(self.waiters))
        for callback in self.waiters:
            try:
                callback(messages)
            except:
                logging.error("Error in waiter callback", exc_info=True)
        self.waiters = set()
        self.cache.extend(messages)
        if len(self.cache) > self.cache_size:
            self.cache = self.cache[-self.cache_size:]


# Making this a non-singleton is left as an exercise for the reader.
global_message_buffer = MessageBuffer()


class MessageUpdatesHandler(BaseHandler):
    @tornado.web.authenticated
    @tornado.web.asynchronous
    def post(self):
        cursor = self.get_argument("cursor", None)
        global_message_buffer.wait_for_messages(self.on_new_messages,
                                                cursor=cursor)

    def on_new_messages(self, messages):
        # Closed client connection
        if self.request.connection.stream.closed():
            return
        self.finish(dict(messages=messages))

    def on_connection_close(self):
        global_message_buffer.cancel_wait(self.on_new_messages)

I tried removing @tornado.web.asynchronous and replaced with @tornado.gen.coroutine but thats as far as i can go , i do not understand how to yield global_message_buffer.wait_for_messages() without on_new_messages(self, messages) callback, as what i understand is it makes callbacks obsolete . global_message_buffer is designed with a callback but , yeilds do not have callback, so how to yield them?

tornado chat exmaple demo : https://github.com/tornadoweb/tornado/blob/c9af9a7224b1f42e91ad88b0a3f8f10478584b0a/demos/chat/chatdemo.py#L101

Upvotes: 0

Views: 387

Answers (1)

zihen
zihen

Reputation: 261

Here is a simple example, Hope it helps:

class MessageUpdatesHandler(BaseHandler):
    @tornado.web.authenticated
    @gen.coroutine
    def post(self):
        cursor = self.get_argument("cursor", None)
        messages = yield gen.Task(global_message_buffer.wait_for_messages, cursor=cursor)

        if self.request.connection.stream.closed():
            return

        self.finish(dict(messages=messages))

Upvotes: 1

Related Questions