App-Alice
view release on metacpan or search on metacpan
lib/App/Alice/HTTPD.pm view on Meta::CPAN
package App::Alice::HTTPD;
use AnyEvent;
use AnyEvent::HTTP;
use Twiggy::Server;
use Plack::Request;
use Plack::Builder;
use Plack::Middleware::Static;
use Plack::Session::Store::File;
use IRC::Formatting::HTML qw/html_to_irc/;
use App::Alice::Stream;
use App::Alice::Commands;
use JSON;
use Encode;
use utf8;
use Any::Moose;
use Try::Tiny;
has 'app' => (
is => 'ro',
isa => 'App::Alice',
required => 1,
);
has 'httpd' => (is => 'rw');
has 'ping_timer' => (is => 'rw');
has 'config' => (
is => 'ro',
isa => 'App::Alice::Config',
lazy => 1,
default => sub {shift->app->config},
);
my $url_handlers = [
[ qr{^/$} => \&send_index ],
[ qr{^/say/?$} => \&handle_message ],
[ qr{^/stream/?$} => \&setup_stream ],
[ qr{^/config/?$} => \&send_config ],
[ qr{^/prefs/?$} => \&send_prefs ],
[ qr{^/serverconfig/?$} => \&server_config ],
[ qr{^/save/?$} => \&save_config ],
[ qr{^/tabs/?$} => \&tab_order ],
[ qr{^/login/?$} => \&login ],
[ qr{^/logout/?$} => \&logout ],
[ qr{^/logs/?$} => \&send_logs ],
[ qr{^/search/?$} => \&send_search ],
[ qr{^/range/?$} => \&send_range ],
[ qr{^/view/?$} => \&send_index ],
[ qr{^/get} => \&image_proxy ],
];
sub url_handlers { return $url_handlers }
has 'streams' => (
is => 'rw',
auto_deref => 1,
isa => 'ArrayRef[App::Alice::Stream]',
default => sub {[]},
);
sub add_stream {push @{shift->streams}, @_}
sub no_streams {@{$_[0]->streams} == 0}
sub stream_count {scalar @{$_[0]->streams}}
sub BUILD {
my $self = shift;
my $httpd = Twiggy::Server->new(
host => $self->config->http_address,
port => $self->config->http_port,
);
$httpd->register_service(
builder {
if ($self->app->auth_enabled) {
mkdir $self->config->path."/sessions"
unless -d $self->config->path."/sessions";
enable "Session",
store => Plack::Session::Store::File->new(dir => $self->config->path),
expires => "24h";
}
enable "Static", path => qr{^/static/}, root => $self->config->assetdir;
sub {$self->dispatch(shift)}
}
);
$self->httpd($httpd);
$self->ping;
}
sub dispatch {
my ($self, $env) = @_;
my $req = Plack::Request->new($env);
if ($self->app->auth_enabled) {
unless ($req->path eq "/login" or $self->is_logged_in($req)) {
my $res = $req->new_response;
$res->redirect("/login");
return $res->finalize;
}
}
for my $handler (@{$self->url_handlers}) {
my $re = $handler->[0];
lib/App/Alice/HTTPD.pm view on Meta::CPAN
$writer->write(encode_utf8 $self->app->render('window_head', $window));
$window->buffer->with_messages(sub {
my @messages = @_;
$writer->write(encode_utf8 $_->{html}) for @messages;
}, 0, sub {
$writer->write(encode_utf8 $self->app->render('window_footer', $window));
$self->send_windows($writer, $cb, @windows);
});
}
}
sub send_logs {
my ($self, $req) = @_;
my $output = $self->app->render('logs');
my $res = $req->new_response(200);
$res->body(encode_utf8 $output);
return $res->finalize;
}
sub send_search {
my ($self, $req) = @_;
return sub {
my $respond = shift;
$self->app->history->search(
user => $self->app->user, %{$req->parameters}, sub {
my $rows = shift;
my $content = $self->app->render('results', $rows);
my $res = $req->new_response(200);
$res->body(encode_utf8 $content);
$respond->($res->finalize);
});
}
}
sub send_range {
my ($self, $req) = @_;
return sub {
my $respond = shift;
$self->app->history->range(
$self->app->user, $req->param('channel'), $req->param('id'), sub {
my ($before, $after) = @_;
$before = $self->app->render('range', $before, 'before');
$after = $self->app->render('range', $after, 'after');
my $res = $req->new_response(200);
$res->body(to_json [$before, $after]);
$respond->($res->finalize);
}
);
}
}
sub send_config {
my ($self, $req) = @_;
$self->app->log(info => "serving config");
my $output = $self->app->render('servers');
my $res = $req->new_response(200);
$res->body($output);
return $res->finalize;
}
sub send_prefs {
my ($self, $req) = @_;
$self->app->log(info => "serving prefs");
my $output = $self->app->render('prefs');
my $res = $req->new_response(200);
$res->body($output);
return $res->finalize;
}
sub server_config {
my ($self, $req) = @_;
$self->app->log(info => "serving blank server config");
my $name = $req->param('name');
$name =~ s/\s+//g;
my $config = $self->app->render('new_server', $name);
my $listitem = $self->app->render('server_listitem', $name);
my $res = $req->new_response(200);
$res->body(to_json({config => $config, listitem => $listitem}));
$res->header("Cache-control" => "no-cache");
return $res->finalize;
}
sub save_config {
my ($self, $req) = @_;
$self->app->log(info => "saving config");
my $new_config = {};
if ($req->parameters->{has_servers}) {
$new_config->{servers} = {};
}
for my $name (keys %{$req->parameters}) {
next unless $req->parameters->{$name};
next if $name eq "has_servers";
if ($name =~ /^(.+?)_(.+)/ and exists $new_config->{servers}) {
if ($2 eq "channels" or $2 eq "on_connect") {
$new_config->{servers}{$1}{$2} = [$req->parameters->get_all($name)];
} else {
$new_config->{servers}{$1}{$2} = $req->param($name);
}
}
elsif ($name eq "highlights") {
$new_config->{$name} = [$req->parameters->get_all($name)];
}
else {
$new_config->{$name} = $req->param($name);
}
}
$self->app->reload_config($new_config);
$self->app->broadcast(
$self->app->format_info("config", "saved")
);
my $res = $req->new_response(200);
$res->content_type('text/plain');
$res->content_length(2);
$res->body('ok');
return $res->finalize;
}
sub tab_order {
my ($self, $req) = @_;
( run in 1.290 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )