package main import ( "io/ioutil" "log" "strconv" "strings" "sync" "time" "474420502.top/eson/requests" "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(time.RFC3339) //2018-07-11 15:10:19 content += dhost.Host + "(" + tm.Format(time.RFC3339) + overtimeLabel + ")," } content = strings.TrimRight(content, ",") + "]\n" } content = strings.TrimRight(content, "\n") return content } // DIPGroup 动态ip组, 一个组指的是一条可动态切换的线 type DIPGroup struct { Group map[string]*DHost // 原始参照 Waitor map[string]*DHost Ready map[string]*DHost IPTableNum string Current *DHost City string Mutex *sync.Mutex } // NewDIPGroup 创建一个,动态ip组, 一个组指的是一条可动态切换的线 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 { log.Println(addr, " Current is nil") } else { i := 0 for ; i < 3; i++ { imokURL := "http://" + dhost.Host + ":8800/pppoe/imok" if _, err := requests.NewSession().Get(imokURL).Execute(); err != nil { log.Println(err) } else { // 如果ping 通下个切换的主机就切换 for ii := 0; ii < 3; ii++ { restartURL := "http://" + group.Current.Host + ":8800/pppoe/restart" if _, err := requests.NewSession().Get(restartURL).Execute(); err != nil { log.Println(err) } else { break // 可以切换 ii := 0; ii < 3; ii++ } } break // for ; i < 3; i++ { } } if i == 3 { // 下个需要切换的DHost错误 delete(group.Ready, ip) continue // 不执行下面的 切换操作 for ip, dhost := range group.Ready } } group.Current = dhost group.Current.ActiveTime = now SetAddrForward(group.IPTableNum, addr, ip) group.Waitor[ip] = group.Ready[ip] delete(group.Ready, ip) return } } // DHost 动态IP的一个vps // Host vps的host属性 指定ip // ActiveTime ActiveTime活跃时间 type DHost struct { Host string ActiveTime int64 } // NewDHost 创建一个DHost host 为 ip func NewDHost(host string) *DHost { dh := DHost{} dh.ActiveTime = time.Now().Unix() dh.Host = host return &dh } // OverTime dhost对比时间是否超过limit的限制, 超时判断 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 }