# frozen_string_literal: true require "blather/client/dsl" require "em_promise" require "timeout" module BlatherNotify extend Blather::DSL @ready = Queue.new when_ready { @ready << :ready } def self.start(jid, password) # workqueue_count MUST be 0 or else Blather uses threads! setup(jid, password, nil, nil, nil, nil, workqueue_count: 0) EM.error_handler(&method(:panic)) @thread = Thread.new { EM.run do client.run end } Timeout.timeout(30) { @ready.pop } at_exit { wait_then_exit } end def self.panic(e) warn e.message warn e.backtrace exit! 2 end def self.wait_then_exit disconnected { EM.stop } EM.add_timer(30) { EM.stop } shutdown @thread.join end def self.timeout_promise(promise, timeout: 15) timer = EM.add_timer(timeout) { promise.reject(:timeout) } promise.then do timer.cancel end end def self.write_with_promise(stanza) promise = EMPromise.new timeout_promise(promise) client.write_with_handler(stanza) do |s| if s.error? || s.type == :error promise.reject(s) else promise.fulfill(s) end end promise end def self.command(node, sessionid=nil, action: :execute, form: nil) Blather::Stanza::Iq::Command.new.tap do |cmd| cmd.to = CONFIG[:sgx_jmp] cmd.node = node cmd.command[:sessionid] = sessionid if sessionid cmd.action = action cmd.command << form if form end end def self.execute(command_node, form=nil) write_with_promise(command(command_node)).then do |iq| next iq unless form write_with_promise(command(command_node, iq.sessionid, form: form)) end end end