File Coverage

blib/lib/AnyEvent/JSONRPC/TCP/Server.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package AnyEvent::JSONRPC::TCP::Server;
2 1     1   621 use Moose;
  0            
  0            
3              
4             extends 'AnyEvent::JSONRPC::Server';
5              
6             use Carp;
7             use Scalar::Util 'weaken';
8              
9             use AnyEvent::Handle;
10             use AnyEvent::Socket;
11              
12             use AnyEvent::JSONRPC::InternalHandle;
13             use AnyEvent::JSONRPC::CondVar;
14             use JSON::RPC::Common::Procedure::Call;
15              
16             has address => (
17             is => 'ro',
18             isa => 'Maybe[Str]',
19             default => undef,
20             );
21              
22             has port => (
23             is => 'ro',
24             isa => 'Int|Str',
25             default => 4423,
26             );
27              
28             has on_error => (
29             is => 'rw',
30             isa => 'CodeRef',
31             lazy => 1,
32             default => sub {
33             return sub {
34             my ($handle, $fatal, $message) = @_;
35             carp sprintf "Server got error: %s", $message;
36             };
37             },
38             );
39              
40             has on_eof => (
41             is => 'rw',
42             isa => 'CodeRef',
43             lazy => 1,
44             default => sub {
45             return sub { };
46             },
47             );
48              
49             has handler_options => (
50             is => 'ro',
51             isa => 'HashRef',
52             default => sub { {} },
53             );
54              
55             has _handlers => (
56             is => 'ro',
57             isa => 'ArrayRef',
58             default => sub { [] },
59             );
60              
61             has methods => (
62             isa => 'HashRef[CodeRef]',
63             lazy => 1,
64             traits => ['Hash'],
65             handles => {
66             reg_cb => 'set',
67             method => 'get',
68             },
69             default => sub { {} },
70             );
71              
72             no Moose;
73              
74             sub BUILD {
75             my $self = shift;
76              
77             tcp_server $self->address, $self->port, sub {
78             my ($fh, $host, $port) = @_;
79             my $indicator = "$host:$port";
80              
81             my $handle = AnyEvent::Handle->new(
82             on_error => sub {
83             my ($h, $fatal, $msg) = @_;
84             $self->on_error->(@_);
85             $h->destroy;
86             },
87             on_eof => sub {
88             my ($h) = @_;
89             # client disconnected
90             $self->on_eof->(@_);
91             $h->destroy;
92             },
93             json => $self->json,
94             %{ $self->handler_options },
95             fh => $fh,
96             );
97             $handle->on_read(sub {
98             shift->unshift_read( json => sub {
99             $self->_dispatch($indicator, @_);
100             }),
101             });
102              
103             $self->_handlers->[ fileno($fh) ] = $handle;
104             };
105             weaken $self;
106              
107             $self;
108             }
109              
110             sub _dispatch {
111             my ($self, $indicator, $handle, $request) = @_;
112              
113             return $self->_batch($handle, @$request) if ref $request eq "ARRAY";
114             return unless $request and ref $request eq "HASH";
115              
116             my $call = JSON::RPC::Common::Procedure::Call->inflate($request);
117             my $target = $self->method( $call->method );
118              
119             my $cv = AnyEvent::JSONRPC::CondVar->new( call => $call );
120             $cv->cb( sub {
121             my $response = $cv->recv;
122              
123             $handle->push_write( json => $response->deflate ) if not $cv->is_notification;
124             });
125              
126             $target ||= sub { shift->error(qq/No such method "$request->{method}" found/) };
127             $target->( $cv, $call->params_list );
128             }
129              
130             sub _batch {
131             my ($self, $handle, @request) = @_;
132              
133             my @response;
134             for my $request (@request) {
135             my $internal = AnyEvent::JSONRPC::InternalHandle->new;
136              
137             $self->_dispatch(undef, $internal, $request);
138              
139             push @response, $internal;
140             }
141            
142             $handle->push_write( json => [ map { $_->recv } @response ] );
143             }
144              
145             __PACKAGE__->meta->make_immutable;
146              
147             __END__
148              
149             =for stopwords JSONRPC TCP TCP-based unix Str
150              
151             =head1 NAME
152              
153             AnyEvent::JSONRPC::TCP::Server - Simple TCP-based JSONRPC server
154              
155             =head1 SYNOPSIS
156              
157             use AnyEvent::JSONRPC::TCP::Server;
158            
159             my $server = AnyEvent::JSONRPC::TCP::Server->new( port => 4423 );
160             $server->reg_cb(
161             echo => sub {
162             my ($res_cv, @params) = @_;
163             $res_cv->result(@params);
164             },
165             sum => sub {
166             my ($res_cv, @params) = @_;
167             $res_cv->result( $params[0] + $params[1] );
168             },
169             );
170              
171             =head1 DESCRIPTION
172              
173             This module is server part of L<AnyEvent::JSONRPC>.
174              
175             =head1 METHOD
176              
177             =head1 new (%options)
178              
179             Create server object, start listening socket, and return object.
180              
181             my $server = AnyEvent::JSONRPC::TCP::Server->new(
182             port => 4423,
183             );
184              
185             Available C<%options> are:
186              
187             =over 4
188              
189             =item port => 'Int | Str'
190              
191             Listening port or path to unix socket (Required)
192              
193             =item address => 'Str'
194              
195             Bind address. Default to undef: This means server binds all interfaces by default.
196              
197             If you want to use unix socket, this option should be set to "unix/"
198              
199             =item on_error => $cb->($handle, $fatal, $message)
200              
201             Error callback which is called when some errors occurred.
202             This is actually L<AnyEvent::Handle>'s on_error.
203              
204             =item on_eof => $cb->($handle)
205              
206             EOF callback. same as L<AnyEvent::Handle>'s on_eof callback.
207              
208             =item handler_options => 'HashRef'
209              
210             Hashref options of L<AnyEvent::Handle> that is used to handle client connections.
211              
212             =back
213              
214             =head2 reg_cb (%callbacks)
215              
216             Register JSONRPC methods.
217              
218             $server->reg_cb(
219             echo => sub {
220             my ($res_cv, @params) = @_;
221             $res_cv->result(@params);
222             },
223             sum => sub {
224             my ($res_cv, @params) = @_;
225             $res_cv->result( $params[0] + $params[1] );
226             },
227             );
228              
229             =head3 callback arguments
230              
231             JSONRPC callback arguments consists of C<$result_cv>, and request C<@params>.
232              
233             my ($result_cv, @params) = @_;
234              
235             C<$result_cv> is L<AnyEvent::JSONRPC::CondVar> object.
236             Callback must be call C<< $result_cv->result >> to return result or C<< $result_cv->error >> to return error.
237              
238             If C<$result_cv-E<gt>is_notification()> returns true, this is a notify request
239             and the result will not be send to the client.
240              
241             C<@params> is same as request parameter.
242              
243             =head1 AUTHOR
244              
245             Daisuke Murase <typester@cpan.org>
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             Copyright (c) 2009 by KAYAC Inc.
250              
251             This program is free software; you can redistribute
252             it and/or modify it under the same terms as Perl itself.
253              
254             The full text of the license can be found in the
255             LICENSE file included with this module.
256              
257             =cut