Module: Sinatra::SSE::Marshal

Included in:
Sinatra::SSE
Defined in:
lib/sinatra/sse/marshal.rb

Overview

packing/unpacking SSE events

Constant Summary collapse

FIXED_ORDER =
{
  :event  => 1,
  :id     => 2,
  :data   => 3
}

Instance Method Summary collapse

Instance Method Details

#marshal(object) ⇒ Object

converts an object into an event.

The object must be a hash or a String.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/sinatra/sse/marshal.rb', line 20

def marshal(object)
  expect! object => [ String, Hash ]
  
  if object.is_a?(String)
    object = { :data => object }
  end
  
  # sort all entries in a way, that make sure that event, id, data
  # are at the end. This makes sure that confirming clients just
  # ignore the extra entries. If we would just send them in random
  # order we might produce "bogus" events, when "data", "event",
  # and "id" are separated by invalid entries. 
  entries = object.sort_by { |key, value| FIXED_ORDER[key.to_sym] || 0 }

  entries.map do |key, value|
    escaped_value = value.gsub(/(\r\n|\r|\n)/, "\n#{key}: ")
    "#{key}: #{escaped_value}\n"
  end.join + "\n"
end

#unmarshal(data) ⇒ Object

Unmarshals a single event in data. The string SHOULD NOT contain multipe events, or else the returned hash somehow mangles all these events into a single one.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/sinatra/sse/marshal.rb', line 43

def unmarshal(data)
  event = Hash.new { |hash, key| hash[key] = [] }

  data.split("\n").each do |line|
    key, value = line.split(/: ?/, 2)
    next if key =~ /^\s*$/

    event[key.to_sym] << value
  end

  event.inject({}) do |hash, (key, value)|
    hash.update key => value.join("\n")
  end
end

#unmarshal_all(data) ⇒ Object

Extract all events from a data stream.



59
60
61
62
63
# File 'lib/sinatra/sse/marshal.rb', line 59

def unmarshal_all(data)
  data.split(/\n\n/).
    map { |event| unpack(event) }.
    reject(&:empty?)
end