Skip to content
Snippets Groups Projects
Commit 1635b36f authored by inertia's avatar inertia
Browse files

added new methods to bridge

parent fa72c95f
No related branches found
No related tags found
No related merge requests found
...@@ -74,6 +74,10 @@ module Hive ...@@ -74,6 +74,10 @@ module Hive
raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error) raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
end end
if error.message.include? 'Invalid parameter'
raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
end
if error.message.include? 'blk->transactions.size() > itr->trx_in_block' if error.message.include? 'blk->transactions.size() > itr->trx_in_block'
raise Hive::VirtualOperationsNotAllowedError, "#{context}: #{error.message}", build_backtrace(error) raise Hive::VirtualOperationsNotAllowedError, "#{context}: #{error.message}", build_backtrace(error)
end end
...@@ -122,6 +126,10 @@ module Hive ...@@ -122,6 +126,10 @@ module Hive
raise Hive::UpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error) raise Hive::UpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
end end
if error.message.include? 'Request Timeout'
raise Hive::RequestTimeoutUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
end
if error.message.include? 'Bad or missing upstream response' if error.message.include? 'Bad or missing upstream response'
raise Hive::BadOrMissingUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error) raise Hive::BadOrMissingUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
end end
...@@ -205,6 +213,7 @@ module Hive ...@@ -205,6 +213,7 @@ module Hive
class UpstreamResponseError < RemoteNodeError; end class UpstreamResponseError < RemoteNodeError; end
class RemoteDatabaseLockError < UpstreamResponseError; end class RemoteDatabaseLockError < UpstreamResponseError; end
class PluginNotEnabledError < UpstreamResponseError; end class PluginNotEnabledError < UpstreamResponseError; end
class RequestTimeoutUpstreamResponseError < UpstreamResponseError; end
class BadOrMissingUpstreamResponseError < UpstreamResponseError; end class BadOrMissingUpstreamResponseError < UpstreamResponseError; end
class TransactionIndexDisabledError < BaseError; end class TransactionIndexDisabledError < BaseError; end
class NotAppBaseError < BaseError; end class NotAppBaseError < BaseError; end
......
...@@ -208,11 +208,25 @@ module Hive::Fallback ...@@ -208,11 +208,25 @@ module Hive::Fallback
:get_account_reputations :get_account_reputations
], ],
bridge: [ bridge: [
:normalize_post,
:get_post_header,
:get_discussion,
:get_post,
:get_account_posts,
:get_ranked_posts,
:get_profile,
:get_trending_topics,
:post_notifications,
:account_notifications, :account_notifications,
:unread_notifications,
:get_payout_stats,
:get_community, :get_community,
:get_ranked_posts, :get_community_context,
:list_pop_communities,
:list_subscribers,
:list_all_subscriptions, :list_all_subscriptions,
:list_community_roles, :list_community_roles,
:list_communities
] ]
} }
...@@ -277,11 +291,25 @@ module Hive::Fallback ...@@ -277,11 +291,25 @@ module Hive::Fallback
get_account_reputations: {account_lower_bound: String, limit: Integer} get_account_reputations: {account_lower_bound: String, limit: Integer}
}, },
bridge: { bridge: {
account_notifications: {account: String, limit: Integer}, normalize_post: {post: Hash},
get_post_header: {author: String, permlink: String},
get_discussion: {author: String, permlink: String},
get_post: {author: String, permlink: String, observer: String},
get_account_posts: {sort: String, account: String, start_account: String, start_permlink: String, limit: Integer, observer: String},
get_ranked_posts: {sort: String, tag: String, observer: String, limit: Integer, start_author: String, start_permlink: String},
get_profile: {account: String, observer: String},
get_trending_topics: {limit: Integer, observer: String},
post_notifications: {author: String, permlink: String, min_score: Integer, last_id: String, limit: Integer},
account_notifications: {account: String, min_score: Integer, last_id: Integer, limit: Integer},
unread_notifications: {account: String, min_score: Integer},
get_payout_stats: {limit: Integer},
get_community: {name: String, observer: String}, get_community: {name: String, observer: String},
get_ranked_posts: {sort: String, tag: String, observer: String, limit: Integer}, get_community_context: {name: String, account: String},
list_all_subscriptions: {account: String}, list_communities: {last: String, limit: Integer, query: String, sort: String, observer: String},
list_community_roles: {community: String} list_pop_communities: {limit: Integer},
list_community_roles: {community: String, last: String, limit: Integer},
list_subscribers: {community: String},
list_all_subscriptions: {account: String}
} }
} }
end end
...@@ -17,7 +17,8 @@ module Hive ...@@ -17,7 +17,8 @@ module Hive
# #
# @private # @private
TIMEOUT_ERRORS = [Net::OpenTimeout, JSON::ParserError, Net::ReadTimeout, TIMEOUT_ERRORS = [Net::OpenTimeout, JSON::ParserError, Net::ReadTimeout,
Errno::EBADF, IOError, Errno::ENETDOWN, Hive::RemoteDatabaseLockError] Errno::EBADF, IOError, Errno::ENETDOWN, Hive::RemoteDatabaseLockError,
Hive::RequestTimeoutUpstreamResponseError, Hive::RemoteNodeError]
# @private # @private
POST_HEADERS = { POST_HEADERS = {
...@@ -57,8 +58,10 @@ module Hive ...@@ -57,8 +58,10 @@ module Hive
def rpc_execute(api_name = @api_name, api_method = nil, options = {}, &block) def rpc_execute(api_name = @api_name, api_method = nil, options = {}, &block)
reset_timeout reset_timeout
catch :tota_cera_pila do; begin response = nil
request = http_post
loop do
request = http_post(api_name)
request_object = if !!api_name && !!api_method request_object = if !!api_name && !!api_method
put(api_name, api_method, options) put(api_name, api_method, options)
...@@ -80,11 +83,11 @@ module Hive ...@@ -80,11 +83,11 @@ module Hive
response = catch :http_request do; begin; http_request(request) response = catch :http_request do; begin; http_request(request)
rescue *TIMEOUT_ERRORS => e rescue *TIMEOUT_ERRORS => e
throw retry_timeout(:http_request, e) retry_timeout(:http_request, e) and redo
end; end end; end
if response.nil? if response.nil?
throw retry_timeout(:tota_cera_pila, 'response was nil') retry_timeout(:tota_cera_pila, 'response was nil') and redo
end end
case response.code case response.code
...@@ -108,6 +111,9 @@ module Hive ...@@ -108,6 +111,9 @@ module Hive
else; response else; response
end end
timeout_detected = false
timeout_cause = nil
[response].flatten.each_with_index do |r, i| [response].flatten.each_with_index do |r, i|
if defined?(r.error) && !!r.error if defined?(r.error) && !!r.error
if !!r.error.message if !!r.error.message
...@@ -116,7 +122,10 @@ module Hive ...@@ -116,7 +122,10 @@ module Hive
rpc_args = [request_object].flatten[i] rpc_args = [request_object].flatten[i]
raise_error_response rpc_method_name, rpc_args, r raise_error_response rpc_method_name, rpc_args, r
rescue *TIMEOUT_ERRORS => e rescue *TIMEOUT_ERRORS => e
throw retry_timeout(:tota_cera_pila, e) timeout_detected = true
timeout_cause = nil
break # fail fast
end end
else else
raise Hive::ArgumentError, r.error.inspect raise Hive::ArgumentError, r.error.inspect
...@@ -124,19 +133,29 @@ module Hive ...@@ -124,19 +133,29 @@ module Hive
end end
end end
if timeout_detected
retry_timeout(:tota_cera_pila, timeout_cause) and redo
end
yield_response response, &block yield_response response, &block
when '504' # Gateway Timeout when '504' # Gateway Timeout
throw retry_timeout(:tota_cera_pila, response.body) retry_timeout(:tota_cera_pila, response.body) and redo
when '502' # Bad Gateway when '502' # Bad Gateway
throw retry_timeout(:tota_cera_pila, response.body) retry_timeout(:tota_cera_pila, response.body) and redo
else else
raise UnknownError, "#{api_name}.#{api_method}: #{response.body}" raise UnknownError, "#{api_name}.#{api_method}: #{response.body}"
end end
end; end
break # success!
end
response
end end
def rpc_batch_execute(options = {}, &block) def rpc_batch_execute(options = {}, &block)
yield_response rpc_execute(nil, nil, options), &block api_name = options[:api_name]
yield_response rpc_execute(api_name, nil, options), &block
end end
end end
end end
......
...@@ -10,13 +10,20 @@ module Hive ...@@ -10,13 +10,20 @@ module Hive
class ThreadSafeHttpClient < HttpClient class ThreadSafeHttpClient < HttpClient
SEMAPHORE = Mutex.new.freeze SEMAPHORE = Mutex.new.freeze
# Same as #{HttpClient#http_post}, but scoped to each thread so it is # Same as #{HttpClient#http_post}, but scoped to each thread, uri, and
# thread safe. # api_name so it is thread safe.
def http_post def http_post(api_name)
raise "Namespace required." if api_name.nil?
thread = Thread.current thread = Thread.current
http_post = thread.thread_variable_get(:http_post) http_posts = thread.thread_variable_get(:http_posts) || {}
http_post ||= Net::HTTP::Post.new(uri.request_uri, POST_HEADERS)
thread.thread_variable_set(:http_post, http_post) SEMAPHORE.synchronize do
http_posts[[uri, api_name]] ||= Net::HTTP::Post.new(uri.request_uri, POST_HEADERS)
thread.thread_variable_set(:http_posts, http_posts)
end
http_posts[[uri, api_name]]
end end
def http_request(request); SEMAPHORE.synchronize{super}; end def http_request(request); SEMAPHORE.synchronize{super}; end
......
...@@ -4,6 +4,7 @@ module Hive ...@@ -4,6 +4,7 @@ module Hive
class BridgeTest < Hive::Test class BridgeTest < Hive::Test
def setup def setup
@api = Hive::Bridge.new(url: TEST_NODE) @api = Hive::Bridge.new(url: TEST_NODE)
@condenser_api = Hive::CondenserApi.new(url: TEST_NODE)
@jsonrpc = Jsonrpc.new(url: TEST_NODE) @jsonrpc = Jsonrpc.new(url: TEST_NODE)
@methods = @jsonrpc.get_api_methods[@api.class.api_name] rescue Fallback::API_METHODS[:bridge] @methods = @jsonrpc.get_api_methods[@api.class.api_name] rescue Fallback::API_METHODS[:bridge]
end end
...@@ -13,7 +14,7 @@ module Hive ...@@ -13,7 +14,7 @@ module Hive
end end
def test_inspect def test_inspect
assert_equal "#<Bridge [@chain=hive, @methods=<5 elements>]>", @api.inspect assert_equal "#<Bridge [@chain=hive, @methods=<19 elements>]>", @api.inspect
end end
def test_method_missing def test_method_missing
...@@ -28,6 +29,47 @@ module Hive ...@@ -28,6 +29,47 @@ module Hive
end end
end end
def test_normalize_post
vcr_cassette('bridge_normalize_post', record: :once) do
author = 'inertia'
permlink = 'kinda-spooky'
post = @condenser_api.get_content(author, permlink).result
options = {
post: post
}
@api.normalize_post(options) do |result|
assert_equal Hashie::Mash, result.class
assert_equal author, result.author
assert_equal permlink, result.permlink
known_normalization_fields = %w(post_id updated is_paidout payout_at payout
author_payout_value stats)
assert_equal known_normalization_fields, result.keys - post.keys, 'found unknown fields added by hivemind normalization'
end
end
end
def test_get_post_header
vcr_cassette('bridge_get_post_header', record: :once) do
author = 'inertia'
permlink = 'kinda-spooky'
post = @condenser_api.get_content(author, permlink).result
options = {
author: author,
permlink: permlink
}
@api.get_post_header(options) do |result|
assert_equal Hashie::Mash, result.class
assert_equal author, result.author
assert_equal permlink, result.permlink
assert_equal [], result.keys - post.keys
end
end
end
def test_account_notifications def test_account_notifications
vcr_cassette('bridge_account_notifications', record: :once) do vcr_cassette('bridge_account_notifications', record: :once) do
options = { options = {
...@@ -54,12 +96,57 @@ module Hive ...@@ -54,12 +96,57 @@ module Hive
end end
end end
def test_get_discussion
vcr_cassette('bridge_get_discussion', record: :once) do
options = {
author: 'inertia',
permlink: 'kinda-spooky'
}
@api.get_discussion(options) do |result|
assert_equal Hashie::Mash, result.class
end
end
end
def test_get_post
vcr_cassette('bridge_get_post', record: :once) do
options = {
author: 'inertia',
permlink: 'kinda-spooky',
observer: 'alice'
}
@api.get_post(options) do |result|
assert_equal Hashie::Mash, result.class
end
end
end
def test_get_account_posts
vcr_cassette('bridge_get_account_posts', record: :once) do
options = {
sort: 'blog',
account: 'alice',
start_author: '',
start_permlink: '',
limit: 1,
observer: 'alice'
}
@api.get_account_posts(options) do |result|
assert_equal Hashie::Array, result.class
end
end
end
def test_get_ranked_posts def test_get_ranked_posts
vcr_cassette('bridge_get_ranked_posts', record: :once) do vcr_cassette('bridge_get_ranked_posts', record: :once) do
options = { options = {
sort: 'trending', sort: 'trending',
tag: '', tag: '',
observer: 'alice' observer: 'alice',
limit: 1
} }
@api.get_ranked_posts(options) do |result| @api.get_ranked_posts(options) do |result|
...@@ -68,6 +155,92 @@ module Hive ...@@ -68,6 +155,92 @@ module Hive
end end
end end
def test_get_profile
vcr_cassette('bridge_get_profile', record: :once) do
options = {
account: 'bob',
observer: 'alice'
}
@api.get_profile(options) do |result|
assert_equal Hashie::Mash, result.class
end
end
end
def test_get_trending_topics
vcr_cassette('bridge_get_trending_topics', record: :once) do
limit = 25
options = {
limit: limit,
observer: 'alice'
}
@api.get_trending_topics(options) do |result|
assert_equal Hashie::Array, result.class
assert_equal limit, result.size
end
end
end
def test_get_trending_topics_over_limit
vcr_cassette('bridge_get_trending_topics_over_limit', record: :once) do
limit = 26
options = {
limit: limit,
observer: 'alice'
}
assert_raises Hive::ArgumentError do
@api.get_trending_topics(options)
end
end
end
def test_post_notifications_empty
vcr_cassette('bridge_post_notifications', record: :once) do
limit = 0
options = {
author: '',
permlink: '',
last_id: '',
min_score: 25,
limit: limit
}
assert_raises Hive::ArgumentError do
@api.post_notifications(options)
end
end
end
def test_unread_notifications
vcr_cassette('bridge_unread_notifications', record: :once) do
options = {
account: 'alice',
min_score: 25
}
@api.unread_notifications(options) do |result|
assert_equal Hashie::Mash, result.class
end
end
end
def test_get_payout_stats
vcr_cassette('bridge_get_payout_stats', record: :once) do
limit = 250
options = {
limit: limit
}
@api.get_payout_stats(options) do |result|
assert_equal Hashie::Mash, result.class
assert_equal limit, result.items.size
end
end
end
def test_list_all_subscriptions def test_list_all_subscriptions
vcr_cassette('bridge_list_all_subscriptions', record: :once) do vcr_cassette('bridge_list_all_subscriptions', record: :once) do
options = { options = {
...@@ -91,5 +264,73 @@ module Hive ...@@ -91,5 +264,73 @@ module Hive
end end
end end
end end
def test_list_communities_empty
vcr_cassette('bridge_list_communities_empty', record: :once) do
options = {
last: '',
limit: 0,
query: '',
sort: '',
observer: ''
}
assert_raises Hive::ArgumentError do
@api.list_communities(options)
end
end
end
def test_list_communities
vcr_cassette('bridge_list_communities', record: :once) do
options = {
last: '',
limit: 1,
query: '',
sort: 'rank',
observer: 'alice'
}
@api.list_communities(options) do |result|
assert_equal Hashie::Array, result.class
end
end
end
def test_list_pop_communities
skip 'not implemented'
vcr_cassette('bridge_list_pop_communities', record: :once) do
options = {
limit: 1
}
assert_nil @api.list_pop_communities(options)
end
end
def test_list_pop_communities_over_limit
skip 'not implemented'
vcr_cassette('bridge_list_pop_communities_over_limit', record: :once) do
options = {
limit: 26
}
assert_nil @api.list_pop_communities(options)
end
end
end
def test_list_subscribers
vcr_cassette('bridge_list_subscribers', record: :once) do
options = {
community: 'hive-100525'
}
@api.list_subscribers(options) do |result|
assert_equal Hashie::Array, result.class
end
end
end end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment