From e26179af9aaf7cae5a0aa68ad87a50e4b1e1aba5 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Tue, 3 Jan 2012 19:38:03 -0700 Subject: [PATCH] add comet support for real-time chatting --- db/schema.sql | 11 --- lib/Chatty/Controller/Chat.pm | 32 ++----- lib/Chatty/Form/MessageCreate.pm | 13 --- lib/Chatty/Model/DB.pm | 2 +- lib/Chatty/Schema.pm | 7 +- lib/Chatty/Schema/Result/Account.pm | 73 +++++++++------- lib/Chatty/Schema/Result/Message.pm | 124 ---------------------------- lib/Chatty/Schema/Result/Room.pm | 66 ++++++++++----- root/tt/chat/view.tt | 43 ++++++++-- root/tt/wrapper.tt | 1 + 10 files changed, 141 insertions(+), 231 deletions(-) delete mode 100644 lib/Chatty/Form/MessageCreate.pm delete mode 100644 lib/Chatty/Schema/Result/Message.pm diff --git a/db/schema.sql b/db/schema.sql index 536b1f3..dfd06e3 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -15,14 +15,3 @@ CREATE TABLE account ( current_room INTEGER REFERENCES room(id) ); -CREATE TABLE message ( - id INTEGER PRIMARY KEY, - posted TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - author INTEGER REFERENCES account(id), - room INTEGER REFERENCES room(id), - content TEXT -); - -INSERT INTO account (username, password) VALUES ('chaz', 'mypass'); -INSERT INTO account (username, password) VALUES ('jdoe', 'foobar'); - diff --git a/lib/Chatty/Controller/Chat.pm b/lib/Chatty/Controller/Chat.pm index 73fe274..911c127 100644 --- a/lib/Chatty/Controller/Chat.pm +++ b/lib/Chatty/Controller/Chat.pm @@ -7,7 +7,6 @@ BEGIN { extends 'Catalyst::Controller' } #__PACKAGE__->config(namespace => 'room'); use Chatty::Form::RoomCreate; -use Chatty::Form::MessageCreate; has 'roomcreate_form' => ( isa => 'Chatty::Form::RoomCreate', @@ -16,13 +15,6 @@ has 'roomcreate_form' => ( default => sub { Chatty::Form::RoomCreate->new } ); -has 'messagecreate_form' => ( - isa => 'Chatty::Form::MessageCreate', - is => 'rw', - lazy => 1, - default => sub { Chatty::Form::MessageCreate->new } -); - =head1 NAME Chatty::Controller::Chat - Catalyst Controller @@ -100,27 +92,17 @@ sub view :Chained(room) :PathPart('') :Args(1) { $c->stash(room => $c->model('DB::Room')->find($room)); $c->detach('/missing') if !$c->stash->{room}; - $c->stash(messages => [$c->model('DB::Message')->search(room => $room)]); - - $c->stash(form => $self->messagecreate_form); + my $name = $c->user->obj->username; - my $new_message = $c->model('DB::Message')->new_result({ - author => $c->user->obj->id, - room => $c->stash->{room}->id - }); - $self->messagecreate_form->process( - item => $new_message, - params => $c->req->params - ); - - if (!$self->messagecreate_form->is_valid) { - if ($c->req->method eq 'POST') { - $c->stash->{error} = "The form has a validation error. Try again..."; - } + my $msg = $c->req->param('msg'); + if ($msg) { + $c->model('Meteor')->addMessage($room, "$name: $msg"); + $c->stash->{json} = \1; + $c->forward('View::JSON'); return; } - $c->res->redirect($c->uri_for_action('/chat/view', $c->stash->{room}->id)); + $c->model('Meteor')->addMessage($room, "** $name has entered **"); } =head1 AUTHOR diff --git a/lib/Chatty/Form/MessageCreate.pm b/lib/Chatty/Form/MessageCreate.pm deleted file mode 100644 index 72b616e..0000000 --- a/lib/Chatty/Form/MessageCreate.pm +++ /dev/null @@ -1,13 +0,0 @@ -package Chatty::Form::MessageCreate; - -use HTML::FormHandler::Moose; -extends 'HTML::FormHandler::Model::DBIC'; -use namespace::autoclean; - -has '+item_class' => (default => 'Message'); - -has_field 'content' => (input_class => 'validate[required]', label => 'Message', required => 1); -has_field 'submit' => (type => 'Submit', value => 'Create'); - -__PACKAGE__->meta->make_immutable; -1; diff --git a/lib/Chatty/Model/DB.pm b/lib/Chatty/Model/DB.pm index 91b1c19..82b4e94 100644 --- a/lib/Chatty/Model/DB.pm +++ b/lib/Chatty/Model/DB.pm @@ -28,7 +28,7 @@ L Model using schema L =head1 GENERATED BY -Catalyst::Helper::Model::DBIC::Schema - 0.55 +Catalyst::Helper::Model::DBIC::Schema - 0.59 =head1 AUTHOR diff --git a/lib/Chatty/Schema.pm b/lib/Chatty/Schema.pm index 3d5ca2d..885c67b 100644 --- a/lib/Chatty/Schema.pm +++ b/lib/Chatty/Schema.pm @@ -1,17 +1,18 @@ +use utf8; package Chatty::Schema; # Created by DBIx::Class::Schema::Loader # DO NOT MODIFY THE FIRST PART OF THIS FILE use Moose; -use namespace::autoclean; +use MooseX::MarkAsMethods autoclean => 1; extends 'DBIx::Class::Schema'; __PACKAGE__->load_namespaces; -# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-10-12 22:19:43 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:cnsy0B+9E32Gp6UQcsNpuA +# Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-03 16:46:04 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Kti71GT2ETr1GjBJljQ1Zg # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/lib/Chatty/Schema/Result/Account.pm b/lib/Chatty/Schema/Result/Account.pm index 60b33b1..cedd0ae 100644 --- a/lib/Chatty/Schema/Result/Account.pm +++ b/lib/Chatty/Schema/Result/Account.pm @@ -1,21 +1,36 @@ +use utf8; package Chatty::Schema::Result::Account; # Created by DBIx::Class::Schema::Loader # DO NOT MODIFY THE FIRST PART OF THIS FILE +=head1 NAME + +Chatty::Schema::Result::Account + +=cut + use strict; use warnings; use Moose; use MooseX::NonMoose; -use namespace::autoclean; +use MooseX::MarkAsMethods autoclean => 1; extends 'DBIx::Class::Core'; -__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp"); +=head1 COMPONENTS LOADED -=head1 NAME +=over 4 -Chatty::Schema::Result::Account +=item * L + +=back + +=cut + +__PACKAGE__->load_components("InflateColumn::DateTime"); + +=head1 TABLE: C =cut @@ -29,11 +44,6 @@ __PACKAGE__->table("account"); is_auto_increment: 1 is_nullable: 0 -=head2 email - - data_type: 'text' - is_nullable: 1 - =head2 username data_type: 'text' @@ -61,8 +71,6 @@ __PACKAGE__->table("account"); __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "email", - { data_type => "text", is_nullable => 1 }, "username", { data_type => "text", is_nullable => 1 }, "password", @@ -72,7 +80,31 @@ __PACKAGE__->add_columns( "current_room", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, ); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + __PACKAGE__->set_primary_key("id"); + +=head1 UNIQUE CONSTRAINTS + +=head2 C + +=over 4 + +=item * L + +=back + +=cut + __PACKAGE__->add_unique_constraint("username_unique", ["username"]); =head1 RELATIONS @@ -97,24 +129,9 @@ __PACKAGE__->belongs_to( }, ); -=head2 messages - -Type: has_many - -Related object: L - -=cut - -__PACKAGE__->has_many( - "messages", - "Chatty::Schema::Result::Message", - { "foreign.author" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, -); - -# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-10-17 20:21:50 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jbeLiaDPsjHNHj5O11tPFA +# Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-03 16:58:35 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vESFaWXuN0WYXW2Y18BfRg # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/lib/Chatty/Schema/Result/Message.pm b/lib/Chatty/Schema/Result/Message.pm deleted file mode 100644 index 78a7441..0000000 --- a/lib/Chatty/Schema/Result/Message.pm +++ /dev/null @@ -1,124 +0,0 @@ -package Chatty::Schema::Result::Message; - -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - -use strict; -use warnings; - -use Moose; -use MooseX::NonMoose; -use namespace::autoclean; -extends 'DBIx::Class::Core'; - -__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp"); - -=head1 NAME - -Chatty::Schema::Result::Message - -=cut - -__PACKAGE__->table("message"); - -=head1 ACCESSORS - -=head2 id - - data_type: 'integer' - is_auto_increment: 1 - is_nullable: 0 - -=head2 posted - - data_type: 'timestamp' - default_value: current_timestamp - is_nullable: 1 - -=head2 author - - data_type: 'integer' - is_foreign_key: 1 - is_nullable: 1 - -=head2 room - - data_type: 'integer' - is_foreign_key: 1 - is_nullable: 1 - -=head2 content - - data_type: 'text' - is_nullable: 1 - -=cut - -__PACKAGE__->add_columns( - "id", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "posted", - { - data_type => "timestamp", - default_value => \"current_timestamp", - is_nullable => 1, - }, - "author", - { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, - "room", - { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, - "content", - { data_type => "text", is_nullable => 1 }, -); -__PACKAGE__->set_primary_key("id"); - -=head1 RELATIONS - -=head2 room - -Type: belongs_to - -Related object: L - -=cut - -__PACKAGE__->belongs_to( - "room", - "Chatty::Schema::Result::Room", - { id => "room" }, - { - is_deferrable => 1, - join_type => "LEFT", - on_delete => "CASCADE", - on_update => "CASCADE", - }, -); - -=head2 author - -Type: belongs_to - -Related object: L - -=cut - -__PACKAGE__->belongs_to( - "author", - "Chatty::Schema::Result::Account", - { id => "author" }, - { - is_deferrable => 1, - join_type => "LEFT", - on_delete => "CASCADE", - on_update => "CASCADE", - }, -); - - -# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-10-17 20:21:50 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:R28y3tHGM5FZTILUAO/0XA - - -# You can replace this text with custom code or comments, and it will be preserved on regeneration -__PACKAGE__->meta->make_immutable; -1; diff --git a/lib/Chatty/Schema/Result/Room.pm b/lib/Chatty/Schema/Result/Room.pm index 53516f3..2ba8652 100644 --- a/lib/Chatty/Schema/Result/Room.pm +++ b/lib/Chatty/Schema/Result/Room.pm @@ -1,21 +1,36 @@ +use utf8; package Chatty::Schema::Result::Room; # Created by DBIx::Class::Schema::Loader # DO NOT MODIFY THE FIRST PART OF THIS FILE +=head1 NAME + +Chatty::Schema::Result::Room + +=cut + use strict; use warnings; use Moose; use MooseX::NonMoose; -use namespace::autoclean; +use MooseX::MarkAsMethods autoclean => 1; extends 'DBIx::Class::Core'; -__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp"); +=head1 COMPONENTS LOADED -=head1 NAME +=over 4 -Chatty::Schema::Result::Room +=item * L + +=back + +=cut + +__PACKAGE__->load_components("InflateColumn::DateTime"); + +=head1 TABLE: C =cut @@ -54,7 +69,31 @@ __PACKAGE__->add_columns( is_nullable => 1, }, ); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + __PACKAGE__->set_primary_key("id"); + +=head1 UNIQUE CONSTRAINTS + +=head2 C + +=over 4 + +=item * L + +=back + +=cut + __PACKAGE__->add_unique_constraint("name_unique", ["name"]); =head1 RELATIONS @@ -74,24 +113,9 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); -=head2 messages - -Type: has_many - -Related object: L - -=cut - -__PACKAGE__->has_many( - "messages", - "Chatty::Schema::Result::Message", - { "foreign.room" => "self.id" }, - { cascade_copy => 0, cascade_delete => 0 }, -); - -# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-10-17 20:21:50 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:U0zHyxd2zFVEnATmgpd+Ag +# Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-03 16:46:51 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:36bNroQtVWZPWUMc+6yAQw # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/root/tt/chat/view.tt b/root/tt/chat/view.tt index 19fe0c0..5804093 100644 --- a/root/tt/chat/view.tt +++ b/root/tt/chat/view.tt @@ -1,9 +1,42 @@ [% META title = 'Live' -%] +[% BLOCK js_include -%] + +[% END -%] [% BLOCK js -%] -$('form').validationEngine(); + Meteor.hostid = '' + Math.floor(999*Math.random()); + Meteor.host = "data."+location.hostname; + Meteor.registerEventCallback("process", addMessage); + Meteor.registerEventCallback("eof", function() { + addMessage("** stream closed **"); + }); + Meteor.registerEventCallback("reset", function() { + addMessage("** stream reset **"); + }); + Meteor.registerEventCallback("changemode", function(mode) { + addMessage("** mode changed to "+mode+" **"); + }); + Meteor.joinChannel("[% room.id %]", 5); + Meteor.mode = 'stream'; + Meteor.connect(); + + function addMessage(line) { + $("#chat").append("

"+line+"

"); + $("#chat").stop().animate({scrollTop:$("#chat").prop("scrollHeight")}, 350); + }; + + $("#submit").click(function(e) { + $.getJSON("", {msg: $("#msg").val()}, + function(data) { + }); + $("#msg").val(""); + e.preventDefault(); + }); + $("#msg").focus(); [% END -%]

Room: [% room.name %]

-[% FOREACH msg IN messages -%] -

[% msg.author.username %] ([% msg.posted %]): [% msg.content %]

-[% END -%] -[% form.render -%] +
+
+ Say your thing: + + + diff --git a/root/tt/wrapper.tt b/root/tt/wrapper.tt index 87d5106..82e3403 100644 --- a/root/tt/wrapper.tt +++ b/root/tt/wrapper.tt @@ -43,6 +43,7 @@ +[% TRY; INCLUDE js_include; CATCH; ''; END -%]