Files
web_hgdjb_server/app/service/appser/cache.go
T
rootandClaude Opus 4.7 cd8dea8787 同步 web_hga 的五项改造
- 移除 买点 (user acquisition tracking) 子系统:dataReport SDK、eventmod
  事件模型、reportdata 定时上报 job、reportser/srv_report 包装层,以及业务
  侧的 ~20 处 Report* 调用点;去掉 proto.ConfigInfo 的 ReportSDKConfig
  字段、DataReport yaml 配置块和 pubdef.TrackerAppId。
- 广告获取改走 versionUrl /api/stat/advitise/v2/get(appId=12),移除
  adcenter(Jt) 调用;新增 POST /api/app/ads/click 异步上报;
  proto.AdvitiseData 别名 proxy.AdvitiseData,AList/BList 改名
  AppInfoAList/AppInfoBList。
- web 后台登录取消谷歌验证码(srv_mwacc.AccLogin 去掉 code 参数),密码
  正确即发放 token。
- app 端取消注册/登录/找回密码/游客登录接口及密码、token 相关代码;鉴权
  中间件按 X-User-Agent 中的 devID 识别用户,首次访问自动建号,Redis 缓存
  10 分钟;修改资料不再支持改密码。
- app m3u8 ticket 校验失败不再降级到 fallback 路径,仍按原 m3u8Name 返回。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-11-07 11:22:25 +08:00

197 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
selfAppName := strings.TrimSpace(config.WebSiteName)
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 selfAppName != "" && strings.HasPrefix(app.Name, selfAppName) {
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.AppInfoAList {
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.AppInfoBList {
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()
}