Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["channel_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/app-channel/conf:go_default_library",
"//app/interface/main/app-channel/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"audit.go",
"cache.go",
"channel.go",
"index.go",
"index2.go",
"infoc.go",
"manager.go",
"service.go",
"tab.go",
],
importpath = "go-common/app/interface/main/app-channel/service/channel",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/app-card/model:go_default_library",
"//app/interface/main/app-card/model/card:go_default_library",
"//app/interface/main/app-card/model/card/audio:go_default_library",
"//app/interface/main/app-card/model/card/bangumi:go_default_library",
"//app/interface/main/app-card/model/card/live:go_default_library",
"//app/interface/main/app-card/model/card/operate:go_default_library",
"//app/interface/main/app-card/model/card/show:go_default_library",
"//app/interface/main/app-channel/conf:go_default_library",
"//app/interface/main/app-channel/dao/account:go_default_library",
"//app/interface/main/app-channel/dao/activity:go_default_library",
"//app/interface/main/app-channel/dao/archive:go_default_library",
"//app/interface/main/app-channel/dao/article:go_default_library",
"//app/interface/main/app-channel/dao/audio:go_default_library",
"//app/interface/main/app-channel/dao/audit:go_default_library",
"//app/interface/main/app-channel/dao/bangumi:go_default_library",
"//app/interface/main/app-channel/dao/card:go_default_library",
"//app/interface/main/app-channel/dao/converge:go_default_library",
"//app/interface/main/app-channel/dao/game:go_default_library",
"//app/interface/main/app-channel/dao/live:go_default_library",
"//app/interface/main/app-channel/dao/location:go_default_library",
"//app/interface/main/app-channel/dao/region:go_default_library",
"//app/interface/main/app-channel/dao/relation:go_default_library",
"//app/interface/main/app-channel/dao/shopping:go_default_library",
"//app/interface/main/app-channel/dao/special:go_default_library",
"//app/interface/main/app-channel/dao/tab:go_default_library",
"//app/interface/main/app-channel/dao/tag:go_default_library",
"//app/interface/main/app-channel/model:go_default_library",
"//app/interface/main/app-channel/model/activity:go_default_library",
"//app/interface/main/app-channel/model/card:go_default_library",
"//app/interface/main/app-channel/model/channel:go_default_library",
"//app/interface/main/app-channel/model/feed:go_default_library",
"//app/interface/main/app-channel/model/tab:go_default_library",
"//app/interface/main/tag/model:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/openplatform/pgc-season/api/grpc/episode/v1:go_default_library",
"//app/service/openplatform/pgc-season/api/grpc/season/v1:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup:go_default_library",
"//vendor/github.com/dgryski/go-farm:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,67 @@
package channel
import (
"context"
"go-common/app/interface/main/app-channel/model"
"go-common/library/log"
)
var (
_auditRids = map[int8]map[int]struct{}{
model.PlatIPad: map[int]struct{}{
1: struct{}{},
160: struct{}{},
119: struct{}{},
155: struct{}{},
165: struct{}{},
5: struct{}{},
181: struct{}{},
65552: struct{}{},
65556: struct{}{},
},
model.PlatIPhone: map[int]struct{}{
1: struct{}{},
160: struct{}{},
119: struct{}{},
155: struct{}{},
165: struct{}{},
5: struct{}{},
181: struct{}{},
65552: struct{}{},
65556: struct{}{},
},
}
)
// auditRegion region data list.
func (s *Service) auditRegion(mobiApp string, plat int8, build, rid int) (isAudit bool) {
if plats, ok := s.auditCache[mobiApp]; ok {
if _, ok = plats[build]; ok {
if rids, ok := _auditRids[plat]; ok {
if _, ok = rids[rid]; ok {
return true
}
}
}
}
return false
}
func (s *Service) auditList(mobiApp string, plat int8, build int) (isAudit bool) {
if plats, ok := s.auditCache[mobiApp]; ok {
if _, ok = plats[build]; ok {
return true
}
}
return false
}
func (s *Service) loadAuditCache() {
as, err := s.adt.Audits(context.TODO())
if err != nil {
log.Error("s.adt.Audits error(%v)", err)
return
}
s.auditCache = as
}

View File

@@ -0,0 +1,115 @@
package channel
import (
"context"
"time"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/tab"
"go-common/library/log"
)
// loadCardCache card cache
func (s *Service) loadCardCache(now time.Time) {
var (
tmp = map[int64][]*card.Card{}
tmpPlat = map[string][]*card.CardPlat{}
tmpUp = map[int64]*operate.Follow{}
err error
c = context.TODO()
)
if tmp, err = s.cd.Card(c, now); err != nil {
log.Error("card s.cd.Card error(%v)", err)
return
}
s.cardCache = tmp
log.Info("loadCardCache success")
if tmpPlat, err = s.cd.CardPlat(c); err != nil {
log.Error("card s.cd.CardPlat error(%v)", err)
return
}
s.cardPlatCache = tmpPlat
log.Info("loadCardPlatCache success")
if tmpUp, err = s.cd.UpCard(c); err != nil {
log.Error("card s.cd.UpCard error(%v)", err)
return
}
s.upCardCache = tmpUp
log.Info("loadUpCardCache success")
}
func (s *Service) loadConvergeCache() {
var (
tmp = map[int64]*operate.Converge{}
err error
c = context.TODO()
)
if tmp, err = s.ce.Cards(c); err != nil {
log.Error("converge s.ce.Cards error(%v)", err)
return
}
s.convergeCardCache = tmp
log.Info("loadConvergeCache success")
}
func (s *Service) loadSpecialCache() {
var (
tmp = map[int64]*operate.Special{}
err error
c = context.TODO()
)
if tmp, err = s.sl.Card(c); err != nil {
log.Error("special s.sl.Card error(%v)", err)
return
}
s.specialCardCache = tmp
log.Info("loadSpecialCache success")
}
func (s *Service) loadLiveCardCache() {
csm, err := s.lv.Card(context.TODO())
if err != nil {
log.Error("live s.lv.Card error(%v)", err)
return
}
s.liveCardCache = csm
log.Info("loadLiveCardCache success")
}
func (s *Service) loadGameDownloadCache() {
var (
download map[int64]*operate.Download
err error
)
c := context.TODO()
if download, err = s.g.DownLoad(c); err != nil {
log.Error("%+v", err)
return
}
s.gameDownloadCache = download
}
func (s *Service) loadCardSetCache() {
var (
cards map[int64]*operate.CardSet
err error
)
if cards, err = s.cd.CardSet(context.TODO()); err != nil {
log.Error("%+v", err)
return
}
s.cardSetCache = cards
}
func (s *Service) loadMenusCache(now time.Time) {
var (
menus map[int64][]*tab.Menu
err error
)
if menus, err = s.tab.Menus(context.TODO(), now); err != nil {
log.Error("%+v", err)
return
}
s.menuCache = menus
}

View File

