package MojoX::JSON::RPC::Service; use Mojo::Base -base; { # Store rpc methods registered by register_rpc_method_names my $_rpcs = undef; sub new { my $class = shift; my $self = $class->SUPER::new(@_); # make shallow copy of class level rpcs if ( ref $_rpcs eq 'HASH' && exists $_rpcs->{$class} ) { $self->{_rpcs} = { %{ $_rpcs->{$class} } }; } return $self; } sub register_rpc_method_names { my ( $class, @methods ) = @_; METHOD: foreach my $m (@methods) { my $name = $class . '::' . $m; my $method = eval qq|*{*$name}{CODE}|; if ( ref $method ne 'CODE' ) { Carp::croak qq{register_rpc_method_names: $name not a method.}; } if ( exists $_rpcs->{$class}->{$m} ) { Carp::croak qq{register_rpc_method_names: $name already registered.}; } $_rpcs->{$class}->{$m} = { method => $method, with_svc_obj => 1 }; } return $class; } } sub register { my ( $self, $name, $sub, $options ) = @_; if ( !defined $name || $name eq q{} ) { Carp::croak 'name?'; } if ( ref $sub ne 'CODE' ) { Carp::croak qq{name[$name] code?}; } if ( exists $self->{_rpcs}->{$name} ) { Carp::croak qq{$name already registered}; } $options ||= {}; if ( ref $options ne 'HASH' ) { Carp::croak 'options?'; } my %obj = ( method => $sub ); OPTION: foreach my $opt ( 'with_mojo_tx', 'with_svc_obj' ) { if ( !exists $options->{$opt} ) { next OPTION; } $obj{$opt} = $options->{$opt}; } $self->{_rpcs}->{$name} = \%obj; return $self; } 1; __END__ =head1 NAME MojoX::JSON::RPC::Service - JSON RPC Service registration =head1 SYNOPSIS use MojoX::JSON::RPC::Service; my $svc = MojoX::JSON::RPC::Service->new; $svc->register( 'sum', sub { my @params = @_; my $sum = 0; $sum += $_ for @params; return $sum; } ); $svc->register( 'remote_address', sub { my $tx = shift; return $tx->remote_address; }, { with_mojo_tx => 1 } ); ## Then in Mojolicious application $self->plugin( 'json_rpc_dispatcher', services => { '/jsonrpc' => $svc, } ); This package can also be used as a base class to make it easy to create object-oriented JSON-RPC applications: package MyService; use Mojo::Base 'MojoX::JSON::RPC::Service'; sub sum { my ($self, @params) = @_; my $sum = 0; $sum += $_ for @params; return $sum; } __PACKAGE__->register_rpc_method_names( 'sum' ); ## Then in Mojolicious application $self->plugin( 'json_rpc_dispatcher', services => { '/jsonrpc' => MyService->new, } ); =head1 DESCRIPTION Register JSON-RPC service calls. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 C Register RPC methods. $svc->register( 'sum', sub { my @params = @_; my $sum = 0; $sum += $_ for @params; return $sum; } ); with_mojo_tx can be passed as options. In that case, L object will be pass as first argument of the subroutine. $svc->register( 'remote_address', sub { my $tx = shift; return $tx->remote_address; }, { with_mojo_tx => 1 } ); =head2 C Class method. Register a list of methods as JSON-RPC calls. __PACKAGE__->register_rpc_method_names( 'sum', 'multiply' ); =head1 SEE ALSO L =cut