In the grand, time-honored tradition of re-inventing the wheel, we offer here YET ANOTHER protocol that handles line-oriented data with interspersed binary text. This one trades away some of the performance optimizations of EventMachine::Protocols::LineAndTextProtocol in order to get better correctness with regard to binary text blocks that can switch back to line mode. It also permits the line-delimiter to change in midstream. This was originally written to support Stomp.
TODO! We're not enforcing the limits on header lengths and text-lengths. When we get around to that, call receive_error if the user defined it, otherwise throw exceptions.
Stub. Should be subclassed by user code.
# File lib/em/protocols/linetext2.rb, line 147 def receive_binary_data data # no-op end
# File lib/em/protocols/linetext2.rb, line 48 def receive_data data return unless (data and data.length > 0) # Do this stuff in lieu of a constructor. @lt2_mode ||= :lines @lt2_delimiter ||= "\n" @lt2_linebuffer ||= [] if @lt2_mode == :lines if ix = data.index( @lt2_delimiter ) @lt2_linebuffer << data[0...ix] ln = @lt2_linebuffer.join @lt2_linebuffer.clear if @lt2_delimiter == "\n" ln.chomp! end receive_line ln receive_data data[(ix+@lt2_delimiter.length)..-1] else @lt2_linebuffer << data end elsif @lt2_mode == :text if @lt2_textsize needed = @lt2_textsize - @lt2_textpos will_take = if data.length > needed needed else data.length end @lt2_textbuffer << data[0...will_take] tail = data[will_take..-1] @lt2_textpos += will_take if @lt2_textpos >= @lt2_textsize # Reset line mode (the default behavior) BEFORE calling the # receive_binary_data. This makes it possible for user code # to call set_text_mode, enabling chains of text blocks # (which can possibly be of different sizes). set_line_mode receive_binary_data @lt2_textbuffer.join receive_end_of_binary_data end receive_data tail else receive_binary_data data end end end
Stub. Should be subclassed by user code. This is called when transitioning internally from text mode back to line mode. Useful when client code doesn't want to keep track of how much data it's received.
# File lib/em/protocols/linetext2.rb, line 155 def receive_end_of_binary_data # no-op end
Stub. Should be subclassed by user code.
# File lib/em/protocols/linetext2.rb, line 142 def receive_line ln # no-op end
Alias for set_text_mode, added for back-compatibility with LineAndTextProtocol.
# File lib/em/protocols/linetext2.rb, line 127 def set_binary_mode size=nil set_text_mode size end
# File lib/em/protocols/linetext2.rb, line 100 def set_delimiter delim @lt2_delimiter = delim.to_s end
Called internally but also exposed to user code, for the case in which processing of binary data creates a need to transition back to line mode. We support an optional parameter to “throw back” some data, which might be an umprocessed chunk of the transmitted binary data, or something else entirely.
# File lib/em/protocols/linetext2.rb, line 109 def set_line_mode data="" @lt2_mode = :lines (@lt2_linebuffer ||= []).clear receive_data data.to_s end
# File lib/em/protocols/linetext2.rb, line 115 def set_text_mode size=nil if size == 0 set_line_mode else @lt2_mode = :text (@lt2_textbuffer ||= []).clear @lt2_textsize = size # which can be nil, signifying no limit @lt2_textpos = 0 end end
In case of a dropped connection, we'll send a partial buffer to user code when in sized text mode. User overrides of receive_binary_data need to be aware that they may get a short buffer.
# File lib/em/protocols/linetext2.rb, line 134 def unbind @lt2_mode ||= nil if @lt2_mode == :text and @lt2_textpos > 0 receive_binary_data @lt2_textbuffer.join end end