bitcoind_rpc 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f74740329efd56a839d8fd49beb9b8afd03ac12c
4
- data.tar.gz: 1193a537f6b3486f5acb53fcf3385866932ba1c9
3
+ metadata.gz: 79c3c0305faaac12a984279bb387c5dbea898dd5
4
+ data.tar.gz: 6551d3485a5fd61b3e17f796d7a0d5622f6fc527
5
5
  SHA512:
6
- metadata.gz: 3706284e82201f575dc003ce85eede6176ebcda1c4709f67be722d33e4fb4e846522be3686438deb232b571cd71b5024c54ffbb9a03e06e677cb7b6e9b167650
7
- data.tar.gz: f52e87dce9121b3e1be4e277f042b41876aa8c630de92117bdb79f29ef9dbfd1e422718e71c42cdb1ae551ea8cb0eec2e9ca0766863ab6ce5831385b78180b25
6
+ metadata.gz: a48811ef87ee14964e6164fd4bb13bcf17a4896b4cee6c3b4e4d977ff5b9b2e5e3fea6e709d951509d28304e38b4526312df720f8852a30af88687f82cad2272
7
+ data.tar.gz: 65bda6c214c0e9e3239bd821be130df68761caa9d557d1a1b4a4c4f272ecedef5ea3054db7275cc151334b0d9bab2780e20cbbe3a3ac2fef92937f586d14e60e
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
- # BitcoindRPC
1
+ # Bitcoind RPC
2
2
 
