tip.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package tip
  2. import (
  3. "context"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "encoding/json"
  7. "fmt"
  8. "net/url"
  9. "strconv"
  10. "sync/atomic"
  11. "time"
  12. cmcd "go-common/library/ecode"
  13. "go-common/library/log"
  14. xhttp "go-common/library/net/http/blademaster"
  15. xtime "go-common/library/time"
  16. )
  17. const (
  18. _codeOk = 0
  19. _codeNotModified = -304
  20. _checkURL = "http://%s/x/v1/msm/codes/2"
  21. )
  22. var (
  23. defualtEcodes = &ecodes{}
  24. defaultConfig = &Config{
  25. Domain: "api.bilibili.co",
  26. All: xtime.Duration(time.Hour),
  27. Diff: xtime.Duration(time.Minute * 5),
  28. ClientConfig: &xhttp.ClientConfig{
  29. App: &xhttp.App{
  30. Key: "3c4e41f926e51656",
  31. Secret: "26a2095b60c24154521d24ae62b885bb",
  32. },
  33. Dial: xtime.Duration(time.Second),
  34. Timeout: xtime.Duration(time.Second),
  35. },
  36. }
  37. )
  38. // Config config.
  39. type Config struct {
  40. // Domain server domain
  41. Domain string
  42. // All get all time slice
  43. All xtime.Duration
  44. // Diff get diff time slice
  45. Diff xtime.Duration
  46. //HTTPClient httpclient config
  47. ClientConfig *xhttp.ClientConfig
  48. }
  49. type ecodes struct {
  50. codes atomic.Value
  51. client *xhttp.Client
  52. conf *Config
  53. }
  54. type res struct {
  55. Code int `json:"code"`
  56. Message string `json:"message"`
  57. Data *data `json:"data"`
  58. }
  59. type data struct {
  60. Ver int64
  61. MD5 string
  62. Code map[int]string
  63. }
  64. // Init init ecode.
  65. func Init(conf *Config) {
  66. if conf == nil {
  67. conf = defaultConfig
  68. } else {
  69. panic(`请删除配置文件内无用配置!!!perf、log、trace、report、ecode、httpServer
  70. http://info.bilibili.co/pages/viewpage.action?pageId=3671762
  71. `)
  72. }
  73. defualtEcodes.conf = conf
  74. defualtEcodes.client = xhttp.NewClient(conf.ClientConfig)
  75. defualtEcodes.codes.Store(make(map[int]string))
  76. ver, _ := defualtEcodes.update(0)
  77. go defualtEcodes.updateproc(ver)
  78. }
  79. func (e *ecodes) updateproc(lastVer int64) {
  80. var (
  81. ver int64
  82. err error
  83. last = time.Now()
  84. all = time.Duration(e.conf.All)
  85. diff = time.Duration(e.conf.Diff)
  86. )
  87. if e.conf.All == 0 {
  88. all = time.Hour
  89. }
  90. if e.conf.Diff == 0 {
  91. diff = 5 * time.Minute
  92. }
  93. time.Sleep(diff)
  94. for {
  95. cur := time.Now()
  96. if cur.Sub(last) > all {
  97. if ver, err = e.update(0); err != nil {
  98. log.Error("e.update() error(%v)", err)
  99. time.Sleep(10 * time.Second)
  100. continue
  101. }
  102. last = cur
  103. } else {
  104. if ver, err = e.update(lastVer); err != nil {
  105. log.Error("e.update(%d) error(%v)", lastVer, err)
  106. time.Sleep(10 * time.Second)
  107. continue
  108. }
  109. }
  110. lastVer = ver
  111. time.Sleep(diff)
  112. }
  113. }
  114. func (e *ecodes) update(ver int64) (lver int64, err error) {
  115. var (
  116. res = &res{}
  117. bytes []byte
  118. params = url.Values{}
  119. )
  120. params.Set("ver", strconv.FormatInt(ver, 10))
  121. if err = e.client.Get(context.TODO(), fmt.Sprintf(_checkURL, e.conf.Domain), "", params, &res); err != nil {
  122. err = fmt.Errorf("e.client.Get(%v) error(%v)", fmt.Sprintf(_checkURL, e.conf.Domain), err)
  123. return
  124. }
  125. switch res.Code {
  126. case _codeOk:
  127. if res.Data == nil {
  128. err = fmt.Errorf("code get() response error result: %v", res)
  129. return
  130. }
  131. case _codeNotModified:
  132. return ver, nil
  133. default:
  134. err = cmcd.Int(res.Code)
  135. return
  136. }
  137. if bytes, err = json.Marshal(res.Data.Code); err != nil {
  138. return
  139. }
  140. mb := md5.Sum(bytes)
  141. if res.Data.MD5 != hex.EncodeToString(mb[:]) {
  142. err = fmt.Errorf("get codes fail,error md5")
  143. return
  144. }
  145. oCodes, ok := e.codes.Load().(map[int]string)
  146. if !ok {
  147. return
  148. }
  149. nCodes := copy(oCodes)
  150. for k, v := range res.Data.Code {
  151. nCodes[k] = v
  152. }
  153. cmcd.Register(nCodes)
  154. e.codes.Store(nCodes)
  155. return res.Data.Ver, nil
  156. }
  157. func copy(src map[int]string) (dst map[int]string) {
  158. dst = make(map[int]string)
  159. for k1, v1 := range src {
  160. dst[k1] = v1
  161. }
  162. return
  163. }