You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
8.9 KiB
395 lines
8.9 KiB
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 |
|
}
|
|
|