Class: Arpie::ProtocolChain
- Inherits:
-
Object
- Object
- Arpie::ProtocolChain
- Includes:
- Arpie
- 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.
Constant Summary
Constants included from Arpie
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, *messages) ⇒ Object
Write
message
toio
.
Methods included from Arpie
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.
35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/arpie/protocol.rb', line 35 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.
20 21 22 |
# File 'lib/arpie/protocol.rb', line 20 def buffer @buffer end |
#chain ⇒ Object (readonly)
Array of Protocols.
17 18 19 |
# File 'lib/arpie/protocol.rb', line 17 def chain @chain end |
#endpoint_class ⇒ Object
The endpoint class of this Protocol. Defaults to Arpie::Endpoint
27 28 29 |
# File 'lib/arpie/protocol.rb', line 27 def endpoint_class @endpoint_class end |
#messages ⇒ Object (readonly)
A buffer holding all parsed, but unreturned messages.
23 24 25 |
# File 'lib/arpie/protocol.rb', line 23 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.
73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/arpie/protocol.rb', line 73 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.
89 90 91 92 93 94 95 96 97 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 |
# File 'lib/arpie/protocol.rb', line 89 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_with_index do |, m_index| cut_to_index = p.from() do |object| << object end rescue case $! when YieldResult .concat($!.result) next when EIncomplete if .size - 1 - m_index > 0 next else raise end else raise end end rescue case $! when EIncomplete if p_index == 0 select([io]) @buffer << io.readpartial(MTU) rescue raise $!.class, "#{$!.to_s}; unparseable bytes remaining in buffer: #{@buffer.size}" retry else p_index = 0 = [] = [@buffer] next # of loop protocol chain end else raise end if .size == 0 # Get back to IO level and retry reading more crud = [@buffer] p_index = -1 end = 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 # loop chain = .shift @messages = end |
#reset ⇒ Object
169 170 171 |
# File 'lib/arpie/protocol.rb', line 169 def reset @buffer = "" end |
#to(message) ⇒ Object
Convert the given message
to wire format by passing it through all protocols in the chain.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/arpie/protocol.rb', line 51 def to = [] @chain.each {|p| for_next = [] .each {|msg| p.to(msg) do |a| for_next << a end } = for_next } end |
#write_message(io, *messages) ⇒ Object
Write message
to io
.
164 165 166 167 |
# File 'lib/arpie/protocol.rb', line 164 def io, * binary = .map {|m| to(m)} io.write(binary) end |