File Coverage

blib/lib/AnyEvent/JSONRPC/HTTP/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::HTTP::Server;
2 1     1   348 use Moose;
  0            
  0            
3              
4             extends 'AnyEvent::JSONRPC::Server';
5              
6             use Carp;
7             use Scalar::Util 'weaken';
8              
9             use AnyEvent::JSONRPC::CondVar;
10              
11             use AnyEvent::HTTPD;
12              
13             use JSON::XS;
14             use JSON::RPC::Common::Procedure::Call;
15              
16             has host => (
17             is => 'ro',
18             isa => 'Str',
19             default => '127.0.0.1',
20             );
21              
22             has port => (
23             is => 'ro',
24             isa => 'Int|Str',
25             default => 8080,
26             );
27              
28             has httpd => (
29             is => 'rw',
30             isa => 'AnyEvent::HTTPD',
31             predicate => 'has_httpd',
32             );
33              
34             has methods => (
35             isa => 'HashRef[CodeRef]',
36             lazy => 1,
37             traits => ['Hash'],
38             handles => {
39             reg_cb => 'set',
40             method => 'get',
41             },
42             default => sub { {} },
43             );
44              
45             no Moose;
46              
47             sub BUILD {
48             my $self = shift;
49              
50             unless ( $self->has_httpd ) {
51             $self->httpd( AnyEvent::HTTPD->new( host => $self->host, port => $self->port ) );
52             }
53              
54             $self->httpd->reg_cb(
55             request => sub {
56             my ($httpd, $req) = @_;
57              
58             my $request = eval { $self->json->decode( $req->content ) };
59              
60             unless (defined $request ) {
61             $req->respond( [ 400, 'Bad Request' ] );
62             warn "Bad content: [[[" . $req->content . "]]]" ;
63             $httpd->stop_request;
64             }
65              
66             my $response = $self->_dispatch( $request );
67              
68             if ($response) {
69             $req->respond( [ 200, 'Ok', { "Content-Type" => "application/json" }, $self->json->encode( $response ) ] );
70             } else {
71             $req->respond( [ 204, 'No Content' ] );
72             }
73              
74             $httpd->stop_request;
75             },
76             );
77              
78             $self;
79             }
80              
81             sub _dispatch {
82             my ($self, $request) = @_;
83              
84             return $self->_batch(@$request) if ref $request eq "ARRAY";
85             return unless $request and ref $request eq "HASH";
86              
87             my $call = JSON::RPC::Common::Procedure::Call->inflate($request);
88             my $target = $self->method( $call->method );
89              
90             my $cv = AnyEvent::JSONRPC::CondVar->new( call => $call );
91              
92             $target ||= sub { shift->error(qq/No such method "$request->{method}" found/) };
93             $target->( $cv, $call->params_list );
94              
95             return $cv->recv->deflate;
96             }
97              
98             sub _batch {
99             my ($self, @request) = @_;
100              
101             return [ map { $self->_dispatch($_) } @request ] ;
102             }
103              
104             __PACKAGE__->meta->make_immutable;
105              
106             __END__
107              
108             =for stopwords JSONRPC TCP TCP-based unix Str
109              
110             =head1 NAME
111              
112             AnyEvent::JSONRPC::HTTP::Server - Simple HTTP-based JSONRPC server
113              
114             =head1 SYNOPSIS
115              
116             use AnyEvent::JSONRPC::HTTP::Server;
117            
118             my $server = AnyEvent::JSONRPC::HTTP::Server->new( port => 8080 );
119             $server->reg_cb(
120             echo => sub {
121             my ($res_cv, @params) = @_;
122             $res_cv->result(@params);
123             },
124             sum => sub {
125             my ($res_cv, @params) = @_;
126             $res_cv->result( $params[0] + $params[1] );
127             },
128             );
129              
130             =head1 DESCRIPTION
131              
132             This module is server part of L<AnyEvent::JSONRPC>.
133              
134             =head1 METHOD
135              
136             =head1 new (%options)
137              
138             Create server object, start listening socket, and return object.
139              
140             my $server = AnyEvent::JSONRPC::HTTP::Server->new(
141             port => 4423,
142             );
143              
144             Available C<%options> are:
145              
146             =over 4
147              
148             =item host => 'Str'
149              
150             Bind address. Default to 'localhost'.
151              
152             If you want to use unix socket, this option should be set to "unix/"
153              
154             =item port => 'Int | Str'
155              
156             Listening port. Default to '8080'.
157              
158             =back
159              
160             =head2 reg_cb (%callbacks)
161              
162             Register JSONRPC methods.
163              
164             $server->reg_cb(
165             echo => sub {
166             my ($res_cv, @params) = @_;
167             $res_cv->result(@params);
168             },
169             sum => sub {
170             my ($res_cv, @params) = @_;
171             $res_cv->result( $params[0] + $params[1] );
172             },
173             );
174              
175             =head3 callback arguments
176              
177             JSONRPC callback arguments consists of C<$result_cv>, and request C<@params>.
178              
179             my ($result_cv, @params) = @_;
180              
181             C<$result_cv> is L<AnyEvent::JSONRPC::CondVar> object.
182             Callback must be call C<< $result_cv->result >> to return result or C<< $result_cv->error >> to return error.
183              
184             If C<$result_cv-E<gt>is_notification()> returns true, this is a notify request
185             and the result will not be send to the client.
186              
187             C<@params> is same as request parameter.
188              
189             =head1 SEE ALSO
190              
191             =over 4
192              
193             =item L<JSON::RPC::Dispatch>
194              
195             A server based on PSGI/L<Plack>. Quite more flexible than this module.
196              
197             =back
198              
199             =head1 AUTHOR
200              
201             Peter Makholm <peter@makholm.net>
202              
203             =head1 COPYRIGHT AND LICENSE
204              
205             Copyright (c) 2010 by Peter Makholm.
206              
207             This program is free software; you can redistribute
208             it and/or modify it under the same terms as Perl itself.
209              
210             The full text of the license can be found in the
211             LICENSE file included with this module.
212              
213             =cut