Mojolicious::Lite で WebSocket を使ったチャットを作る(現時点:2012年3月10日で動くコード)
(新しい記事書いたら間違って消した・・・からもう一度書いたorz)
Mojolicious::Lite で WebSocket を使ったチャットを作る - naoyaのはてなダイアリー
で書かれていたものを
【perlメモ】Mojolicious::Lite+WebSocketでのチャットプログラム - KUMA TYPE
で最新版のMojoliciousに対応してくださったんですけど、
現時点でコピペで動かなかったので最新版に修正してみました。
以下のIRCに解決方法が書いてありました。というかドキュメント読めと。
17:26 echoecho Hello! I am trying to get the hang of mojo websockets with this pretty simple chat-room example on Github (http://bit.ly/yOa4cZ), but whenever I send a message, my server fails with "Event "read" failed: Can't locate object method "send_message" via package "Mojo::Transaction::WebSocket"". Any ideas as to what I'm doing wrong?
17:27 sri that example is outdated, some methods have been renamed
17:27 echoecho Ah, that makes sense! Could you help me figure out which, or point to a newer example?
17:27 sri the websocket api is still experimental and changing
17:28 judofyr echoecho: https://metacpan.org/module/Mo[…]::Controller#send
超意訳
なんかGithubに乗ってるコード使ってもエラーでるんすけど?
↓
いやそれふりーし、もうメソッド名もかわってんよ
↓
おふ、最新の例とかねーの?
↓
つーかまだWebSocketの仕様決まってねーしなぁー
↓
とりまドキュメント嫁
ってことでいろいろなおしたら以下みたいになりましたよー
on_messageとかon_finishとかsend_messageが全部名前と使い方が変わってましたね。。。
JSのWebSocketの部分のURLは自分の環境に合わせて変えてください。
実行は以下のようにやるとできました。perl app.pl --daemonとかじゃできなかったのはなんで?
morbo app.pl
ということで現時点で動くであろうコードをのっけておきます。
すぐタイムアウトしてしまうって人は以下の記事も参照。
Mojolicious::Lite で WebSocketのタイムアウトの時間を修正する - kazuphの車輪の再発明
app.pl
#!/usr/bin/env perl use utf8; use Mojolicious::Lite; use DateTime; use Mojo::JSON; use Encode qw/from_to decode_utf8 encode_utf8/; use Data::Dumper qw/Dumper/; get '/' => sub { my $self = shift; # return $self->render(j => $j, f => $f); } => 'index'; my $clients = {}; websocket '/echo' => sub { my $self = shift; app->log->debug(sprintf 'Client connected: %s', $self->tx); my $id = sprintf "%s", $self->tx; app->log->debug("id:".$id); $clients->{$id} = $self->tx; # $self->receive_message( $self->on(message => sub { my ($self, $msg) = @_; my ($name,$message) = split(/\t/,$msg); $self->app->log->debug('name: ', $name, 'message: ', $message); unless($name){ $name = '名無し'; } my $json = Mojo::JSON->new; my $dt = DateTime->now( time_zone => 'Asia/Tokyo'); for (keys %$clients) { $self->app->log->debug('clients', Dumper $clients->{$_}); $clients->{$_}->send( decode_utf8($json->encode({ hms => $dt->hms, name => $name, text => $message, })) ); } } ); # $self->finished( $self->on(finish => sub { app->log->debug('Client disconnected'); delete $clients->{$id}; } ); }; app->start; __DATA__ @@ index.html.ep % layout 'main'; %= javascript begin jQuery(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.name + ') ' + res.text); }; $('#msg').keydown(function (e) { if (e.keyCode == 13 && $('#msg').val()) { ws.send($('#name').val() + "\t" + $('#msg').val()); $('#msg').val(''); } }); }); % end <h1>Mojolicious + WebSocket</h1> <p>name<input type="text" id="name" />msg<input type="text" id="msg" /></p> <textarea id="log" readonly></textarea> <div> </div> @@ layouts/main.html.ep <html> <head> <meta charset="<%= app->renderer->encoding %>"> <title>WebSocket Client</title> %= javascript 'https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js' <style type="text/css"> textarea { width: 40em; height:10em; } </style> </head> <body><%= content %></body> </html>