Rubyエンジニアのためのpowソースコードリーディング

先日、37signalsより "pow" というプロダクトが発表されました。Railsの開発をより簡単に行うための開発用HTTPサーバです。MaxOS向けにチューニングされていて、zero configでセットアップできるのが特徴になっています。

使い方は非常に簡単で、

curl get.pow.cx | sh

でインストールを行って

cd ~/.pow
ln -s /path/to/myapp

というようにアプリのシンボリックリンクを ~/.pow のディレクトリに貼れば http://myapp.dev/ というホスト名で起動します。本当に zero config で動きます。37signalsのプロダクトはおもろいですね。

さらに、面白いのがRailsの開発用アプリケーションサーバなのですが、中身の実装は node.js で書かれています。注目を集めてきているサーバサイドJavaScriptですね。

僕自身はまだあんまり node.js は触ったことがなかったのですが、ちょっとpowを改良してみたくなったのでいろいろ調べてみました。何を改良したかったかというと、HTTPSでアクセスしても動くようにしたかったのです。別サービスと連携する時やhttpsのテストをするときなどに、必要に感じていたのですがなかなか簡単に開発環境でHTTPSを動作させることは面倒ですよね。powが対応したらそれは便利だろうと思ったのです。
https://github.com/37signals/pow/issues/5

といっても僕は node.js を触ったことがないのですが、とりあえずコードを見てみることにしてみました。
https://github.com/37signals/pow
libディレクトリがJavaScript本体です。しかし、これは生成されたJavaScriptなのです。CoffeeScriptというJavaScriptをよりRuby, Pythonのようにシンプルに記述して、コンパイルしてJavaScriptに変換するものが流行っているらしいです。その実態は、srcディレクトリにあります。

pow自体は、非常に面白い動作をするのですが、実際ファイルを見てみるとコードは非常にすくないです。驚きました。主要なファイルは daemon.coffee, dns_server.coffee, http_server.coffee, rack_application.coffee の4つのファイルです。なぜ、このような少ないファイルでpowは実現できているかというと、その先にライブラリがあるからです。まぁ、当然ちゃ当然ですが、とてもうまく利用しているなぁという感じです。

まずは、利用している重要なライブラリを紹介します。 node.js にはもうこんなにも有用なライブラリが揃っているのかととても驚きました。npmというRubyのgemにあたるパッケージ管理システムも存在します。

1. connect http://senchalabs.github.com/connect/
Rubyでいうと、Rackのようなものだと思います。middlewareをたくさん組み込む感じでHTTPサーバを動かせます。

2. nack http://josh.github.com/nack/
node.js で受け取ったリクエストをRubyのRackを利用して実装されたアプリに受け渡しして処理することを実現してくれます。

この2つのライブラリがあれば、powで実現していることの基本的な仕組みは実現できているということがわかるのではないでしょうか?connectでHTTPリクエストを受け取って、nackを使ってRubyを呼び出してレスポンスを返す。あと足りない部分は、シンボリックリンクを作成したら自動的にホスト名を割り当てて起動させるようにする部分です。powのコードは主にこの部分の実装になるんですね。

で、先ほど出した4つのファイルファイルですが、以下の関係になっています。

daemon.coffee => dns_server.coffee
              => http_server.coffee => rack_application.coffee

daemonが起動されて、dns_serverとhttp_servertを立ち上げます。myapp.devでローカルホストを指すようにdns_serverで処理するんですね。さらにhttp_serverにリクエストがくるようになるので、それをホスト名などからどのRubyアプリに受け渡すのかを決定しrack_applicationを呼び出すという流れです。

http_serverの実装にconnectが、rack_applicationにnackが利用されています。それぞれを拡張する形でこのように動作するように実装されています。スクリプト言語の拡張性をうまく使っていると思います。

詳細なコードリーディングの解説にはなりませんでしたが、powがどのようなことをどうやって実現しているのか解説できたのではないかと思います。まだまだ、 node.js の素人なので間違っている部分はあるかと思いますが、ご指摘いただければと思います。