github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/catgo/cat-go/cat/router.go (about) 1 package cat 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "math" 9 "math/rand" 10 "net" 11 "net/http" 12 "net/url" 13 "strconv" 14 "time" 15 ) 16 17 type routerConfigXMLProperty struct { 18 XMLName xml.Name `xml:"property"` 19 Id string `xml:"id,attr"` 20 Value string `xml:"value,attr"` 21 } 22 23 type routerConfigXML struct { 24 XMLName xml.Name `xml:"property-config"` 25 Properties []routerConfigXMLProperty `xml:"property"` 26 } 27 28 type catRouterConfig struct { 29 scheduleMixin 30 sample float64 31 routers []serverAddress 32 current *serverAddress 33 ticker *time.Ticker 34 } 35 36 var router = catRouterConfig{ 37 scheduleMixin: makeScheduleMixedIn(signalRouterExit), 38 sample: 1.0, 39 routers: make([]serverAddress, 0), 40 ticker: nil, 41 } 42 43 func (c *catRouterConfig) GetName() string { 44 return "Router" 45 } 46 47 func (c *catRouterConfig) updateRouterConfig() { 48 var query = url.Values{} 49 query.Add("env", config.env) 50 query.Add("domain", config.domain) 51 query.Add("ip", config.ip) 52 query.Add("hostname", config.hostname) 53 query.Add("op", "xml") 54 55 u := url.URL{ 56 Scheme: "http", 57 Path: "/cat/s/router", 58 RawQuery: query.Encode(), 59 } 60 61 client := http.Client{ 62 Timeout: 10 * time.Second, 63 } 64 65 for _, server := range config.httpServerAddresses { 66 u.Host = fmt.Sprintf("%s:%d", server.host, config.httpServerPort) 67 logger.Info("Getting router config from %s", u.String()) 68 69 resp, err := client.Get(u.String()) 70 if err != nil { 71 logger.Warning("Error occurred while getting router config from url %s, with err [%v]", u.String(), err) 72 continue 73 } 74 75 c.parse(resp.Body) 76 return 77 } 78 79 logger.Error("Can't get router config from remote server.") 80 return 81 } 82 83 func (c *catRouterConfig) handle(signal int) { 84 switch signal { 85 case signalResetConnection: 86 logger.Warning("Connection has been reset, reconnecting.") 87 c.current = nil 88 c.updateRouterConfig() 89 default: 90 c.scheduleMixin.handle(signal) 91 } 92 } 93 94 func (c *catRouterConfig) afterStart() { 95 c.ticker = time.NewTicker(time.Minute * 3) 96 c.updateRouterConfig() 97 } 98 99 func (c *catRouterConfig) beforeStop() { 100 c.ticker.Stop() 101 } 102 103 func (c *catRouterConfig) process() { 104 select { 105 case sig := <-c.signals: 106 c.handle(sig) 107 case <-c.ticker.C: 108 c.updateRouterConfig() 109 } 110 } 111 112 func (c *catRouterConfig) updateSample(v string) { 113 sample, err := strconv.ParseFloat(v, 32) 114 if err != nil { 115 logger.Warning("Sample should be a valid float, %s given", v) 116 } else if math.Abs(sample-c.sample) > 1e-9 { 117 c.sample = sample 118 logger.Info("Sample rate has been set to %f%%", c.sample*100) 119 } 120 } 121 122 func (c *catRouterConfig) updateBlock(v string) { 123 if v == "false" { 124 enable() 125 } else { 126 disable() 127 } 128 } 129 130 func (c *catRouterConfig) parse(reader io.ReadCloser) { 131 bytes, err := ioutil.ReadAll(reader) 132 if err != nil { 133 return 134 } 135 136 t := new(routerConfigXML) 137 if err := xml.Unmarshal(bytes, &t); err != nil { 138 logger.Warning("Error occurred while parsing router config xml content.\n%s", string(bytes)) 139 } 140 141 for _, property := range t.Properties { 142 switch property.Id { 143 case propertySample: 144 c.updateSample(property.Value) 145 case propertyRouters: 146 c.updateRouters(property.Value) 147 case propertyBlock: 148 c.updateBlock(property.Value) 149 } 150 } 151 } 152 153 func (c *catRouterConfig) updateRouters(router string) { 154 newRouters := resolveServerAddresses(router) 155 156 oldLen, newLen := len(c.routers), len(newRouters) 157 158 if newLen == 0 { 159 return 160 } else if oldLen == 0 { 161 logger.Info("Routers has been initialized to: %s", newRouters) 162 c.routers = newRouters 163 } else if oldLen != newLen { 164 logger.Info("Routers has been changed to: %s", newRouters) 165 c.routers = newRouters 166 } else { 167 for i := 0; i < oldLen; i++ { 168 if !compareServerAddress(&c.routers[i], &newRouters[i]) { 169 logger.Info("Routers has been changed to: %s", newRouters) 170 c.routers = newRouters 171 break 172 } 173 } 174 } 175 176 rander := rand.New(rand.NewSource(time.Now().UnixNano())) 177 178 l := len(newRouters) 179 for i := l - 1; i > 0; i-- { 180 r := rander.Intn(i) 181 newRouters[r], newRouters[i] = newRouters[i], newRouters[r] 182 } 183 184 for _, server := range newRouters { 185 if compareServerAddress(c.current, &server) { 186 return 187 } 188 189 addr := fmt.Sprintf("%s:%d", server.host, server.port) 190 if conn, err := net.DialTimeout("tcp", addr, time.Second); err != nil { 191 logger.Info("Failed to connect to %s, retrying...", addr) 192 } else { 193 c.current = &server 194 logger.Info("Connected to %s.", addr) 195 sender.chConn <- conn 196 return 197 } 198 } 199 200 logger.Info("Cannot established a connection to cat server.") 201 }