Class: Takagi::CompositeRouter

Inherits:
Object
  • Object
show all
Defined in:
lib/takagi/composite_router.rb

Overview

Composite router that routes requests to mounted controllers

The CompositeRouter handles prefix-based routing, matching incoming requests to the appropriate controller based on mount paths.

Examples:

router = CompositeRouter.new
router.mount(TelemetryController, '/telemetry')
router.mount(ConfigController, '/config')

handler, params = router.find_route('POST', '/telemetry/data')

Defined Under Namespace

Classes: MountedController

Instance Method Summary collapse

Constructor Details

#initializeCompositeRouter

Returns a new instance of CompositeRouter.



37
38
39
40
# File 'lib/takagi/composite_router.rb', line 37

def initialize
  @mounted = []
  @logger = Takagi.logger
end

Instance Method Details

#all_routesArray<String>

Get all routes from all mounted controllers

Returns:

  • (Array<String>)

    List of all routes



101
102
103
104
105
106
107
108
109
# File 'lib/takagi/composite_router.rb', line 101

def all_routes
  @mounted.flat_map do |mounted|
    mounted.router.all_routes.map do |route|
      method, path = route.split(' ', 2)
      full_path = mounted.mount_path == '/' ? path : File.join(mounted.mount_path, path)
      "#{method} #{full_path}"
    end
  end
end

#find_controller_for_path(path) ⇒ Class?

Find the controller class that handles a given path

Parameters:

  • path (String)

    Request path

Returns:

  • (Class, nil)

    Controller class or nil if no match



139
140
141
142
# File 'lib/takagi/composite_router.rb', line 139

def find_controller_for_path(path)
  mounted = find_mounted_controller(path)
  mounted&.controller_class
end

#find_route(method, path) ⇒ Array(Proc, Hash)

Find a route handler for the given method and path

Parameters:

  • method (String)

    HTTP/CoAP method

  • path (String)

    Request path

Returns:

  • (Array(Proc, Hash))

    Handler and params, or [nil, {}]



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/takagi/composite_router.rb', line 79

def find_route(method, path)
  @logger.debug "CompositeRouter: Looking for #{method} #{path}"

  # Find matching mounted controller (longest prefix match)
  mounted = find_mounted_controller(path)

  unless mounted
    @logger.debug "CompositeRouter: No mounted controller for #{path}"
    return [nil, {}]
  end

  # Get relative path within controller
  relative = mounted.relative_path(path)
  @logger.debug "CompositeRouter: Routing to #{mounted.controller_class} with path #{relative}"

  # Find route in controller's router
  mounted.router.find_route(method, relative)
end

Get link format entries from all mounted controllers

Returns:



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/takagi/composite_router.rb', line 114

def link_format_entries
  @mounted.flat_map do |mounted|
    mounted.router.link_format_entries.map do |entry|
      # Create a copy with the full path
      entry_copy = entry.dup
      full_path = mounted.mount_path == '/' ? entry.path : File.join(mounted.mount_path, entry.path)

      # Update the path in the copy
      entry_copy.instance_variable_set(:@path, full_path)
      entry_copy
    end
  end
end

#mount(controller_class, at: nil) ⇒ void

This method returns an undefined value.

Mount a controller at a specific path

Examples:

mount(TelemetryController, at: '/telemetry')
mount(TelemetryController) # Uses controller's configured mount_path

Parameters:

  • controller_class (Class)

    Controller class to mount

  • at (String, nil) (defaults to: nil)

    Mount path (uses controller’s mount_path if nil)

Raises:

  • (ArgumentError)


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/takagi/composite_router.rb', line 51

def mount(controller_class, at: nil)
  path = at || controller_class.mount_path

  raise ArgumentError, "Controller #{controller_class} has no mount path" unless path

  # Normalize path
  path = "/#{path}" unless path.start_with?('/')
  path = path.chomp('/') unless path == '/'

  mounted = MountedController.new(
    controller_class,
    path,
    controller_class.router,
    controller_class.nested_controllers
  )

  @mounted << mounted
  @logger.debug "Mounted #{controller_class} at #{path}"

  # Recursively mount nested controllers
  mount_nested_controllers(mounted)
end

#mounted_controllersArray<MountedController>

Get all mounted controllers

Returns:



131
132
133
# File 'lib/takagi/composite_router.rb', line 131

def mounted_controllers
  @mounted
end