October 11, 2010
■ Mojolicious::Lite で WebSocket を使ったチャットを作る
WebSocketで目指せ“リアルタイムWeb”! - @IT という記事を読みました。node.js という V8 を用いたサーバーサイド JavaScript フレームワークを使うと簡単にイベント駆動のサーバが書ける、node-websocket-server.js を使うと node.js で WebSocket サーバが実装できる。Ajax による polling や Long Polling などと WebSocket のアーキテクチャ比較といった内容でした。
WebSocket を使うと手軽にサーバプッシュ的なアプリケーションが作れて嬉しいのですが、現時点では、HTTPサーバー側で WebSocket を処理する下地の実装をどう用意するかというところがひとつ課題でしょう。node.js はその回答のひとつとして、なかなか面白いですね。
Perl で WebSocket サーバ ・・・ Mojolicious::Lite
さて、記事に触発されつつサーバー側を JavaScript ではなく Perl で書けたらいいなと言うことで Mojolicious::Lite を使ったサンプルを作ってみました。Mojoliciious には WebSocket を処理できるサーバー実装が同梱されていて、
use Mojolicious::Lite; websocket '/echo' => sub { my $self = shift; $self->receive_message(sub { my ($self, $message) = @_; $self->send_message("echo: $message"); }); }; app->start;
と書いて
% perl app.pl --daemon
でサーバーが起動、 ws://localhost:3000/echo が WebSocket のエンドポイントになり、receive_message() に渡したコールバックが、クライアント側からメッセージを受信する度にキックされるようになります。ハンドシェイクそのほかは Mojo が適当に処理してくれます。お手軽です。
サンプルの WebSocket チャットのコード
以下、サンプルで作ってみたチャットです。/ でチャット画面をHTMLで返す。/echo が WebSocket のエンドポイント。メッセージを受け取ると時刻と受け取ったテキストを、接続しているすべてのクライアントに送ります。
#!/usr/bin/env perl use utf8; use Mojolicious::Lite; use DateTime; use Mojo::JSON; get '/' => 'index'; my $clients = {}; websocket '/echo' => sub { my $self = shift; app->log->debug(sprintf 'Client connected: %s', $self->tx); my $id = sprintf "%s", $self->tx; $clients->{$id} = $self->tx; $self->receive_message( sub { my ($self, $msg) = @_; my $json = Mojo::JSON->new; my $dt = DateTime->now( time_zone => 'Asia/Tokyo'); for (keys %$clients) { $clients->{$_}->send_message( $json->encode({ hms => $dt->hms, text => $msg, }) ); } } ); $self->finished( sub { app->log->debug('Client disconnected'); delete $clients->{$id}; } ); }; app->start; __DATA__ @@ index.html.ep <html> <head> <title>WebSocket Client</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" ></script> <script type="text/javascript" src="/js/ws.js"></script> <style type="text/css"> textarea { width: 40em; height:10em; } </style> </head> <body> <h1>Mojolicious + WebSocket</h1> <p><input type="text" id="msg" /></p> <textarea id="log" readonly></textarea> </body> </html>
クライアントの js の中身。WebSocket API で /echo に接続して入出力を適当に処理。
$(function () { $('#msg').focus(); var log = function (text) { $('#log').val( $('#log').val() + text + "\n"); }; var ws = new WebSocket('ws://localhost:3000/echo'); ws.onopen = function () { log('Connection opened'); }; ws.onmessage = function (msg) { var res = JSON.parse(msg.data); log('[' + res.hms + '] ' + res.text); }; $('#msg').keydown(function (e) { if (e.keyCode == 13 && $('#msg').val()) { ws.send($('#msg').val()); $('#msg').val(''); } }); });
Google Chrome で localhost:3000 にアクセス、ちゃんと動きました。
こうして WebSocket のサーバー側を Perl で実装できる、とわかれば後は既存の資産を生かしていろんなことが考えられますね。先の記事の Activity Monitor のようなものを、サーバーで Perl で実装してしまって、リモートのサーバーステータスをグラフィカルに表示するとかアイデアは尽きません。
ほか
- More Mojolicious WebSocket examples にいくと、Mojolicious + WebSocket のもっと豪華なサンプルがいくつか見られます
- Perl で WebSocket のサーバー側を処理している例はほかにないかな、と検索していたら http://cpansearch.perl.org/src/MIYAGAWA/Twiggy-0.1007/eg/chat-websocket/chat.psgi に Twiggy (AnyEvent + PSGI) ベースのサンプルが見つかりました。WebSocket を Plack/PSGI で処理できるのは嬉しいですね。
- punitanのメモ - Mojolicious の wiki を書いた
- mizon dev - 何かつくろう
- Websocket 亳 Mojolicious
- 雑記 - [javascript][node.js]node.js入門メモ
- milkteaさんち。 - WebSocketを弄ってみたくなったので。
- Mojoliciousサンプルは古いとメソッド変わっていて動かないことがあ...
- TwistedでwebSocket を使ったチャットを作る(Python備忘:05)
- kazuphの車輪の再発明 - Mojolicious::Lite で WebSocket を使った...
- kazuphの車輪の再発明 - Mojolicious::Lite で WebSocket を使った...
- Twitter / @asami81
- Twitter / @duck75
- Twitter / @yukiyuki_1
- Twitter / @lrev
- punitanのメモ - Mojolicious の wiki を書いた
- aircastle.py - node.js, websocketのURL少しまとめ
- suzu-log/g86 - 時代のおわり
- kurainの壺 - Titaniumビルド手順まとめ
- altgoldTech2の日記 - JavaScript 10.10.15
- amari3のはてなダイアリー - Web開発者のための大規模サービス技術...
- Twitter / @knagano
- Twitter / @isoparametric
- Twitter / @isoparametric
- Twitter / @shase_
- 愛と勇気と缶ビール - gumistudy #5に行ってきたかもしれない
- BASHI_BASHI - Corona SDKを試してみた。
- 1232 http://reader.livedoor.com/reader/
- 1144 http://astronaughts.net/?p=204
- 1040 http://b.hatena.ne.jp/hotentry
- 1026 http://b.hatena.ne.jp/
- 997 http://twitter.com/
- 801 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&sqi=2&ved=0CC0QFjAA&url=http://d.hatena.ne.jp/naoya/20101011/1286778922&ei=vm84T-3-D8igmQXF2OSVAg&usg=AFQjCNEFR5wlFyuMLUIAOIX4uLES4XL44w
- 630 http://b.hatena.ne.jp/hotentry/it
- 611 http://www.google.co.jp/search?q=titanium&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&hl=ja&client=firefox
- 550 http://www.google.co.jp/search?sourceid=chrome&ie=UTF-8&q=Titanium
- 537 http://longurl.org

