Module: Lich::Main::ArgvOptions::SideEffects

Defined in:
documented/main/argv_options.rb

Overview

Apply side effects: dark mode, hosts-dir, bind-address, detachable-client

Class Method Summary collapse

Class Method Details

.announce(level, message) ⇒ Object

Surface a message on both channels every bind handler uses.



216
217
218
219
# File 'documented/main/argv_options.rb', line 216

def self.announce(level, message)
  $stdout.puts "#{level}: #{message}"
  Lich.log "#{level}: #{message}"
end

.die(message) ⇒ Object

Fatal argv problem: tell the user everywhere, then stop.



222
223
224
225
# File 'documented/main/argv_options.rb', line 222

def self.die(message)
  announce('error', message)
  exit 1
end

.execute(argv_options) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Applies side effects for dark mode, hosts directory, bind address, detachable client configuration, and SAL launch file handling.

Mutates argv_options by adding or resolving :bind_address, :detachable_client_host, :detachable_client_port, :hosts_dir, and processing :sal launch files. May exit with error status if configuration is invalid.

Parameters:

  • argv_options (Hash)

    mutable option hash from OptionParser.execute

Returns:

  • (Hash)

    the mutated argv_options hash



206
207
208
209
210
211
212
213
# File 'documented/main/argv_options.rb', line 206

def self.execute(argv_options)
  StartupTheme.apply(argv_options)
  handle_hosts_dir(argv_options)
  handle_bind_address(argv_options)
  handle_detachable_client(argv_options)
  handle_sal_launch(argv_options)
  argv_options
end

.handle_bind_address(argv_options) ⇒ Object

--bind-address shares the keyword vocabulary of --detachable-client hosts (tailscale/lan/any). Resolve it once, up front, so the frontend listener, the --game proxy, and a detachable client that inherits it all bind the same concrete address -- and so the exposure warning appears exactly once.



232
233
234
235
236
237
238
239
# File 'documented/main/argv_options.rb', line 232

def self.handle_bind_address(argv_options)
  result = BindAddressOption.apply(argv_options[:bind_address])
  die(result.error) if result.error
  return unless result.host

  argv_options[:bind_address] = result.host
  announce('warning', result.warning) if result.warning
end

.handle_detachable_client(argv_options) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Processes --detachable-client argument and configures host and port.

Parses --detachable-client=HOST:PORT or --detachable-client=PORT, resolving the host via BindHostResolver (unless port-only), and inherits :bind_address from argv_options if no explicit host is given. Sets :detachable_client_host and :detachable_client_port in argv_options.

Parameters:

  • argv_options (Hash)

    mutable option hash

Raises:



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'documented/main/argv_options.rb', line 276

def self.handle_detachable_client(argv_options)
  argv_options[:detachable_client_host] = argv_options[:bind_address] || '127.0.0.1'
  argv_options[:detachable_client_port] = nil
  arg = ARGV.find { |a| a.start_with?('--detachable-client=') }
  return unless arg

  begin
    target = DetachableClientTarget.parse(arg.split('=', 2).last)
    if target.host
      resolution = Lich::Common::BindHostResolver.resolve(target.host)
      argv_options[:detachable_client_host] = resolution.host
      announce('warning', resolution.warning) if resolution.warning
    end
    # (The port-only form inherits --bind-address, which
    # handle_bind_address already resolved and warned about; the
    # loopback default warrants no warning.)
    argv_options[:detachable_client_port] = target.port
  rescue DetachableClientTarget::ParseError, Lich::Common::BindHostResolver::Error => e
    die(e.message)
  end
end

.handle_hosts_dir(argv_options) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Processes --hosts-dir argument and sets argv_options if valid.

Extracts the directory path from --hosts-dir=PATH in ARGV, validates existence, normalizes slashes, and removes the argument from ARGV. Warns if the directory does not exist but does not exit.

Parameters:

  • argv_options (Hash)

    mutable option hash



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'documented/main/argv_options.rb', line 250

def self.handle_hosts_dir(argv_options)
  if (arg = ARGV.find { |a| a =~ /^--hosts-dir=(.+)$/i })
    hosts_dir = arg[/^--hosts-dir=(.+)$/i, 1]
    ARGV.delete(arg)
    if hosts_dir && File.exist?(hosts_dir)
      hosts_dir = hosts_dir.tr('\\', '/')
      hosts_dir += '/' unless hosts_dir[-1..-1] == '/'
      argv_options[:hosts_dir] = hosts_dir
    else
      $stdout.puts "warning: given hosts directory does not exist: #{hosts_dir}"
    end
  end
end

.handle_sal_launch(argv_options) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

Exits on file not found, launcher not found, or after successful launch

This method returns an undefined value.

Launches a SAL or Gse.~xt file if argv_options is set.

Validates file existence, looks up the Simutronics launcher, and executes it via Win32.ShellExecute (Windows), Wine (if defined), or system() (other platforms). Logs and shows error messages, then exits on failure. Exits after successful launch.

Parameters:

  • argv_options (Hash)

    option hash with optional :sal key



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'documented/main/argv_options.rb', line 309

def self.handle_sal_launch(argv_options)
  return unless argv_options[:sal]

  unless File.exist?(argv_options[:sal])
    Lich.log "error: launch file does not exist: #{argv_options[:sal]}"
    Lich.msgbox "error: launch file does not exist: #{argv_options[:sal]}"
    exit
  end
  Lich.log "info: launch file: #{argv_options[:sal]}"

  if argv_options[:sal] =~ /SGE\.sal/i
    unless (launcher_cmd = Lich.get_simu_launcher)
      $stdout.puts 'error: failed to find the Simutronics launcher'
      Lich.log 'error: failed to find the Simutronics launcher'
      exit
    end
    launcher_cmd.sub!('%1', argv_options[:sal])
    Lich.log "info: launcher_cmd: #{launcher_cmd}"
    if defined?(Win32) && launcher_cmd =~ /^"(.*?)"\s*(.*)$/
      dir_file = $1
      param = $2
      dir = dir_file.slice(/^.*[\\\/]/)
      file = dir_file.sub(/^.*[\\\/]/, '')
      operation = (Win32.isXP? ? 'open' : 'runas')
      r = Win32.ShellExecute(lpOperation: operation, lpFile: file, lpDirectory: dir, lpParameters: param)
      Lich.log "error: Win32.ShellExecute returned #{r}; Win32.GetLastError: #{Win32.GetLastError}" if r < 33
    elsif defined?(Wine)
      system("#{Wine::BIN} #{launcher_cmd}")
    else
      system(launcher_cmd)
    end
    exit
  end
end