Ccrpc - A minimalistic RPC library for Ruby
Features:
- Simple human readable wire protocol
- Works on arbitrary ruby IO objects (Pipes, Sockets, STDIN, STDOUT) even Windows CR/LF converting IOs
- No object definitions - only plain string transfers (so no issues with undefined classes or garbage collection like in DRb)
- Each call transfers a function name and a list of parameters in form of a Hash<String=>String>
- Each response equally transfers a list of parameters
- Similar to closures, it's possible to respond to a particular call as a call_back
- Fully asynchronous, either by use of multiple threads or by using lazy_answers, so that arbitrary calls in both directions can be mixed simultaneously without blocking each other
- Fully thread safe, but doesn't use additional internal threads
- Each call_back arrives in the thread of the caller
- Only dedicated functions can be called (not arbitrary as in DRb)
- No dependencies
Installation
Add this line to your application's Gemfile:
gem 'ccrpc'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install ccrpc
Usage
Fork a subprocess and communicate with it through pipes
require 'ccrpc'
ar, aw = IO.pipe
br, bw = IO.pipe
fork do
ar.close; bw.close
rpc = Ccrpc::RpcConnection.new(br, aw)
rpc.call do |call|
pp func: call.func, params: call.params
{my_answer: 'hello back'}
end
end
br.close; aw.close
rpc = Ccrpc::RpcConnection.new(ar, bw)
pp rpc.call(:hello, who: 'world')
Communicate with a subprocess through STDIN and STDOUT.
Since STDIN and STDOUT are used for the RPC connection, it's best zu redirect STDOUT to STDERR after the RPC object is created.
This avoids clashes between "p" calls and the RPC protocol.
The following example invokes the call in the opposite direction, from the subprocess to the main process.
require 'ccrpc'
code = <<-EOT
require 'ccrpc'
# Create the receiver side of the connection
# Use a copy of STDOUT because...
rpc = Ccrpc::RpcConnection.new(STDIN, STDOUT.dup)
# .. STDOUT is now redirected to STDERR, so that pp prints to STDERR
STDOUT.reopen(STDERR)
# Call function "hello" with param {"who" => "world"}
pp rpc.call(:hello, who: 'world') # => {"my_answer"=>"hello back"}
EOT
tf = Tempfile.new('rpc')
tf.write(code)
tf.flush
io = IO.popen(['ruby', tf.path], "w+")
rpc = Ccrpc::RpcConnection.new(io, io)
rpc.call do |call|
pp func: call.func, params: call.params
{my_answer: 'hello back'}
end
Full API documentation is here: https://rubydoc.info/gems/ccrpc
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/larskanis/ccrpc.
License
The gem is available as open source under the terms of the MIT License.