blather_notify.rb

 1# frozen_string_literal: true
 2
 3require "blather/client/dsl"
 4require "em_promise"
 5require "timeout"
 6
 7module BlatherNotify
 8	extend Blather::DSL
 9
10	@ready = Queue.new
11
12	when_ready { @ready << :ready }
13
14	def self.start(jid, password)
15		# workqueue_count MUST be 0 or else Blather uses threads!
16		setup(jid, password, nil, nil, nil, nil, workqueue_count: 0)
17
18		EM.error_handler(&method(:panic))
19
20		@thread = Thread.new {
21			EM.run do
22				client.run
23			end
24		}
25
26		Timeout.timeout(30) { @ready.pop }
27		at_exit { wait_then_exit }
28	end
29
30	def self.panic(e)
31		warn e.message
32		warn e.backtrace
33		exit! 2
34	end
35
36	def self.wait_then_exit
37		disconnected { EM.stop }
38		EM.add_timer(30) { EM.stop }
39		shutdown
40		@thread.join
41	end
42
43	def self.timeout_promise(promise, timeout: 15)
44		timer = EM.add_timer(timeout) {
45			promise.reject(:timeout)
46		}
47
48		promise.then do
49			timer.cancel
50		end
51	end
52
53	def self.write_with_promise(stanza)
54		promise = EMPromise.new
55		timeout_promise(promise)
56
57		client.write_with_handler(stanza) do |s|
58			if s.error? || s.type == :error
59				promise.reject(s)
60			else
61				promise.fulfill(s)
62			end
63		end
64		promise
65	end
66
67	def self.command(node, sessionid=nil, action: :execute, form: nil)
68		Blather::Stanza::Iq::Command.new.tap do |cmd|
69			cmd.to = CONFIG[:sgx_jmp]
70			cmd.node = node
71			cmd.command[:sessionid] = sessionid if sessionid
72			cmd.action = action
73			cmd.command << form if form
74		end
75	end
76
77	def self.execute(command_node, form=nil)
78		write_with_promise(command(command_node)).then do |iq|
79			next iq unless form
80
81			write_with_promise(command(command_node, iq.sessionid, form: form))
82		end
83	end
84end