リアルタイムチャット (Mojolicious::Lite)
WebSocketを使ったリアルタイムチャットのサンプルです。複数の画面を開いても他の画面に書き込みがすぐに反映されます。
[f:id:perlcodesample:20100418234248p:image]
ソースコード
use strict; use warnings; use Mojolicious::Lite; my $clients = {}; websocket '/' => sub { my $self = shift; # Client id my $cid = "$self"; # Resist controller $clients->{$cid}{controller} = $self; # Receive message $self->on('message' => sub { my ($self, $message) = @_; # Send message to all clients foreach my $cid (keys %$clients) { $clients->{$cid}{controller}->send($message); } }); # Finish $self->on('finish' => sub { # Remove client delete $clients->{$cid}; }); }; get '/' => 'index'; app->start; __DATA__ @@ index.html.ep % my $url = $self->req->url->to_abs->scheme($self->req->is_secure ? 'wss' : 'ws')->path( '/' ); <!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Mojo Websocket Demo</title> <script type="text/javascript"> // only load the flash fallback when needed if ( !( 'WebSocket' in window ) ) { document.write([ '<scr'+'ipt type="text/javascript" src="web-socket-js/swfobject.js"></scr'+'ipt>', '<scr'+'ipt type="text/javascript" src="web-socket-js/FABridge.js"></scr'+'ipt>', '<scr'+'ipt type="text/javascript" src="web-socket-js/web_socket.js"></scr'+'ipt>' ].join('')); } </script> <script type="text/javascript"> if ( WebSocket.__initialize ) { // Set URL of your WebSocketMain.swf here: WebSocket.__swfLocation = 'web-socket-js/WebSocketMain.swf'; } // example copied from web-socket-js/sample.html var ws, input, clock; function init() { // Connect to Web Socket. ws = new WebSocket('<%= $url %>'); // Receive message ws.onmessage = function(e) { // Write message var message = document.createElement('div'); message.appendChild(document.createTextNode(e.data)); var display = document.getElementById( 'display' ); display.appendChild(message); }; } function sendChatMessage() { var input = document.getElementById('message-box'); var message = input.value; // Send message ws.send(message); input.value = ""; } window.onload = init; </script> </head> <div id="display" style="width:500px; height:200px; border:1px solid black"></div> <form onsubmit="sendChatMessage(); return false;"> <input size="60" type="text" id="message-box"> <input type="submit" onclick="sendChatMessage(); return false;" value=Send > </form> </html>
本番環境+WebSocketリバースプロキシにも対応したRedisを使うバージョンのリアルタイムチャット
本番環境WebSocketリバースプロキシにも対応したRedisを使うバージョンのリアルタイムチャットのロジックも紹介しておきます。
ApacheやnginxのWebSocketリバースプロキシを使って、Mojoliciousの本番サーバーhypnotoadで動くバージョンです。
Redisのpub/sub機能を組み合わせて実現しています。
パスの部分は必要に応じて「/」から必要なものに修正してください。index.html.epの一行目のパス「/」も合わせて修正してください。Apacheの場合は、WebSocket用のパスに分ける必要があります。
use strict; use warnings; use Mojolicious::Lite; websocket '/' => sub { my $self = shift; my $tx = $self->tx; my $redis = Mojo::Redis->new; my $pub = $redis->pubsub; # message from Redis my $sub = $pub->listen('messages', sub { my ($sub, $message) = @_; # $channel == messages $tx->send($message); }); # message from websocket $self->on(message => sub { my ($self, $message) = @_; $pub->notify(messages => $message); }); # need to clean up after websocket close $self->on(finish => sub { undef $redis; undef $pub; undef $sub; undef $tx; }); }; get '/' => 'index'; app->start;