File Coverage

blib/lib/AnyEvent/JSONRPC/Lite/Server.pm
Criterion Covered Total %
statement 53 64 82.8
branch 9 16 56.2
condition 2 7 28.5
subroutine 13 15 86.6
pod 2 2 100.0
total 79 104 75.9


line stmt bran cond sub pod time code
1             package AnyEvent::JSONRPC::Lite::Server;
2 9     9   2560 use Any::Moose;
  9         19  
  9         68  
3              
4 9     9   4897 use Carp;
  9         23  
  9         676  
5 9     9   53 use Scalar::Util 'weaken';
  9         18  
  9         419  
6              
7 9     9   63 use AnyEvent::Handle;
  9         18  
  9         236  
8 9     9   48 use AnyEvent::Socket;
  9         25  
  9         1204  
9              
10 9     9   5196 use AnyEvent::JSONRPC::Lite::CondVar;
  9         640  
  9         2496  
11              
12             has address => (
13             is => 'ro',
14             isa => 'Maybe[Str]',
15             default => undef,
16             );
17              
18             has port => (
19             is => 'ro',
20             isa => 'Int|Str',
21             default => 4423,
22             );
23              
24             has server => (
25             is => 'rw',
26             isa => 'Object',
27             );
28              
29             has on_error => (
30             is => 'rw',
31             isa => 'CodeRef',
32             lazy => 1,
33             default => sub {
34             return sub {
35             my ($handle, $fatal, $message) = @_;
36             carp sprintf "Server got error: %s", $message;
37             };
38             },
39             );
40              
41             has on_eof => (
42             is => 'rw',
43             isa => 'CodeRef',
44             lazy => 1,
45             default => sub {
46             return sub { };
47             },
48             );
49              
50             has handler_options => (
51             is => 'ro',
52             isa => 'HashRef',
53             default => sub { {} },
54             );
55              
56             has _handlers => (
57             is => 'ro',
58             isa => 'ArrayRef',
59             default => sub { [] },
60             );
61              
62             has _callbacks => (
63             is => 'ro',
64             isa => 'HashRef',
65             lazy => 1,
66             default => sub { {} },
67             );
68              
69 9     9   56 no Any::Moose;
  9         18  
  9         46  
70              
71             sub BUILD {
72 8     8 1 21 my $self = shift;
73              
74             my $server = tcp_server $self->address, $self->port, sub {
75 7     7   716 my ($fh, $host, $port) = @_;
76 7         33 my $indicator = "$host:$port";
77              
78             my $handle = AnyEvent::Handle->new(
79             on_error => sub {
80 0         0 my ($h, $fatal, $msg) = @_;
81 0         0 $self->on_error->(@_);
82 0         0 $h->destroy;
83             },
84             on_eof => sub {
85 0         0 my ($h) = @_;
86             # client disconnected
87 0         0 $self->on_eof->(@_);
88 0         0 $h->destroy;
89             },
90 7         61 %{ $self->handler_options },
  7         75  
91             fh => $fh,
92             );
93             $handle->on_read(sub {
94             shift->unshift_read( json => sub {
95 12         847 $self->_dispatch($indicator, @_);
96 12         1051 }),
97 7         915 });
98              
99 7         328 $self->_handlers->[ fileno($fh) ] = $handle;
100 8         143 };
101 8         30013 $self->server($server);
102 8         44 weaken $self;
103              
104 8         50 $self;
105             }
106              
107             sub reg_cb {
108 6     6 1 112 my ($self, %callbacks) = @_;
109              
110 6         48 while (my ($method, $callback) = each %callbacks) {
111 6         55 $self->_callbacks->{ $method } = $callback;
112             }
113             }
114              
115             sub _dispatch {
116 12     12   30 my ($self, $indicator, $handle, $request) = @_;
117 12 50 33     127 return unless $request and ref $request eq 'HASH';
118              
119 12         52 my $target = $self->_callbacks->{ $request->{method} };
120              
121             # must response if id is exists
122 12 50       47 if (my $id = $request->{id}) {
123 12         33 $indicator = "$indicator:$id";
124              
125             my $res_cb = sub {
126 12     12   167 my $type = shift;
127 12 50       75 my $result = @_ > 1 ? \@_ : $_[0];
128              
129 12 100       215 $handle->push_write( json => {
    100          
    50          
130             id => $id,
131             result => $type eq 'result' ? $result : undef,
132             error => $type eq 'error' ? $result : undef,
133             }) if $handle;
134 12         56 };
135 12         40 weaken $handle;
136              
137 12         141 my $cv = AnyEvent::JSONRPC::Lite::CondVar->new;
138 12     12   214 $cv->_cb(sub { $res_cb->( $_[0]->recv ) });
  12         305  
139              
140 12   50 0   126 $target ||= sub { shift->error(qq/No such method "$request->{method}" found/) };
  0         0  
141 12 50       32 $target->( $cv, @{ $request->{params} || [] } );
  12         64  
142             }
143             else {
144             # without id parameter, this is notification.
145             # dispatch to method without cv object.
146 0   0 0     $target ||= sub { warn qq/No such method "$request->{method}" found/ };
  0            
147 0 0         $target->(undef, @{ $request->{params} || [] });
  0            
148             }
149             }
150              
151             __PACKAGE__->meta->make_immutable;
152              
153             __END__