#!/usr/bin/perl # "HTTP Push" is not readily attainable, so instead we will simulate it using a # long-pull, aka "Comet". The client browser simply opens an HTTP connection to # the server and waits for a response. The server doesn't respond until there # is some event (here a new message), giving the appearance of HTTP-push. # # Each user gets three continuations for these three cases: # # - Initial load or reload of the page # - Sending a message (uses AJAX on the client) # - Recieving messages (uses COMET on the client) use strict; use lib '../lib'; use Continuity; my @messages; # Global (shared) list of messages my $got_message; # Flag to indicate that there is a new message to display my $server = Continuity->new( port => 16001, path_session => 1, cookie_session => 'sid', ); $server->loop; # This is the main entrypoint. We are looking for one of three things -- a # pushstream, a sent message, or a request for the main HTML. We delegate each # of these cases, none of which will return (they all loop forever). sub main { my ($req) = @_; my $path = $req->request->url->path; print STDERR "Path: '$path'\n"; # If this is a request for the pushtream, then give them that if($path =~ /pushstream/) { pushstream($req); } # If they are sending us a message, we give them a thread for that too if($path =~ /sendmessage/) { send_message($req); } # Otherwise, lets give them the base page send_base_page($req); } # Here we accept a connection to the browser, and keep it open. Meanwhile we # watch the global $got_message variable, and when it gets touched we send off # the list of messages through the held-open connection. Then we let the # browser open a new connection and begin again. sub pushstream { my ($req) = @_; # Set up watch event -- this will be triggered when $got_message is written my $w = Coro::Event->var(var => \$got_message, poll => 'w'); while(1) { print STDERR "**** GOT MESSAGE, SENDING ****\n"; my $log = join "
", @messages; $req->print($log); $req->next; print STDERR "**** Waiting for got_message indicator ****\n"; $w->next; } } # Watch for the user to send us a message. As soon as we get it, we add it to # our list of messages and touch the $got_message flag to let all the # pushstreams know. sub send_message { my ($req) = @_; while(1) { my $msg = $req->param('message'); my $name = $req->param('username'); if($msg) { unshift @messages, "$name: $msg"; pop @messages if $#messages > 15; # Only keep the recent 15 messages } $got_message = 1; $req->print("Got it!"); $req->next; } } # This isn't a pushstream, nor a new message. It is just the main page. We loop # in case they ask for it multiple times :) sub send_base_page { my ($req) = @_; while(1) { $req->print(qq{ Chat!

-- no messages yet --
}); $req->next; } }