123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- package conf
- import (
- "bytes"
- "crypto/md5"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "path"
- "strings"
- "time"
- "go-common/library/ecode"
- "go-common/library/log"
- )
- const (
- // api
- _apiGet1 = "http://%s/config/v2/get?%s"
- _apiCheck1 = "http://%s/config/v2/check?%s"
- _apiCreate = "http://%s/config/v2/create"
- _apiUpdate = "http://%s/config/v2/update"
- _apiConfIng = "http://%s/config/v2/config/ing?%s"
- )
- type version1 struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data *ver `json:"data"`
- }
- type ver struct {
- Version int64 `json:"version"`
- Diffs []int64 `json:"diffs"`
- }
- type confIng struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data *Value `json:"data"`
- }
- type res struct {
- Code int `json:"code"`
- Message string `json:"message"`
- }
- //Value value.
- type Value struct {
- CID int64 `json:"cid"`
- Name string `json:"name"`
- Config string `json:"config"`
- }
- // Toml2 return config value.
- func (c *Client) Toml2() (cf string, ok bool) {
- var (
- m map[string]*Value
- val *Value
- )
- if m, ok = c.data.Load().(map[string]*Value); !ok {
- return
- }
- if val, ok = m[commonKey]; !ok {
- return
- }
- cf = val.Config
- return
- }
- // Value2 return config value.
- func (c *Client) Value2(key string) (cf string, ok bool) {
- var (
- m map[string]*Value
- val *Value
- )
- if m, ok = c.data.Load().(map[string]*Value); !ok {
- return
- }
- if val, ok = m[key]; !ok {
- return
- }
- cf = val.Config
- return
- }
- // init check local config is ok
- func (c *Client) init2() (err error) {
- var v *ver
- c.data.Store(make(map[string]*Value))
- if v, err = c.checkVersion2(&ver{Version: _unknownVersion}); err != nil {
- fmt.Printf("get remote version error(%v)\n", err)
- return
- }
- for i := 0; i < 3; i++ {
- if v.Version == _unknownVersion {
- fmt.Println("get null version")
- return
- }
- if err = c.download2(v, true); err == nil {
- return
- }
- fmt.Printf("retry times: %d, c.download() error(%v)\n", i, err)
- time.Sleep(_retryInterval)
- }
- return
- }
- func (c *Client) updateproc2() (err error) {
- var ver *ver
- for {
- time.Sleep(_retryInterval)
- if ver, err = c.checkVersion2(c.diff); err != nil {
- log.Error("c.checkVersion(%d) error(%v)", c.ver, err)
- continue
- } else if ver.Version == c.diff.Version {
- continue
- }
- if err = c.download2(ver, false); err != nil {
- log.Error("c.download() error(%s)", err)
- continue
- }
- }
- }
- // download download config from config service
- func (c *Client) download2(ver *ver, isFirst bool) (err error) {
- var (
- d *data
- tmp []*Value
- oConfs, confs map[string]*Value
- buf = new(bytes.Buffer)
- ok bool
- )
- if d, err = c.getConfig2(ver); err != nil {
- return
- }
- bs := []byte(d.Content)
- // md5 file
- if mh := md5.Sum(bs); hex.EncodeToString(mh[:]) != d.Md5 {
- err = fmt.Errorf("md5 mismatch, local:%s, remote:%s", hex.EncodeToString(mh[:]), d.Md5)
- return
- }
- // write conf
- if err = json.Unmarshal(bs, &tmp); err != nil {
- return
- }
- confs = make(map[string]*Value)
- if oConfs, ok = c.data.Load().(map[string]*Value); ok {
- for k, v := range oConfs {
- confs[k] = v
- }
- }
- for _, v := range tmp {
- if err = ioutil.WriteFile(path.Join(conf.Path, v.Name), []byte(v.Config), 0644); err != nil {
- return
- }
- confs[v.Name] = v
- }
- for _, v := range confs {
- if strings.Contains(v.Name, ".toml") {
- buf.WriteString(v.Config)
- buf.WriteString("\n")
- }
- }
- confs[commonKey] = &Value{Config: buf.String()}
- // update current version
- c.diff = ver
- c.data.Store(confs)
- if isFirst {
- return
- }
- for _, v := range tmp {
- if c.watchAll {
- c.event <- v.Name
- continue
- }
- if c.watchFile == nil {
- continue
- }
- if _, ok := c.watchFile[v.Name]; ok {
- c.event <- v.Name
- }
- }
- return
- }
- // poll config server
- func (c *Client) checkVersion2(reqVer *ver) (ver *ver, err error) {
- var (
- url string
- req *http.Request
- resp *http.Response
- rb []byte
- )
- if url, err = c.makeURL2(_apiCheck1, reqVer); err != nil {
- err = fmt.Errorf("checkVersion() c.makeUrl() error url empty")
- return
- }
- // http
- if req, err = http.NewRequest("GET", url, nil); err != nil {
- return
- }
- if resp, err = c.httpCli.Do(req); err != nil {
- return
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- err = fmt.Errorf("checkVersion() http error url(%s) status: %d", url, resp.StatusCode)
- return
- }
- // ok
- if rb, err = ioutil.ReadAll(resp.Body); err != nil {
- return
- }
- v := &version1{}
- if err = json.Unmarshal(rb, v); err != nil {
- return
- }
- switch v.Code {
- case _codeOk:
- if v.Data == nil {
- err = fmt.Errorf("checkVersion() response error result: %v", v)
- return
- }
- ver = v.Data
- case _codeNotModified:
- ver = reqVer
- default:
- err = fmt.Errorf("checkVersion() response error result: %v", v)
- }
- return
- }
- // updateVersion update config version
- func (c *Client) getConfig2(ver *ver) (data *data, err error) {
- var (
- url string
- req *http.Request
- resp *http.Response
- rb []byte
- res = &result{}
- )
- if url, err = c.makeURL2(_apiGet1, ver); err != nil {
- err = fmt.Errorf("getConfig() c.makeUrl() error url empty")
- return
- }
- // http
- if req, err = http.NewRequest("GET", url, nil); err != nil {
- return
- }
- if resp, err = c.httpCli.Do(req); err != nil {
- return
- }
- defer resp.Body.Close()
- // ok
- if resp.StatusCode != http.StatusOK {
- err = fmt.Errorf("getConfig() http error url(%s) status: %d", url, resp.StatusCode)
- return
- }
- if rb, err = ioutil.ReadAll(resp.Body); err != nil {
- return
- }
- if err = json.Unmarshal(rb, res); err != nil {
- return
- }
- switch res.Code {
- case _codeOk:
- // has new config
- if res.Data == nil {
- err = fmt.Errorf("getConfig() response error result: %v", res)
- return
- }
- data = res.Data
- default:
- err = fmt.Errorf("getConfig() response error result: %v", res)
- }
- return
- }
- // makeUrl signed url
- func (c *Client) makeURL2(api string, ver *ver) (query string, err error) {
- var ids []byte
- params := url.Values{}
- // service
- params.Set("service", service())
- params.Set("hostname", conf.Host)
- params.Set("build", conf.Ver)
- params.Set("version", fmt.Sprint(ver.Version))
- if ids, err = json.Marshal(ver.Diffs); err != nil {
- return
- }
- params.Set("ids", string(ids))
- params.Set("ip", localIP())
- params.Set("token", conf.Token)
- params.Set("appoint", conf.Appoint)
- params.Set("customize", c.customize)
- // api
- query = fmt.Sprintf(api, conf.Addr, params.Encode())
- return
- }
- //Create create.
- func (c *Client) Create(name, content, operator, mark string) (err error) {
- var (
- resp *http.Response
- rb []byte
- res = &res{}
- )
- params := url.Values{}
- params.Set("service", service())
- params.Set("name", name)
- params.Set("content", content)
- params.Set("operator", operator)
- params.Set("mark", mark)
- params.Set("token", conf.Token)
- if resp, err = c.httpCli.PostForm(fmt.Sprintf(_apiCreate, conf.Addr), params); err != nil {
- return
- }
- defer resp.Body.Close()
- // ok
- if resp.StatusCode != http.StatusOK {
- err = fmt.Errorf("Create() http error url(%s) status: %d", fmt.Sprintf(_apiCreate, conf.Addr), resp.StatusCode)
- return
- }
- if rb, err = ioutil.ReadAll(resp.Body); err != nil {
- return
- }
- if err = json.Unmarshal(rb, res); err != nil {
- return
- }
- if res.Code != ecode.OK.Code() {
- err = ecode.Int(res.Code)
- }
- return
- }
- //Update update.
- func (c *Client) Update(ID int64, content, operator, mark string) (err error) {
- var (
- resp *http.Response
- rb []byte
- res = &result{}
- )
- params := url.Values{}
- params.Set("conf_id", fmt.Sprintf("%d", ID))
- params.Set("content", content)
- params.Set("operator", operator)
- params.Set("mark", mark)
- params.Set("service", service())
- params.Set("token", conf.Token)
- if resp, err = c.httpCli.PostForm(fmt.Sprintf(_apiUpdate, conf.Addr), params); err != nil {
- return
- }
- defer resp.Body.Close()
- // ok
- if resp.StatusCode != http.StatusOK {
- err = fmt.Errorf("Update() http error url(%s) status: %d", fmt.Sprintf(_apiUpdate, conf.Addr), resp.StatusCode)
- return
- }
- if rb, err = ioutil.ReadAll(resp.Body); err != nil {
- return
- }
- if err = json.Unmarshal(rb, res); err != nil {
- return
- }
- if res.Code != ecode.OK.Code() {
- err = ecode.Int(res.Code)
- }
- return
- }
- //ConfIng confIng.
- func (c *Client) ConfIng(name string) (v *Value, err error) {
- var (
- req *http.Request
- resp *http.Response
- rb []byte
- res = &confIng{}
- )
- params := url.Values{}
- params.Set("name", name)
- params.Set("service", service())
- params.Set("token", conf.Token)
- // http
- if req, err = http.NewRequest("GET", fmt.Sprintf(_apiConfIng, conf.Addr, params.Encode()), nil); err != nil {
- return
- }
- if resp, err = c.httpCli.Do(req); err != nil {
- return
- }
- defer resp.Body.Close()
- // ok
- if resp.StatusCode != http.StatusOK {
- err = fmt.Errorf("ConfIng() http error url(%s) status: %d", _apiCreate, resp.StatusCode)
- return
- }
- if rb, err = ioutil.ReadAll(resp.Body); err != nil {
- return
- }
- if err = json.Unmarshal(rb, res); err != nil {
- return
- }
- if res.Code != ecode.OK.Code() {
- err = ecode.Int(res.Code)
- return
- }
- v = res.Data
- return
- }
- //Configs configs.
- func (c *Client) Configs() (confs []*Value, ok bool) {
- var (
- m map[string]*Value
- )
- if m, ok = c.data.Load().(map[string]*Value); !ok {
- return
- }
- for _, v := range m {
- if v.CID == 0 {
- continue
- }
- confs = append(confs, v)
- }
- return
- }
- func service() string {
- return fmt.Sprintf("%s_%s_%s", conf.TreeID, conf.DeployEnv, conf.Zone)
- }
|