Module: Terminalwire::V2::Rails
- Defined in:
- lib/terminalwire/v2/rails.rb
Overview
Drop-in Rails integration for serving a Terminalwire CLI over BOTH the v1 and v2 wire on a SINGLE endpoint during the transition. The whole wiring is one line in config/routes.rb:
require "terminalwire/v2/rails"
match "/terminal", to: Terminalwire::V2::Rails.dual_terminal(MainTerminal),
via: [:get, :connect]
A v2 client advertises the terminalwire.v2 WebSocket subprotocol on the
upgrade; the dispatcher detects that (before the socket is accepted) and routes
to the v2 server, otherwise to the unchanged v1 handler. Same URL for both —
the exec launcher's url: never changes. dualize extends the Thor tree so
it's the SAME CLI answering on either wire, not a v2 fork.
For a v2-only app (no v1 sub-gems), skip this and just
mount Terminalwire::V2::Server::Rack.new(cli) directly.
Defined Under Namespace
Modules: Thor Classes: Dispatcher, Session, VersionEndpoint
Constant Summary collapse
- SUBPROTOCOL =
"terminalwire.v2"
Class Method Summary collapse
-
.default_v1(cli) ⇒ Object
Lazily resolve the v1 handler so this gem doesn't hard-depend on the v1
terminalwire-railsgem at load time. -
.dual_terminal(cli, v1: nil, v2: nil) ⇒ Object
Returns a Rack endpoint that serves
cliover both protocols. -
.report ⇒ Object
Log + report unexpected command errors to Rails (mirrors the v1 handler).
-
.terminal(cli, verbose: nil, report: nil) ⇒ Object
The v2-DEFAULT endpoint: serve
cliover v2, with no v1. -
.verbose? ⇒ Boolean
In dev/test, show the full backtrace to the client (consider_all_requests_local, like v1).
Class Method Details
.default_v1(cli) ⇒ Object
Lazily resolve the v1 handler so this gem doesn't hard-depend on the v1
terminalwire-rails gem at load time. Apps doing the transition have it;
if not, fail with a clear message instead of a NameError.
262 263 264 265 266 267 268 269 |
# File 'lib/terminalwire/v2/rails.rb', line 262 def self.default_v1(cli) unless defined?(Terminalwire::Rails::Thor) raise "terminalwire/v2/rails: the v1 handler (Terminalwire::Rails::Thor) " \ "isn't loaded. Add the v1 `terminalwire-rails` gem, or pass v2:-only " \ "and mount Terminalwire::V2::Server::Rack directly for a v2-only app." end Terminalwire::Rails::Thor.new(cli) end |
.dual_terminal(cli, v1: nil, v2: nil) ⇒ Object
Returns a Rack endpoint that serves cli over both protocols. Pass v1:/v2:
to override the handlers (tests, custom adapters); by default it builds the
stock v1 Terminalwire::Rails::Thor and v2 Terminalwire::V2::Server::Rack.
210 211 212 213 214 215 216 |
# File 'lib/terminalwire/v2/rails.rb', line 210 def self.dual_terminal(cli, v1: nil, v2: nil) Terminalwire::V2::Server.dualize(cli) Dispatcher.new( v1: v1 || default_v1(cli), v2: v2 || Terminalwire::V2::Server::Rack.new(cli, verbose: verbose?, report: report) ) end |
.report ⇒ Object
Log + report unexpected command errors to Rails (mirrors the v1 handler). Without this the v2 Handler drops the exception on the floor behind the generic message, which is exactly what made the missing-host bug hard to find.
252 253 254 255 256 257 |
# File 'lib/terminalwire/v2/rails.rb', line 252 def self.report lambda do |error| ::Rails.error.report(error, handled: true) if ::Rails.respond_to?(:error) ::Rails.logger&.error("terminalwire: #{error.class}: #{error.}\n#{Array(error.backtrace).join("\n")}") end end |
.terminal(cli, verbose: nil, report: nil) ⇒ Object
The v2-DEFAULT endpoint: serve cli over v2, with no v1. Mount it the same way
as dual_terminal:
match "/terminal", to: Terminalwire::V2::Rails.terminal(MainTerminal),
via: [:get, :connect]
It returns a version endpoint (not the bare Rack): a connection advertising the
terminalwire.v2 subprotocol — and any connection that doesn't ask for another
version — is served by the v2 server. The endpoint is the forward-compatible
seam: a future v3 registers another handler here without changing the app's
route. (A bare Rack handed to match to: drops streaming output in production;
the endpoint, like dual_terminal's, is what Rails routing needs.)
230 231 232 233 234 235 236 237 238 |
# File 'lib/terminalwire/v2/rails.rb', line 230 def self.terminal(cli, verbose: nil, report: nil) Terminalwire::V2::Server.terminalize(cli) v2 = Terminalwire::V2::Server::Rack.new( cli, verbose: verbose.nil? ? verbose?() : verbose, report: report || self.report ) VersionEndpoint.new(default: v2, by_subprotocol: { SUBPROTOCOL => v2 }) end |
.verbose? ⇒ Boolean
In dev/test, show the full backtrace to the client (consider_all_requests_local, like v1). In production the client sees the generic message — but the real exception is still LOGGED + reported (below), never silently swallowed.
243 244 245 246 247 |
# File 'lib/terminalwire/v2/rails.rb', line 243 def self.verbose? ::Rails.application.config.consider_all_requests_local rescue StandardError false end |