# rpc_client.rb require 'ffi-rzmq' require 'json' require 'securerandom' require 'timeout' ENDPOINT = "ipc:///tmp/zmq-rpc-demo" class RpcClient def initialize(endpoint, timeout_ms: 2000) @ctx = ZMQ::Context.new @req = @ctx.socket(ZMQ::REQ) @req.setsockopt(ZMQ::LINGER, 0) rc = @req.connect(endpoint) raise "connect failed: #{ZMQ::Util.error_string}" unless rc == 0 @poller = ZMQ::Poller.new @poller.register_readable(@req) @timeout = timeout_ms end def call(method, params=nil) id = SecureRandom.uuid payload = { jsonrpc: "2.0", id: id, method: method, params: params }.to_json @req.send_string(payload) # Wait for reply with timeout rc = @poller.poll(@timeout) raise Timeout::Error, "RPC timeout after #{@timeout}ms" if rc == 0 raw = '' @req.recv_string(raw) res = JSON.parse(raw) if res["error"] code = res["error"]["code"] msg = res["error"]["message"] data = res["error"]["data"] raise StandardError, "RPC error (#{code}): #{msg}#{data ? " | #{data}" : ""}" end raise "Mismatched id" if res["id"] != id res["result"] end def close @req.close @ctx.terminate end end