# encoding: UTF-8 # frozen_string_literal: true # Refinements # ======================================================================= require 'nrser/refinements/types' using NRSER::Types # Definitions # ======================================================================= # Mixin for common stuff that system agents do different. # # System agents are specific types of {Locd::Agent} built in to Loc'd to # handle things like proxying HTTP request site ({Locd::Agent::Proxy}), # rotating logs so they don't get unwieldily ({Locd::Agent::RotaeLogs}), # and probably more in the future, like serving a site index, API, etc. # # System agents are singular - there's only one of each for a Loc'd # label namespace, which is set via the configuration, and Loc'd uses # that label namespace, together with the each system agent's `.label_name`, # to form the agent's unique label, which is how it finds the system agents. # # This was really just to make it simpler by side-stepping how to handle # many proxies and log rotators and such because besides the dev/release # situation described above I can't really think of any reason you would want # to create and manage multiple of each system agent. # # As a consequence, {Locd::Agent} subclasses that mix {Locd::Agent::System} # in must define a `.label_name` class method. # module Locd::Agent::System @@classes = Hamster::Set.new def self.classes @@classes end def self.label? label label.is_a?( String ) \ && label.start_with?( Locd.config[:namespace, :label] ) end # Is a plist for one of this config's system agents? # # @param plist (see Locd::Agent.plist?) # # @return [Boolean] # `true` if the plist is for a system agent for this Loc'd config. # def self.plist? plist !!( plist.dig( Locd.config[:agent, :config_key], 'is_system' ) \ && label?( plist['Label'] ) ) end # .plist? # Find the concrete {Locd::Agent} subclass (that has mixed in # {Locd::Agent::System}) for a property list. # # @param plist (see Locd::Agent.plist?) # # @return [Class] # If the plist is for one of {.classes}, returns that class. # # @return [nil] # If the plist is: # # 1. Not a system plist (see {.plist?}) # # 2. If none of {.classes} claim it (via their `.plist?` method). # # Though, really, this one shouldn't happen except in weird version # switching situations maybe or something. # def self.class_for plist return nil unless plist?( plist ) classes.to_a.find_bounded( max: 1 ) { |cls| cls.plist? plist }.first end # .class_for def self.included base base.extend ClassMethods @@classes = @@classes.add base end # Mixed in to classes themselves that include {Locd::Agent::System}. # module ClassMethods def label "#{ Locd.config[:namespace, :label] }.#{ label_name }" end # The property lists for system agents are identified by their unique # label (unique to the label namespace). # # @param (see Locd::Agent.plist?) # @return (see Locd::Agent.plist?) # def plist? plist plist['Label'] == self.label end # Overridden as convenience, defaults the label to `.label`. # # @param (see Locd::Agent.plist_abs_path) # @return (see Locd::Agent.plist_abs_path) # def plist_abs_path label = self.label super label end # .plist_abs_path # By default system agent logs are placed in the Loc'd log directory, # which is `/log` and named `