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  }