From 54338bd83cb6ca5a12fe31321d246845ed6802ea Mon Sep 17 00:00:00 2001
From: Anthony Martin <github@martin-studio.com>
Date: Thu, 19 Jul 2018 12:40:49 -0700
Subject: [PATCH] refactor class level signatures cache to instance access

---
 lib/steem/api.rb              | 38 +++++++++++++++++++++--------------
 lib/steem/mixins/retriable.rb | 35 ++++++++++++++++++++------------
 test/steem/broadcast_test.rb  |  8 ++++++--
 test/steem/jsonrpc_test.rb    |  1 +
 4 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/lib/steem/api.rb b/lib/steem/api.rb
index ab69f1d..cdf6e80 100644
--- a/lib/steem/api.rb
+++ b/lib/steem/api.rb
@@ -1,6 +1,6 @@
 module Steem
   # This ruby API works with
-  # {https://github.com/steemit/steem/releases steemd-0.19.4} and other AppBase
+  # {https://github.com/steemit/steem/releases steemd-0.19.10} and other AppBase
   # compatible upstreams.  To access different API namespaces, use the
   # following:
   #
@@ -36,7 +36,7 @@ module Steem
   #
   # Also see: {https://developers.steem.io/apidefinitions/ Complete API Definitions}
   class Api
-    attr_accessor :chain, :methods
+    attr_accessor :chain, :methods, :rpc_client
     
     # Use this for debugging naive thread handler.
     # DEFAULT_RPC_CLIENT_CLASS = RPC::HttpClient
@@ -57,12 +57,17 @@ module Steem
       @api_name.to_s.split('_').map(&:capitalize).join
     end
     
-    def self.jsonrpc=(jsonrpc)
-      @jsonrpc = jsonrpc
+    def self.jsonrpc=(jsonrpc, url = nil)
+      @jsonrpc ||= {}
+      @jsonrpc[url || jsonrpc.rpc_client.uri.to_s] = jsonrpc
     end
     
-    def self.jsonrpc
-      @jsonrpc
+    def self.jsonrpc(url = nil)
+      if @jsonrpc.size < 2 && url.nil?
+        @jsonrpc.values.first
+      else
+        @jsonrpc[url]
+      end
     end
     
     # Override this if you want to use your own client.
@@ -89,7 +94,7 @@ module Steem
         # have access to instance options until now.
         
         Api::jsonrpc = Jsonrpc.new(options)
-        @methods = Api::jsonrpc.get_api_methods
+        @methods = Api::jsonrpc(rpc_client.uri.to_s).get_api_methods
         
         unless !!@methods[@api_name]
           raise UnknownApiError, "#{@api_name} (known APIs: #{@methods.keys.join(' ')})"
@@ -115,19 +120,22 @@ module Steem
     end
   private
     # @private
-    def self.args_keys_to_s(rpc_method_name)
+    def args_keys_to_s(rpc_method_name)
       args = signature(rpc_method_name).args
       args_keys = JSON[args.to_json]
     end
     
     # @private
-    def self.signature(rpc_method_name)
+    def signature(rpc_method_name)
+      url = rpc_client.uri.to_s
+      
       @@signatures ||= {}
-      @@signatures[rpc_method_name] ||= jsonrpc.get_signature(method: rpc_method_name).result
+      @@signatures[url] ||= {}
+      @@signatures[url][rpc_method_name] ||= Api::jsonrpc(url).get_signature(method: rpc_method_name).result
     end
     
     # @private
-    def self.raise_error_response(rpc_method_name, rpc_args, response)
+    def raise_error_response(rpc_method_name, rpc_args, response)
       raise UnknownError, "#{rpc_method_name}: #{response}" if response.error.nil?
       
       error = response.error
@@ -153,9 +161,9 @@ module Steem
       when :condenser_api then args
       when :jsonrpc then args.first
       else
-        expected_args = Api::signature(rpc_method_name).args || []
+        expected_args = signature(rpc_method_name).args || []
         expected_args_key_string = if expected_args.size > 0
