File Coverage

blib/lib/XAS/Lib/RPC/JSON/Server.pm
Criterion Covered Total %
statement 15 94 15.9
branch 0 20 0.0
condition n/a
subroutine 5 17 29.4
pod 4 4 100.0
total 24 135 17.7


line stmt bran cond sub pod time code
1             package XAS::Lib::RPC::JSON::Server;
2              
3             our $VERSION = '0.04';
4              
5 1     1   758 use POE;
  1         2  
  1         8  
6 1     1   254 use Try::Tiny;
  1         2  
  1         42  
7 1     1   4 use Set::Light;
  1         1  
  1         37  
8              
9             use XAS::Class
10 1         5 debug => 0,
11             version => $VERSION,
12             base => 'XAS::Lib::Net::Server',
13             utils => ':validation dotid',
14             accessors => 'methods',
15             codec => 'JSON',
16             constants => 'HASH ARRAY :jsonrpc ARRAYREF HASHREF',
17 1     1   3 ;
  1         1  
18              
19             my $ERRORS = {
20             '-32700' => 'Parse Error',
21             '-32600' => 'Invalid Request',
22             '-32601' => 'Method not Found',
23             '-32602' => 'Invalid Params',
24             '-32603' => 'Internal Error',
25             '-32099' => 'Server Error',
26             '-32001' => 'App Error',
27             };
28              
29 1     1   1073 use Data::Dumper;
  1         1  
  1         872  
