Ctrl K
ComunidadGuías…

app/services/connection_testing.rb

Rama develop · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Shared plumbing for the surveys' "test connection" buttons. Each integration
# ships a `<Namespace>::ConnectionTest` service that responds to
# `call(check:, values:)` and returns a Result. New targets (MQTT, Shelly,
# SENEC, …) only need a service here plus a REGISTRY entry and a test button in
# their survey JSON — the controller and the frontend stay untouched.
module ConnectionTesting
  # `reason` is a stable symbol the controller maps to a localized message
  # (see `configurations.connection_test.*` in the locale files). `args` fills
  # the placeholders of a message that names what the probe was given, such as
  # the host it could not use.
  #
  # `warning` marks an answer that is neither a yes nor a no: the probe could
  # not settle the question, and the configuration it describes may still be
  # right. Such an answer is shown as a note rather than as a failure, so a
  # probe that cannot reach a correct setup does not talk the user out of it.
  Result = Data.define(:ok, :reason, :args, :warning) do
    def initialize(ok:, reason:, args: {}, warning: false) # rubocop:disable Naming/MethodParameterName
      super
    end

    # What the form shows: a confirmation, a note, or a failure.
    def state
      return 'ok' if ok
      return 'warn' if warning

      'error'
    end
  end

  # Mixed into the per-integration ConnectionTest services so each can build
  # a Result without repeating the keyword wiring.
  module ResultBuilder
    private

    def result(success, reason, warning: false, **args)
      Result.new(ok: success, reason:, args:, warning:)
    end

    # A probe that could not reach its target. A collector runs in its own
    # service, where a loopback address points at that service instead of at
    # the machine or the device meant, so the address cannot work. The answer
    # then names it, in place of a generic "not reachable" the user cannot act
    # on. Classified after the attempt, not before it, so a host that does
    # answer is never refused.
    def unreachable_result(host, reason)
      return result(false, reason) unless HostAddress.loopback?(host)

      result(false, :loopback_host, host:)
    end
  end

  # Survey `target` → connection-test service.
  REGISTRY = {
    'influxdb' => InfluxDb::ConnectionTest,
    'senec' => Senec::ConnectionTest,
    'shelly' => Shelly::ConnectionTest,
    'mqtt' => Mqtt::ConnectionTest,
    'backup' => Backups::ConnectionTest,
    'reverse_proxy' => ReverseProxy::ConnectionTest,
  }.freeze

  def self.run(target:, check:, values:)
    tester = REGISTRY[target]
    return Result.new(ok: false, reason: :error) unless tester

    tester.new.call(check:, values:)
  end
end