xrbp 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +7 -0
- data/examples/autoconnect_timeout.rb +20 -0
- data/examples/cmd.rb +13 -0
- data/examples/ledger.rb +15 -0
- data/examples/ledger_multi_subscribe.rb +20 -0
- data/examples/ledger_subscribe.rb +18 -0
- data/examples/multi.rb +10 -0
- data/examples/paginate.rb +13 -0
- data/examples/prioritized.rb +13 -0
- data/examples/round_robin.rb +11 -0
- data/examples/websocket.rb +20 -0
- data/lib/xrbp/model/account.rb +27 -0
- data/lib/xrbp/model/base.rb +31 -0
- data/lib/xrbp/model/ledger.rb +24 -0
- data/lib/xrbp/model.rb +3 -0
- data/lib/xrbp/network/nodes.rb +8 -0
- data/lib/xrbp/network.rb +6 -0
- data/lib/xrbp/version.rb +3 -0
- data/lib/xrbp/websocket/client.rb +127 -0
- data/lib/xrbp/websocket/cmds/account_info.rb +20 -0
- data/lib/xrbp/websocket/cmds/account_lines.rb +33 -0
- data/lib/xrbp/websocket/cmds/account_objects.rb +33 -0
- data/lib/xrbp/websocket/cmds/account_offers.rb +33 -0
- data/lib/xrbp/websocket/cmds/account_tx.rb +20 -0
- data/lib/xrbp/websocket/cmds/book_offers.rb +38 -0
- data/lib/xrbp/websocket/cmds/ledger.rb +25 -0
- data/lib/xrbp/websocket/cmds/ledger_entry.rb +16 -0
- data/lib/xrbp/websocket/cmds/paginated.rb +43 -0
- data/lib/xrbp/websocket/cmds/server_info.rb +11 -0
- data/lib/xrbp/websocket/cmds/subscribe.rb +18 -0
- data/lib/xrbp/websocket/cmds.rb +12 -0
- data/lib/xrbp/websocket/command.rb +19 -0
- data/lib/xrbp/websocket/connection.rb +169 -0
- data/lib/xrbp/websocket/has_plugin.rb +30 -0
- data/lib/xrbp/websocket/message.rb +41 -0
- data/lib/xrbp/websocket/multi/fallback.rb +18 -0
- data/lib/xrbp/websocket/multi/multi_connection.rb +55 -0
- data/lib/xrbp/websocket/multi/parallel.rb +28 -0
- data/lib/xrbp/websocket/multi/prioritized.rb +15 -0
- data/lib/xrbp/websocket/multi/round_robin.rb +19 -0
- data/lib/xrbp/websocket/plugins/autoconnect.rb +42 -0
- data/lib/xrbp/websocket/plugins/command_dispatcher.rb +39 -0
- data/lib/xrbp/websocket/plugins/command_paginator.rb +45 -0
- data/lib/xrbp/websocket/plugins/connection_timeout.rb +54 -0
- data/lib/xrbp/websocket/plugins/message_dispatcher.rb +141 -0
- data/lib/xrbp/websocket/plugins/result_parser.rb +31 -0
- data/lib/xrbp/websocket/plugins.rb +18 -0
- data/lib/xrbp/websocket/socket.rb +109 -0
- data/lib/xrbp/websocket.rb +15 -0
- data/lib/xrbp.rb +5 -0
- metadata +123 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
module XRBP
|
2
|
+
module WebSocket
|
3
|
+
module Plugins
|
4
|
+
# Dispatch messages & wait for responses (w/ optional timeout)
|
5
|
+
class MessageDispatcher
|
6
|
+
attr_reader :connection, :messages
|
7
|
+
attr_accessor :message_timeout
|
8
|
+
|
9
|
+
DEFAULT_TIMEOUT = 10
|
10
|
+
|
11
|
+
def initialize(connection)
|
12
|
+
@connection = connection
|
13
|
+
@message_timeout = DEFAULT_TIMEOUT
|
14
|
+
@messages = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def added
|
18
|
+
plugin = self
|
19
|
+
|
20
|
+
connection.define_instance_method(:message_timeout=) do |t|
|
21
|
+
plugin.message_timeout = t
|
22
|
+
|
23
|
+
self.plugins.find { |plg|
|
24
|
+
plg.kind_of?(MessageDipsatcher)
|
25
|
+
}.message_timeout = t if self.kind_of?(MultiConnection)
|
26
|
+
end
|
27
|
+
|
28
|
+
connection.define_instance_method(:msg) do |msg, &bl|
|
29
|
+
return next_connection.msg msg, &bl if self.kind_of?(MultiConnection)
|
30
|
+
|
31
|
+
msg = Message.new(msg) unless msg.kind_of?(Message)
|
32
|
+
msg.connection = self
|
33
|
+
msg.bl = bl if bl
|
34
|
+
|
35
|
+
unless self.open?
|
36
|
+
msg.bl.call nil if msg.bl
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
plugin.messages << msg
|
41
|
+
|
42
|
+
send_data msg.to_s
|
43
|
+
|
44
|
+
return nil if bl
|
45
|
+
msg.wait
|
46
|
+
msg.result
|
47
|
+
end
|
48
|
+
|
49
|
+
connection.on :close do
|
50
|
+
plugin.messages.each { |msg|
|
51
|
+
plugin.cancel_message(msg)
|
52
|
+
}
|
53
|
+
end unless connection.kind_of?(MultiConnection)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Should be overridden in subclass return
|
57
|
+
# request message & formatted response
|
58
|
+
# given raw response
|
59
|
+
def match_message(msg)
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return bool if message,response is read to be unlocked / returned to client.
|
64
|
+
# Allows other plugins to block message unlocking
|
65
|
+
def unlock!(req, res)
|
66
|
+
!connection.plugins.any? { |plg|
|
67
|
+
plg != self && plg.respond_to?(:unlock!) && !plg.unlock!(req, res)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
# Allows plugins to convert results
|
72
|
+
def parse_result(res)
|
73
|
+
connection.plugins.each { |plg|
|
74
|
+
res = plg.parse_result(res) if plg != self && plg.respond_to?(:parse_result)
|
75
|
+
}
|
76
|
+
res
|
77
|
+
end
|
78
|
+
|
79
|
+
def message(res)
|
80
|
+
req, res = match_message(res)
|
81
|
+
return unless req
|
82
|
+
messages.delete(req)
|
83
|
+
|
84
|
+
return unless unlock!(req, res)
|
85
|
+
|
86
|
+
begin
|
87
|
+
res = parse_result(res)
|
88
|
+
rescue Exception => e
|
89
|
+
if conn = connection.next_connection(req.connection)
|
90
|
+
conn.msg(req, &req.bl)
|
91
|
+
return
|
92
|
+
|
93
|
+
else
|
94
|
+
res = nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
req.bl.call(res)
|
99
|
+
end
|
100
|
+
|
101
|
+
def cancel_message(msg)
|
102
|
+
connection.state_mutex.synchronize {
|
103
|
+
messages.delete(msg)
|
104
|
+
msg.signal
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
def opened
|
109
|
+
@timeout_thread = Thread.new {
|
110
|
+
# XXX remove force_quit? condition check from this loop,
|
111
|
+
# so we're sure messages always timeout, even on force quit.
|
112
|
+
# Always ensure close! is called after websocket is no longer
|
113
|
+
# being used!
|
114
|
+
until connection.closed? || Thread.current != @timeout_thread
|
115
|
+
now = Time.now
|
116
|
+
tmsgs = Array.new(messages)
|
117
|
+
tmsgs.each { |msg|
|
118
|
+
if now - msg.time > @message_timeout
|
119
|
+
connection.emit :timeout, msg
|
120
|
+
cancel_message(msg)
|
121
|
+
|
122
|
+
# XXX manually close the connection as
|
123
|
+
# a broken pipe will not stop websocket polling
|
124
|
+
connection.close!
|
125
|
+
end
|
126
|
+
}
|
127
|
+
|
128
|
+
connection.rsleep(0.1)
|
129
|
+
end
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def closed
|
134
|
+
@timeout_thread.join unless @timeout_thread == Thread.current
|
135
|
+
end
|
136
|
+
end # class MessageDispatcher
|
137
|
+
|
138
|
+
WebSocket.register_plugin :message_dispatcher, MessageDispatcher
|
139
|
+
end # module Plugins
|
140
|
+
end # module WebSocket
|
141
|
+
end # module XRBP
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module XRBP
|
2
|
+
module WebSocket
|
3
|
+
module Plugins
|
4
|
+
class ResultParser
|
5
|
+
attr_accessor :parser, :connection
|
6
|
+
|
7
|
+
def initialize(connection)
|
8
|
+
@connection = connection
|
9
|
+
end
|
10
|
+
|
11
|
+
def added
|
12
|
+
plugin = self
|
13
|
+
connection.define_instance_method(:parse_results) do |&bl|
|
14
|
+
plugin.parser = bl
|
15
|
+
|
16
|
+
self.connections.each { |conn|
|
17
|
+
conn.parse_results &bl
|
18
|
+
} if self.kind_of?(MultiConnection)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_result(res)
|
23
|
+
return res unless parser
|
24
|
+
parser.call(res)
|
25
|
+
end
|
26
|
+
end # class ResultParser
|
27
|
+
|
28
|
+
WebSocket.register_plugin :result_parser, ResultParser
|
29
|
+
end # module Plugins
|
30
|
+
end # module WebSocket
|
31
|
+
end # module XRBP
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module XRBP
|
2
|
+
module WebSocket
|
3
|
+
def self.plugins
|
4
|
+
@plugins ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.register_plugin(label, cls)
|
8
|
+
plugins[label] = cls
|
9
|
+
end
|
10
|
+
end # module WebSocket
|
11
|
+
end # module XRPB
|
12
|
+
|
13
|
+
require_relative './plugins/autoconnect'
|
14
|
+
require_relative './plugins/connection_timeout'
|
15
|
+
require_relative './plugins/message_dispatcher'
|
16
|
+
require_relative './plugins/command_dispatcher'
|
17
|
+
require_relative './plugins/command_paginator'
|
18
|
+
require_relative './plugins/result_parser'
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'socket'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module XRBP
|
6
|
+
module WebSocket
|
7
|
+
class Socket
|
8
|
+
DEFAULT_PORTS = {:ws => 80,
|
9
|
+
:http => 80,
|
10
|
+
:wss => 443,
|
11
|
+
:https => 443}
|
12
|
+
|
13
|
+
|
14
|
+
attr_reader :connection, :socket, :pipe_broken
|
15
|
+
|
16
|
+
def options
|
17
|
+
connection.options
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(connection)
|
21
|
+
@connection = connection
|
22
|
+
@pipe_broken = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def connect
|
26
|
+
uri = URI.parse connection.url
|
27
|
+
host = uri.host
|
28
|
+
port = uri.port || DEFAULT_PORTS[uri.scheme.intern]
|
29
|
+
|
30
|
+
@socket = TCPSocket.new(host, port)
|
31
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
32
|
+
|
33
|
+
init_ssl_socket if ['https', 'wss'].include? uri.scheme
|
34
|
+
end
|
35
|
+
|
36
|
+
def init_ssl_socket
|
37
|
+
ssl_context = options[:ssl_context] || begin
|
38
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
39
|
+
ctx.ssl_version = options[:ssl_version] || 'SSLv23'
|
40
|
+
|
41
|
+
# use VERIFY_PEER for verification:
|
42
|
+
ctx.verify_mode = options[:verify_mode] ||
|
43
|
+
OpenSSL::SSL::VERIFY_NONE
|
44
|
+
|
45
|
+
cert_store = OpenSSL::X509::Store.new
|
46
|
+
cert_store.set_default_paths
|
47
|
+
ctx.cert_store = cert_store
|
48
|
+
|
49
|
+
ctx
|
50
|
+
end
|
51
|
+
|
52
|
+
@socket = ::OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
53
|
+
socket.connect
|
54
|
+
end
|
55
|
+
|
56
|
+
###
|
57
|
+
|
58
|
+
def close
|
59
|
+
socket.close if socket
|
60
|
+
end
|
61
|
+
|
62
|
+
def write(data)
|
63
|
+
socket.write data
|
64
|
+
end
|
65
|
+
|
66
|
+
def write_nonblock(data)
|
67
|
+
begin
|
68
|
+
socket.write_nonblock(data)
|
69
|
+
|
70
|
+
rescue IO::WaitReadable
|
71
|
+
IO.select([socket]) # OpenSSL needs to read internally
|
72
|
+
retry
|
73
|
+
|
74
|
+
rescue IO::WaitWritable, Errno::EINTR
|
75
|
+
IO.select(nil, [socket])
|
76
|
+
retry
|
77
|
+
|
78
|
+
rescue Errno::EPIPE => e
|
79
|
+
@pipe_broken = true
|
80
|
+
raise
|
81
|
+
|
82
|
+
rescue OpenSSL::SSL::SSLError => e
|
83
|
+
@pipe_broken = true
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def read_next(dest)
|
89
|
+
begin
|
90
|
+
read_sockets, _, _ = IO.select([socket], nil, nil, 10)
|
91
|
+
|
92
|
+
if read_sockets && read_sockets[0]
|
93
|
+
dest << socket.read_nonblock(1024)
|
94
|
+
|
95
|
+
if socket.respond_to?(:pending) # SSLSocket
|
96
|
+
dest << socket.read(socket.pending) while socket.pending > 0
|
97
|
+
end
|
98
|
+
end
|
99
|
+
rescue IO::WaitReadable
|
100
|
+
# No op
|
101
|
+
|
102
|
+
rescue IO::WaitWritable
|
103
|
+
IO.select(nil, [socket])
|
104
|
+
retry
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end # class Socket
|
108
|
+
end # module WebSocket
|
109
|
+
end # module XRBP
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'xrbp/websocket/socket'
|
2
|
+
require 'xrbp/websocket/client'
|
3
|
+
require 'xrbp/websocket/connection'
|
4
|
+
|
5
|
+
require 'xrbp/websocket/multi/multi_connection'
|
6
|
+
require 'xrbp/websocket/multi/round_robin'
|
7
|
+
require 'xrbp/websocket/multi/prioritized'
|
8
|
+
require 'xrbp/websocket/multi/fallback'
|
9
|
+
require 'xrbp/websocket/multi/parallel'
|
10
|
+
|
11
|
+
require 'xrbp/websocket/message'
|
12
|
+
require 'xrbp/websocket/command'
|
13
|
+
require 'xrbp/websocket/plugins'
|
14
|
+
|
15
|
+
require 'xrbp/websocket/cmds'
|
data/lib/xrbp.rb
ADDED
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xrbp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dev Null Productions
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: websocket
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: event_emitter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
41
|
+
description: Ruby XRP Tools
|
42
|
+
email:
|
43
|
+
- devnullproductions@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE.txt
|
49
|
+
- README.md
|
50
|
+
- examples/autoconnect_timeout.rb
|
51
|
+
- examples/cmd.rb
|
52
|
+
- examples/ledger.rb
|
53
|
+
- examples/ledger_multi_subscribe.rb
|
54
|
+
- examples/ledger_subscribe.rb
|
55
|
+
- examples/multi.rb
|
56
|
+
- examples/paginate.rb
|
57
|
+
- examples/prioritized.rb
|
58
|
+
- examples/round_robin.rb
|
59
|
+
- examples/websocket.rb
|
60
|
+
- lib/xrbp.rb
|
61
|
+
- lib/xrbp/model.rb
|
62
|
+
- lib/xrbp/model/account.rb
|
63
|
+
- lib/xrbp/model/base.rb
|
64
|
+
- lib/xrbp/model/ledger.rb
|
65
|
+
- lib/xrbp/network.rb
|
66
|
+
- lib/xrbp/network/nodes.rb
|
67
|
+
- lib/xrbp/version.rb
|
68
|
+
- lib/xrbp/websocket.rb
|
69
|
+
- lib/xrbp/websocket/client.rb
|
70
|
+
- lib/xrbp/websocket/cmds.rb
|
71
|
+
- lib/xrbp/websocket/cmds/account_info.rb
|
72
|
+
- lib/xrbp/websocket/cmds/account_lines.rb
|
73
|
+
- lib/xrbp/websocket/cmds/account_objects.rb
|
74
|
+
- lib/xrbp/websocket/cmds/account_offers.rb
|
75
|
+
- lib/xrbp/websocket/cmds/account_tx.rb
|
76
|
+
- lib/xrbp/websocket/cmds/book_offers.rb
|
77
|
+
- lib/xrbp/websocket/cmds/ledger.rb
|
78
|
+
- lib/xrbp/websocket/cmds/ledger_entry.rb
|
79
|
+
- lib/xrbp/websocket/cmds/paginated.rb
|
80
|
+
- lib/xrbp/websocket/cmds/server_info.rb
|
81
|
+
- lib/xrbp/websocket/cmds/subscribe.rb
|
82
|
+
- lib/xrbp/websocket/command.rb
|
83
|
+
- lib/xrbp/websocket/connection.rb
|
84
|
+
- lib/xrbp/websocket/has_plugin.rb
|
85
|
+
- lib/xrbp/websocket/message.rb
|
86
|
+
- lib/xrbp/websocket/multi/fallback.rb
|
87
|
+
- lib/xrbp/websocket/multi/multi_connection.rb
|
88
|
+
- lib/xrbp/websocket/multi/parallel.rb
|
89
|
+
- lib/xrbp/websocket/multi/prioritized.rb
|
90
|
+
- lib/xrbp/websocket/multi/round_robin.rb
|
91
|
+
- lib/xrbp/websocket/plugins.rb
|
92
|
+
- lib/xrbp/websocket/plugins/autoconnect.rb
|
93
|
+
- lib/xrbp/websocket/plugins/command_dispatcher.rb
|
94
|
+
- lib/xrbp/websocket/plugins/command_paginator.rb
|
95
|
+
- lib/xrbp/websocket/plugins/connection_timeout.rb
|
96
|
+
- lib/xrbp/websocket/plugins/message_dispatcher.rb
|
97
|
+
- lib/xrbp/websocket/plugins/result_parser.rb
|
98
|
+
- lib/xrbp/websocket/socket.rb
|
99
|
+
homepage: https://devnull.network
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.7.6
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Helper module to read and write data from the XRP Ledger and related resources!
|
123
|
+
test_files: []
|