Real-time chat (Mojolicious::Lite)
This is a sample of real-time chat using WebSocket. Even if you open multiple screens, the writing will be reflected immediately on the other screens.
[f: id: perlcodesample: 20100418234248p: image]
Source code
use strict; use warnings; use Mojolicious::Lite; my $clients = {}; websocket'/' => sub { my $self = shift; #Client id my $cid = "$self"; #Resistance 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>
Real-time chat version using Redis that also supports production environment + WebSocket reverse proxy
I will also introduce the logic of the real-time chat of the version using Redis that also supports the production environment WebSocket reverse proxy.
A version that runs on Mojolicious's production server hypnotoad, using Apache and nginx WebSocket reverse proxies.
It is realized by combining the pub / sub function of Redis.
Please modify the path part from "/" to the required one if necessary. Please also correct the path "/" on the first line of index.html.ep. For Apache, you need to separate the paths for WebSockets.
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;