//最新版本参见https://github.com/karlseguin/dnscache地址 或者  https://github.com/netroby/dnscache   

package dnscache
// Package dnscache caches DNS lookups

import (
  "net"
  "sync"
  "time"
)
//一个域名可能对应多个ip
type Resolver struct {
  lock sync.RWMutex   //锁--读写锁
  cache map[string][]net.IP  //map中key 为address ,value为域名对应的ip结合集合
}
//参数 refreshRate   设置刷新周期
func New(refreshRate time.Duration) *Resolver {
  resolver := &Resolver {
    cache: make(map[string][]net.IP, 64),
  }
  if refreshRate > 0 {//当刷新周期大于零  开启一个协程来自动解析域名,再次填充cache
    go resolver.autoRefresh(refreshRate)
  }
  return resolver
}
//解析域名对应的ip集合  如果在当前缓存中不存在  ,重新解析并返回
func (r *Resolver) Fetch(address string) ([]net.IP, error) {
  r.lock.RLock()
  ips, exists := r.cache[address]
  r.lock.RUnlock()
  if exists { return ips, nil }

  return r.Lookup(address)
}
//解析域名对应的ip集合中第一个ip
func (r *Resolver) FetchOne(address string) (net.IP, error) {
  ips, err := r.Fetch(address)
  if err != nil || len(ips) == 0 { return nil, err}
  return ips[0], nil
}
//解析域名对应的ip集合第一个ip的String方法
func (r *Resolver) FetchOneString(address string) (string, error) {
  ip, err := r.FetchOne(address)
  if err != nil || ip == nil { return "", err }
  return ip.String(), nil
}
//解析当前cache中所有的域名 并且处于阻塞中2秒  。每一个域名对应一个ip集合 并存储在cache中
func (r *Resolver) Refresh() {
  i := 0
  r.lock.RLock()//获取读锁
  addresses := make([]string, len(r.cache)) //创建一个slice  初始容量为 cache大小  用来存储当前的域名
  for key, _ := range r.cache {
    addresses[i] = key
    i++
  }
  r.lock.RUnlock()

  for _, address := range addresses {
    r.Lookup(address)
    time.Sleep(time.Second * 2)
  }
}
//通过net包 解析域名对应的ip集合
func (r *Resolver) Lookup(address string) ([]net.IP, error) {
  ips, err := net.LookupIP(address)
  if err != nil { return nil, err }

  r.lock.Lock()
  r.cache[address] = ips
  r.lock.Unlock()
  return ips, nil
}
//参数 rate   刷新周期
func (r *Resolver) autoRefresh(rate time.Duration) {
  for {
    time.Sleep(rate) //睡眠rate周期  并且处于阻塞中
    r.Refresh()
  }
}