# frozen_string_literal: true require 'distributed_press/v1/client/site' # Soportar Distributed Press APIv1 # # Usa tokens de publicación efímeros para todas las acciones. # # Al ser creado, genera el sitio en la instancia de Distributed Press # configurada y almacena el ID. # # Al ser publicado, envía los archivos en un tarball y actualiza la # información. class DeployDistributedPress < Deploy store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON before_create :create_remote_site! before_destroy :delete_remote_site! DEPENDENCIES = %i[deploy_local] # Actualiza la información y luego envía los cambios # # @param :output [Bool] # @return [Bool] def deploy status = false log = [] time_start create_remote_site! if remote_site_id.blank? save if remote_site_id.blank? raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press' end site_client.tap do |c| stdout = Thread.new(publisher.logger_out) do |io| until io.eof? line = io.gets puts line if output log << line end end begin status = c.publish(publishing_site, deploy_local.destination) rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) status = false end if status self.remote_info[:distributed_press] = c.show(publishing_site).to_h save end publisher.logger.close stdout.join end time_stop create_stat! status, log.join status end def limit; end def size deploy_local.size end def destination; end # Devuelve las URLs de todos los protocolos def urls gateway_urls end private # @return [Array] def gateway_urls remote_info.dig(:distributed_press, :links)&.values&.map do |protocol| [ protocol[:link]] end&.flatten&.compact&.select do |link| link.include? '://' end || [] end # El cliente de la API # # TODO: cuando soportemos más, tiene que haber una relación entre # DeployDistributedPress y DistributedPressPublisher. # # @return [DistributedPressPublisher] def publisher @publisher ||= DistributedPressPublisher.last end # El cliente para actualizar el sitio # # @return [DistributedPress::V1::Client::Site] def site_client DistributedPress::V1::Client::Site.new(publisher.client) end # Genera el esquema de datos para poder publicar el sitio # # @return [DistributedPress::V1::Schemas::PublishingSite] def publishing_site DistributedPress::V1::Schemas::PublishingSite.new.call(id: remote_site_id) end # Genera el esquema de datos para crear el sitio # # @return [DistributedPressPublisher::V1::Schemas::NewSite] def create_site DistributedPress::V1::Schemas::NewSite.new.call(domain: hostname, protocols: { http: true, ipfs: true, hyper: true }) end # Crea el sitio en la instancia con el hostname especificado # # @return [nil] def create_remote_site! created_site = site_client.create(create_site) self.remote_site_id = created_site[:id] self.remote_info ||= {} self.remote_info[:distributed_press] = created_site.to_h nil rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) nil end # Registra lo que sucedió # # @param status [Bool] # @param log [String] # @return [nil] def create_stat!(status, log) build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status nil end def delete_remote_site! site_client.delete(publishing_site) nil rescue DistributedPress::V1::Error => e ExceptionNotifier.notify_exception(e, data: { site: site.name }) nil end end