package main import ( "io/ioutil" "log" "strconv" "strings" "sync" "time" "github.com/levigross/grequests" "gopkg.in/yaml.v2" ) type DIPWorker struct { ForMatch map[string]*DIPGroup `yaml:"switch"` ForLoop map[string]*DIPGroup Restart int64 `yaml:"restart"` Mutex *sync.Mutex } // ShowGroupInfo 展示实时的 Group 信息动态 func (worker *DIPWorker) ShowGroupInfo() string { now := time.Now().Unix() content := "" for addr, group := range worker.ForLoop { content += addr + ": [" for _, dhost := range group.Group { overtimeLabel := "" if now-dhost.ActiveTime >= 150 { overtimeLabel = "<☠?>" } tm := time.Unix(dhost.ActiveTime, 0) tm.Format("2006-01-02 15:04:05") //2018-07-11 15:10:19 content += dhost.Host + "(" + tm.Format("2006-01-02 15:04:05") + overtimeLabel + ")," } content = strings.TrimRight(content, ",") + "]\n" } content = strings.TrimRight(content, "\n") return content } type DIPGroup struct { Group map[string]*DHost // 原始参照 Waitor map[string]*DHost Ready map[string]*DHost IPTableNum string Current *DHost City string Mutex *sync.Mutex } func NewDIPGroup() *DIPGroup { group := DIPGroup{} group.Group = make(map[string]*DHost) group.Waitor = make(map[string]*DHost) group.Ready = make(map[string]*DHost) group.Mutex = &sync.Mutex{} return &group } // Choose 选择一个正在准备的vps节点 func (group *DIPGroup) Choose(addr string) { now := time.Now().Unix() for ip, dhost := range group.Ready { // 设置转换的iptable if group.Current == nil { group.Current = dhost group.Current.ActiveTime = now SetAddrForward(group.IPTableNum, addr, ip) } else { restartAddr := "http://" + group.Current.Host + ":8800/pppoe/restart" if _, err := grequests.Get(restartAddr, nil); err != nil { log.Println(err) group.Current.ActiveTime += 12 } else { group.Current = dhost group.Current.ActiveTime = now // log.Println("new set addr:", group.Current.Host, "restartAddr:", restartAddr, "resp", resp.Content()) SetAddrForward(group.IPTableNum, addr, ip) } } group.Waitor[ip] = group.Ready[ip] delete(group.Ready, ip) break } } type DHost struct { Host string ActiveTime int64 } func NewDHost(host string) *DHost { dh := DHost{} dh.ActiveTime = time.Now().Unix() dh.Host = host return &dh } func (dh *DHost) OverTime(now int64, limit int64) int64 { if now-dh.ActiveTime >= limit { return 1 } return 0 } func (dip *DIPWorker) UnmarshalYAML(unmarshal func(interface{}) error) error { var data map[string]interface{} if err := unmarshal(&data); err != nil { return err } log.Println(data["switch"]) myswitch := data["switch"] dip.Restart = int64(data["restart"].(int)) num := 1 for k, v := range myswitch.(map[interface{}]interface{}) { group := NewDIPGroup() addrmap := v.(map[interface{}]interface{}) // sudo iptables -t nat -R IPSWITCH 1 -p icmp -j DNAT --to 1.1.1.1:8885 city := addrmap["city"].(string) group.City = city for _, host := range addrmap["group"].([]interface{}) { dhost := NewDHost(host.(string)) group.Group[dhost.Host] = dhost dip.ForMatch[dhost.Host] = group } dip.ForLoop[k.(string)] = group group.IPTableNum = strconv.Itoa(num) num++ } return nil } // NewDipWorker 创建一个 func NewDipWorker(filename string) *DIPWorker { worker := DIPWorker{} worker.ForMatch = make(map[string]*DIPGroup) worker.ForLoop = make(map[string]*DIPGroup) worker.Mutex = &sync.Mutex{} data, err := ioutil.ReadFile(filename) if err != nil { panic(err) } err = yaml.Unmarshal(data, &worker) if err != nil { panic(err) } return &worker }