Class: Capsium::Reactor

Inherits:
Object
  • Object
show all
Includes:
Endpoints, Responses, Serving
Defined in:
sig/capsium/reactor.rbs,
lib/capsium/reactor.rb,
lib/capsium/reactor/mount.rb,
lib/capsium/reactor/deploy.rb,
lib/capsium/reactor/oauth2.rb,
lib/capsium/reactor/metrics.rb,
lib/capsium/reactor/overlay.rb,
lib/capsium/reactor/serving.rb,
lib/capsium/reactor/session.rb,
lib/capsium/reactor/data_api.rb,
lib/capsium/reactor/htpasswd.rb,
lib/capsium/reactor/endpoints.rb,
lib/capsium/reactor/responses.rb,
lib/capsium/reactor/content_api.rb,
lib/capsium/reactor/graphql_api.rb,
lib/capsium/reactor/authenticator.rb,
lib/capsium/reactor/introspection.rb,
lib/capsium/reactor/package_saver.rb,
lib/capsium/reactor/graphql_schema.rb,
sig/capsium/reactor/mount.rbs,
sig/capsium/reactor/deploy.rbs,
sig/capsium/reactor/oauth2.rbs,
sig/capsium/reactor/metrics.rbs,
sig/capsium/reactor/overlay.rbs,
sig/capsium/reactor/serving.rbs,
sig/capsium/reactor/session.rbs,
sig/capsium/reactor/data_api.rbs,
sig/capsium/reactor/htpasswd.rbs,
sig/capsium/reactor/endpoints.rbs,
sig/capsium/reactor/responses.rbs,
sig/capsium/reactor/content_api.rbs,
sig/capsium/reactor/graphql_api.rbs,
sig/capsium/reactor/authenticator.rbs,
sig/capsium/reactor/introspection.rbs,
sig/capsium/reactor/package_saver.rbs,
sig/capsium/reactor/graphql_schema.rbs

Overview

Rack-free WEBrick reactor: serves the package routes plus the Monitoring HTTP API (ARCHITECTURE.md section 7) and reloads the package on filesystem changes.

Defined Under Namespace

Modules: Endpoints, Responses, Serving Classes: Authenticator, ContentApi, DataApi, Deploy, GraphqlApi, GraphqlSchema, Htpasswd, Introspection, Metrics, Mount, MountConflictError, OAuth2, Overlay, PackageSaver, Session

Constant Summary collapse

DEFAULT_PORT =

Returns:

  • (Integer)
8864
DEFAULT_CACHE_CONTROL =

Returns:

  • (String)
"public, max-age=31536000"
PACKAGE_SAVE_PATTERN =

Returns:

  • (Regexp)
%r{\A/package/(?<name>[^/]+)/save\z}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Serving

#authorized?, #content_type_for, #headers_for, #inherited_processing, #mounts_by_length, #record_request, #resolve_mount, #root_mount, #serve_content_api, #serve_data_api, #serve_dataset, #serve_file, #serve_mounted_request, #serve_route

Methods included from Responses

#respond_error, #respond_forbidden, #respond_json, #respond_method_not_allowed, #respond_not_found, #respond_not_implemented, #respond_text

Methods included from Endpoints

#serve_introspection, #serve_package_save

Constructor Details

#initialize(package: nil, mounts: nil, port: DEFAULT_PORT, cache_control: DEFAULT_CACHE_CONTROL, do_not_listen: false, store: nil, deploy: nil, registry: nil, workdir: nil) ⇒ Reactor

Serves one or more packages: either a single package (directory, .cap file or Package, mounted at "/") or a list of mounts (Reactor::Mount) resolved by longest-prefix matching. workdir holds the writable overlays (ARCHITECTURE.md section 5a) and saved packages; it defaults to a temporary directory the reactor removes on cleanup.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/capsium/reactor.rb', line 63

def initialize(package: nil, mounts: nil, port: DEFAULT_PORT,
               cache_control: DEFAULT_CACHE_CONTROL, do_not_listen: false,
               store: nil, deploy: nil, registry: nil, workdir: nil)
  @store = store
  @registry = registry
  @workdir = workdir || Dir.mktmpdir("capsium-reactor-")
  @own_workdir = workdir.nil?
  @mounts = mounts || [Mount.new(path: Mount::ROOT_PATH, package: package,
                                 store: store, registry: registry)]
  @mounts.each { |mount| mount.attach_workdir(@workdir) }
  @port = port
  @cache_control = cache_control
  @started_at = Time.now
  @metrics = Metrics.new
  @log_buffer = Capsium::LogBuffer.new
  @deploy_config = Deploy.load(deploy)
  setup_server(do_not_listen)
  load_state
  mount_routes
  @log_buffer.add("reactor started: " \
                  "#{@mounts.map(&:summary).join(', ')} on port #{@port}")