-          " (#{Api::args_keys_to_s(rpc_method_name)})"
+          " (#{args_keys_to_s(rpc_method_name)})"
         end
         expected_args_size = expected_args.size
         
@@ -178,11 +186,11 @@ module Steem
         args
       end
       
-      response = @rpc_client.rpc_execute(@api_name, m, rpc_args)
+      response = rpc_client.rpc_execute(@api_name, m, rpc_args)
       
       if defined?(response.error) && !!response.error
         if !!response.error.message
-          Api::raise_error_response rpc_method_name, rpc_args, response
+          raise_error_response rpc_method_name, rpc_args, response
         else
           raise Steem::ArgumentError, response.error.inspect
         end
diff --git a/lib/steem/mixins/retriable.rb b/lib/steem/mixins/retriable.rb
index 9f16944..b918488 100644
--- a/lib/steem/mixins/retriable.rb
+++ b/lib/steem/mixins/retriable.rb
@@ -13,24 +13,12 @@ module Steem
       IncorrectResponseIdError, RemoteDatabaseLockError
     ]
     
-    # Expontential backoff.
-    #
-    # @private
-    def backoff
-      @backoff ||= 0.1
-      @backoff *= 2
-      @backoff = 0.1 if @backoff > MAX_BACKOFF
-      
-      sleep @backoff
-    end
-    
     def can_retry?(e = nil)
       @retry_count ||= 0
-      @first_retry_at ||= Time.now.utc
       
       return false if @retry_count >= MAX_RETRY_COUNT
       
-      @retry_count = if Time.now.utc - @first_retry_at > MAX_RETRY_ELAPSE
+      @retry_count = if retry_reset?
         @first_retry_at = nil
       else
         @retry_count + 1
@@ -45,5 +33,26 @@ module Steem
       
       can_retry
     end
+  private
+    # @private
+    def first_retry_at
+      @first_retry_at ||= Time.now.utc
+    end
+    
+    # @private
+    def retry_reset?
+      Time.now.utc - first_retry_at > MAX_RETRY_ELAPSE
+    end
+    
+    # Expontential backoff.
+    #
+    # @private
+    def backoff
+      @backoff ||= 0.1
+      @backoff *= 2
+      @backoff = 0.1 if @backoff > MAX_BACKOFF
+      
+      sleep @backoff
+    end
   end
 end
diff --git a/test/steem/broadcast_test.rb b/test/steem/broadcast_test.rb
index e88ca43..c8d198b 100644
--- a/test/steem/broadcast_test.rb
+++ b/test/steem/broadcast_test.rb
@@ -1084,12 +1084,16 @@ module Steem
     
     def test_can_retry
       e = NonCanonicalSignatureError.new("test")
-      assert Broadcast.send(:can_retry?, e)
+      
+      refute_nil Broadcast.send(:first_retry_at)
+      assert Broadcast.send(:can_retry?, e) unless Broadcast.send :retry_reset?
     end
     
     def test_can_retry_remote_node_error
       e = IncorrectResponseIdError.new("test: The json-rpc id did not match")
-      assert Broadcast.send(:can_retry?, e)
+      
+      refute_nil Broadcast.send(:first_retry_at)
+      assert Broadcast.send(:can_retry?, e) unless Broadcast.send :retry_reset?
     end
   end
 end
\ No newline at end of file
diff --git a/test/steem/jsonrpc_test.rb b/test/steem/jsonrpc_test.rb
index d6de60d..78b3968 100644
--- a/test/steem/jsonrpc_test.rb
+++ b/test/steem/jsonrpc_test.rb
@@ -70,6 +70,7 @@ module Steem
         assert_raises SocketError, Errno::ECONNREFUSED do
           jsonrpc = Jsonrpc.new(url: 'https://bad.node')
           jsonrpc.get_methods
+          fail 'regression detected, SocketError or Errno::ECONNREFUSED expected'
         end
       end
     end
-- 
GitLab