Class: Lumberjack::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/lumberjack/server.rb

Overview

class Server

Constant Summary collapse

FRAME_WINDOW =

def need

"W".ord
FRAME_DATA =
"D".ord
FRAME_COMPRESSED =
"C".ord

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



66
67
68
69
70
71
# File 'lib/lumberjack/server.rb', line 66

def initialize
  @buffer_offset = 0
  @buffer = ""
  @buffer.force_encoding("BINARY")
  transition(:header, 2)
end

Instance Method Details

#compressed_lead(&block) ⇒ Object

def data_field_value



188
189
190
191
# File 'lib/lumberjack/server.rb', line 188

def compressed_lead(&block)
  length = get.unpack("N").first
  transition(:compressed_payload, length)
end

#compressed_payload(&block) ⇒ Object



193
194
195
196
197
198
199
# File 'lib/lumberjack/server.rb', line 193

def compressed_payload(&block)
  original = Zlib::Inflate.inflate(get)
  transition(:header, 2)

  # Parse the uncompressed payload.
  feed(original, &block)
end

#data_field_key(&block) ⇒ Object



163
164
165
166
# File 'lib/lumberjack/server.rb', line 163

def data_field_key(&block)
  @key = get
  transition(:data_field_value_len, 4)
end

#data_field_key_len(&block) ⇒ Object



158
159
160
161
# File 'lib/lumberjack/server.rb', line 158

def data_field_key_len(&block)
  key_len = get.unpack("N").first
  transition(:data_field_key, key_len)
end

#data_field_value(&block) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/lumberjack/server.rb', line 172

def data_field_value(&block)
  @value = get

  @data_count -= 1
  @data[@key] = @value

  if @data_count > 0
    transition(:data_field_key_len, 4)
  else
    # emit the whole map now that we found the end of the data fields list.
    yield :data, @sequence, @data
    transition(:header, 2)
  end

end

#data_field_value_len(&block) ⇒ Object



168
169
170
# File 'lib/lumberjack/server.rb', line 168

def data_field_value_len(&block)
  transition(:data_field_value, get.unpack("N").first)
end

#data_lead(&block) ⇒ Object

def window_size



152
153
154
155
156
# File 'lib/lumberjack/server.rb', line 152

def data_lead(&block)
  @sequence, @data_count = get.unpack("NN")
  @data = {}
  transition(:data_field_key_len, 4)
end

#feed(data, &block) ⇒ String?

Feed data to this parser.

Currently, it will return the raw payload of websocket messages. Otherwise, it returns nil if no complete message has yet been consumed.

Parameters:

  • the (String)

    string data to feed into the parser.

Returns:

  • (String, nil)

    the websocket message payload, if any, nil otherwise.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/lumberjack/server.rb', line 89

def feed(data, &block)
  @buffer << data
  #p :need => @need
  while have?(@need)
    send(@state, &block) 
    #case @state
      #when :header; header(&block)
      #when :window_size; window_size(&block)
      #when :data_lead; data_lead(&block)
      #when :data_field_key_len; data_field_key_len(&block)
      #when :data_field_key; data_field_key(&block)
      #when :data_field_value_len; data_field_value_len(&block)
      #when :data_field_value; data_field_value(&block)
      #when :data_field_value; data_field_value(&block)
      #when :compressed_lead; compressed_lead(&block)
      #when :compressed_payload; compressed_payload(&block)
    #end # case @state
  end
  return nil
end

#get(length = nil) ⇒ Object

Get ‘length’ string from the buffer.



116
117
118
119
120
121
122
123
124
125
# File 'lib/lumberjack/server.rb', line 116

def get(length=nil)
  length = @need if length.nil?
  data = @buffer[@buffer_offset ... @buffer_offset + length]
  @buffer_offset += length
  if @buffer_offset > 16384
    @buffer = @buffer[@buffer_offset  .. -1]
    @buffer_offset = 0
  end
  return data
end

#have?(length) ⇒ Boolean

Do we have at least ‘length’ bytes in the buffer?

Returns:

  • (Boolean)


111
112
113
# File 'lib/lumberjack/server.rb', line 111

def have?(length)
  return length <= (@buffer.size - @buffer_offset)
end

#header(&block) ⇒ Object



135
136
137
138
139
140
141
142
143
144
# File 'lib/lumberjack/server.rb', line 135

def header(&block)
  version, frame_type = get.bytes.to_a[0..1]

  case frame_type
    when FRAME_WINDOW; transition(:window_size, 4)
    when FRAME_DATA; transition(:data_lead, 8)
    when FRAME_COMPRESSED; transition(:compressed_lead, 4)
    else; raise "Unknown frame type: #{frame_type}"
  end
end

#need(length) ⇒ Object

Set the minimum number of bytes we need in the buffer for the next read.



128
129
130
# File 'lib/lumberjack/server.rb', line 128

def need(length)
  @need = length
end

#transition(state, next_length) ⇒ Object

def initialize



73
74
75
76
77
78
79
80
# File 'lib/lumberjack/server.rb', line 73

def transition(state, next_length)
  @state = state
  #puts :transition => state
  # TODO(sissel): Assert this self.respond_to?(state)
  # TODO(sissel): Assert state is in STATES
  # TODO(sissel): Assert next_length is a number
  need(next_length)
end

#window_size {|:window_size, @window_size| ... } ⇒ Object

Yields:



146
147
148
149
150
# File 'lib/lumberjack/server.rb', line 146

def window_size(&block)
  @window_size = get.unpack("N").first
  transition(:header, 2)
  yield :window_size, @window_size
end