Index: src/query.cr ================================================================== --- src/query.cr +++ src/query.cr @@ -1,11 +1,13 @@ require "./dns_class" require "./rr_type" module AsyncDNS class Query - getter :name, :class, :type + getter name : String + getter class : DNSClass + getter type : RRType def initialize(@name : String, @class : DNSClass, @type : RRType) end end end Index: src/resolver.cr ================================================================== --- src/resolver.cr +++ src/resolver.cr @@ -2,29 +2,26 @@ require "./settings" require "./response" module AsyncDNS class Resolver - getter :settings + getter settings : Settings enum Error NO_NAME_SERVER end - private struct Context - def initialize(@id : UInt16, @settings : Settings, - @block : Response | Error ->) - end - end + private record Context, id : UInt16, settings : Settings, + block : Response | Error -> def initialize @settings = Settings.new @queries = Hash(UInt16, Context).new @tcp_queries = Hash(Socket, Context).new end - def resolve(query, &block : Response | Error ->) + def resolve(query : Query, &block : Response | Error ->) id : UInt16 while true id = Random::Secure.rand(UInt16::MIN..UInt16::MAX) break unless @queries.has_key?(id) end @@ -35,11 +32,11 @@ end send(Context.new(id, settings.dup, block)) end - def send(context : Context) + private def send(context : Context) @queries[context.@id] = context # TODO end Index: src/response.cr ================================================================== --- src/response.cr +++ src/response.cr @@ -1,10 +1,13 @@ require "./rr" module AsyncDNS class Response - property :name, :answer, :authority, :additional + property name : String + property answer : Array(RR) + property authority : Array(RR) + property additional : Array(RR) def initialize(@name : String, @answer : Array(RR), @authority : Array(RR), @additional : Array(RR)) end end Index: src/rr.cr ================================================================== --- src/rr.cr +++ src/rr.cr @@ -1,103 +1,119 @@ require "socket" module AsyncDNS abstract struct RR - property :name, :class, :type, :ttl + property name : String + property class : DNSClass + property type : RRType + property ttl : UInt32 def initialize(@name : String, @class : DNSClass, @type : RRType, - @ttl : Int32) + @ttl : UInt32) end struct A < RR - property :address + property address : Socket::IPAddress - def initialize(name, @address : Socket::IPAddress, ttl) - super(name, DNSClass::IN, RRType::A, ttl) + def initialize(name : String, @address : Socket::IPAddress, ttl : UInt32) + super(name, :in, :a, ttl) end end struct AAAA < RR - property :address + property address : Socket::IPAddress - def initialize(name, @address : Socket::IPAddress, ttl) - super(name, DNSClass::IN, RRType::AAAA, ttl) + def initialize(name : String, @address : Socket::IPAddress, ttl : UInt32) + super(name, :in, :aaaa, ttl) end end struct CNAME < RR - property :alias + property alias : String - def initialize(name, @alias : String, ttl) - super(name, DNSClass::IN, RRType::CNAME, ttl) + def initialize(name : String, @alias : String, ttl : UInt32) + super(name, :in, :cname, ttl) end end struct HINFO < RR - property :cpu, :os + property cpu : String + property os : String - def initialize(name, @cpu : String, @os : String, ttl) - super(name, DNSClass::IN, RRType::HINFO, ttl) + def initialize(name : String, @cpu : String, @os : String, ttl : UInt32) + super(name, :in, :hinfo, ttl) end end struct MX < RR - property :preference, :mx + property preference : UInt16 + property mx : String - def initialize(name, @preference : UInt16, @mx : String, ttl) - super(name, DNSClass::IN, RRType::MX, ttl) + def initialize(name : String, @preference : UInt16, @mx : String, + ttl : UInt32) + super(name, :in, :mx, ttl) end end struct NS < RR - property :authority + property authority : String - def initialize(name, @authority : String, ttl) - super(name, DNSClass::IN, RRType::NS, ttl) + def initialize(name : String, @authority : String, ttl : UInt32) + super(name, :in, :ns, ttl) end end struct PTR < RR - property :domain + property domain : String - def initialize(name, @domain : String, ttl) - super(name, DNSClass::IN, RRType::PTR, ttl) + def initialize(name : String, @domain : String, ttl : UInt32) + super(name, :in, :ptr, ttl) end end struct RP < RR - property :mailbox, :domain + property mailbox : String + property domain : String - def initialize(name, @mailbox : String, @domain : String, ttl) - super(name, DNSClass::IN, RRType::RP, ttl) + def initialize(name : String, @mailbox : String, @domain : String, + ttl : UInt32) + super(name, :in, :rp, ttl) end end struct SOA < RR - property :primary_ns, :responsible, :serial, :refresh, :retry, - :expire, :min_ttl + property primary_ns : String + property responsible : String + property serial : UInt32 + property refresh : UInt32 + property retry : UInt32 + property expire : UInt32 + property min_ttl : UInt32 - def initialize(name, @primary_ns : String, @responsible : String, + def initialize(name : String, @primary_ns : String, @responsible : String, @serial : UInt32, @refresh : UInt32, @retry : UInt32, - @expire : UInt32, @min_ttl : UInt32) - super(name, DNSClass::IN, RRType::SOA, ttl) + @expire : UInt32, @min_ttl : UInt32, ttl : UInt32) + super(name, :in, :soa, ttl) end end struct SRV < RR - property :prio, :weight, :target, :port + property prio : UInt16 + property weight : UInt16 + property target : String + property port : UInt16 - def initialize(name, @prio : UInt16, @weight : UInt16, @target : String, - @port : UInt16, ttl) - super(name, DNSClass::IN, RRType::SRV, ttl) + def initialize(name : String, @prio : UInt16, @weight : UInt16, + @target : String, @port : UInt16, ttl : UInt32) + super(name, :in, :srv, ttl) end end struct TXT < RR - property :text + property text : Array(String) - def initialize(name, @text : Array(String), ttl) - super(name, DNSClass::IN, RRType::TXT) + def initialize(name : String, @text : Array(String), ttl : UInt32) + super(name, :in, :txt) end end end end Index: src/settings.cr ================================================================== --- src/settings.cr +++ src/settings.cr @@ -1,30 +1,36 @@ module AsyncDNS class Settings @local_domain : String? - property :static_hosts, :nameservers, :local_domain, :search_domains, - :uses_tcp, :reload_period - getter :timeout, :max_attempts, :abs_num_dots + property static_hosts : Hash(String, Array(String)) + property nameservers : Array(String) + property local_domain : String? + property search_domains : Array(String) + property uses_tcp : Bool + property reload_period : Time::Span + getter timeout : Time::Span + getter max_attempts : Int32 + getter abs_num_dots : Int32 - def timeout=(timeout) + def timeout=(timeout : Time::Span) if timeout < Time::Span.zero raise ArgumentError.new("timeout must be positive") end @timeout = timeout end - def max_attempts=(max_attempts) + def max_attempts=(max_attempts : Int32) if max_attempts < 0 raise ArgumentError.new("max_attempts must be positive") end @max_attempts = max_attempts end - def abs_num_dots=(abs_num_dots) + def abs_num_dots=(abs_num_dots : Int32) if abs_num_dots < 0 raise ArgumentError.new("abs_num_dots must be positive") end @abs_num_dots = abs_num_dots @@ -58,11 +64,11 @@ {% end %} @last_reload = Time.monotonic end - def parse_hosts(path) + private def parse_hosts(path) @static_hosts.clear File.each_line(path, chomp: true) do |line| pos = line.index('#') line = line[0, pos] if pos @@ -81,11 +87,11 @@ addresses << address end end end - def parse_resolv_conf(path) + private def parse_resolv_conf(path) @nameservers.clear @local_domain = nil @search_domains.clear File.each_line(path, chomp: true) do |line|