Class: DragonRuby::Rack::Game

Inherits:
Object
  • Object
show all
Defined in:
lib/dragonruby/rack/game.rb

Overview

Serves a DragonRuby GTK HTML5 export as a self-contained, cross-origin isolated static bundle, mountable at any path in a Rack or Rails app:

mount DragonRuby::Rack::Game.new("games/underwater") => "/underwater"

Why this exists: DragonRuby's WASM runtime uses SharedArrayBuffer, which the browser only hands out to a cross-origin isolated document — one served with both COOP and COEP. Rails' public/ file server (ActionDispatch::Static) runs before the router and cannot set these headers per path, which is why the bundle belongs outside public/ and is served exclusively through this endpoint.

Everything in here refers to the real Rack as ::Rack. Inside DragonRuby::Rack, a bare Rack::Static resolves to DragonRuby::Rack::Static and raises NameError — the one price of naming the module after the gem.

Constant Summary collapse

ISOLATION_HEADERS =

The two headers that put the document into cross-origin isolation. Without them the WASM runtime cannot allocate its SharedArrayBuffer and refuses to boot. Same-origin subresources (all of the bundle) satisfy require-corp without a per-file Cross-Origin-Resource-Policy header.

{
  "cross-origin-opener-policy" => "same-origin",
  "cross-origin-embedder-policy" => "require-corp"
}.freeze
NOT_FOUND =
->(_env) { [404, {"content-type" => "text/plain"}, ["Not found"]] }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root, index: "index.html") ⇒ Game

A missing directory is deliberately not an error. Routes are drawn at boot, and a fresh clone has no build in it yet; raising here would stop the whole app from starting over a game that has not been exported. Requests simply 404 until the bundle is there.



39
40
41
42
43
44
45
46
47
# File 'lib/dragonruby/rack/game.rb', line 39

def initialize(root, index: "index.html")
  @root = root.to_s
  @static = ::Rack::Static.new(
    NOT_FOUND,
    root: @root,
    urls: [""],   # serve every path under this mount from the bundle
    index: index # directory requests ("/") resolve to index.html
  )
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



33
34
35
# File 'lib/dragonruby/rack/game.rb', line 33

def root
  @root
end

Instance Method Details

#call(env) ⇒ Object



49
50
51
52
53
54
55
# File 'lib/dragonruby/rack/game.rb', line 49

def call(env)
  env = normalize_root(env)
  status, headers, body = @static.call(env)
  ISOLATION_HEADERS.each { |key, value| headers[key] = value }
  body = rebase_html(body, headers, env) if html?(headers)
  [status, headers, body]
end