Hobby-RPC is a simple RPC system for callable Ruby constants. It allows to expose them over HTTP safely, only to authorized users.
It is available on RubyGems as hobby-rpc.
Defining user roles
First, we need to define who the users are and what they can do. Otherwise, all the requests will return 403 Forbidden.
We can do this by creating at least one user role. A user role is a class that includes
Hobby::RPC::User and implements
#can? methods. For example:
class Client include Hobby::RPC::User # Accepts a `token`(String). # # Here we can look up at the place where we store active sessions. # It could be a Redis server mapping session tokens to users. # # Returns a user or nil(if a session for such token does not exist). def self.find_by_token token new if 'the token' == token end # Accepts a `function`(String). # # This determines what a user can do. A user will be allowed to call # `function` only when this method returns truthy value. # # One way to implement it is with Redis Sets: # https://redis.io/commands/sismember def can? function ['SomeFunction', 'SomeNamespace::SomeFunction'].include? function end
Client is the only role at the moment, but we can define as many as
we would like. The role names would be specific to the business logic
of your application.
An RPC function is a Ruby constant whose object implements
that can accept
input parameters. It can accept them either
as a Hash or as keyword arguments. For example:
module SomeFunction def self.call hash hash[:user] hash[:input] 'return any value serializable to JSON' end end module SomeNamespace module SomeFunction def self.call user:, input: 'return any value serializable to JSON' end end end
user would be an instance of a user role defined earlier.
Running a server
To start a server, we can use rackup. For that, we can put the
require 'hobby/rpc' run Hobby::RPC.new
Or we can use Puma directly as follows:
require 'hobby/rpc' require 'puma' server = Puma::Server.new Hobby::RPC.new server.add_tcp_listener '127.0.0.1', port server.run sleep
By default, it will return permissive CORS headers for requests from any origin. You can restrict the origins from which requests will be accepted as follows:
Hobby::RPC.new cors_origins: ['https://some.domain', 'https://another.domain']
To call RPC functions from browsers, you can use this client.
To work on
hobby-rpc itself, you can build the project and run the tests:
bundle exec rake