リアルタイムチャット (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;
Mojolicious入門