Giter Site home page Giter Site logo

perl-mojo-websocketproxy's Introduction

perl-Mojo-WebSocketProxy

Build Status codecov

INSTALLATION

To install this module, run the following commands:

perl Makefile.PL
make
make test
make install

NAME

Mojo::WebSocketProxy - WebSocket proxy for JSON-RPC 2.0 server

SYNOPSYS

 # lib/your-application.pm

 use base 'Mojolicious';

 sub startup {
     my $self = shift;
     $self->plugin(
         'web_socket_proxy' => {
             actions => [
                 ['json_key', {some_param => 'some_value'}]
             ],
             base_path => '/api',
             url => 'http://rpc-host.com:8080/',
         }
     );
}

Or to manually call RPC server:

 # lib/your-application.pm

 use base 'Mojolicious';

 sub startup {
     my $self = shift;
     $self->plugin(
         'web_socket_proxy' => {
             actions => [
                 [
                     'json_key',
                     {
                         instead_of_forward => sub {
                             shift->call_rpc({
                                 args => $args,
                                 method => $rpc_method, # it'll call 'http://rpc-host.com:8080/rpc_method'
                                 rpc_response_cb => sub {...}
                             });
                         }
                     }
                 ]
             ],
             base_path => '/api',
             url => 'http://rpc-host.com:8080/',
         }
     );
}

DESCRIPTION

Using this module you can forward WebSocket-JSON requests to RPC server.

For every message it creates separate hash ref storage, which is available from hooks as $req_storage. Request storage have RPC call parameters in $req_storage->{call_params}. It copies message args to $req_storage->{call_params}->{args}. You can use Mojolicious stash to store data between messages in one connection.

Proxy responses

The plugin sends websocket messages to client with RPC response data. If RPC reponse looks like this:

{status => 1}

It returns simple response like this:

{$msg_type => 1, msg_type => $msg_type}

If RPC returns something like this:

{
    response_data => [..],
    status        => 1,
}

Plugin returns common response like this:

{
    $msg_type => $rpc_response,
    msg_type  => $msg_type,
}

You can customize ws porxy response using 'response' hook.

Sequence Diagram

Alt text

ws_proxy @startuml; title Websocket Proxy

participant Client

Client->Websocket:Initiate connection Client->Websocket:Send Message

note over Websocket: before_forward note over Websocket: instead_of_forward

Websocket->Websocket: instead_of_forward does not forward to rpc and returns response back from ws if its valid one

Websocket->Client: send response (only if instead_of_forward)

note over Websocket: before_call

Websocket->RPC: RPC request

note over Websocket: after_forward note over Websocket: after_dispatch

note over RPC: processing

note over Websocket: before_got_rpc_response

RPC->Websocket: RPC response

note over Websocket: after_got_rpc_response note over Websocket: success/error note over Websocket: response note over Websocket: before_send_api_response note over Websocket: send

Websocket->Client:send response back

note over Websocket: after_send_api_response

Client->Websocket:Close Websocket connection @enduml ws_proxy

Plugin parameters

The plugin understands the following parameters.

actions

A pointer to array of action details, which contain stash_params, request-response callbacks, other call parameters.

$self->plugin(
    'web_socket_proxy' => {
        actions => [
            ['action1_json_key', {details_key1 => details_value1}],
            ['action2_json_key']
        ]
    });
before_forward
before_forward => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Global hook which will run after request is dispatched and before to start preparing RPC call. It'll run every hook or until any hook returns some non-empty result. If returns any hash ref then that value will be JSON encoded and send to client, without forward action to RPC. To call RPC every hook should return empty or undefined value. It's good place to some validation or subscribe actions.

instead_of_forward (global)

instead_of_forward => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Use this hook if you don't want dispatcher to call RPC and want to handle request in websocket itself. It's not good practice to use it as global hook because if if you return response from sub passed then it will return same response for each call. Read more

before_call (global)

before_call => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Global hook which will run just before making rpc call.

after_forward (global)
after_forward => [sub { my ($c, $result, $req_storage) = @_; ... }, sub {...}]

Global hook which will run after every forwarded RPC call done. Or even forward action isn't running. It can view or modify result value from 'before_forward' hook. It'll run every hook or until any hook returns some non-empty result. If returns any hash ref then that value will be JSON encoded and send to client.

after_dispatch (global)
after_dispatch => [sub { my $c = shift; ... }, sub {...}]

Global hook which will run at the end of request handling.

before_get_rpc_response (global)
before_get_rpc_response => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Global hook which will run when asynchronous RPC call is answered.

after_got_rpc_response (global)
after_got_rpc_response => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Global hook which will run after checked that response exists.

before_send_api_response (global)
before_send_api_response => [sub { my ($c, $req_storage, $api_response) = @_; ... }, sub {...}]

Global hook which will run immediately before send API response.

