@@ -0,0 +1,120 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"91porn-server/app/service/sys_config"
|
||||
"91porn-server/models/cache/sysconfdata"
|
||||
"91porn-server/models/v/sysconfmod"
|
||||
"91porn-server/models/v/usermod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
)
|
||||
|
||||
// FreeTrialBadgeContext 是一次视频列表组装过程中复用的用户免费观看上下文。
|
||||
type FreeTrialBadgeContext struct {
|
||||
uid uint64
|
||||
enabled bool
|
||||
remaining uint64
|
||||
canShow bool
|
||||
canUse bool
|
||||
}
|
||||
|
||||
// NewFreeTrialBadgeContext 构造免费观看上下文。
|
||||
// remaining 会按系统配置的总次数截断,避免历史异常数据透传给前端。
|
||||
func NewFreeTrialBadgeContext(uid, total, remaining uint64, isVIP, enabled bool) FreeTrialBadgeContext {
|
||||
if total == 0 || uid == 0 {
|
||||
remaining = 0
|
||||
} else if remaining > total {
|
||||
remaining = total
|
||||
}
|
||||
canShow := uid > 0 && total > 0 && !isVIP
|
||||
return FreeTrialBadgeContext{
|
||||
uid: uid,
|
||||
enabled: enabled,
|
||||
remaining: remaining,
|
||||
canShow: canShow,
|
||||
canUse: canShow && remaining > 0,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFreeTrialBadgeContext 加载用户和后台角标开关。
|
||||
func LoadFreeTrialBadgeContext(uid uint64) FreeTrialBadgeContext {
|
||||
if uid == 0 {
|
||||
return FreeTrialBadgeContext{}
|
||||
}
|
||||
user, err := usermod.FindUserByUID(uid)
|
||||
if err != nil || user == nil {
|
||||
return FreeTrialBadgeContext{}
|
||||
}
|
||||
return FreeTrialBadgeContextForUser(uid, user)
|
||||
}
|
||||
|
||||
// FreeTrialBadgeContextForUser 使用已查询的用户构造上下文,避免列表组装重复查询用户。
|
||||
func FreeTrialBadgeContextForUser(uid uint64, user *usermod.User) FreeTrialBadgeContext {
|
||||
if uid == 0 || user == nil {
|
||||
return FreeTrialBadgeContext{}
|
||||
}
|
||||
enabled := false
|
||||
if value, err := sysconfdata.GetBoolFromSharedCache(sysconfmod.VCodeFreeTrialBadgeEnabled); err == nil {
|
||||
enabled = value
|
||||
}
|
||||
return NewFreeTrialBadgeContext(
|
||||
uid,
|
||||
sys_config.GetTotalWatchCount(),
|
||||
user.WatchCount,
|
||||
user.IsVIP(time.Now()),
|
||||
enabled,
|
||||
)
|
||||
}
|
||||
|
||||
// Fields 返回当前视频的角标字段。
|
||||
func (c FreeTrialBadgeContext) Fields(
|
||||
newsType string,
|
||||
originCoins int64,
|
||||
freeArea bool,
|
||||
publisherID uint64,
|
||||
) (show bool, remaining uint64, canUse bool) {
|
||||
remaining = c.remaining
|
||||
eligible := isVIPVideoForFreeTrial(newsType, originCoins, freeArea) &&
|
||||
publisherID != c.uid
|
||||
canUse = c.canUse && eligible
|
||||
show = c.enabled && canUse
|
||||
return
|
||||
}
|
||||
|
||||
func isVIPVideoForFreeTrial(newsType string, originCoins int64, freeArea bool) bool {
|
||||
if originCoins != 0 || freeArea {
|
||||
return false
|
||||
}
|
||||
return newsType == vidmod.SP || newsType == vidmod.SHORT
|
||||
}
|
||||
|
||||
// ApplyFreeTrialBadgeToVideoInfos 设置标准视频列表/详情对象的角标字段。
|
||||
func ApplyFreeTrialBadgeToVideoInfos(ctx FreeTrialBadgeContext, videos []*vidmod.VideoInfo) {
|
||||
for _, video := range videos {
|
||||
if video == nil {
|
||||
continue
|
||||
}
|
||||
video.ShowFreeTrialBadge, video.FreeTrialRemaining, video.CanUseFreeTrial = ctx.Fields(
|
||||
video.NewsType,
|
||||
video.OriginCoins,
|
||||
video.FreeArea,
|
||||
video.UInfo.UID,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyFreeTrialBadgeToVideoInfoResps 设置无状态视频列表对象的角标字段。
|
||||
func ApplyFreeTrialBadgeToVideoInfoResps(ctx FreeTrialBadgeContext, videos []*vidmod.VideoInfoResp) {
|
||||
for _, video := range videos {
|
||||
if video == nil {
|
||||
continue
|
||||
}
|
||||
video.ShowFreeTrialBadge, video.FreeTrialRemaining, video.CanUseFreeTrial = ctx.Fields(
|
||||
video.NewsType,
|
||||
video.OriginCoins,
|
||||
video.FreeArea,
|
||||
video.UInfo.UID,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"91porn-server/models/v/vidmod"
|
||||
)
|
||||
|
||||
func TestFreeTrialBadgeContextFields(t *testing.T) {
|
||||
const (
|
||||
uid = uint64(1001)
|
||||
publisherID = uint64(2002)
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx FreeTrialBadgeContext
|
||||
newsType string
|
||||
originCoins int64
|
||||
freeArea bool
|
||||
publisherID uint64
|
||||
wantShow bool
|
||||
wantRemaining uint64
|
||||
wantCanUse bool
|
||||
}{
|
||||
{
|
||||
name: "eligible vip video",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, true),
|
||||
newsType: vidmod.SP,
|
||||
publisherID: publisherID,
|
||||
wantShow: true,
|
||||
wantRemaining: 2,
|
||||
wantCanUse: true,
|
||||
},
|
||||
{
|
||||
name: "switch only hides badge",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, false),
|
||||
newsType: vidmod.SHORT,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 2,
|
||||
wantCanUse: true,
|
||||
},
|
||||
{
|
||||
name: "active vip does not use trial",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, true, true),
|
||||
newsType: vidmod.SP,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 2,
|
||||
},
|
||||
{
|
||||
name: "coin video",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, true),
|
||||
newsType: vidmod.SP,
|
||||
originCoins: 10,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 2,
|
||||
},
|
||||
{
|
||||
name: "free area",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, true),
|
||||
newsType: vidmod.SP,
|
||||
freeArea: true,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 2,
|
||||
},
|
||||
{
|
||||
name: "own video",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, true),
|
||||
newsType: vidmod.SP,
|
||||
publisherID: uid,
|
||||
wantRemaining: 2,
|
||||
},
|
||||
{
|
||||
name: "advertisement",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 2, false, true),
|
||||
newsType: vidmod.AD_SP,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 2,
|
||||
},
|
||||
{
|
||||
name: "remaining count is clamped",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 99, false, true),
|
||||
newsType: vidmod.SP,
|
||||
publisherID: publisherID,
|
||||
wantShow: true,
|
||||
wantRemaining: 3,
|
||||
wantCanUse: true,
|
||||
},
|
||||
{
|
||||
name: "no remaining count hides badge",
|
||||
ctx: NewFreeTrialBadgeContext(uid, 3, 0, false, true),
|
||||
newsType: vidmod.SP,
|
||||
publisherID: publisherID,
|
||||
wantRemaining: 0,
|
||||
wantCanUse: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
show, remaining, canUse := tt.ctx.Fields(tt.newsType, tt.originCoins, tt.freeArea, tt.publisherID)
|
||||
if show != tt.wantShow || remaining != tt.wantRemaining || canUse != tt.wantCanUse {
|
||||
t.Fatalf(
|
||||
"Fields() = (%v, %d, %v), want (%v, %d, %v)",
|
||||
show,
|
||||
remaining,
|
||||
canUse,
|
||||
tt.wantShow,
|
||||
tt.wantRemaining,
|
||||
tt.wantCanUse,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyFreeTrialBadgeToVideoInfos(t *testing.T) {
|
||||
ctx := NewFreeTrialBadgeContext(1001, 3, 2, false, true)
|
||||
video := &vidmod.VideoInfo{
|
||||
VideoBase: vidmod.VideoBase{
|
||||
NewsType: vidmod.SP,
|
||||
OriginCoins: 0,
|
||||
},
|
||||
UInfo: vidmod.Publisher{
|
||||
UInfo: vidmod.UInfo{UID: 2002},
|
||||
},
|
||||
}
|
||||
|
||||
ApplyFreeTrialBadgeToVideoInfos(ctx, []*vidmod.VideoInfo{video})
|
||||
|
||||
if !video.ShowFreeTrialBadge || !video.CanUseFreeTrial || video.FreeTrialRemaining != 2 {
|
||||
t.Fatalf("unexpected badge fields: %+v", video.VideoBase)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/models/v/vidmod"
|
||||
)
|
||||
|
||||
// H265URLForApp 根据 App 配置决定是否下发已经入库的 H265 播放地址。
|
||||
// enableApp 未配置时保持向后兼容;显式配置为 false 时可快速关闭 H265 下发。
|
||||
func H265URLForApp(video *vidmod.VideoModel) string {
|
||||
if video == nil {
|
||||
return ""
|
||||
}
|
||||
return appg.H265URLForApp(video.H265Url)
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/models/v/locmod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
)
|
||||
|
||||
func TestH265URLForApp(t *testing.T) {
|
||||
oldConf := appg.Conf
|
||||
t.Cleanup(func() {
|
||||
appg.Conf = oldConf
|
||||
})
|
||||
|
||||
video := &vidmod.VideoModel{H265Url: "https://cdn.example.com/h265/index.m3u8"}
|
||||
if got := H265URLForApp(nil); got != "" {
|
||||
t.Fatalf("nil video returned %q", got)
|
||||
}
|
||||
|
||||
appg.Conf = nil
|
||||
if got := H265URLForApp(video); got != video.H265Url {
|
||||
t.Fatalf("unconfigured switch returned %q", got)
|
||||
}
|
||||
|
||||
disabled := false
|
||||
appg.Conf = &appg.GlobalConfig{}
|
||||
appg.Conf.Hevc.EnableApp = &disabled
|
||||
if got := H265URLForApp(video); got != "" {
|
||||
t.Fatalf("disabled switch returned %q", got)
|
||||
}
|
||||
|
||||
enabled := true
|
||||
appg.Conf.Hevc.EnableApp = &enabled
|
||||
if got := H265URLForApp(video); got != video.H265Url {
|
||||
t.Fatalf("enabled switch returned %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransfer2InfoIncludesH265URL(t *testing.T) {
|
||||
video := &vidmod.VideoModel{
|
||||
SourceURL: "https://cdn.example.com/h264/index.m3u8",
|
||||
H265Url: "https://cdn.example.com/h265/index.m3u8",
|
||||
}
|
||||
|
||||
info := transfer2Info(
|
||||
video,
|
||||
vidmod.Publisher{},
|
||||
vidmod.VideoStatus{},
|
||||
locmod.Location{},
|
||||
nil,
|
||||
vidmod.CommentInfo{},
|
||||
0,
|
||||
)
|
||||
|
||||
data, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal video info: %v", err)
|
||||
}
|
||||
|
||||
var response map[string]interface{}
|
||||
if err := json.Unmarshal(data, &response); err != nil {
|
||||
t.Fatalf("unmarshal video info response: %v", err)
|
||||
}
|
||||
if response["sourceURL"] != video.SourceURL {
|
||||
t.Fatalf("unexpected H.264 URL: %v", response["sourceURL"])
|
||||
}
|
||||
if response["h265Url"] != video.H265Url {
|
||||
t.Fatalf("unexpected H.265 URL: %v", response["h265Url"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTransfer2InfoIncludesH265URL(t *testing.T) {
|
||||
video := &vidmod.VideoModel{
|
||||
SourceURL: "https://cdn.example.com/h264/index.m3u8",
|
||||
H265Url: "https://cdn.example.com/h265/index.m3u8",
|
||||
}
|
||||
|
||||
info := NewTransfer2Info(
|
||||
video,
|
||||
vidmod.Publisher{},
|
||||
vidmod.VideoStatus{},
|
||||
nil,
|
||||
0,
|
||||
)
|
||||
|
||||
data, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal video info response: %v", err)
|
||||
}
|
||||
|
||||
var response map[string]interface{}
|
||||
if err := json.Unmarshal(data, &response); err != nil {
|
||||
t.Fatalf("unmarshal video info response: %v", err)
|
||||
}
|
||||
if response["sourceURL"] != video.SourceURL {
|
||||
t.Fatalf("unexpected H.264 URL: %v", response["sourceURL"])
|
||||
}
|
||||
if response["h265Url"] != video.H265Url {
|
||||
t.Fatalf("unexpected H.265 URL: %v", response["h265Url"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestToVideoBaseInfoIncludesH265URL(t *testing.T) {
|
||||
video := &vidmod.VideoModel{
|
||||
SourceURL: "https://cdn.example.com/h264/index.m3u8",
|
||||
H265Url: "https://cdn.example.com/h265/index.m3u8",
|
||||
}
|
||||
|
||||
info := ToVideoBaseInfo(video, nil, 0)
|
||||
if info.SourceURL != video.SourceURL {
|
||||
t.Fatalf("unexpected H.264 URL: %q", info.SourceURL)
|
||||
}
|
||||
if info.H265Url != video.H265Url {
|
||||
t.Fatalf("unexpected H.265 URL: %q", info.H265Url)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func parseHelpserSource(t *testing.T) *ast.File {
|
||||
t.Helper()
|
||||
_, testFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
t.Fatal("resolve test source path")
|
||||
}
|
||||
path := filepath.Join(filepath.Dir(testFile), "helpser.go")
|
||||
file, err := parser.ParseFile(token.NewFileSet(), path, nil, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("parse %s: %v", path, err)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func findFunction(t *testing.T, file *ast.File, name string) *ast.FuncDecl {
|
||||
t.Helper()
|
||||
for _, decl := range file.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if ok && fn.Name.Name == name {
|
||||
return fn
|
||||
}
|
||||
}
|
||||
t.Fatalf("function %s not found", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestVideoInfoEncodersAggregatePageViewsOnlyThroughRedis(t *testing.T) {
|
||||
file := parseHelpserSource(t)
|
||||
encoders := []string{
|
||||
"encodeVideoInfo",
|
||||
"newEncodeVideoInfoNotStatus",
|
||||
"newEncodeVideoInfo",
|
||||
"encodeVideoInfoNoUID",
|
||||
}
|
||||
|
||||
for _, name := range encoders {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fn := findFunction(t, file, name)
|
||||
directMongoCalls := 0
|
||||
redisAggregateCalls := 0
|
||||
ast.Inspect(fn.Body, func(node ast.Node) bool {
|
||||
call, ok := node.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
switch callee := call.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
if callee.Name == "incVideoPageView" {
|
||||
redisAggregateCalls++
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
pkg, ok := callee.X.(*ast.Ident)
|
||||
if ok && pkg.Name == "vidmod" && callee.Sel.Name == "IncVideoPageView" {
|
||||
directMongoCalls++
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if directMongoCalls != 0 {
|
||||
t.Fatalf("direct Mongo page-view increments = %d, want 0", directMongoCalls)
|
||||
}
|
||||
if redisAggregateCalls != 1 {
|
||||
t.Fatalf("Redis page-view aggregate calls = %d, want 1", redisAggregateCalls)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAsyncClosuresDoNotAssignCapturedErr(t *testing.T) {
|
||||
file := parseHelpserSource(t)
|
||||
functions := []string{
|
||||
"encodeVideoInfo",
|
||||
"GetVideosByIDs",
|
||||
"NewGetVideosByIDs",
|
||||
}
|
||||
|
||||
for _, name := range functions {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fn := findFunction(t, file, name)
|
||||
ast.Inspect(fn.Body, func(node ast.Node) bool {
|
||||
closure, ok := node.(*ast.FuncLit)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
ast.Inspect(closure.Body, func(node ast.Node) bool {
|
||||
assign, ok := node.(*ast.AssignStmt)
|
||||
if !ok || assign.Tok != token.ASSIGN {
|
||||
return true
|
||||
}
|
||||
for _, lhs := range assign.Lhs {
|
||||
ident, ok := lhs.(*ast.Ident)
|
||||
if ok && ident.Name == "err" {
|
||||
t.Errorf("async closure assigns captured err at %s", name)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return false
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"91porn-server/models/v/tagmod"
|
||||
"91porn-server/models/v/usermod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func getUsersBaseInfoFromMongo(uids []uint64) ([]*usermod.BaseInfoVip, error) {
|
||||
return usermod.GetUsersBaseInfoWithVip(uids)
|
||||
}
|
||||
|
||||
func getTagsByIDsFromMongo(tids []primitive.ObjectID) ([]vidmod.TagInfo, error) {
|
||||
tInfo, err := tagmod.FindTagsByIDS(tids)
|
||||
if err != nil {
|
||||
return []vidmod.TagInfo{}, err
|
||||
}
|
||||
info := make([]vidmod.TagInfo, len(tInfo))
|
||||
for i, v := range tInfo {
|
||||
info[i] = vidmod.TagInfo{
|
||||
ID: v.ID,
|
||||
Name: v.TagName,
|
||||
CoverImg: v.CoverImg,
|
||||
Description: v.Description,
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func getVideoListByIDsFromMongo(vids []primitive.ObjectID) ([]*vidmod.VideoModel, error) {
|
||||
return vidmod.GetVideoListByIDs(vids)
|
||||
}
|
||||
|
||||
func getVideoListByIDsFromMongoBaseNoStatus(vids []primitive.ObjectID) ([]*vidmod.VideoModel, error) {
|
||||
return vidmod.GetVideoListByIDsNoStatus(vids)
|
||||
}
|
||||
|
||||
func getNewestNewsFromMongo(page, size uint64, recentMinute time.Time) ([]*vidmod.VideoModel, bool, error) {
|
||||
return vidmod.GetNewestNews(page, size, recentMinute)
|
||||
}
|
||||
|
||||
func getNewestNewsFromMongo_old(page, size uint64) ([]*vidmod.VideoModel, bool, error) {
|
||||
return vidmod.GetNewestNews_old(page, size)
|
||||
}
|
||||
|
||||
func getNewestShortVideoFromMongo(page, size uint64) ([]*vidmod.VideoModel, bool, error) {
|
||||
return vidmod.GetNewestShortVideo(page, size)
|
||||
}
|
||||
|
||||
func getNewsTop200FromMongo(recentMinute time.Time) []string {
|
||||
vModel, _, err := vidmod.GetNewestNews(1, MaxNewestCacheNum, recentMinute)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
ids := make([]string, len(vModel))
|
||||
for i, v := range vModel {
|
||||
ids[i] = v.ID.Hex()
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getNewsTop200FromMongo_old() []string {
|
||||
vModel, _, err := vidmod.GetNewestNews_old(1, MaxNewestCacheNum)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
ids := make([]string, len(vModel))
|
||||
for i, v := range vModel {
|
||||
ids[i] = v.ID.Hex()
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getNewsShortVideoTop200FromMongo() []string {
|
||||
vModel, _, err := vidmod.GetNewestShortVideo(1, MaxNewestCacheNum)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
ids := make([]string, len(vModel))
|
||||
for i, v := range vModel {
|
||||
ids[i] = v.ID.Hex()
|
||||
}
|
||||
return ids
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
package vidhelpser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/redis"
|
||||
"91porn-server/models/v/usermod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func getUIDKey(uids []uint64) []string {
|
||||
format := redisconst.UserInfoKey()
|
||||
keys := make([]string, len(uids))
|
||||
for i, u := range uids {
|
||||
keys[i] = fmt.Sprintf(format, u)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func getTidKey(tids []primitive.ObjectID) []string {
|
||||
format := redisconst.TagInfoKey()
|
||||
keys := make([]string, len(tids))
|
||||
for i, t := range tids {
|
||||
keys[i] = fmt.Sprintf(format, t.Hex())
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func getVidKey(vids []primitive.ObjectID) []string {
|
||||
format := redisconst.VideoInfoKey()
|
||||
keys := make([]string, len(vids))
|
||||
for i, v := range vids {
|
||||
keys[i] = fmt.Sprintf(format, v.Hex())
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func parseUserInfo(data []interface{}) []usermod.BaseInfoVip {
|
||||
infos := make([]usermod.BaseInfoVip, 0, len(data))
|
||||
for _, d := range data {
|
||||
str, ok := d.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var u usermod.BaseInfoVip
|
||||
if err := json.Unmarshal([]byte(str), &u); err != nil {
|
||||
continue
|
||||
}
|
||||
infos = append(infos, u)
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func getPublisher(info []usermod.BaseInfoVip) map[uint64]*vidmod.Publisher {
|
||||
m := make(map[uint64]*vidmod.Publisher)
|
||||
for _, u := range info {
|
||||
p := vidmod.Publisher{
|
||||
UInfo: u,
|
||||
}
|
||||
m[u.UID] = &p
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func getUnExistUID(uids []uint64, m map[uint64]*vidmod.Publisher) []uint64 {
|
||||
ids := make([]uint64, 0, len(uids))
|
||||
for _, u := range uids {
|
||||
if m[u] == nil {
|
||||
ids = append(ids, u)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getUsersBaseInfoFromRedis(uids []uint64) (map[uint64]*vidmod.Publisher, []uint64, error) {
|
||||
sInfo := getUIDKey(uids)
|
||||
uInfo, err := appg.Redis.MGet(sInfo...)
|
||||
if err != nil {
|
||||
log.Error("getUsersBaseInfoFromRedis error", log.Any("uids", uids), log.Any("sInfo", sInfo), log.E(err))
|
||||
return nil, uids, err
|
||||
}
|
||||
userInfo := parseUserInfo(uInfo)
|
||||
mPublisher := getPublisher(userInfo)
|
||||
unExist := getUnExistUID(uids, mPublisher)
|
||||
return mPublisher, unExist, nil
|
||||
}
|
||||
|
||||
func setUsersBaseInfo2Redis(infos []*usermod.BaseInfoVip) error {
|
||||
format := redisconst.UserInfoKey()
|
||||
expire := redisconst.UserInfoExpire()
|
||||
for _, u := range infos {
|
||||
d, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s := fmt.Sprintf(format, u.UID)
|
||||
_ = appg.Redis.Set(s, string(d), expire)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseTagInfo(data []interface{}) []vidmod.TagInfo {
|
||||
infos := make([]vidmod.TagInfo, 0, len(data))
|
||||
for _, d := range data {
|
||||
str, ok := d.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var t vidmod.TagInfo
|
||||
if err := json.Unmarshal([]byte(str), &t); err != nil {
|
||||
continue
|
||||
}
|
||||
infos = append(infos, t)
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func getUnExistTID(ids []primitive.ObjectID, info []vidmod.TagInfo) []primitive.ObjectID {
|
||||
m := make(map[primitive.ObjectID]bool)
|
||||
for _, i := range info {
|
||||
m[i.ID] = true
|
||||
}
|
||||
unExist := make([]primitive.ObjectID, 0, len(ids))
|
||||
for _, i := range ids {
|
||||
if !m[i] {
|
||||
unExist = append(unExist, i)
|
||||
}
|
||||
}
|
||||
return unExist
|
||||
}
|
||||
|
||||
func getTagsByIDsFromRedis(ids []primitive.ObjectID) ([]vidmod.TagInfo, []primitive.ObjectID, error) {
|
||||
sInfo := getTidKey(ids)
|
||||
uInfo, err := appg.Redis.MGet(sInfo...)
|
||||
if err != nil {
|
||||
log.Error("getTagsByIDsFromRedis error", log.Any("ids", ids), log.Any("sInfo", sInfo), log.E(err))
|
||||
return nil, ids, err
|
||||
}
|
||||
tagInfo := parseTagInfo(uInfo)
|
||||
unExist := getUnExistTID(ids, tagInfo)
|
||||
return tagInfo, unExist, nil
|
||||
}
|
||||
|
||||
func setTagsByIDs2Redis(tags []vidmod.TagInfo) error {
|
||||
expire := redisconst.TagInfoExpire()
|
||||
format := redisconst.TagInfoKey()
|
||||
for _, t := range tags {
|
||||
d, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s := fmt.Sprintf(format, t.ID.Hex())
|
||||
_ = appg.Redis.Set(s, string(d), expire)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseVideoInfo(data []interface{}) []*vidmod.VideoModel {
|
||||
infos := make([]*vidmod.VideoModel, 0, len(data))
|
||||
for _, d := range data {
|
||||
str, ok := d.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var v vidmod.VideoModel
|
||||
if err := json.Unmarshal([]byte(str), &v); err != nil {
|
||||
continue
|
||||
}
|
||||
infos = append(infos, &v)
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func getUnExistVID(ids []primitive.ObjectID, info []*vidmod.VideoModel) []primitive.ObjectID {
|
||||
m := make(map[primitive.ObjectID]bool)
|
||||
for _, i := range info {
|
||||
m[i.ID] = true
|
||||
}
|
||||
unExist := make([]primitive.ObjectID, 0, len(ids))
|
||||
for _, i := range ids {
|
||||
if !m[i] {
|
||||
unExist = append(unExist, i)
|
||||
}
|
||||
}
|
||||
return unExist
|
||||
}
|
||||
|
||||
func getVideoListByIDsFromRedis(ids []primitive.ObjectID) ([]*vidmod.VideoModel, []primitive.ObjectID, error) {
|
||||
sInfo := getVidKey(ids)
|
||||
uInfo, err := appg.Redis.MGet(sInfo...)
|
||||
if err != nil {
|
||||
log.Error("getVideoListByIDsFromRedis error", log.Any("ids", ids), log.Any("sInfo", sInfo), log.E(err))
|
||||
return nil, ids, err
|
||||
}
|
||||
videoInfo := parseVideoInfo(uInfo)
|
||||
unExist := getUnExistVID(ids, videoInfo)
|
||||
return videoInfo, unExist, nil
|
||||
}
|
||||
|
||||
func setVideoListByIDs2Redis(infos []*vidmod.VideoModel) error {
|
||||
expire := redisconst.VideoInfoExpire()
|
||||
format := redisconst.VideoInfoKey()
|
||||
for _, v := range infos {
|
||||
d, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s := fmt.Sprintf(format, v.ID.Hex())
|
||||
_ = appg.Redis.Set(s, string(d), expire)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNewestNewsFromRedis(page, size uint64, recentMinute time.Time) ([]string, error) {
|
||||
key := redisconst.NewestNewsKey(recentMinute)
|
||||
start := (page - 1) * size
|
||||
end := page*size - 1
|
||||
ids, err := appg.Redis.ZRange(key, int64(start), int64(end))
|
||||
if err != nil {
|
||||
log.Error("getNewestNewsFromRedis error", log.Any("page", page), log.Any("size", size), log.E(err))
|
||||
}
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func getNewestNewsFromRedis_old(page, size uint64) ([]string, error) {
|
||||
key := redisconst.NewestNewsKey_old()
|
||||
start := (page - 1) * size
|
||||
end := page*size - 1
|
||||
ids, err := appg.Redis.ZRange(key, int64(start), int64(end))
|
||||
if err != nil {
|
||||
log.Error("getNewestNewsFromRedis error", log.Any("page", page), log.Any("size", size), log.E(err))
|
||||
}
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func getNewestShortVideoFromRedis(page, size uint64) ([]string, error) {
|
||||
key := redisconst.NewestShortVideoKey()
|
||||
start := (page - 1) * size
|
||||
end := page*size - 1
|
||||
ids, err := appg.Redis.ZRange(key, int64(start), int64(end))
|
||||
if err != nil {
|
||||
log.Error("getNewestNewsFromRedis error", log.Any("page", page), log.Any("size", size), log.E(err))
|
||||
}
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func news2RedisZ(ids []string) []redis.Member {
|
||||
if len(ids) == 0 {
|
||||
return []redis.Member{}
|
||||
}
|
||||
members := make([]redis.Member, 0, len(ids))
|
||||
for k, v := range ids {
|
||||
if v != "" {
|
||||
members = append(members, redis.Member{Score: float64(k), Member: v})
|
||||
}
|
||||
}
|
||||
return members
|
||||
}
|
||||
|
||||
func setNewestNews2Redis(ids []string, recentMinute time.Time) {
|
||||
key := redisconst.NewestNewsKey(recentMinute)
|
||||
expird := redisconst.NewestNewsExpire()
|
||||
if _, err := appg.Redis.Del(key); err != nil {
|
||||
return
|
||||
}
|
||||
values := news2RedisZ(ids)
|
||||
if _, err := appg.Redis.ZAdd(key, values...); err != nil {
|
||||
return
|
||||
}
|
||||
_, _ = appg.Redis.ExpireKeAt(key, time.Now().Add(expird))
|
||||
}
|
||||
|
||||
func setNewestNews2Redis_old(ids []string) {
|
||||
key := redisconst.NewestNewsKey_old()
|
||||
expird := redisconst.NewestNewsExpire()
|
||||
if _, err := appg.Redis.Del(key); err != nil {
|
||||
return
|
||||
}
|
||||
values := news2RedisZ(ids)
|
||||
if _, err := appg.Redis.ZAdd(key, values...); err != nil {
|
||||
return
|
||||
}
|
||||
_, _ = appg.Redis.ExpireKeAt(key, time.Now().Add(expird))
|
||||
}
|
||||
|
||||
func setNewestShortVideo2Redis(ids []string) {
|
||||
key := redisconst.NewestShortVideoKey()
|
||||
expird := redisconst.NewestNewsExpire()
|
||||
if _, err := appg.Redis.Del(key); err != nil {
|
||||
return
|
||||
}
|
||||
values := news2RedisZ(ids)
|
||||
if _, err := appg.Redis.ZAdd(key, values...); err != nil {
|
||||
return
|
||||
}
|
||||
_, _ = appg.Redis.ExpireKeAt(key, time.Now().Add(expird))
|
||||
}
|
||||
|
||||
func incComment(vid primitive.ObjectID) {
|
||||
infos, _, err := getVideoListByIDsFromRedis([]primitive.ObjectID{vid})
|
||||
if err != nil || len(infos) == 0 {
|
||||
return
|
||||
}
|
||||
if infos[0] == nil {
|
||||
return
|
||||
}
|
||||
infos[0].CommentCount++
|
||||
infos[0].FakeCommentCount++
|
||||
_ = setVideoListByIDs2Redis(infos)
|
||||
}
|
||||
Reference in New Issue
Block a user