55 lines
1.1 KiB
Ruby
55 lines
1.1 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
class FinalDestination::Resolver
|
||
|
@mutex = Mutex.new
|
||
|
def self.lookup(addr, timeout: nil)
|
||
|
timeout ||= 2
|
||
|
@mutex.synchronize do
|
||
|
@result = nil
|
||
|
|
||
|
@queue ||= Queue.new
|
||
|
@queue << ""
|
||
|
ensure_lookup_thread
|
||
|
|
||
|
@lookup = addr
|
||
|
@parent = Thread.current
|
||
|
|
||
|
# This sleep will be interrupted by the lookup thread
|
||
|
# if completed within timeout
|
||
|
sleep timeout
|
||
|
if !@result
|
||
|
@thread.kill
|
||
|
@thread.join
|
||
|
@thread = nil
|
||
|
if @error
|
||
|
@error.backtrace.push(*caller)
|
||
|
raise @error
|
||
|
else
|
||
|
raise Timeout::Error
|
||
|
end
|
||
|
end
|
||
|
@result
|
||
|
end
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def self.ensure_lookup_thread
|
||
|
return if @thread&.alive?
|
||
|
|
||
|
@thread = Thread.new do
|
||
|
while true
|
||
|
@queue.deq
|
||
|
@error = nil
|
||
|
begin
|
||
|
@result = Addrinfo.getaddrinfo(@lookup, 80, nil, :STREAM).map(&:ip_address)
|
||
|
rescue => e
|
||
|
@error = e
|
||
|
end
|
||
|
@parent.wakeup
|
||
|
end
|
||
|
end
|
||
|
@thread.name = "final-destination_resolver_thread"
|
||
|
end
|
||
|
end
|