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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d140a426f073971891c8e8e81f5313112c661703cebaee32719f6b04d6ca86b0
4
+ data.tar.gz: 394f8602052b068b2816ddfa4e06621e7537311b26a9d8248c8eaeb44514e510
5
+ SHA512:
6
+ metadata.gz: b47922beac1ce4613e1bc4b8953bcdf9368d9fdecdef26b6c489f08ad00db2ce2be9780fa9e3fdcdf3f9b31f5912dd4c54c352e8833c002cef6e5c0c30edbafd
7
+ data.tar.gz: '0833467cf31a91d158f78b9b480faaddb4447fc7bd4eeb693b21e93ac91ad9e7fdd7ede68e432d7b4755da81ac6fd46f08abaf97e27e27536eee22a34b0af503'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2019 Dev Null Productions <devnullproductions@gmail.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ XRBP - Ruby XRP Library
2
+ Copyright (C) 2019 Dev Null Productions
3
+ MIT License
4
+
5
+ ---
6
+
7
+ XRPB is a rubygem which facilitates reading and writing data to/from the XRP ledger.
@@ -0,0 +1,20 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+
6
+ ws.on :open do
7
+ puts "Opened"
8
+ end
9
+
10
+ ws.on :close do
11
+ puts "Closed"
12
+ end
13
+
14
+ ws.on :error do |e|
15
+ puts "Err #{e}"
16
+ end
17
+
18
+ ws.add_plugin :autoconnect, :connection_timeout
19
+ ws.connection_timeout = 3
20
+ sleep(60)
data/examples/cmd.rb ADDED
@@ -0,0 +1,13 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+
6
+ ws.connect
7
+ ws.add_plugin :command_dispatcher
8
+ ws.cmd(XRBP::WebSocket::Cmds::ServerInfo.new) do |r|
9
+ puts r
10
+ ws.close!
11
+ end
12
+
13
+ ws.wait_for_close
@@ -0,0 +1,15 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+ ws.add_plugin :command_dispatcher
6
+ ws.connect
7
+
8
+ puts XRBP::Model::Ledger.new.sync(:connection => ws)
9
+
10
+ XRBP::Model::Ledger.new.sync(:connection => ws) do |l|
11
+ puts l
12
+ ws.close!
13
+ end
14
+
15
+ ws.wait_for_close
@@ -0,0 +1,20 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Parallel.new "wss://s1.ripple.com:443",
5
+ "wss://s2.ripple.com:443"
6
+ ws.add_plugin :command_dispatcher
7
+ ws.connect
8
+
9
+ l = 0
10
+ ws.on :message do |msg|
11
+ msg = JSON.parse(msg.data)
12
+ next unless msg["ledger_index"] && msg["ledger_index"] > l
13
+ l = msg["ledger_index"]
14
+ puts msg
15
+ end
16
+
17
+ XRBP::Model::Ledger.subscribe(:connection => ws)
18
+
19
+ #ws.wait_for_close
20
+ sleep(1) while true
@@ -0,0 +1,18 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+ ws.add_plugin :command_dispatcher
6
+ ws.connect
7
+
8
+ i = 0
9
+ ws.on :message do |msg|
10
+ puts msg
11
+
12
+ i += 1
13
+ ws.close! if i > 5
14
+ end
15
+
16
+ XRBP::Model::Ledger.subscribe(:connection => ws)
17
+
18
+ ws.wait_for_close
data/examples/multi.rb ADDED
@@ -0,0 +1,10 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::MultiConnection.new "wss://s1.ripple.com:443",
5
+ "wss://s2.ripple.com:443"
6
+
7
+ ws.add_plugin :command_dispatcher
8
+ ws.connect
9
+
10
+ puts ws.cmd(XRBP::WebSocket::Cmds::ServerInfo.new)
@@ -0,0 +1,13 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+
6
+ ws.connect
7
+ ws.add_plugin :command_dispatcher, :command_paginator
8
+ ws.cmd(XRBP::WebSocket::Cmds::AccountObjects.new("rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq", :paginate => true)) do |r|
9
+ puts r
10
+ ws.close!
11
+ end
12
+
13
+ ws.wait_for_close
@@ -0,0 +1,13 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Prioritized.new "wss://s1.ripple.com:443",
5
+ "wss://s2.ripple.com:443"
6
+
7
+ ws.add_plugin :command_dispatcher, :result_parser
8
+ ws.parse_results { |res|
9
+ res["result"]["ledger"]
10
+ }
11
+ ws.connect
12
+
13
+ puts ws.cmd(XRBP::WebSocket::Cmds::Ledger.new(28327070))
@@ -0,0 +1,11 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::RoundRobin.new "wss://s1.ripple.com:443",
5
+ "wss://s2.ripple.com:443"
6
+
7
+ ws.add_plugin :command_dispatcher
8
+ ws.connect
9
+
10
+ puts ws.cmd(XRBP::WebSocket::Cmds::ServerInfo.new)
11
+ puts ws.cmd(XRBP::WebSocket::Cmds::ServerInfo.new)
@@ -0,0 +1,20 @@
1
+ $: << File.expand_path('../../lib', __FILE__)
2
+ require 'xrbp'
3
+
4
+ ws = XRBP::WebSocket::Connection.new "wss://s1.ripple.com:443"
5
+
6
+ ws.on :open do
7
+ puts "Opened"
8
+ ws.close!
9
+ end
10
+
11
+ ws.on :close do
12
+ puts "Closed"
13
+ end
14
+
15
+ ws.on :error do |e|
16
+ puts "Err #{e}"
17
+ end
18
+
19
+ ws.connect
20
+ ws.wait_for_close
@@ -0,0 +1,27 @@
1
+ module XRBP
2
+ module Model
3
+ class Account < Base
4
+ extend Base::ClassMethods
5
+
6
+ attr_accessor :id
7
+
8
+ def self.create(opts={})
9
+ end
10
+
11
+ def initialize(opts={})
12
+ @id = opts[:id]
13
+ super(opts)
14
+ end
15
+
16
+ def info(opts={}, &bl)
17
+ set_opts(opts)
18
+ connection.cmd(WebSocket::Cmds::AccountInfo.new(id, full_opts), &bl)
19
+ end
20
+
21
+ def objects(opts={}, &bl)
22
+ set_opts(opts)
23
+ connection.cmd(WebSocket::Cmds::AccountObjects.new(id, full_opts), &bl)
24
+ end
25
+ end # class Account
26
+ end # module Model
27
+ end # module XRBP
@@ -0,0 +1,31 @@
1
+ module XRBP
2
+ module Model
3
+ class Base
4
+ module ClassMethods
5
+ attr_accessor :opts, :connection
6
+
7
+ def set_opts(opts={})
8
+ self.opts ||= {}
9
+ self.opts.merge!(opts)
10
+ self.connection = opts[:connection] if opts[:connection]
11
+ end
12
+ end
13
+
14
+ attr_accessor :opts, :connection
15
+
16
+ def initialize(opts={})
17
+ set_opts(opts)
18
+ end
19
+
20
+ def set_opts(opts={})
21
+ @opts ||= {}
22
+ @opts.merge!(opts)
23
+ @connection = opts[:connection] if opts[:connection]
24
+ end
25
+
26
+ def full_opts
27
+ (self.class.opts || {}).merge(opts || {}).except(:connection)
28
+ end
29
+ end # class Base
30
+ end # module Model
31
+ end # module XRBP
@@ -0,0 +1,24 @@
1
+ module XRBP
2
+ module Model
3
+ class Ledger < Base
4
+ extend Base::ClassMethods
5
+
6
+ attr_accessor :id
7
+
8
+ def initialize(opts={})
9
+ @id = opts[:id]
10
+ super(opts)
11
+ end
12
+
13
+ def sync(opts={}, &bl)
14
+ set_opts(opts)
15
+ connection.cmd(WebSocket::Cmds::Ledger.new(id, full_opts), &bl)
16
+ end
17
+
18
+ def self.subscribe(opts={}, &bl)
19
+ set_opts(opts)
20
+ connection.cmd(WebSocket::Cmds::Subscribe.new(:streams => ["ledger"]), &bl)
21
+ end
22
+ end # class Ledger
23
+ end # module Model
24
+ end # module XRBP
data/lib/xrbp/model.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative './model/base'
2
+ require_relative './model/ledger'
3
+ require_relative './model/account'
@@ -0,0 +1,8 @@
1
+ module XRBP
2
+ module Network
3
+ class Node
4
+ # TODO retrieve individual node peers &
5
+ # iterator-based mechanism to crawl nodes
6
+ end
7
+ end # module Network
8
+ end # module XRBP
@@ -0,0 +1,6 @@
1
+ # TODO implement these http based synchronization targets (w/ robust common http logic)
2
+ #require_relative './network/nodes'
3
+ #require_relative './network/validators'
4
+ #require_relative './network/gateways'
5
+ #require_relative './network/valuations'
6
+ #require_relative './network/tips'
@@ -0,0 +1,3 @@
1
+ module XRBP
2
+ VERSION = '0.0.1'
3
+ end # module XRBP
@@ -0,0 +1,127 @@
1
+ require 'websocket'
2
+
3
+ module XRBP
4
+ module WebSocket
5
+ class Client
6
+ include EventEmitter
7
+
8
+ attr_reader :url, :options
9
+
10
+ def initialize(url, options={})
11
+ @url = url
12
+ @options = options
13
+
14
+ @handshaked = false
15
+ @closed = false
16
+ end
17
+
18
+ def connect
19
+ emit :connecting
20
+ @closed = false
21
+ socket.connect
22
+ handshake!
23
+ @thread = poll
24
+ self
25
+ end
26
+
27
+ ###
28
+
29
+ def open?
30
+ handshake.finished? and !closed?
31
+ end
32
+
33
+ def closed?
34
+ !!@closed
35
+ end
36
+
37
+ def close(err=nil)
38
+ return if closed?
39
+
40
+ # XXX set closed true first incase callbacks need to check this
41
+ @closed = true
42
+
43
+ send_data nil, :type => :close unless socket.pipe_broken
44
+ emit :close, err
45
+
46
+ ensure
47
+ # Always set closed true
48
+ @closed = true
49
+ socket.close if socket
50
+ @handshake = nil
51
+ @handshaked = false
52
+ @socket = nil
53
+ #Thread.kill @thread if @thread
54
+ @thread.join if @thread && Thread.current != @thread
55
+ emit :completed
56
+ end
57
+
58
+ ###
59
+
60
+ def socket
61
+ @socket ||= Socket.new self
62
+ end
63
+
64
+ ###
65
+
66
+ def handshake
67
+ @handshake ||= ::WebSocket::Handshake::Client.new :url => url,
68
+ :headers => options[:headers]
69
+ end
70
+
71
+ def handshaked?
72
+ !!@handshaked
73
+ end
74
+
75
+ def handshake!
76
+ socket.write handshake.to_s
77
+
78
+ until handshaked?
79
+ socket.read_next handshake
80
+ @handshaked = handshake.finished?
81
+ end
82
+ end
83
+
84
+ ###
85
+
86
+ def send_data(data, opt={:type => :text})
87
+ return if !handshaked? || closed?
88
+
89
+ frame = ::WebSocket::Frame::Outgoing::Client.new(:data => data,
90
+ :type => opt[:type],
91
+ :version => handshake.version)
92
+
93
+ begin
94
+ socket.write_nonblock(frame.to_s)
95
+
96
+ rescue Errno::EPIPE, OpenSSL::SSL::SSLError => e
97
+ close(e)
98
+ end
99
+ end
100
+
101
+ def poll
102
+ return Thread.new(socket) do |socket|
103
+ frame = ::WebSocket::Frame::Incoming::Client.new
104
+ emit :open
105
+
106
+ until closed? do
107
+ begin
108
+ socket.read_next(frame)
109
+
110
+ if msg = frame.next
111
+ emit :message, msg
112
+ frame = ::WebSocket::Frame::Incoming::Client.new
113
+ end
114
+
115
+ rescue EOFError => e
116
+ emit :error, e
117
+ close(e)
118
+
119
+ rescue => e
120
+ emit :error, e
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end # class Client
126
+ end # module WebSocket
127
+ end # module XRBP
@@ -0,0 +1,20 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class AccountInfo < Command
5
+ attr_accessor :account, :args
6
+
7
+ def initialize(account, args={})
8
+ @account = account
9
+ @args = args
10
+ super(to_h)
11
+ end
12
+
13
+ def to_h
14
+ args.merge(:command => :account_info,
15
+ :account => account)
16
+ end
17
+ end # class AccountInfo
18
+ end # module Cmds
19
+ end # module WebSocket
20
+ end # module Wipple
@@ -0,0 +1,33 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class AccountLines < Command
5
+ include Paginated
6
+
7
+ def page_title
8
+ "account_lines"
9
+ end
10
+
11
+ attr_accessor :account, :args
12
+
13
+ def initialize(account, args={})
14
+ @account = account
15
+ @args = args
16
+ parse_paginate(args)
17
+ super(to_h)
18
+ end
19
+
20
+ def self.from_h(h)
21
+ _h = Hash[h]
22
+ a = _h.delete(:account)
23
+ new a, _h
24
+ end
25
+
26
+ def to_h
27
+ args_without_paginate.merge(:command => :account_lines,
28
+ :account => account)
29
+ end
30
+ end # class AccountLines
31
+ end # module Cmds
32
+ end # module WebSocket
33
+ end # module Wipple
@@ -0,0 +1,33 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class AccountObjects < Command
5
+ include Paginated
6
+
7
+ def page_title
8
+ "account_objects"
9
+ end
10
+
11
+ attr_accessor :account, :args
12
+
13
+ def initialize(account, args={})
14
+ @account = account
15
+ @args = args
16
+ parse_paginate(args)
17
+ super(to_h)
18
+ end
19
+
20
+ def self.from_h(h)
21
+ _h = Hash[h]
22
+ a = _h.delete(:account)
23
+ new a, _h
24
+ end
25
+
26
+ def to_h
27
+ args_without_paginate.merge(:command => :account_objects,
28
+ :account => account)
29
+ end
30
+ end # class AccountLines
31
+ end # module Cmds
32
+ end # module WebSocket
33
+ end # module Wipple
@@ -0,0 +1,33 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class AccountOffers < Command
5
+ include Paginated
6
+
7
+ def page_title
8
+ "offers"
9
+ end
10
+
11
+ attr_accessor :account, :args
12
+
13
+ def initialize(account, args={})
14
+ @account = account
15
+ @args = args
16
+ parse_paginate(args)
17
+ super(to_h)
18
+ end
19
+
20
+ def self.from_h(h)
21
+ _h = Hash[h]
22
+ a = _h.delete(:account)
23
+ new a, _h
24
+ end
25
+
26
+ def to_h
27
+ args_without_paginate.merge(:command => :account_offers,
28
+ :account => account)
29
+ end
30
+ end # class AccountLines
31
+ end # module Cmds
32
+ end # module WebSocket
33
+ end # module Wipple
@@ -0,0 +1,20 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class AccountTx < Command
5
+ attr_accessor :account, :args
6
+
7
+ def initialize(account, args={})
8
+ @account = account
9
+ @args = args
10
+ super(to_h)
11
+ end
12
+
13
+ def to_h
14
+ args.merge(:command => :account_tx,
15
+ :account => account)
16
+ end
17
+ end # class AccountLines
18
+ end # module Cmds
19
+ end # module WebSocket
20
+ end # module Wipple
@@ -0,0 +1,38 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class BookOffers < Command
5
+ include Paginated
6
+
7
+ def page_title
8
+ "offers"
9
+ end
10
+
11
+ attr_accessor :args
12
+
13
+ def initialize(args={})
14
+ @args = args
15
+ parse_paginate(args)
16
+ super(to_h)
17
+ end
18
+
19
+ def self.from_h(h)
20
+ new Hash[h]
21
+ end
22
+
23
+ def sanitized_args
24
+ sa = Hash[args_without_paginate]
25
+
26
+ sa[:taker_gets].delete(:issuer) if sa[:taker_gets][:currency] == "XRP"
27
+ sa[:taker_pays].delete(:issuer) if sa[:taker_pays][:currency] == "XRP"
28
+
29
+ sa
30
+ end
31
+
32
+ def to_h
33
+ sanitized_args.merge(:command => :book_offers)
34
+ end
35
+ end # class BookOffers
36
+ end # module Cmds
37
+ end # module WebSocket
38
+ end # module Wipple
@@ -0,0 +1,25 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class Ledger < Command
5
+ attr_accessor :id, :args
6
+
7
+ def initialize(id=nil, args={})
8
+ @id = id
9
+ @args = args
10
+ super(to_h)
11
+ end
12
+
13
+ def id?
14
+ !!id
15
+ end
16
+
17
+ def to_h
18
+ h = args.merge(:command => :ledger)
19
+ h['ledger_index'] = id if id?
20
+ return h
21
+ end
22
+ end
23
+ end # module Cmds
24
+ end # module WebSocket
25
+ end # module Wipple
@@ -0,0 +1,16 @@
1
+ module XRBP
2
+ module WebSocket
3
+ module Cmds
4
+ class LedgerEntry < Command
5
+ def initialize(args={})
6
+ @args = args
7
+ super(to_h)
8
+ end
9
+
10
+ def to_h
11
+ @args.merge('command' => 'ledger_entry')
12
+ end
13
+ end
14
+ end # module Cmds
15
+ end # module WebSocket
16
+ end # module Wipple