3
- A Ruby client for the bitcoind JSON-RPC.
3
+ A Ruby client for the *bitcoind* ([Bitcoin Core](https://github.com/bitcoin/bitcoin) compatible) JSON-RPC.
4
+
5
+ Features:
6
+
7
+ * Parses floats as BigDecimal
8
+ * Lists methods supported by the connected bitcoind
9
+ * Allows access to RPC methods as plain Ruby methods of Connection object
4
10
 
5
11
  ## Installation
6
12
 
@@ -20,7 +26,19 @@ Or install it yourself as:
20
26
 
21
27
  ## Usage
22
28
 
23
- TODO: Write usage instructions here
29
+ ```ruby
30
+
31
+ require 'bitcoind_rpc'
32
+
33
+ bitcoind = BitcoindRPC::Connection.new(uri: 'http://{username}:{password}@{host}:{port}')
34
+
35
+ bitcoind.supported_methods # => [ :getbestblockhash, :getblock, ... ]
36
+ bitcoind.getbalance # => #<BigDecimal:...>
37
+ bitcoind.blablabla # => NoMethodError
38
+
39
+ bitcoind.getblock "3d587773d2cbaf64f208f165f5f7717d7324350612d189063b4d1d2f14711380" # => { :hash => "3d58..." ...}
40
+
41
+ ```
24
42
 
25
43
 
26
44
  ## Contributing
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
+ spec.add_dependency 'oj', '~> 2.15'
31
+
30
32
  spec.add_development_dependency 'bundler', '~> 1.11'
31
33
  spec.add_development_dependency 'rake', '~> 10.0'
32
34
  spec.add_development_dependency 'rspec', '~> 3.0'
@@ -1,5 +1,28 @@
1
- require 'bitcoind_rpc/version'
1
+ require 'logger'
2
+ require_relative 'bitcoind_rpc/version'
3
+ require_relative 'bitcoind_rpc/connection'
2
4
 
3
5
  module BitcoindRPC
4
- # Your code goes here...
5
- end
6
+ DEFAULT_OPTIONS = {
7
+ logger: Logger.new(STDOUT).tap { |l| l.level = ::Logger::WARN }
8
+ }.freeze
9
+
10
+ def self.configure(opts = {})
11
+ opts = DEFAULT_OPTIONS.dup.merge(opts.dup)
12
+ @connection = BitcoindRPC::Connection.new(opts)
13
+ @logger = opts[:logger] if opts[:logger]
14
+ @connection
15
+ end
16
+
17
+ def self.connection
18
+ @connection
19
+ end
20
+
21
+ def self.logger
22
+ @logger ||= DEFAULT_OPTIONS[:logger]
23
+ end
24
+
25
+ def self.logger=(new_logger)
26
+ @logger = new_logger
27
+ end
28
+ end # module BitcoindRPC
@@ -0,0 +1,85 @@
1
+ require 'oj'
2
+ require 'net/http'
3
+
4
+ module BitcoindRPC
5
+ class Connection
6
+ attr_reader :options, :uri
7
+
8
+ DEFAULT_OPTIONS = {
9
+ host: 'localhost',
10
+ port: 18332 # Default for testnet: 18332, for mainnet: 8332
11
+ }.freeze
12
+
13
+ CONTENT_TYPE = 'application/json'.freeze
14
+
15
+ # Creates a new connection to a bitcoind
16
+ #
17
+ # @param [Hash] opts Connection parameters
18
+ # @option opts [String] :host
19
+ # @option opts [String] :port
20
+ # @option opts [String] :username
21
+ # @option opts [String] :password
22
+ # @option opts [String,URI] :uri Specify a complete URI instead of separate host, port etc
23
+ #
24
+ def initialize(opts)
25
+ @options = DEFAULT_OPTIONS.dup.merge(opts.dup)
26
+ @uri = @options[:uri] ? URI(@options[:uri]) : URI(uri_to_s)
27
+ end
28
+
29
+ def respond_to_missing?(name, _include_all = false)
30
+ supported_methods.include?(name.to_sym) || super
31
+ end
32
+
33
+ def method_missing(name, *args)
34
+ return request(name, *args) if supported_methods.include?(name.to_sym)
35
+ super
36
+ end
37
+
38
+ def request(name, *args)
39
+ BitcoindRPC.logger.debug "> #{name}: #{args.join(',')}"
40
+ response = request_http_post(name, args)
41
+ BitcoindRPC.logger.debug "< #{response.code} #{response.message}"
42
+ raise Error, response.message unless (200...300).cover?(response.code.to_i)
43
+ begin
44
+ response = Oj.load(response.body, symbol_keys: true, bigdecimal_load: true)
45
+ rescue StandardError => e
46
+ BitcoindRPC.logger.warn "Failed to parse JSON response: #{e}"
47
+ raise
48
+ end
49
+ raise Error, response[:error] if response[:error]
50
+ response[:result]
51
+ end
52
+
53
+ # Makes a request to a bitcoind instance once and returns the list of supported RPC methods
54
+ #
55
+ def supported_methods
56
+ return @supported_methods if @supported_methods
57
+ help_response = request(:help)
58
+ mm = help_response.split("\n").select { |l| l =~ /^\w+(\s|$)/ }
59
+ @supported_methods = mm.map { |l| l.split(' ').first }.map(&:to_sym)
60
+ end
61
+
62
+ private
63
+
64
+ def uri_to_s
65
+ "http://#{options[:username]}:#{options[:password]}@#{options[:host]}:#{options[:port]}"
66
+ end
67
+
68
+ def request_http_post(name, params)
69
+ username = uri.user
70
+ password = uri.password
71
+ http = Net::HTTP.new(uri.host, uri.port)
72
+ request = Net::HTTP::Post.new(uri.request_uri)
73
+ request.basic_auth(username, password)
74
+ request.body = request_body(name, params)
75
+ request['Content-Type'] = CONTENT_TYPE
76
+ http.request(request)
77
+ end
78
+
79
+ def request_body(name, params)
80
+ Oj.dump({ method: name, params: params, id: 'jsonrpc' }, mode: :compat)
81
+ end
82
+
83
+ class Error < RuntimeError; end
84
+ end # class Connection
85
+ end # module BitcoindRPC
@@ -1,3 +1,3 @@
1
1
  module BitcoindRPC
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoind_rpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
@@ -10,6 +10,20 @@ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2016-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: oj
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.15'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.15'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -85,6 +99,7 @@ files:
85
99
  - bin/setup
86
100
  - bitcoind_rpc.gemspec
87
101
  - lib/bitcoind_rpc.rb
102
+ - lib/bitcoind_rpc/connection.rb
88
103
  - lib/bitcoind_rpc/version.rb
89
104
  homepage: https://github.com/kukushkin/bitcoind_rpc
90
105
  licenses: