list.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package service
  2. import (
  3. "context"
  4. "sort"
  5. "go-common/app/interface/openplatform/article/model"
  6. "go-common/library/ecode"
  7. "go-common/library/log"
  8. "go-common/library/sync/errgroup"
  9. )
  10. var (
  11. _blankList = &model.List{ID: -1}
  12. _blankArtList = int64(-1)
  13. _blankListArts = []*model.ListArtMeta{&model.ListArtMeta{ID: -1}}
  14. )
  15. func (s *Service) rawListArticles(c context.Context, listID int64) (res []*model.ListArtMeta, err error) {
  16. if listID <= 0 {
  17. return
  18. }
  19. arts, err := s.dao.CreativeListArticles(c, listID)
  20. if err != nil {
  21. return
  22. }
  23. var ids []int64
  24. for _, art := range arts {
  25. ids = append(ids, art.ID)
  26. }
  27. metas, err := s.dao.CreativeArticles(c, ids)
  28. if err != nil {
  29. return
  30. }
  31. for _, id := range ids {
  32. if metas[id] != nil {
  33. res = append(res, metas[id])
  34. }
  35. }
  36. return
  37. }
  38. // List .
  39. func (s *Service) List(c context.Context, id int64) (res *model.List, err error) {
  40. res, err = s.dao.List(c, id)
  41. res.FillDefaultImage(s.c.Article.ListDefaultImage)
  42. return
  43. }
  44. // ListArticles get list passed articles
  45. func (s *Service) ListArticles(c context.Context, id, mid int64) (res *model.ListArticles, err error) {
  46. if id <= 0 {
  47. return
  48. }
  49. res = &model.ListArticles{}
  50. res.List, err = s.List(c, id)
  51. if err != nil {
  52. return
  53. }
  54. if res.List == nil {
  55. err = ecode.NothingFound
  56. return
  57. }
  58. var lastID int64
  59. group := &errgroup.Group{}
  60. group.Go(func() (err error) {
  61. arts, err := s.dao.ListArts(c, id)
  62. if err != nil {
  63. return
  64. }
  65. for _, a := range arts {
  66. if a.IsNormal() {
  67. res.Articles = append(res.Articles, a)
  68. }
  69. }
  70. return
  71. })
  72. group.Go(func() (err error) {
  73. res.Author, err = s.author(c, res.List.Mid)
  74. return
  75. })
  76. group.Go(func() (err error) {
  77. res.List.Read, err = s.dao.CacheListReadCount(c, id)
  78. return
  79. })
  80. group.Go(func() (err error) {
  81. if mid > 0 {
  82. res.Attention, _ = s.isAttention(c, mid, res.List.Mid)
  83. }
  84. return
  85. })
  86. group.Go(func() (err error) {
  87. if mid == 0 {
  88. return
  89. }
  90. lastID, _ = s.historyPosition(c, mid, res.List.ID)
  91. return
  92. })
  93. err = group.Wait()
  94. if res.Articles == nil {
  95. res.Articles = []*model.ListArtMeta{}
  96. }
  97. res.List.ArticlesCount = int64(len(res.Articles))
  98. res.Last.Strong()
  99. if lastID == 0 {
  100. return
  101. }
  102. for _, a := range res.Articles {
  103. if a.ID == lastID {
  104. res.Last = *a
  105. break
  106. }
  107. }
  108. return
  109. }
  110. // WebListArticles .
  111. func (s *Service) WebListArticles(c context.Context, id, mid int64) (res *model.WebListArticles, err error) {
  112. arts, err := s.ListArticles(c, id, mid)
  113. res = &model.WebListArticles{Attention: arts.Attention, Author: arts.Author, List: arts.List, Last: arts.Last}
  114. var ids []int64
  115. for _, a := range arts.Articles {
  116. ids = append(ids, a.ID)
  117. }
  118. var stats map[int64]*model.Stats
  119. var states map[int64]int8
  120. group, ctx := errgroup.WithContext(c)
  121. group.Go(func() (err error) {
  122. if len(ids) == 0 {
  123. return
  124. }
  125. stats, _ = s.stats(ctx, ids)
  126. return
  127. })
  128. group.Go(func() (err error) {
  129. if mid == 0 || len(ids) == 0 {
  130. return
  131. }
  132. states, _ = s.HadLikesByMid(ctx, mid, ids)
  133. return
  134. })
  135. group.Wait()
  136. for _, a := range arts.Articles {
  137. art := &model.FullListArtMeta{ListArtMeta: a}
  138. if s.categoriesMap[art.Category.ID] != nil {
  139. art.Category = s.categoriesMap[art.Category.ID]
  140. art.Categories = s.categoryParents[art.Category.ID]
  141. }
  142. s := stats[art.ID]
  143. if s != nil {
  144. art.Stats = *s
  145. }
  146. if states != nil {
  147. art.LikeState = states[art.ID]
  148. }
  149. res.Articles = append(res.Articles, art)
  150. }
  151. return
  152. }
  153. // RebuildListCache rebuild list cache
  154. func (s *Service) rebuildArticleListCache(c context.Context, aid int64) (listID int64, err error) {
  155. s.deleteArtsListCache(c, aid)
  156. lists, _ := s.dao.RawArtsListID(c, []int64{aid})
  157. listID = lists[aid]
  158. if listID > 0 {
  159. err = s.dao.SetArticleListCache(c, listID, []*model.ListArtMeta{&model.ListArtMeta{ID: aid}})
  160. }
  161. return
  162. }
  163. // RebuildListCache rebuild list cache
  164. func (s *Service) RebuildListCache(c context.Context, id int64) (err error) {
  165. err = s.updateListCache(c, id)
  166. if err != nil {
  167. return
  168. }
  169. arts, err := s.dao.RawListArts(c, id)
  170. if err != nil {
  171. return
  172. }
  173. if err = s.updateListArtsCache(c, id, arts); err != nil {
  174. return
  175. }
  176. if err = s.updateArtListCache(c, id, arts); err != nil {
  177. return
  178. }
  179. list, err := s.dao.RawList(c, id)
  180. if err != nil {
  181. return
  182. }
  183. if list == nil {
  184. err = ecode.NothingFound
  185. return
  186. }
  187. if err = s.dao.RebuildUpListsCache(c, list.Mid); err != nil {
  188. return
  189. }
  190. if err = s.dao.RebuildListReadCountCache(c, id); err != nil {
  191. return
  192. }
  193. return
  194. }
  195. func (s *Service) updateListCache(c context.Context, id int64) (err error) {
  196. list, err := s.dao.RawList(c, id)
  197. if err != nil {
  198. return
  199. }
  200. err = s.dao.AddCacheList(c, id, list)
  201. return
  202. }
  203. func (s *Service) updateListArtsCache(c context.Context, id int64, arts []*model.ListArtMeta) (err error) {
  204. if arts == nil {
  205. arts, err = s.dao.RawListArts(c, id)
  206. if err != nil {
  207. return
  208. }
  209. }
  210. if len(arts) == 0 {
  211. err = s.deleteListArtsCache(c, id)
  212. return
  213. }
  214. err = s.dao.AddCacheListArts(c, id, arts)
  215. return
  216. }
  217. func (s *Service) updateArtListCache(c context.Context, id int64, arts []*model.ListArtMeta) (err error) {
  218. if arts == nil {
  219. arts, err = s.dao.RawListArts(c, id)
  220. if err != nil {
  221. return
  222. }
  223. }
  224. err = s.dao.SetArticleListCache(c, id, arts)
  225. return
  226. }
  227. func (s *Service) deleteListArtsCache(c context.Context, listID int64) (err error) {
  228. err = s.dao.AddCacheListArts(c, listID, _blankListArts)
  229. return
  230. }
  231. func (s *Service) deleteListCache(c context.Context, listID int64) (err error) {
  232. l := map[int64]*model.List{listID: _blankList}
  233. err = s.dao.AddCacheLists(c, l)
  234. return
  235. }
  236. func (s *Service) deleteArtsListCache(c context.Context, ids ...int64) (err error) {
  237. if len(ids) == 0 {
  238. return
  239. }
  240. m := make(map[int64]int64)
  241. for _, id := range ids {
  242. m[id] = _blankArtList
  243. }
  244. if err = s.dao.AddCacheArtsListID(c, m); err != nil {
  245. log.Errorv(c, log.KV("log", "deleteArtsListCache"), log.KV("err", err), log.KV("arg", ids))
  246. }
  247. return
  248. }
  249. // ListInfo list info
  250. func (s *Service) ListInfo(c context.Context, aid int64) (res *model.ListInfo, err error) {
  251. lists, err := s.dao.ArtsList(c, []int64{aid})
  252. if err != nil {
  253. return
  254. }
  255. list := lists[aid]
  256. if list == nil {
  257. err = ecode.NothingFound
  258. return
  259. }
  260. res = &model.ListInfo{List: list}
  261. var articles []*model.ListArtMeta
  262. arts, err := s.dao.ListArts(c, list.ID)
  263. if err != nil {
  264. return
  265. }
  266. for _, a := range arts {
  267. if a.IsNormal() {
  268. articles = append(articles, a)
  269. }
  270. }
  271. res.Total = len(articles)
  272. for i, l := range articles {
  273. if l.ID == aid {
  274. res.Now = i
  275. if i-1 >= 0 {
  276. res.Last = articles[i-1]
  277. }
  278. if (i + 1) < len(articles) {
  279. res.Next = articles[i+1]
  280. }
  281. break
  282. }
  283. }
  284. res.List.FillDefaultImage(s.c.Article.ListDefaultImage)
  285. res.List.Read, err = s.dao.CacheListReadCount(c, list.ID)
  286. return
  287. }
  288. // Lists .
  289. func (s *Service) Lists(c context.Context, keys []int64) (res map[int64]*model.List, err error) {
  290. res, err = s.dao.Lists(c, keys)
  291. for _, l := range res {
  292. l.FillDefaultImage(s.c.Article.ListDefaultImage)
  293. }
  294. return
  295. }
  296. // UpLists .
  297. func (s *Service) UpLists(c context.Context, mid int64, sortType int8) (res model.UpLists, err error) {
  298. lists, err := s.dao.UpLists(c, mid)
  299. if err != nil {
  300. return
  301. }
  302. lmap, err := s.Lists(c, lists)
  303. if err != nil {
  304. return
  305. }
  306. arts, err := s.dao.ListsArts(c, lists)
  307. if err != nil {
  308. return
  309. }
  310. counts, err := s.dao.CacheListsReadCount(c, lists)
  311. for _, l := range lists {
  312. if lmap[l] != nil {
  313. list := lmap[l]
  314. if arts[l] != nil {
  315. list.ArticlesCount = int64(len(arts[l]))
  316. }
  317. list.Read = counts[l]
  318. res.Lists = append(res.Lists, list)
  319. }
  320. }
  321. if sortType == model.ListSortView {
  322. sort.Slice(res.Lists, func(i, j int) bool { return res.Lists[i].Read > res.Lists[j].Read })
  323. } else {
  324. sort.Slice(res.Lists, func(i, j int) bool { return res.Lists[i].PublishTime > res.Lists[j].PublishTime })
  325. }
  326. res.Total = len(res.Lists)
  327. return
  328. }
  329. // rebuildAllListReadCount .
  330. func (s *Service) rebuildAllListReadCount(c context.Context) error {
  331. i := 0
  332. for {
  333. lists, err := s.dao.RawAllListsEx(c, i, 1000)
  334. if err != nil {
  335. log.Errorv(c, log.KV("RebuildAllReadCount err", err))
  336. return err
  337. }
  338. if lists == nil {
  339. return nil
  340. }
  341. for _, list := range lists {
  342. err = s.dao.RebuildListReadCountCache(c, list.ID)
  343. if err != nil {
  344. log.Errorv(c, log.KV("RebuildAllReadCount err", err), log.KV("id", list.ID))
  345. } else {
  346. log.Infov(c, log.KV("RebuildAllReadCount", list.ID))
  347. }
  348. }
  349. i += 1000
  350. }
  351. }
  352. // RebuildAllListReadCount .
  353. func (s *Service) RebuildAllListReadCount(c context.Context) {
  354. go s.rebuildAllListReadCount(context.TODO())
  355. }
  356. // UpArtMetasAndLists .
  357. func (s *Service) UpArtMetasAndLists(c context.Context, mid int64, pn int, ps int, sortType int) (res model.UpArtMetasLists, err error) {
  358. metas, err := s.UpArticleMetas(c, mid, pn, ps, sortType)
  359. if err != nil {
  360. return
  361. }
  362. res.UpArtMetas = metas
  363. res.UpLists, err = s.UpLists(c, mid, model.ListSortPtime)
  364. if res.UpArtMetas == nil {
  365. res.UpArtMetas = &model.UpArtMetas{}
  366. }
  367. if res.UpArtMetas.Articles == nil {
  368. res.UpArtMetas.Articles = []*model.Meta{}
  369. }
  370. if res.UpLists.Lists == nil {
  371. res.UpLists.Lists = []*model.List{}
  372. }
  373. return
  374. }