josefnpat/vapor — pull request #19 by leafo (2013-08-05 03:51:51+00:00)
Title: Add asynchronous http requests for game images and games

This replaces the blocking calls to `http.request` with non-blocking calls. I ended up implementing something similar to [Copas](http://keplerproject.github.io/copas/) that wraps the luasocket sockets and forces them to be non-blocking and runs the request through a coroutine.

`async.SocketQueue` is the data structure that manages all of our open connections. It has an update method that needs to be called every frame. It will trigger any work for any pending sockets. I've created an instance and stored it in a global called `downloader`.

In order to make a request you now do:

```lua
downloader:request(url, ltn12_sink, callback)
```

`sink` is an ltn12 sink where the response of the request goes.

`callback` is an optional function that is called after the request is completely done. It receives no arguments.

I opted to use [ltn12](http://w3.impa.br/~diego/software/luasocket/old/luasocket-2.0-beta2/ltn12.html) similar to the built in HTTP module because it's pretty flexible. It allows us to stream files as they are downloaded, which is great for us because we might be downloading huge files and we don't want to take up a ton of memory and we can incrementally write to disk.

I created a special sink that writes to a file using `love.filesystem`. It's located at `async.love_filesystem_sink`.

So, to write to a file, we might do something like this:

```lua
downloader:request("http://leafo.net", async.love_filesystem_sink("leafo_net.html"))
```

Try it out and tell me if you have any problems.