File Coverage

blib/lib/Mojo/WebSocketProxy/Backend/JSONRPC.pm
Criterion Covered Total %
statement 51 65 78.4
branch 5 16 31.2
condition 8 18 44.4
subroutine 10 10 100.0
pod 2 2 100.0
total 76 111 68.4


line stmt bran cond sub pod time code
1             package Mojo::WebSocketProxy::Backend::JSONRPC;
2              
3 17     17   99 use strict;
  17         36  
  17         457  
4 17     17   86 use warnings;
  17         35  
  17         426  
5              
6 17     17   92 use parent qw(Mojo::WebSocketProxy::Backend);
  17         65  
  17         137  
7              
8 17     17   1141 use feature qw(state);
  17         42  
  17         1350  
9              
10 17     17   100 no indirect;
  17         40  
  17         116  
11              
12 17     17   9390 use curry;
  17         4245  
  17         512  
13              
14 17     17   5884 use MojoX::JSON::RPC::Client;
  17         31802  
  17         104  
15              
16             our $VERSION = '0.13'; ## VERSION
17              
18             __PACKAGE__->register_type('jsonrpc');
19              
20 21     21 1 81 sub url { return shift->{url} }
21              
22             my $request_number = 0;
23              
24             =head2 call_rpc
25              
26             Description: Makes a remote call to a process returning the result to the client in JSON format.
27             Before, After and error actions can be specified using call backs.
28             It takes the following arguments
29              
30             =over 4
31              
32             =item - $c : L
33              
34             =item - $req_storage A hashref of attributes stored with the request. This routine uses some of the,
35             following named arguments.
36              
37             =over 4
38              
39             =item - url, if not specified url set on C<< $self >> object is used. Must be supplied by either method.
40              
41             =item - method, The name of the method at the remote end (this is appened to C<< $request_storage->{url} >> )
42              
43             =item - msg_type, a name for this method if not supplied C is used.
44              
45             =item - call_params, a hashref of arguments on top of C to send to remote method. This will be suplemented with C<< $req_storage->{args} >>
46             added as an C key and be merged with C<< $req_storage->{stash_params} >> with stash_params overwriting any matching
47             keys in C.
48              
49             =item - rpc_response_callback, If supplied this will be run with C<< Mojolicious::Controller >> instance the rpc_response and C<< $req_storage >>.
50             B if C<< rpc_response_callback >> is supplied the success and error callbacks are not used.
51              
52             =item - before_get_rpc_response, array ref of subroutines to run before the remote response, is passed C<< $c >> and C<< req_storage >>
53              
54             =item - after_get_rpc_response, arrayref of subroutines to run after the remote response, is passed C<< $c >> and C<< req_storage >>
55             called only when there is an actual response from the remote call . IE if there is communication error with the call it will
56             not be called versus an error message being returned from the call when it will.
57              
58             =item - before_call, arrayref of subroutines called before the request to the remote service is made.
59              
60             =item - error, a subroutine reference that will be called with C<< Mojolicious::Controller >> the rpc_response and C<< $req_storage >>
61             if a C<< $response->{error} >> error was returned from the remote call, and C<< $req_storage->{rpc_response_cb} >> was not passed.
62              
63             =item - success, a subroutines reference that will be called if there was no error returned from the remote call and C<< $req_storage->{rpc_response_cb} >> was not passed.
64              
65             =item - rpc_failure_cb, a sub routine reference to call if the remote call fails at a http level. Called with C<< Mojolicious::Controller >> the rpc_response and C<< $req_storage >>
66              
67             =back
68              
69             =back
70              
71             Returns undef.
72              
73             =cut
74              
75             sub call_rpc {
76 21     21 1 67 my ($self, $c, $req_storage) = @_;
77 21         210 state $client = MojoX::JSON::RPC::Client->new;
78              
79 21   33     177 my $url = $req_storage->{url} // $self->url;
80 21 50       62 die 'No url found' unless $url;
81              
82 21         62 $url .= $req_storage->{method};
83              
84 21         49 my $method = $req_storage->{method};
85 21   66     113 my $msg_type = $req_storage->{msg_type} ||= $req_storage->{method};
86              
87 21   50     145 $req_storage->{call_params} ||= {};
88              
89 21         117 my $rpc_response_cb = $self->get_rpc_response_cb($c, $req_storage);
90              
91 21   50     75 my $before_get_rpc_response_hook = delete($req_storage->{before_get_rpc_response}) || [];
92 21   50     72 my $after_got_rpc_response_hook = delete($req_storage->{after_got_rpc_response}) || [];
93 21   50     62 my $before_call_hook = delete($req_storage->{before_call}) || [];
94 21   50     108 my $rpc_failure_cb = delete($req_storage->{rpc_failure_cb}) || 0;
95              
96 21         789 my $callobj = {
97             # enough for short-term uniqueness
98             id => join('_', $$, $request_number++, time, (0 + [])),
99             method => $method,
100             params => $self->make_call_params($c, $req_storage),
101             };
102              
103 21         72 $_->($c, $req_storage) for @$before_call_hook;
104              
105             $client->call(
106             $url, $callobj,
107             $client->$curry::weak(
108             sub {
109 21     21   155080 my $client = shift;
110 21         44 my $res = pop;
111              
112 21         59 $_->($c, $req_storage) for @$before_get_rpc_response_hook;
113              
114             # unconditionally stop any further processing if client is already disconnected
115 21 50       78 return unless $c->tx;
116              
117 21         122 my $api_response;
118 21 50       83 if (!$res) {
119 0         0 my $tx = $client->tx;
120 0         0 my $details = 'URL: ' . $tx->req->url;
121 0 0       0 if (my $err = $tx->error) {
122 0   0     0 $details .= ', code: ' . ($err->{code} // 'n/a') . ', response: ' . $err->{message};
123             }
124 0         0 warn "WrongResponse [$msg_type], details: $details";
125 0 0       0 $rpc_failure_cb->($c, $res, $req_storage) if $rpc_failure_cb;
126 0         0 $api_response = $c->wsp_error($msg_type, 'WrongResponse', 'Sorry, an error occurred while processing your request.');
127 0         0 $c->send({json => $api_response}, $req_storage);
128 0         0 return;
129             }
130              
131 21         61 $_->($c, $req_storage, $res) for @$after_got_rpc_response_hook;
132              
133 21 50       100 if ($res->is_error) {
134 0         0 warn $res->error_message;
135 0 0       0 $rpc_failure_cb->($c, $res, $req_storage) if $rpc_failure_cb;
136 0         0 $api_response = $c->wsp_error($msg_type, 'CallError', 'Sorry, an error occurred while processing your request.');
137 0         0 $c->send({json => $api_response}, $req_storage);
138 0         0 return;
139             }
140              
141 21         619 $api_response = $rpc_response_cb->($res->result);
142              
143 21 50       79 return unless $api_response;
144              
145 21         578 $c->send({json => $api_response}, $req_storage);
146              
147 21         124 return;
148 21         179 }));
149 21         14998 return;
150             }
151              
152             1;
153              
154             __END__