main
1# frozen_string_literal: true
2
3module Net
4 module Hippie
5 # Thread-safe DNS resolution cache with TTL.
6 class DnsCache
7 def initialize(timeout: 5, ttl: 300, logger: nil)
8 @timeout = timeout
9 @ttl = ttl
10 @logger = logger
11 @cache = {}
12 @monitor = Monitor.new
13 end
14
15 def resolve(hostname)
16 cached = get(hostname)
17 return cached if cached
18
19 ip = Net::Hippie.resolve(hostname, timeout: @timeout)
20 set(hostname, ip)
21 ip
22 rescue Timeout::Error, Resolv::ResolvError => error
23 @logger&.warn("[Hippie] DNS resolution failed for #{hostname}: #{error.message}")
24 nil
25 end
26
27 def clear
28 @monitor.synchronize { @cache.clear }
29 end
30
31 private
32
33 def get(hostname)
34 @monitor.synchronize do
35 entry = @cache[hostname]
36 entry[:ip] if entry && (Time.now - entry[:time]) < @ttl
37 end
38 end
39
40 def set(hostname, ip_addr)
41 @monitor.synchronize { @cache[hostname] = { ip: ip_addr, time: Time.now } }
42 end
43 end
44 end
45end