Class: Karst::Web::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/karst/web/middleware.rb

Overview

Owns Karst's development-only HTTP evidence surface directly at the Rack boundary, rather than through a Rails engine. An engine would mount routes, load ActionView, and integrate into the host application's controller stack; Karst needs none of that to answer "what evidence does Karst currently hold," and all of it would blur the line between Karst's own page and the host application it is inspecting.

Beyond serving /karst itself, this middleware also gives every other development HTML response a tiny link back into /karst, already scoped to the controller/action that produced it (see Badge). Karst sees a request before Rails routes it, so the controller/action that will eventually handle it is not yet known -- that evidence only exists once ActionController has actually dispatched the request, and is captured here via a real process_action.action_controller notification rather than guessed from the request path. Request-local state, not global mutable state, carries that evidence from the notification callback (which fires nested inside @app.call, on whatever thread or fiber is serving this request) back out to the code injecting the badge, so concurrent Puma requests never cross-contaminate each other's context. rubocop:disable Metrics/ClassLength

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Middleware

Returns a new instance of Middleware.



61
62
63
64
65
# File 'lib/karst/web/middleware.rb', line 61

def initialize(app)
  @app = app
  @locality = Locality.new
  self.class.ensure_context_capture!
end

Class Method Details

.ensure_context_capture!Object

One subscription for the process lifetime of this middleware class, regardless of how many instances Rack::Builder creates: the notification is process-wide by nature, and its callback only ever writes into the current thread/fiber's own IsolatedExecutionState slot, so a single subscription safely serves every request.



341
342
343
344
345
346
347
348
349
350
351
# File 'lib/karst/web/middleware.rb', line 341

def ensure_context_capture!
  @context_capture_mutex ||= Mutex.new
  @context_capture_mutex.synchronize do
    next if @context_capture_installed

    ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
      capture_context(args.last)
    end
    @context_capture_installed = true
  end
end

Instance Method Details

#call(env) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/karst/web/middleware.rb', line 67

def call(env)
  return call_owned(env) if owned?(env)

  return @app.call(env) unless development? && @locality.local?(env["REMOTE_ADDR"])

  call_with_badge(env)
end