Making Comet based chat servers seems to be quite the rage as of late. In my attempt at learning how to use Eventlet and Mulib, I thought that I would create my own little toy chat server. Full source (all 2 files of it :)) can be downloaded here. Note that you will need the latests SVN versions (or v0.2 if it has been released) of Eventlet and Mulib for this example to work.
Eventlet has a nice class for handling events called event (imagine that) in the eventlet.coros module. Calling the wait() function of an event will block the current code path until a send() is sent to the event, at which point all paths of code that are waiting for that event will receive the message sent. I use this mechanism to handle the long polling for new chat messages. The Mulib stacked module provides a nice interface that exposes events as a resource, so all you have to do is add your event object to your url heirarchy. the code looks something like this:
chat_listener = coros.event()
root = {'listen' : chat_listener}
This will expose the chat_listener at /listen.
We will also need to add a resource that receives new chat events from the web interface. Custom resources can be made by subclassing mulib.mu.Resource. In order to handle requests, override the appropriate handler(handle_get, handle_post, etc.). In this case we will override the handle_post function to look something like this:
class ChatMessage(mu.Resource):
def handle_post(self, request):
nick = request.get_arg('nick')
message = request.get_arg('message')
chat_listener.send("%s: %s" % (nick, message))
chat_listener.reset()
request.write('')
This will get the nick and message from the POST arguments and then send the message to chat_listener. Also notice that a call to chat_listener.reset() is called to reset the event, and allow future messages to be sent.
The last thing we need is some HTML and fancy JS to do the rest. Mulib provides a File resource (along with several other helper reousrces) in the mulib.resources module. So we expose our html file like this:
root = {
'chat' : resources.File('chat.html'),
'listen' : chat_listener,
'message' : ChatMessage()
}
This wil load the chat.html when a user browses /chat. Also noticed that we attached our ChatMessage resource to /message.
There isn't anything super fancy in the html file to really blog about. It is pretty much the standard AJAXy stuff you might see other places. I've included it in the source download so that you can check it out.
You can run the server from the source by running the chat.py file, and then browsing to http://localhost:5000/chat. Enter a message at the bottom and hit enter to see what happens!
I did run into a couple of problems with HTTP/1.1 support, so I had to force the server to send HTTP/1.0, until the bugs have been fixed. The Eventlet devs have been very helpful and responsive to my bug reports, so I hope to see them fixed in the near future. It also sounds like they have a lot planned for it in the future.
Next up... A full fledged MUD... Well maybe not quite yet, but I am getting there a step at a time :)
2 comments:
Howdy EvilChuck. This is Phoenix Linden. We discovered this recently, and would like to include it in our mulib examples on http://wiki.secondlife.com/wiki/Mulib/Examples -- would you mind?
I tried to use wordpress to login and prove my identity but that does not appear to work.
Hi Phoenix,
By all means feel free to use it! And thanks for checking my articles out :)
Chuck
Post a Comment