Class: Cloudflare::SSEStream

Inherits:
Object
  • Object
show all
Defined in:
lib/cloudflare_workers/stream.rb

Overview

Stream returned from a Sinatra route. ‘build_js_response` checks `#sse_stream?` and hands the JS readable stream straight to Workers’ ‘new Response(readable, { headers })`.

Constant Summary collapse

DEFAULT_HEADERS =
{
  'content-type'       => 'text/event-stream; charset=utf-8',
  'cache-control'      => 'no-cache, no-transform',
  'x-accel-buffering'  => 'no',
  'connection'         => 'keep-alive'
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(headers: nil, ctx: nil, &block) ⇒ SSEStream

Returns a new instance of SSEStream.



44
45
46
47
48
49
# File 'lib/cloudflare_workers/stream.rb', line 44

def initialize(headers: nil, ctx: nil, &block)
  @block = block
  @ctx = ctx
  @extra_headers = headers || {}
  @js_stream = nil
end

Instance Method Details

#closeObject



90
# File 'lib/cloudflare_workers/stream.rb', line 90

def close; end

#eachObject

Rack body contract. Iterating is a no-op — the actual bytes flow through the JS pipe. Sinatra’s content-length calculator therefore sees no body and leaves the header out, which is exactly right for a chunked streaming response.



89
# File 'lib/cloudflare_workers/stream.rb', line 89

def each; end

#js_streamObject

Build the JS ReadableStream lazily — build_js_response calls ‘.js_stream`. After this point the async task is running; we can only do it once per stream.

Raises:

  • (ArgumentError)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/cloudflare_workers/stream.rb', line 64

def js_stream
  return @js_stream if @js_stream
  blk = @block
  ctx = @ctx
  raise ArgumentError, 'SSEStream needs a block' if blk.nil?

  ts = `new TransformStream()`
  writer = `#{ts}.writable.getWriter()`
  out = SSEOut.new(writer)

  # Kick off the user block in an async task. run_stream compiles
  # to a JS async function (this file is `# await: true`), so
  # calling it returns a Promise; we bind it to ctx.waitUntil so
  # the Workers runtime doesn't tear the isolate down before the
  # stream finishes.
  promise = run_stream(out, blk)
  `#{ctx}.waitUntil(#{promise})` if ctx

  @js_stream = `#{ts}.readable`
end

#response_headersObject

Merged header set to emit on the Response.



57
58
59
# File 'lib/cloudflare_workers/stream.rb', line 57

def response_headers
  DEFAULT_HEADERS.merge(@extra_headers)
end

#sse_stream?Boolean

Duck-typed marker consumed by Rack::Handler::CloudflareWorkers.

Returns:

  • (Boolean)


52
53
54
# File 'lib/cloudflare_workers/stream.rb', line 52

def sse_stream?
  true
end