196 lines
5.2 KiB
Go
196 lines
5.2 KiB
Go
package appser
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/url"
|
|
"strings"
|
|
"sync"
|
|
"videoweb/app/api/proto"
|
|
"videoweb/app/service/configser"
|
|
"videoweb/pub/common/http"
|
|
"videoweb/pub/common/log"
|
|
"videoweb/pub/common/netutil"
|
|
"videoweb/pub/pubdef"
|
|
"videoweb/pub/storage/proxy"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
const appListAPIPath = "/media/web/appinfo/applist"
|
|
|
|
var jsonHeader = map[string]string{"Content-Type": "application/json"}
|
|
|
|
var (
|
|
appListCron *cron.Cron
|
|
appListCache struct {
|
|
lock sync.RWMutex
|
|
appList []proto.AppCategoryInfo
|
|
categoryMaps map[int64]proto.AppCategoryInfo
|
|
}
|
|
)
|
|
|
|
type remoteAppListResp struct {
|
|
Code int `json:"code"`
|
|
Data struct {
|
|
List []proto.AppCategoryInfo `json:"list"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// Start 启动定时刷新应用列表缓存(每10分钟一次)
|
|
func Start() {
|
|
appListCron = cron.New(cron.WithSeconds())
|
|
UpdateAppListCache(context.Background())
|
|
_, _ = appListCron.AddFunc("0 */10 * * * ?", func() {
|
|
UpdateAppListCache(context.Background())
|
|
})
|
|
appListCron.Start()
|
|
}
|
|
|
|
// GetAppListCache 返回全部应用分类列表(带各分类下应用)
|
|
func GetAppListCache() []proto.AppCategoryInfo {
|
|
appListCache.lock.RLock()
|
|
defer appListCache.lock.RUnlock()
|
|
if len(appListCache.appList) == 0 {
|
|
return make([]proto.AppCategoryInfo, 0)
|
|
}
|
|
result := make([]proto.AppCategoryInfo, len(appListCache.appList))
|
|
copy(result, appListCache.appList)
|
|
return result
|
|
}
|
|
|
|
// GetCategoryCache 按分类ID返回单个分类(含应用列表);categoryId=0 返回第一个分类
|
|
func GetCategoryCache(categoryId int64) proto.AppCategoryInfo {
|
|
appListCache.lock.RLock()
|
|
defer appListCache.lock.RUnlock()
|
|
if categoryId == 0 && len(appListCache.appList) > 0 {
|
|
return appListCache.appList[0]
|
|
}
|
|
if v, ok := appListCache.categoryMaps[categoryId]; ok {
|
|
return v
|
|
}
|
|
return proto.AppCategoryInfo{AppList: make([]proto.AppInfoData, 0)}
|
|
}
|
|
|
|
// UpdateAppListCache 从远端拉取应用列表并刷新内存缓存
|
|
func UpdateAppListCache(ctx context.Context) {
|
|
domain := proxy.DomainAddressRepair("", proxy.BucketVideoAddressV2)
|
|
apiURL := strings.TrimSuffix(domain, "/") + appListAPIPath
|
|
|
|
reqBody, _ := json.Marshal(map[string]string{"dc": "dc"})
|
|
resp, err := http.Post(apiURL, jsonHeader, bytes.NewReader(reqBody))
|
|
if err != nil {
|
|
log.Warn("UpdateAppListCache http.Post failed", log.Any("url", apiURL), log.E(err))
|
|
return
|
|
}
|
|
|
|
var remote remoteAppListResp
|
|
if err = json.Unmarshal(resp.Data, &remote); err != nil {
|
|
log.Warn("UpdateAppListCache unmarshal failed", log.Any("url", apiURL), log.E(err))
|
|
return
|
|
}
|
|
if remote.Code != 200 {
|
|
log.Warn("UpdateAppListCache bad code", log.Any("url", apiURL), log.Any("code", remote.Code))
|
|
return
|
|
}
|
|
|
|
config := configser.GetConfigInfo()
|
|
advitise := configser.GetAdvitise()
|
|
channelCode := config.ChannelCode
|
|
|
|
categoryMaps := make(map[int64]proto.AppCategoryInfo)
|
|
var appList []proto.AppCategoryInfo
|
|
|
|
for _, category := range remote.Data.List {
|
|
var apps []proto.AppInfoData
|
|
for _, app := range category.AppList {
|
|
// 过滤掉本应用自身
|
|
if strings.HasPrefix(app.Name, pubdef.AppName) {
|
|
continue
|
|
}
|
|
apps = append(apps, proto.AppInfoData{
|
|
Id: app.Id,
|
|
CategoryId: app.CategoryId,
|
|
Name: app.Name,
|
|
Intro: app.Intro,
|
|
Description: app.Description,
|
|
Logo: netutil.MergeURL(config.ImgCdn, app.Logo),
|
|
Url: appendChannelCode(app.Url, channelCode),
|
|
Sort: app.Sort,
|
|
})
|
|
}
|
|
// 广告位 A(code=12)注入图标广告
|
|
if category.Code == 12 {
|
|
for _, ad := range advitise.AList {
|
|
apps = append(apps, proto.AppInfoData{
|
|
AdvitiseId: ad.Id,
|
|
CategoryId: category.Id,
|
|
Name: ad.Title,
|
|
Logo: netutil.MergeURL(config.ImgCdn, ad.Images),
|
|
Url: ad.Link,
|
|
Location: ad.Location,
|
|
})
|
|
}
|
|
}
|
|
// 广告位 B(code=13)注入图标文字广告
|
|
if category.Code == 13 {
|
|
for _, ad := range advitise.BList {
|
|
apps = append(apps, proto.AppInfoData{
|
|
AdvitiseId: ad.Id,
|
|
CategoryId: category.Id,
|
|
Name: ad.Title,
|
|
Logo: netutil.MergeURL(config.ImgCdn, ad.Images),
|
|
Url: ad.Link,
|
|
Location: ad.Location,
|
|
})
|
|
}
|
|
}
|
|
// 空分类不展示
|
|
if len(apps) == 0 {
|
|
continue
|
|
}
|
|
category.AppList = apps
|
|
categoryMaps[category.Id] = proto.AppCategoryInfo{
|
|
Id: category.Id,
|
|
Title: category.Title,
|
|
Intro: category.Intro,
|
|
Sort: category.Sort,
|
|
Code: category.Code,
|
|
}
|
|
appList = append(appList, category)
|
|
}
|
|
|
|
appListCache.lock.Lock()
|
|
appListCache.appList = appList
|
|
appListCache.categoryMaps = categoryMaps
|
|
appListCache.lock.Unlock()
|
|
}
|
|
|
|
// appendChannelCode 为应用 URL 拼接渠道码参数 dc=xxx;已含 dc 参数则不再拼接
|
|
func appendChannelCode(rawURL, channelCode string) string {
|
|
if len(channelCode) == 0 {
|
|
channelCode = pubdef.DefaultChannelCode
|
|
}
|
|
|
|
rawURL = strings.TrimSpace(rawURL)
|
|
channelCode = strings.TrimSpace(channelCode)
|
|
if rawURL == "" || channelCode == "" {
|
|
return rawURL
|
|
}
|
|
|
|
parsed, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
return rawURL
|
|
}
|
|
|
|
query := parsed.Query()
|
|
if query.Has("dc") {
|
|
return parsed.String()
|
|
}
|
|
|
|
query.Set("dc", channelCode)
|
|
parsed.RawQuery = query.Encode()
|
|
return parsed.String()
|
|
}
|