Created
January 31, 2018 23:09
-
-
Save ahoward/63e0b925d6e984155e77a34ce3d927a5 to your computer and use it in GitHub Desktop.
all the ruby json rpc gems suck so i made this teeny one. put it in lib/json_rpc.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ref: http://www.jsonrpc.org/specification | |
# | |
# stdlibs | |
# | |
require 'net/http' | |
# gems | |
# | |
require 'addressable/uri' | |
require 'json' | |
require 'map' | |
require 'fattr' | |
require 'logger' | |
require 'timeout' | |
require 'openssl' | |
require 'securerandom' | |
# | |
Object.send(:remove_const, :JsonRPC) if defined?(JsonRPC) | |
# | |
class JsonRPC | |
# | |
class Error < ::StandardError | |
fattr(:raw) | |
def message | |
[super, raw].compact.join("\n\n@raw:\n\n") | |
end | |
end | |
# | |
class Client | |
def initialize(url, *args, &block) | |
@uri = Addressable::URI.parse(url.to_s) | |
@options = Map.extract_options!(args) | |
@headers = Map.for(@options[:headers] || {}) | |
end | |
def call(method, *args) | |
method = method.to_s.strip | |
params = | |
case | |
when args.size == 1 && args.last.is_a?(Hash) | |
args.last | |
when args.size == 1 && args.last.is_a?(Array) | |
args.last | |
else | |
args | |
end | |
id = SecureRandom.uuid | |
data = { | |
:jsonrpc => '2.0', | |
:id => id, | |
:method => method, | |
:params => params, | |
} | |
uri = @uri.dup | |
headers = @headers.merge({ | |
'Content-Type' =>'application/json' | |
}) | |
n = 42 | |
request = nil | |
response = nil | |
result = nil | |
begin | |
http = Net::HTTP.new(uri.host, uri.port) | |
case uri.scheme | |
when 'https' | |
http.use_ssl = true | |
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
end | |
request = Net::HTTP::Post.new(uri.request_uri, headers) | |
request.body = data.to_json | |
response = debugging_http(http){ http.request(request) } | |
rescue SocketError, Timeout::Error | |
n -= 1 | |
return nil if n <= 0 | |
sleep(rand) | |
retry | |
end | |
unless response.is_a?(Net::HTTPSuccess) | |
error!("failed with: url=#{ url }, path=#{ path }, headers=#{ headers.to_json}, json=#{ json }") | |
end | |
body = response.body | |
result = JSON.parse(body) | |
if result.has_key?("error") | |
raise(JsonRPC::Error, result.inspect) | |
end | |
result["result"] | |
end | |
# | |
def uri_for(*args, &block) | |
options = Map.options_for!(args) | |
path_info = absolute_path_for(args.join('/') || options[:path_info]) | |
query = Map.for(options[:query] || {}) | |
uri = self.uri.dup | |
unless path_info.to_s.strip.empty? | |
uri.path = absolute_path_for(uri.path, path_info) | |
end | |
uri | |
end | |
# | |
def url_for(*args, &block) | |
uri_for(*args, &block).to_s | |
end | |
# | |
def paths_for(*args) | |
path = args.flatten.compact.join('/') | |
path.gsub!(%r|[.]+/|, '/') | |
path.squeeze!('/') | |
path.sub!(%r|^/|, '') | |
path.sub!(%r|/$|, '') | |
paths = path.split('/') | |
end | |
def absolute_path_for(*args) | |
path = ('/' + paths_for(*args).join('/')).squeeze('/') | |
path unless path.to_s.strip.empty? | |
end | |
def relative_path_for(*args) | |
path = absolute_path_for(*args).sub(%r{^/+}, '') | |
path unless path.to_s.strip.empty? | |
end | |
# | |
def post(url, data ={}) | |
uri = url.is_a?(URI) ? url : URI.parse(url.to_s) | |
n = 42 | |
begin | |
http = Net::HTTP.new(uri.host, uri.port) | |
case uri.scheme | |
when 'https' | |
http.use_ssl = true | |
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
end | |
headers = {'Content-Type' =>'application/json'} | |
request = Net::HTTP::Post.new(uri.request_uri, headers) | |
request.body = data.to_json | |
response = debugging_http(http){ http.request(request) } | |
rescue SocketError, Timeout::Error | |
n -= 1 | |
return nil if n <= 0 | |
sleep(rand) | |
retry | |
end | |
end | |
# | |
def get(url) | |
uri = url.is_a?(URI) ? URI.parse(url.to_s) : url | |
n = 42 | |
begin | |
http = Net::HTTP.new(uri.host, uri.port) | |
case uri.scheme | |
when 'https' | |
http.use_ssl = true | |
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
end | |
headers = {'Content-Type' =>'application/json'} | |
request = Net::HTTP::Get.new(uri.request_uri, headers) | |
response = debugging_http(http){ http.request(request) } | |
rescue SocketError, TimeoutError | |
n -= 1 | |
return nil if n <= 0 | |
sleep(rand) | |
retry | |
end | |
end | |
# | |
fattr(:debug_log){ Array.new } | |
# | |
def debug(*args, &block) | |
if defined?(@debug) | |
@debug | |
else | |
@debug = | |
case | |
when ENV['JSONRPC_DEBUG'] | |
Coerce.boolean(ENV['JSONRPC_DEBUG']) | |
else | |
rails_logger | |
end | |
end | |
if((args.size>0) || block) | |
debug!(*args, &block) | |
else | |
@debug | |
end | |
end | |
# | |
def debug=(debug) | |
case | |
when debug.respond_to?(:<<) | |
@debug = debug | |
when debug == true | |
@debug = rails_logger | |
else | |
@debug = debug | |
end | |
end | |
def rails_logger | |
defined?(Rails) ? Rails.logger : Logger.new(STDERR) | |
end | |
# | |
def debug? | |
!!debug | |
end | |
# | |
def debugging_http(http, &block) | |
return block.call unless debug? | |
sio = StringIO.new | |
http.set_debug_output(sio) | |
begin | |
block.call | |
ensure | |
sio.rewind | |
raw = sio.read | |
debug_log.push(raw) | |
debug!(raw) | |
end | |
end | |
# | |
def debug!(*args, &block) | |
msg = args.flatten.compact.join(' ') | |
if block | |
msg << Array(block.call).flatten.compact.join(' ') | |
end | |
msg.strip! | |
return false if msg.to_s.strip.empty? | |
case | |
when debug.respond_to?(:info) | |
debug.info(msg) | |
when debug.respond_to?(:<<) | |
debug << msg | |
when debug.respond_to?(:write) | |
debug.write(msg) | |
if debug.respond_to?(:flush) | |
debug.flush | |
end | |
else | |
$stderr.puts(msg) | |
end | |
end | |
# | |
def error!(*args, &block) | |
error = Error.new(*args, &block) | |
raise(error) | |
ensure | |
error.raw = debug_log.last | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment