go-common/app/interface/openplatform/article/service/list.go
2019-04-22 18:49:16 +08:00

396 lines
8.9 KiB
Go

package service
import (
"context"
"sort"
"go-common/app/interface/openplatform/article/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
var (
_blankList = &model.List{ID: -1}
_blankArtList = int64(-1)
_blankListArts = []*model.ListArtMeta{&model.ListArtMeta{ID: -1}}
)
func (s *Service) rawListArticles(c context.Context, listID int64) (res []*model.ListArtMeta, err error) {
if listID <= 0 {
return
}
arts, err := s.dao.CreativeListArticles(c, listID)
if err != nil {
return
}
var ids []int64
for _, art := range arts {
ids = append(ids, art.ID)
}
metas, err := s.dao.CreativeArticles(c, ids)
if err != nil {
return
}
for _, id := range ids {
if metas[id] != nil {
res = append(res, metas[id])
}
}
return
}
// List .
func (s *Service) List(c context.Context, id int64) (res *model.List, err error) {
res, err = s.dao.List(c, id)
res.FillDefaultImage(s.c.Article.ListDefaultImage)
return
}
// ListArticles get list passed articles
func (s *Service) ListArticles(c context.Context, id, mid int64) (res *model.ListArticles, err error) {
if id <= 0 {
return
}
res = &model.ListArticles{}
res.List, err = s.List(c, id)
if err != nil {
return
}
if res.List == nil {
err = ecode.NothingFound
return
}
var lastID int64
group := &errgroup.Group{}
group.Go(func() (err error) {
arts, err := s.dao.ListArts(c, id)
if err != nil {
return
}
for _, a := range arts {
if a.IsNormal() {
res.Articles = append(res.Articles, a)
}
}
return
})
group.Go(func() (err error) {
res.Author, err = s.author(c, res.List.Mid)
return
})
group.Go(func() (err error) {
res.List.Read, err = s.dao.CacheListReadCount(c, id)
return
})
group.Go(func() (err error) {
if mid > 0 {
res.Attention, _ = s.isAttention(c, mid, res.List.Mid)
}
return
})
group.Go(func() (err error) {
if mid == 0 {
return
}
lastID, _ = s.historyPosition(c, mid, res.List.ID)
return
})
err = group.Wait()
if res.Articles == nil {
res.Articles = []*model.ListArtMeta{}
}
res.List.ArticlesCount = int64(len(res.Articles))
res.Last.Strong()
if lastID == 0 {
return
}
for _, a := range res.Articles {
if a.ID == lastID {
res.Last = *a
break
}
}
return
}
// WebListArticles .
func (s *Service) WebListArticles(c context.Context, id, mid int64) (res *model.WebListArticles, err error) {
arts, err := s.ListArticles(c, id, mid)
res = &model.WebListArticles{Attention: arts.Attention, Author: arts.Author, List: arts.List, Last: arts.Last}
var ids []int64
for _, a := range arts.Articles {
ids = append(ids, a.ID)
}
var stats map[int64]*model.Stats
var states map[int64]int8
group, ctx := errgroup.WithContext(c)
group.Go(func() (err error) {
if len(ids) == 0 {
return
}
stats, _ = s.stats(ctx, ids)
return
})
group.Go(func() (err error) {
if mid == 0 || len(ids) == 0 {
return
}
states, _ = s.HadLikesByMid(ctx, mid, ids)
return
})
group.Wait()
for _, a := range arts.Articles {
art := &model.FullListArtMeta{ListArtMeta: a}
if s.categoriesMap[art.Category.ID] != nil {
art.Category = s.categoriesMap[art.Category.ID]
art.Categories = s.categoryParents[art.Category.ID]
}
s := stats[art.ID]
if s != nil {
art.Stats = *s
}
if states != nil {
art.LikeState = states[art.ID]
}
res.Articles = append(res.Articles, art)
}
return
}
// RebuildListCache rebuild list cache
func (s *Service) rebuildArticleListCache(c context.Context, aid int64) (listID int64, err error) {
s.deleteArtsListCache(c, aid)
lists, _ := s.dao.RawArtsListID(c, []int64{aid})
listID = lists[aid]
if listID > 0 {
err = s.dao.SetArticleListCache(c, listID, []*model.ListArtMeta{&model.ListArtMeta{ID: aid}})
}
return
}
// RebuildListCache rebuild list cache
func (s *Service) RebuildListCache(c context.Context, id int64) (err error) {
err = s.updateListCache(c, id)
if err != nil {
return
}
arts, err := s.dao.RawListArts(c, id)
if err != nil {
return
}
if err = s.updateListArtsCache(c, id, arts); err != nil {
return
}
if err = s.updateArtListCache(c, id, arts); err != nil {
return
}
list, err := s.dao.RawList(c, id)
if err != nil {
return
}
if list == nil {
err = ecode.NothingFound
return
}
if err = s.dao.RebuildUpListsCache(c, list.Mid); err != nil {
return
}
if err = s.dao.RebuildListReadCountCache(c, id); err != nil {
return
}
return
}
func (s *Service) updateListCache(c context.Context, id int64) (err error) {
list, err := s.dao.RawList(c, id)
if err != nil {
return
}
err = s.dao.AddCacheList(c, id, list)
return
}
func (s *Service) updateListArtsCache(c context.Context, id int64, arts []*model.ListArtMeta) (err error) {
if arts == nil {
arts, err = s.dao.RawListArts(c, id)
if err != nil {
return
}
}
if len(arts) == 0 {
err = s.deleteListArtsCache(c, id)
return
}
err = s.dao.AddCacheListArts(c, id, arts)
return
}
func (s *Service) updateArtListCache(c context.Context, id int64, arts []*model.ListArtMeta) (err error) {
if arts == nil {
arts, err = s.dao.RawListArts(c, id)
if err != nil {
return
}
}
err = s.dao.SetArticleListCache(c, id, arts)
return
}
func (s *Service) deleteListArtsCache(c context.Context, listID int64) (err error) {
err = s.dao.AddCacheListArts(c, listID, _blankListArts)
return
}
func (s *Service) deleteListCache(c context.Context, listID int64) (err error) {
l := map[int64]*model.List{listID: _blankList}
err = s.dao.AddCacheLists(c, l)
return
}
func (s *Service) deleteArtsListCache(c context.Context, ids ...int64) (err error) {
if len(ids) == 0 {
return
}
m := make(map[int64]int64)
for _, id := range ids {
m[id] = _blankArtList
}
if err = s.dao.AddCacheArtsListID(c, m); err != nil {
log.Errorv(c, log.KV("log", "deleteArtsListCache"), log.KV("err", err), log.KV("arg", ids))
}
return
}
// ListInfo list info
func (s *Service) ListInfo(c context.Context, aid int64) (res *model.ListInfo, err error) {
lists, err := s.dao.ArtsList(c, []int64{aid})
if err != nil {
return
}
list := lists[aid]
if list == nil {
err = ecode.NothingFound
return
}
res = &model.ListInfo{List: list}
var articles []*model.ListArtMeta
arts, err := s.dao.ListArts(c, list.ID)
if err != nil {
return
}
for _, a := range arts {
if a.IsNormal() {
articles = append(articles, a)
}
}
res.Total = len(articles)
for i, l := range articles {
if l.ID == aid {
res.Now = i
if i-1 >= 0 {
res.Last = articles[i-1]
}
if (i + 1) < len(articles) {
res.Next = articles[i+1]
}
break
}
}
res.List.FillDefaultImage(s.c.Article.ListDefaultImage)
res.List.Read, err = s.dao.CacheListReadCount(c, list.ID)
return
}
// Lists .
func (s *Service) Lists(c context.Context, keys []int64) (res map[int64]*model.List, err error) {
res, err = s.dao.Lists(c, keys)
for _, l := range res {
l.FillDefaultImage(s.c.Article.ListDefaultImage)
}
return
}
// UpLists .
func (s *Service) UpLists(c context.Context, mid int64, sortType int8) (res model.UpLists, err error) {
lists, err := s.dao.UpLists(c, mid)
if err != nil {
return
}
lmap, err := s.Lists(c, lists)
if err != nil {
return
}
arts, err := s.dao.ListsArts(c, lists)
if err != nil {
return
}
counts, err := s.dao.CacheListsReadCount(c, lists)
for _, l := range lists {
if lmap[l] != nil {
list := lmap[l]
if arts[l] != nil {
list.ArticlesCount = int64(len(arts[l]))
}
list.Read = counts[l]
res.Lists = append(res.Lists, list)
}
}
if sortType == model.ListSortView {
sort.Slice(res.Lists, func(i, j int) bool { return res.Lists[i].Read > res.Lists[j].Read })
} else {
sort.Slice(res.Lists, func(i, j int) bool { return res.Lists[i].PublishTime > res.Lists[j].PublishTime })
}
res.Total = len(res.Lists)
return
}
// rebuildAllListReadCount .
func (s *Service) rebuildAllListReadCount(c context.Context) error {
i := 0
for {
lists, err := s.dao.RawAllListsEx(c, i, 1000)
if err != nil {
log.Errorv(c, log.KV("RebuildAllReadCount err", err))
return err
}
if lists == nil {
return nil
}
for _, list := range lists {
err = s.dao.RebuildListReadCountCache(c, list.ID)
if err != nil {
log.Errorv(c, log.KV("RebuildAllReadCount err", err), log.KV("id", list.ID))
} else {
log.Infov(c, log.KV("RebuildAllReadCount", list.ID))
}
}
i += 1000
}
}
// RebuildAllListReadCount .
func (s *Service) RebuildAllListReadCount(c context.Context) {
go s.rebuildAllListReadCount(context.TODO())
}
// UpArtMetasAndLists .
func (s *Service) UpArtMetasAndLists(c context.Context, mid int64, pn int, ps int, sortType int) (res model.UpArtMetasLists, err error) {
metas, err := s.UpArticleMetas(c, mid, pn, ps, sortType)
if err != nil {
return
}
res.UpArtMetas = metas
res.UpLists, err = s.UpLists(c, mid, model.ListSortPtime)
if res.UpArtMetas == nil {
res.UpArtMetas = &model.UpArtMetas{}
}
if res.UpArtMetas.Articles == nil {
res.UpArtMetas.Articles = []*model.Meta{}
}
if res.UpLists.Lists == nil {
res.UpLists.Lists = []*model.List{}
}
return
}