#!/usr/bin/env ruby # frozen_string_literal: true require "dhall" require "net/http" require "uri" require "time" require "em-http" require "em-synchrony/em-http" require "link-header-parser" require_relative "../lib/em" require_relative "../lib/blather_notify" require_relative "../lib/form_to_h" require "ougai" $stdout.sync = true LOG = Ougai::Logger.new($stdout) LOG.level = ENV.fetch("LOG_LEVEL", "info") LOG.formatter = Ougai::Formatters::Readable.new( nil, nil, plain: !$stdout.isatty ) Blather.logger = LOG SCHEMA = "{ jid: Text, password: Text, sgx_jmp: Text, interval: Natural, max_attempts: Natural }" CONFIG = Dhall::Coder .new(safe: Dhall::Coder::JSON_LIKE) .load("#{ARGV.first} : #{SCHEMA}", transform_keys: :to_sym) DOMAIN = "jmp-test-#{Time.now.to_i}.snikket.chat" using FormToH class TestInstance def launch puts "Launching instance at #{DOMAIN}" BlatherNotify.execute( "snikket", { domain: DOMAIN }.to_form(:submit) ).then do |iq| @id = iq.form.field("instance-id").value.to_s @uri = iq.form.field("bootstrap-uri").value.to_s end end def extract_link(res) LinkHeaderParser.parse( Array(res.response_header["LINK"]), base: @uri ).group_by_relation_type[:alternate].find { |header| URI.parse(header.target_uri).scheme == "xmpp" }.target_uri end def ping_http(attempt: 0) raise "Couldn't ping #{DOMAIN} over HTTP" if attempt > CONFIG[:max_attempts] EM::HttpRequest.new( @uri, tls: { verify_peer: true } ).ahead(redirects: 5).then { |res| extract_link(res) }.catch { |e| puts "HTTP ping attempt #{attempt} failed: #{e}" EM.promise_timer(CONFIG[:interval]).then { ping_http(attempt: attempt + 1) } } end def ping_xmpp(attempt: 0) raise "Couldn't ping {#DOMAIN} over XMPP" if attempt > CONFIG[:max_attempts] BlatherNotify.write_with_promise( Blather::Stanza::Iq::Ping.new(:get, DOMAIN) ).catch { |e| puts "XMPP ping attempt #{attempt} failed: #{e}" EM.promise_timer(CONFIG[:interval]).then { ping_xmpp(attempt: attempt + 1) } } end def stop puts "Stopping instance at #{DOMAIN}" BlatherNotify.execute( "stop snikket", { instance_id: @id }.to_form(:submit) ).then do |iq| raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error end end def delete puts "Deleting instance at #{DOMAIN}" BlatherNotify.execute( "delete snikket", { instance_id: @id }.to_form(:submit) ).then do |iq| puts iq raise "Couldn't stop instance: #{iq.note}" if iq.note_type == :error end end end EM.run do instance = TestInstance.new BlatherNotify.start( CONFIG[:jid], CONFIG[:password] ).then { instance.launch }.then { puts "Launch instance success" instance.ping_http }.then { puts "HTTP ping success" instance.ping_xmpp }.then { puts "XMPP ping success" instance.stop }.then { puts "Stop instance success" instance.delete }.catch { |e| p e exit(e == :timeout ? 0 : 1) }.then { puts "Delete instance success" EM.stop } end