mission_control-web 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +20 -0
- data/README.md +122 -15
- data/Rakefile +21 -3
- data/app/assets/config/mission_control_web_manifest.js +2 -0
- data/app/assets/stylesheets/mission_control/web/application.css +15 -0
- data/app/assets/stylesheets/mission_control/web/vendor/bulma.min.css +1 -0
- data/app/controllers/concerns/mission_control/web/application_scoped.rb +17 -0
- data/app/controllers/mission_control/web/application_controller.rb +4 -0
- data/app/controllers/mission_control/web/errors_controller.rb +6 -0
- data/app/controllers/mission_control/web/routes_controller.rb +52 -0
- data/app/helpers/mission_control/web/applications_helper.rb +9 -0
- data/app/helpers/mission_control/web/routes_helper.rb +9 -0
- data/app/javascript/mission_control/web/application.js +1 -0
- data/app/models/concerns/mission_control/web/route/applications.rb +17 -0
- data/app/models/mission_control/web/application/routes.rb +24 -0
- data/app/models/mission_control/web/application.rb +34 -0
- data/app/models/mission_control/web/application_record.rb +3 -0
- data/app/models/mission_control/web/current.rb +8 -0
- data/app/models/mission_control/web/route.rb +14 -0
- data/app/views/layouts/mission_control/web/application.html.erb +23 -0
- data/app/views/mission_control/web/application/_current_application_selector.html.erb +15 -0
- data/app/views/mission_control/web/application/_flash.html.erb +3 -0
- data/app/views/mission_control/web/application/_form_errors.html.erb +11 -0
- data/app/views/mission_control/web/application/_navbar.html.erb +14 -0
- data/app/views/mission_control/web/errors/disallowed.html.erb +8 -0
- data/app/views/mission_control/web/routes/_form.html.erb +26 -0
- data/app/views/mission_control/web/routes/_route.html.erb +13 -0
- data/app/views/mission_control/web/routes/edit.html.erb +8 -0
- data/app/views/mission_control/web/routes/index.html.erb +27 -0
- data/app/views/mission_control/web/routes/new.html.erb +8 -0
- data/app/views/mission_control/web/routes/show.html.erb +42 -0
- data/config/importmap.rb +2 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20221025093008_create_mission_control_web_routes.rb +14 -0
- data/lib/generators/mission_control/web/install/admin_generator.rb +38 -0
- data/lib/generators/mission_control/web/install/middleware_generator.rb +26 -0
- data/lib/generators/mission_control/web/install_generator.rb +6 -0
- data/lib/mission_control/web/action_dispatch_request.rb +7 -0
- data/lib/mission_control/web/bulma_form_builder.rb +50 -0
- data/lib/mission_control/web/configuration.rb +21 -0
- data/lib/mission_control/web/engine.rb +45 -0
- data/lib/mission_control/web/errors/resource_not_found.rb +2 -0
- data/lib/mission_control/web/request_filter.rb +17 -0
- data/lib/mission_control/web/request_filter_middleware.rb +26 -0
- data/lib/mission_control/web/routes_cache.rb +52 -0
- data/lib/mission_control/web/version.rb +1 -3
- data/lib/mission_control/web.rb +18 -4
- data/lib/tasks/mission_control/web_tasks.rake +4 -0
- metadata +147 -8
- data/LICENSE.txt +0 -21
- data/mission_control-web.gemspec +0 -35
- data/sig/mission_control/web.rbs +0 -6
@@ -0,0 +1,24 @@
|
|
1
|
+
module MissionControl::Web::Application::Routes
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
def routes
|
5
|
+
MissionControl::Web::Route.where(application_id: id)
|
6
|
+
end
|
7
|
+
|
8
|
+
def route_was_updated(route)
|
9
|
+
routes_cache.put(route)
|
10
|
+
end
|
11
|
+
|
12
|
+
def route_was_deleted(route)
|
13
|
+
routes_cache.remove(route)
|
14
|
+
end
|
15
|
+
|
16
|
+
def route_disabled?(path)
|
17
|
+
routes_cache.disabled?(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def routes_cache
|
22
|
+
@routes_cache ||= MissionControl::Web::RoutesCache.new(self)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class MissionControl::Web::Application
|
2
|
+
include ActiveModel::Model
|
3
|
+
include Routes
|
4
|
+
|
5
|
+
attr_accessor :name, :redis
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def all
|
9
|
+
MissionControl::Web.configuration.administered_applications.map { |app| new(**app) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id)
|
13
|
+
all.find { |application| application.id == id }
|
14
|
+
end
|
15
|
+
|
16
|
+
def find!(id)
|
17
|
+
find(id) or raise MissionControl::Web::Errors::ResourceNotFound
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_or_initialize_by_name(name)
|
21
|
+
find(name.parameterize) || new(name: name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def default
|
25
|
+
all.first or raise MissionControl::Web::Errors::ResourceNotFound
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def id
|
30
|
+
name.parameterize
|
31
|
+
end
|
32
|
+
|
33
|
+
alias to_param id
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class MissionControl::Web::Route < ApplicationRecord
|
2
|
+
include Applications
|
3
|
+
|
4
|
+
validates :name, :pattern, presence: true
|
5
|
+
validates :pattern, uniqueness: { scope: :application_id }
|
6
|
+
|
7
|
+
def application
|
8
|
+
@application ||= MissionControl::Web::Application.find!(application_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def disabled?
|
12
|
+
!enabled?
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Mission Control - Web</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
|
8
|
+
<%= stylesheet_link_tag "mission_control/web/application", "data-turbo-track": "reload" %>
|
9
|
+
<%= javascript_importmap_tags %>
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<body>
|
13
|
+
<div class="container">
|
14
|
+
<section class="section">
|
15
|
+
<%= render "navbar" %>
|
16
|
+
<%= render "flash" %>
|
17
|
+
|
18
|
+
<%= yield %>
|
19
|
+
|
20
|
+
</section>
|
21
|
+
</div>
|
22
|
+
</body>
|
23
|
+
</html>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% if selectable_applications.any? %>
|
2
|
+
<div class="application-selector navbar-item has-dropdown is-hoverable">
|
3
|
+
<a class="navbar-link">
|
4
|
+
<%= MissionControl::Web::Current.application.name %>
|
5
|
+
</a>
|
6
|
+
|
7
|
+
<div class="navbar-dropdown">
|
8
|
+
<% selectable_applications.each do |application| %>
|
9
|
+
<%= link_to application_routes_path(application), class: "navbar-item" do %>
|
10
|
+
<span><%= application.name %></span>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if model.errors.any? %>
|
2
|
+
<div class="notification content">
|
3
|
+
<h3 class="subtitle is-6"><%= pluralize(model.errors.count, "error") %> prohibited this <%= model.class.name.demodulize %> from being saved:</h3>
|
4
|
+
|
5
|
+
<ul>
|
6
|
+
<% model.errors.each do |error| %>
|
7
|
+
<li><%= error.full_message %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<nav class="navbar" role="navigation" aria-label="main navigation">
|
2
|
+
<div class="navbar-brand">
|
3
|
+
<h1 class="title">Mission Control - Web</h1>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<div class="navbar-menu is-active">
|
7
|
+
<div class="navbar-start">
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div class="navbar-end">
|
11
|
+
<%= render "current_application_selector" %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</nav>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%= form_with(model: [ route.application, route] ) do |form| %>
|
2
|
+
<%= render partial: "form_errors", locals: { model: route } %>
|
3
|
+
|
4
|
+
<div class="field">
|
5
|
+
<%= form.label :name %>
|
6
|
+
<%= form.text_field :name %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="field">
|
10
|
+
<%= form.label :pattern %>
|
11
|
+
<%= form.text_field :pattern %>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="field">
|
15
|
+
<%= form.label_check_box :enabled, "Traffic allowed" %>
|
16
|
+
<%= form.check_box :enabled %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="field is-grouped">
|
20
|
+
<%= form.submit_primary %>
|
21
|
+
|
22
|
+
<%= form.div_control do %>
|
23
|
+
<%= link_to "Cancel", application_routes_path(route.application), class: "button is-link is-light" %>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="level">
|
2
|
+
<div class="level-left">
|
3
|
+
<h2 class="subtitle level-item"><%= @application.name %> - Routes</h2>
|
4
|
+
</div>
|
5
|
+
<div class="level-right">
|
6
|
+
<%= link_to "New Route", new_application_route_path(@application), class: "button is-primary level-item" %>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div class="content">
|
11
|
+
<% if @routes.any? %>
|
12
|
+
<table class="table">
|
13
|
+
<thead>
|
14
|
+
<tr>
|
15
|
+
<th>Name</th>
|
16
|
+
<th>Pattern</th>
|
17
|
+
<th>Traffic Status</th>
|
18
|
+
</tr>
|
19
|
+
</thead>
|
20
|
+
<tbody>
|
21
|
+
<%= render @routes, application: @application %>
|
22
|
+
</tbody>
|
23
|
+
</table>
|
24
|
+
<% else %>
|
25
|
+
<p>No Routes have yet been configured.</p>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<nav class="breadcrumb" aria-label="breadcrumbs">
|
2
|
+
<ul>
|
3
|
+
<li><%= link_to @application.name, application_routes_path(@application) %></li>
|
4
|
+
<li class="is-active"><%= link_to @route.name, [ @application, @route ] %></li>
|
5
|
+
</ul>
|
6
|
+
</nav>
|
7
|
+
|
8
|
+
<div class="my-4">
|
9
|
+
<div class="columns">
|
10
|
+
<div class="column is-one-fifth">
|
11
|
+
<p class="has-text-weight-semibold">Name</p>
|
12
|
+
</div>
|
13
|
+
<div class="column">
|
14
|
+
<p><%= @route.name %></p>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="columns">
|
19
|
+
<div class="column is-one-fifth">
|
20
|
+
<p class="has-text-weight-semibold">Pattern</p>
|
21
|
+
</div>
|
22
|
+
<div class="column">
|
23
|
+
<p><%= @route.pattern %></p>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="columns">
|
28
|
+
<div class="column is-one-fifth">
|
29
|
+
<p class="has-text-weight-semibold">Traffic Status</p>
|
30
|
+
</div>
|
31
|
+
<div class="column">
|
32
|
+
<p><%= route_status_tag @route.enabled %></p>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<div class="level">
|
38
|
+
<div class="level-left">
|
39
|
+
<%= link_to "Edit", edit_application_route_path(@application, @route), class: "button level-item" %>
|
40
|
+
<%= button_to "Delete", [ @application, @route ], method: :delete, class: "button is-danger level-item" %>
|
41
|
+
</div>
|
42
|
+
</div>
|
data/config/importmap.rb
ADDED
data/config/routes.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateMissionControlWebRoutes < ActiveRecord::Migration[7.0]
|
2
|
+
def up
|
3
|
+
create_table :mission_control_web_routes do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.string :pattern, null: false
|
6
|
+
t.boolean :enabled, default: true
|
7
|
+
t.string :application_id, null: false, index: true
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :mission_control_web_routes, [ :application_id, :pattern ], unique: true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MissionControl::Web::Install
|
2
|
+
class AdminGenerator < Rails::Generators::Base
|
3
|
+
INITIALIZER_FILE_PATH = "config/initializers/mission_control_web.rb"
|
4
|
+
|
5
|
+
def create_initializer_file
|
6
|
+
create_file INITIALIZER_FILE_PATH, <<~RUBY, skip: true
|
7
|
+
Rails.application.configure do
|
8
|
+
end
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
|
12
|
+
def insert_admin_configuration
|
13
|
+
initializer = <<~RUBY
|
14
|
+
config.mission_control.web.middleware_enabled = false
|
15
|
+
|
16
|
+
# Admin
|
17
|
+
config.mission_control.web.administered_applications = [
|
18
|
+
{ name: "My App", redis: Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0")) }
|
19
|
+
]
|
20
|
+
RUBY
|
21
|
+
|
22
|
+
insert_into_file INITIALIZER_FILE_PATH, indent(initializer), after: "Rails.application.configure do\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_engine_routes
|
26
|
+
route "mount MissionControl::Web::Engine => '/mission_control-web'"
|
27
|
+
end
|
28
|
+
|
29
|
+
def copy_migrations
|
30
|
+
rake "mission_control_web:install:migrations"
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_migrations
|
34
|
+
say "Running migrations..."
|
35
|
+
rails_command "db:migrate"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MissionControl::Web::Install
|
2
|
+
class MissionControl::Web::Install::MiddlewareGenerator < Rails::Generators::Base
|
3
|
+
INITIALIZER_FILE_PATH = "config/initializers/mission_control_web.rb"
|
4
|
+
|
5
|
+
def create_initializer_file
|
6
|
+
create_file INITIALIZER_FILE_PATH, <<~RUBY, skip: true
|
7
|
+
Rails.application.configure do
|
8
|
+
end
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
|
12
|
+
def insert_middleware_configuration
|
13
|
+
initializer = <<~RUBY
|
14
|
+
# Middleware
|
15
|
+
config.mission_control.web.host_application_name = "My App"
|
16
|
+
config.mission_control.web.redis = Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0"))
|
17
|
+
RUBY
|
18
|
+
|
19
|
+
insert_into_file INITIALIZER_FILE_PATH, indent(initializer), after: "Rails.application.configure do\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def toggle_middleware_enabled
|
23
|
+
gsub_file INITIALIZER_FILE_PATH, "middleware_enabled = false", "middleware_enabled = true"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Inspired by https://medium.com/@dyanagi/a-bulma-form-builder-for-ruby-on-rails-applications-aef780808bab
|
2
|
+
|
3
|
+
class MissionControl::Web::BulmaFormBuilder < ActionView::Helpers::FormBuilder
|
4
|
+
def label_default(method, text = nil, options = {}, &block)
|
5
|
+
label(method, text, merge_class(options, "label"), &block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def label_check_box(method, text = nil, options = {}, &block)
|
9
|
+
label(method, text, merge_class(options, "checkbox"), &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def text_field(method, options = {})
|
13
|
+
super(method, merge_class(options, "input"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def submit(value = nil, options = {})
|
17
|
+
div_control do
|
18
|
+
super(value, merge_class(options, "button"))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def submit_primary(value = nil, options = {})
|
23
|
+
submit(value, merge_class(options, "is-primary"))
|
24
|
+
end
|
25
|
+
|
26
|
+
def div_control
|
27
|
+
@template.content_tag(:div, class: "control") do
|
28
|
+
yield
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def select_with_label(method, choices = nil, options = {}, html_options = {}, &block)
|
33
|
+
label_default(method) + select(method, choices, options, html_options, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
37
|
+
label(method, class: "select") do
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def merge_class_attribute_value(options, value)
|
44
|
+
new_options = options.clone
|
45
|
+
new_options[:class] = [ value, new_options[:class] ].join(" ")
|
46
|
+
new_options
|
47
|
+
end
|
48
|
+
|
49
|
+
alias_method :merge_class, :merge_class_attribute_value
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class MissionControl::Web::Configuration
|
2
|
+
include ActiveModel::Attributes, ActiveModel::Dirty
|
3
|
+
|
4
|
+
attribute :host_application_name, :string
|
5
|
+
attribute :middleware_enabled, :boolean, default: true
|
6
|
+
attribute :routes_cache_ttl, :integer, default: 10.seconds
|
7
|
+
attribute :base_controller_class, :string, default: "::ApplicationController"
|
8
|
+
|
9
|
+
attr_writer :redis, :administered_applications
|
10
|
+
attr_accessor :errors_controller
|
11
|
+
|
12
|
+
alias :middleware_enabled? :middleware_enabled
|
13
|
+
|
14
|
+
def redis
|
15
|
+
@redis || raise("Redis client not configured. Configure with MissionControl::Web.configuration.redis = Redis.new")
|
16
|
+
end
|
17
|
+
|
18
|
+
def administered_applications
|
19
|
+
@administered_applications || []
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "importmap-rails"
|
2
|
+
require "turbo-rails"
|
3
|
+
|
4
|
+
module MissionControl
|
5
|
+
module Web
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
isolate_namespace MissionControl::Web
|
8
|
+
|
9
|
+
config.mission_control = ActiveSupport::OrderedOptions.new unless config.try(:mission_control)
|
10
|
+
config.mission_control.web = ActiveSupport::OrderedOptions.new
|
11
|
+
|
12
|
+
initializer "mission_control-web.config" do
|
13
|
+
config.mission_control.web.each do |key, value|
|
14
|
+
MissionControl::Web.configuration.public_send("#{key}=", value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
initializer "mission_control-web.request" do
|
19
|
+
ActiveSupport.on_load :action_dispatch_request do
|
20
|
+
include MissionControl::Web::ActionDispatchRequest
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
initializer "mission_control-web.add_middleware", after: "mission_control-web.config" do |app|
|
25
|
+
if MissionControl::Web.configuration.middleware_enabled?
|
26
|
+
app.middleware.use MissionControl::Web::RequestFilterMiddleware
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
initializer "mission_control-web.assets" do |app|
|
31
|
+
app.config.assets.paths << root.join("app/javascript")
|
32
|
+
app.config.assets.precompile += %w[ mission_control_web_manifest ]
|
33
|
+
end
|
34
|
+
|
35
|
+
initializer "mission_control-web.importmap", before: "importmap" do |app|
|
36
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
37
|
+
app.config.importmap.cache_sweepers << root.join("app/javascript")
|
38
|
+
end
|
39
|
+
|
40
|
+
config.after_initialize do
|
41
|
+
MissionControl::Web.configuration.host_application_name ||= ::Rails.application.class.module_parent.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MissionControl::Web
|
2
|
+
class RequestFilter
|
3
|
+
attr_reader :request
|
4
|
+
|
5
|
+
def initialize(request)
|
6
|
+
@request = request
|
7
|
+
end
|
8
|
+
|
9
|
+
def action
|
10
|
+
request.fetch_header("mission_control.action") do
|
11
|
+
if MissionControl::Web.host_application.route_disabled?(request.path)
|
12
|
+
:disallowed
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MissionControl::Web
|
2
|
+
class RequestFilterMiddleware
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
filter(env) || @app.call(env)
|
9
|
+
end
|
10
|
+
|
11
|
+
def filter(env)
|
12
|
+
return unless MissionControl::Web.configuration.middleware_enabled?
|
13
|
+
|
14
|
+
request = ActionDispatch::Request.new(env)
|
15
|
+
|
16
|
+
if action = request.mission_control.action
|
17
|
+
errors_controller.action(action).call(request.env)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def errors_controller
|
23
|
+
MissionControl::Web.configuration.errors_controller || MissionControl::Web::ErrorsController
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class MissionControl::Web::RoutesCache
|
2
|
+
delegate :redis, to: MissionControl::Web
|
3
|
+
|
4
|
+
def initialize(application)
|
5
|
+
@application = application
|
6
|
+
end
|
7
|
+
|
8
|
+
def put(route)
|
9
|
+
remove(route)
|
10
|
+
|
11
|
+
if route.disabled?
|
12
|
+
add(route)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove(route)
|
17
|
+
redis.srem redis_key, [ route.pattern_previously_was.to_s, route.pattern.to_s ]
|
18
|
+
end
|
19
|
+
|
20
|
+
def disabled?(path)
|
21
|
+
all_disabled_patterns.any? { |pattern| Regexp.new(pattern) =~ path }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
attr_reader :application
|
26
|
+
|
27
|
+
def add(route)
|
28
|
+
redis.sadd redis_key, route.pattern.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def redis_key
|
32
|
+
:"mission_control_web_#{application.id}_disabled_patterns"
|
33
|
+
end
|
34
|
+
|
35
|
+
def all_disabled_patterns
|
36
|
+
memoize(ttl: MissionControl::Web.configuration.routes_cache_ttl) do
|
37
|
+
# Using Redis client rather than Kredis as request interception with a middleware is performance-critical.
|
38
|
+
redis.smembers redis_key
|
39
|
+
end
|
40
|
+
rescue Redis::BaseConnectionError
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
|
44
|
+
def memoize(ttl:)
|
45
|
+
if !@patterns.nil? && @patterns_expires_at > Time.now
|
46
|
+
@patterns
|
47
|
+
else
|
48
|
+
@patterns_expires_at = Time.now + ttl
|
49
|
+
@patterns = yield
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|