Class: Takagi::MiddlewareStack

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/takagi/middleware_stack.rb

Overview

Middleware stack for processing CoAP requests

Provides a Rack-style middleware chain for request/response processing. Middleware can be configured via Takagi.config.middleware or programmatically.

Examples:

Programmatic configuration

stack = MiddlewareStack.instance
stack.use(Takagi::Middleware::Logging.new)
stack.use(Takagi::Middleware::Caching.new)

YAML configuration (takagi.yml)

middleware:
  enabled: true
  stack:
    - Logging
    - name: Caching
      options:
        ttl: 300

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMiddlewareStack

Returns a new instance of MiddlewareStack.



30
31
32
33
34
35
# File 'lib/takagi/middleware_stack.rb', line 30

def initialize
  @logger = Takagi.logger
  @middlewares = []
  @router = Takagi::Router.instance
  @config_loaded = false
end

Instance Attribute Details

#middlewaresObject (readonly)

Returns the value of attribute middlewares.



28
29
30
# File 'lib/takagi/middleware_stack.rb', line 28

def middlewares
  @middlewares
end

#routerObject (readonly)

Returns the value of attribute router.



28
29
30
# File 'lib/takagi/middleware_stack.rb', line 28

def router
  @router
end

Instance Method Details

#call(request) ⇒ Takagi::Message::Outbound

Processes the request through the middleware stack and routes it

Parameters:

Returns:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/takagi/middleware_stack.rb', line 68

def call(request)
  # Lazily load configuration on first request
  load_from_config unless @config_loaded
  Takagi::Hooks.emit(:middleware_before_call, request: request)

  # Define the core application logic (routing)
  app = lambda do |req|
    block, params = @router.find_route(req.method.to_s, req.uri.path)
    if block
      block.call(req, params)
    else
      req.to_response('4.04 Not Found', { error: 'not found' })
    end
  end

  # Build middleware chain (reverse order for proper execution)
  response = @middlewares.reverse.reduce(app) do |next_middleware, middleware|
    ->(req) { middleware.call(req, &next_middleware) }
  end.call(request)

  Takagi::Hooks.emit(:middleware_after_call, request: request, response: response)
  response
end

#clearObject

Clear all middleware (useful for testing)



93
94
95
# File 'lib/takagi/middleware_stack.rb', line 93

def clear
  @middlewares.clear
end

#load_from_configObject

Load middleware from Takagi configuration This is called lazily on first request to ensure config is loaded



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/takagi/middleware_stack.rb', line 39

def load_from_config
  return if @config_loaded
  return unless defined?(Takagi.config)

  @config_loaded = true

  # Check if middleware is globally disabled
  return unless Takagi.config.middleware.enabled

  # Load middleware stack from configuration
  Takagi.config.middleware.stack.each do |middleware_config|
    load_middleware(middleware_config)
  end

  @logger.debug "Loaded #{@middlewares.size} middleware(s)" if @middlewares.any?
rescue StandardError => e
  @logger.error "Failed to load middleware configuration: #{e.message}"
  @logger.debug e.backtrace.join("\n")
end

#reset!Object

Reset configuration loaded flag (useful for testing)



98
99
100
101
# File 'lib/takagi/middleware_stack.rb', line 98

def reset!
  @middlewares.clear
  @config_loaded = false
end

#use(middleware) ⇒ Object

Adds a new middleware to the stack

Parameters:

  • middleware (Object)

    Middleware instance that responds to ‘call`



61
62
63
# File 'lib/takagi/middleware_stack.rb', line 61

def use(middleware)
  @middlewares << middleware
end