30              
31             # ----------------------------------------------------------------------
32             # Public Methods
33             # ----------------------------------------------------------------------
34              
35             sub process_request {
36 0     0 1   my $self = shift;
37 0           my ($input, $ctx) = validate_params(\@_, [
38             1,
39             { type => HASHREF }
40             ]);
41              
42 0           my $request;
43 0           my $alias = $self->alias;
44              
45 0           $self->log->debug("$alias: entering process_request");
46 0           $self->log->debug(Dumper($input));
47              
48             try {
49              
50 0     0     $request = decode($input);
51              
52 0 0         if (ref($request) eq ARRAY) {
53              
54 0           foreach my $r (@$request) {
55              
56 0           $self->_rpc_request($r, $ctx);
57              
58             }
59              
60             } else {
61              
62 0           $self->_rpc_request($request, $ctx);
63              
64             }
65              
66             } catch {
67              
68 0     0     my $ex = $_;
69              
70 0           $self->log->error(Dumper($input));
71 0           $self->exception_handler($ex);
72              
73 0           };
74              
75             }
76              
77             sub process_response {
78 0     0 1   my $self = shift;
79 0           my ($output, $ctx) = validate_params(\@_, [
80             1,
81             { type => HASHREF }
82             ]);
83              
84 0           my $json;
85 0           my $alias = $self->alias;
86              
87 0           $self->log->debug("$alias: entering process_response");
88              
89 0           $json = $self->_rpc_result($ctx->{'id'}, $output);
90              
91 0           $poe_kernel->post($alias, 'client_output', encode($json), $ctx);
92              
93             }
94              
95             sub process_errors {
96 0     0 1   my $self = shift;
97 0           my ($error, $ctx) = validate_params(\@_, [
98             { type => HASHREF },
99             { type => HASHREF }
100             ]);
101              
102 0           my $json;
103 0           my $alias = $self->alias;
104              
105 0           $self->log->debug("$alias: entering process_errors");
106              
107 0           $json = $self->_rpc_error($ctx->{'id'}, $error->{'code'}, $error->{'message'});
108              
109 0           $poe_kernel->post($alias, 'client_output', encode($json), $ctx);
110              
111             }
112              
113             # ----------------------------------------------------------------------
114             # Private Methods
115             # ----------------------------------------------------------------------
116              
117             sub _rpc_exception_handler {
118 0     0     my $self = shift;
119 0           my ($ex, $id) = validate_params(\@_, [1,1]);
120              
121 0           my $packet;
122 0           my $ref = ref($ex);
123              
124 0 0         if ($ref) {
125              
126 0 0         if ($ex->isa('XAS::Exception')) {
127              
128 0           my $type = $ex->type;
129 0           my $info = $ex->info;
130              
131 0 0         if ($type =~ /server\.rpc_method$/) {
    0          
    0          
    0          
132              
133 0           $packet = $self->_rpc_error($id, RPC_ERR_METHOD, $info);
134              
135             } elsif ($type =~ /server\.rpc_version$/) {
136              
137 0           $packet = $self->_rpc_error($id, RPC_ERR_REQ, $info);
138              
139             } elsif ($type =~ /server\.rpc_format$/) {
140              
141 0           $packet = $self->_rpc_error($id, RPC_ERR_PARSE, $info);
142              
143             } elsif ($type =~ /server\.rpc_notify$/) {
144              
145 0           $packet = $self->_rpc_error($id, RPC_ERR_INTERNAL, $info);
146              
147             } else {
148              
149 0           my $msg = $type . ' - ' . $info;
150 0           $packet = $self->_rpc_error($id, RPC_ERR_APP, $msg);
151              
152             }
153              
154 0           $self->log->error_msg('exception', $type, $info);
155              
156             } else {
157              
158 0           my $msg = sprintf("%s", $ex);
159              
160 0           $packet = $self->_rpc_error($id, RPC_ERR_SERVER, $msg);
161 0           $self->log->error_msg('unexpected', $msg);
162              
163             }
164              
165             } else {
166              
167 0           my $msg = sprintf("%s", $ex);
168              
169 0           $packet = $self->_rpc_error($id, RPC_ERR_APP, $msg);
170 0           $self->log->error_msg('unexpected', $msg);
171              
172             }
173              
174 0           return $packet;
175              
176             }
177              
178             sub _rpc_request {
179 0     0     my $self = shift;
180 0           my ($request, $ctx) = validate_params(\@_, [
181             { type => HASHREF },
182             { type => HASHREF },
183             ]);
184              
185 0           my $method;
186 0           my $alias = $self->alias;
187            
188             try {
189              
190 0 0   0     if ($request->{'jsonrpc'} ne RPC_JSON) {
191              
192 0           $self->throw_msg(
193             dotid($self->class) . '.server.rpc_version',
194             'json_rpc_version'
195             );
196              
197             }
198              
199 0 0         unless (defined($request->{'id'})) {
200              
201 0           $self->throw_msg(
202             dotid($self->class) . '.server.rpc_notify',
203             'json_rpc_notify'
204             );
205              
206             }
207              
208 0 0         if ($self->methods->has($request->{'method'})) {
209              
210 0           $ctx->{'id'} = $request->{'id'};
211 0           $self->log->debug("$alias: performing \"" . $request->{'method'} . '"');
212              
213 0           $poe_kernel->post($alias, $request->{'method'}, $request->{'params'}, $ctx);
214              
215             } else {
216              
217             $self->throw_msg(
218             dotid($self->class) . '.server.rpc_method',
219             'json_rpc_method',
220 0           $request->{'method'}
221             );
222              
223             }
224              
225             } catch {
226              
227 0     0     my $ex = $_;
228              
229 0           my $output = $self->_rpc_exception_handler($ex, $request->{'id'});
230 0           $poe_kernel->post($alias, 'client_output', encode($output), $ctx);
231              
232 0           };
233              
234             }
235              
236             sub _rpc_error {
237 0     0     my $self = shift;
238 0           my ($id, $code, $message) = validate_params(\@_, [1,1,1]);
239              
240             return {
241             jsonrpc => RPC_JSON,
242             id => $id,
243             error => {
244             code => $code,
245 0           message => $ERRORS->{$code},
246             data => $message
247             }
248             };
249              
250             }
251              
252             sub _rpc_result {
253 0     0     my $self = shift;
254 0           my ($id, $result) = validate_params(\@_, [1,1]);
255              
256             return {
257 0           jsonrpc => RPC_JSON,
258             id => $id,
259             result => $result
260             };
261              
262             }
263              
264             sub init {
265 0     0 1   my $class = shift;
266              
267 0           my $self = $class->SUPER::init(@_);
268              
269 0           $self->{'methods'} = Set::Light->new();
270              
271 0           return $self;
272              
273             }
274              
275             1;
276              
277             __END__