Files
jx-callback/business/jxutils/tasks/configrefresh.go
2020-08-12 14:27:23 +08:00

371 lines
12 KiB
Go

package tasks
import (
"fmt"
"io/ioutil"
"net/http"
"time"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/jx-callback/business/jxutils/eventhub/syseventhub"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
"git.rosy.net.cn/baseapi/platformapi/yilianyunapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
const (
weixinTokenExpires = 7200 * time.Second
dingdingTokenExpires = 7200 * time.Second
weimobTokenExpires = 7200 * time.Second
yilianyunTokenExpires = 30 * 24 * 3600 * time.Second
maxRefreshGap = 5 * 60 * time.Second
errRefreshGap = 10 * time.Second
minRefreshGap = 1 * time.Second
)
type CallResult struct {
Code string `json:"code"`
Desc string `json:"desc"`
Data string `json:"data"`
}
func RefreshConfig(configKey string, expiresTime time.Duration, configGetter func() (string, string), configSetter func(value string)) error {
needRefreshGap := expiresTime * 8 / 10
sleepGap := expiresTime / 10
if sleepGap > maxRefreshGap {
sleepGap = maxRefreshGap
}
refreshFunc := func() (sleepDuration time.Duration) {
sleepDuration = sleepGap
curConfig := &legacymodel.Config{
Thirdparty: configKey,
}
db := orm.NewOrm()
// 0: don't refresh, 1 update, 2 insert
handleType := 0
if err := db.Read(curConfig, "Thirdparty"); err != nil {
if err != orm.ErrNoRows {
globals.SugarLogger.Errorf("db error:%v, curConfig:%v", err, curConfig)
return errRefreshGap
}
handleType = 2
} else {
configSetter(curConfig.Token)
if curConfig.Date <= utils.Time2Str(time.Now().Add(-needRefreshGap)) {
handleType = 1
}
}
if handleType != 0 {
if curConfig.Token, curConfig.Date = configGetter(); curConfig.Token == "" {
if globals.IsProductEnv() {
globals.SugarLogger.Infof("RefreshConfig %s get empty token", configKey)
sleepDuration = errRefreshGap
} else {
globals.SugarLogger.Infof("RefreshConfig %s get empty token", configKey)
}
return sleepDuration
}
configSetter(curConfig.Token)
if curConfig.Date == "" {
curConfig.Date = utils.GetCurTimeStr()
} else {
sleepDuration = expiresTime - time.Now().Sub(utils.Str2Time(curConfig.Date))
}
var num int64
var err error
if handleType == 1 {
num, err = db.Update(curConfig, "Token", "Date")
} else {
num, err = db.Insert(curConfig)
}
if err != nil || num == 0 {
globals.SugarLogger.Errorf("db error:%v, num:%d, curConfig:%v", err, num, curConfig)
}
}
if sleepDuration < minRefreshGap {
sleepDuration = minRefreshGap
} else if sleepDuration > maxRefreshGap {
sleepDuration = maxRefreshGap
}
return sleepDuration
}
utils.CallFuncAsync(func() {
for {
sleepGap := refreshFunc()
time.Sleep(sleepGap)
}
})
return nil
}
func RefreshWeixinToken() (err error) {
if api.WeixinAPI != nil {
err = RefreshConfig("wechat", weixinTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshWeixinToken RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() {
if tokenInfo, err := api.WeixinAPI.CBRetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshWeixinToken tokenInfo:%s", utils.Format4Output(tokenInfo, true))
token = tokenInfo.AccessToken
} else {
globals.SugarLogger.Errorf("RefreshWeixinToken RefreshToken failed with error:%v", err)
}
} else {
if tokenInfo := getWXTokenFromRemote(api.WeixinAPI.CBGetToken()); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-weixinTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
globals.SugarLogger.Debugf("RefreshWeixinToken setter value:%s", value)
syseventhub.SysEventHub.OnNewWXToken(value)
api.WeixinAPI.CBSetToken(value)
})
}
return err
}
func RefreshWeixin2Token() (err error) {
if api.WeixinMiniAPI2 != nil {
err = RefreshConfig("wechat2", weixinTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshWeixin2Token RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() {
if tokenInfo, err := api.WeixinMiniAPI2.CBRetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshWeixin2Token tokenInfo:%s", utils.Format4Output(tokenInfo, true))
token = tokenInfo.AccessToken
} else {
globals.SugarLogger.Errorf("RefreshWeixin2Token RefreshToken failed with error:%v", err)
}
} else {
if tokenInfo := getWX2TokenFromRemote(api.WeixinMiniAPI2.CBGetToken()); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-weixinTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
globals.SugarLogger.Debugf("RefreshWeixinToken setter value:%s", value)
syseventhub.SysEventHub.OnNewWX2Token(value)
api.WeixinMiniAPI2.CBSetToken(value)
})
}
return err
}
func RefreshWeixin3Token() (err error) {
if api.WeixinMiniAPI3 != nil {
err = RefreshConfig("wechat3", weixinTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshWeixin3Token RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() {
if tokenInfo, err := api.WeixinMiniAPI3.CBRetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshWeixin3Token tokenInfo:%s", utils.Format4Output(tokenInfo, true))
token = tokenInfo.AccessToken
} else {
globals.SugarLogger.Errorf("RefreshWeixin3Token RefreshToken failed with error:%v", err)
}
} else {
if tokenInfo := getWX3TokenFromRemote(api.WeixinMiniAPI3.CBGetToken()); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-weixinTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
globals.SugarLogger.Debugf("RefreshWeixinToken setter value:%s", value)
syseventhub.SysEventHub.OnNewWX3Token(value)
api.WeixinMiniAPI3.CBSetToken(value)
})
}
return err
}
func RefreshWeimobToken() (err error) {
if api.WeimobAPI != nil {
err = RefreshConfig("weimob", weimobTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshWeimobToken RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() {
if tokenInfo, err := api.WeimobAPI.RefreshTokenByRefreshToken(); err == nil {
return string(utils.MustMarshal(tokenInfo)), utils.Time2Str(time.Now().Add((time.Duration(tokenInfo.ExpiresIn) - weimobTokenExpires/time.Second) * time.Second))
} else {
globals.SugarLogger.Debugf("RefreshWeimobToken err:%s", err)
}
} else {
curToken := ""
if tokenInfo := api.WeimobAPI.GetToken(); tokenInfo != nil {
curToken = string(utils.MustMarshal(tokenInfo))
}
if tokenInfo := getWeimobTokenFromRemote(curToken); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-weimobTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
var tokenInfo *weimobapi.TokenInfo
err := utils.UnmarshalUseNumber([]byte(value), &tokenInfo)
if err == nil {
syseventhub.SysEventHub.OnNewWeimobToken(string(utils.MustMarshal(tokenInfo)))
api.WeimobAPI.SetToken(tokenInfo)
}
})
}
return err
}
func RefreshDingDingToken() (err error) {
api.DingDingAPI.RetrieveToken()
return RefreshConfig("dingding", dingdingTokenExpires, func() (string, string) {
globals.SugarLogger.Debugf("RefreshDingDingToken RunMode:%s", beego.BConfig.RunMode)
if true { //globals.IsProductEnv() {
if token, err := api.DingDingAPI.RetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshDingDingToken tokenInfo:%s", token)
return token, ""
} else {
globals.SugarLogger.Errorf("RefreshDingDingToken RefreshToken failed with error:%v", err)
}
}
return "", ""
}, func(value string) {
api.DingDingAPI.SetToken(value)
})
}
func SaveWeimobToken(token *weimobapi.TokenInfo) (err error) {
db := dao.GetDB()
config := &legacymodel.Config{
Thirdparty: "weimob",
Token: string(utils.MustMarshal(token)),
Date: utils.Time2Str(time.Now().Add((time.Duration(token.ExpiresIn) - weimobTokenExpires/time.Second) * time.Second)),
LastOperator: model.AdminName,
}
return dao.CreateOrUpdate(db, config)
}
func RefreshYilianyunToken() (err error) {
return RefreshConfig("yilianyun", yilianyunTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshYilianyunToken RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() { // 只有京西菜市刷新易联云key
if tokenInfo, err := api.YilianyunAPI.RetrieveToken(); err == nil {
token = string(utils.MustMarshal(tokenInfo))
} else {
globals.SugarLogger.Errorf("RefreshYilianyunToken RefreshToken failed with error:%v", err)
}
} else {
if tokenInfo := getYLYTokenFromRemote(api.YilianyunAPI.GetToken()); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-yilianyunTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
token := value
var tokenInfo *yilianyunapi.TokenInfo
if err := utils.TryUnmarshalUseNumber([]byte(value), &tokenInfo); err == nil {
token = tokenInfo.AccessToken
}
syseventhub.SysEventHub.OnNewYLYToken(token)
api.YilianyunAPI.SetToken(token)
})
}
func PollingRemotEvent(remoteURL string, waitSecond int, params map[string]interface{}) (tokenInfo *syseventhub.TokenInfo) {
if waitSecond == 0 {
waitSecond = 5 * 60
}
params2 := utils.MergeMaps(params, map[string]interface{}{
"accessKey": globals.GetWeixinTokenKey,
"waitSecond": waitSecond,
})
for {
globals.SugarLogger.Debugf("PollingRemotEvent %s", remoteURL)
response, err := http.Get(utils.GenerateGetURL(remoteURL, "", params2))
globals.SugarLogger.Debugf("PollingRemotEvent2 %s error:%v", remoteURL, err)
if err == nil {
defer response.Body.Close()
if response.StatusCode == http.StatusOK {
data, err2 := ioutil.ReadAll(response.Body)
if err = err2; err == nil {
var result CallResult
if err = utils.UnmarshalUseNumber(data, &result); err == nil {
if result.Code == "0" {
if result.Data != "" {
if err = utils.UnmarshalUseNumber([]byte(result.Data), &tokenInfo); err == nil && tokenInfo != nil {
globals.SugarLogger.Debugf("PollingRemotEvent %s:%s", remoteURL, utils.Format4Output(tokenInfo, false))
break
}
}
} else {
err = fmt.Errorf("PollingRemotEvent %s return code is:%s", remoteURL, result.Code)
}
}
}
} else {
err = platformapi.ErrHTTPCodeIsNot200
}
}
globals.SugarLogger.Infof("PollingRemotEvent %s failed with error:%v", remoteURL, err)
if err != nil {
time.Sleep(errRefreshGap)
}
}
return tokenInfo
}
func getWXTokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) {
if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetWeixinTokenURL != "" {
tokenInfo = PollingRemotEvent(globals.GetWeixinTokenURL, 0, map[string]interface{}{
"oldToken": oldToken,
})
}
return tokenInfo
}
func getWX2TokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) {
if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetWeixinTokenURL != "" {
tokenInfo = PollingRemotEvent(globals.GetWeixinTokenURL, 0, map[string]interface{}{
"oldToken": oldToken,
})
}
return tokenInfo
}
func getWX3TokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) {
if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetWeixinTokenURL != "" {
tokenInfo = PollingRemotEvent(globals.GetWeixinTokenURL, 0, map[string]interface{}{
"oldToken": oldToken,
})
}
return tokenInfo
}
func getYLYTokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) {
if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetYLYTokenURL != "" {
tokenInfo = PollingRemotEvent(globals.GetYLYTokenURL, 0, map[string]interface{}{
"oldToken": oldToken,
})
}
return tokenInfo
}
func getWeimobTokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) {
if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetWeimobTokenURL != "" {
tokenInfo = PollingRemotEvent(globals.GetWeimobTokenURL, 0, map[string]interface{}{
"oldToken": oldToken,
})
}
return tokenInfo
}