Class: IB::Messages::Incoming::AbstractMessage

Inherits:
AbstractMessage show all
Defined in:
lib/ib/messages/incoming/abstract_message.rb

Direct Known Subclasses

AbstractTick

Instance Attribute Summary collapse

Attributes inherited from AbstractMessage

#created_at, #data

Instance Method Summary collapse

Methods inherited from AbstractMessage

data_map, message_id, #message_id, message_type, #message_type, #to_human, version

Constructor Details

#initialize(source) ⇒ AbstractMessage

Create incoming message from a given source (IB Socket or data Hash)



25
26
27
28
29
30
31
32
33
34
# File 'lib/ib/messages/incoming/abstract_message.rb', line 25

def initialize source
  @created_at = Time.now
  if source.is_a?(Hash)  # Source is a @data Hash
    @data = source
  else # Source is a Socket
    @socket = source
    @data = Hash.new
    self.load
  end
end

Instance Attribute Details

#socketObject

Returns the value of attribute socket.



12
13
14
# File 'lib/ib/messages/incoming/abstract_message.rb', line 12

def socket
  @socket
end

Instance Method Details

#check_version(actual, expected) ⇒ Object



18
19
20
21
22
# File 'lib/ib/messages/incoming/abstract_message.rb', line 18

def check_version actual, expected
  unless actual == expected || expected.is_a?(Array) && expected.include?(actual)
    error "Unsupported version #{actual} received, expected #{expected}"
  end
end

#loadObject

Every message loads received message version first Override the load method in your subclass to do actual reading into @data.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/ib/messages/incoming/abstract_message.rb', line 38

def load
  if socket
    @data[:version] = socket.read_int

    check_version @data[:version], self.class.version

    load_map *self.class.data_map
  else
    raise "Unable to load, no socket"
  end

rescue => e
  error "Reading #{self.class}: #{e.class}: #{e.message}", :load, e.backtrace
end

#load_map(*map) ⇒ Object

Load @data from the socket according to the given data map.

map is a series of Arrays in the format of

[ :name, :type ], [  :group, :name, :type]

type identifiers must have a corresponding read_type method on socket (read_int, etc.). group is used to lump together aggregates, such as Contract or Order fields



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/ib/messages/incoming/abstract_message.rb', line 59

def load_map(*map)
  map.each do |instruction|
    # We determine the function of the first element
    head = instruction.first
    case head
    when Integer # >= Version condition: [ min_version, [map]]
      load_map *instruction.drop(1) if version >= head

    when Proc # Callable condition: [ condition, [map]]
      load_map *instruction.drop(1) if head.call

    when true # Pre-condition already succeeded!
      load_map *instruction.drop(1)

    when nil, false # Pre-condition already failed! Do nothing...

    when Symbol # Normal map
      group, name, type, block =
      if  instruction[2].nil? || instruction[2].is_a?(Proc)
        [nil] + instruction # No group, [ :name, :type, (:block) ]
      else
        instruction # [ :group, :name, :type, (:block)]
      end

      data = socket.__send__("read_#{type}", &block)
      if group
        @data[group] ||= {}
        @data[group][name] = data
      else
        @data[name] = data
      end
    else
      error "Unrecognized instruction #{instruction}"
    end
  end
end

#versionObject

Per message, received messages may have the different versions



14
15
16
# File 'lib/ib/messages/incoming/abstract_message.rb', line 14

def version # Per message, received messages may have the different versions
  @data[:version]
end