xrbp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []