1# frozen_string_literal: true
 2
 3class SessionManager
 4	class Timeout < StandardError; end
 5
 6	def initialize(blather, id_msg, timeout: 10, error_if: nil)
 7		@blather = blather
 8		@sessions = {}
 9		@id_msg = id_msg
10		@timeout = timeout
11		@error_if = error_if
12	end
13
14	def promise_for(stanza, timeout: @timeout)
15		begin; raise Timeout, "Timeout"; rescue Timeout; timeout_exception = $!; end
16		id = "#{stanza.to.stripped}/#{stanza.public_send(@id_msg)}"
17		@sessions.fetch(id) do
18			@sessions[id] = EMPromise.new
19			EM.add_timer(timeout) do
20				@sessions.delete(id)&.reject(timeout_exception)
21			end
22			@sessions[id]
23		end
24	end
25
26	def write(stanza, timeout: @timeout)
27		promise = promise_for(stanza, timeout: timeout)
28		@blather << stanza
29		promise
30	end
31
32	def fulfill(stanza)
33		id = "#{stanza.from.stripped}/#{stanza.public_send(@id_msg)}"
34		if stanza.error? || @error_if&.call(stanza)
35			@sessions.delete(id)&.reject(stanza)
36		else
37			@sessions.delete(id)&.fulfill(stanza)
38		end
39	end
40end