173 lines
5.9 KiB
Go
173 lines
5.9 KiB
Go
package versionser
|
|
|
|
import (
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common/httputil"
|
|
"91porn-server/common/localcache"
|
|
"91porn-server/common/log"
|
|
"91porn-server/models/commod"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"golang.org/x/sync/singleflight"
|
|
)
|
|
|
|
const (
|
|
versionCacheTTL = time.Minute
|
|
versionFailureCacheTTL = 10 * time.Second
|
|
versionLastSuccessTTL = 24 * time.Hour
|
|
)
|
|
|
|
var versionRequestGroup singleflight.Group
|
|
|
|
type PacketType int32
|
|
|
|
const (
|
|
PacketTypeEnterprise PacketType = 1 // 企业签
|
|
PacketTypeShop PacketType = 2 // 商店包
|
|
PacketTypeTestFlight PacketType = 3 // TF包
|
|
)
|
|
|
|
type AppAllReq struct {
|
|
AppId int32 `json:"appId" binding:"required"` // AppID
|
|
SysType string `json:"sysType,omitempty"` // 终端类型
|
|
PktType PacketType `json:"pktType,omitempty"` // 包类型
|
|
CurVersion string `json:"curVersion,omitempty"` // 当前版本
|
|
CurPackageName string `json:"curPackageName,omitempty"` // 包名
|
|
}
|
|
|
|
// 返回参数
|
|
type AppAllResp struct {
|
|
VersionInfo VersionInfo `json:"versionInfo"` // 版本信息
|
|
AdvList []AdvertiseInfo `json:"advList"` // 广告信息
|
|
AnnouList []AnnouInfo `json:"annouList"` // 公告信息
|
|
IosUrl string `json:"iosLink"` // ios下载链接,网页版使用
|
|
AndroidUrl string `json:"andLink"` // 安卓下载链接,网页版使用
|
|
ShopIosLink string `json:"shopIosLink"` // ios商店包下载链接
|
|
}
|
|
|
|
// 版本信息
|
|
type VersionInfo struct {
|
|
HasNewVersion bool `json:"hasNewVersion,omitempty"` // 是否存在新版本
|
|
ServerVersion string `json:"serverVersion,omitempty"` // 服务器新版本
|
|
DownloadLink []string `json:"downloadLink,omitempty"` // 下载地址
|
|
Description string `json:"description,omitempty"` // 描述
|
|
IsForceUpdate bool `json:"isForceUpdate,omitempty"` // 是否强制升级
|
|
Size string `json:"size,omitempty"` // 大小
|
|
Md5 string `json:"md5,omitempty"` // md5
|
|
}
|
|
|
|
// 广告信息
|
|
type AdvertiseInfo struct {
|
|
Id int64 `json:"id"` // 广告id
|
|
Title string `json:"title"` // 广告标题
|
|
CoverImg string `json:"coverImg"` // 封面
|
|
RandomImgs []string `json:"randomImgs"` // 随机封面
|
|
RandomNames []string `json:"randomNames"` // 随机名称
|
|
LocId int32 `json:"locId"` // 位置id
|
|
JumpType int32 `json:"jumpType"` // 跳转方式 0:外部浏览器跳转 1:内部浏览器跳转 2:app内部跳转
|
|
Link string `json:"link"` // 链接地址
|
|
Sort int64 `json:"sort"` // 排序
|
|
Duration int32 `json:"duration"` // 广告持续时间(弃用)
|
|
CoverImgSize string `json:"coverImgSize"` // 封面尺寸
|
|
WatchTime int `json:"watchTime"` // 视频广告时长
|
|
}
|
|
|
|
// 公告信息
|
|
type AnnouInfo struct {
|
|
//id
|
|
ID string `json:"id"`
|
|
//名字
|
|
Title string `json:"title"`
|
|
//内容
|
|
Content string `json:"content"`
|
|
//广告图
|
|
Cover string `json:"cover"`
|
|
//链接地址
|
|
Href string `json:"href"`
|
|
//类型
|
|
Type int64 `json:"type"`
|
|
//时间
|
|
Time string `json:"time"`
|
|
}
|
|
|
|
// 广告、版本、公告,三合一接口
|
|
func AdvVersionAnnounThreeServer(curVersion, sysType string) (ver VersionInfo, adv []AdvertiseInfo, annou []AnnouInfo, iosUrl, androidUrl, shopIosLink string, err error) {
|
|
//版本
|
|
key := "VerAnnInfo:" + sysType + ":" + curVersion
|
|
if resp, ok := getVersionCache(key); ok {
|
|
ver, annou, iosUrl, androidUrl, shopIosLink = unpackAppAllResp(resp)
|
|
return
|
|
}
|
|
|
|
value, requestErr, _ := versionRequestGroup.Do(key, func() (interface{}, error) {
|
|
// 同一版本的并发请求只允许一个访问产品中心;等待者进入后再检查一次缓存。
|
|
if cached, ok := getVersionCache(key); ok {
|
|
return cached, nil
|
|
}
|
|
|
|
resp, fetchErr := fetchAppAllResp(curVersion, sysType)
|
|
if fetchErr == nil {
|
|
localcache.C.Set(key, resp, versionCacheTTL)
|
|
localcache.C.Set(key+":lastSuccess", resp, versionLastSuccessTTL)
|
|
return resp, nil
|
|
}
|
|
|
|
// 下游异常时短暂缓存最后一次成功结果(没有则为空结果),避免每个 Ping
|
|
// 都同步等待同一个失败请求;10 秒后自动重试,恢复后能快速拿到新数据。
|
|
fallback, _ := getVersionCache(key + ":lastSuccess")
|
|
localcache.C.Set(key, fallback, versionFailureCacheTTL)
|
|
return fallback, fetchErr
|
|
})
|
|
resp, ok := value.(AppAllResp)
|
|
if !ok {
|
|
return ver, adv, annou, iosUrl, androidUrl, shopIosLink, fmt.Errorf("invalid version cache type")
|
|
}
|
|
ver, annou, iosUrl, androidUrl, shopIosLink = unpackAppAllResp(resp)
|
|
err = requestErr
|
|
//log.Info("AdvVersionAnnounThreeServer response", log.Any("resp", resp))
|
|
return
|
|
}
|
|
|
|
func getVersionCache(key string) (AppAllResp, bool) {
|
|
value, ok := localcache.C.Get(key)
|
|
if !ok || value == nil {
|
|
return AppAllResp{}, false
|
|
}
|
|
resp, ok := value.(AppAllResp)
|
|
return resp, ok
|
|
}
|
|
|
|
func unpackAppAllResp(resp AppAllResp) (VersionInfo, []AnnouInfo, string, string, string) {
|
|
return resp.VersionInfo, resp.AnnouList, resp.IosUrl, resp.AndroidUrl, resp.ShopIosLink
|
|
}
|
|
|
|
func fetchAppAllResp(curVersion, sysType string) (AppAllResp, error) {
|
|
req := AppAllReq{
|
|
AppId: commod.KFK_APPID,
|
|
PktType: PacketTypeEnterprise,
|
|
SysType: sysType,
|
|
CurVersion: curVersion,
|
|
}
|
|
bodyStr, err := json.Marshal(req)
|
|
if err != nil {
|
|
log.Info(fmt.Sprintf("AdvVersionAnnounThreeServer json.Marshal is fail error:%+v/data:%+v", err, req))
|
|
return AppAllResp{}, err
|
|
}
|
|
|
|
url := appg.Conf.URL.ProductUrl + "/api/stat/all/app"
|
|
resp := AppAllResp{}
|
|
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, bodyStr)
|
|
if err != nil {
|
|
log.Error("AdvVersionAnnounThreeServer POSTWithJResp ", log.Any("url", url), log.E(err))
|
|
return AppAllResp{}, err
|
|
}
|
|
if code != http.StatusOK {
|
|
log.Error("AdvVersionAnnounThreeServer response status ", log.Any("code", code))
|
|
return AppAllResp{}, fmt.Errorf("response status %d", code)
|
|
}
|
|
return resp, nil
|
|
}
|