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,132 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"audit_test.go",
"banner_test.go",
"black_test.go",
"cache_test.go",
"index2_test.go",
"index_test.go",
"infoc_test.go",
"operate_test.go",
"player_test.go",
"service_test.go",
"tab_test.go",
"upper_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/app-card/model/card/ai: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-feed/conf:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"audit.go",
"banner.go",
"black.go",
"cache.go",
"index.go",
"index2.go",
"infoc.go",
"operate.go",
"player.go",
"rank.go",
"search.go",
"service.go",
"tab.go",
"tab2.go",
"upper.go",
],
importpath = "go-common/app/interface/main/app-feed/service/feed",
tags = ["automanaged"],
deps = [
"//app/interface/main/app-card/model:go_default_library",
"//app/interface/main/app-card/model/bplus:go_default_library",
"//app/interface/main/app-card/model/card:go_default_library",
"//app/interface/main/app-card/model/card/ai: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/banner:go_default_library",
"//app/interface/main/app-card/model/card/cm: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/rank:go_default_library",
"//app/interface/main/app-card/model/card/show:go_default_library",
"//app/interface/main/app-feed/conf:go_default_library",
"//app/interface/main/app-feed/dao/account:go_default_library",
"//app/interface/main/app-feed/dao/ad:go_default_library",
"//app/interface/main/app-feed/dao/archive:go_default_library",
"//app/interface/main/app-feed/dao/article:go_default_library",
"//app/interface/main/app-feed/dao/audio:go_default_library",
"//app/interface/main/app-feed/dao/audit:go_default_library",
"//app/interface/main/app-feed/dao/bangumi:go_default_library",
"//app/interface/main/app-feed/dao/black:go_default_library",
"//app/interface/main/app-feed/dao/bplus:go_default_library",
"//app/interface/main/app-feed/dao/card:go_default_library",
"//app/interface/main/app-feed/dao/converge:go_default_library",
"//app/interface/main/app-feed/dao/game:go_default_library",
"//app/interface/main/app-feed/dao/live:go_default_library",
"//app/interface/main/app-feed/dao/location:go_default_library",
"//app/interface/main/app-feed/dao/rank:go_default_library",
"//app/interface/main/app-feed/dao/recommend:go_default_library",
"//app/interface/main/app-feed/dao/relation:go_default_library",
"//app/interface/main/app-feed/dao/resource:go_default_library",
"//app/interface/main/app-feed/dao/search:go_default_library",
"//app/interface/main/app-feed/dao/show:go_default_library",
"//app/interface/main/app-feed/dao/special:go_default_library",
"//app/interface/main/app-feed/dao/tab:go_default_library",
"//app/interface/main/app-feed/dao/tag:go_default_library",
"//app/interface/main/app-feed/dao/upper:go_default_library",
"//app/interface/main/app-feed/model:go_default_library",
"//app/interface/main/app-feed/model/feed:go_default_library",
"//app/interface/main/app-feed/model/live:go_default_library",
"//app/interface/main/app-feed/model/tag: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/api:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/feed/model:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//app/service/openplatform/pgc-season/api/grpc/episode/v1:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup: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,124 @@
package feed
import (
"context"
"time"
cdm "go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card"
"go-common/app/interface/main/app-card/model/card/banner"
"go-common/app/interface/main/app-card/model/card/operate"
"go-common/app/interface/main/app-feed/model"
"go-common/app/interface/main/app-feed/model/feed"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
var (
_auditBanners = []*banner.Banner{
&banner.Banner{
Title: "充电",
Image: "http://i0.hdslb.com/bfs/archive/9ce8f6cdf76e6cbd50ce7db76262d5a35e594c79.png",
Hash: "3c4990d06c46de0080e3821fca6bedca",
URI: "bilibili://video/813060",
},
}
// av2314237 已经删除,后续看情况处理
// 已删除失效id已更换新的稿件id
_aids = []int64{308040, 2431658, 2432648, 2427553, 539600, 1968681, 850424, 887861, 1960912, 1935680, 1406019,
1985297, 1977493, 2312184, 2316891, 864845, 1986932, 880857, 875624, 744299}
)
// Audit check audit plat then return audit data.
func (s *Service) Audit(c context.Context, mobiApp string, plat int8, build int) (is []*feed.Item, ok bool) {
if plats, ok := s.auditCache[mobiApp]; ok {
if _, ok = plats[build]; ok {
return s.auditData(c), true
}
}
return
}
// Audit2 check audit plat and ip, then return audit data.
func (s *Service) Audit2(c context.Context, mobiApp string, plat int8, build int, column cdm.ColumnStatus) (is []card.Handler, ok bool) {
if plats, ok := s.auditCache[mobiApp]; ok {
if _, ok = plats[build]; ok {
return s.auditData2(c, plat, column), true
}
}
return
}
// auditData some data for audit.
func (s *Service) auditData(c context.Context) (is []*feed.Item) {
i := &feed.Item{}
i.FromBanner(_auditBanners, "")
is = append(is, i)
am, err := s.ArchivesWithPlayer(c, _aids, 0, "", 0, 0, 0, 0)
if err != nil {
log.Error("%+v", err)
return
}
for _, aid := range _aids {
if a, ok := am[aid]; ok {
i := &feed.Item{}
i.FromAv(a)
is = append(is, i)
}
}
return
}
// auditData2 some data for audit.
func (s *Service) auditData2(c context.Context, plat int8, column cdm.ColumnStatus) (is []card.Handler) {
i := card.Handle(plat, model.GotoBanner, "", column, nil, nil, nil, nil, nil)
if i != nil {
op := &operate.Card{}
op.FromBanner(_auditBanners, "")
i.From(nil, op)
is = append(is, i)
}
am, err := s.arc.Archives(c, _aids)
if err != nil {
log.Error("%+v", err)
}
var main interface{}
for _, aid := range _aids {
if a, ok := am[aid]; ok {
i := card.Handle(plat, model.GotoAv, "", column, nil, nil, nil, nil, nil)
if i == nil {
continue
}
op := &operate.Card{}
op.From(cdm.CardGotoAv, aid, 0, 0, 0)
main = map[int64]*archive.ArchiveWithPlayer{a.Aid: &archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(a)}}
i.From(main, op)
if !i.Get().Right {
continue
}
if model.IsIPad(plat) {
// ipad卡片不展示标签
i.Get().DescButton = nil
}
is = append(is, i)
}
}
return
}
func (s *Service) loadAuditCache() {
as, err := s.adt.Audits(context.Background())
if err != nil {
log.Error("s.adt.Audits error(%v)", err)
return
}
s.auditCache = as
}
// auditproc load audit cache.
func (s *Service) auditproc() {
for {
time.Sleep(s.tick)
s.loadAuditCache()
}
}

View File

@@ -0,0 +1,15 @@
package feed
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Audit(t *testing.T) {
Convey("should get audit", t, func() {
_, err := s.Audit(context.Background(), "", 1, 2)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,41 @@
package feed
import (
"context"
resource "go-common/app/service/main/resource/model"
"strconv"
"go-common/app/interface/main/app-card/model/card/banner"
"go-common/app/interface/main/app-feed/model"
)
var (
_banners = map[int8]int{
model.PlatIPhoneB: 467,
model.PlatIPhone: 467,
model.PlatAndroid: 631,
model.PlatIPad: 771,
model.PlatIPhoneI: 947,
model.PlatAndroidG: 1285,
model.PlatAndroidI: 1707,
model.PlatIPadI: 1117,
}
)
// banners get banners by plat, build channel, ip.
func (s *Service) banners(c context.Context, plat int8, build int, mid int64, buvid, network, mobiApp, device, openEvent, adExtra, hash string) (bs []*banner.Banner, version string, err error) {
plat = model.PlatAPPBuleChange(plat)
var (
rscID = _banners[plat]
bm map[int][]*resource.Banner
)
if bm, version, err = s.rsc.Banner(c, plat, build, mid, strconv.Itoa(rscID), "", buvid, network, mobiApp, device, true, openEvent, adExtra, hash); err != nil {
return
}
for _, rb := range bm[rscID] {
b := &banner.Banner{}
b.Change(rb)
bs = append(bs, b)
}
return
}

View File

@@ -0,0 +1,15 @@
package feed
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_banners(t *testing.T) {
Convey("should get banners", t, func() {
_, _, err := s.banners(context.Background(), 1, 2, 3, "", "", "", "", "", "", "")
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,33 @@
package feed
import (
"context"
"time"
"go-common/library/log"
)
func (s *Service) loadBlackCache() {
bs, err := s.blk.Black(context.Background())
if err != nil {
log.Error("s.blk.Black error(%v)", err)
return
}
s.blackCache = bs
log.Info("reBlackList success")
}
// blackproc load blacklist cache.
func (s *Service) blackproc() {
for {
time.Sleep(s.tick)
s.loadBlackCache()
}
}
func (s *Service) BlackList(c context.Context, mid int64) (aidm map[int64]struct{}, err error) {
if mid == 0 {
return
}
return s.blk.BlackList(c, mid)
}

View File

@@ -0,0 +1,15 @@
package feed
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_BlackList(t *testing.T) {
Convey("should get BlackList", t, func() {
_, err := s.BlackList(context.Background(), 1)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,336 @@
package feed
import (
"context"
"hash/crc32"
"math/rand"
"time"
"go-common/app/interface/main/app-card/model/card/ai"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-feed/model"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
func (s *Service) indexCache(c context.Context, mid int64, count int) (rs []*ai.Item, err error) {
var (
pos, nextPos int
)
cache := s.rcmdCache
if len(cache) < count {
return
}
if pos, err = s.rcmd.PositionCache(c, mid); err != nil {
return
}
rs = make([]*ai.Item, 0, count)
if pos < len(cache)-count-1 {
nextPos = pos + count
rs = append(rs, cache[pos:nextPos]...)
} else if pos < len(cache)-1 {
nextPos = count - (len(cache) - pos)
rs = append(rs, cache[pos:]...)
rs = append(rs, cache[:nextPos]...)
} else {
nextPos = count - 1
rs = append(rs, cache[:nextPos]...)
}
s.addCache(func() {
s.rcmd.AddPositionCache(context.Background(), mid, nextPos)
})
return
}
func (s *Service) recommendCache(count int) (rs []*ai.Item) {
cache := s.rcmdCache
index := len(cache)
if count > 0 && count < index {
index = count
}
rs = make([]*ai.Item, 0, index)
for _, idx := range rand.Perm(len(cache))[:index] {
rs = append(rs, cache[idx])
}
return
}
func (s *Service) group(mid int64, buvid string) (group int) {
if mid == 0 && buvid == "" {
group = -1
return
}
if mid != 0 {
if v, ok := s.groupCache[mid]; ok {
group = v
return
}
group = int(mid % 20)
return
}
group = int(crc32.ChecksumIEEE([]byte(buvid)) % 20)
return
}
func (s *Service) loadRcmdCache() {
is, err := s.rcmd.RcmdCache(context.Background())
if err != nil {
log.Error("%+v", err)
}
if len(is) >= 50 {
for _, i := range is {
i.Goto = model.GotoAv
}
s.rcmdCache = is
return
}
aids, err := s.rcmd.Hots(context.Background())
if err != nil {
log.Error("%+v", err)
}
if len(aids) == 0 {
if aids, err = s.rcmd.RcmdAidsCache(context.Background()); err != nil {
log.Error("%+v", err)
return
}
}
if len(aids) < 50 && len(s.rcmdCache) != 0 {
return
}
s.addCache(func() {
s.rcmd.AddRcmdAidsCache(context.Background(), aids)
})
if is, err = s.fromArchvies(aids); err != nil {
log.Error("%+v", err)
return
}
s.rcmdCache = is
}
func (s *Service) UpRcmdCache(c context.Context, is []*ai.Item) (err error) {
if err = s.rcmd.AddRcmdCache(c, is); err != nil {
log.Error("%+v", err)
}
return
}
func (s *Service) fromArchvies(aids []int64) (is []*ai.Item, err error) {
var as map[int64]*archive.ArchiveWithPlayer
if as, err = s.arc.ArchivesWithPlayer(context.Background(), aids, 0, "", 0, 0, 0, 0); err != nil {
return
}
is = make([]*ai.Item, 0, len(aids))
for _, aid := range aids {
a, ok := as[aid]
if !ok || a.Archive3 == nil || !a.IsNormal() {
continue
}
is = append(is, &ai.Item{ID: aid, Goto: model.GotoAv, Archive: a.Archive3})
}
return
}
func (s *Service) rcmdproc() {
for {
time.Sleep(s.tick)
s.loadRcmdCache()
}
}
func (s *Service) loadRankCache() {
rank, err := s.rank.AllRank(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.rankCache = rank
}
func (s *Service) rankproc() {
for {
time.Sleep(s.tick)
s.loadRankCache()
}
}
func (s *Service) loadConvergeCache() {
converge, err := s.cvg.Cards(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.convergeCache = converge
}
func (s *Service) convergeproc() {
for {
time.Sleep(s.tick)
s.loadConvergeCache()
}
}
func (s *Service) loadDownloadCache() {
download, err := s.gm.DownLoad(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.downloadCache = download
}
func (s *Service) downloadproc() {
for {
time.Sleep(s.tick)
s.loadDownloadCache()
}
}
func (s *Service) loadSpecialCache() {
special, err := s.sp.Card(context.Background(), time.Now())
if err != nil {
log.Error("%+v", err)
return
}
var roomIDs []int64
idm := map[int64]int64{}
for _, sp := range special {
if sp.Goto == model.GotoLive && sp.Pid != 0 {
roomIDs = append(roomIDs, sp.Pid)
idm[sp.Pid] = sp.ID
}
}
room, err := s.lv.Rooms(context.Background(), roomIDs, "")
if err != nil {
log.Error("%+v", err)
}
if len(room) != 0 {
for rid, id := range idm {
if r, ok := room[rid]; !ok || r.LiveStatus != 1 {
delete(special, id)
}
}
}
s.specialCache = special
}
func (s *Service) specialproc() {
for {
time.Sleep(s.tick)
s.loadSpecialCache()
}
}
func (s *Service) loadGroupCache() {
group, err := s.rcmd.Group(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.groupCache = group
}
func (s *Service) groupproc() {
for {
time.Sleep(s.tick)
s.loadGroupCache()
}
}
func (s *Service) loadFollowModeList() {
list, err := s.rcmd.FollowModeList(context.Background())
if err != nil {
log.Error("%+v", err)
if list, err = s.rcmd.FollowModeListCache(context.Background()); err != nil {
log.Error("%+v", err)
return
}
} else {
s.addCache(func() {
s.rcmd.AddFollowModeListCache(context.Background(), list)
})
}
log.Warn("loadFollowModeList list len(%d)", len(list))
s.followModeList = list
}
func (s *Service) followModeListproc() {
for {
time.Sleep(s.tick)
s.loadFollowModeList()
}
}
func (s *Service) loadUpCardCache() {
follow, err := s.card.Follow(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.followCache = follow
}
func (s *Service) upCardproc() {
for {
time.Sleep(s.tick)
s.loadUpCardCache()
}
}
func (s *Service) loadLiveCardCache() {
liveCard, err := s.lv.Card(context.Background())
if err != nil {
log.Error("%+v", err)
return
}
s.liveCardCache = liveCard
}
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) liveCardproc() {
for {
time.Sleep(1 * time.Second)
s.loadLiveCardCache()
}
}
func (s *Service) loadABTestCache() {
res, err := s.rsc.AbTest(context.Background(), _feedgroups)
if err != nil {
log.Error("resource s.rsc.AbTest error(%v)", err)
return
}
s.abtestCache = res
log.Info("loadAbTestCache cache success")
}
func (s *Service) loadABTestCacheProc() {
for {
time.Sleep(s.tick)
s.loadABTestCache()
}
}
func (s *Service) loadAutoPlayMid() {
tmp := map[int64]struct{}{}
for _, mid := range s.c.AutoPlayMids {
tmp[mid] = struct{}{}
}
s.autoplayMidsCache = tmp
}

View File

@@ -0,0 +1,15 @@
package feed
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_indexCache(t *testing.T) {
Convey("should get indexCache", t, func() {
_, err := s.indexCache(context.Background(), 1, 2)
So(err, ShouldBeNil)
})
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
package feed
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Index2(t *testing.T) {
Convey(t.Name(), t, func() {
gotIs, gotConfig, gotInfoc, err := s.Index2(context.Background(), "", 0, 0, nil, 1, time.Now())
So(gotIs, ShouldNotBeNil)
So(gotConfig, ShouldNotBeNil)
So(gotInfoc, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func TestService_indexBanner2(t *testing.T) {
Convey(t.Name(), t, func() {
gotBanners, gotVersion, err := s.indexBanner2(context.Background(), 0, "", 0, nil)
So(gotBanners, ShouldNotBeNil)
So(gotVersion, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func TestService_mergeItem2(t *testing.T) {
Convey(t.Name(), t, func() {
gotIs, gotAdInfom := s.mergeItem2(context.Background(), 0, 0, nil, nil, nil, nil, "", nil, nil, false)
So(gotIs, ShouldNotBeNil)
So(gotAdInfom, ShouldNotBeNil)
})
}
func TestService_dealAdLoc(t *testing.T) {
Convey(t.Name(), t, func() {
s.dealAdLoc(nil, nil, nil, time.Now())
})
}
func TestService_dealItem2(t *testing.T) {
Convey(t.Name(), t, func() {
gotIs, gotIsAI := s.dealItem2(context.Background(), 0, "", 0, nil, nil, false, false, false, nil, time.Now())
So(gotIs, ShouldNotBeNil)
So(gotIsAI, ShouldNotBeNil)
})
}
func TestService_Converge(t *testing.T) {
Convey(t.Name(), t, func() {
gotIs, gotConverge, err := s.Converge(context.Background(), 0, 0, nil, time.Now())
So(gotIs, ShouldNotBeNil)
So(gotConverge, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,16 @@
package feed
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_DislikeCancel(t *testing.T) {
Convey("should get DislikeCancel", t, func() {
err := s.DislikeCancel(context.Background(), 1, 2, "", "", 3, 9, 4, 8, 5, 6, "", time.Now())
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,254 @@
package feed
import (
"bytes"
"context"
"encoding/json"
"strconv"
"time"
"go-common/app/interface/main/app-card/model/card/ai"
"go-common/app/interface/main/app-feed/model"
"go-common/library/log"
binfoc "go-common/library/log/infoc"
"go-common/library/net/metadata"
)
type infoc struct {
typ string
mid string
client string
build string
buvid string
disid string
ip string
style string
api string
now string
isRcmd string
pull string
userFeature json.RawMessage
code string
items []*ai.Item
zoneID string
adResponse string
deviceID string
network string
newUser string
flush string
autoPlay string
deviceType string
}
func (s *Service) IndexInfoc(c context.Context, mid int64, plat int8, build int, buvid, disid, api string, userFeature json.RawMessage, style, code int, items []*ai.Item, isRcmd, pull, newUser bool, now time.Time, adResponse, deviceID, network string, flush int, autoPlay string, deviceType int) {
if items == nil {
return
}
var (
isRc = "0"
isPull = "0"
isNewUser = "0"
zoneID int64
)
if isRcmd {
isRc = "1"
}
if pull {
isPull = "1"
}
if newUser {
isNewUser = "1"
}
ip := metadata.String(c, metadata.RemoteIP)
info, err := s.loc.Info(c, ip)
if err != nil {
log.Warn(" s.loc.Info(%v) error(%v)", ip, err)
err = nil
}
if info != nil {
zoneID = info.ZoneID
}
s.infoc(infoc{"综合推荐", strconv.FormatInt(mid, 10), strconv.Itoa(int(plat)), strconv.Itoa(build), buvid, disid, ip, strconv.Itoa(style), api, strconv.FormatInt(now.Unix(), 10), isRc, isPull, userFeature, strconv.Itoa(code), items, strconv.FormatInt(zoneID, 10), adResponse, deviceID, network, isNewUser, strconv.Itoa(flush), autoPlay, strconv.Itoa(deviceType)})
}
func (s *Service) infoc(i interface{}) {
select {
case s.logCh <- i:
default:
log.Warn("infocproc chan full")
}
}
// writeInfoc
func (s *Service) infocproc() {
const (
// infoc format {"section":{"id":"%s推荐","pos":1,"style":%d,"items":[{"id":%s,"pos":%d,"type":1,"url":""}]}}
noItem1 = `{"section":{"id":"`
noItem2 = `{","pos":1,"style":`
noItem3 = `,"items":[]}}`
)
// is_ad_loc, resource_idsource_id, creative_id,
var (
msg1 = []byte(`{"section":{"id":"`)
msg2 = []byte(`","pos":1,"style":`)
msg3 = []byte(`,"items":[`)
msg4 = []byte(`{"id":`)
msg5 = []byte(`,"pos":`)
msg6 = []byte(`,"type":`)
msg7 = []byte(`,"source":"`)
msg8 = []byte(`","tid":`)
msg9 = []byte(`,"av_feature":`)
msg10 = []byte(`,"url":"`)
msg11 = []byte(`","rcmd_reason":"`)
msg12 = []byte(`","is_ad_loc":`)
msg13 = []byte(`,"resource_id":`)
msg14 = []byte(`,"source_id":`)
msg15 = []byte(`,"creative_id":`)
msg16 = []byte(`},`)
msg17 = []byte(`"},`)
msg18 = []byte(`]}}`)
showInf = binfoc.New(s.c.ShowInfoc2)
buf bytes.Buffer
list string
trackID string
)
for {
i, ok := <-s.logCh
if !ok {
log.Warn("infoc proc exit")
return
}
switch l := i.(type) {
case infoc:
if len(l.items) > 0 {
buf.Write(msg1)
buf.WriteString(l.typ)
buf.Write(msg2)
buf.WriteString(l.style)
buf.Write(msg3)
for i, v := range l.items {
if v == nil {
continue
}
if v.TrackID != "" {
trackID = v.TrackID
}
buf.Write(msg4)
buf.WriteString(strconv.FormatInt(v.ID, 10))
buf.Write(msg5)
buf.WriteString(strconv.Itoa(i + 1))
buf.Write(msg6)
buf.WriteString(gotoMapID(v.Goto))
buf.Write(msg7)
buf.WriteString(v.Source)
buf.Write(msg8)
buf.WriteString(strconv.FormatInt(v.Tid, 10))
buf.Write(msg9)
if v.AvFeature != nil {
buf.Write(v.AvFeature)
} else {
buf.Write([]byte(`""`))
}
buf.Write(msg10)
buf.WriteString("")
buf.Write(msg11)
if v.RcmdReason != nil {
buf.WriteString(v.RcmdReason.Content)
}
if v.Ad != nil {
buf.Write(msg12)
buf.WriteString(strconv.FormatBool(v.Ad.IsAdLoc))
buf.Write(msg13)
buf.WriteString(strconv.FormatInt(v.Ad.Resource, 10))
buf.Write(msg14)
buf.WriteString(strconv.Itoa(v.Ad.Source))
buf.Write(msg15)
buf.WriteString(strconv.FormatInt(v.Ad.CreativeID, 10))
buf.Write(msg16)
} else {
buf.Write(msg17)
}
}
buf.Truncate(buf.Len() - 1)
buf.Write(msg18)
list = buf.String()
buf.Reset()
} else {
list = noItem1 + l.typ + noItem2 + l.style + noItem3
}
showInf.Info(l.ip, l.now, l.api, l.buvid, l.mid, l.client, l.pull, list, l.disid, l.isRcmd, l.build, l.code, string(l.userFeature), l.zoneID, l.adResponse, l.deviceID, l.network, l.newUser, l.flush, l.autoPlay, trackID, l.deviceType)
log.Info("infocproc %s param(mid:%s,buvid:%s,plat:%s,build:%s,isRcmd:%s,code:%s,zone_id:%s,user_feature:%s,ad_response:%s,device_id:%s,network:%s,new_user:%s,flush:%s,autoplay_card:%s,trackid:%s,device_type:%s) response(%s)", l.api, l.mid, l.buvid, l.client, l.build, l.isRcmd, l.code, l.zoneID, l.userFeature, l.adResponse, l.deviceID, l.network, l.newUser, l.flush, l.autoPlay, trackID, l.deviceType, list)
}
}
}
func gotoMapID(gt string) (id string) {
if gt == model.GotoAv {
id = "1"
} else if gt == model.GotoBangumi {
id = "2"
} else if gt == model.GotoLive {
id = "3"
} else if gt == model.GotoRank {
id = "6"
} else if gt == model.GotoAdAv {
id = "8"
} else if gt == model.GotoAdWeb {
id = "9"
} else if gt == model.GotoBangumiRcmd {
id = "10"
} else if gt == model.GotoLogin {
id = "11"
} else if gt == model.GotoUpBangumi {
id = "12"
} else if gt == model.GotoBanner {
id = "13"
} else if gt == model.GotoAdWebS {
id = "14"
} else if gt == model.GotoUpArticle {
id = "15"
} else if gt == model.GotoConverge {
id = "17"
} else if gt == model.GotoSpecial {
id = "18"
} else if gt == model.GotoArticleS {
id = "20"
} else if gt == model.GotoGameDownloadS {
id = "21"
} else if gt == model.GotoShoppingS {
id = "22"
} else if gt == model.GotoAudio {
id = "23"
} else if gt == model.GotoPlayer {
id = "24"
} else if gt == model.GotoSpecialS {
id = "25"
} else if gt == model.GotoAdLarge {
id = "26"
} else if gt == model.GotoPlayerLive {
id = "27"
} else if gt == model.GotoSong {
id = "28"
} else if gt == model.GotoLiveUpRcmd {
id = "29"
} else if gt == model.GotoUpRcmdAv {
id = "30"
} else if gt == model.GotoSubscribe {
id = "31"
} else if gt == model.GotoChannelRcmd {
id = "32"
} else if gt == model.GotoMoe {
id = "33"
} else if gt == model.GotoPGC {
id = "34"
} else if gt == model.GotoSearchSubscribe {
id = "35"
} else if gt == model.GotoPicture {
id = "36"
} else if gt == model.GotoInterest {
id = "37"
} else {
id = "-1"
}
return
}

View File

@@ -0,0 +1,100 @@
package feed
import (
"context"
"encoding/json"
"testing"
"time"
"go-common/app/interface/main/app-card/model/card/ai"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_IndexInfoc(t *testing.T) {
type args struct {
c context.Context
mid int64
plat int8
build int
buvid string
disid string
api string
userFeature json.RawMessage
style int
code int
items []*ai.Item
isRcmd bool
pull bool
newUser bool
now time.Time
zoneID int64
adResponse string
deviceID string
network string
flush int
autoPlay string
deviceType int
}
tests := []struct {
name string
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
s.IndexInfoc(tt.args.c, tt.args.mid, tt.args.plat, tt.args.build, tt.args.buvid, tt.args.disid, tt.args.api, tt.args.userFeature, tt.args.style, tt.args.code, tt.args.items, tt.args.isRcmd, tt.args.pull, tt.args.newUser, tt.args.now, tt.args.adResponse, tt.args.deviceID, tt.args.network, tt.args.flush, tt.args.autoPlay, tt.args.deviceType)
})
}
}
func TestService_infoc(t *testing.T) {
type args struct {
i interface{}
}
tests := []struct {
name string
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s.infoc(tt.args.i)
})
}
}
func TestService_infocproc(t *testing.T) {
tests := []struct {
name string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s.infocproc()
})
}
}
func Test_gotoMapID(t *testing.T) {
type args struct {
gt string
}
tests := []struct {
name string
args args
wantId string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotId := gotoMapID(tt.args.gt); gotId != tt.wantId {
t.Errorf("gotoMapID() = %v, want %v", gotId, tt.wantId)
}
})
}
}

View File

@@ -0,0 +1,122 @@
package feed
import (
"context"
"go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card/operate"
)
func (s *Service) convergeCard(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.convergeCache[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.downloadCache[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.followCache[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.followCache[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) 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.specialCache[id]; ok {
card := &operate.Card{}
card.FromSpecial(o)
cardm[id] = card
}
}
return
}

View File

@@ -0,0 +1,146 @@
package feed
import (
"context"
"reflect"
"testing"
"go-common/app/interface/main/app-card/model/card/live"
"go-common/app/interface/main/app-card/model/card/operate"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_convergeCard(t *testing.T) {
type args struct {
c context.Context
limit int
ids []int64
}
tests := []struct {
name string
args args
wantCardm map[int64]*operate.Converge
wantAids []int64
wantRoomIDs []int64
wantMetaIDs []int64
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
gotCardm, gotAids, gotRoomIDs, gotMetaIDs := s.convergeCard(tt.args.c, tt.args.limit, tt.args.ids...)
So(gotCardm, ShouldResemble, tt.wantCardm)
So(gotAids, ShouldResemble, tt.wantAids)
So(gotRoomIDs, ShouldResemble, tt.wantRoomIDs)
So(gotMetaIDs, ShouldResemble, tt.wantMetaIDs)
})
}
}
func TestService_downloadCard(t *testing.T) {
type args struct {
c context.Context
ids []int64
}
tests := []struct {
name string
args args
wantCardm map[int64]*operate.Download
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
if gotCardm := s.downloadCard(tt.args.c, tt.args.ids...); !reflect.DeepEqual(gotCardm, tt.wantCardm) {
t.Errorf("Service.downloadCard() = %v, want %v", gotCardm, tt.wantCardm)
}
})
}
}
func TestService_subscribeCard(t *testing.T) {
type args struct {
c context.Context
ids []int64
}
tests := []struct {
name string
args args
wantCardm map[int64]*operate.Follow
wantUpIDs []int64
wantTids []int64
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
gotCardm, gotUpIDs, gotTids := s.subscribeCard(tt.args.c, tt.args.ids...)
if !reflect.DeepEqual(gotCardm, tt.wantCardm) {
t.Errorf("Service.subscribeCard() gotCardm = %v, want %v", gotCardm, tt.wantCardm)
}
if !reflect.DeepEqual(gotUpIDs, tt.wantUpIDs) {
t.Errorf("Service.subscribeCard() gotUpIDs = %v, want %v", gotUpIDs, tt.wantUpIDs)
}
if !reflect.DeepEqual(gotTids, tt.wantTids) {
t.Errorf("Service.subscribeCard() gotTids = %v, want %v", gotTids, tt.wantTids)
}
})
}
}
func TestService_channelRcmdCard(t *testing.T) {
type args struct {
c context.Context
ids []int64
}
tests := []struct {
name string
args args
wantCardm map[int64]*operate.Follow
wantUpIDs []int64
wantTids []int64
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
gotCardm, gotUpIDs, gotTids := s.channelRcmdCard(tt.args.c, tt.args.ids...)
if !reflect.DeepEqual(gotCardm, tt.wantCardm) {
t.Errorf("Service.channelRcmdCard() gotCardm = %v, want %v", gotCardm, tt.wantCardm)
}
if !reflect.DeepEqual(gotUpIDs, tt.wantUpIDs) {
t.Errorf("Service.channelRcmdCard() gotUpIDs = %v, want %v", gotUpIDs, tt.wantUpIDs)
}
if !reflect.DeepEqual(gotTids, tt.wantTids) {
t.Errorf("Service.channelRcmdCard() gotTids = %v, want %v", gotTids, tt.wantTids)
}
})
}
}
func TestService_liveUpRcmdCard(t *testing.T) {
type args struct {
c context.Context
ids []int64
}
tests := []struct {
name string
args args
wantCardm map[int64][]*live.Card
wantUpIDs []int64
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
gotCardm, gotUpIDs := s.liveUpRcmdCard(tt.args.c, tt.args.ids...)
if !reflect.DeepEqual(gotCardm, tt.wantCardm) {
t.Errorf("Service.liveUpRcmdCard() gotCardm = %v, want %v", gotCardm, tt.wantCardm)
}
if !reflect.DeepEqual(gotUpIDs, tt.wantUpIDs) {
t.Errorf("Service.liveUpRcmdCard() gotUpIDs = %v, want %v", gotUpIDs, tt.wantUpIDs)
}
})
}
}

View File

@@ -0,0 +1,30 @@
package feed
import (
"context"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
// ArchivesWithPlayer archives witch player
func (s *Service) ArchivesWithPlayer(c context.Context, aids []int64, qn int, platform string, fnver, fnval, forceHost, build int) (res map[int64]*archive.ArchiveWithPlayer, err error) {
if res, err = s.arc.ArchivesWithPlayer(c, aids, qn, platform, fnver, fnval, forceHost, 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
}

View File

@@ -0,0 +1,44 @@
package feed
import (
"context"
"reflect"
"testing"
"go-common/app/service/main/archive/model/archive"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_ArchivesWithPlayer(t *testing.T) {
type args struct {
c context.Context
aids []int64
qn int
platform string
fnver int
fnval int
forceHost int
build int
}
tests := []struct {
name string
args args
wantRes map[int64]*archive.ArchiveWithPlayer
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
Convey(tt.name, t, func() {
gotRes, err := s.ArchivesWithPlayer(tt.args.c, tt.args.aids, tt.args.qn, tt.args.platform, tt.args.fnver, tt.args.fnval, tt.args.forceHost, tt.args.build)
if (err != nil) != tt.wantErr {
t.Errorf("Service.ArchivesWithPlayer() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotRes, tt.wantRes) {
t.Errorf("Service.ArchivesWithPlayer() = %v, want %v", gotRes, tt.wantRes)
}
})
}
}

View File

@@ -0,0 +1,25 @@
package feed
import (
"go-common/app/interface/main/app-card/model/card/rank"
"go-common/app/interface/main/app-feed/model"
)
func (s *Service) RankCard(plat int8) (ranks []*rank.Rank, aids []int64) {
var limit int
if !model.IsIPad(plat) {
limit = 3
} else {
limit = 4
}
ranks = make([]*rank.Rank, 0, limit)
aids = make([]int64, 0, limit)
for _, rank := range s.rankCache {
ranks = append(ranks, rank)
aids = append(aids, rank.Aid)
if len(ranks) == limit {
break
}
}
return
}

View File

@@ -0,0 +1,57 @@
package feed
import (
"context"
"strconv"
"go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/card/operate"
)
func (s *Service) SearchFollow(c context.Context, platform, mobiApp, device, buvid string, build int, mid int64) (follow *operate.Follow, err error) {
const _title = "人气UP主推荐"
ups, trackID, err := s.search.Follow(c, platform, mobiApp, device, buvid, build, mid)
if err != nil {
return
}
items := make([]*operate.Follow, 0, len(ups))
for _, up := range ups {
if up.Mid != 0 {
item := &operate.Follow{Pid: up.Mid, Goto: model.GotoMid}
items = append(items, item)
}
}
if len(items) < 3 {
return
}
id, _ := strconv.ParseInt(trackID, 10, 64)
if id < 1 {
return
}
follow = &operate.Follow{ID: id, Items: items, Title: _title, Type: "upper"}
return
}
func (s *Service) SearchFollow2(c context.Context, platform, mobiApp, device, buvid string, build int, mid int64) (follow *operate.Card, err error) {
const _title = "人气UP主推荐"
ups, trackID, err := s.search.Follow(c, platform, mobiApp, device, buvid, build, mid)
if err != nil {
return
}
items := make([]*operate.Card, 0, len(ups))
for _, up := range ups {
if up.Mid != 0 {
item := &operate.Card{ID: up.Mid, Goto: model.GotoMid, Param: strconv.FormatInt(up.Mid, 10), URI: strconv.FormatInt(up.Mid, 10), Desc: up.RecReason}
items = append(items, item)
}
}
if len(items) < 3 {
return
}
id, _ := strconv.ParseInt(trackID, 10, 64)
if id < 1 {
return
}
follow = &operate.Card{ID: id, Param: trackID, Items: items, Title: _title, CardGoto: model.CardGotoSearchSubscribe}
return
}

View File

@@ -0,0 +1,233 @@
package feed
import (
"time"
"go-common/app/interface/main/app-card/model/card/ai"
"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-card/model/card/rank"
"go-common/app/interface/main/app-feed/conf"
accdao "go-common/app/interface/main/app-feed/dao/account"
addao "go-common/app/interface/main/app-feed/dao/ad"
arcdao "go-common/app/interface/main/app-feed/dao/archive"
artdao "go-common/app/interface/main/app-feed/dao/article"
audiodao "go-common/app/interface/main/app-feed/dao/audio"
adtdao "go-common/app/interface/main/app-feed/dao/audit"
bgmdao "go-common/app/interface/main/app-feed/dao/bangumi"
blkdao "go-common/app/interface/main/app-feed/dao/black"
bplusdao "go-common/app/interface/main/app-feed/dao/bplus"
carddao "go-common/app/interface/main/app-feed/dao/card"
cvgdao "go-common/app/interface/main/app-feed/dao/converge"
gamedao "go-common/app/interface/main/app-feed/dao/game"
livdao "go-common/app/interface/main/app-feed/dao/live"
locdao "go-common/app/interface/main/app-feed/dao/location"
rankdao "go-common/app/interface/main/app-feed/dao/rank"
rcmdao "go-common/app/interface/main/app-feed/dao/recommend"
reldao "go-common/app/interface/main/app-feed/dao/relation"
rscdao "go-common/app/interface/main/app-feed/dao/resource"
searchdao "go-common/app/interface/main/app-feed/dao/search"
showdao "go-common/app/interface/main/app-feed/dao/show"
specdao "go-common/app/interface/main/app-feed/dao/special"
tabdao "go-common/app/interface/main/app-feed/dao/tab"
tagdao "go-common/app/interface/main/app-feed/dao/tag"
updao "go-common/app/interface/main/app-feed/dao/upper"
"go-common/app/interface/main/app-feed/model"
"go-common/app/interface/main/app-feed/model/feed"
resource "go-common/app/service/main/resource/model"
"go-common/library/log"
"go-common/library/stat/prom"
)
var (
_emptyItem = []*feed.Item{}
)
// Service is show service.
type Service struct {
c *conf.Config
pHit *prom.Prom
pMiss *prom.Prom
// dao
rcmd *rcmdao.Dao
bgm *bgmdao.Dao
tg *tagdao.Dao
adt *adtdao.Dao
blk *blkdao.Dao
lv *livdao.Dao
ad *addao.Dao
rank *rankdao.Dao
gm *gamedao.Dao
sp *specdao.Dao
cvg *cvgdao.Dao
show *showdao.Dao
tab *tabdao.Dao
audio *audiodao.Dao
// rpc
arc *arcdao.Dao
acc *accdao.Dao
rel *reldao.Dao
upper *updao.Dao
art *artdao.Dao
rsc *rscdao.Dao
card *carddao.Dao
search *searchdao.Dao
bplus *bplusdao.Dao
loc *locdao.Dao
// tick
tick time.Duration
// audit cache
auditCache map[string]map[int]struct{} // audit mobi_app builds
// black cache
blackCache map[int64]struct{} // black aids
// ai cache
rcmdCache []*ai.Item
// rank
rankCache []*rank.Rank
// converge cache
convergeCache map[int64]*operate.Converge
// download cache
downloadCache map[int64]*operate.Download
// special cache
specialCache map[int64]*operate.Special
// follow cache
followCache map[int64]*operate.Follow
liveCardCache map[int64][]*live.Card
// tab cache
menuCache []*operate.Menu
tabCache map[int64][]*operate.Active
coverCache map[int64]string
// group cache
groupCache map[int64]int
// cache
cacheCh chan func()
// infoc
logCh chan interface{}
// ad
cmResourceMap map[int8]int64
// abtest cache
abtestCache map[string]*resource.AbTest
// autoplay mids cache
autoplayMidsCache map[int64]struct{}
// follow mode list
followModeList map[int64]struct{}
}
// New new a show service.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
pHit: prom.CacheHit,
pMiss: prom.CacheMiss,
// dao
rcmd: rcmdao.New(c),
bgm: bgmdao.New(c),
tg: tagdao.New(c),
adt: adtdao.New(c),
blk: blkdao.New(c),
lv: livdao.New(c),
ad: addao.New(c),
rank: rankdao.New(c),
gm: gamedao.New(c),
cvg: cvgdao.New(c),
sp: specdao.New(c),
show: showdao.New(c),
tab: tabdao.New(c),
audio: audiodao.New(c),
card: carddao.New(c),
search: searchdao.New(c),
bplus: bplusdao.New(c),
// rpc
arc: arcdao.New(c),
rel: reldao.New(c),
acc: accdao.New(c),
upper: updao.New(c),
art: artdao.New(c),
rsc: rscdao.New(c),
loc: locdao.New(c),
// tick
tick: time.Duration(c.Tick),
// group cache
groupCache: map[int64]int{},
// cache
cacheCh: make(chan func(), 1024),
// infoc
logCh: make(chan interface{}, 1024),
// abtest cache
abtestCache: map[string]*resource.AbTest{},
// autoplay mids cache
autoplayMidsCache: map[int64]struct{}{},
}
var err error
if s.cmResourceMap, err = s.coverCMResource(c.Feed.CMResource); err != nil {
panic(err)
}
s.loadAuditCache()
s.loadBlackCache()
s.loadRcmdCache()
s.loadRankCache()
s.loadConvergeCache()
s.loadDownloadCache()
s.loadSpecialCache()
s.loadTabCache()
s.loadGroupCache()
s.loadUpCardCache()
s.loadLiveCardCache()
s.loadABTestCache()
s.loadAutoPlayMid()
s.loadFollowModeList()
go s.cacheproc()
go s.auditproc()
go s.blackproc()
go s.rcmdproc()
go s.rankproc()
go s.convergeproc()
go s.downloadproc()
go s.specialproc()
go s.tabproc()
go s.groupproc()
go s.infocproc()
go s.upCardproc()
go s.liveCardproc()
go s.loadABTestCacheProc()
go s.followModeListproc()
return
}
func (s *Service) coverCMResource(resource map[string]int64) (rscm map[int8]int64, err error) {
if len(resource) == 0 {
return
}
rscm = make(map[int8]int64, len(resource))
for mobiApp, r := range resource {
var plat int8
if mobiApp == "iphone" {
plat = model.PlatIPhone
} else if mobiApp == "android" {
plat = model.PlatAndroid
} else if mobiApp == "ipad" {
plat = model.PlatIPad
}
rscm[plat] = r
}
return
}
func (s *Service) addCache(f func()) {
select {
case s.cacheCh <- f:
default:
log.Warn("cacheproc chan full")
}
}
func (s *Service) cacheproc() {
for {
f, ok := <-s.cacheCh
if !ok {
log.Warn("cache proc exit")
return
}
f()
}
}

View File

@@ -0,0 +1,21 @@
package feed
import (
"flag"
"path/filepath"
"time"
"go-common/app/interface/main/app-feed/conf"
)
var (
s *Service
)
func init() {
dir, _ := filepath.Abs("../../cmd/app-feed-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}

View File

@@ -0,0 +1,300 @@
package feed
import (
"context"
"sort"
"time"
"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"
"go-common/app/interface/main/app-feed/model"
"go-common/app/interface/main/app-feed/model/feed"
tag "go-common/app/interface/main/tag/model"
article "go-common/app/interface/openplatform/article/model"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
func (s *Service) Menus(c context.Context, plat int8, build int, now time.Time) (menus []*operate.Menu) {
memuCache := s.menuCache
menus = make([]*operate.Menu, 0, len(memuCache))
LOOP:
for _, m := range memuCache {
if vs, ok := m.Versions[plat]; ok {
for _, v := range vs {
if model.InvalidBuild(build, v.Build, v.Condition) {
continue LOOP
}
}
if m.Status == 1 && (m.STime == 0 || now.After(m.STime.Time())) && (m.ETime == 0 || now.Before(m.ETime.Time())) {
if m.ID == s.c.Bnj.TabID {
m.Img = s.c.Bnj.TabImg
}
menus = append(menus, m)
}
}
}
return
}
// Actives return actives
func (s *Service) Actives(c context.Context, id, mid int64, now time.Time) (items []*feed.Item, cover string, isBnj bool, bnjDays int, err error) {
if id == s.c.Bnj.TabID {
isBnj = true
nt := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
bt, _ := time.Parse("2006-01-02", s.c.Bnj.BeginTime)
bnjDays = int(bt.Sub(nt).Hours() / 24)
if bnjDays < 0 {
bnjDays = 0
}
}
rs := s.tabCache[id]
if items, err = s.dealTab(c, rs, mid, now); err != nil {
log.Error("%+v", err)
return
}
cover = s.coverCache[id]
return
}
func (s *Service) dealTab(c context.Context, rs []*operate.Active, mid int64, now time.Time) (is []*feed.Item, err error) {
if len(rs) == 0 {
is = _emptyItem
return
}
var (
aids, tids, roomIDs, sids, metaIDs []int64
am map[int64]*archive.ArchiveWithPlayer
rm map[int64]*live.Room
sm map[int64]*bangumi.Season
metam map[int64]*article.Meta
tagm map[int64]*tag.Tag
)
convergem := map[int64]*operate.Converge{}
downloadm := map[int64]*operate.Download{}
for _, r := range rs {
switch r.Type {
case model.GotoPlayer:
if r.Pid != 0 {
aids = append(aids, r.Pid)
}
case model.GotoPlayerLive:
if r.Pid != 0 {
roomIDs = append(roomIDs, r.Pid)
}
case model.GotoTabTagRcmd:
if r.Pid != 0 {
var taids []int64
if taids, err = s.rcmd.TagTop(c, mid, r.Pid, r.Limit); err != nil {
log.Error("%+v", err)
err = nil
continue
}
tids = append(tids, r.Pid)
r.Items = make([]*operate.Active, 0, len(taids))
for _, aid := range taids {
item := &operate.Active{Pid: aid, Goto: model.GotoAv}
r.Items = append(r.Items, item)
aids = append(aids, aid)
}
}
case model.GotoConverge:
if card, ok := s.convergeCache[r.Pid]; 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[r.Pid] = card
}
case model.GotoTabEntrance, model.GotoTabContentRcmd:
for _, item := range r.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.GotoBangumi:
if item.Pid != 0 {
sids = append(sids, item.Pid)
}
case model.GotoGame:
if card, ok := s.downloadCache[item.Pid]; ok {
downloadm[item.Pid] = card
}
case model.GotoArticle:
if item.Pid != 0 {
metaIDs = append(metaIDs, item.Pid)
}
}
}
}
}
g, ctx := errgroup.WithContext(c)
if len(tids) != 0 {
g.Go(func() (err error) {
if tagm, err = s.tg.InfoByIDs(c, 0, tids); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(aids) != 0 {
g.Go(func() (err error) {
if am, err = s.ArchivesWithPlayer(ctx, aids, 0, "", 0, 0, 0, 0); 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
}
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(metaIDs) != 0 {
g.Go(func() (err error) {
if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
is = make([]*feed.Item, 0, len(rs))
for _, r := range rs {
i := &feed.Item{}
switch r.Type {
case model.GotoPlayer:
if a, ok := am[r.Pid]; ok {
i.FromPlayer(a)
is = append(is, i)
}
case model.GotoPlayerLive:
if room, ok := rm[r.Pid]; ok {
i.FromPlayerLive(room)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoSpecial:
if sc, ok := s.specialCache[r.Pid]; 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.GotoConverge:
if cc, ok := convergem[r.Pid]; ok {
i.FromConverge(cc, am, rm, metam)
if i.Goto != "" {
is = append(is, i)
}
}
case model.GotoTabTagRcmd:
i.FromTabTags(r, am, tagm)
if i.Goto != "" {
is = append(is, i)
}
case model.GotoTabEntrance, model.GotoTabContentRcmd:
i.FromTabCards(r, am, downloadm, sm, rm, metam, s.specialCache)
if i.Goto != "" {
is = append(is, i)
}
case model.GotoBanner:
i.FromTabBanner(r)
if i.Goto != "" {
is = append(is, i)
}
case model.GotoTabNews:
i.FromNews(r)
if i.Goto != "" {
is = append(is, i)
}
}
}
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) loadTabCache() {
c := context.TODO()
menus, err := s.tab.Menus(c)
if err != nil {
log.Error("%+v", err)
} else {
s.menuCache = menus
}
acs, err := s.tab.Actives(c)
if err != nil {
log.Error("%+v", err)
} else {
s.tabCache, s.coverCache = mergeTab(acs)
}
}
func mergeTab(acs []*operate.Active) (tabm map[int64][]*operate.Active, coverm map[int64]string) {
coverm = make(map[int64]string, len(acs))
parentm := make(map[int64]struct{}, len(acs))
for _, ac := range acs {
if ac.Type == model.GotoTabBackground {
parentm[ac.ID] = struct{}{}
coverm[ac.ID] = ac.Cover
}
}
sort.Sort(operate.Actives(acs))
tabm = make(map[int64][]*operate.Active, len(acs))
for parentID := range parentm {
for _, ac := range acs {
if ac.ParentID == parentID {
tabm[ac.ParentID] = append(tabm[ac.ParentID], ac)
}
}
}
return
}
func (s *Service) tabproc() {
for {
time.Sleep(time.Minute * 1)
s.loadTabCache()
}
}

View File

@@ -0,0 +1,252 @@
package feed
import (
"context"
"strconv"
"time"
cdm "go-common/app/interface/main/app-card/model"
"go-common/app/interface/main/app-card/model/bplus"
"go-common/app/interface/main/app-card/model/card"
"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"
"go-common/app/interface/main/app-feed/model"
tag "go-common/app/interface/main/tag/model"
article "go-common/app/interface/openplatform/article/model"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// Actives2 return actives
func (s *Service) Actives2(c context.Context, id, mid int64, mobiApp string, plat int8, build, forceHost int, now time.Time) (items []card.Handler, cover string, isBnj bool, bnjDays int, err error) {
if id == s.c.Bnj.TabID {
isBnj = true
nt := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
bt, _ := time.Parse("2006-01-02", s.c.Bnj.BeginTime)
bnjDays = int(bt.Sub(nt).Hours() / 24)
if bnjDays < 0 {
bnjDays = 0
}
}
rs := s.tabCache[id]
if items, err = s.dealTab2(c, rs, mid, mobiApp, plat, build, forceHost, now); err != nil {
log.Error("s.dealTab(%v) error(%v)", rs, err)
return
}
cover = s.coverCache[id]
return
}
func (s *Service) dealTab2(c context.Context, rs []*operate.Active, mid int64, mobiApp string, plat int8, build, forceHost int, now time.Time) (is []card.Handler, err error) {
if len(rs) == 0 {
is = []card.Handler{}
return
}
var (
paids, aids, tids, roomIDs, sids, metaIDs, picIDs []int64
pam, am map[int64]*archive.ArchiveWithPlayer
rm map[int64]*live.Room
sm map[int64]*bangumi.Season
metam map[int64]*article.Meta
tagm map[int64]*tag.Tag
picm map[int64]*bplus.Picture
)
convergem := map[int64]*operate.Card{}
specialm := map[int64]*operate.Card{}
downloadm := map[int64]*operate.Download{}
for _, r := range rs {
switch r.Type {
case model.GotoPlayer:
if r.Pid != 0 {
paids = append(paids, r.Pid)
}
case model.GotoPlayerLive:
if r.Pid != 0 {
roomIDs = append(roomIDs, r.Pid)
}
case model.GotoTabTagRcmd:
if r.Pid != 0 {
var taids []int64
if taids, err = s.rcmd.TagTop(c, mid, r.Pid, r.Limit); err != nil {
log.Error("%+v", err)
err = nil
continue
}
tids = append(tids, r.Pid)
r.Items = make([]*operate.Active, 0, len(taids))
for _, aid := range taids {
item := &operate.Active{Pid: aid, Goto: model.GotoAv, Param: strconv.FormatInt(aid, 10)}
r.Items = append(r.Items, item)
aids = append(aids, aid)
}
}
case model.GotoConverge:
cardm, aid, roomID, metaID := s.convergeCard(c, 3, r.Pid)
for id, card := range cardm {
convergem[id] = card
}
aids = append(aids, aid...)
roomIDs = append(roomIDs, roomID...)
metaIDs = append(metaIDs, metaID...)
case model.GotoTabContentRcmd:
for _, item := range r.Items {
if item.Pid == 0 {
continue
}
switch item.Goto {
case cdm.GotoAv:
aids = append(aids, item.Pid)
case cdm.GotoLive:
roomIDs = append(roomIDs, item.Pid)
case cdm.GotoBangumi:
sids = append(sids, item.Pid)
case cdm.GotoGame:
if card, ok := s.downloadCache[item.Pid]; ok {
downloadm[item.Pid] = card
}
case cdm.GotoArticle:
metaIDs = append(metaIDs, item.Pid)
case cdm.GotoSpecial:
cardm := s.specialCard(c, item.Pid)
for id, card := range cardm {
specialm[id] = card
}
case cdm.GotoPicture:
// 版本过滤5.37为新卡片
if (plat == model.PlatIPhone && build > 8300) || (plat == model.PlatAndroid && build > 5365000) {
picIDs = append(picIDs, item.Pid)
}
}
}
case model.GotoSpecial:
cardm := s.specialCard(c, r.Pid)
for id, card := range cardm {
specialm[id] = card
}
}
}
g, ctx := errgroup.WithContext(c)
if len(tids) != 0 {
g.Go(func() (err error) {
if tagm, err = s.tg.InfoByIDs(c, 0, tids); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(aids) != 0 {
g.Go(func() (err error) {
if am, err = s.ArchivesWithPlayer(ctx, aids, 0, "", 0, 0, 0, 0); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(paids) != 0 {
g.Go(func() (err error) {
if pam, err = s.ArchivesWithPlayer(ctx, paids, 32, mobiApp, 0, 0, forceHost, build); 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
}
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(metaIDs) != 0 {
g.Go(func() (err error) {
if metam, err = s.art.Articles(ctx, metaIDs); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if len(picIDs) != 0 {
g.Go(func() (err error) {
if picm, err = s.bplus.DynamicDetail(ctx, picIDs...); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
is = make([]card.Handler, 0, len(rs))
for _, r := range rs {
var main interface{}
cardGoto := cdm.CardGt(r.Type)
op := &operate.Card{}
op.From(cardGoto, r.Pid, 0, plat, build)
// 版本过滤
hasThreePoint := (plat == model.PlatIPhone && build >= 8240) || (plat == model.PlatAndroid && build > 5341000)
if hasThreePoint {
op.FromSwitch(cdm.SwitchFeedIndexTabThreePoint)
}
h := card.Handle(plat, cardGoto, "", cdm.ColumnSvrDouble, nil, tagm, nil, nil, nil)
if h == nil {
continue
}
switch r.Type {
case model.GotoPlayer:
main = pam
case model.GotoPlayerLive:
main = rm
case model.GotoSpecial:
op = specialm[r.Pid]
case model.GotoConverge:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoLive: rm, cdm.GotoArticle: metam}
op = convergem[r.Pid]
case model.GotoBanner:
op.FromActiveBanner(r.Items, "")
case model.GotoTabNews:
op.FromActive(r)
case model.GotoTabContentRcmd:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am, cdm.GotoGame: downloadm, cdm.GotoBangumi: sm, cdm.GotoLive: rm, cdm.GotoArticle: metam, cdm.GotoSpecial: specialm, cdm.GotoPicture: picm}
op.FromActive(r)
case model.GotoTabEntrance:
op.FromActive(r)
case model.GotoTabTagRcmd:
main = map[cdm.Gt]interface{}{cdm.GotoAv: am}
op.FromActive(r)
op.Items = make([]*operate.Card, 0, len(r.Items))
for _, item := range r.Items {
if item != nil {
op.Items = append(op.Items, &operate.Card{ID: item.Pid, Goto: item.Goto})
}
}
}
h.From(main, op)
if !h.Get().Right {
continue
}
if hasThreePoint {
h.Get().TabThreePointWatchLater()
}
is = append(is, h)
}
return
}

View File

@@ -0,0 +1,16 @@
package feed
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Menus(t *testing.T) {
Convey(t.Name(), t, func() {
m := s.Menus(context.Background(), 1, 2, time.Now())
So(m, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,403 @@
package feed
import (
"context"
"strconv"
"time"
"go-common/app/interface/main/app-feed/model"
"go-common/app/interface/main/app-feed/model/feed"
"go-common/app/interface/main/app-feed/model/live"
"go-common/app/interface/main/app-feed/model/tag"
article "go-common/app/interface/openplatform/article/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
busfeed "go-common/app/service/main/feed/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_iosBanBangumi = 4310
_androidBanBangumi = 502000
_androidIBanBangumi = 104000
)
func (s *Service) Upper(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) {
if (plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || (plat == model.PlatAndroidI && build >= _androidIBanBangumi) || plat == model.PlatIPhoneB {
is, lp = s.UpperFeed(c, mid, plat, build, pn, ps, now)
} else {
is, lp = s.UpperArchive(c, mid, plat, build, pn, ps, now)
}
return
}
// UpperFeed get the archives and bangumi for feed
// if archives are less then `_minTotalCnt` then will fill with recommended archives
func (s *Service) UpperFeed(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) {
var (
err error
hc bool
uis, fis []*busfeed.Feed
fp = pn == 1
)
if fp {
var (
unread int
count = ps
)
if unread, err = s.upper.UnreadCountCache(c, mid); err != nil {
log.Error("%+v", err)
} else if unread != 0 {
count = s.c.Feed.FeedCacheCount
}
if uis, err = s.upper.Feed(c, mid, pn, count); err != nil {
log.Error("%+v", err)
// get cache from redis
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil {
log.Error("%+v", err)
} else if hc {
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil {
log.Error("%+v", err)
}
}
if len(uis) == 0 {
is = _emptyItem
lp = true
return
}
} else if unread != 0 {
s.addCache(func() {
s.upper.AddUpItemCaches(context.Background(), mid, uis...)
})
}
} else {
if uis, err = s.upper.Feed(c, mid, pn, ps); err != nil {
log.Error("%+v", err)
// get cache from redis
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil {
log.Error("%+v", err)
} else if hc {
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil {
log.Error("%+v", err)
}
}
if len(uis) == 0 {
is = _emptyItem
lp = true
return
}
}
}
// handle feed
if len(uis) > ps {
fis = uis[:ps]
} else {
fis = uis
}
is = s.upperItem(c, fis, mid, now)
if len(is) < ps {
lp = true
}
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) upperCache(c context.Context, mid int64, plat int8, build, pn, ps int, now time.Time) (uis []*busfeed.Feed, err error) {
var (
start = (pn - 1) * ps
end = start + ps // from slice, end no -1
aids []int64
am map[int64]*api.Arc
seasonIDs []int64
psm map[int64]*busfeed.Bangumi
)
if uis, aids, seasonIDs, err = s.upper.UpItemCaches(c, mid, start, end); err != nil {
log.Error("%+v", err)
return
}
if len(aids) > 0 {
if am, err = s.arc.Archives(c, aids); err != nil {
log.Error("%+v", err)
return
}
}
if len(seasonIDs) > 0 && ((plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || plat == model.PlatIPhoneB) {
if psm, err = s.bgm.PullSeasons(c, seasonIDs, now); err != nil {
log.Error("%+v", err)
}
}
for _, ui := range uis {
switch ui.Type {
case busfeed.ArchiveType:
if a, ok := am[ui.ID]; ok {
ui.Archive = a
}
for _, r := range ui.Fold {
if a, ok := am[r.Aid]; ok {
r = a
} else {
r = nil
}
}
case busfeed.BangumiType:
if s, ok := psm[ui.ID]; ok {
ui.Bangumi = s
}
}
}
return
}
func (s *Service) UpperArchive(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) {
var (
err error
uis []*busfeed.Feed
hc bool
)
if uis, err = s.upper.ArchiveFeed(c, mid, pn, ps); err != nil {
log.Error("%+v", err)
// get cache from redis
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil {
log.Error("%+v", err)
} else if hc {
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil {
log.Error("%+v", err)
}
}
if len(uis) == 0 {
is = _emptyItem
lp = true
return
}
}
// handle feed
is = s.upperItem(c, uis, mid, now)
if len(is) < ps {
lp = true
}
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) UpperBangumi(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) {
var (
err error
uis []*busfeed.Feed
hc bool
)
if uis, err = s.upper.BangumiFeed(c, mid, pn, ps); err != nil {
log.Error("%+v", err)
// get cache from redis
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil {
log.Error("%+v", err)
} else if hc {
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil {
log.Error("%+v", err)
}
}
if len(uis) == 0 {
is = _emptyItem
lp = true
return
}
}
// handle feed
is = s.upperItem(c, uis, mid, now)
if len(is) < ps {
lp = true
}
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) UpperRecent(c context.Context, mid, upperID, aid int64, now time.Time) (is []*feed.Item) {
var (
err error
uis []*busfeed.Feed
)
if uis, err = s.upper.Recent(c, upperID, aid); err != nil {
log.Error("%+v", err)
}
// handle feed
is = s.upperItem(c, uis, mid, now)
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) upperItem(c context.Context, uis []*busfeed.Feed, mid int64, now time.Time) (is []*feed.Item) {
var (
g *errgroup.Group
ctx context.Context
owners, aids []int64
follows map[int64]bool
tm map[string][]*tag.Tag
err error
)
owners = make([]int64, 0, len(uis))
for _, ui := range uis {
if ui != nil {
if ui.Archive != nil {
owners = append(owners, ui.Archive.Author.Mid)
aids = append(aids, ui.Archive.Aid)
}
for _, r := range ui.Fold {
if r != nil {
aids = append(aids, r.Aid)
}
}
}
}
g, ctx = errgroup.WithContext(c)
if len(owners) != 0 {
g.Go(func() (err error) {
follows = s.acc.Relations3(ctx, owners, mid)
return
})
}
if len(aids) != 0 {
g.Go(func() (err error) {
if tm, err = s.tg.Tags(ctx, mid, aids, now); err != nil {
log.Error("%+v", err)
err = nil
}
return
})
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
return
}
is = make([]*feed.Item, 0, len(uis))
for _, ui := range uis {
if ui != nil {
switch ui.Type {
case busfeed.ArchiveType:
if ui.Archive != nil && ui.Archive.IsNormal() {
i := &feed.Item{}
i.FromAv(&archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(ui.Archive)})
i.RecCnt = len(ui.Fold)
if len(ui.Fold) > 0 {
ris := make([]*feed.Item, 0, len(ui.Fold))
for _, r := range ui.Fold {
if r != nil && r.IsNormal() {
ri := &feed.Item{}
ri.FromAv(&archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(r)})
if infos, ok := tm[strconv.FormatInt(r.Aid, 10)]; ok {
if len(infos) != 0 {
ri.Tag = &feed.Tag{TagID: infos[0].ID, TagName: infos[0].Name, IsAtten: infos[0].IsAtten, Count: &feed.TagCount{Atten: infos[0].Count.Atten}}
}
}
if follows[i.Mid] {
ri.IsAtten = 1
}
ris = append(ris, ri)
}
}
i.Recent = ris
}
if infos, ok := tm[strconv.FormatInt(ui.Archive.Aid, 10)]; ok {
if len(infos) != 0 {
i.Tag = &feed.Tag{TagID: infos[0].ID, TagName: infos[0].Name, IsAtten: infos[0].IsAtten, Count: &feed.TagCount{Atten: infos[0].Count.Atten}}
}
}
if follows[i.Mid] {
i.IsAtten = 1
}
is = append(is, i)
}
case busfeed.BangumiType:
if ui.Bangumi != nil {
i := &feed.Item{}
i.FromUpBangumi(ui.Bangumi)
is = append(is, i)
}
}
}
}
return
}
func (s *Service) UpperLive(c context.Context, mid int64) (is []*feed.Item, count int) {
var (
err error
fs []*live.Feed
pn = 1
ps = s.c.Feed.LiveFeedCount
)
if fs, count, err = s.lv.FeedList(c, mid, pn, ps); err != nil {
log.Error("%+v", err)
}
for _, f := range fs {
i := &feed.Item{}
i.FromUpLive(f)
is = append(is, i)
}
return
}
func (s *Service) UpperArticle(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) {
var (
err error
uis []*article.Meta
)
if uis, err = s.upper.ArticleFeed(c, mid, pn, ps); err != nil {
log.Error("%+v", err)
return
}
// handle feed
is = s.articleItem(c, uis, mid)
if len(is) < ps {
lp = true
}
if len(is) == 0 {
is = _emptyItem
}
return
}
func (s *Service) articleItem(c context.Context, uis []*article.Meta, mid int64) (is []*feed.Item) {
is = make([]*feed.Item, 0, len(uis))
for _, ui := range uis {
if ui != nil {
i := &feed.Item{}
i.FromUpArticle(ui)
is = append(is, i)
}
}
return
}
func (s *Service) UnreadCount(c context.Context, mid int64, plat int8, build int, now time.Time) (total, feedCount, articleCount int) {
var (
withoutBangumi = true
err error
)
if (plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || plat == model.PlatIPhoneB {
withoutBangumi = false
}
if feedCount, err = s.upper.AppUnreadCount(c, mid, withoutBangumi); err != nil {
log.Error("%+v", err)
}
if true {
if articleCount, err = s.upper.ArticleUnreadCount(c, mid); err != nil {
log.Error("%+v", err)
}
}
total = feedCount + articleCount
// add feed unread count cache
if feedCount > 0 {
s.addCache(func() {
s.upper.AddUnreadCountCache(context.Background(), mid, feedCount)
})
}
return
}

View File

@@ -0,0 +1,16 @@
package feed
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_UpperFeed(t *testing.T) {
Convey("should get UpperFeed", t, func() {
uf, _ := s.UpperFeed(context.Background(), 1, 2, 3, 4, 5, time.Now())
So(uf, ShouldNotBeNil)
})
}