Module: Lich::Common::Frontend

Defined in:
documented/common/front-end.rb,
documented/common/front-end.rb

Overview

Frontend registry and capabilities system for client identification.

Manages a registry of game frontends (e.g., Wrayth, Saga, Wizard) with their capabilities and discovery metadata. Scripts query this module to check frontend features and access the current client identity.

Constant Summary collapse

PLATFORM_KEYS =

Canonical platform identifiers used in discovery and launch plans.

%i[darwin linux windows unsupported].freeze
ORIGIN_SENTINEL =
"\x1f"
SAGA_LICH_LAUNCH_ENVIRONMENT =

Environment variables passed to Saga during launch via the launcher adapter.

Tokens like %host%, %port%, and %key% are substituted by the launcher with values from the connection context.

See Also:

{
  'SAGA_LICH_MODE' => '1',
  'SAGA_LICH_HOST' => '%host%',
  'SAGA_LICH_PORT' => '%port%',
  'SAGA_LICH_KEY'  => '%key%'
}.freeze
CLIENT_STRING =

--- Client String ----------------------------------------- Default client string (Wrayth identity) sent during handshake

"/FE:WRAYTH /VERSION:1.0.1.28 /P:WIN_UNKNOWN /XML"
XML_FRONTENDS =

--- Backward-Compatible Constants ------------------------- These arrays are derived from the registry for backward compatibility. External code may still reference these constants directly.

frontends_with_capability(:xml).freeze
GSL_FRONTENDS =

Deprecated: list of frontends supporting GSL.

For backward compatibility. New code should call .frontends_with_capability(:gsl) or check a specific frontend with .has_capability?(name, :gsl).

frontends_with_capability(:gsl).freeze
STREAM_FRONTENDS =

Deprecated: list of frontends supporting XML streams.

For backward compatibility. New code should call .frontends_with_capability(:streams) or check a specific frontend with .has_capability?(name, :streams).

frontends_with_capability(:streams).freeze
MONO_FRONTENDS =

Deprecated: list of frontends supporting monospace rendering.

For backward compatibility. New code should call .frontends_with_capability(:mono) or check a specific frontend with .has_capability?(name, :mono).

frontends_with_capability(:mono).freeze
SENTINEL_FRONTENDS =

Deprecated: list of frontends supporting sentinel tags.

For backward compatibility. New code should call .frontends_with_capability(:sentinel) or check a specific frontend with .has_capability?(name, :sentinel).

frontends_with_capability(:sentinel).freeze

Class Method Summary collapse

Class Method Details

.canonical_name(frontend_name) ⇒ String

Returns the stable catalog identifier for a frontend or alias. Unknown values are normalized but are not registered.

Parameters:

  • frontend_name (String, Symbol)

Returns:



125
126
127
128
# File 'documented/common/front-end.rb', line 125

def self.canonical_name(frontend_name)
  key = frontend_name.to_s.downcase
  @aliases.fetch(key, key)
end

.cleanup_session_filevoid

This method returns an undefined value.

Deletes the session descriptor file if it exists.

Called during shutdown to clean up temporary launch artifacts.



550
551
552
553
# File 'documented/common/front-end.rb', line 550

def self.cleanup_session_file
  return if @session_file.nil?
  File.delete(@session_file) if File.exist? @session_file
end

.clientObject

Accessor for the current frontend identity ($frontend global)



484
485
486
# File 'documented/common/front-end.rb', line 484

def self.client
  $frontend
end

.client=(value) ⇒ Object

Setter for the current frontend identity



489
490
491
# File 'documented/common/front-end.rb', line 489

def self.client=(value)
  $frontend = value
end

.create_session_file(name, host, port, display_session: true) ⇒ void

This method returns an undefined value.

Writes a session descriptor to a temporary file for detachable clients.

Creates the directory structure under the system temp folder ($TMPDIR/simutronics/sessions/) and writes a JSON file with the session details. Used by launcher adapters to hand off connection info to frontends like Saga.

Examples:

Frontend.create_session_file("Talan", "eaccess.play.net", 7024)

Parameters:

  • name (String, nil)

    character name (lowercase, then capitalized for filename); if nil, does nothing

  • host (String)

    game server hostname or IP

  • port (Integer)

    game server port

  • display_session (Boolean) (defaults to: true)

    if true, prints the descriptor to stdout



