@@ -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