123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- package service
- import (
- "context"
- "sort"
- "go-common/app/interface/main/reply/model/reply"
- xmodel "go-common/app/interface/main/reply/model/xreply"
- "go-common/library/sync/errgroup.v2"
- )
- const (
- _secondRepliesPn = 1
- _secondRepliesPs = 3
- _hotSize = 5
- _hotSizeWeb = 3
- )
- func fillHot(rs []*reply.Reply, sub *reply.Subject, maxSize int) (hots []*reply.Reply) {
- for _, r := range rs {
- if r.Like >= 3 && !r.IsTop() && !r.IsDeleted() {
- hots = append(hots, r)
- }
- }
- if hots == nil {
- hots = _emptyReplies
- } else if len(hots) > maxSize {
- hots = hots[:maxSize]
- }
- if sub.RCount <= 20 && len(hots) > 0 {
- hots = _emptyReplies
- }
- return hots
- }
- // buildResCursor ...
- func buildResCursor(reqCursor *xmodel.Cursor, replies []*reply.Reply, cursorMode int) (resCursor xmodel.CursorRes) {
- length := len(replies)
- switch cursorMode {
- case xmodel.CursorModePage:
- // next和prev只可能一个不为0
- curPage := reqCursor.Next + reqCursor.Prev
- if reqCursor.Latest() {
- resCursor.IsBegin = true
- if length == 0 {
- resCursor.Next = curPage
- resCursor.Prev = curPage
- resCursor.IsEnd = true
- } else {
- // 下一页是第二页
- resCursor.Next = 2
- resCursor.Prev = 1
- if length < reqCursor.Ps {
- resCursor.IsEnd = true
- }
- }
- } else if reqCursor.Forward() {
- resCursor.Next = curPage + 1
- resCursor.Prev = curPage
- if length < reqCursor.Ps {
- resCursor.IsEnd = true
- }
- } else if reqCursor.Backward() {
- resCursor.Next = curPage
- resCursor.Prev = curPage - 1
- if length < reqCursor.Ps {
- resCursor.IsBegin = true
- }
- }
- case xmodel.CursorModeCursor:
- if reqCursor.Latest() {
- resCursor.IsBegin = true
- // Latest, 点进来默认访问的情况
- if length == 0 {
- resCursor.Next = reqCursor.Next
- resCursor.Prev = reqCursor.Prev
- resCursor.IsEnd = true
- } else {
- resCursor.Next = replies[length-1].Floor
- resCursor.Prev = replies[0].Floor
- if length < reqCursor.Ps {
- resCursor.IsEnd = true
- }
- }
- } else if reqCursor.Forward() {
- if length == 0 {
- resCursor.Next = reqCursor.Next
- resCursor.Prev = reqCursor.Prev
- resCursor.IsEnd = true
- } else {
- resCursor.Next = replies[length-1].Floor
- resCursor.Prev = replies[0].Floor
- if length < reqCursor.Ps {
- resCursor.IsEnd = true
- }
- }
- } else if reqCursor.Backward() {
- if length == 0 {
- resCursor.Next = reqCursor.Next
- resCursor.Prev = reqCursor.Prev
- resCursor.IsBegin = true
- } else {
- resCursor.Next = replies[length-1].Floor
- resCursor.Prev = replies[0].Floor
- if length < reqCursor.Ps {
- resCursor.IsBegin = true
- }
- }
- }
- }
- return
- }
- // replyMisc ...
- func (s *Service) replyCommonRes(ctx context.Context, mid, oid int64, tp int8, sub *reply.Subject) (res xmodel.CommonRes) {
- if sub == nil {
- return
- }
- g := errgroup.WithContext(ctx)
- g.Go(func(ctx context.Context) error {
- if s.RelationBlocked(ctx, sub.Mid, mid) {
- res.Blacklist = 1
- }
- return nil
- })
- g.Go(func(ctx context.Context) error {
- if ok, _ := s.CheckAssist(ctx, sub.Mid, mid); ok {
- res.Assist = 1
- }
- return nil
- })
- // 默认都是展示
- res.Config.ShowAdmin, res.Config.ShowEntry, res.Config.ShowFloor = 1, 1, 1
- g.Go(func(ctx context.Context) error {
- if cfg, _ := s.GetReplyLogConfig(ctx, sub, 1); cfg != nil {
- res.Config.ShowAdmin, res.Config.ShowEntry = cfg.ShowAdmin, cfg.ShowEntry
- }
- // 特殊稿件不显示楼层
- if !s.ShowFloor(oid, tp) {
- res.Config.ShowFloor = 0
- }
- return nil
- })
- g.Wait()
- res.Upper.Mid = sub.Mid
- return
- }
- // fillXreplyRes ...
- func (s *Service) fillXreplyRes(ctx context.Context, sub *reply.Subject, req *xmodel.ReplyReq, res *xmodel.ReplyRes) {
- res.CommonRes = s.replyCommonRes(ctx, req.Mid, req.Oid, req.Type, sub)
- res.Notice = s.RplyNotice(ctx, req.Plat, req.Build, req.MobiApp, req.Buvid)
- // 过滤掉可能的脏数据
- res.Replies = s.FilDelReply(res.Replies)
- res.Hots = s.FilDelReply(res.Hots)
- // 过滤掉赞数小于3的
- res.Hots = fillHot(res.Hots, sub, s.hotNum(req.Oid, req.Type))
- res.Cursor.AllCount = sub.ACount
- res.Folder = sub.Folder()
- }
- // Xreply ...
- func (s *Service) Xreply(ctx context.Context, req *xmodel.ReplyReq) (res *xmodel.ReplyRes, err error) {
- var (
- sub *reply.Subject
- cursor *reply.Cursor
- cursorRes *reply.RootReplyList
- pageRes *reply.PageResult
- )
- res = new(xmodel.ReplyRes)
- mode, supportMode := req.ModeInfo(s.sortByHot, s.sortByTime)
- switch mode {
- case xmodel.ModeOrigin, xmodel.ModeTime:
- // 这里原来用的闭区间,所以这里有坑
- if req.Cursor.Forward() {
- if req.Cursor.Next > 1 {
- req.Cursor.Next--
- }
- } else if req.Cursor.Backward() {
- req.Cursor.Prev++
- }
- if cursor, err = reply.NewCursor(int64(req.Cursor.Next), int64(req.Cursor.Prev), req.Cursor.Ps, reply.OrderDESC); err != nil {
- return
- }
- if req.Cursor.Backward() {
- if cursor, err = reply.NewCursor(int64(req.Cursor.Next), int64(req.Cursor.Prev), req.Cursor.Ps, reply.OrderASC); err != nil {
- return
- }
- }
- cursorParams := &reply.CursorParams{
- IP: req.IP,
- Oid: req.Oid,
- OTyp: req.Type,
- Sort: reply.SortByFloor,
- HTMLEscape: false,
- Cursor: cursor,
- HotSize: s.hotNum(req.Oid, req.Type),
- Mid: req.Mid,
- }
- if cursorRes, err = s.GetRootReplyListByCursor(ctx, cursorParams); err != nil {
- return
- }
- sub = cursorRes.Subject
- res.Replies = cursorRes.Roots
- if cursorRes.Header != nil {
- res.Top.Admin = cursorRes.Header.TopAdmin
- res.Top.Upper = cursorRes.Header.TopUpper
- res.Hots = cursorRes.Header.Hots
- // 纯按楼层排序 去掉热评
- if mode == xmodel.ModeTime {
- res.Hots = _emptyReplies
- }
- }
- if !sort.SliceIsSorted(res.Replies, func(i, j int) bool { return res.Replies[i].Floor > res.Replies[j].Floor }) {
- sort.Slice(res.Replies, func(i, j int) bool { return res.Replies[i].Floor > res.Replies[j].Floor })
- }
- // 这里原来用的闭区间,所以这里有坑
- if req.Cursor.Next == 1 {
- res.Replies = _emptyReplies
- }
- // 由服务端来控制翻页逻辑
- res.Cursor = buildResCursor(&xmodel.Cursor{Prev: req.Cursor.Prev, Next: req.Cursor.Next, Ps: req.Cursor.Ps}, res.Replies, xmodel.CursorModeCursor)
- case xmodel.ModeHot:
- var curPage = req.Cursor.Prev + req.Cursor.Next
- if req.Cursor.Latest() {
- curPage = 1
- }
- pageParams := &reply.PageParams{
- Mid: req.Mid,
- Oid: req.Oid,
- Type: req.Type,
- Sort: reply.SortByLike,
- PageNum: curPage,
- PageSize: req.Cursor.Ps,
- NeedSecond: true,
- Escape: false,
- NeedHot: false,
- }
- if pageRes, err = s.RootReplies(ctx, pageParams); err != nil {
- return
- }
- sub = pageRes.Subject
- res.Replies = pageRes.Roots
- res.Top.Admin = pageRes.TopAdmin
- res.Top.Upper = pageRes.TopUpper
- // 按页码翻页控制返回页码
- res.Cursor = buildResCursor(&xmodel.Cursor{Prev: req.Cursor.Prev, Next: req.Cursor.Next, Ps: req.Cursor.Ps}, res.Replies, xmodel.CursorModePage)
- }
- res.Cursor.Mode = mode
- res.Cursor.SupportMode = supportMode
- s.fillXreplyRes(ctx, sub, req, res)
- return
- }
- // SubFoldedReply ...
- func (s *Service) SubFoldedReply(ctx context.Context, req *xmodel.SubFolderReq) (res *xmodel.SubFolderRes, err error) {
- var (
- rpIDs []int64
- rootMap map[int64]*reply.Reply
- childrenMap map[int64][]*reply.Reply
- rootRps []*reply.Reply
- childrenRps []*reply.Reply
- sub *reply.Subject
- )
- res = new(xmodel.SubFolderRes)
- if req.Cursor.Backward() {
- return
- }
- cursor := &xmodel.Cursor{
- Ps: req.Cursor.Ps,
- Next: req.Cursor.Next,
- }
- if sub, err = s.Subject(ctx, req.Oid, req.Type); err != nil {
- return
- }
- if rpIDs, err = s.foldedReplies(ctx, sub, 0, cursor); err != nil {
- return
- }
- if rootMap, err = s.repliesMap(ctx, req.Oid, req.Type, rpIDs); err != nil {
- return
- }
- if childrenMap, childrenRps, err = s.secondReplies(ctx, sub, rootMap, req.Mid, _secondRepliesPn, _secondRepliesPs); err != nil {
- return
- }
- for _, rpID := range rpIDs {
- if r, ok := rootMap[rpID]; ok {
- if children, hasChild := childrenMap[rpID]; hasChild {
- r.Replies = children
- childrenRps = append(childrenRps, children...)
- } else {
- r.Replies = _emptyReplies
- }
- rootRps = append(rootRps, r)
- }
- }
- if rootRps != nil {
- res.Replies = rootRps
- } else {
- res.Replies = _emptyReplies
- }
- var rps []*reply.Reply
- rps = append(rps, rootRps...)
- rps = append(rps, childrenRps...)
- if err = s.buildReply(ctx, sub, rps, req.Mid, false); err != nil {
- return
- }
- res.Cursor = buildResCursor(&xmodel.Cursor{Prev: req.Cursor.Prev, Next: req.Cursor.Next, Ps: req.Cursor.Ps}, res.Replies, xmodel.CursorModeCursor)
- res.CommonRes = s.replyCommonRes(ctx, req.Mid, req.Oid, req.Type, sub)
- return
- }
- // RootFoldedReply ...
- func (s *Service) RootFoldedReply(ctx context.Context, req *xmodel.RootFolderReq) (res *xmodel.RootFolderRes, err error) {
- var (
- rpIDs []int64
- childrenMap map[int64]*reply.Reply
- childrenRps []*reply.Reply
- sub *reply.Subject
- )
- res = new(xmodel.RootFolderRes)
- if req.Cursor.Backward() {
- return
- }
- cursor := &xmodel.Cursor{
- Ps: req.Cursor.Ps,
- Next: req.Cursor.Next,
- }
- if sub, err = s.Subject(ctx, req.Oid, req.Type); err != nil {
- return
- }
- if rpIDs, err = s.foldedReplies(ctx, sub, req.Root, cursor); err != nil {
- return
- }
- if childrenMap, err = s.repliesMap(ctx, req.Oid, req.Type, rpIDs); err != nil {
- return
- }
- for _, rpID := range rpIDs {
- if r, ok := childrenMap[rpID]; ok {
- childrenRps = append(childrenRps, r)
- }
- }
- if childrenRps != nil {
- res.Replies = childrenRps
- } else {
- res.Replies = _emptyReplies
- }
- if err = s.buildReply(ctx, sub, res.Replies, req.Mid, false); err != nil {
- return
- }
- // 只有往下翻
- res.Cursor = buildResCursor(&xmodel.Cursor{Prev: req.Cursor.Prev, Next: req.Cursor.Next, Ps: req.Cursor.Ps}, res.Replies, xmodel.CursorModeCursor)
- res.CommonRes = s.replyCommonRes(ctx, req.Mid, req.Oid, req.Type, sub)
- return
- }
- // foldedReplies ...
- func (s *Service) foldedReplies(ctx context.Context, sub *reply.Subject, root int64, cursor *xmodel.Cursor) (rpIDs []int64, err error) {
- var (
- kind string
- ID int64
- ok bool
- )
- if root == 0 {
- kind = xmodel.FolderKindSub
- ID = sub.Oid
- } else {
- kind = xmodel.FolderKindRoot
- ID = root
- }
- if ok, err = s.dao.Redis.ExpireFolder(ctx, kind, ID); err != nil {
- return
- }
- if ok {
- if rpIDs, err = s.dao.Redis.FolderByCursor(ctx, kind, ID, cursor); err != nil {
- return
- }
- } else {
- if rpIDs, err = s.dao.Reply.FoldedRepliesCursor(ctx, sub.Oid, sub.Type, root, cursor); err != nil {
- return
- }
- s.cache.Do(ctx, func(ctx context.Context) {
- s.dao.Databus.RecoverFolderIdx(ctx, sub.Oid, sub.Type, root)
- })
- }
- return
- }
|