diff --git a/lib/blather_notify.rb b/lib/blather_notify.rb index 6c5716cd3655cd28e94184818cd0c611efbe7e83..70d2300c44e30e58c20ae704178c3300907ce433 100644 --- a/lib/blather_notify.rb +++ b/lib/blather_notify.rb @@ -4,6 +4,10 @@ require "blather/client/dsl" require "em_promise" require "timeout" +require "ostruct" +require "securerandom" +require_relative "form_to_h" + module BlatherNotify extend Blather::DSL @@ -38,6 +42,65 @@ module BlatherNotify end end + class CommandExecution + using FormToH + + class FormErrorResponse < RuntimeError; end + + def initialize(blather, server, node) + @blather = blather + @server = server + @node = node + @sessionid = nil + end + + def fetch_and_submit(**form) + get_form.then { |response| + @sessionid ||= response.sessionid + + validate_form(form, response.form) + + @blather.write_with_promise(@blather.command( + @node, @sessionid, form: form.to_form(:submit), server: @server + )) + }.then(&method(:check_for_error)).then { |response| + @last_response = response + OpenStruct.new(response.form.to_h) + } + end + + protected + + def check_for_error(response) + if response.note&.[]("type") == "error" + raise FormErrorResponse, response.note.text + end + + response + end + + def validate_form(to_submit, received) + to_submit.each_key do |key| + raise "No field #{key}" unless received.field(key.to_s) + end + end + + def get_form + # If we already got a form on the last submit then + # assume we should fill that out here. + # If not, then move next to find the form + if @last_response&.form&.form? + EMPromise.resolve(@last_response) + else + @blather.write_with_promise(@blather.command( + @node, + @sessionid, + server: @server + )) + end + end + end + @ready = Queue.new when_ready { @ready << :ready } @@ -104,9 +167,12 @@ module BlatherNotify promise end - def self.command(node, sessionid=nil, action: :execute, form: nil) + def self.command( + node, sessionid=nil, + server: CONFIG[:sgx_jmp], action: :execute, form: nil + ) Blather::Stanza::Iq::Command.new.tap do |cmd| - cmd.to = CONFIG[:sgx_jmp] + cmd.to = server cmd.node = node cmd.command[:sessionid] = sessionid if sessionid cmd.action = action @@ -135,4 +201,8 @@ module BlatherNotify @default_pubsub.publish(xml) end + + def self.command_execution(server, node) + CommandExecution.new(self, server, node) + end end