Class: Bitcoin::Network::CommandHandler
- Inherits:
-
EM::Connection
- Object
- EM::Connection
- Bitcoin::Network::CommandHandler
- Defined in:
- lib/bitcoin/network/command_handler.rb
Overview
Started by the Node, accepts connections from CommandClient and answers requests or registers for events and notifies the clients when they happen.
Instance Method Summary collapse
-
#format_uptime(t) ⇒ Object
format node uptime.
-
#handle_addrs(count = 32) ⇒ Object
display known peer addrs (used by bin/bitcoin_dns_seed) bitcoin_node addrs [count].
-
#handle_config ⇒ Object
display configuration hash currently used bitcoin_node config.
-
#handle_connect(*args) ⇒ Object
connect to given peer(s) bitcoin_node connect
: [, : ]. -
#handle_connections ⇒ Object
display connected peers bitcoin_node connections.
-
#handle_disconnect(*args) ⇒ Object
disconnect peer(s) bitcoin_node disconnect
: [, , ]. -
#handle_getaddr ⇒ Object
trigger node to ask for new peer addrs bitcoin_node getaddr.
-
#handle_getblocks ⇒ Object
trigger node to ask peers for new blocks bitcoin_node getblocks.
-
#handle_help ⇒ Object
list all commands bitcoin_node help.
-
#handle_info ⇒ Object
display various statistics bitcoin_node info.
-
#handle_monitor(*channels) ⇒ Object
handle
monitorcommand; subscribe client to specified channels (+block+,tx,connection) bitcoin_node monitor block bitcoin_node monitor "block tx connection". -
#handle_relay_tx(data) ⇒ Object
relay given transaction (in hex) bitcoin_node relay_tx
. -
#handle_stop ⇒ Object
stop bitcoin node bitcoin_node stop.
-
#initialize(node) ⇒ CommandHandler
constructor
create new CommandHandler.
-
#log ⇒ Object
wrap logger and append prefix.
-
#receive_data(data) ⇒ Object
receive request from the client.
-
#respond(cmd, data) ⇒ Object
respond to a command; send serialized response to the client.
-
#unbind ⇒ Object
disconnect notification clients when connection is closed.
Constructor Details
#initialize(node) ⇒ CommandHandler
create new CommandHandler
9 10 11 12 13 14 |
# File 'lib/bitcoin/network/command_handler.rb', line 9 def initialize node @node = node @node.command_connections << self @buf = BufferedTokenizer.new("\x00") @lock = Monitor.new end |
Instance Method Details
#format_uptime(t) ⇒ Object
format node uptime
166 167 168 169 170 171 |
# File 'lib/bitcoin/network/command_handler.rb', line 166 def format_uptime t mm, ss = t.divmod(60) #=> [4515, 21] hh, mm = mm.divmod(60) #=> [75, 15] dd, hh = hh.divmod(24) #=> [3, 3] "%02d:%02d:%02d:%02d" % [dd, hh, mm, ss] end |
#handle_addrs(count = 32) ⇒ Object
display known peer addrs (used by bin/bitcoin_dns_seed) bitcoin_node addrs [count]
135 136 137 138 139 140 141 |
# File 'lib/bitcoin/network/command_handler.rb', line 135 def handle_addrs count = 32 @node.addrs.weighted_sample(count.to_i) do |addr| Time.now.tv_sec + 7200 - addr.time end.map do |addr| [addr.ip, addr.port, Time.now.tv_sec - addr.time] rescue nil end.compact end |
#handle_config ⇒ Object
display configuration hash currently used bitcoin_node config
86 87 88 |
# File 'lib/bitcoin/network/command_handler.rb', line 86 def handle_config @node.config end |
#handle_connect(*args) ⇒ Object
connect to given peer(s)
bitcoin_node connect
103 104 105 106 |
# File 'lib/bitcoin/network/command_handler.rb', line 103 def handle_connect *args args.each {|a| @node.connect_peer(*a.split(':')) } {:state => "Connecting..."} end |
#handle_connections ⇒ Object
display connected peers bitcoin_node connections
92 93 94 95 96 97 98 99 |
# File 'lib/bitcoin/network/command_handler.rb', line 92 def handle_connections @node.connections.sort{|x,y| y.uptime <=> x.uptime}.map{|c| "#{c.host.rjust(15)}:#{c.port} [state: #{c.state}, " + "version: #{c.version.version rescue '?'}, " + "block: #{c.version.block rescue '?'}, " + "uptime: #{format_uptime(c.uptime) rescue 0}, " + "client: #{c.version.user_agent rescue '?'}]" } end |
#handle_disconnect(*args) ⇒ Object
disconnect peer(s)
bitcoin_node disconnect
110 111 112 113 114 115 116 117 |
# File 'lib/bitcoin/network/command_handler.rb', line 110 def handle_disconnect *args args.each do |c| host, port = *c.split(":") conn = @node.connections.select{|c| c.host == host && c.port == port.to_i}.first conn.close_connection if conn end {:state => "Disconnected"} end |
#handle_getaddr ⇒ Object
trigger node to ask for new peer addrs bitcoin_node getaddr
128 129 130 131 |
# File 'lib/bitcoin/network/command_handler.rb', line 128 def handle_getaddr @node.connections.sample.send_getaddr {:state => "Sending getaddr..."} end |
#handle_getblocks ⇒ Object
trigger node to ask peers for new blocks bitcoin_node getblocks
121 122 123 124 |
# File 'lib/bitcoin/network/command_handler.rb', line 121 def handle_getblocks @node.connections.sample.send_getblocks {:state => "Sending getblocks..."} end |
#handle_help ⇒ Object
list all commands bitcoin_node help
161 162 163 |
# File 'lib/bitcoin/network/command_handler.rb', line 161 def handle_help self.methods.grep(/^handle_(.*?)/).map {|m| m.to_s.sub(/^(.*?)_/, '')} end |
#handle_info ⇒ Object
display various statistics bitcoin_node info
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/bitcoin/network/command_handler.rb', line 68 def handle_info blocks = @node.connections.map(&:version).compact.map(&:block) rescue nil { :blocks => "#{@node.store.get_depth} (#{(blocks.inject{|a,b| a+=b;a} / blocks.size rescue '?')})#{@node.in_sync ? ' sync' : ''}", :addrs => "#{@node.addrs.select{|a| a.alive?}.size} (#{@node.addrs.size})", :connections => "#{@node.connections.select{|c| c.state == :connected}.size} (#{@node.connections.size})", :queue => @node.queue.size, :inv_queue => @node.inv_queue.size, :inv_cache => @node.inv_cache.size, :network => @node.config[:network], :storage => @node.config[:storage], :version => Bitcoin::Protocol::VERSION, :uptime => format_uptime(@node.uptime), } end |
#handle_monitor(*channels) ⇒ Object
handle monitor command; subscribe client to specified channels
(+block+, tx, connection)
bitcoin_node monitor block
bitcoin_node monitor "block tx connection"
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/bitcoin/network/command_handler.rb', line 48 def handle_monitor *channels channels.each do |channel| @node.notifiers[channel.to_sym].subscribe do |*data| respond("monitor", [channel, *data]) end case channel.to_sym when :block head = Bitcoin::P::Block.new(@node.store.get_head.to_payload) rescue nil respond("monitor", ["block", [head, @node.store.get_depth.to_s]]) if head when :connection @node.connections.select {|c| c.connected?}.each do |conn| respond("monitor", [:connection, [:connected, conn.info]]) end end end nil end |
#handle_relay_tx(data) ⇒ Object
relay given transaction (in hex)
bitcoin_node relay_tx
145 146 147 148 149 150 |
# File 'lib/bitcoin/network/command_handler.rb', line 145 def handle_relay_tx data tx = Bitcoin::Protocol::Tx.from_hash(data) @node.relay_tx(tx) rescue {:error => $!} end |
#handle_stop ⇒ Object
stop bitcoin node bitcoin_node stop
154 155 156 157 |
# File 'lib/bitcoin/network/command_handler.rb', line 154 def handle_stop Thread.start { sleep 0.1; @node.stop } {:state => "Stopping..."} end |
#log ⇒ Object
wrap logger and append prefix
17 18 19 |
# File 'lib/bitcoin/network/command_handler.rb', line 17 def log @log ||= Bitcoin::Logger::LogWrapper.new("command:", @node.log) end |
#receive_data(data) ⇒ Object
receive request from the client
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/bitcoin/network/command_handler.rb', line 30 def receive_data data @buf.extract(data).each do |packet| cmd, args = JSON::parse(packet) log.debug { [cmd, args] } if respond_to?("handle_#{cmd}") respond(cmd, send("handle_#{cmd}", *args)) else respond(cmd, {:error => "unknown command: #{cmd}. send 'help' for help."}) end end rescue Exception p $! end |
#respond(cmd, data) ⇒ Object
respond to a command; send serialized response to the client
22 23 24 25 26 27 |
# File 'lib/bitcoin/network/command_handler.rb', line 22 def respond(cmd, data) return unless data @lock.synchronize do send_data([cmd, data].to_json + "\x00") end end |
#unbind ⇒ Object
disconnect notification clients when connection is closed
174 175 176 177 |
# File 'lib/bitcoin/network/command_handler.rb', line 174 def unbind #@node.notifiers.unsubscribe(@notify_sid) if @notify_sid @node.command_connections.delete(self) end |