discourse/lib/final_destination/resolver.rb

67 lines
1.3 KiB
Ruby

# frozen_string_literal: true
class FinalDestination::Resolver
@mutex = Mutex.new
def self.lookup(addr, timeout: nil)
timeout ||= default_dns_query_timeout
@mutex.synchronize do
@result = nil
@queue ||= Queue.new
ensure_lookup_thread
@lookup = addr
@parent = Thread.current
# Wakeup the worker thread
@queue << ""
# 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.default_dns_query_timeout
if gs = GlobalSetting.dns_query_timeout_secs.presence
Integer(gs)
else
2
end
end
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