end

Instance Attribute Details

#authenticatorAuthenticator (readonly)

Returns the value of attribute authenticator.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def authenticator
  @authenticator
end

#cache_controlString? (readonly)

Returns the value of attribute cache_control.

Returns:

  • (String, nil)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def cache_control
  @cache_control
end

#introspectionIntrospection (readonly)

Returns the value of attribute introspection.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def introspection
  @introspection
end

#log_bufferCapsium::LogBuffer (readonly)

Returns the value of attribute log_buffer.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def log_buffer
  @log_buffer
end

#metricsMetrics (readonly)

Returns the value of attribute metrics.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def metrics
  @metrics
end

#mountsArray[Mount] (readonly)

Returns the value of attribute mounts.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def mounts
  @mounts
end

#packagePackage (readonly)

Returns the value of attribute package.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def package
  @package
end

#package_pathString (readonly)

Returns the value of attribute package_path.

Returns:

  • (String)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def package_path
  @package_path
end

#portInteger (readonly)

Returns the value of attribute port.

Returns:

  • (Integer)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def port
  @port
end

#registryCapsium::Registry, ... (readonly)

Returns the value of attribute registry.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def registry
  @registry
end

#routesPackage::Routes (readonly)

Returns the value of attribute routes.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def routes
  @routes
end

#serverObject (readonly)

Returns the value of attribute server.

Returns:

  • (Object)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def server
  @server
end

#server_threadThread? (readonly)

Returns the value of attribute server_thread.

Returns:

  • (Thread, nil)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def server_thread
  @server_thread
end

#started_atTime (readonly)

Returns the value of attribute started_at.

Returns:

  • (Time)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def started_at
  @started_at
end

#storePackage::Store, ... (readonly)

Returns the value of attribute store.

Returns:



52
53
54
# File 'lib/capsium/reactor.rb', line 52

def store
  @store
end

#workdirString (readonly)

Returns the value of attribute workdir.

Returns:

  • (String)


52
53
54
# File 'lib/capsium/reactor.rb', line 52

def workdir
  @workdir
end

Class Method Details

.secure_compare(own, theirs) ⇒ Boolean

Constant-time string comparison (length-check first).

Parameters:

  • own (String)
  • theirs (String)

Returns:

  • (Boolean)


149
150
151
152
# File 'lib/capsium/reactor/htpasswd.rb', line 149

def self.secure_compare(own, theirs)
  own.bytesize == theirs.bytesize &&
    OpenSSL.fixed_length_secure_compare(own, theirs)
end

Instance Method Details

#cleanupvoid

This method returns an undefined value.

Cleans up every mounted package (Package#cleanup for all) and the workdir when the reactor created it.



124
125
126
127
# File 'lib/capsium/reactor.rb', line 124

def cleanup
  @mounts.each { |mount| mount.package.cleanup }
  FileUtils.remove_entry(@workdir) if @own_workdir && File.directory?(@workdir)
end

#handle_request(request, response) ⇒ Object

Entry point for every mounted path: dispatches the request, then records it in the request metrics and the log buffer.

Parameters:

  • request (Object)
  • response (Object)

Returns:

  • (Object)


94
95
96
97
98
# File 'lib/capsium/reactor.rb', line 94

def handle_request(request, response)
  dispatch_request(request, response)
ensure
  record_request(request, response)
end

#mount_routesvoid

This method returns an undefined value.



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/capsium/reactor.rb', line 100

def mount_routes
  paths = Introspection::PATHS + Introspection::REACTOR_PATHS +
          @authenticator.endpoints
  paths.concat(@mounts.flat_map(&:server_paths))
  paths.each do |path|
    @server.mount_proc(path.to_s) { |req, res| handle_request(req, res) }
  end
  # WEBrick longest-prefix matching: catches every "/package/...".
  @server.mount_proc(Introspection::PACKAGE_MOUNT) do |req, res|
    handle_request(req, res)
  end
end

#restart_serverThread

Returns:

  • (Thread)


113
114
115
116
117
118
119
120
# File 'lib/capsium/reactor.rb', line 113

def restart_server
  @server.shutdown
  @server_thread&.join
  load_packages
  setup_server(false)
  mount_routes
  @server_thread = start_server
end

#serveObject

Returns:

  • (Object)


86
87
88
89
90
# File 'lib/capsium/reactor.rb', line 86

def serve
  trap("INT") { shutdown_server }
  @server_thread = start_server
  start_listener
end