I’m writing an IRC Server
Yes, really, in 2012. See here, it’s on GitHub.
Why, in the name of all that is 8-bit?
For one, it’s fun. The core protocol is well defined by the RFCs. In the web development world you don’t often get to program to specifications like that; it’s a nice change of pace. There’s no need for any front-end work either. I get to write Python, which I haven’t done for a while. And finally, it’s my own free time, nowgetoffmydamnlawn.
Networking
I wrote basically zero networking code – gevent does all the hard work.
gevent is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libevent event loop.
Pure goodness. It’s also ridiculously easy to use. Note the mention of coroutines – gevent abstracts away not only the bit pushing of low-level networking, it also takes care of the handler threads greenlets. Here’s the networking code of the IRC server, all four lines of it:
def handle(socket, address):
fileobj = socket.makefile('rw')
# From here on, I can just use fileobj as a simple file object.
# Yes, fileobj.close() will close the socket.
server = gevent.server.StreamServer(('127.0.0.1', 6667), handle)
server.serve_forever()
Design and implementation
The server has four main components at the moment:
- abnf.py: Parses and checks the ABNF grammars specified in the RFCs. No regular expressions, but not a full-fledged ABNF parser either; just some helper functions that can be considered to be a semi-complete DSL. Pretty strict syntax checking.
- dispatcher.py: loads and calls command handlers as needed. Uses some
importlib
trickery to load handlers based on the incoming commands. - commands: Command handlers. They get and return abstract Message objects, and operate on the server database.
- db: Contains the server state: users, channels, other servers when I get to that. Currently just a simplistic implementation with dictionaries, but it’s probably enough for this project.
Currently enough commands are implemented to allow irssi to connect, join a channel, and have a conversation in a channel or in private (no user lists yet though). Adding new commands is pretty simple, so I hope to have a mostly functional server soon. I’m not too optimistic about how the current parser can be extended to support less compliant clients; it’ll probably have to be replaced with a more robust design.