#!perl use warnings; use strict; use JSON::XS; use EV; use Scalar::Util qw/weaken/; use HTML::Entities qw/encode_entities/; use URI::Escape qw/uri_unescape/; my $clients = 0; my @handles; my @timers; my @html_hdrs = ( 'Content-Type' => 'text/html; charset=UTF-8', 'Cache-Control' => 'no-cache, no-store, private', 'Pragma' => 'no-cache', ); sub show_chat { my ($r,$client) = @_; $r->send_response(200, \@html_hdrs, < Chat! EOHTML } sub show_form { my ($r, $client, $nick) = @_; $r->send_response(200, \@html_hdrs, < Chat!
Nick:
Say:
EOHTML } sub start_stream { my ($r, $client) = @_; my $w = $r->start_streaming(200, \@html_hdrs); $handles[$client] = $w; weaken $w; $timers[$client] = EV::timer 1,1,sub { $w->write('') if $w; }; $w->write(<

Hello! (connection $client)

EOH } sub broadcast { my $kv = shift; my $client = $kv->{client}; $kv->{nick} ||= "anon$client"; $kv->{nick} = encode_entities(uri_unescape($kv->{nick})); $kv->{say} ||= '*wants to say something*'; $kv->{say} = encode_entities(uri_unescape($kv->{say})); my $msg = \"

$kv->{nick}: $kv->{say}

"; warn $$msg."\n"; for my $i (1 .. $clients) { my $w = $handles[$i]; next unless $w; eval { $w->write($msg) }; if ($@) { warn $@; $handles[$i] = undef } } } my $app = sub { my $r = shift; my $env = $r->env; my $path = $env->{PATH_INFO}; if ($path eq '/post' && $env->{REQUEST_METHOD} eq 'POST') { my $input = delete $env->{'psgi.input'}; my $body = ''; $input->read($body, $env->{CONTENT_LENGTH}); my %kv = map { split('=',$_,2) } split('&',$body); my $t; $t = EV::timer 0.00001, 0, sub{ broadcast(\%kv); undef $t; }; show_form($r,$kv{client},$kv{nick}); } elsif ($path =~ m{^/form/(\d+)$}) { my $client = $1; show_form($r,$client,''); } elsif ($path =~ m{^/chat/(\d+)$}) { my $client = $1; start_stream($r,$client); } else { my $client = ++$clients; show_chat($r,$client); } };