March 21, 2010

Thinking about Miniboa 2.0

In the early 90s, my hobby was running a computer bulletin board system (BBS) in Virginia called Grendel's Place. I started with a free package called RBBS and then bought a license for the more spiffy TriBBS. Like the joke said; a sysop is someone who spends thousands of dollars to let other people use his computer.

I spent a lot of time writing utilities and experimental games with Borland's Turbo C compiler. Man, I loved that program. Eventually, I bought their C++ compiler for Windows but the combination of the awful C++ language and Microsoft's hideous Foundation Class Library killed my hobby programming for years.

BBSes had a wealth of Door games, which were external programs that the BBS passed control of the serial port to while the user played them. Some of these were, like Tradewar 2000 and Solar Realms Elite were incredibly compelling. Since the typical BBS had only a single phone line, these games tended to be turn-based with only so many moves allotted to each player per day.

Having started to work with Telnet, I immediately lamented the absence of two features from my days coding for a BBS. The first was IBM's extended character set that let you draw lines and blocks. Check out this screen from Global War:

The second thing I missed was ANSI.SYS, a DOS driver from Microsoft that controlled character color and cursor placement. Most BBS clients either used ANSI.SYS directly or as the standard against their own implementation. You could safely make assumptions about the capability of your visitor's terminal and do neat things.

Telnet clients, on the other hand, are horrible.

They are horrible in two ways -- actually implementing the Telnet protocol and supporting those same ANSI control codes. Feature support across the various clients is so awful and quirky that it's impossible to rely on anything but the shallowest of implementations -- even little things like setting the background color.

While writing Miniboa, I scaled back many of my aspirations and focused on two areas; things that mostly worked regardless of client and things that were harmless if they failed. If your client supported NAWS, you got 'on-the-fly' terminal sizing. If not, you got 80 columns. This is one of the reasons Miniboa is line-based (as in, it gives you an entire line of client input rather than keystrokes). It worked by default on every client I tested.

Another reason I went line-based was I'm toying with the idea of writing a Jabber/XMPP server to support play from instant messaging and wanted to keep my interface to the clients duck-typed; client.get_cmd() and client.send().

Whew, that's too much background eh?

OK, OK -- Miniboa 2.0. I had a request to add character support to Miniboa and realized there was no way to do it without some really ugly hacks and the right thing(tm) was to decouple, decouple, decouple. Currently, Telnet is handled via a do-it-all class that stores the Socket object as a member property and performs a lot of state juggling. I think I want to switch things over to nested coroutines. Where the inner ones perform progressively lower level IO.

David Beazley, author of the excellent Python Essential Reference, gave a lecture entitled A Curious Course on Coroutines and Concurrency at PyCon 2009. You can watch a video of it here:

Part 1
Part 2
Part 3

Another development comes from Confuto and Stendec who have kindly donated code for implementing WebSocket and Flash servers with Miniboa. This is pretty exciting because of the potential for rich clients that both represent. Plus if I do write a Jabber server, it would benefit from the decoupling process as well.