bilibili-backup/library/ecode/tip/tip.go
2019-04-22 02:59:20 +00:00

176 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}