@@ -0,0 +1,635 @@
package channel
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
cdm "go-common/app/interface/main/app-card/model"
cardm "go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-channel/model"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/channel"
"go-common/app/interface/main/app-channel/model/tab"
tag "go-common/app/interface/main/tag/model"
locmdl "go-common/app/service/main/location/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
"github.com/dgryski/go-farm"
)
const (
_initRegionKey = "region_key_%d_%v"
_initlanguage = "hans"
_initVersion = "region_version"
_regionRepeat = "r_%d_%d"
_maxAtten = 10 //展示最多10个我的订阅
)
var (
_tabList = []*channel.TabList{
&channel.TabList{
Name: "推荐",
URI: "bilibili://pegasus/channel/feed/%d",
TabID: "multiple",
},
&channel.TabList{
Name: "话题",
URI: "bilibili://following/topic_detail?id=%d&name=%s",
TabID: "topic",
},
}
)
// Tab channel tab
func (s *Service) Tab(c context.Context, tid, mid int64, tname string, plat int8) (res *channel.Tab, err error) {
var (
t *tag.ChannelDetail
)
if t, err = s.tg.ChannelDetail(c, mid, tid, tname, s.isOverseas(plat)); err != nil || t == nil {
log.Error("s.tag.ChannelDetail(%d, %d, %v) error(%v)", mid, tid, tname, err)
return
}
res = &channel.Tab{}
res.SimilarTagChange(t)
res.TabList = s.tablist(t)
return
}
//SubscribeAdd subscribe add
func (s *Service) SubscribeAdd(c context.Context, mid, id int64, now time.Time) (err error) {
if err = s.tg.SubscribeAdd(c, mid, id, now); err != nil {
log.Error("s.tg.SubscribeAdd(%d,%d) error(%v)", mid, id, err)
return
}
return
}
//SubscribeCancel subscribe channel
func (s *Service) SubscribeCancel(c context.Context, mid, id int64, now time.Time) (err error) {
if err = s.tg.SubscribeCancel(c, mid, id, now); err != nil {
log.Error("s.tg.SubscribeCancel(%d,%d) error(%v)", mid, id, err)
return
}
return
}
// SubscribeUpdate subscribe update
func (s *Service) SubscribeUpdate(c context.Context, mid int64, ids string) (err error) {
if err = s.tg.SubscribeUpdate(c, mid, ids); err != nil {
log.Error("s.tg.SubscribeUpdate(%d,%s) error(%v)", mid, ids, err)
return
}
return
}
// List 频道tab页
func (s *Service) List(c context.Context, mid int64, plat int8, build, limit int, ver, mobiApp, device, lang string) (res *channel.List, err error) {
var (
rec, atten []*channel.Channel
top, bottom []*channel.Region
max = 3
)
g, _ := errgroup.WithContext(c)
//获取推荐的三个频道
g.Go(func() (err error) {
rec, err = s.Recommend(c, mid, plat)
if err != nil {
log.Error("%+v", err)
err = nil
}
return
})
//获取我的订阅
if mid > 0 {
g.Go(func() (err error) {
atten, err = s.Subscribe(c, mid, limit)
if err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
//获取分区
g.Go(func() (err error) {
top, bottom, _, err = s.RegionList(c, plat, build, mobiApp, device, lang)
if err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Wait()
if tl := len(rec); tl < max {
if last := max - tl; len(atten) > last {
rec = append(rec, atten[:last]...)
} else {
rec = append(rec, atten...)
}
} else {
rec = rec[:max]
}
res = &channel.List{
RegionTop: top,
RegionBottom: bottom,
}
if isAudit := s.auditList(mobiApp, plat, build); !isAudit {
res.RecChannel = rec
res.AttenChannel = atten
}
res.Ver = s.hash(res)
return
}
// Recommend 推荐
func (s *Service) Recommend(c context.Context, mid int64, plat int8) (res []*channel.Channel, err error) {
list, err := s.tg.Discover(c, mid, s.isOverseas(plat))
if err != nil {
log.Error("%+v", err)
return
}
for _, chann := range list {
item := &channel.Channel{
ID: chann.ID,
Name: chann.Name,
Cover: chann.Cover,
IsAtten: chann.Attention,
Atten: chann.Sub,
}
res = append(res, item)
}
return
}
//Subscribe 我订阅的tag standard放前面用户自定义custom放后面
func (s *Service) Subscribe(c context.Context, mid int64, limit int) (res []*channel.Channel, err error) {
var (
tinfo []*tag.TagInfo
)
list, err := s.tg.Subscribe(c, mid)
if err != nil {
log.Error("%+v", err)
return
}
tinfo = list.Standard
tinfo = append(tinfo, list.Custom...)
for _, chann := range tinfo {
item := &channel.Channel{
ID: chann.ID,
Name: chann.Name,
Cover: chann.Cover,
Atten: chann.Sub,
IsAtten: chann.Attention,
Content: chann.Content,
}
res = append(res, item)
}
if len(res) > limit && limit > 0 {
res = res[:limit]
} else if len(res) == 0 {
res = []*channel.Channel{}
}
return
}
// Discover 发现频道页推荐走recommend接口有分类的揍list接口
func (s *Service) Discover(c context.Context, id, mid int64, plat int8) (res []*channel.Channel, err error) {
var (
list []*tag.Channel
)
if id > 0 {
list, err = s.tg.ListByCategory(c, id, mid, s.isOverseas(plat))
if err != nil {
log.Error("%+v", err)
return
}
} else {
list, err = s.tg.Recommend(c, mid, s.isOverseas(plat))
if err != nil {
log.Error("%+v", err)
return
}
}
if len(list) == 0 {
res = []*channel.Channel{}
return
}
for _, chann := range list {
item := &channel.Channel{
ID: chann.ID,
Name: chann.Name,
Cover: chann.Cover,
Atten: chann.Sub,
IsAtten: chann.Attention,
Content: chann.Content,
}
res = append(res, item)
}
return
}
// Category 频道分类
func (s *Service) Category(c context.Context, plat int8) (res []*channel.Category, err error) {
category, err := s.tg.Category(c, s.isOverseas(plat))
if err != nil {
log.Error("%+v", err)
return
}
res = append(res, &channel.Category{
ID: 0,
Name: "推荐",
})
for _, cat := range category {
item := &channel.Category{
ID: cat.ID,
Name: cat.Name,
}
res = append(res, item)
}
return
}
// RegionList 分区信息
func (s *Service) RegionList(c context.Context, plat int8, build int, mobiApp, device, lang string) (regionTop, regionBottom, regions []*channel.Region, err error) {
var (
hantlanguage = "hant"
)
if ok := model.IsOverseas(plat); ok && lang != _initlanguage && lang != hantlanguage {
lang = hantlanguage
} else if lang == "" {
lang = _initlanguage
}
var (
rs = s.cachelist[fmt.Sprintf(_initRegionKey, plat, lang)]
// maxTop = 8
ridtmp = map[string]struct{}{}
pids []string
auths map[string]*locmdl.Auth
ip = metadata.String(c, metadata.RemoteIP)
)
regionTop = []*channel.Region{}
regionBottom = []*channel.Region{}
regions = []*channel.Region{}
for _, rtmp := range rs {
if rtmp.ReID != 0 { //过滤二级分区
continue
}
if rtmp.Area != "" {
pids = append(pids, rtmp.Area)
}
}
if len(pids) > 0 {
auths, _ = s.loc.AuthPIDs(c, strings.Join(pids, ","), ip)
}
LOOP:
for _, rtmp := range rs {
r := &channel.Region{}
*r = *rtmp
if r.ReID != 0 { //过滤二级分区
continue
}
var tmpl, limitshow bool
if limit, ok := s.limitCache[r.ID]; ok {
for i, l := range s.limitCache[r.ID] {
if i+1 <= len(limit)-1 {
if ((l.Condition == "gt" && limit[i+1].Condition == "lt") && (l.Build < limit[i+1].Build)) ||
((l.Condition == "lt" && limit[i+1].Condition == "gt") && (l.Build > limit[i+1].Build)) {
if (l.Condition == "gt" && limit[i+1].Condition == "lt") &&
(build > l.Build && build < limit[i+1].Build) {
break
} else if (l.Condition == "lt" && limit[i+1].Condition == "gt") &&
(build < l.Build && build > limit[i+1].Build) {
break
} else {
tmpl = true
continue
}
}
}
if tmpl {
if i == len(limit)-1 {
limitshow = true
break
// continue LOOP
}
tmpl = false
continue
}
if model.InvalidBuild(build, l.Build, l.Condition) {
limitshow = true
continue
// continue LOOP
} else {
limitshow = false
break
}
}
}
if limitshow {
continue LOOP
}
if r.RID == 65539 {
if model.IsIOS(plat) {
r.URI = fmt.Sprintf("%s?from=category", r.URI)
} else {
r.URI = fmt.Sprintf("%s?sourceFrom=541", r.URI)
}
}
if auth, ok := auths[r.Area]; ok && auth.Play == locmdl.Forbidden {
log.Warn("s.invalid area(%v) ip(%v) error(%v)", r.Area, ip, err)
continue
}
if isAudit := s.auditRegion(mobiApp, plat, build, r.RID); isAudit {
continue
}
config, ok := s.configCache[r.ID]
if !ok {
continue
}
key := fmt.Sprintf(_regionRepeat, r.RID, r.ReID)
if _, ok := ridtmp[key]; !ok {
ridtmp[key] = struct{}{}
} else {
continue
}
for _, conf := range config {
if conf.ScenesID == 1 /*&& len(regionTop) < maxTop*/ {
regionTop = append(regionTop, r)
regions = append(regions, r)
} else if conf.ScenesID == 0 {
regionBottom = append(regionBottom, r)
regions = append(regions, r)
}
}
}
return
}
func (s *Service) hash(v *channel.List) string {
bs, err := json.Marshal(v)
if err != nil {
log.Error("json.Marshal error(%v)", err)
return _initVersion
}
return strconv.FormatUint(farm.Hash64(bs), 10)
}
func (s *Service) loadRegionlist() {
res, err := s.rg.AllList(context.TODO())
if err != nil {
log.Error("s.dao.All error(%v)", err)
return
}
tmp := map[string][]*channel.Region{}
for _, v := range res {
key := fmt.Sprintf(_initRegionKey, v.Plat, v.Language)
tmp[key] = append(tmp[key], v)
}
if len(tmp) > 0 {
s.cachelist = tmp
}
log.Info("region list cacheproc success")
limit, err := s.rg.Limit(context.TODO())
if err != nil {
log.Error("s.dao.limit error(%v)", err)
return
}
s.limitCache = limit
log.Info("region limit cacheproc success")
config, err := s.rg.Config(context.TODO())
if err != nil {
log.Error("s.dao.Config error(%v)", err)
return
}
s.configCache = config
log.Info("region config cacheproc success")
}
// Square 频道广场页
func (s *Service) Square(c context.Context, mid int64, plat int8, build int, loginEvent int32, mobiApp, device, lang, buvid string) (res *channel.Square, err error) {
res = new(channel.Square)
var (
squ *tag.ChannelSquare
regions []*channel.Region
oidNum = 2
)
isAudit := s.auditList(mobiApp, plat, build)
eg := errgroup.Group{}
//获取分区
eg.Go(func() (err error) {
_, _, regions, err = s.RegionList(c, plat, build, mobiApp, device, lang)
if err != nil {
log.Error("%+v", err)
err = nil
}
res.Region = regions
return
})
if !isAudit {
//获取推荐频道
eg.Go(func() (err error) {
var (
oids []int64
tagm = map[int64]*tag.Tag{}
chanOids = map[int64][]*channel.ChanOids{}
channelCards = map[int64][]*card.Card{}
initCardPlatKey = "card_platkey_%d_%d"
)
squ, err = s.tg.Square(c, mid, s.c.SquareCount, oidNum, build, loginEvent, plat, buvid, s.isOverseas(plat))
if err != nil {
log.Error("%+v", err)
err = nil
}
for _, rec := range squ.Channels {
cards, ok := s.cardCache[rec.ID]
if !ok {
continue
}
LOOP:
for _, c := range cards {
key := fmt.Sprintf(initCardPlatKey, plat, c.ID)
cardPlat, ok := s.cardPlatCache[key]
if !ok {
continue
}
if c.Type != model.GotoAv {
continue
}
for _, l := range cardPlat {
if model.InvalidBuild(build, l.Build, l.Condition) {
continue LOOP
}
}
channelCards[c.ChannelID] = append(channelCards[c.ChannelID], c)
}
}
for channelID, recOid := range squ.Oids {
oids = append(oids, recOid...)
if cards, ok := channelCards[channelID]; ok {
for _, c := range cards {
if c.Type == model.GotoAv {
chanOids[channelID] = append(chanOids[channelID], &channel.ChanOids{Oid: c.Value, FromType: _fTypeOperation})
oids = append(oids, c.Value)
}
}
}
for _, tmpOid := range recOid {
chanOids[channelID] = append(chanOids[channelID], &channel.ChanOids{Oid: tmpOid, FromType: _fTypeRecommend})
}
}
am, err := s.arc.Archives(c, oids)
if err != nil {
return
}
for _, rec := range squ.Channels {
var cardItem []*operate.Card
tagm[rec.ID] = &tag.Tag{
ID: rec.ID,
Name: rec.Name,
Cover: rec.Cover,
Content: rec.ShortContent,
Type: int8(rec.Type),
State: int8(rec.State),
IsAtten: int8(rec.Attention),
}
tagm[rec.ID].Count.Atten = int(rec.Sub)
for _, oidItem := range chanOids[rec.ID] {
if len(cardItem) >= 2 {
break
}
if _, ok := am[oidItem.Oid]; !ok {
continue
}
cardItem = append(cardItem, &operate.Card{ID: oidItem.Oid, FromType: oidItem.FromType})
}
if len(cardItem) < 2 {
continue
}
var (
h = cardm.Handle(plat, cdm.CardGt("channel_square"), "channel_square", cdm.ColumnSvrSingle, nil, tagm, nil, nil, nil)
)
if h == nil {
continue
}
op := &operate.Card{
ID: rec.ID,
Items: cardItem,
Plat: plat,
Param: strconv.FormatInt(rec.ID, 10),
}
h.From(am, op)
if h.Get() != nil && h.Get().Right {
res.Square = append(res.Square, h)
}
}
return
})
}
eg.Wait()
return
}
// Mysub 我订阅的tag standard放前面用户自定义custom放后面
func (s *Service) Mysub(c context.Context, mid int64, limit int) (res *channel.Mysub, err error) {
var (
tinfo []*tag.TagInfo
subChannel []*channel.Channel
)
res = new(channel.Mysub)
list, err := s.tg.Subscribe(c, mid)
if err != nil {
log.Error("%+v", err)
return
}
tinfo = list.Standard
tinfo = append(tinfo, list.Custom...)
if len(tinfo) > 0 {
for _, chann := range tinfo {
subChannel = append(subChannel, &channel.Channel{
ID: chann.ID,
Name: chann.Name,
Cover: chann.Cover,
Atten: chann.Sub,
IsAtten: chann.Attention,
Content: chann.Content,
})
}
if len(subChannel) > limit && limit > 0 {
subChannel = subChannel[:limit]
}
}
res.List = subChannel
res.DisplayCount = _maxAtten
return
}
func (s *Service) isOverseas(plat int8) (res int32) {
if ok := model.IsOverseas(plat); ok {
res = 1
} else {
res = 0
}
return
}
func (s *Service) tablist(t *tag.ChannelDetail) (res []*channel.TabList) {
res = s.defaultTab(t)
var (
mpos []int
tmpmenus = map[int]*tab.Menu{}
menus = s.menuCache[t.Tag.ID]
menusTabIDs = map[int64]struct{}{}
)
if len(menus) == 0 {
return
}
for _, m := range menus {
tmpmenus[m.Priority] = m
mpos = append(mpos, m.Priority)
}
for _, pos := range mpos {
var (
tmpm *tab.Menu
ok bool
)
if tmpm, ok = tmpmenus[pos]; !ok || pos == 0 {
continue
}
if _, ok := menusTabIDs[tmpm.TabID]; !ok {
menusTabIDs[tmpm.TabID] = struct{}{}
} else {
continue
}
tl := &channel.TabList{}
tl.TabListChange(tmpm)
if len(res) < pos {
res = append(res, tl)
continue
}
res = append(res[:pos-1], append([]*channel.TabList{tl}, res[pos-1:]...)...)
}
return
}
func (s *Service) defaultTab(t *tag.ChannelDetail) (res []*channel.TabList) {
for _, tmp := range _tabList {
r := &channel.TabList{}
*r = *tmp
switch tmp.TabID {
case "multiple":
r.URI = fmt.Sprintf(r.URI, t.Tag.ID)
case "topic":
r.URI = fmt.Sprintf(r.URI, t.Tag.ID, url.QueryEscape(t.Tag.Name))
}
res = append(res, r)
}
return
}

View File

@@ -0,0 +1,116 @@
package channel
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/app-channel/conf"
"go-common/app/interface/main/app-channel/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func WithService(f func(s *Service)) func() {
return func() {
f(s)
}
}
func init() {
dir, _ := filepath.Abs("../../cmd/app-channel-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}
func TestTab(t *testing.T) {
Convey("get Tab data", t, WithService(func(s *Service) {
res, err := s.Tab(context.TODO(), 1, 1, "", 1)
So(res, ShouldNotBeEmpty)
So(err, ShouldBeNil)
}))
}
func TestSubscribeAdd(t *testing.T) {
Convey("get SubscribeAdd data", t, WithService(func(s *Service) {
err := s.SubscribeAdd(context.TODO(), 1, 1, time.Now())
So(err, ShouldBeNil)
}))
}
func TestSubscribeCancel(t *testing.T) {
Convey("get SubscribeCancel data", t, WithService(func(s *Service) {
err := s.SubscribeCancel(context.TODO(), 1, 1, time.Now())
So(err, ShouldBeNil)
}))
}
func TestSubscribeUpdate(t *testing.T) {
Convey("get SubscribeUpdate data", t, WithService(func(s *Service) {
err := s.SubscribeUpdate(context.TODO(), 1, "")
So(err, ShouldBeNil)
}))
}
func TestList(t *testing.T) {
Convey("get List data", t, WithService(func(s *Service) {
res, err := s.List(context.TODO(), 1, model.PlatIPhone, 1, 1, "", "iphone", "phone", "hans")
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestRecommend(t *testing.T) {
Convey("get Recommend data", t, WithService(func(s *Service) {
res, err := s.Recommend(context.TODO(), 1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestSubscribe(t *testing.T) {
Convey("get Subscribe data", t, WithService(func(s *Service) {
res, err := s.Subscribe(context.TODO(), 1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestDiscover(t *testing.T) {
Convey("get Discover data", t, WithService(func(s *Service) {
res, err := s.Discover(context.TODO(), 1, 1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestCategory(t *testing.T) {
Convey("get Category data", t, WithService(func(s *Service) {
res, err := s.Category(context.TODO(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestRegionList(t *testing.T) {
Convey("get RegionList data", t, WithService(func(s *Service) {
_, _, _, err := s.RegionList(context.TODO(), model.PlatIPhone, 1, "iphone", "device", "hans")
So(err, ShouldBeNil)
}))
}
func TestIndex(t *testing.T) {
Convey("get Index data", t, WithService(func(s *Service) {
res, err := s.Index(context.TODO(), 1, 1, 1, model.PlatIPhone, "", "", "", "", 1, 1, 1, 0, 0, 0, false, time.Now())
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}

View File

@@ -0,0 +1,666 @@
package channel
import (
"context"
"fmt"
"strconv"
"time"
cdm "go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card/audio"
"go-common/app/interface/main/app-card/model/card/bangumi"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
shopping "go-common/app/interface/main/app-card/model/card/show"
"go-common/app/interface/main/app-channel/model"
"go-common/app/interface/main/app-channel/model/activity"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/feed"
bustag "go-common/app/interface/main/tag/model"
tag "go-common/app/interface/main/tag/model"
article "go-common/app/interface/openplatform/article/model"
account "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/model/archive"
relation "go-common/app/service/main/relation/model"
episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
var (
_emptyItem = []*feed.Item{}
)
// Index channel index
func (s *Service) Index(c context.Context, mid, channelID, idx int64, plat int8, mobiApp, device, buvid, channelName string, build, loginEvent, displayID, qn, fnver, fnval int, pull bool, now time.Time) (res *feed.Show, err error) {
var (
aids []int64
requestCnt = 10
isIpad = plat == model.PlatIPad
topic *feed.Item
item []*feed.Item
channelResource *tag.ChannelResource
topChannel, isRec int
)
if isIpad {
requestCnt = 20
}
if channelID > 0 {
channelName = ""
}
g, ctx := errgroup.WithContext(c)
g.Go(func() (err error) {
if channelResource, err = s.tg.Resources(ctx, plat, channelID, mid, channelName, buvid, build, requestCnt, loginEvent, displayID); err != nil {
log.Error("index s.tg.Resources error(%v)", err)
return
}
if channelResource != nil {
aids = channelResource.Oids
if channelResource.Failover {
isRec = 0
} else {
isRec = 1
}
if channelResource.IsChannel {
topChannel = 1
} else {
topChannel = 0
}
}
return
})
g.Go(func() (err error) {
var t *tag.ChannelDetail
if t, err = s.tg.ChannelDetail(c, mid, channelID, channelName, s.isOverseas(plat)); err != nil {
log.Error("s.tag.ChannelDetail(%d, %d, %s) error(%v)", mid, channelID, channelName, err)
return
}
channelID = t.Tag.ID
channelName = t.Tag.Name
return
})
if err = g.Wait(); err != nil {
if (mobiApp == "iphone" && build > 8050) || (mobiApp == "android" && build > 5305000) {
log.Error("%+v", err)
res = &feed.Show{
Feed: _emptyItem,
}
return
}
err = nil
}
if loginEvent == 1 || loginEvent == 2 {
if cards, ok := s.cardCache[channelID]; ok {
topic, item, err = s.dealItem(c, mid, idx, channelID, plat, build, qn, fnver, fnval, mobiApp, buvid, pull, now, cards, aids)
} else {
item, err = s.feedItem(c, plat, aids, mobiApp, qn, fnver, fnval, build)
}
} else {
item, err = s.feedItem(c, plat, aids, mobiApp, qn, fnver, fnval, build)
}
res = &feed.Show{
Topic: topic,
Feed: item,
}
//infoc
infoc := &feedInfoc{
mobiApp: mobiApp,
device: device,
build: strconv.Itoa(build),
now: now.Format("2006-01-02 15:04:05"),
pull: strconv.FormatBool(pull),
loginEvent: strconv.Itoa(loginEvent),
channelID: strconv.FormatInt(channelID, 10),
channelName: channelName,
mid: strconv.FormatInt(mid, 10),
buvid: buvid,
displayID: strconv.Itoa(displayID),
feed: res,
isRec: strconv.Itoa(isRec),
topChannel: strconv.Itoa(topChannel),
ServerCode: "0",
}
s.infoc(infoc)
return
}
// dealItem
func (s *Service) dealItem(c context.Context, mid, idx, channelID int64, plat int8, build, qn, fnver, fnval int, mobiApp, buvid string, pull bool, now time.Time, cards []*card.Card, listAID []int64) (top *feed.Item, is []*feed.Item, err error) {
if len(cards) == 0 {
is = _emptyItem
return
}
var (
aids, sids, roomIDs, metaIDs, shopIDs, audioIDs []int64
upIDs, tids, avUpIDs, rmUpIDs, mtUpIDs []int64
seasonIDs []int32
am map[int64]*archive.ArchiveWithPlayer
tagm map[int64]*bustag.Tag
follows map[int64]bool
rm map[int64]*live.Room
sm map[int64]*bangumi.Season
actIDs, topIDs []int64
actm, topm map[int64]*activity.Activity
atm map[int64]*article.Meta
scm map[int64]*shopping.Shopping
aum map[int64]*audio.Audio
infocard map[int64]*account.Card
upStatm map[int64]*relation.Stat
cardAids = map[int64]struct{}{}
channelCards []*card.Card
seasonCards map[int32]*episodegrpc.EpisodeCardsProto
// key
_initCardPlatKey = "card_platkey_%d_%d"
_fTypeOperation = "operation"
_fTypeRecommend = "recommend"
)
convergem := map[int64]*operate.Converge{}
downloadm := map[int64]*operate.Download{}
liveUpm := map[int64][]*live.Card{}
followm := map[int64]*operate.Follow{}
LOOP:
for _, c := range cards {
key := fmt.Sprintf(_initCardPlatKey, plat, c.ID)
if cardPlat, ok := s.cardPlatCache[key]; ok {
for _, l := range cardPlat {
if model.InvalidBuild(build, l.Build, l.Condition) {
continue LOOP
}
}
} else {
continue LOOP
}
channelCards = append(channelCards, c)
switch c.Type {
case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv:
if c.Value != 0 {
aids = append(aids, c.Value)
cardAids[c.Value] = struct{}{}
}
case model.GotoLive, model.GotoPlayerLive:
if c.Value != 0 {
roomIDs = append(roomIDs, c.Value)
}
case model.GotoBangumi:
if c.Value != 0 {
sids = append(sids, c.Value)
}
case model.GotoPGC:
if c.Value != 0 {
seasonIDs = append(seasonIDs, int32(c.Value))
}
case model.GotoActivity:
if c.Value != 0 {
actIDs = append(actIDs, c.Value)
}
case model.GotoTopic:
if c.Value != 0 {
topIDs = append(topIDs, c.Value)
}
case model.GotoConverge:
if card, ok := s.convergeCardCache[c.Value]; ok {
for _, item := range card.Items {
switch item.Goto {
case model.GotoAv:
if item.Pid != 0 {
aids = append(aids, item.Pid)
}
case model.GotoLive:
if item.Pid != 0 {
roomIDs = append(roomIDs, item.Pid)
}
case model.GotoArticle:
if item.Pid != 0 {
metaIDs = append(metaIDs, item.Pid)
}
}
}
convergem[c.Value] = card
}
case model.GotoGameDownload, model.GotoGameDownloadS:
if card, ok := s.gameDownloadCache[c.Value]; ok {
downloadm[c.Value] = card
}
case model.GotoArticle, model.GotoArticleS:
if c.Value != 0 {
metaIDs = append(metaIDs, c.Value)
}
case model.GotoShoppingS:
if c.Value != 0 {
shopIDs = append(shopIDs, c.Value)
}
case model.GotoAudio:
if c.Value != 0 {
audioIDs = append(audioIDs, c.Value)
}
case model.GotoLiveUpRcmd:
if c.Value != 0 {
if cs, ok := s.liveCardCache[c.Value]; ok {
for _, c := range cs {
upIDs = append(upIDs, c.UID)
}
}
}
case model.GotoSubscribe:
if c.Value != 0 {
if card, ok := s.upCardCache[c.Value]; ok {
for _, item := range card.Items {
switch item.Goto {
case cdm.GotoMid:
if item.Pid != 0 {
upIDs = append(upIDs, item.Pid)
}
case cdm.GotoTag:
if item.Pid != 0 {
tids = append(tids, item.Pid)
}
}
}
followm[c.Value] = card
}
}
case model.GotoChannelRcmd:
if c.Value != 0 {
if card, ok := s.upCardCache[c.Value]; ok {
if card.Pid != 0 {
aids = append(aids, card.Pid)
}
if card.Tid != 0 {
tids = append(tids, card.Tid)
}
followm[c.Value] = card
}
}
}
}
if len(listAID) != 0 {
aids = append(aids, listAID...)
}
g, ctx := errgroup.WithContext(c)
if len(aids) != 0 {
g.Go(func() (err error) {
if am, err = s.ArchivesWithPlayer(ctx, aids, qn, mobiApp, fnver, fnval, build); err != nil {
return
}
for _, a := range am {
avUpIDs = append(avUpIDs, a.Author.Mid)
}
return
})
}
if len(tids) != 0 {
g.Go(func() (err error) {
if tagm, err = s.tg.InfoByIDs(ctx, mid, tids); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(roomIDs) != 0 {
g.Go(func() (err error) {
if rm, err = s.lv.AppMRoom(ctx, roomIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, r := range rm {
rmUpIDs = append(rmUpIDs, r.UID)
}
return
})
}
if len(sids) != 0 {
g.Go(func() (err error) {
if sm, err = s.bgm.Seasons(ctx, sids, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(seasonIDs) != 0 {
g.Go(func() (err error) {
if seasonCards, err = s.bgm.EpidsCardsInfoReply(ctx, seasonIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(metaIDs) != 0 {
g.Go(func() (err error) {
if atm, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, at := range atm {
if at.Author != nil {
mtUpIDs = append(mtUpIDs, at.Author.Mid)
}
}
return
})
}
if len(shopIDs) != 0 {
g.Go(func() (err error) {
if scm, err = s.sp.Card(ctx, shopIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(audioIDs) != 0 {
g.Go(func() (err error) {
if aum, err = s.audio.Audios(ctx, audioIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(actIDs) != 0 {
g.Go(func() (err error) {
if actm, err = s.act.Activitys(ctx, actIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(topIDs) != 0 {
g.Go(func() (err error) {
if topm, err = s.act.Activitys(ctx, topIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
upIDs = append(upIDs, avUpIDs...)
upIDs = append(upIDs, rmUpIDs...)
upIDs = append(upIDs, mtUpIDs...)
g, ctx = errgroup.WithContext(c)
if len(upIDs) != 0 {
g.Go(func() (err error) {
if infocard, err = s.acc.Cards3(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if upStatm, err = s.rel.Stats(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if mid != 0 {
g.Go(func() error {
follows = s.acc.Relations3(ctx, upIDs, mid)
return nil
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
for _, c := range channelCards {
i := &feed.Item{}
i.Pos = c.Pos
i.FromType = _fTypeOperation
switch c.Type {
case model.GotoAv, model.GotoUpRcmdAv:
a := am[c.Value]
isOsea := model.IsOverseas(plat)
if a != nil && a.IsNormal() && (!isOsea || (isOsea && a.AttrVal(archive.AttrBitOverseaLock) == 0)) {
i.FromPlayerAv(a)
i.FromDislikeReason()
i.FromRcmdReason(c)
if follows[i.Mid] {
i.IsAtten = 1
if i.RcmdReason != nil && i.RcmdReason.Content == "已关注" {
i.RcmdReason.Content = ""
}
}
//for GotoUpRcmdAv
i.Goto = c.Type
is = append(is, i)
}
case model.GotoLive:
if r, ok := rm[c.Value]; ok {
i.FromLive(r)
if card, ok := infocard[i.Mid]; ok {
if card.Official.Role != 0 {
i.Official = &feed.OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
}
}
if stat, ok := upStatm[i.Mid]; ok {
i.Fans = stat.Follower
}
if follows[i.Mid] {
i.IsAtten = 1
}
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoBangumi:
if s, ok := sm[c.Value]; ok {
i.FromSeason(s)
is = append(is, i)
}
case model.GotoPGC:
if s, ok := seasonCards[int32(c.Value)]; ok {
i.FromPGCSeason(s)
is = append(is, i)
}
case model.GotoActivity:
if act, ok := actm[c.Value]; ok && act.H5Cover != "" && act.H5URL != "" {
i.FromActivity(act, now)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoTopic:
if top, ok := topm[c.Value]; ok && top.H5Cover != "" && top.H5URL != "" {
i.FromTopic(top)
is = append(is, i)
}
case model.GotoSpecial:
if sc, ok := s.specialCardCache[c.Value]; ok {
i.FromSpecial(sc.ID, sc.Title, sc.Cover, sc.Desc, sc.ReValue, sc.ReType, sc.Badge, sc.Size)
}
if i.Goto != "" {
is = append(is, i)
}
case model.GotoSpecialS:
if sc, ok := s.specialCardCache[c.Value]; ok {
i.FromSpecialS(sc.ID, sc.Title, sc.Cover, sc.Desc, sc.ReValue, sc.ReType, sc.Badge)
}
if i.Goto != "" {
is = append(is, i)
}
case model.GotoTopstick:
if sc, ok := s.specialCardCache[c.Value]; ok {
i.FromTopstick(sc.ID, sc.Title, sc.Cover, sc.Desc, sc.ReValue, sc.ReType)
top = i
}
case model.GotoConverge:
if cc, ok := convergem[c.Value]; ok {
i.FromConverge(cc, am, rm, atm)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoGameDownload:
if gd, ok := downloadm[c.Value]; ok {
i.FromGameDownload(gd, plat, build)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoGameDownloadS:
if gd, ok := downloadm[c.Value]; ok {
i.FromGameDownloadS(gd, plat, build)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoArticle:
if m, ok := atm[c.Value]; ok {
i.FromArticle(m)
if card, ok := infocard[i.Mid]; ok {
if card.Official.Role != 0 {
i.Official = &feed.OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
}
}
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoArticleS:
if m, ok := atm[c.Value]; ok {
i.FromArticleS(m)
if card, ok := infocard[i.Mid]; ok {
if card.Official.Role != 0 {
i.Official = &feed.OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
}
}
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoShoppingS:
if c, ok := scm[c.Value]; ok {
i.FromShoppingS(c)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoAudio:
if au, ok := aum[c.Value]; ok {
i.FromAudio(au)
is = append(is, i)
}
case model.GotoPlayer:
if a, ok := am[c.Value]; ok {
i.FromPlayer(a)
if i.Goto != "" {
if follows[i.Mid] {
i.IsAtten = 1
}
if card, ok := infocard[i.Mid]; ok {
if card.Official.Role != 0 {
i.Official = &feed.OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
}
}
i.FromDislikeReason()
is = append(is, i)
}
}
case model.GotoPlayerLive:
if r, ok := rm[c.Value]; ok {
i.FromPlayerLive(r)
if i.Goto != "" {
if follows[i.Mid] {
i.IsAtten = 1
}
if card, ok := infocard[i.Mid]; ok {
if card.Official.Role != 0 {
i.Official = &feed.OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
}
}
if stat, ok := upStatm[i.Mid]; ok {
i.Fans = stat.Follower
}
is = append(is, i)
}
}
case model.GotoSubscribe:
if c, ok := followm[c.Value]; ok {
i.FromSubscribe(c, infocard, follows, upStatm, tagm)
is = append(is, i)
}
case model.GotoChannelRcmd:
if c, ok := followm[c.Value]; ok {
i.FromChannelRcmd(c, am, tagm)
is = append(is, i)
}
case model.GotoLiveUpRcmd:
if l, ok := liveUpm[c.Value]; ok {
i.FromLiveUpRcmd(c.Value, l, infocard)
is = append(is, i)
}
}
}
if len(listAID) > 0 {
isOsea := model.IsOverseas(plat)
for _, aid := range listAID {
if _, ok := cardAids[aid]; ok {
continue
}
i := &feed.Item{}
a := am[aid]
if a != nil && a.IsNormal() && (!isOsea || (isOsea && a.AttrVal(archive.AttrBitOverseaLock) == 0)) {
i.FromType = _fTypeRecommend
i.FromPlayerAv(a)
i.FromDislikeReason()
//for GotoUpRcmdAv
i.Goto = model.GotoAv
is = append(is, i)
}
}
}
rl := len(is)
if rl == 0 {
is = _emptyItem
return
}
if idx == 0 {
idx = now.Unix()
}
for i, r := range is {
if pull {
r.Idx = idx + int64(rl-i)
} else {
r.Idx = idx - int64(i+1)
}
}
return
}
func (s *Service) feedItem(c context.Context, plat int8, cids []int64, mobiApp string, qn, fnver, fnval, build int) (is []*feed.Item, err error) {
var (
channelids map[int64]*archive.ArchiveWithPlayer
_fTypeRecommend = "recommend"
)
if len(cids) == 0 {
is = _emptyItem
return
}
if channelids, err = s.ArchivesWithPlayer(c, cids, qn, mobiApp, fnver, fnval, build); err != nil {
return
}
if len(channelids) > 0 {
isOsea := model.IsOverseas(plat)
for _, aid := range cids {
i := &feed.Item{}
i.FromType = _fTypeRecommend
a := channelids[aid]
if a != nil && a.IsNormal() && (!isOsea || (isOsea && a.AttrVal(archive.AttrBitOverseaLock) == 0)) {
i.FromPlayerAv(a)
i.FromDislikeReason()
i.Goto = model.GotoAv
is = append(is, i)
}
}
}
return
}

View File

@@ -0,0 +1,599 @@
package channel
import (
"context"
"encoding/json"
"fmt"
"strconv"
"sync"
"time"
cdm "go-common/app/interface/main/app-card/model"
cardm "go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/audio"
"go-common/app/interface/main/app-card/model/card/bangumi"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
shopping "go-common/app/interface/main/app-card/model/card/show"
"go-common/app/interface/main/app-channel/model"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/feed"
tag "go-common/app/interface/main/tag/model"
article "go-common/app/interface/openplatform/article/model"
account "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/model/archive"
relation "go-common/app/service/main/relation/model"
episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
"go-common/library/log"
"go-common/library/sync/errgroup"
farm "github.com/dgryski/go-farm"
)
const (
_fTypeOperation = "operation"
_fTypeRecommend = "recommend"
)
// Index channel index
func (s *Service) Index2(c context.Context, mid, channelID, idx int64, plat int8, mobiApp, device, buvid, channelName, ip string,
build, loginEvent, displayID, qn, fnver, fnval int, pull bool, now time.Time) (res *feed.Show2, err error) {
var (
aiCards []*card.Card
requestCnt = 10
isIpad = plat == model.PlatIPad
topic cardm.Handler
item []cardm.Handler
channelResource *tag.ChannelResource
topChannel, isRec int
infocs []*feed.Item
)
if isIpad {
requestCnt = 20
}
if channelID > 0 {
channelName = ""
}
g, ctx := errgroup.WithContext(c)
g.Go(func() (err error) {
if channelResource, err = s.tg.Resources(ctx, plat, channelID, mid, channelName, buvid, build, requestCnt, loginEvent, displayID); err != nil {
log.Error("index s.tg.Resources error(%v)", err)
return
}
if channelResource != nil {
aids := channelResource.Oids
for _, aid := range aids {
t := &card.Card{
Type: model.GotoAv,
Value: aid,
FromType: _fTypeRecommend,
}
aiCards = append(aiCards, t)
}
if channelResource.Failover {
isRec = 0
} else {
isRec = 1
}
if channelResource.IsChannel {
topChannel = 1
} else {
topChannel = 0
}
}
return
})
g.Go(func() (err error) {
var t *tag.ChannelDetail
if t, err = s.tg.ChannelDetail(c, mid, channelID, channelName, s.isOverseas(plat)); err != nil {
log.Error("s.tag.ChannelDetail(%d, %d, %s) error(%v)", mid, channelID, channelName, err)
return
}
channelID = t.Tag.ID
channelName = t.Tag.Name
return
})
err = g.Wait()
//infoc
infoc := &feedInfoc{
mobiApp: mobiApp,
device: device,
build: strconv.Itoa(build),
now: now.Format("2006-01-02 15:04:05"),
pull: strconv.FormatBool(pull),
loginEvent: strconv.Itoa(loginEvent),
channelID: strconv.FormatInt(channelID, 10),
channelName: channelName,
mid: strconv.FormatInt(mid, 10),
buvid: buvid,
displayID: strconv.Itoa(displayID),
isRec: strconv.Itoa(isRec),
topChannel: strconv.Itoa(topChannel),
ServerCode: "0",
}
//infoc
if err != nil {
log.Error("RankUser errgroup.WithContext error(%v)", err)
res = &feed.Show2{
Feed: []cardm.Handler{},
}
infoc.Items = []*feed.Item{}
infoc.ServerCode = err.Error()
s.infoc(infoc)
return
}
var (
tmps = []*card.Card{}
)
if loginEvent == 1 || loginEvent == 2 {
if cards, ok := s.cardCache[channelID]; ok {
isShowCard := s.isShowOperationCards(c, buvid, channelID, cards, now)
for _, c := range cards {
if !isShowCard && c.Type != model.GotoTopstick {
continue
}
t := &card.Card{}
*t = *c
t.FromType = _fTypeOperation
tmps = append(tmps, t)
}
tmps = append(tmps, aiCards...)
} else {
tmps = aiCards
}
} else {
tmps = aiCards
}
topic, item, infocs, err = s.dealItem2(c, mid, idx, channelID, plat, build, buvid, ip, mobiApp, pull, qn, fnver, fnval, now, tmps)
res = &feed.Show2{
Topic: topic,
Feed: item,
}
infoc.Items = infocs
s.infoc(infoc)
return
}
// dealItem
func (s *Service) dealItem2(c context.Context, mid, idx, channelID int64, plat int8, build int, buvid, ip, mobiApp string, pull bool,
qn, fnver, fnval int, now time.Time, cards []*card.Card) (top cardm.Handler, is []cardm.Handler, infocs []*feed.Item, err error) {
if len(cards) == 0 {
is = []cardm.Handler{}
return
}
var (
aids, shopIDs, audioIDs, sids, roomIDs, metaIDs []int64
upIDs, tids, rmUpIDs, mtUpIDs, avUpIDs, avUpCountIDs []int64
seasonIDs, epIDs []int32
am map[int64]*archive.ArchiveWithPlayer
tagm map[int64]*tag.Tag
rm map[int64]*live.Room
sm map[int64]*bangumi.Season
metam map[int64]*article.Meta
shopm map[int64]*shopping.Shopping
audiom map[int64]*audio.Audio
cardAids = map[int64]struct{}{}
ac map[int64]*account.Card
statm map[int64]*relation.Stat
isAtten map[int64]int8
upAvCount = map[int64]int{}
channelCards []*card.Card
seasonm map[int32]*seasongrpc.CardInfoProto
epidsCards map[int32]*episodegrpc.EpisodeCardsProto
// key
_initCardPlatKey = "card_platkey_%d_%d"
)
specialm := map[int64]*operate.Card{}
convergem := map[int64]*operate.Card{}
downloadm := map[int64]*operate.Card{}
followm := map[int64]*operate.Card{}
liveUpm := map[int64][]*live.Card{}
cardSet := map[int64]*operate.Card{}
LOOP:
for _, card := range cards {
key := fmt.Sprintf(_initCardPlatKey, plat, card.ID)
if cardPlat, ok := s.cardPlatCache[key]; ok {
for _, l := range cardPlat {
if model.InvalidBuild(build, l.Build, l.Condition) {
continue LOOP
}
}
} else if card.FromType == _fTypeOperation {
continue LOOP
}
channelCards = append(channelCards, card)
switch card.Type {
case model.GotoAv, model.GotoPlayer, model.GotoUpRcmdAv:
if card.Value != 0 {
aids = append(aids, card.Value)
cardAids[card.Value] = struct{}{}
}
case model.GotoLive, model.GotoPlayerLive:
if card.Value != 0 {
roomIDs = append(roomIDs, card.Value)
}
case model.GotoBangumi:
if card.Value != 0 {
sids = append(sids, card.Value)
}
case model.GotoPGC:
if card.Value != 0 {
epIDs = append(epIDs, int32(card.Value))
}
case model.GotoConverge:
if card.Value != 0 {
cardm, aid, roomID, metaID := s.convergeCard2(c, 3, card.Value)
for id, card := range cardm {
convergem[id] = card
}
aids = append(aids, aid...)
roomIDs = append(roomIDs, roomID...)
metaIDs = append(metaIDs, metaID...)
}
case model.GotoGameDownload, model.GotoGameDownloadS:
if card.Value != 0 {
cardm := s.downloadCard(c, card.Value)
for id, card := range cardm {
downloadm[id] = card
}
}
case model.GotoArticle, model.GotoArticleS:
if card.Value != 0 {
metaIDs = append(metaIDs, card.Value)
}
case model.GotoShoppingS:
if card.Value != 0 {
shopIDs = append(shopIDs, card.Value)
}
case model.GotoAudio:
if card.Value != 0 {
audioIDs = append(audioIDs, card.Value)
}
case model.GotoChannelRcmd:
cardm, aid, tid := s.channelRcmdCard(c, card.Value)
for id, card := range cardm {
followm[id] = card
}
aids = append(aids, aid...)
tids = append(tids, tid...)
case model.GotoLiveUpRcmd:
if card.Value != 0 {
cardm, upID := s.liveUpRcmdCard(c, card.Value)
for id, card := range cardm {
liveUpm[id] = card
}
upIDs = append(upIDs, upID...)
}
case model.GotoSubscribe:
if card.Value != 0 {
cardm, upID, tid := s.subscribeCard(c, card.Value)
for id, card := range cardm {
followm[id] = card
}
upIDs = append(upIDs, upID...)
tids = append(tids, tid...)
}
case model.GotoSpecial, model.GotoSpecialS:
cardm := s.specialCard(c, card.Value)
for id, card := range cardm {
specialm[id] = card
}
case model.GotoTopstick:
cardm := s.topstickCard(c, card.Value)
for id, card := range cardm {
specialm[id] = card
}
case model.GotoPgcsRcmd:
cardm, ssid := s.cardSetChange(c, card.Value)
seasonIDs = append(seasonIDs, ssid...)
for id, card := range cardm {
cardSet[id] = card
}
case model.GotoUpRcmdS:
if card.Value != 0 {
avUpCountIDs = append(avUpCountIDs, card.Value)
}
}
}
g, ctx := errgroup.WithContext(c)
if len(aids) != 0 {
g.Go(func() (err error) {
if am, err = s.ArchivesWithPlayer(ctx, aids, qn, mobiApp, fnver, fnval, build); err != nil {
return
}
for _, a := range am {
avUpIDs = append(avUpIDs, a.Author.Mid)
}
return
})
}
if len(tids) != 0 {
g.Go(func() (err error) {
if tagm, err = s.tg.InfoByIDs(ctx, mid, tids); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(roomIDs) != 0 {
g.Go(func() (err error) {
if rm, err = s.lv.AppMRoom(ctx, roomIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, r := range rm {
rmUpIDs = append(rmUpIDs, r.UID)
}
return
})
}
if len(sids) != 0 {
g.Go(func() (err error) {
if sm, err = s.bgm.Seasons(ctx, sids, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(seasonIDs) != 0 {
g.Go(func() (err error) {
if seasonm, err = s.bgm.CardsInfoReply(ctx, seasonIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(epIDs) != 0 {
g.Go(func() (err error) {
if epidsCards, err = s.bgm.EpidsCardsInfoReply(ctx, epIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(metaIDs) != 0 {
g.Go(func() (err error) {
if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, meta := range metam {
if meta.Author != nil {
mtUpIDs = append(mtUpIDs, meta.Author.Mid)
}
}
return
})
}
if len(shopIDs) != 0 {
g.Go(func() (err error) {
if shopm, err = s.sp.Card(ctx, shopIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(audioIDs) != 0 {
g.Go(func() (err error) {
if audiom, err = s.audio.Audios(ctx, audioIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(avUpCountIDs) != 0 {
var mutex sync.Mutex
for _, upid := range avUpCountIDs {
var (
tmpupid = upid
)
g.Go(func() (err error) {
var cnt int
if cnt, err = s.arc.UpCount2(ctx, tmpupid); err != nil {
log.Error("%+v", err)
err = nil
}
mutex.Lock()
upAvCount[tmpupid] = cnt
mutex.Unlock()
return
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
upIDs = append(upIDs, avUpIDs...)
upIDs = append(upIDs, rmUpIDs...)
upIDs = append(upIDs, mtUpIDs...)
upIDs = append(upIDs, avUpCountIDs...)
g, ctx = errgroup.WithContext(c)
if len(upIDs) != 0 {
g.Go(func() (err error) {
if ac, err = s.acc.Cards3(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if statm, err = s.rel.Stats(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if mid != 0 {
g.Go(func() error {
isAtten = s.acc.IsAttention(ctx, upIDs, mid)
return nil
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
for _, card := range channelCards {
var (
r = card.CardToAiChange()
main interface{}
)
switch r.Goto {
case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer:
r.HideButton = true
}
h := cardm.Handle(plat, cdm.CardGt(r.Goto), "", cdm.ColumnSvrSingle, r, tagm, isAtten, statm, ac)
if h == nil {
continue
}
op := &operate.Card{}
op.From(cdm.CardGt(r.Goto), r.ID, 0, plat, build)
switch r.Goto {
case model.GotoAv, model.GotoUpRcmdAv, model.GotoPlayer:
op.ShowUGCPay = true
if a, ok := am[r.ID]; ok && (a.AttrVal(archive.AttrBitOverseaLock) == 0 || !model.IsOverseas(plat)) {
main = am
}
op.Switch = cdm.SwitchCooperationHide
case model.GotoLive, model.GotoPlayerLive:
main = rm
case model.GotoBangumi:
main = sm
case model.GotoPGC:
main = epidsCards
case model.GotoSpecial, model.GotoSpecialS, model.GotoTopstick:
op = specialm[r.ID]
case model.GotoGameDownload, model.GotoGameDownloadS:
op = downloadm[r.ID]
case model.GotoArticle, model.GotoArticleS:
main = metam
case model.GotoShoppingS:
main = shopm
case model.GotoAudio:
main = audiom
case model.GotoChannelRcmd:
main = am
op = followm[r.ID]
case model.GotoSubscribe:
op = followm[r.ID]
case model.GotoLiveUpRcmd:
main = liveUpm
case model.GotoConverge:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoLive: rm, cdm.GotoArticle: metam}
op = convergem[r.ID]
case model.GotoPgcsRcmd:
main = seasonm
op = cardSet[r.ID]
case model.GotoUpRcmdS:
op.Limit = upAvCount[r.ID]
}
h.From(main, op)
if h.Get() == nil {
continue
}
h.Get().FromType = card.FromType
if h.Get().Right {
switch card.FromType {
case _fTypeOperation:
h.Get().ThreePointWatchLater()
case _fTypeRecommend:
h.Get().ThreePointChannel()
}
switch r.Goto {
case model.GotoTopstick:
top = h
default:
is = append(is, h)
}
}
// infoc
tinfo := &feed.Item{
Goto: card.Type,
Param: strconv.FormatInt(card.Value, 10),
URI: h.Get().URI,
FromType: card.FromType,
}
infocs = append(infocs, tinfo)
}
rl := len(is)
if rl == 0 {
is = []cardm.Handler{}
return
}
if idx == 0 {
idx = now.Unix()
}
for i, h := range is {
if pull {
h.Get().Idx = idx + int64(rl-i)
} else {
h.Get().Idx = idx - int64(i+1)
}
}
return
}
// ArchivesWithPlayer archives witch player
func (s *Service) ArchivesWithPlayer(c context.Context, aids []int64, qn int, platform string, fnver, fnval, build int) (res map[int64]*archive.ArchiveWithPlayer, err error) {
if res, err = s.arc.ArchivesWithPlayer(c, aids, qn, platform, fnver, fnval, build); err != nil {
log.Error("%+v", err)
}
if len(res) != 0 {
return
}
am, err := s.arc.Archives(c, aids)
if err != nil {
return
}
if len(am) == 0 {
return
}
res = make(map[int64]*archive.ArchiveWithPlayer, len(am))
for aid, a := range am {
res[aid] = &archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(a)}
}
return
}
// isShowOperationCards is show operation cards by buvid
func (s *Service) isShowOperationCards(c context.Context, buvid string, channelID int64, cards []*card.Card, now time.Time) (isShow bool) {
var (
md5, mcmd5 string
)
g, ctx := errgroup.WithContext(c)
g.Go(func() (err error) {
if mcmd5, err = s.cd.ChannelCardCache(ctx, buvid, channelID); err != nil {
isShow = true
return
}
return nil
})
g.Go(func() (err error) {
md5 = s.hashCards(cards)
return nil
})
g.Wait()
if md5 != mcmd5 {
isShow = true
s.cd.AddChannelCardCache(c, buvid, md5, channelID, now)
}
return
}
func (s *Service) hashCards(v []*card.Card) string {
bs, err := json.Marshal(v)
if err != nil {
log.Error("json.Marshal error(%v)", err)
return ""
}
return strconv.FormatUint(farm.Hash64(bs), 10)
}

View File

@@ -0,0 +1,175 @@
package channel
import (
"bytes"
"strconv"
"time"
"go-common/app/interface/main/app-channel/model/feed"
"go-common/library/log"
"go-common/library/log/infoc"
)
type feedInfoc struct {
mobiApp string
device string
build string
now string
pull string
loginEvent string
channelID string
channelName string
mid string
buvid string
displayID string
feed *feed.Show
Items []*feed.Item
isRec string
topChannel string
ServerCode string
}
type channelOperation struct {
mobiApp string
device string
build string
now string
channelID string
operation string
mid string
from string
}
// OperationInfoc channel operation infoc
func (s *Service) OperationInfoc(mobiApp, device, operation string, build, from int, channelID, mid int64, now time.Time) {
infoc := &channelOperation{
mobiApp: mobiApp,
device: device,
build: strconv.Itoa(build),
now: now.Format("2006-01-02 15:04:05"),
channelID: strconv.FormatInt(channelID, 10),
operation: operation,
mid: strconv.FormatInt(mid, 10),
from: strconv.Itoa(from),
}
s.infoc(infoc)
}
func (s *Service) infoc(i interface{}) {
select {
case s.logCh <- i:
default:
log.Warn("infocproc chan full")
}
}
func (s *Service) infocproc() {
const (
noItem = `[]`
)
var (
msg1 = []byte(`[`)
msg2 = []byte(`{"goto":"`)
msg3 = []byte(`","param":"`)
msg4 = []byte(`","uri":"`)
msg5 = []byte(`","r_pos":`)
msg6 = []byte(`,"from_type":"`)
msg7 = []byte(`"},`)
msg8 = []byte(`]`)
buf bytes.Buffer
list string
feedInf2 = infoc.New(s.c.FeedInfoc2)
channelnf2 = infoc.New(s.c.ChannelInfoc2)
)
for {
i, ok := <-s.logCh
if !ok {
log.Warn("infoc proc exit")
return
}
var pos int
switch l := i.(type) {
case *feedInfoc:
if l.feed != nil {
if f := l.feed; len(f.Feed) == 0 && f.Topic == nil {
list = noItem
} else {
buf.Write(msg1)
if t := f.Topic; t != nil {
buf.Write(msg2)
buf.WriteString(t.Goto)
buf.Write(msg3)
buf.WriteString(t.Param)
buf.Write(msg4)
buf.WriteString(t.URI)
buf.Write(msg5)
pos = t.Pos
buf.WriteString(strconv.Itoa(pos))
buf.Write(msg6)
buf.WriteString(t.FromType)
buf.Write(msg7)
}
if items := f.Feed; len(items) == 0 {
buf.Truncate(buf.Len() - 1)
} else {
for _, item := range items {
buf.Write(msg2)
buf.WriteString(item.Goto)
buf.Write(msg3)
buf.WriteString(item.Param)
buf.Write(msg4)
buf.WriteString(item.URI)
buf.Write(msg5)
if item.Pos == 0 {
pos++
} else {
pos = item.Pos
}
buf.WriteString(strconv.Itoa(pos))
buf.Write(msg6)
buf.WriteString(item.FromType)
buf.Write(msg7)
}
buf.Truncate(buf.Len() - 1)
}
buf.Write(msg8)
list = buf.String()
buf.Reset()
}
} else if items := l.Items; len(items) > 0 {
buf.Write(msg1)
for _, item := range items {
buf.Write(msg2)
buf.WriteString(item.Goto)
buf.Write(msg3)
buf.WriteString(item.Param)
buf.Write(msg4)
buf.WriteString(item.URI)
buf.Write(msg5)
if item.Pos == 0 {
pos++
} else {
pos = item.Pos
}
buf.WriteString(strconv.Itoa(pos))
buf.Write(msg6)
buf.WriteString(item.FromType)
buf.Write(msg7)
}
buf.Truncate(buf.Len() - 1)
buf.Write(msg8)
list = buf.String()
buf.Reset()
} else if len(l.Items) == 0 {
list = noItem
}
log.Info("channel_infoc_index(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)_list(%s)", l.mobiApp, l.device, l.build, l.now, l.pull, l.loginEvent,
l.channelID, l.channelName, l.mid, l.buvid, l.displayID, l.ServerCode, list)
feedInf2.Info(l.mobiApp, l.device, l.build, l.now, l.pull, l.loginEvent, l.channelID, l.channelName, l.mid, l.buvid, l.displayID,
list, "9", l.isRec, l.topChannel, l.ServerCode)
case *channelOperation:
log.Info("channel_infoc_operation_(%s,%s,%s,%s,%s,%s,%s,%s)", l.mobiApp, l.device, l.build, l.now, l.channelID, l.operation, l.mid, l.from)
channelnf2.Info(l.mobiApp, l.device, l.build, l.now, l.channelID, l.operation, l.mid, l.from)
}
}
}

View File

@@ -0,0 +1,177 @@
package channel
import (
"context"
"go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
)
func (s *Service) convergeCard2(c context.Context, limit int, ids ...int64) (cardm map[int64]*operate.Card, aids, roomIDs, metaIDs []int64) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for i, id := range ids {
if o, ok := s.convergeCardCache[id]; ok {
card := &operate.Card{}
card.FromConverge(o)
cardm[id] = card
for _, item := range card.Items {
switch item.Goto {
case model.GotoAv:
if item.ID != 0 {
aids = append(aids, item.ID)
}
case model.GotoLive:
if item.ID != 0 {
roomIDs = append(roomIDs, item.ID)
}
case model.GotoArticle:
if item.ID != 0 {
metaIDs = append(metaIDs, item.ID)
}
}
if i == limit-1 {
break
}
}
}
}
return
}
func (s *Service) downloadCard(c context.Context, ids ...int64) (cardm map[int64]*operate.Card) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if o, ok := s.gameDownloadCache[id]; ok {
card := &operate.Card{}
card.FromDownload(o)
cardm[id] = card
}
}
return
}
func (s *Service) subscribeCard(c context.Context, ids ...int64) (cardm map[int64]*operate.Card, upIDs, tids []int64) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if o, ok := s.upCardCache[id]; ok {
card := &operate.Card{}
card.FromFollow(o)
cardm[id] = card
for _, item := range card.Items {
switch item.Goto {
case model.GotoMid:
if item.ID != 0 {
upIDs = append(upIDs, item.ID)
}
case model.GotoTag:
if item.ID != 0 {
tids = append(tids, item.ID)
}
}
}
}
}
return
}
func (s *Service) channelRcmdCard(c context.Context, ids ...int64) (cardm map[int64]*operate.Card, aids, tids []int64) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if o, ok := s.upCardCache[id]; ok {
card := &operate.Card{}
card.FromFollow(o)
cardm[id] = card
switch card.Goto {
case model.GotoAv:
if card.ID != 0 {
aids = append(aids, card.ID)
}
if card.Tid != 0 {
tids = append(tids, card.Tid)
}
}
}
}
return
}
func (s *Service) liveUpRcmdCard(c context.Context, ids ...int64) (cardm map[int64][]*live.Card, upIDs []int64) {
if len(ids) == 0 {
return
}
cardm = make(map[int64][]*live.Card, len(ids))
for _, id := range ids {
if card, ok := s.liveCardCache[id]; ok {
cardm[id] = card
for _, c := range card {
if c.UID != 0 {
upIDs = append(upIDs, c.UID)
}
}
}
}
return
}
func (s *Service) specialCard(c context.Context, ids ...int64) (cardm map[int64]*operate.Card) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if o, ok := s.specialCardCache[id]; ok {
card := &operate.Card{}
card.FromSpecial(o)
cardm[id] = card
}
}
return
}
func (s *Service) topstickCard(c context.Context, ids ...int64) (cardm map[int64]*operate.Card) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if o, ok := s.specialCardCache[id]; ok {
card := &operate.Card{}
card.FromTopstick(o)
cardm[id] = card
}
}
return
}
func (s *Service) cardSetChange(c context.Context, ids ...int64) (cardm map[int64]*operate.Card, seasonIDs []int32) {
if len(ids) == 0 {
return
}
cardm = make(map[int64]*operate.Card, len(ids))
for _, id := range ids {
if cs, ok := s.cardSetCache[id]; ok {
card := &operate.Card{}
card.FromCardSet(cs)
cardm[id] = card
for _, item := range card.Items {
switch cs.Type {
case "pgcs_rcmd":
seasonIDs = append(seasonIDs, int32(item.ID))
}
}
}
}
return
}

View File

@@ -0,0 +1,152 @@
package channel
import (
"context"
"time"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-channel/conf"
accdao "go-common/app/interface/main/app-channel/dao/account"
actdao "go-common/app/interface/main/app-channel/dao/activity"
arcdao "go-common/app/interface/main/app-channel/dao/archive"
artdao "go-common/app/interface/main/app-channel/dao/article"
audiodao "go-common/app/interface/main/app-channel/dao/audio"
adtdao "go-common/app/interface/main/app-channel/dao/audit"
bgmdao "go-common/app/interface/main/app-channel/dao/bangumi"
carddao "go-common/app/interface/main/app-channel/dao/card"
convergedao "go-common/app/interface/main/app-channel/dao/converge"
gamedao "go-common/app/interface/main/app-channel/dao/game"
livdao "go-common/app/interface/main/app-channel/dao/live"
locdao "go-common/app/interface/main/app-channel/dao/location"
rgdao "go-common/app/interface/main/app-channel/dao/region"
reldao "go-common/app/interface/main/app-channel/dao/relation"
shopdao "go-common/app/interface/main/app-channel/dao/shopping"
specialdao "go-common/app/interface/main/app-channel/dao/special"
tabdao "go-common/app/interface/main/app-channel/dao/tab"
tagdao "go-common/app/interface/main/app-channel/dao/tag"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/channel"
"go-common/app/interface/main/app-channel/model/tab"
)
// Service channel
type Service struct {
c *conf.Config
// dao
acc *accdao.Dao
arc *arcdao.Dao
act *actdao.Dao
art *artdao.Dao
adt *adtdao.Dao
bgm *bgmdao.Dao
audio *audiodao.Dao
rel *reldao.Dao
sp *shopdao.Dao
tg *tagdao.Dao
cd *carddao.Dao
ce *convergedao.Dao
g *gamedao.Dao
sl *specialdao.Dao
rg *rgdao.Dao
lv *livdao.Dao
loc *locdao.Dao
tab *tabdao.Dao
// tick
tick time.Duration
// cache
cardCache map[int64][]*card.Card
cardPlatCache map[string][]*card.CardPlat
upCardCache map[int64]*operate.Follow
convergeCardCache map[int64]*operate.Converge
gameDownloadCache map[int64]*operate.Download
specialCardCache map[int64]*operate.Special
liveCardCache map[int64][]*live.Card
cardSetCache map[int64]*operate.CardSet
menuCache map[int64][]*tab.Menu
// new region list cache
cachelist map[string][]*channel.Region
limitCache map[int64][]*channel.RegionLimit
configCache map[int64][]*channel.RegionConfig
// audit cache
auditCache map[string]map[int]struct{} // audit mobi_app builds
// infoc
logCh chan interface{}
}
// New channel
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
arc: arcdao.New(c),
acc: accdao.New(c),
adt: adtdao.New(c),
art: artdao.New(c),
act: actdao.New(c),
bgm: bgmdao.New(c),
sp: shopdao.New(c),
tg: tagdao.New(c),
cd: carddao.New(c),
ce: convergedao.New(c),
g: gamedao.New(c),
sl: specialdao.New(c),
rg: rgdao.New(c),
audio: audiodao.New(c),
lv: livdao.New(c),
rel: reldao.New(c),
loc: locdao.New(c),
tab: tabdao.New(c),
// tick
tick: time.Duration(c.Tick),
// cache
cardCache: map[int64][]*card.Card{},
cardPlatCache: map[string][]*card.CardPlat{},
upCardCache: map[int64]*operate.Follow{},
convergeCardCache: map[int64]*operate.Converge{},
gameDownloadCache: map[int64]*operate.Download{},
specialCardCache: map[int64]*operate.Special{},
cachelist: map[string][]*channel.Region{},
limitCache: map[int64][]*channel.RegionLimit{},
configCache: map[int64][]*channel.RegionConfig{},
liveCardCache: map[int64][]*live.Card{},
cardSetCache: map[int64]*operate.CardSet{},
menuCache: map[int64][]*tab.Menu{},
// audit cache
auditCache: map[string]map[int]struct{}{},
// infoc
logCh: make(chan interface{}, 1024),
}
s.loadCache()
go s.loadCacheproc()
go s.infocproc()
return
}
func (s *Service) loadCacheproc() {
for {
time.Sleep(s.tick)
s.loadCache()
}
}
func (s *Service) loadCache() {
now := time.Now()
s.loadAuditCache()
s.loadRegionlist()
// card
s.loadCardCache(now)
s.loadConvergeCache()
s.loadSpecialCache()
s.loadLiveCardCache()
s.loadGameDownloadCache()
s.loadCardSetCache()
s.loadMenusCache(now)
}
// Ping is check server ping.
func (s *Service) Ping(c context.Context) (err error) {
if err = s.cd.PingDB(c); err != nil {
return
}
return
}

View File

@@ -0,0 +1,192 @@
package channel
import (
"context"
"time"
cdm "go-common/app/interface/main/app-card/model"
cardm "go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
shopping "go-common/app/interface/main/app-card/model/card/show"
"go-common/app/interface/main/app-channel/model"
"go-common/app/interface/main/app-channel/model/card"
"go-common/app/interface/main/app-channel/model/feed"
article "go-common/app/interface/openplatform/article/model"
account "go-common/app/service/main/account/model"
relation "go-common/app/service/main/relation/model"
seasongrpc "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
func (s *Service) TabList(c context.Context, channelID, mid int64, channelName, mobiApp string, displayID, build, from int, plat int8, now time.Time) (res *feed.Tab, err error) {
var (
cards []*card.Card
// requestCnt = 10
isIpad = plat == model.PlatIPad
item []cardm.Handler
)
if isIpad {
// requestCnt = 20
}
if channelID > 0 {
channelName = ""
}
item, err = s.dealTab2(c, plat, build, mobiApp, mid, cards, now)
res = &feed.Tab{
Items: item,
}
return
}
func (s *Service) dealTab2(c context.Context, plat int8, build int, mobiApp string, mid int64, cards []*card.Card, now time.Time) (is []cardm.Handler, err error) {
if len(cards) == 0 {
is = []cardm.Handler{}
return
}
var (
shopIDs, roomIDs, metaIDs []int64
rmUpIDs, mtUpIDs, upIDs []int64
seasonIDs []int32
rm map[int64]*live.Room
metam map[int64]*article.Meta
shopm map[int64]*shopping.Shopping
seasonm map[int32]*seasongrpc.CardInfoProto
ac map[int64]*account.Card
statm map[int64]*relation.Stat
isAtten map[int64]int8
)
for _, card := range cards {
switch card.Type {
case model.GotoPGC:
if card.Value != 0 {
seasonIDs = append(seasonIDs, int32(card.Value))
}
case model.GotoLive:
if card.Value != 0 {
roomIDs = append(roomIDs, card.Value)
}
case model.GotoArticle:
if card.Value != 0 {
metaIDs = append(metaIDs, card.Value)
}
case model.GotoShoppingS:
if card.Value != 0 {
shopIDs = append(shopIDs, card.Value)
}
}
}
g, ctx := errgroup.WithContext(c)
if len(roomIDs) != 0 {
g.Go(func() (err error) {
if rm, err = s.lv.AppMRoom(ctx, roomIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, r := range rm {
rmUpIDs = append(rmUpIDs, r.UID)
}
return
})
}
if len(seasonIDs) != 0 {
g.Go(func() (err error) {
if seasonm, err = s.bgm.CardsInfoReply(ctx, seasonIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(metaIDs) != 0 {
g.Go(func() (err error) {
if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
for _, meta := range metam {
if meta.Author != nil {
mtUpIDs = append(mtUpIDs, meta.Author.Mid)
}
}
return
})
}
if len(shopIDs) != 0 {
g.Go(func() (err error) {
if shopm, err = s.sp.Card(ctx, shopIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
upIDs = append(upIDs, rmUpIDs...)
upIDs = append(upIDs, mtUpIDs...)
g, ctx = errgroup.WithContext(c)
if len(upIDs) != 0 {
g.Go(func() (err error) {
if ac, err = s.acc.Cards3(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
g.Go(func() (err error) {
if statm, err = s.rel.Stats(ctx, upIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
if mid != 0 {
g.Go(func() error {
isAtten = s.acc.IsAttention(ctx, upIDs, mid)
return nil
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
for _, card := range cards {
var (
r = card.CardToAiChange()
main interface{}
)
h := cardm.Handle(plat, cdm.CardGt(r.Goto), "", cdm.ColumnSvrSingle, r, nil, isAtten, statm, ac)
if h == nil {
continue
}
op := &operate.Card{}
op.From(cdm.CardGt(r.Goto), r.ID, 0, plat, build)
switch r.Goto {
case model.GotoLive:
main = rm
case model.GotoPGC:
main = seasonm
case model.GotoArticle:
main = metam
case model.GotoShoppingS:
main = shopm
}
h.From(main, op)
if h.Get() == nil {
continue
}
if h.Get().Right {
is = append(is, h)
}
}
if rl := len(is); rl == 0 {
is = []cardm.Handler{}
return
}
return
}