Beginning Io

I’m pretty excited about this programming language “Io”. _why the lucky stiff has been writing about it a bit lately over on Hackety. He’s been writing about the insane inflection the language allows. Its pretty much directly on par with Lisp… and in fact, I wonder if it couldn’t be classified as a dialect of Lisp… with syntax.

Anyway… The inflection is great, and I’m sure I’ll use it more as I progress further with the language. However, I like to start small… and one of the first things I try to do when I pick up a new language is write a little web server with it.

In this case, I’ve decided to go a bit further and write a little blog application with it.

The easy route would be to just use the CGI capabilities that Io comes with. But thats not what we’re going to do… because why do easy when you can do fun? So, we’re going to throw together a little, buggy application server. Then we’ll build the blog on top of it.

First things first, we’re going to need to setup a basic web server.

AppServe := Server clone 

AppServe handleSocket := method(socket,               
                socket streamWrite( "Foobar" )
                socket close) 

AppServe start

Kick off a new browser tab and head to localhost:8000. You should see truth written all over your monitor. I mean… It works! Great, so now we have a place to start.

Lets consider for a moment exactly what our application server needs to do. In this case, we’re not interested in serving static files like a real web server. We just need it to give an application, which we’ve not yet defined, an easy way to get requests… and send responses.

For this exercise then, we’re just going to make a simple event-based system. The application server is initialized by the application. The application provides a callback to the server. Whenever a request comes in, the callback is called, and the application gets the data it needs. What it sends back is a response, and we’ll deal with that in a little while.

AppServe run := method(port, handler,
                  self setPort(port)
                  self handler := handler
                  self start)

AppServer run simply takes a port and a callback… and starts the server. Easy enough. Moving along…

Request := Object clone do( raw := nil resource := nil httpVersion := nil httpMethod := nil headers := nil body := nil )

Request parse := method(data, self raw = data

requestLines := data split("\n")
statusParts := requestLines at(0) split
self httpMethod = statusParts at(0)
self resource = statusParts at(1)
self httpVersion = statusParts at(2)
headerLines := requestLines slice(1, requestLines indexOf("") - 1)
self headers = headerLines map(v, v split(": "))
self body = requestLines slice( headerLines size + 2 ) join("\n") )

Response := Object clone do( status := 200 reason := “OK” headers := nil body := nil

init := method(
          headers = Map clone atPut("Content-Type", "text/html") ) )

Response assemble := method( lines := List clone

lines append("HTTP/1.1 #{status} #{reason}" interpolate)
headers foreach(k, v, lines append("#{k}: #{v}" interpolate))
lines append("")
lines append(body)
lines join("\n") )

AppServe := Server clone do( setPort(8000) handleSocket := method(socket, socket streamReadNextChunk data := socket readBuffer

response := Response clone
request := Request clone
request parse(data)
response = handler call(request, response)
socket streamWrite( response assemble )
socket close) )

AppServe run := method(handler, self handler := handler self start)

blog comments powered by Disqus