xrbp 0.0.1 → 0.1.0
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 +4 -4
- data/README.md +103 -5
- data/examples/accounts.rb +13 -0
- data/examples/autoconnect_timeout.rb +5 -1
- data/examples/autorety.rb +7 -0
- data/examples/crawl_nodes.rb +32 -0
- data/examples/dsl/account.rb +16 -0
- data/examples/dsl/ledger.rb +7 -0
- data/examples/dsl/ledger_subscribe.rb +18 -0
- data/examples/dsl/validators.rb +8 -0
- data/examples/gateways.rb +8 -0
- data/examples/latest_account.rb +4 -0
- data/examples/ledger_multi_subscribe.rb +1 -1
- data/examples/ledger_subscribe.rb +2 -2
- data/examples/market.rb +13 -0
- data/examples/username.rb +12 -0
- data/examples/validator.rb +8 -0
- data/lib/xrbp.rb +5 -1
- data/lib/xrbp/common.rb +10 -0
- data/lib/xrbp/core_ext.rb +24 -0
- data/lib/xrbp/dsl.rb +25 -0
- data/lib/xrbp/dsl/accounts.rb +13 -0
- data/lib/xrbp/dsl/ledgers.rb +23 -0
- data/lib/xrbp/dsl/validators.rb +10 -0
- data/lib/xrbp/dsl/webclient.rb +8 -0
- data/lib/xrbp/dsl/websocket.rb +28 -0
- data/lib/xrbp/model.rb +4 -0
- data/lib/xrbp/model/account.rb +142 -1
- data/lib/xrbp/model/base.rb +1 -0
- data/lib/xrbp/model/gateway.rb +24 -0
- data/lib/xrbp/model/ledger.rb +30 -1
- data/lib/xrbp/model/market.rb +52 -0
- data/lib/xrbp/model/node.rb +131 -0
- data/lib/xrbp/model/parsers/account.rb +44 -0
- data/lib/xrbp/model/parsers/gateway.rb +40 -0
- data/lib/xrbp/model/parsers/market.rb +28 -0
- data/lib/xrbp/model/parsers/node.rb +19 -0
- data/lib/xrbp/model/parsers/quote.rb +47 -0
- data/lib/xrbp/model/parsers/validator.rb +25 -0
- data/lib/xrbp/model/validator.rb +24 -0
- data/lib/xrbp/plugins.rb +6 -0
- data/lib/xrbp/plugins/base.rb +10 -0
- data/lib/xrbp/plugins/has_plugin.rb +45 -0
- data/lib/xrbp/plugins/has_result_parsers.rb +27 -0
- data/lib/xrbp/plugins/plugin_registry.rb +20 -0
- data/lib/xrbp/plugins/result_parser.rb +19 -0
- data/lib/xrbp/terminatable.rb +19 -0
- data/lib/xrbp/thread_registry.rb +22 -0
- data/lib/xrbp/version.rb +1 -1
- data/lib/xrbp/webclient.rb +2 -0
- data/lib/xrbp/webclient/connection.rb +100 -0
- data/lib/xrbp/webclient/plugins.rb +8 -0
- data/lib/xrbp/webclient/plugins/autoretry.rb +54 -0
- data/lib/xrbp/webclient/plugins/result_parser.rb +23 -0
- data/lib/xrbp/websocket/client.rb +85 -24
- data/lib/xrbp/websocket/cmds/account_info.rb +4 -0
- data/lib/xrbp/websocket/cmds/account_lines.rb +5 -0
- data/lib/xrbp/websocket/cmds/account_objects.rb +4 -0
- data/lib/xrbp/websocket/cmds/account_offers.rb +5 -0
- data/lib/xrbp/websocket/cmds/account_tx.rb +4 -0
- data/lib/xrbp/websocket/cmds/book_offers.rb +4 -0
- data/lib/xrbp/websocket/cmds/ledger.rb +3 -0
- data/lib/xrbp/websocket/cmds/ledger_entry.rb +4 -0
- data/lib/xrbp/websocket/cmds/paginated.rb +4 -1
- data/lib/xrbp/websocket/cmds/server_info.rb +4 -0
- data/lib/xrbp/websocket/cmds/subscribe.rb +4 -0
- data/lib/xrbp/websocket/command.rb +11 -0
- data/lib/xrbp/websocket/connection.rb +75 -22
- data/lib/xrbp/websocket/message.rb +5 -2
- data/lib/xrbp/websocket/multi/fallback.rb +2 -4
- data/lib/xrbp/websocket/multi/multi_connection.rb +37 -2
- data/lib/xrbp/websocket/multi/parallel.rb +2 -4
- data/lib/xrbp/websocket/multi/prioritized.rb +2 -4
- data/lib/xrbp/websocket/multi/round_robin.rb +4 -0
- data/lib/xrbp/websocket/plugins.rb +1 -7
- data/lib/xrbp/websocket/plugins/autoconnect.rb +25 -5
- data/lib/xrbp/websocket/plugins/command_dispatcher.rb +5 -0
- data/lib/xrbp/websocket/plugins/command_paginator.rb +9 -8
- data/lib/xrbp/websocket/plugins/connection_timeout.rb +27 -16
- data/lib/xrbp/websocket/plugins/message_dispatcher.rb +60 -30
- data/lib/xrbp/websocket/plugins/result_parser.rb +19 -19
- data/lib/xrbp/websocket/socket.rb +23 -6
- metadata +118 -8
- data/lib/xrbp/network.rb +0 -6
- data/lib/xrbp/network/nodes.rb +0 -8
- data/lib/xrbp/websocket/has_plugin.rb +0 -30
@@ -0,0 +1,44 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Account Info data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class AccountInfo < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
j = JSON.parse(res)
|
15
|
+
# return res unless j.key?("accounts")
|
16
|
+
|
17
|
+
accts = (j["accounts"] || []).collect { |a|
|
18
|
+
{:id => a["account"],
|
19
|
+
:inception => a["inception"],
|
20
|
+
:parent_id => a["parent"]}
|
21
|
+
}
|
22
|
+
|
23
|
+
{:marker => j["marker"],
|
24
|
+
:accounts => accts}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Account Username data parser
|
29
|
+
#
|
30
|
+
# @private
|
31
|
+
class AccountUsername < PluginBase
|
32
|
+
def parser_priority
|
33
|
+
0
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_result(res, req)
|
37
|
+
j = JSON.parse(res)
|
38
|
+
# return res unless j.key?("exists")
|
39
|
+
j["exists"] ? j["username"] : nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end # module Parsers
|
43
|
+
end # module Model
|
44
|
+
end # module XRBP
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Gateway list data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Gateway < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
gateways = []
|
15
|
+
|
16
|
+
j = JSON.parse(res)
|
17
|
+
j.each_key { |currency|
|
18
|
+
j[currency].each { |currency_gateway|
|
19
|
+
id = currency_gateway["account"]
|
20
|
+
name = currency_gateway["name"]
|
21
|
+
gateway = gateways.find { |gw| gw[:id] == id }
|
22
|
+
if gateway
|
23
|
+
gateway[:currencies] << "#{currency}"
|
24
|
+
gateway[:names] << "#{name}" unless gateway[:names].include?(name)
|
25
|
+
|
26
|
+
else
|
27
|
+
gateways << {:id => id,
|
28
|
+
:names => [name],
|
29
|
+
:currencies => [currency],
|
30
|
+
:start_date => currency_gateway["start_date"]}
|
31
|
+
end
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
gateways
|
36
|
+
end
|
37
|
+
end # class GatewayParser
|
38
|
+
end # module Parsers
|
39
|
+
end # module Model
|
40
|
+
end # module XRBP
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Market List data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Market < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
j = JSON.parse(res)
|
15
|
+
return res unless j["result"] &&
|
16
|
+
j["result"]["markets"] &&
|
17
|
+
j["result"]["markets"]["base"]
|
18
|
+
j["result"]["markets"]["base"]
|
19
|
+
.collect { |market|
|
20
|
+
{:exchange => market["exchange"],
|
21
|
+
:currency => market["pair"][3..-1],
|
22
|
+
:route => market["route"]}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end # module Parsers
|
27
|
+
end # module Model
|
28
|
+
end # module XRBP
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Node Peers data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class NodePeers < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
JSON.parse(res)["overlay"]["active"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end # module Parsers
|
18
|
+
end # module Model
|
19
|
+
end # module XRBP
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Market quotes data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Quote < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
return [] unless res && res != ''
|
15
|
+
|
16
|
+
j = JSON.parse(res)
|
17
|
+
return [] unless j["result"]
|
18
|
+
|
19
|
+
j["result"].collect { |p, quotes|
|
20
|
+
next nil unless quotes
|
21
|
+
quotes.collect { |q|
|
22
|
+
t = q[0]
|
23
|
+
o = q[1]
|
24
|
+
h = q[2]
|
25
|
+
l = q[3]
|
26
|
+
c = q[4]
|
27
|
+
vol = q[5]
|
28
|
+
|
29
|
+
# discard invalid data
|
30
|
+
# (some exchanges periodically
|
31
|
+
# return '0's for some timestamps,
|
32
|
+
# perhaps for periods with no trades?)
|
33
|
+
next nil if o.zero? || h.zero? || l.zero? || c.zero? || vol.zero?
|
34
|
+
|
35
|
+
{:timestamp => Time.at(t).to_datetime,
|
36
|
+
:open => o,
|
37
|
+
:high => h,
|
38
|
+
:low => l,
|
39
|
+
:close => c,
|
40
|
+
:volume => vol}
|
41
|
+
}
|
42
|
+
}.flatten.compact
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # module Parsers
|
46
|
+
end # module Model
|
47
|
+
end # module XRBP
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Model
|
3
|
+
# @private
|
4
|
+
module Parsers
|
5
|
+
# Validator list data parser
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Validator < PluginBase
|
9
|
+
def parser_priority
|
10
|
+
0
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_result(res, req)
|
14
|
+
JSON.parse(res)["validators"].collect { |v|
|
15
|
+
id = v["validation_public_key"]
|
16
|
+
next nil unless id
|
17
|
+
|
18
|
+
{:id => id,
|
19
|
+
:domain => v["domain"]}
|
20
|
+
}.compact
|
21
|
+
end
|
22
|
+
end # class ValidatorParser
|
23
|
+
end # module Parsers
|
24
|
+
end # module Model
|
25
|
+
end # module XRBP
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative './parsers/validator'
|
2
|
+
|
3
|
+
module XRBP
|
4
|
+
module Model
|
5
|
+
class Validator < Base
|
6
|
+
extend Base::ClassMethods
|
7
|
+
|
8
|
+
# Retrieve list of validators via WebClient::Connection
|
9
|
+
#
|
10
|
+
# @param opts [Hash] options to retrieve validator list with
|
11
|
+
# @option opts [WebClient::Connection] :connection Connection
|
12
|
+
# to use to retrieve validator list
|
13
|
+
def self.all(opts={})
|
14
|
+
set_opts(opts)
|
15
|
+
connection.url = "https://data.ripple.com/v2/network/validators/"
|
16
|
+
|
17
|
+
connection.add_plugin :result_parser unless connection.plugin?(:result_parser)
|
18
|
+
connection.add_plugin Parsers::Validator unless connection.plugin?(Parsers::Validator)
|
19
|
+
|
20
|
+
connection.perform
|
21
|
+
end
|
22
|
+
end # class Validator
|
23
|
+
end # module Model
|
24
|
+
end # module XRBP
|
data/lib/xrbp/plugins.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module XRBP
|
2
|
+
# Helper mixin provding plugin management capabilities.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
module HasPlugin
|
6
|
+
# should be overridden
|
7
|
+
def plugin_namespace
|
8
|
+
raise
|
9
|
+
end
|
10
|
+
|
11
|
+
def plugins
|
12
|
+
@plugins ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_plugin(*plgs)
|
16
|
+
plgs.each { |plg|
|
17
|
+
plg = plugin_namespace.plugins[plg] if plg.is_a?(Symbol)
|
18
|
+
raise ArgumentError unless !!plg
|
19
|
+
plg = plg.new(self)
|
20
|
+
plugins << plg
|
21
|
+
plg.added if plg.respond_to?(:added)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def plugin?(plg)
|
26
|
+
clss = plugins.collect { |plg| plg.class }
|
27
|
+
cls = plugin_namespace.plugins[plg]
|
28
|
+
clss.include?(plg) || clss.include?(cls)
|
29
|
+
end
|
30
|
+
|
31
|
+
def plugin(plg)
|
32
|
+
cls = plugin_namespace.plugins[plg]
|
33
|
+
plugins.find { |_plg|
|
34
|
+
(plg.is_a?(Class) && _plg.kind_of?(plg)) ||
|
35
|
+
(cls.is_a?(Class) && _plg.class.kind_of?(cls))
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_instance_method(name, &block)
|
40
|
+
(class << self; self; end).class_eval do
|
41
|
+
define_method name, &block
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end # module HasPlugin
|
45
|
+
end # module XRBP
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module XRBP
|
2
|
+
# Helper mixing providing result parser management capabilities.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
module HasResultParsers
|
6
|
+
def parsing_plugins
|
7
|
+
raise
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_result(res, req)
|
11
|
+
_res = res
|
12
|
+
|
13
|
+
prioritized = parsing_plugins.select { |p|
|
14
|
+
p != self && p.respond_to?(:parse_result)
|
15
|
+
|
16
|
+
}.sort { |p1, p2|
|
17
|
+
(p1.respond_to?(:parser_priority) ? p1.parser_priority : 1) <=>
|
18
|
+
(p2.respond_to?(:parser_priority) ? p2.parser_priority : 1)
|
19
|
+
}
|
20
|
+
|
21
|
+
prioritized.each { |plg|
|
22
|
+
_res = plg.parse_result(_res, req)
|
23
|
+
}
|
24
|
+
_res
|
25
|
+
end
|
26
|
+
end # module HasResultParsers
|
27
|
+
end # module XRBP
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XRBP
|
2
|
+
# Helper mixin providing list of plugins.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
module PluginRegistry
|
6
|
+
module ClassMethods
|
7
|
+
def plugins
|
8
|
+
@plugins ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def register_plugin(label, cls)
|
12
|
+
plugins[label] = cls
|
13
|
+
end
|
14
|
+
end # module ClassMethods
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
end # module PluginRegistry
|
20
|
+
end # module XRBP
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module XRBP
|
2
|
+
# Result Parser plugin base class, allows request results
|
3
|
+
# to be converted before returning / invoking callback.
|
4
|
+
class ResultParserBase < PluginBase
|
5
|
+
attr_accessor :parser
|
6
|
+
|
7
|
+
def added
|
8
|
+
plugin = self
|
9
|
+
connection.define_instance_method(:parse_results) do |&bl|
|
10
|
+
plugin.parser = bl
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_result(res, req)
|
15
|
+
return res unless parser
|
16
|
+
parser.call(res, req)
|
17
|
+
end
|
18
|
+
end # class ResultParserBase
|
19
|
+
end # module XRBP
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module XRBP
|
2
|
+
# Helper mixin facilitating controlled termination of
|
3
|
+
# asynchronous components.
|
4
|
+
#
|
5
|
+
# @private
|
6
|
+
module Terminatable
|
7
|
+
def terminate_queue
|
8
|
+
@terminate_queue ||= Queue.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def terminate?
|
12
|
+
!!terminate_queue.pop_or_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def terminate!
|
16
|
+
terminate_queue << true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
module XRBP
|
4
|
+
# Helper mixin providing internal thread management.
|
5
|
+
#
|
6
|
+
# @private
|
7
|
+
module ThreadRegistry
|
8
|
+
def thread_registry
|
9
|
+
@thread_registry ||= Concurrent::Array.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def rsleep(t)
|
13
|
+
thread_registry << Thread.current
|
14
|
+
sleep(t)
|
15
|
+
thread_registry.delete(Thread.current)
|
16
|
+
end
|
17
|
+
|
18
|
+
def wake_all
|
19
|
+
thread_registry.each { |th| th.wakeup }
|
20
|
+
end
|
21
|
+
end # module ThreadRegistry
|
22
|
+
end # module XRBP
|
data/lib/xrbp/version.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'curb'
|
2
|
+
require_relative '../thread_registry'
|
3
|
+
|
4
|
+
module XRBP
|
5
|
+
module WebClient
|
6
|
+
# HTTP interface, use Connection to perform web requests.
|
7
|
+
#
|
8
|
+
# @example retrieve data from the web
|
9
|
+
# connection = WebClient::Connection.new
|
10
|
+
# connection.url = "https://devnull.network"
|
11
|
+
# connection.perform
|
12
|
+
class Connection
|
13
|
+
include EventEmitter
|
14
|
+
include HasPlugin
|
15
|
+
include HasResultParsers
|
16
|
+
include ThreadRegistry
|
17
|
+
|
18
|
+
DELEGATED_METHODS = [:url=,
|
19
|
+
:timeout=,
|
20
|
+
:ssl_verify_peer=,
|
21
|
+
:ssl_verify_host=]
|
22
|
+
|
23
|
+
# @private
|
24
|
+
def plugin_namespace
|
25
|
+
WebClient
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
def parsing_plugins
|
30
|
+
plugins
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return current url
|
34
|
+
def url
|
35
|
+
c.url
|
36
|
+
end
|
37
|
+
|
38
|
+
# delegated methods
|
39
|
+
DELEGATED_METHODS.each { |m|
|
40
|
+
define_method(m) do |v|
|
41
|
+
c.send(m, v)
|
42
|
+
end
|
43
|
+
}
|
44
|
+
|
45
|
+
def initialize(url=nil)
|
46
|
+
self.url = url
|
47
|
+
@force_quit = false
|
48
|
+
|
49
|
+
yield self if block_given?
|
50
|
+
end
|
51
|
+
|
52
|
+
def force_quit?
|
53
|
+
@force_quit
|
54
|
+
end
|
55
|
+
|
56
|
+
# Immediate terminate outstanding requests
|
57
|
+
def force_quit!
|
58
|
+
@force_quit = true
|
59
|
+
wake_all
|
60
|
+
# TODO immediate terminate outstanding requests
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def c
|
66
|
+
@curl ||= Curl::Easy.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_error
|
70
|
+
plugins.select { |plg|
|
71
|
+
plg.respond_to?(:handle_error)
|
72
|
+
}.last&.handle_error
|
73
|
+
end
|
74
|
+
|
75
|
+
public
|
76
|
+
|
77
|
+
# Execute web request, retrieving results and returning
|
78
|
+
def perform
|
79
|
+
# TODO fault tolerance plugins:
|
80
|
+
# configurable timeout,
|
81
|
+
# round-robin urls,
|
82
|
+
# redirect handling, etc
|
83
|
+
begin
|
84
|
+
c.perform
|
85
|
+
rescue => e
|
86
|
+
emit :error, e
|
87
|
+
return handle_error
|
88
|
+
end
|
89
|
+
|
90
|
+
if c.response_code != 200
|
91
|
+
emit :http_error, c.response_code
|
92
|
+
return handle_error
|
93
|
+
end
|
94
|
+
|
95
|
+
emit :success, c.body_str
|
96
|
+
parse_result(c.body_str, c)
|
97
|
+
end
|
98
|
+
end # class Connection
|
99
|
+
end # module WebClient
|
100
|
+
end # module XRBP
|