こばやし けんいち
- こばやし けんいち @Niratama
- Perlでサーバーサイドプログラム書いてます
- が、最近はサーバのお守りまでやってる気が
- Raspberry Pi使ったネタがやりたかったんだけど
- 時間足りなかったので手軽なところで……
- "Real-time web framework"
- 基本的にはMojoliciousだけインストールすれば使える
- サーバーサイドだけでなくクライアント側を書くのにも便利
- コマンドラインやワンライナーのための仕組みが用意されている
- 「日刊Mojolicious」にハマるとちょっと困る
- Mojolicious::Guides::Cookbookに例が
- Mojo::IOLoopを使ったノンブロッキング処理
- WebSocket
- EventSource
- Mojo::IOLoopを使ったノンブロッキング処理
- デモに使うソースはhttps://github.com/niratama/chibapm3に置いてあります
- 内蔵のWebサーバを使っていればMojo::IOLoopを使ったノンブロッキング処理が使える
- timerなんかも使える←使い道は?
- TwitterのIDからプロフィール情報とATNDのイベント参加履歴を取得して表示するデモ
Mojo::IOLoop->delay(
# 並列処理の準備
sub {
my $delay = shift;
# APIのURL設定(中略)
# それぞれのAPIを呼び出す→レスポンスはdelayで受け取る
$self->ua->get($twitter_api => $delay->begin);
$self->ua->get($atnd_api => $delay->begin);
},
# delayの値が揃った時に実行される処理
sub {
my ($delay, $twitter, $atnd) = @_;
$self->render(
template => 'search',
twitter_id => $id,
user => $twitter->res->json,
events => $atnd->res->json->{events}
);
}
);
- RFC 6455
- WebアプリケーションとWebサーバとの双方向通信
- クリックした升目をWebSocketで通信して、複数のブラウザでリアルタイム共有するデモ
# コネクションのタイムアウトを長めにする
Mojo::IOLoop->stream($self->tx->connection)->timeout(300);
# MyEventのreceiveイベント受信時の処理
my $cb = sub {
my ($event, $cell) = @_;
$self->send($cell);
};
# MyEventのreceiveイベントに登録する
$event->on(receive => $cb);
# WebSocketのメッセージ受信時の処理
$self->on(message => sub {
my ($self, $cell) = @_;
# MyEventに送る
$event->send($cell);
});
# WebSocket終了時の処理
$self->on(finish => sub {
my ($self, $code, $reason) = @_;
# MyEventのreceiveイベント受け取りをやめる
$event->unsubscribe(receive => $cb);
});
var ws = new WebSocket('<%= url_for('share')->to_abs %>');
ws.onmessage = function(event) {
var cellid = '#' + event.data;
$(cellid).toggleClass('on');
};
$('.cell').click(function() {
var $cell = $(this);
ws.send($cell.attr('id'));
});
- Server-Sent EventsというHTML5からの新機能
- Webサーバからクライアントへのイベントやデータのプッシュ
- やってることはLong polling
- コネクション切れたらEventSourceのオブジェクトが生きているうちは勝手に再接続する
- Mojolicious::Controllerにはコンテンツを細切れで送るためのメソッドがある
- ログファイルをtail -Fしてブラウザに逐次送信するデモ
# コネクションのタイムアウトを長めにする
Mojo::IOLoop->stream($self->tx->connection)->timeout(300);
# レスポンスのContent-Typeをtext/event-streamにする
$self->res->headers->content_type('text/event-stream');
# ログファイルをtailで監視する
my $pid = open(my $fh, "-|", "tail -q -n 0 -F test.log");
if (!$pid) {
# 開けなかったらエラーを返す
$self->write("data: can't open test.log.\n\n");
return;
}
# ログファイルのハンドルを非同期で処理する
my $stream = Mojo::IOLoop::Stream->new($fh);
# ログファイル読み込み時の処理
$stream->on(read => sub {
my ($stream, $bytes) = @_;
# すべての行を送信する
foreach my $line (split(/\n/, $bytes)) {
$self->write("data: $line\n\n");
}
});
# コネクション切断時
$self->on(finish => sub {
my $self = shift;
# tailを殺す
kill 'QUIT', $pid;
});
# ログファイルの処理を開始する
$stream->start;
var source = new EventSource('<%= url_for 'events' %>');
source.onmessage = function(event) {
$('#log').append(event.data + '<br/>');
};
- Mojolicious使うとわりとお手軽にリアルタイムWebを体験できる
- Mojolicious::Liteでちょっと書いて動かしながら試すとわかりやすい
- Mojoliciousのドキュメントは充実してきているけど、細かい部分はソースを見たほうが早い
- 今回の発表資料はhttps://github.com/niratama/chibapm3に置いておきます