436 lines
9.3 KiB
Go
436 lines
9.3 KiB
Go
|
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)
|
||
|
}
|