go-common/library/ecode/tip/tip.go

176 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package tip
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"net/url"
"strconv"
"sync/atomic"
"time"
cmcd "go-common/library/ecode"
"go-common/library/log"
xhttp "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
)
const (
_codeOk = 0
_codeNotModified = -304
_checkURL = "http://%s/x/v1/msm/codes/2"
)
var (
defualtEcodes = &ecodes{}
defaultConfig = &Config{
Domain: "api.bilibili.co",
All: xtime.Duration(time.Hour),
Diff: xtime.Duration(time.Minute * 5),
ClientConfig: &xhttp.ClientConfig{
App: &xhttp.App{
Key: "3c4e41f926e51656",
Secret: "26a2095b60c24154521d24ae62b885bb",
},
Dial: xtime.Duration(time.Second),
Timeout: xtime.Duration(time.Second),
},
}
)
// Config config.
type Config struct {
// Domain server domain
Domain string
// All get all time slice
All xtime.Duration
// Diff get diff time slice
Diff xtime.Duration
//HTTPClient httpclient config
ClientConfig *xhttp.ClientConfig
}
type ecodes struct {
codes atomic.Value
client *xhttp.Client
conf *Config
}
type res struct {
Code int `json:"code"`
Message string `json:"message"`
Data *data `json:"data"`
}
type data struct {
Ver int64
MD5 string
Code map[int]string
}
// Init init ecode.
func Init(conf *Config) {
if conf == nil {
conf = defaultConfig
} else {
panic(`请删除配置文件内无用配置perf、log、trace、report、ecode、httpServer
http://info.bilibili.co/pages/viewpage.action?pageId=3671762
`)
}
defualtEcodes.conf = conf
defualtEcodes.client = xhttp.NewClient(conf.ClientConfig)
defualtEcodes.codes.Store(make(map[int]string))
ver, _ := defualtEcodes.update(0)
go defualtEcodes.updateproc(ver)
}
func (e *ecodes) updateproc(lastVer int64) {
var (
ver int64
err error
last = time.Now()
all = time.Duration(e.conf.All)
diff = time.Duration(e.conf.Diff)
)
if e.conf.All == 0 {
all = time.Hour
}
if e.conf.Diff == 0 {
diff = 5 * time.Minute
}
time.Sleep(diff)
for {
cur := time.Now()
if cur.Sub(last) > all {
if ver, err = e.update(0); err != nil {
log.Error("e.update() error(%v)", err)
time.Sleep(10 * time.Second)
continue
}
last = cur
} else {
if ver, err = e.update(lastVer); err != nil {
log.Error("e.update(%d) error(%v)", lastVer, err)
time.Sleep(10 * time.Second)
continue
}
}
lastVer = ver
time.Sleep(diff)
}
}
func (e *ecodes) update(ver int64) (lver int64, err error) {
var (
res = &res{}
bytes []byte
params = url.Values{}
)
params.Set("ver", strconv.FormatInt(ver, 10))
if err = e.client.Get(context.TODO(), fmt.Sprintf(_checkURL, e.conf.Domain), "", params, &res); err != nil {
err = fmt.Errorf("e.client.Get(%v) error(%v)", fmt.Sprintf(_checkURL, e.conf.Domain), err)
return
}
switch res.Code {
case _codeOk:
if res.Data == nil {
err = fmt.Errorf("code get() response error result: %v", res)
return
}
case _codeNotModified:
return ver, nil
default:
err = cmcd.Int(res.Code)
return
}
if bytes, err = json.Marshal(res.Data.Code); err != nil {
return
}
mb := md5.Sum(bytes)
if res.Data.MD5 != hex.EncodeToString(mb[:]) {
err = fmt.Errorf("get codes fail,error md5")
return
}
oCodes, ok := e.codes.Load().(map[int]string)
if !ok {
return
}
nCodes := copy(oCodes)
for k, v := range res.Data.Code {
nCodes[k] = v
}
cmcd.Register(nCodes)
e.codes.Store(nCodes)
return res.Data.Ver, nil
}
func copy(src map[int]string) (dst map[int]string) {
dst = make(map[int]string)
for k1, v1 := range src {
dst[k1] = v1
}
return
}