after_sent_api_response (global)
before_send_api_response => [sub { my ($c, $req_storage) = @_; ... }, sub {...}]

Global hook which will run immediately after sent API response back to client.

base_path

API url for make route.

stream_timeout

See "timeout" in Mojo::IOLoop::Stream

max_connections

See "max_connections" in Mojo::IOLoop

max_response_size

Returns error if RPC response size is over value.

opened_connection

Callback for doing something once after connection is opened

finish_connection

Callback for doing something every time when connection is closed.

url

RPC host url - store url string or function to set url dynamically for manually RPC calls. When using forwarded call then url storing in request storage. You can store url in every action options, or make it at before_forward hook.

Actions options

stash_params
stash_params => [qw/ stash_key1 stash_key2 /]

Use this if you want to send specified parameters from Mojolicious $c->stash to RPC. RPC will receive this as part of call params.

You can store RPC response data to Mojolicious stash returning data like this:

rpc_response => {
    stash => {..} # data to store in Mojolicious stash
    response_key1 => response_value1, # response to API client
    response_key2 => response_value2
}
success
success => sub { my ($c, $rpc_response) = @_; ... }

Hook which will run if RPC returns success value.

error
error => sub { my ($c, $rpc_response) = @_; ... }

Hook which will run if RPC returns value with error key, e.g.

{ result => { error => { code => 'some_error' } } }
response
response => sub { my ($c, $rpc_response) = @_; ... }

Hook which will run every time when success or error callbacks is running. It good place to modify API response format.

Instead of forward

This hook is generally used if you don't want to forward request to RPC and want to handle it within websocket itself, for example like send back server time.

Another case where its useful is if you don't want to send response to rpc url provided in global scope and want to forward to separate RPC service (useful if you have multiple RPC service to handle different type of request)

 instead_of_forward => sub {
     shift->call_rpc({
         url  => 'some other rpc url',
         args => $args,
         method => $rpc_method, # it'll call 'http://rpc-host.com:8080/rpc_method'
         rpc_response_cb => sub {...}
     });

SEE ALSO

Mojolicious::Plugin::WebSocketProxy, Mojo::WebSocketProxy Mojo::WebSocketProxy::CallingEngine, Mojo::WebSocketProxy::Dispatcher, Mojo::WebSocketProxy::Config Mojo::WebSocketProxy::Parser

COPYRIGHT AND LICENSE

Copyright (C) 2016 binary.com

perl-mojo-websocketproxy's People

Contributors

4p00rv avatar aisha-deriv avatar aminmarashi avatar anthony-wong avatar chengyang-binary avatar chylli avatar chylli-deriv avatar denissafiullin-deriv avatar diego-deriv avatar evostrov avatar jy-deriv avatar kirill-deriv avatar leonerd avatar mat-fs avatar mehdi-deriv avatar michaelmueller-binary avatar mukesh-deriv avatar nael-binary avatar nihal-deriv avatar nima-fs avatar raunakkathuria avatar tom-binary avatar youssef-deriv avatar zakame avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

perl-mojo-websocketproxy's Issues

Tests fail (with newer Mojolicious versions?)

Most of my smokers report the following failure:

Mojo::Reactor::EV: I/O watcher failed: Can't locate object method "is_status_class" via package "Mojo::Message::Response" at /usr/perl5.16.3t/lib/site_perl/5.16.3/MojoX/JSON/RPC/Client.pm line 111.

    #   Failed test 'message received'
    #   at t/10-before_forward.t line 30.
    # Looks like you failed 1 test of 3.

#   Failed test 'w/o before-forward'
#   at t/10-before_forward.t line 34.
Can't use an undefined value as an ARRAY reference at t/10-before_forward.t line 31.
# Tests were run but no plan was declared and done_testing() was not seen.
# Looks like your test exited with 255 just after 1.
...(etc.)...

This seems to happen for Mojolicious 7.31 and newer:

****************************************************************
Regression 'mod:Mojolicious'
****************************************************************
Name           	       Theta	      StdErr	 T-stat
[0='const']    	      1.0000	      0.0000	27320188019381960.00
[1='eq_7.05']  	     -0.0000	      0.0000	  -1.75
[2='eq_7.30']  	     -0.0000	      0.0000	  -4.95
[3='eq_7.31']  	     -1.0000	      0.0000	-25130917837409580.00
[4='eq_7.32']  	     -1.0000	      0.0000	-24939805422496476.00

R^2= 1.000, N= 28, K= 5
****************************************************************

Undeclared dependency Path::Tiny

t/23-binary-frame.t fails if Path::Tiny is not installed

Can't locate Path/Tiny.pm in @INC (you may need to install the Path::Tiny module) (@INC contains: ... .) at t/23-binary-frame.t line 10.
BEGIN failed--compilation aborted at t/23-binary-frame.t line 10.
t/23-binary-frame.t ............... 
Dubious, test returned 2 (wstat 512, 0x200)
No subtests run 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.