Module: Lich::Common::FrontendLauncher

Defined in:
documented/common/frontend_launcher.rb

Overview

Converts catalog launcher metadata into either a launch-file command template or a shell-free environment/argv process plan.

Defined Under Namespace

Classes: Error, SpawnPlan, UnavailableError, UnsupportedError

Class Method Summary collapse

Class Method Details

.command(frontend_id, platform_key: Frontend.platform_key, locator: FrontendLocator, simu_launcher: -> { Lich.get_simu_launcher }) ⇒ String

Builds the platform command template for a registered frontend.

Parameters:

  • frontend_id (String, Symbol)

    registered frontend identifier

  • platform_key (Symbol) (defaults to: Frontend.platform_key)

    canonical host classification

  • locator (FrontendLocator) (defaults to: FrontendLocator)

    injectable discovery API

  • simu_launcher (#call) (defaults to: -> { Lich.get_simu_launcher })

    injectable legacy launcher lookup

Returns:

Raises:

  • (ArgumentError)

    for an unknown frontend identifier

  • (UnsupportedError)

    when the adapter has no platform command

  • (UnavailableError)

    when a required executable/launcher is absent



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'documented/common/frontend_launcher.rb', line 46

def command(
  frontend_id,
  platform_key: Frontend.platform_key,
  locator: FrontendLocator,
  simu_launcher: -> { Lich.get_simu_launcher }
)
  definition = Frontend.definition_for(frontend_id)

  case definition.dig(:metadata, :launcher_adapter)
  when :environment
    raise UnsupportedError, "#{definition[:id]} requires a structured spawn plan"
  when :avalon
    avalon_command(definition, platform_key, locator)
  when :simutronics
    simu_launcher.call || raise(UnavailableError, 'Simutronics launcher was not found')
  else
    raise UnsupportedError, "no launcher adapter for #{definition[:id]}"
  end
end

.saga_managed_login_plan(account:, character:, game_code:, platform_key: Frontend.platform_key, locator: FrontendLocator, refresh: true) ⇒ SpawnPlan

Builds a shell-free Saga launch plan that asks Saga to authenticate the named character and start its own Via-Lich session. Unlike spawn_plan, this contract does not create a Lich proxy listener or pass a game key; Saga owns authentication and Lich process startup.

Parameters:

  • account (String)

    Saga account with a saved password

  • character (String)

    character to launch

  • game_code (String)

    Saga instance code (for example, GS3 or DR)

  • platform_key (Symbol) (defaults to: Frontend.platform_key)

    canonical host classification

  • locator (FrontendLocator) (defaults to: FrontendLocator)

    injectable discovery API

  • refresh (Boolean) (defaults to: true)

    refresh executable discovery before resolving

Returns:

Raises:

  • (ArgumentError)

    for blank launch identifiers

  • (UnsupportedError)

    when no Saga plan exists on the platform

  • (UnavailableError)

    when Saga is not installed



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'documented/common/frontend_launcher.rb', line 133

def (
  account:,
  character:,
  game_code:,
  platform_key: Frontend.platform_key,
  locator: FrontendLocator,
  refresh: true
)
  identifiers = {
    account: ,
    character: character,
    game_code: game_code
  }
  identifiers.each do |name, value|
    raise ArgumentError, "#{name} must not be empty" if value.to_s.strip.empty?
  end

  definition = Frontend.definition_for('saga')
  unless definition.dig(:metadata, :launcher_adapter) == :environment
    raise UnsupportedError, 'no environment launcher for saga'
  end

  platform_key = Frontend.validate_platform_key!(platform_key)
  plan = definition.dig(:metadata, :launch_plans, platform_key)
  raise UnsupportedError, "no #{platform_key} launcher for saga" unless plan

  command = resolve_plan_command(plan.fetch(:command), definition, locator, refresh: refresh)
  SpawnPlan.new(
    environment: {
      # Saga 0.8.5 implements this currently undocumented startup contract.
      'SAGA_AUTO_LOGIN'         => "#{character.to_s.strip}@#{game_code.to_s.strip.upcase}",
      'SAGA_AUTO_LOGIN_ACCOUNT' => .to_s.strip,
      'SAGA_AUTO_LOGIN_MODE'    => 'lich'
    },
    argv: [command, *plan.fetch(:arguments)]
  )
end

.spawn_plan(frontend_id, host:, port:, key:, platform_key: Frontend.platform_key, locator: FrontendLocator, refresh: true) ⇒ SpawnPlan

Builds a shell-free process environment and argv for an environment launcher adapter. Catalog launch_plans are keyed by platform and contain :command, :arguments, and :environment. A command may be a literal executable or :resolved_executable for locator discovery; %host%, %port%, and %key% tokens are replaced in environment values. Connection secrets remain out of process arguments.

Parameters:

  • frontend_id (String, Symbol)

    registered frontend identifier

  • host (String)

    local proxy host

  • port (Integer, String)

    local proxy port

  • key (String)

    authenticated game connection key

  • platform_key (Symbol) (defaults to: Frontend.platform_key)

    canonical host classification

  • locator (FrontendLocator) (defaults to: FrontendLocator)

    injectable discovery API

  • refresh (Boolean) (defaults to: true)

    refresh executable discovery before resolving

Returns:

Raises:

  • (ArgumentError)

    for blank connection values

  • (UnsupportedError)

    when no plan exists on the platform



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'documented/common/frontend_launcher.rb', line 83

def spawn_plan(
  frontend_id,
  host:,
  port:,
  key:,
  platform_key: Frontend.platform_key,
  locator: FrontendLocator,
  refresh: true
)
  definition = Frontend.definition_for(frontend_id)
  unless definition.dig(:metadata, :launcher_adapter) == :environment
    raise UnsupportedError, "no environment launcher for #{definition[:id]}"
  end

  replacements = { '%host%' => host, '%port%' => port, '%key%' => key }
  replacements.each do |token, value|
    raise ArgumentError, "#{token.delete('%')} must not be empty" if value.to_s.empty?
  end

  platform_key = Frontend.validate_platform_key!(platform_key)
  plan = definition.dig(:metadata, :launch_plans, platform_key)
  unless plan
    raise UnsupportedError, "no #{platform_key} launcher for #{definition[:id]}"
  end

  environment = plan.fetch(:environment).transform_values do |value|
    replacements.reduce(value.to_s) { |resolved, (token, replacement)| resolved.gsub(token, replacement.to_s) }
  end
  command = resolve_plan_command(plan.fetch(:command), definition, locator, refresh: refresh)
  SpawnPlan.new(
    environment: environment,
    argv: [command, *plan.fetch(:arguments)]
  )
end