525
526
527
528
529
530
531
532
533
534
# File 'documented/common/front-end.rb', line 525

def self.create_session_file(name, host, port, display_session: true)
  return if name.nil?
  FileUtils.mkdir_p @tmp_session_dir
  @session_file = File.join(@tmp_session_dir, "%s.session" % name.downcase.capitalize)
  session_descriptor = { name: name, host: host, port: port }.to_json
  puts "writing session descriptor to %s\n%s" % [@session_file, session_descriptor] if display_session
  File.open(@session_file, "w") do |fd|
    fd << session_descriptor
  end
end

.definition_for(frontend_name) ⇒ Hash

Returns an immutable catalog definition for a registered frontend.

Accepted inputs are a non-empty String or Symbol naming an existing registry entry. Invalid or unknown identifiers raise ArgumentError. This method performs no discovery and persists nothing.

Parameters:

  • frontend_name (String, Symbol)

Returns:

Raises:

  • (ArgumentError)

    if frontend_name is blank or unregistered



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'documented/common/front-end.rb', line 161

def self.definition_for(frontend_name)
  key = canonical_name(frontend_name)
  raise ArgumentError, 'frontend name must not be empty' if key.empty?
  raise ArgumentError, "unknown frontend: #{frontend_name}" unless @registry.key?(key)

  @definitions[key] ||= Lich::Util.deep_freeze(
    {
      id: key,
      capabilities: @registry.fetch(key)[:capabilities].to_a,
      metadata: deep_copy(@registry.fetch(key)[:metadata])
    }
  )
end

.definitions(gui_selectable: nil) ⇒ Array<Hash>

Returns immutable catalog definitions, optionally restricted to those intended for the graphical launcher.

Parameters:

  • gui_selectable (Boolean, nil) (defaults to: nil)

Returns:



180
181
182
183
184
185
186
187
# File 'documented/common/front-end.rb', line 180

def self.definitions(gui_selectable: nil)
  definitions = @registry.keys.map { |name| definition_for(name) }
  return definitions if gui_selectable.nil?

  definitions.select do |definition|
    definition.dig(:metadata, :gui_selectable) == gui_selectable
  end
end

.detect_pidInteger?

Detect and store the frontend process ID Uses various methods depending on how Lich was launched

Returns:

  • (Integer, nil)

    The detected PID or nil if detection fails



613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
# File 'documented/common/front-end.rb', line 613

def self.detect_pid
  # Return existing PID if already set
  current_pid = self.pid
  return current_pid if current_pid && current_pid > 0

  # Try to detect based on launch method
  # This is a fallback for cases where init wasn't called
  parent_pid = Process.ppid
  resolved_pid = resolve_pid(parent_pid)

  if resolved_pid && resolved_pid > 0
    self.pid = resolved_pid
    Lich.log "Frontend PID detected (fallback): #{resolved_pid}" if defined?(Lich.log)
    resolved_pid
  else
    Lich.log "Failed to detect frontend PID" if defined?(Lich.log)
    nil
  end
end

.detect_platformSymbol

Detect the current platform

Returns:

  • (Symbol)

    :windows, :macos, :linux, or :unsupported



665
666
667
668
# File 'documented/common/front-end.rb', line 665

def self.detect_platform
  key = platform_key
  key == :darwin ? :macos : key
end

.display_name(frontend_name) ⇒ String

Returns the catalog display name, with a stable fallback for legacy saved entries that predate the catalog.

Parameters:

  • frontend_name (String, Symbol)

Returns:



224
225
226
227
228
# File 'documented/common/front-end.rb', line 224

def self.display_name(frontend_name)
  definition_for(frontend_name).dig(:metadata, :display_name) || frontend_name.to_s.capitalize
rescue ArgumentError
  frontend_name.to_s.capitalize
end

.ensure_windows_modulesObject

