Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active August 23, 2025 17:53
Show Gist options
  • Select an option

  • Save tompng/f20d4aebbfff95bfd0fb3b38c14d8579 to your computer and use it in GitHub Desktop.

Select an option

Save tompng/f20d4aebbfff95bfd0fb3b38c14d8579 to your computer and use it in GitHub Desktop.
RackOnRactors::Minitra::Routes.draw do
before do
@foo = rand(1000)
end
get "/longlonglong" do
raise if Ractor.main?
"hello! " * @foo + request_header.inspect
end
end
Ractor.make_shareable RackOnRactors::Minitra::BaseApp
run(->(env){
env = env.select{String === _2}
Ractor.new(env){|env|
RackOnRactors::Minitra::BaseApp.call(env)
}.value
})
# frozen_string_literal: true
# Modified from https://github.com/osyoyu/rack_on_ractors/blob/master/lib/rack_on_ractors/minitra.rb
module RackOnRactors
module Minitra
class Action
attr_reader :request_header, :request_body
def initialize(request_header, request_body)
@request_header = request_header
@request_body = request_body
end
end
module Routes
def self.draw(&block)
DSL.new.freeze.instance_eval(&block)
end
end
class DSL
def before(&block)
BaseApp.register_before(block)
end
def get(path, &action_block)
BaseApp.register_handler(path, action_block)
end
end
class App
def initialize
@routes = {}
end
def register_before(block)
@before = block
end
def register_handler(path, action_block)
@routes[path] = action_block
end
def call(env)
method = env['REQUEST_METHOD'].downcase
path = env['PATH_INFO']
request_headers = {}
env.each do |key, value|
next if !(key == 'CONTENT_TYPE' || key == 'CONTENT_LENGTH' || key.start_with?('HTTP_'))
request_headers[key.delete_prefix('HTTP_').downcase.gsub('_', '-')] = value
end
request_body = env['rack.input']
handler = @routes[path] || proc{"404: #{path}"}
action = Action.new(request_headers, request_body)
action.instance_eval(&@before) if @before
res = action.instance_eval(&handler)
response_headers = {}
if res.is_a?(Stream)
response_headers['Transfer-Encoding'] = 'chunked'
response_headers['Content-Type'] = 'text/event-stream'
response_body = res
else
response_body = [res]
end
[200, response_headers, response_body]
end
def stream(&block)
Stream.new(&block)
end
end
BaseApp = App.new
class Stream
def initialize(&producer_block)
@producer_block = producer_block
@consumer_block = nil
end
def each(&consumer_block)
@consumer_block = consumer_block
@producer_block.call(self)
end
def write(data)
@consumer_block.call(data.to_s)
data.to_s.bytesize
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment