xrbp 0.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +7 -0
  4. data/examples/autoconnect_timeout.rb +20 -0
  5. data/examples/cmd.rb +13 -0
  6. data/examples/ledger.rb +15 -0
  7. data/examples/ledger_multi_subscribe.rb +20 -0
  8. data/examples/ledger_subscribe.rb +18 -0
  9. data/examples/multi.rb +10 -0
  10. data/examples/paginate.rb +13 -0
  11. data/examples/prioritized.rb +13 -0
  12. data/examples/round_robin.rb +11 -0
  13. data/examples/websocket.rb +20 -0
  14. data/lib/xrbp/model/account.rb +27 -0
  15. data/lib/xrbp/model/base.rb +31 -0
  16. data/lib/xrbp/model/ledger.rb +24 -0
  17. data/lib/xrbp/model.rb +3 -0
  18. data/lib/xrbp/network/nodes.rb +8 -0
  19. data/lib/xrbp/network.rb +6 -0
  20. data/lib/xrbp/version.rb +3 -0
  21. data/lib/xrbp/websocket/client.rb +127 -0
  22. data/lib/xrbp/websocket/cmds/account_info.rb +20 -0
  23. data/lib/xrbp/websocket/cmds/account_lines.rb +33 -0
  24. data/lib/xrbp/websocket/cmds/account_objects.rb +33 -0
  25. data/lib/xrbp/websocket/cmds/account_offers.rb +33 -0
  26. data/lib/xrbp/websocket/cmds/account_tx.rb +20 -0
  27. data/lib/xrbp/websocket/cmds/book_offers.rb +38 -0
  28. data/lib/xrbp/websocket/cmds/ledger.rb +25 -0
  29. data/lib/xrbp/websocket/cmds/ledger_entry.rb +16 -0
  30. data/lib/xrbp/websocket/cmds/paginated.rb +43 -0
  31. data/lib/xrbp/websocket/cmds/server_info.rb +11 -0
  32. data/lib/xrbp/websocket/cmds/subscribe.rb +18 -0
  33. data/lib/xrbp/websocket/cmds.rb +12 -0
  34. data/lib/xrbp/websocket/command.rb +19 -0
  35. data/lib/xrbp/websocket/connection.rb +169 -0
  36. data/lib/xrbp/websocket/has_plugin.rb +30 -0
  37. data/lib/xrbp/websocket/message.rb +41 -0
  38. data/lib/xrbp/websocket/multi/fallback.rb +18 -0
  39. data/lib/xrbp/websocket/multi/multi_connection.rb +55 -0
  40. data/lib/xrbp/websocket/multi/parallel.rb +28 -0
  41. data/lib/xrbp/websocket/multi/prioritized.rb +15 -0
  42. data/lib/xrbp/websocket/multi/round_robin.rb +19 -0
  43. data/lib/xrbp/websocket/plugins/autoconnect.rb +42 -0
  44. data/lib/xrbp/websocket/plugins/command_dispatcher.rb +39 -0
  45. data/lib/xrbp/websocket/plugins/command_paginator.rb +45 -0
  46. data/lib/xrbp/websocket/plugins/connection_timeout.rb +54 -0
  47. data/lib/xrbp/websocket/plugins/message_dispatcher.rb +141 -0
  48. data/lib/xrbp/websocket/plugins/result_parser.rb +31 -0
  49. data/lib/xrbp/websocket/plugins.rb +18 -0
  50. data/lib/xrbp/websocket/socket.rb +109 -0
  51. data/lib/xrbp/websocket.rb +15 -0
  52. data/lib/xrbp.rb +5 -0
  53. 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
@@ -0,0 +1,5 @@
1
+ require 'event_emitter'
2
+
3
+ require 'xrbp/websocket'
4
+ require 'xrbp/model'
5
+ require 'xrbp/network'
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: []