Class: Arpie::ProtocolChain
- Inherits:
-
Object
- Object
- Arpie::ProtocolChain
- Defined in:
- lib/arpie/protocol.rb
Overview
A ProtocolChain wraps one or more Protocols to provide a parser list, into which io data can be fed and parsed packets received; and vice versa.
Instance Attribute Summary collapse
-
#buffer ⇒ Object
readonly
String holding all read, but yet unparsed bytes.
-
#chain ⇒ Object
readonly
Array of Protocols.
-
#endpoint_class ⇒ Object
The endpoint class of this Protocol.
-
#messages ⇒ Object
readonly
A buffer holding all parsed, but unreturned messages.
Instance Method Summary collapse
-
#from(binary) ⇒ Object
Convert the given
binary
to message format by passing it through all protocols in the chain. -
#initialize(*protocols) ⇒ ProtocolChain
constructor
Create a new Chain.
-
#read_message(io) ⇒ Object
Read a message from
io
. - #reset ⇒ Object
-
#to(message) ⇒ Object
Convert the given
message
to wire format by passing it through all protocols in the chain. -
#write_message(io, message) ⇒ Object
Write
message
toio
.
Constructor Details
#initialize(*protocols) ⇒ ProtocolChain
Create a new Chain. Supply an Array of Protocol instances, where the leftmost is the innermost.
Example:
MarshalProtocol.new, SizedProtocol.new
would wrap marshalled data inside SizedProtocol.
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/arpie/protocol.rb', line 53 def initialize *protocols protocols.size > 0 or raise ArgumentError, "Specify at least one protocol." protocols[-1].class::CAN_SEPARATE_MESSAGES or raise ArgumentError, "The outermost protocol needs to be able to " + "separate messages in a stream (#{protocols.inspect} does not)." @endpoint_class = Arpie::Endpoint @chain = protocols @buffer = "" @messages = [] end |
Instance Attribute Details
#buffer ⇒ Object (readonly)
String holding all read, but yet unparsed bytes.
38 39 40 |
# File 'lib/arpie/protocol.rb', line 38 def buffer @buffer end |
#chain ⇒ Object (readonly)
Array of Protocols.
35 36 37 |
# File 'lib/arpie/protocol.rb', line 35 def chain @chain end |
#endpoint_class ⇒ Object
The endpoint class of this Protocol. Defaults to Arpie::Endpoint
45 46 47 |
# File 'lib/arpie/protocol.rb', line 45 def endpoint_class @endpoint_class end |
#messages ⇒ Object (readonly)
A buffer holding all parsed, but unreturned messages.
41 42 43 |
# File 'lib/arpie/protocol.rb', line 41 def @messages end |
Instance Method Details
#from(binary) ⇒ Object
Convert the given binary
to message format by passing it through all protocols in the chain. May raise EStreamError or EIncomplete, in the case that binary
does not satisfy one of the protocols.
Returns an array of messages, even if only one message was contained.
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/arpie/protocol.rb', line 82 def from binary r, w = IO.pipe w.write(binary) w.close results = [] results << (r) until false rescue begin r.close return results end raise "Interal error: should not reach this." end |
#read_message(io) ⇒ Object
Read a message from io
. Block until all protocols agree that a message has been received.
Returns the message.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/arpie/protocol.rb', line 98 def io return @messages.shift if @messages.size > 0 = [@buffer] chain = @chain.reverse p_index = 0 while p_index < chain.size do p = chain[p_index] cut_to_index = nil = [] .each do || cut_to_index = p.from() do |object| << object end rescue case $! when YieldResult .concat($!.result) next when ESwallow .delete() = p_index -= 1 break when EIncomplete # All protocols above the io one need to wait for each # one above to yield more messages. if p_index > 0 # Unwind to the parent protocol and let it read in some # more messages .. = .shift p_index -= 1 break # The first protocol manages +io+. else select([io]) @buffer << io.readpartial(MTU) rescue raise $!.class, "#{$!.to_s}; unparseable bytes remaining in buffer: #{@buffer.size}" retry end when ETryAgain retry else raise end # rescue case end # messages.each raise "BUG: #{p.class.to_s}#from did not yield a message." if .size == 0 = if p_index == 0 if cut_to_index.nil? || cut_to_index < 0 raise "Protocol '#{p.class.to_s}'implementation faulty: " + "from did return an invalid cut index: #{cut_to_index.inspect}." else @buffer[0, cut_to_index] = "" end end p_index += 1 end # chain loop = .shift @messages = end |
#reset ⇒ Object
178 179 180 |
# File 'lib/arpie/protocol.rb', line 178 def reset @buffer = "" end |
#to(message) ⇒ Object
Convert the given message
to wire format by passing it through all protocols in the chain.
69 70 71 72 73 |
# File 'lib/arpie/protocol.rb', line 69 def to ret = @chain.inject() {|msg, p| p.to(msg) } end |
#write_message(io, message) ⇒ Object
Write message
to io
.
174 175 176 |
# File 'lib/arpie/protocol.rb', line 174 def io, io.write(to ) end |