Module: Rack::Handler::Homura

Defined in:
lib/homura/runtime.rb

Constant Summary collapse

EMPTY_STRING_IO =
StringIO.new("").freeze

Class Method Summary collapse

Class Method Details

.appObject



156
157
158
# File 'lib/homura/runtime.rb', line 156

def self.app
  @app
end

.app=(app) ⇒ Object



160
161
162
# File 'lib/homura/runtime.rb', line 160

def self.app=(app)
  @app = app
end

.call(js_req, js_env, js_ctx, body_text = "") ⇒ Object

Entry point invoked from the Module Worker (src/worker.mjs) for every fetch event. ‘js_req` is a Cloudflare Workers Request, `js_env` is the bindings object (D1, KV, R2, secrets…), `js_ctx` is the ExecutionContext, `body_text` is the pre-resolved request body (the worker.mjs front awaits req.text() before handing control to Ruby because Opal runs synchronously).



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/homura/runtime.rb', line 194

def self.call(js_req, js_env, js_ctx, body_text = "")
  if @app.nil?
    if defined?(::Sinatra::Homura) &&
        ::Sinatra::Homura.respond_to?(:ensure_rack_app!)
      ::Sinatra::Homura.ensure_rack_app!
    end

    if @app.nil?
      raise(
        "`run app` was never called from user code, and no Sinatra app was discoverable (define `class App < Sinatra::Base` or use top-level classic Sinatra routes)"
      )
    end
  end

  env = build_rack_env(js_req, js_env, js_ctx, body_text)
  result = @app.call(env)
  if defined?(::Cloudflare) &&
      ::Cloudflare.js_promise?(result)
    result = result.__await__
  end

  status, headers, body = result
  build_js_response(status, headers, body)
ensure
  body.close if body && body.respond_to?(:close)
end

.ensure_dispatcher_installed!Object

Eagerly install the JS-side dispatcher so a fetch arriving before ‘run` was called (e.g. classic-style apps that omit the trailing `run Sinatra::Application`) still gets routed into our `call` method, which can then discover the user’s Sinatra app lazily via ‘Sinatra::Homura.ensure_rack_app!`. This is what makes the canonical sinatrarb.com snippet work verbatim on Workers — `at_exit` is unreliable here because the isolate never actually exits between fetches.



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

def self.ensure_dispatcher_installed!
  return true if @dispatcher_installed
  handler = self
  `
    globalThis.__HOMURA_RACK_DISPATCH__ = async function(req, env, ctx, body_text) {
      return await #{handler}.$call(req, env, ctx, body_text == null ? "" : body_text);
    };
    (function () {
      var g = globalThis;
      g.__OPAL_WORKERS__ = g.__OPAL_WORKERS__ || {};
      g.__OPAL_WORKERS__.rack = g.__HOMURA_RACK_DISPATCH__;
    })();
  `
  @dispatcher_installed = true
end

.run(app, **_options) ⇒ Object



150
151
152
153
154
# File 'lib/homura/runtime.rb', line 150

def self.run(app, **_options)
  @app = app
  ensure_dispatcher_installed!
  app
end