Class | IB::IB |
In: |
ib.rb
|
Parent: | Object |
Tws_client_version | = | 27 |
# File ib.rb, line 65 65: def initialize(options_in = {}) 66: @options = { 67: :ip => "127.0.0.1", 68: :port => "7496", 69: }.merge(options_in) 70: 71: @connected = false 72: @server = Hash.new # information about server and server connection state 73: 74: # Message listeners. 75: # Key is the message class to listen for. 76: # Value is an Array of Procs. The proc will be called with the populated message instance as its argument when 77: # a message of that type is received. 78: @listeners = Hash.new { |hash, key| 79: hash[key] = Array.new 80: } 81: 82: 83: IBLogger.debug("IB#init: Initializing...") 84: 85: self.open(@options) 86: 87: end
# File ib.rb, line 140 140: def close 141: @server[:reader_thread].kill # Thread uses blocking I/O, so join is useless. 142: @server[:socket].close() 143: @server = Hash.new 144: @@server_version = nil 145: @connected = false 146: IBLogger.debug("Disconnected.") 147: end
Send an outgoing message.
# File ib.rb, line 167 167: def dispatch(message) 168: raise Exception.new("dispatch() must be given an OutgoingMessages::AbstractMessage subclass") unless message.is_a? OutgoingMessage::AbstractMessage 169: message.send(@server) 170: end
# File ib.rb, line 94 94: def open(options_in = {}) 95: raise Exception.new("Already connected!") if @connected 96: 97: opts = { 98: :ip => "127.0.0.1", 99: :port => "7496" 100: }.merge(options_in) 101: 102: @server[:socket] = IBSocket.open(@options[:ip], @options[:port]) 103: IBLogger.debug("* open(): Socket connected to #{@options[:ip]}:#{@options[:port]}.") 104: 105: # Sekrit handshake. 106: IBLogger.debug("\tSending client version #{Tws_client_version}..") 107: 108: @server[:socket].send(Tws_client_version) 109: @server[:version] = @server[:socket].read_int 110: @@server_version = @server[:version] 111: @server[:local_connect_time] = Time.now() 112: 113: IBLogger.debug("\tGot server version: #{@server[:version]}.") 114: 115: # Server version >= 20 sends the server time back. 116: if @server[:version] >= 20 117: @server[:remote_connect_time] = @server[:socket].read_string 118: IBLogger.debug("\tServer connect time: #{@server[:remote_connect_time]}.") 119: end 120: 121: # Server version >= 3 wants an arbitrary client ID at this point. This can be used 122: # to identify subsequent communications. 123: if @server[:version] >= 3 124: @server[:client_id] = SHA1.digest(Time.now.to_s + $$.to_s).unpack("C*").join.to_i % 999999999 125: @server[:socket].send(@server[:client_id]) 126: IBLogger.debug("\tSent client id # #{@server[:client_id]}.") 127: end 128: 129: IBLogger.debug("Starting reader thread..") 130: Thread.abort_on_exception = true 131: @server[:reader_thread] = Thread.new { 132: self.reader 133: } 134: 135: @connected = true 136: end
Subscribe to incoming message events of type messageClass. code is a Proc that will be called with the message instance as its argument.
# File ib.rb, line 159 159: def subscribe(messageClass, code) 160: raise(Exception.new("Invalid argument type (#{messageClass.class}, #{code.class}) - must be (IncomingMessages::AbstractMessage, Proc)")) unless messageClass.is_a?(IncomingMessages::AbstractMessage) && code.is_a?(Proc) 161: @listeners[messageClass].push(code) 162: end
# File ib.rb, line 151 151: def to_s 152: "IB Connector: #{ @connected ? "connected." : "disconnected."}" 153: end
# File ib.rb, line 176 176: def reader 177: IBLogger.debug("Reader started.") 178: 179: while true 180: msg_id = @server[:socket].read_int # this blocks, so Thread#join is useless. 181: IBLogger.debug("Reader: got message id #{msg_id}.") 182: 183: # create a new instance of the appropriate message type, and have it read the message. 184: msg = IncomingMessages::Table[msg_id].new(@server[:socket], @server[:version]) 185: 186: @listeners[msg].each { |listener| 187: listener.call(msg) 188: } 189: 190: # IBLogger.debug("Reader done with message id #{msg_id}.") 191: 192: 193: end # while 194: 195: IBLogger.debug("Reader done.") 196: end