package Tapir::Server; =head1 NAME Tapir::Server - An API server =head1 DESCRIPTION Mainly subclassed, this offers a base class for any implementation of the API. =cut use Moose; use Params::Validate; use Carp; use Data::Dumper; use Try::Tiny; use Tapir::Logger; sub is_valid_request { my ($self, %opt) = @_; return { }; } # User specified arguments has 'thrift_file' => (is => 'ro', required => 1); has 'handlers' => (is => 'ro', default => sub { [] }); has 'transports' => (is => 'ro', default => sub { [] }); has 'logger' => (is => 'ro', lazy_build => 1); sub add_handler { my $self = shift; my %opt = validate(@_, { class => 1, }); eval "require $opt{class}"; if ($@) { croak "Failed to load class $opt{class}: $@"; } my $service = $opt{class}->service; if (! $service) { croak "Class $opt{class} doesn't define a service"; } my %methods = %{ $opt{class}->methods }; if (! %methods) { croak "Class $opt{class} doesn't define any methods"; } push @{ $self->handlers }, { class => $opt{class}, service => $service, methods => \%methods, }; } sub add_transport { my $self = shift; my %opt = validate(@_, { class => 1, options => { default => {} }, }); eval "require $opt{class}"; if ($@) { croak "Failed to load class $opt{class}: $@"; } my $transport; try { $transport = $opt{class}->new( server => $self, logger => $self->logger, %{ $opt{options} } ); $transport->setup(); } catch { croak "Failed to load class $opt{class}: $_"; }; push @{ $self->transports }, $transport; } sub run { my $self = shift; if (! int @{ $self->transports }) { croak "Can't run() without any transports defined"; } $_->run() foreach @{ $self->transports }; } sub _build_logger { my $self = shift; return Tapir::Logger->new(screen => 1); } 1;