Class: Steem::RPC::BaseClient

Inherits:
Object
  • Object
show all
Includes:
ChainConfig
Defined in:
lib/steem/rpc/base_client.rb

Direct Known Subclasses

HttpClient

Constant Summary collapse

MAX_TIMEOUT_RETRY_COUNT =
100
MAX_TIMEOUT_BACKOFF =
30
TIMEOUT_ERRORS =
[Net::ReadTimeout, Errno::EBADF, IOError]

Constants included from ChainConfig

ChainConfig::EXPIRE_IN_SECS, ChainConfig::EXPIRE_IN_SECS_PROPOSAL, ChainConfig::NETWORKS_STEEM_ADDRESS_PREFIX, ChainConfig::NETWORKS_STEEM_CHAIN_ID, ChainConfig::NETWORKS_STEEM_CORE_ASSET, ChainConfig::NETWORKS_STEEM_DEBT_ASSET, ChainConfig::NETWORKS_STEEM_DEFAULT_NODE, ChainConfig::NETWORKS_STEEM_VEST_ASSET, ChainConfig::NETWORKS_TEST_ADDRESS_PREFIX, ChainConfig::NETWORKS_TEST_CHAIN_ID, ChainConfig::NETWORKS_TEST_CORE_ASSET, ChainConfig::NETWORKS_TEST_DEBT_ASSET, ChainConfig::NETWORKS_TEST_DEFAULT_NODE, ChainConfig::NETWORKS_TEST_VEST_ASSET, ChainConfig::NETWORK_CHAIN_IDS

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ BaseClient

Returns a new instance of BaseClient.



17
18
19
20
21
22
23
24
25
26
# File 'lib/steem/rpc/base_client.rb', line 17

def initialize(options = {})
  @chain = options[:chain] || :steem
  @error_pipe = options[:error_pipe] || STDERR
  @api_name = options[:api_name]
  @url = case @chain
  when :steem then options[:url] || NETWORKS_STEEM_DEFAULT_NODE
  when :test then options[:url] || NETWORKS_TEST_DEFAULT_NODE
  else; raise UnsupportedChainError, "Unsupported chain: #{@chain}"
  end
end

Instance Attribute Details

#chainObject

Returns the value of attribute chain.



6
7
8
# File 'lib/steem/rpc/base_client.rb', line 6

def chain
  @chain
end

#error_pipeObject

Returns the value of attribute error_pipe.



6
7
8
# File 'lib/steem/rpc/base_client.rb', line 6

def error_pipe
  @error_pipe
end

#urlObject

Returns the value of attribute url.



6
7
8
# File 'lib/steem/rpc/base_client.rb', line 6

def url
  @url
end

Instance Method Details

#evaluate_id(options = {}) ⇒ Object

Checks json-rpc request/response for corrilated id. If they do not match, IncorrectResponseIdError is thrown. This is usually caused by the client, involving thread safety. It can also be caused by the node responding without an id.

To avoid IncorrectResponseIdError, make sure you implement your client correctly.

Setting DEBUG=true in the envrionment will cause this method to output both the request and response json.

Parameters:

  • options (Hash) (defaults to: {})

    options

Options Hash (options):

  • :debug (Boolean)

    Enable or disable debug output.

  • :request (Hash)

    to compare id

  • :response (Hash)

    to compare id

  • :api_method (String)

See Also:

  • {ThreadSafeHttpClient}


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/steem/rpc/base_client.rb', line 93

def evaluate_id(options = {})
  debug = options[:debug] || ENV['DEBUG'] == 'true'
  request = options[:request]
  response = options[:response]
  api_method = options[:api_method]
  req_id = request[:id].to_i
  res_id = !!response['id'] ? response['id'].to_i : nil
  method = [@api_name, api_method].join('.')
  
  if debug
    req = JSON.pretty_generate(request)
    res = JSON.parse(response) rescue response
    res = JSON.pretty_generate(response) rescue response
    
    error_pipe.puts '=' * 80
    error_pipe.puts "Request:"
    error_pipe.puts req
    error_pipe.puts '=' * 80
    error_pipe.puts "Response:"
    error_pipe.puts res
    error_pipe.puts '=' * 80
    error_pipe.puts Thread.current.backtrace.join("\n")
  end
  
  error = response['error'].to_json if !!response['error']
        
  if req_id != res_id
    raise IncorrectResponseIdError, "#{method}: The json-rpc id did not match.  Request was: #{req_id}, got: #{res_id.inspect}", BaseError.send(:build_backtrace, error)
  end
end

#put(api_name = @api_name, api_method = nil, options = {}) ⇒ Object

Adds a request object to the stack. Usually, this method is called internally by #rpc_execute. If you want to create a batched request, use this method to add to the batch then execute #rpc_batch_execute.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/steem/rpc/base_client.rb', line 35

def put(api_name = @api_name, api_method = nil, options = {})
  current_rpc_id = rpc_id
  rpc_method_name = "#{api_name}.#{api_method}"
  options ||= {}
  request_object = defined?(options.delete) ? options.delete(:request_object) : []
  request_object ||= []
  
  request_object << {
    jsonrpc: '2.0',
    id: current_rpc_id,
    method: rpc_method_name,
    params: options
  }
  
  request_object
end

#rpc_batch_executeObject

This method is abstract.

Subclass is expected to implement #rpc_batch_execute.



# File 'lib/steem/rpc/base_client.rb', line 55

#rpc_executeObject

This method is abstract.

Subclass is expected to implement #rpc_execute.



# File 'lib/steem/rpc/base_client.rb', line 52

#rpc_idObject

Current json-rpc id used for a request. This version auto-increments for each call. Subclasses can use their own strategy.



126
127
128
129
# File 'lib/steem/rpc/base_client.rb', line 126

def rpc_id
  @rpc_id ||= 0
  @rpc_id += 1
end

#uriObject



28
29
30
# File 'lib/steem/rpc/base_client.rb', line 28

def uri
  @uri ||= URI.parse(url)
end

#yield_response(response, &block) ⇒ Object

To be called by #rpc_execute and #rpc_batch_execute when a response has been consructed.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/steem/rpc/base_client.rb', line 60

def yield_response(response, &block)
  if !!block
    case response
    when Hashie::Mash then yield response.result, response.error, response.id
    when Hashie::Array
      response.each do |r|
        r = Hashie::Mash.new(r)
        block.call r.result, r.error, r.id
      end
    else; block.call response
    end
  end
  
  response
end