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/client/orm" beego "github.com/astaxie/beego/server/web" ) const ( weixinTokenExpires = 7200 * time.Second dingdingTokenExpires = 7200 * time.Second weimobTokenExpires = 7200 * time.Second yilianyunTokenExpires = 30 * 24 * 3600 * time.Second pushTokenExpires = 7200 * time.Second fnTokenExpires = 1 * time.Hour tiktokTokenExpires = 14 * 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, string), configSetter func(value, value2 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 { return errRefreshGap } handleType = 2 } else { configSetter(curConfig.Token, curConfig.RefreshToken) if curConfig.Date <= utils.Time2Str(time.Now().Add(-needRefreshGap)) { handleType = 1 } } if handleType != 0 { if curConfig.Token, curConfig.Date, curConfig.RefreshToken = configGetter(); curConfig.Token == "" { if globals.IsProductEnv() { sleepDuration = errRefreshGap } else { globals.SugarLogger.Infof("RefreshConfig %s get empty token", configKey) } return sleepDuration } configSetter(curConfig.Token, curConfig.RefreshToken) 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", "RefreshToken") } 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, invalidParameter string) { if globals.IsMainProductEnv() { if tokenInfo, err := api.WeixinAPI.CBRetrieveToken(); err == nil { 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, v2 string) { syseventhub.SysEventHub.OnNewWXToken(value) api.WeixinAPI.CBSetToken(value) }) } return err } func RefreshFnToken() (err error) { if api.FnAPI != nil { err = RefreshConfig("fn", fnTokenExpires, func() (token string, expireTimeStr string, refreshToken string) { //if globals.IsMainProductEnv() { curConfig := &legacymodel.Config{ Thirdparty: "fn", } if err := orm.NewOrm().Read(curConfig, "Thirdparty"); err != nil { globals.SugarLogger.Errorf("RefreshFnToken RefreshToken failed with error:%v", err) } api.FnAPI.SetToken(curConfig.Token) api.FnAPI.SetRefreshToken(curConfig.RefreshToken) if tokenInfo, err := api.FnAPI.GetAccessToken(); err == nil { token = tokenInfo.BusinessDataObj.AccessToken refreshToken = tokenInfo.BusinessDataObj.RefreshToken } else { globals.SugarLogger.Errorf("RefreshFnToken RefreshToken failed with error:%v", err) } sql := `UPDATE config SET token = ?,refresh_token = ? WHERE thirdparty = ?` dao.ExecuteSQL(dao.GetDB(), sql, []interface{}{ token, refreshToken, "fn", }) //} if beego.BConfig.RunMode == "jxgy" { config := &legacymodel.Config{} sql := `SELECT * FROM config WHERE thirdparty = 'fn'` if err := dao.GetRow(dao.GetDB(), &config, sql, nil); err == nil { token = config.Token } } return token, expireTimeStr, refreshToken }, func(value, v2 string) { api.FnAPI.SetToken(value) api.FnAPI.SetRefreshToken(v2) }) } return err } func RefreshQywxToken() (err error) { if api.QywxAPI != nil { err = RefreshConfig("qywx", weixinTokenExpires, func() (token string, expireTimeStr string, invalidParameter string) { if globals.IsMainProductEnv() { if tokenInfo, err := api.QywxAPI.GetToken(); err == nil { token = tokenInfo } else { globals.SugarLogger.Errorf("RefreshQywxToken RefreshToken failed with error:%v", err) } } return token, expireTimeStr, "" }, func(value, v2 string) { api.QywxAPI.SetToken(value) }) } return err } func RefreshWeixin2Token() (err error) { if api.WeixinMiniAPI2 != nil { err = RefreshConfig("wechat2", weixinTokenExpires, func() (token string, expireTimeStr string, invalidParameter string) { if globals.IsMainProductEnv() { if tokenInfo, err := api.WeixinMiniAPI2.CBRetrieveToken(); err == nil { 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, v2 string) { syseventhub.SysEventHub.OnNewWX2Token(value) api.WeixinMiniAPI2.CBSetToken(value) }) } return err } func RefreshPushToken() (err error) { if api.PushAPI != nil { err = RefreshConfig("push", pushTokenExpires, func() (token string, expireTimeStr string, invalidParameter string) { if globals.IsMainProductEnv() { if tokenInfo, err := api.PushAPI.CBRetrieveToken(); err == nil { token = tokenInfo.Token } else { globals.SugarLogger.Errorf("RefreshPushToken RefreshToken failed with error:%v", err) } } else { if tokenInfo := getPushTokenFromRemote(api.PushAPI.CBGetToken()); tokenInfo != nil { expireTimeStr = utils.Time2Str(time.Now().Add(-pushTokenExpires)) token = tokenInfo.Token } } return token, expireTimeStr, "" }, func(value, v2 string) { syseventhub.SysEventHub.OnNewPushToken(value) api.PushAPI.CBSetToken(value) }) } return err } func RefreshWeixin3Token() (err error) { // if api.WeixinMiniAPI3 != nil { // err = RefreshConfig("wechat3", weixinTokenExpires, func() (token string, expireTimeStr string) { // if globals.IsMainProductEnv() { // if tokenInfo, err := api.WeixinMiniAPI3.CBRetrieveToken(); err == nil { // 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) { // 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, invalidParameter string) { 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, v2 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, string) { if true { //globals.IsProductEnv() { if token, err := api.DingDingAPI.RetrieveToken(); err == nil { return token, "", "" } else { globals.SugarLogger.Errorf("RefreshDingDingToken RefreshToken failed with error:%v", err) } } return "", "", "" }, func(value, v2 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, invalidParameter string) { 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, v2 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 { response, err := http.Get(utils.GenerateGetURL(remoteURL, "", params2)) 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 { break } } } else { err = fmt.Errorf("PollingRemotEvent %s return code is:%s", remoteURL, result.Code) } } } } else { err = platformapi.ErrHTTPCodeIsNot200 } } 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 getPushTokenFromRemote(oldToken string) (tokenInfo *syseventhub.TokenInfo) { if !globals.IsMainProductEnv() && globals.GetWeixinTokenKey != "" && globals.GetPushTokenURL != "" { tokenInfo = PollingRemotEvent(globals.GetPushTokenURL, 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 } // RefreshTiktokToken 刷新抖店token //func RefreshTiktokToken() (err error) { // if api.TiktokStore != nil { // err = RefreshConfig("tiktok", tiktokTokenExpires, func() (token string, expireTimeStr string, refreshToken string) { // curConfig := &legacymodel.Config{ // Thirdparty: "tiktok", // } // if err := orm.NewOrm().Read(curConfig, "Thirdparty"); err != nil { // globals.SugarLogger.Errorf("RefreshTiktokToken RefreshToken failed with error:%v", err) // } // if curConfig.RefreshToken == "" { // if tokenInfo, err := api.TiktokStore.CreateToken(curConfig.Token); err != nil { // globals.SugarLogger.Errorf("tiktok store get token err:%v", err) // } else { // token = tokenInfo.AccessToken // refreshToken = tokenInfo.RefreshToken // expireTimeStr = time.Unix(tokenInfo.ExpiresIn, 0).Format("2006-01-02 15:04:05") // } // } else { // expireIn, _ := time.Parse("2006-01-02 15:04:05", curConfig.Date) // if expireIn.Unix() < time.Now().Unix() { // api.TiktokStore.SetToken(curConfig.Token) // api.TiktokStore.SetRefreshToken(curConfig.RefreshToken) // if tokenInfo, err := api.TiktokStore.RefreshToken(); err == nil { // token = tokenInfo.AccessToken // refreshToken = tokenInfo.RefreshToken // expireTimeStr = time.Unix(tokenInfo.ExpiresIn, 0).Format("2006-01-02 15:04:05") // } else { // globals.SugarLogger.Errorf("RefreshTiktokToken RefreshToken failed with error:%v", err) // } // } // } // // sql := `UPDATE config SET token = ?,refresh_token = ?,data = ? WHERE thirdparty = ?` // dao.ExecuteSQL(dao.GetDB(), sql, []interface{}{ // token, refreshToken, expireTimeStr, "tiktok", // }) // return token, expireTimeStr, refreshToken // }, func(value, v2 string) { // api.TiktokStore.SetToken(value) // api.TiktokStore.SetRefreshToken(v2) // }) // } // return err //}