Mojolicious::LiteとData::ModelとjQueryでAJAXなチャットを作ってみた

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env perl
#utf8
# use Acme::PerlTidy;
use utf8;
package DataModel;
use base 'Data::Model';
use Data::Model::Schema;
use Data::Model::Driver::DBI;
my $dbfile = qq{$0.db};
my $dsn    = qq{dbi:SQLite:dbname=$dbfile};
my $driver = Data::Model::Driver::DBI->new(
dsn             => $dsn,
connect_options => {sqlite_unicode => 1},
);
base_driver($driver);
install_model messages => schema {
key 'id';
column id  => int  => {auto_increment => 1};
column msg => char => {required       => 1};
column ts  => char => {required       => 1};
};
unless (-f $dbfile) {
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0})
or DBI->errstr;
for my $sql (__PACKAGE__->as_sqls) {
$dbh->do($sql) or die $dbh->errstr;
}
$dbh->disconnect;
}
package main;
use Mojolicious::Lite;
use Mojo::Util qw/md5_sum/;
app->secret(md5_sum $0 )->log->level('debug')->path(qq{$0.log})
->debug(app->secret);
app->helper(model => sub { my $dbh = DataModel->new });
get '/' => 'index';
get '/json' => sub {
my $self     = shift;
my $model    = $self->model;
my $messages = [
$model->get(
'messages' => {
where => [id  => {'>' => $self->param('from_id')}],
order => [{id => 'ASC'}],
}
)
];
my @json;
for my $msg (@{$messages}) {
push @json,
{ id  => $msg->id,
msg => $msg->msg,
ts  => $msg->ts,
};
}
$self->render(json => [@json]);
} => 'json';
post '/json' => sub {
my $self  = shift;
my $time  = time;
my $model = $self->model;
$model->set(
'messages' => {
msg => $self->param('msg'),    # jsonもparamで取れる
ts  => $time,
}
);
};
app->start;
__DATA__
@@ index.html.ep
% layout 'main';
%= javascript begin
jQuery(function($) {
$("#message").focus();
var params = $.extend({
refresh:5,
timer:0,
latest:0
},params);
var add_log = function(text){
$('#for_ajax').prepend("<p>" + text + "</p>");
};
var format_date = function(d){
var yyyy = d.getFullYear();
var mm = '0' + (d.getMonth() + 1);
var dd = '0' + d.getDate();
var hh = '0' + d.getHours();
var nn = '0' + d.getMinutes();
var ss = '0' + d.getSeconds();
return yyyy
+ '/' + mm.slice(-2)
+ '/' + dd.slice(-2)
+ ' ' + hh.slice(-2)
+ ':' + nn.slice(-2)
+ ':' + ss.slice(-2);
};
var reload_json = function(){
$.getJSON(
"<%= url_for 'json' %>",
{ 'from_id':params.latest },
function(json) {
$.each(json, function(i, val){
params.latest = val.id;
var latest = new Date();
latest.setTime(val.ts * 1000);
add_log(val.id + ". " + val.msg + " <small>" + format_date(latest) + "</small>");
});
clearTimeout(params.timer);// 念のためタイマーをリセット
params.timer = setTimeout(reload_json,params.refresh*1000);// 次回の実行はparams.refresh秒後
}
);
};
params.timer = setTimeout(reload_json,0);// 一回目実行
$("#msg_form").submit(function() {
if ( 0 < $("#message").val().length ) {
$.post("<%= url_for 'json' %>", {
'msg':$("#message").val(),
},
function(json) {
}, 'json');
$("#message").val('');
}
return false;
})
});
% end
<div>
<%= form_for '/' => (method => 'post', id => 'msg_form') => begin %>
<%= text_field 'msg' => (id => 'message') %>
<%= submit_button '発言する' %>
<% end %>
</div>
<div id="for_ajax"></div>
@@ layouts/main.html.ep
<!DOCTYPE html>
<html>
<head>
<meta charset="<%= app->renderer->encoding %>">
<title>Mojolicious</title>
%= javascript 'https://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'
</head>
<body><%= content %></body>
</html>

Comments

comments powered by Disqus