Alice
view release on metacpan or search on metacpan
lib/Alice/HTTP/Server.pm view on Meta::CPAN
package Alice::HTTP::Server;
use AnyEvent;
use AnyEvent::HTTP;
use Fliggy::Server;
use Plack::Builder;
use Plack::Middleware::Static;
use Plack::Session::Store::File;
use Plack::Session::State::Cookie;
use Alice::HTTP::Request;
use Alice::HTTP::Stream::XHR;
use Alice::HTTP::Stream::WebSocket;
use JSON;
use Encode;
use Any::Moose;
has app => (
is => 'ro',
isa => 'Alice',
required => 1,
);
has httpd => (
is => 'rw',
lazy => 1,
builder => "_build_httpd",
);
has ping => (
is => 'rw',
lazy => 1,
default => sub {
my $self = shift;
AE::timer 1, 5, sub {
$self->app->ping;
};
},
);
has port => (
is => 'ro',
default => 8080,
);
has address => (
is => 'ro',
default => "127.0.0.1",
);
has session => (
is => 'ro'
);
has assets => (
is => 'ro',
required => 1,
);
my $url_handlers = [
[ "say" => "handle_message" ],
[ "stream" => "setup_xhr_stream" ],
[ "wsstream" => "setup_ws_stream" ],
[ "" => "send_index" ],
[ "safe" => "send_safe_index" ],
[ "tabs" => "tab_order" ],
[ "savetabsets" => "save_tabsets" ],
[ "serverconfig" => "server_config" ],
[ "save" => "save_config" ],
[ "login" => "login" ],
[ "logout" => "logout" ],
[ "export" => "export_config" ],
];
sub url_handlers { return $url_handlers }
sub BUILD {
my $self = shift;
$self->httpd;
$self->ping;
}
sub _build_httpd {
my $self = shift;
my $httpd;
# eval in case server can't bind port
eval {
$httpd = Fliggy::Server->new(
host => $self->address,
port => $self->port,
);
$httpd->register_service(
builder {
enable "Session",
store => $self->session,
state => Plack::Session::State::Cookie->new(expires => 60 * 60 * 24 * 7);
enable "Static", path => qr{^/static/}, root => $self->assets;
enable "+Alice::HTTP::WebSocket";
sub {
my $env = shift;
return sub {$self->dispatch($env, shift)}
}
}
);
};
AE::log(warn => $@) if $@;
return $httpd;
}
sub dispatch {
my ($self, $env, $cb) = @_;
my $req = Alice::HTTP::Request->new($env, $cb);
my $res = $req->new_response(200);
AE::log trace => $req->path;
if ($self->auth_enabled) {
unless ($req->path eq "/login" or $self->is_logged_in($req)) {
$self->auth_failed($req, $res);
return;
}
}
for my $handler (@{$self->url_handlers}) {
my $path = $handler->[0];
if ($req->path_info =~ /^\/$path\/?$/) {
my $method = $handler->[1];
$self->$method($req, $res);
return;
}
}
$self->template($req, $res);
}
sub auth_failed {
my ($self, $req, $res) = @_;
if ($req->path =~ m{^(/(?:safe)?)$}) {
$res->redirect("/login".($1 ? "?dest=$1" : ""));
$res->body("bai");
} else {
$res->status(401);
$res->body("unauthorized");
}
$res->send;
}
sub is_logged_in {
my ($self, $req) = @_;
my $session = $req->env->{"psgix.session"};
return $session->{is_logged_in};
}
sub login {
my ($self, $req, $res) = @_;
my $dest = $req->param("dest") || "/";
# no auth is required
if (!$self->auth_enabled) {
$res->redirect($dest);
$res->send;
}
# we have credentials
elsif (my $user = $req->param('username')
and my $pass = $req->param('password')) {
$self->authenticate($user, $pass, sub {
my $app = shift;
if ($app) {
$req->env->{"psgix.session"} = {
is_logged_in => 1,
( run in 1.112 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )