Class: SSE::Impl::BufferedLineReader

Inherits:
Object
  • Object
show all
Defined in:
lib/ld-eventsource/impl/buffered_line_reader.rb

Class Method Summary collapse

Class Method Details

.lines_from(chunks) ⇒ Enumerator

Reads a series of data chunks from an enumerator, and returns an enumerator that parses/aggregates these into text lines. The line terminator may be CR, LF, or CRLF for each line; terminators are not included in the returned lines. When the input data runs out, the output enumerator ends and does not include any partially completed line.

Parameters:

  • chunks (Enumerator)

    an enumerator that will yield strings from a stream

Returns:

  • (Enumerator)

    an enumerator that will yield one line at a time



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ld-eventsource/impl/buffered_line_reader.rb', line 15

def self.lines_from(chunks)
  buffer = ""
  position = 0
  line_start = 0
  last_char_was_cr = false

  Enumerator.new do |gen|
    chunks.each do |chunk|
      buffer << chunk

      loop do
        # Search for a line break in any part of the buffer that we haven't yet seen.
        i = buffer.index(/[\r\n]/, position)
        if i.nil?
          # There isn't a line break yet, so we'll keep accumulating data in the buffer, using
          # position to keep track of where we left off scanning. We can also discard any previously
          # parsed lines from the buffer at this point.
          if line_start > 0
            buffer.slice!(0, line_start)
            line_start = 0
          end
          position = buffer.length
          break
        end

        ch = buffer[i]
        if i == 0 && ch == "\n" && last_char_was_cr
          # This is just the dangling LF of a CRLF pair
          last_char_was_cr = false
          i += 1
          position = i
          line_start = i
          next
        end

        line = buffer[line_start, i - line_start]
        last_char_was_cr = false
        i += 1
        if ch == "\r"
          if i == buffer.length
            last_char_was_cr = true # We'll break the line here, but be on watch for a dangling LF
          elsif buffer[i] == "\n"
            i += 1
          end
        end
        if i == buffer.length
          buffer = ""
          i = 0
        end
        position = i
        line_start = i
        gen.yield line
      end
    end
  end
end