2019-04-22 02:59:20 +00:00

404 lines
9.9 KiB
Go

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
}