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