Ensure Windows modules are loaded (they're defined at top level)



853
854
855
856
857
# File 'documented/common/front-end.rb', line 853

def self.ensure_windows_modules
  return false unless native_windows_runtime?

  defined?(::Win32Enum) && defined?(::WinAPI)
end

.frontends_with_capability(capability) ⇒ Array<String>

Returns all frontends that have a specific capability.

Parameters:

  • capability (Symbol)

    The capability to filter by

Returns:



240
241
242
243
244
245
246
# File 'documented/common/front-end.rb', line 240

def self.frontends_with_capability(capability)
  canonical = @registry.select { |_name, data| data[:capabilities].include?(capability.to_sym) }.keys
  aliases = @aliases.filter_map do |alias_name, name|
    alias_name if canonical.include?(name)
  end
  canonical + aliases
end

.has_capability?(frontend_name, capability) ⇒ Boolean

Checks if a frontend has a specific capability.

Parameters:

  • frontend_name (String)

    The name of the frontend to check

  • capability (Symbol)

    The capability to check for

Returns:

  • (Boolean)


134
135
136
137
138
139
# File 'documented/common/front-end.rb', line 134

def self.has_capability?(frontend_name, capability)
  return false if frontend_name.nil?

  entry = @registry[canonical_name(frontend_name)]
  entry ? entry[:capabilities].include?(capability.to_sym) : false
end

.init_from_parent(parent_pid) ⇒ Integer?

Initialize PID from parent process (for Warlock)

Returns:

  • (Integer, nil)

    The resolved frontend PID



573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
# File 'documented/common/front-end.rb', line 573

def self.init_from_parent(parent_pid)
  Lich.log "=== Frontend.init_from_parent called ==="
  Lich.log "Parent process PID: #{parent_pid}"

  # Let's see what process this actually is on Windows
  if windows_platform?
    begin
      require 'win32ole'
      wmi = WIN32OLE.connect('winmgmts://')
      rows = wmi.ExecQuery("SELECT Name, ProcessId FROM Win32_Process WHERE ProcessId=#{parent_pid}")
      row = rows.each.first rescue nil
      if row
        Lich.log "Parent process name: #{row.Name}"
      end
    rescue StandardError, LoadError => e
      Lich.log "Could not get parent process name: #{e.message}"
    end
  end

  resolved_pid = resolve_pid(parent_pid)
  Lich.log "resolve_pid(#{parent_pid}) returned: #{resolved_pid}"

  self.pid = resolved_pid
  Lich.log "Frontend PID set to: #{self.pid}"

  resolved_pid
end

.metadata_for(frontend_name, key) ⇒ Object?

Retrieves a metadata value for a given frontend.

Parameters:

  • frontend_name (String)

    The name of the frontend

  • key (Symbol)

    The metadata key to retrieve

Returns:

  • (Object, nil)


145
146
147
148
149
150
# File 'documented/common/front-end.rb', line 145

def self.(frontend_name, key)
  return nil if frontend_name.nil?

  entry = @registry[canonical_name(frontend_name)]
  entry && entry[:metadata][key]
end

.native_windows_runtime?Boolean

Native user32 bindings require a Windows MRI ABI, not merely a Windows host.

Returns:

  • (Boolean)


31
32
33
# File 'documented/common/front-end.rb', line 31

def self.native_windows_runtime?
  OS.host_os.to_s.match?(/mingw|mswin/i)
end

.pidInteger?

Get the current frontend PID

Returns:

  • (Integer, nil)

    The PID if set, nil otherwise



559
560
561
# File 'documented/common/front-end.rb', line 559

def self.pid
  @pid_mutex.synchronize { @frontend_pid }
end

.pid=(value) ⇒ Integer

Set the frontend PID

Parameters:

  • value (Integer)

    The PID to store

Returns:

  • (Integer)

    The stored PID



566
567
568
569
# File 'documented/common/front-end.rb', line 566

def self.pid=(value)
  value = value.to_i
  @pid_mutex.synchronize { @frontend_pid = value }
end

.platform_keySymbol

Returns the canonical platform key used by frontend discovery and launch-plan metadata.

Returns:

  • (Symbol)

    :darwin, :windows, :linux, or :unsupported



193
194
195
196
197
198
199
# File 'documented/common/front-end.rb', line 193

def self.platform_key
  return :darwin if OS.mac?
  return :linux if OS.linux?
  return :windows if OS.windows?

  :unsupported
end

.player_id_tag(player_id) ⇒ Object

Build the re-emit tag for a detachable client (e.g. Saga).

Lich consumes the game's one-time during its own login handshake, before a detachable client attaches, so the client never sees it. XMLData.player_id stores the id verbatim, so re-emitting reproduces exactly what a Direct login delivers.

Returns the tag string only when player_id is a bare numeric id (the form the game sends). Returns nil otherwise, so callers skip emitting an empty or malformed tag before login has populated the id.



476
477
478
479
480
481
# File 'documented/common/front-end.rb', line 476

def self.player_id_tag(player_id)
  id = player_id.to_s
  return nil unless id =~ /\A\d+\z/

  "<playerID id='#{id}'/>"
end

.refocusBoolean

Refocus the frontend window

Returns:

  • (Boolean)

    true if successful, false otherwise



635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'documented/common/front-end.rb', line 635

def self.refocus
  pid = self.pid
  return false unless pid && pid > 0

  case detect_platform
  when :windows
    refocus_windows(pid)
  when :macos
    refocus_macos(pid)
  when :linux
    refocus_linux(pid)
  else
    false
  end
end

.refocus_callbackProc

Create a callback for GTK windows to refocus on click

Returns:

  • (Proc)

    A proc that can be called to refocus the frontend



653
654
655
656
657
658
659
660
661
# File 'documented/common/front-end.rb', line 653

def self.refocus_callback
  proc {
    if defined?(GLib) && GLib.respond_to?(:Idle)
      GLib::Idle.add(50) { self.refocus; false }
    else
      self.refocus
    end
  }
end

.refocus_linux(pid) ⇒ Object

Linux refocus implementation



836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
# File 'documented/common/front-end.rb', line 836

def self.refocus_linux(pid)
  return false unless system('which xdotool > /dev/null 2>&1')

  _stdout, stderr, status = Open3.capture3('xdotool', 'search', '--pid', pid.to_s, 'windowactivate')

  if status.success?
    true
  else
    Lich.log "Error refocusing Linux: #{stderr}" if defined?(Lich.log)
    false
  end
rescue => e
  Lich.log "Error refocusing Linux: #{e}" if defined?(Lich.log)
  false
end

.refocus_macos(pid) ⇒ Object

macOS refocus implementation



818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
# File 'documented/common/front-end.rb', line 818

def self.refocus_macos(pid)
  return false unless system('which osascript > /dev/null 2>&1')

  script = %{tell application "System Events" to set frontmost of (first process whose unix id is #{pid}) to true}
  _stdout, stderr, status = Open3.capture3('osascript', '-e', script)

  if status.success?
    true
  else
    Lich.log "Error refocusing macOS: #{stderr}" if defined?(Lich.log)
    false
  end
rescue => e
  Lich.log "Error refocusing macOS: #{e}" if defined?(Lich.log)
  false
end

.refocus_windows(pid) ⇒ Object

Windows refocus implementation



779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
# File 'documented/common/front-end.rb', line 779

def self.refocus_windows(pid)
  ensure_windows_modules

  hwnd_buf = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)

  enum_cb = Fiddle::Closure::BlockCaller.new(
    Fiddle::TYPE_INT,
    [Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG]
  ) do |hwnd, _|
    next 1 if ::WinAPI.IsWindowVisible(hwnd).zero?

    pid_tmp = [0].pack('L')
    ::WinAPI.GetWindowThreadProcessId(hwnd, pid_tmp)
    win_pid = pid_tmp.unpack1('L')

    if win_pid == pid
      hwnd_buf[0, Fiddle::SIZEOF_VOIDP] = [hwnd].pack('L!')
      0  # stop enumeration
    else
      1  # continue enumeration
    end
  end

  ::WinAPI.EnumWindows(enum_cb, 0)
  hwnd = hwnd_buf[0, Fiddle::SIZEOF_VOIDP].unpack1('L!')

  if hwnd != 0
    ::WinAPI.SetForegroundWindow(hwnd)
    true
  else
    Lich.log "Frontend window for PID #{pid} not found" if defined?(Lich.log)
    false
  end
rescue => e
  Lich.log "Error refocusing Windows: #{e}" if defined?(Lich.log)
  false
end

.register(name, capabilities: [], metadata: {}) ⇒ Object

Registers a frontend with its capabilities and metadata.

Parameters:

  • name (Symbol, String)

    The name of the frontend (e.g., :wrayth)

  • capabilities (Array<Symbol>) (defaults to: [])

    A list of capabilities (e.g., [:xml, :streams])

  • metadata (Hash) (defaults to: {})

    Additional data (e.g., { client_string: "..." })

Raises:

  • (ArgumentError)


109
110
111
112
113
114
115
116
117
118
# File 'documented/common/front-end.rb', line 109

def self.register(name, capabilities: [], metadata: {})
  key = name.to_s.downcase
  raise ArgumentError, 'frontend name must not be empty' if key.empty?

  entry = (@registry[key] ||= { capabilities: Set.new, metadata: {} })
  entry[:capabilities].merge(capabilities.map(&:to_sym))
  entry[:metadata].merge!(deep_copy())
  Array([:aliases]).each { |alias_name| @aliases[alias_name.to_s.downcase] = key }
  @definitions.delete(key)
end

.registered_frontendsArray<String>

Returns every recognized frontend name: canonical catalog identifiers followed by their accepted aliases.

Returns:



233
234
235
# File 'documented/common/front-end.rb', line 233

def self.registered_frontends
  @registry.keys + @aliases.keys
end

.resolve_linux_pid(pid) ⇒ Object

Linux-specific PID resolution



753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
# File 'documented/common/front-end.rb', line 753

def self.resolve_linux_pid(pid)
  return pid unless system('which xdotool > /dev/null 2>&1')

  p = pid
  16.times do
    # Check if this process has a window
    return p if system("xdotool search --pid #{p} >/dev/null 2>&1")

    # Walk up to parent process
    begin
      status = File.read("/proc/#{p}/status")
      parent = status[/PPid:\s+(\d+)/, 1].to_i
    rescue
      parent = 0
    end
    return pid if parent.zero? || parent == p
    p = parent
  end

  pid # fallback
rescue => e
  Lich.log "Error resolving Linux PID: #{e}" if defined?(Lich.log)
  pid
end

.resolve_pid(pid) ⇒ Integer

Resolve PID by walking up process tree to find window owner

Parameters:

  • pid (Integer)

    Starting process ID

Returns:

  • (Integer)

    The resolved PID



673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
# File 'documented/common/front-end.rb', line 673

def self.resolve_pid(pid)
  pid = pid.to_i
  return pid if pid <= 0 # Return as-is if invalid

  # Use the FrontendPID resolver logic
  case detect_platform
  when :windows
    resolve_windows_pid(pid)
  when :linux
    resolve_linux_pid(pid)
  else
    # macOS/other: PID usually already owns the window
    pid
  end
end

.resolve_windows_pid(pid) ⇒ Object

Windows-specific PID resolution



690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
# File 'documented/common/front-end.rb', line 690

def self.resolve_windows_pid(pid)
  Lich.log "=== resolve_windows_pid starting with PID: #{pid} ==="

  ensure_windows_modules
  require 'win32ole' rescue (return pid)

  begin
    wmi = WIN32OLE.connect('winmgmts://')
    p = pid

    16.times do
      # Get process name for debugging
      rows = wmi.ExecQuery("SELECT Name FROM Win32_Process WHERE ProcessId=#{p}")
      row = rows.each.first rescue nil
      process_name = row ? row.Name : "unknown"
      Lich.log "  Process name: #{process_name}"

      # Check if this process owns any visible window
      found = false
      cb = Fiddle::Closure::BlockCaller.new(
        Fiddle::TYPE_INT,
        [Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG]
      ) do |hwnd, _|
        next 1 if ::Win32Enum.IsWindowVisible(hwnd).zero?
        buf = [0].pack('L')
        ::Win32Enum.GetWindowThreadProcessId(hwnd, buf)
        if buf.unpack1('L') == p
          found = true
          Lich.log "  Found visible window for PID #{p}"
          0  # stop enumeration
        else
          1  # continue enumeration
        end
      end
      ::Win32Enum.EnumWindows(cb, 0)

      if found
        Lich.log "  Stopping at PID #{p} (#{process_name}) - has visible window"
        return p
      end

      # Walk up to parent process
      parent = windows_parent_pid(wmi, p)

      break if parent.nil? || parent.zero? || parent == p
      p = parent
    end
  rescue => e
    Lich.log "ERROR in resolve_windows_pid: #{e}"
  end

  Lich.log "Fallback: returning original PID #{pid}"
  pid
end

.send_handshake(version_string) ⇒ Object

Send version string, ready signals, and setup commands to the game server. Used during login handshake for wizard/avalon/frostbite frontends.



495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'documented/common/front-end.rb', line 495

def self.send_handshake(version_string)
  $_CLIENTBUFFER_.push(version_string.dup)
  Game._puts(version_string)
  2.times do
    sleep 0.3
    $_CLIENTBUFFER_.push("#{$cmd_prefix}\r\n")
    Game._puts($cmd_prefix)
  end
  ["#{$cmd_prefix}_injury 2",
   "#{$cmd_prefix}_flag Display Inventory Boxes 1",
   "#{$cmd_prefix}_flag Display Dialog Boxes 0"].each do |cmd|
    $_CLIENTBUFFER_.push(cmd)
    Game._puts(cmd)
  end
end

.session_file_locationString?

Returns the path to the session descriptor file, or nil if not yet created.

Returns:

  • (String, nil)

    absolute path to the session file

See Also:



540
541
542
# File 'documented/common/front-end.rb', line 540

def self.session_file_location
  @session_file
end

.set_from_client(pid) ⇒ Integer

Set PID from a detachable frontend such as Profanity or Saga.

Parameters:

  • pid (Integer)

    The PID sent by the client

Returns:

  • (Integer)

    The stored PID



604
605
606
607
608
# File 'documented/common/front-end.rb', line 604

def self.set_from_client(pid)
  self.pid = pid
  Lich.log "Frontend PID set from client: #{pid}" if defined?(Lich.log)
  pid
end

.supports_gsl?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports GSL (game scripting language).

Examples:

Frontend.supports_gsl?("wizard") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :gsl capability



422
423
424
# File 'documented/common/front-end.rb', line 422

def self.supports_gsl?(fe = $frontend)
  has_capability?(fe, :gsl)
end

.supports_mono?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports monospace rendering.

Examples:

Frontend.supports_mono?("stormfront") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :mono capability



442
443
444
# File 'documented/common/front-end.rb', line 442

def self.supports_mono?(fe = $frontend)
  has_capability?(fe, :mono)
end

.supports_room_window?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports a dedicated room window.

Examples:

Frontend.supports_room_window?("wrayth") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :room_window capability



452
453
454
# File 'documented/common/front-end.rb', line 452

def self.supports_room_window?(fe = $frontend)
  has_capability?(fe, :room_window)
end

.supports_sentinel?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports sentinel tags (detachable client protocol).

Examples:

Frontend.supports_sentinel?("saga") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :sentinel capability



462
463
464
# File 'documented/common/front-end.rb', line 462

def self.supports_sentinel?(fe = $frontend)
  has_capability?(fe, :sentinel)
end

.supports_streams?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports XML stream output.

Examples:

Frontend.supports_streams?("saga") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :streams capability



432
433
434
# File 'documented/common/front-end.rb', line 432

def self.supports_streams?(fe = $frontend)
  has_capability?(fe, :streams)
end

.supports_xml?(fe = $frontend) ⇒ Boolean

Checks whether a frontend supports XML protocol.

Examples:

Frontend.supports_xml?("wrayth") #=> true

Parameters:

  • fe (String, nil) (defaults to: $frontend)

    frontend name; defaults to the current $frontend

Returns:

  • (Boolean)

    true if the frontend has the :xml capability



412
413
414
# File 'documented/common/front-end.rb', line 412

def self.supports_xml?(fe = $frontend)
  has_capability?(fe, :xml)
end

.validate_platform_key!(key) ⇒ Symbol

Validates a canonical platform key used by discovery and launch plans.

Parameters:

  • key (Symbol)

Returns:

  • (Symbol)

Raises:

  • (ArgumentError)

    when key is not canonical



206
207
208
209
210
# File 'documented/common/front-end.rb', line 206

def self.validate_platform_key!(key)
  return key if PLATFORM_KEYS.include?(key)

  raise ArgumentError, "invalid platform key: #{key.inspect}"
end

.windows_parent_pid(wmi, pid) ⇒ Object

Get parent process ID on Windows



746
747
748
749
750
# File 'documented/common/front-end.rb', line 746

def self.windows_parent_pid(wmi, pid)
  rows = wmi.ExecQuery("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId=#{pid}")
  row = rows.each.first rescue nil
  row ? row.ParentProcessId.to_i : 0
end

.windows_platform?Boolean

Returns whether the current host is classified as Windows.

Returns:

  • (Boolean)


215
216
217
# File 'documented/common/front-end.rb', line 215

def self.windows_platform?
  platform_key == :windows
end