class H2::Server::Stream::EventSource

Constants

DATA_TEMPL
EVENT_TEMPL
SSE_HEADER

Public Class Methods

new(stream:, headers: {}) click to toggle source

build and return EventSource instance, ready for pushing out data or named events. checks accept header in the request, then responds with valid headers for beginning an SSE stream

@param [H2::Server::Stream] stream: the Stream instance @param [Hash] headers: optional headers to add to the intial response

@return [H2::Server::Stream::EventSource]

# File lib/h2/server/stream/event_source.rb, line 23
def initialize stream:, headers: {}
  @closed  = false
  @stream  = stream
  @parser  = @stream.stream
  @headers = headers
  @gzip    = false
  @deflate = false

  check_accept_header
  check_accept_encoding
  init_response
end

Public Instance Methods

check_accept_encoding() click to toggle source

checks the request for accept-encoding headers and processes data & events accordingly

# File lib/h2/server/stream/event_source.rb, line 49
def check_accept_encoding
  if accept = @stream.request.headers[ACCEPT_ENCODING_KEY]
    accept.split(',').map(&:strip).each do |encoding|
      case encoding
      when GZIP_ENCODING
        if @stream.connection.server.options[:gzip]
          @gzip = true
          @headers[CONTENT_ENCODING_KEY] = GZIP_ENCODING
          break
        end

      # "deflate" has issues: https://zlib.net/zlib_faq.html#faq39
      #
      when DEFLATE_ENCODING
        if @stream.connection.server.options[:deflate]
          @deflate = true
          @headers[CONTENT_ENCODING_KEY] = DEFLATE_ENCODING
          break
        end

      end
    end
  end
end
check_accept_header() click to toggle source

checks accept header in the request and raises a StreamError if not valid for SSE

# File lib/h2/server/stream/event_source.rb, line 39
def check_accept_header
  accept = @stream.request.headers['accept']
  unless accept == SSE_HEADER[CONTENT_TYPE_KEY]
    raise StreamError, "invalid header accept: #{accept}"
  end
end
close() click to toggle source

emit a final frame on this stream with end_stream flag

# File lib/h2/server/stream/event_source.rb, line 108
def close
  @parser.data ''
  @closed = true
end
closed?() click to toggle source

@return [Boolean] true if this stream is closed

# File lib/h2/server/stream/event_source.rb, line 115
def closed?
  @closed
end
data(str) click to toggle source

send out a message with the given data

this would be handled by `es.onmessage((msg)=>{})`

@param [String] data associated with this event

# File lib/h2/server/stream/event_source.rb, line 101
def data str
  d = encode_content(DATA_TEMPL % str)
  @parser.data d, end_stream: false
end
event(name:, data: e = encode_content(EVENT_TEMPL % [name, data])) click to toggle source

send out a named event with the given data

this would be handled by `es.addEventListener('name', (msg)=>{})`

@param [String] name: the name of the event @param [String] data: data associated with this event

# File lib/h2/server/stream/event_source.rb, line 90
def event name:, data:
  e = encode_content(EVENT_TEMPL % [name, data])
  @parser.data e, end_stream: false
end
init_response() click to toggle source

responds with SSE headers on this stream

# File lib/h2/server/stream/event_source.rb, line 76
def init_response
  headers = SSE_HEADER.merge @headers
  @parser.headers stringify_headers(headers)
rescue ::HTTP2::Error::StreamClosed
  @stream.log :warn, "stream closed early by client"
end

Private Instance Methods

encode_content(str) click to toggle source

content-encoding helper for event and data methods

# File lib/h2/server/stream/event_source.rb, line 123
def encode_content str
  str = ::Zlib.gzip str if @gzip
  str = ::Zlib.deflate str if @deflate
  str
end