八発白中

はてなブログに引越しました。

Day 13: websocket-driver

これは fukamachi products advent calendar 2016 の13日目の記事です。ようやく折り返し地点ですね。

今日はwebsocket-driverについて話します。

小さなライブラリではありますが、その後の話の発端となるライブラリなので紹介します。

WebSocket

Clackにより通常のHTTP通信を行うWebアプリケーションは作れるようになりました。しかし、よりリアルタイム性の強いもの、たとえばチャットやゲームのようなアプリケーションを作るには貧弱です。

たとえばWebSocket。TCP上のプロトコルであり、通信時の不要なオーバーヘッドが少なく効率的でリアルタイム性の高い通信プロトコルです。

ClackでWebSocketを使う方法はなく、使えるとすればHunchensocketというHunchentoot拡張くらいでした*1

Socket.IO

少しWebSocket周りの話もしておきます。

WebSocketの欠点は環境による通信状態の不安定さです。環境によってWebSocketが使えなかったり、使えてもすぐに切断されてしまったりします。この管理が難しくWebSocketの一般的な利用が妨げられているように思います。

この一つの解決策としてNode.jsのライブラリにSocket.IOというものがあります。

これはWebSocketが使えない環境のために通常のHTTP通信やHTTPのlong pollingなどで通信することもできます。最初はHTTPを試し、可能であればWebSocketに暗黙的にアップグレードします。ユーザー側もアプリケーション側も、何で通信しているのかということを意識せずに使えます*2

Socket.IOはプロトコルが公開されているので、Common Lispのサーバー実装を作れば公式のフロントエンド実装と通信できるはずです。

ではこれを作ろうと思いました。Common Lispは高速ですし非同期WebサーバーのWookieもあり、言語としての特性を活かせそうです。

これを作るためにはまずはWebSocketから。WebSocketのサーバー実装とクライアント実装を作りました。それが「websocket-driver」です。

EventEmitter

websocket-driverのインターフェイスとして参考にしたのがNode.jsのEventEmitterです。

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');

onでイベントのコールバックを指定しておき、emitで登録されているイベントコールバックを呼ぶものです。

ClackがPlackから実装をコピーしたように、websocket-driverも真似ています。Common Lispならばメソッドを使ってhandle-messageなどでもいいではないか、と思う人もいるかもしれませんが、イベント名が固定でない以上はこうするしかありません。

馴染んでいるのか何なのかまだわかりませんが、これはClackでWebSocketを使える唯一のライブラリです。

おわりに

websocket-driverはGitHubで公開されており、Starは28です。

明日のアドベントカレンダーは14日目のfast-httpについてです。お楽しみに。

*1:しかし僕の意見ではこれも実用に耐えうるものではありません。Hunchentootはクライアント毎にスレッドを立ち上げるため同時接続数に制約があります。1サーバーにつき100ユーザー程度が限界でしょう。

*2:ちなみにこの部分はv1.0からEngine.IOという別プロダクトに分離されました。