func (d *DialClients) Config(config *ConfigDialClients) (rerr error) {

	newClients := make([]*DialClient, 0, len(config.UpStreams))

	newUf, err := ufile.NewUFile(config.BasePath, 1*time.Minute)
	if err != nil {
		return err
	}
	// 出错退出时关闭 UFile
	defer func() {
		if rerr != nil {
			newUf.Close()
		}
	}()

	// 循环处理每个线路
	for _, c := range config.UpStreams {

		pc, err := proxyclient.NewProxyClient(c.ProxyUrl)
		if err != nil {
			rerr = fmt.Errorf("无法创建上级代理:%v", err)
			return
		}

		client := DialClient{
			name:         c.Name,
			dnsResolve:   c.DnsResolve,
			pc:           pc,
			dialCredit:   c.Credit,
			sleep:        time.Duration(c.Sleep) * time.Millisecond,
			correctDelay: time.Duration(c.CorrectDelay) * time.Millisecond,
			whiteList:    domains.NewDomains(100),
			blackList:    domains.NewDomains(100),
		}

		// 循环处理每个黑白名单文件
		// 添加到 ufile 里面,实际重新加载在 ufile 结果信道处处理。
		flist := func(clientList []*ConfigDialClientWBList, wbList *domains.Domains) error {
			for _, f := range clientList {
				UpdateInterval, err := time.ParseDuration(f.UpdateInterval)
				if err != nil {
					return err
				}

				domainType, err := domains.ParseDomainType(f.Type)
				if err != nil {
					return err
				}

				userdara := ufUserdata{
					name:       fmt.Sprintf("%v-%v", f.Type, f.Path),
					domainType: domainType,
					domains:    wbList,
				}

				if err := newUf.Add(f.Path, UpdateInterval, &userdara); err != nil {
					return err
				}
			}
			return nil
		}

		if err := flist(c.Whitelist, client.whiteList); err != nil {
			rerr = err
			return
		}
		if err := flist(c.Blacklist, client.blackList); err != nil {
			rerr = err
			return
		}

		newClients = append(newClients, &client)
	}

	d.rwm.Lock()
	defer d.rwm.Unlock()
	d.clients = newClients

	if d.uf != nil {
		d.uf.Close()
	}
	d.uf = newUf

	go d.loop(newUf)

	return nil
}
Esempio n. 2
0
// 更新配置
// hosts 本地文件会直接载入
//       不存在时打印警告,但是不出错退出,等新建 hosts 文件时将会自动载入
// hosts http、https 文件,定时更新。
// 每次配置重新载入所有的配置文件,并不是函数返回配置就立刻生效,配置生效需要时间。
func (h *hostsDns) Config(c *DnschanHostsConfig) error {
	newUFile, err := ufile.NewUFile(c.BashPath, hostsCheckInterval)
	if err != nil {
		return err
	}

	for _, hosts := range c.Hostss {
		if strings.TrimSpace(hosts.Type) == "" {
			hosts.Type = "base"
		}
	}

	for _, hosts := range c.Hostss {
		// 解析更新间隔
		if lpath := strings.ToLower(hosts.Path); hosts.UpdateInterval == "" &&
			strings.HasPrefix(lpath, "http://") == false &&
			strings.HasPrefix(lpath, "https://") == false {
			// 本地文件不存在更新间隔时自动补一个,其实没有用处。
			hosts.UpdateInterval = "1h"
		}

		updateInterval, err := time.ParseDuration(hosts.UpdateInterval)
		if err != nil {
			newUFile.Close()
			return fmt.Errorf("hosts 配置错误:updateInterval (%v) 格式不是正确的时间格式:%v", hosts.UpdateInterval, err)
		}

		// 类型
		domainType, err := domains.ParseDomainType(hosts.Type)
		if err != nil {
			return fmt.Errorf("未知的 hosts 类型:%v", hosts.Type)
		}

		// userdata
		name := fmt.Sprint(domainType, "-", hosts.Credit, "-", hosts.Path)
		userdata := ufileUserdata{
			name:       name,
			domainType: domainType,
			credit:     hosts.Credit,
		}

		if err := newUFile.Add(hosts.Path, updateInterval, &userdata); err != nil {
			newUFile.Close()
			return err
		}
	}

	// 配置没有明显错误,使用新配置
	h.rwm.Lock()
	defer h.rwm.Unlock()

	if h.uf != nil {
		h.uf.Close() //关闭老配置的自动更新
	}

	newDomains := domains.NewDomains(hostsCacheSize)

	h.ds = newDomains
	h.uf = newUFile

	go h.loop(newUFile, newDomains)

	return nil
}