package service import ( "context" "fmt" "time" model "go-common/app/interface/main/credit/model" accmdl "go-common/app/service/main/account/api" filgrpc "go-common/app/service/main/filter/api/grpc/v1" memmdl "go-common/app/service/main/member/model" "go-common/library/ecode" "go-common/library/log" "go-common/library/net/metadata" xtime "go-common/library/time" "github.com/pkg/errors" ) var ( _emptyBlockedCase = []*model.BlockedCase{} ) // Apply user apply jury. func (s *Service) Apply(c context.Context, mid int64) (err error) { var ( num int64 res *accmdl.CardReply idfStatus *memmdl.RealnameStatus arg = &accmdl.MidReq{Mid: mid} ) if res, err = s.accountClient.Card3(c, arg); err != nil { err = errors.Wrap(err, "s.accountClient.Card2") return } if res.Card.Level <= 3 { err = ecode.CreditLevelLimit return } if res.Card.Silence == 1 { err = ecode.CreditIsBlock return } if idfStatus, err = s.memRPC.RealnameStatus(c, &memmdl.ArgMemberMid{Mid: mid, RemoteIP: metadata.String(c, metadata.RemoteIP)}); err != nil { return } if *idfStatus != memmdl.RealnameStatusTrue { err = ecode.CreditIsVerify return } if num, err = s.dao.BlockTotalTime(c, mid, time.Now().AddDate(0, 0, -90)); err != nil { err = ecode.CreditIsBlock return } if num != 0 { err = ecode.CreditIsBlock return } juryinfo, err := s.JuryInfoCache(c, mid) if err != nil { return } if juryinfo.Status == model.JuryStatusEffect { err = ecode.CreditNoApply return } if juryinfo.Black == model.JuryBlack { err = ecode.CreditBlack return } if err = s.dao.JuryApply(c, mid, time.Now().AddDate(0, 0, model.JuryExpiredDays)); err != nil { return } s.addCache(func() { s.dao.DelJuryInfoCache(context.TODO(), mid) s.dao.SendSysMsg(context.TODO(), mid, model.ApplyJuryTitle, fmt.Sprintf(model.ApplyJuryContext, model.JuryExpiredDays)) }) return } // Requirement user status in apply jury. func (s *Service) Requirement(c context.Context, mid int64) (jr *model.JuryRequirement, err error) { var ( num int64 card *accmdl.CardReply idfStatus *memmdl.RealnameStatus argMId = &accmdl.MidReq{Mid: mid} ) jr = &model.JuryRequirement{} if card, err = s.accountClient.Card3(c, argMId); err != nil { return } jr.Level = card.Card.Level > 3 jr.Blocked = card.Card.Silence == 1 if idfStatus, err = s.memRPC.RealnameStatus(c, &memmdl.ArgMemberMid{Mid: mid, RemoteIP: metadata.String(c, metadata.RemoteIP)}); err != nil { return } jr.Cert = *idfStatus == memmdl.RealnameStatusTrue if num, err = s.dao.BlockTotalTime(c, mid, time.Now().AddDate(0, 0, -90)); err != nil { return } jr.Rule = num == 0 return } // Jury jury user info. func (s *Service) Jury(c context.Context, mid int64) (ui *model.UserInfo, err error) { var ( info *accmdl.InfoReply juryinfo *model.BlockedJury argMId = &accmdl.MidReq{ Mid: mid, } ) if juryinfo, err = s.JuryInfoCache(c, mid); err != nil { return } if juryinfo.MID == 0 { err = ecode.CreditNotJury return } ui = &model.UserInfo{} ui.Status = juryinfo.Status if juryinfo.VoteTotal < 3 { ui.RightRadio = 50 } else { ui.RightRadio = juryinfo.VoteRight * 100 / juryinfo.VoteTotal } if info, err = s.accountClient.Info3(c, argMId); err != nil { log.Error("s.accountClient.Info3(%d) error(%v)", mid, err) return } ui.Uname = info.Info.Name ui.Face = info.Info.Face if juryinfo.Status == 1 { delta := int64(juryinfo.Expired) - time.Now().Unix() if delta <= 0 { ui.RestDays = 0 } else { ui.RestDays = delta / model.OneDaySecond if delta%model.OneDaySecond != 0 { ui.RestDays = ui.RestDays + 1 } } } ui.CaseTotal = juryinfo.CaseTotal return } // CaseObtain jury user obtain case list. func (s *Service) CaseObtain(c context.Context, mid int64, pubCid int64) (cid int64, err error) { juryInfo, err := s.JuryInfoCache(c, mid) if err != nil { return } if juryInfo.MID == 0 { err = ecode.CreditNotJury return } if juryInfo.Status != model.JuryStatusEffect || int64(juryInfo.Expired) < time.Now().Unix() { err = ecode.CreditJuryExpired return } if juryInfo.VoteTotal > 3 && (float64(juryInfo.VoteRight)/float64(juryInfo.VoteTotal)*100 < float64(s.c.Judge.JuryRatio)) { err = ecode.CreditUnderVoteRate return } if cid, err = s.caseVoteID(c, mid, pubCid); err != nil { return } if cid == 0 { err = ecode.CreditNoCase return } return } // Vote jury user vote case. func (s *Service) Vote(c context.Context, mid, cid int64, attr, vote, aType, aReason int8, oc string, likes, hates []int64) (err error) { if vote < model.VoteBanned && vote > model.VoteDel { err = ecode.CreditVoteNotExist return } var r *model.BlockedJury if r, err = s.JuryInfoCache(c, mid); err != nil { return } if r.MID == 0 { err = ecode.CreditNotJury return } var ca *model.BlockedCase if ca, err = s.CaseInfoCache(c, cid); err != nil { return } if ca.ID == 0 { err = ecode.CreditCaseNotExist return } if ca.JudgeType != model.JudgeTypeUndeal || ca.Status == model.CaseStatusDealed || ca.Status == model.CaseStatusUndealed { err = ecode.CreditNovote return } var id int64 if id, err = s.dao.IsVote(c, mid, cid); err != nil { return } if id == 0 { err = ecode.CreditNovote return } var content string if content, err = s.filterContent(c, oc, mid); err != nil { return } if err = s.setVote(c, mid, cid, id, content, attr, vote); err != nil { return } if len(likes) > 0 { s.dao.AddLikes(c, likes) } if len(hates) > 0 { s.dao.AddHates(c, hates) } if aType != 0 && model.ReasonTypeDesc(aReason) != "" { s.dao.AddCaseReasonApply(c, mid, cid, aType, ca.ReasonType, aReason) } var rate int8 if rate, err = s.dao.NewKPI(c, mid); err != nil { return } if s.getVoteField(vote) != "" { if err = s.dao.AddCaseVoteTotal(c, s.getVoteField(vote), cid, s.getVoteNum(rate)); err != nil { return } } if r.CaseTotal >= model.GuardMedalPointC && r.GantMedalID() != model.GuardMedalNone { s.addCache(func() { for i := 0; i <= 5; i++ { if err = s.dao.SendMedal(context.Background(), mid, r.GantMedalID()); err != nil { log.Error("s.dao.SendMedal(mid:%d medalid:%d) err(%v)", mid, r.GantMedalID(), err) continue } break } }) } return } func (s *Service) filterContent(c context.Context, oc string, mid int64) (content string, err error) { var res *filgrpc.FilterReply if oc == "" { return "", nil } if res, err = s.fliClient.Filter(c, &filgrpc.FilterReq{Area: "reply", Message: oc}); err != nil { return } if res.Level > 0 { content = "" } else { content = res.Result } log.Info("fiter mid(%d):oc(%s):content(%s):res(%v)", mid, oc, content, res) return } func (s *Service) getVoteField(vote int8) string { switch vote { case 1: return "vote_break" case 2: return "vote_rule" case 4: return "vote_delete" } return "" } func (s *Service) getVoteNum(rate int8) int8 { switch rate { case model.KPILevelS: return s.c.Judge.VoteNum.RateS case model.KPILevelA: return s.c.Judge.VoteNum.RateA case model.KPILevelB: return s.c.Judge.VoteNum.RateB case model.KPILevelC: return s.c.Judge.VoteNum.RateC case model.KPILevelD: return s.c.Judge.VoteNum.RateD default: return 1 } } func (s *Service) setVote(c context.Context, mid, cid, id int64, content string, attr, vote int8) (err error) { tx, err := s.dao.BeginTran(c) if err != nil { log.Error("BeginTran err(%v)", err) return } defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() _, err = s.dao.SetVoteTx(tx, mid, cid, vote) if err != nil { log.Error("tx.SetVote err(%v)", err) return } if len(content) > 0 { var ( preContent string state int8 ) if preContent, err = s.dao.OpContentMid(c, mid); err != nil { log.Error("s.dao.OpContentMid(%d) err(%v)", mid, err) return } if preContent == content { state = model.OpinionStateNoOK } _, err = s.dao.AddOpinionTx(tx, cid, id, mid, content, attr, vote, state) if err != nil { log.Error("AddOpinionTx err(%v)", err) return } } return } // VoteInfo jury user vote info. func (s *Service) VoteInfo(c context.Context, mid int64, cid int64) (vi *model.VoteInfo, err error) { vi, err = s.VoteInfoCache(c, mid, cid) return } // CaseInfo jury get case info. func (s *Service) CaseInfo(c context.Context, cid int64) (res *model.BlockedCase, err error) { var ca *model.BlockedCase if ca, err = s.CaseInfoCache(c, cid); err != nil || ca.ID == 0 { return } if ca.MID <= 0 { return } res = &model.BlockedCase{} *res = *ca argMId := &accmdl.MidReq{ Mid: res.MID, } info, err := s.accountClient.Info3(c, argMId) if err != nil { log.Error("s.accountClient.Info3(%d) error(%v)", res.MID, err) return } if info != nil { res.Face = info.Info.Face res.Uname = info.Info.Name } return } // JuryCase jury user case info contain vote. func (s *Service) JuryCase(c context.Context, mid int64, cid int64) (res *model.BlockedCase, err error) { var ( bj *model.BlockedJury vi *model.VoteInfo ca *model.BlockedCase ) if bj, err = s.JuryInfoCache(c, mid); err != nil || bj.MID == 0 { return } if vi, err = s.VoteInfoCache(c, mid, cid); err != nil { return } if bj.Black != model.JuryWhite && vi.MID == 0 { err = ecode.CreditCaseLimit return } else if bj.Black == model.JuryWhite && vi.MID == 0 { vi = &model.VoteInfo{} } if ca, err = s.CaseInfoCache(c, cid); err != nil || ca.ID == 0 { err = ecode.CreditCaseNotExist return } res = &model.BlockedCase{} *res = *ca if res.MID > 0 { var info *accmdl.InfoReply argMId := &accmdl.MidReq{ Mid: res.MID, } if info, err = s.accountClient.Info3(c, argMId); err != nil { log.Error("s.accountClient.Info3(%d) error(%v)", res.MID, err) err = nil } if info.Info != nil { res.Face = info.Info.Face res.Uname = info.Info.Name } } res.Vote = vi.Vote res.ID = cid expired := int64(vi.Expired)*1000 - time.Now().UnixNano()/1e6 res.StatusTitle = fmt.Sprintf("封禁%d天", res.BlockedDays) res.Build() res.VoteTime = res.VoteTime * 1000 if vi.Vote == 0 { res.ExpiredMillis = expired } return } // CaseList user case list. TODO:cache func (s *Service) CaseList(c context.Context, mid, pn, ps int64) (res []*model.BlockedCase, err error) { var bs []*model.BlockedCase if bs, err = s.CaseListCache(c, mid, pn, ps); err != nil { return } var mids []int64 for _, v := range bs { bc := &model.BlockedCase{} *bc = *v if bc.JudgeType == 1 { if bc.PunishResult == 3 { bc.StatusTitle = "永久封禁" } else if v.PunishResult == 2 { bc.StatusTitle = fmt.Sprintf("封禁%d天", bc.BlockedDays) } } bc.Build() bc.VoteTime = bc.VoteTime * 1000 mids = append(mids, bc.MID) res = append(res, bc) } argMIds := &accmdl.MidsReq{Mids: mids} infos, err := s.accountClient.Infos3(c, argMIds) if err != nil { log.Error("s.accountClient.Infos(%+v) error(%v)", argMIds, err) return } for _, v := range res { if info, ok := infos.Infos[v.MID]; ok { v.Uname = info.Name v.Face = info.Face } } return } // Notice get notice info. func (s *Service) Notice(c context.Context) (n *model.Notice, err error) { var mc = true if n, err = s.dao.NoticeInfoCache(c); err != nil { err = nil mc = false } if n != nil { return } if n, err = s.dao.Notice(c); err != nil { return } if mc && n != nil { s.addCache(func() { s.dao.SetNoticeInfoCache(context.TODO(), n) }) } return } // ReasonList get reason list. func (s *Service) ReasonList(c context.Context) (n []*model.Reason, err error) { var mc = true if n, err = s.dao.ReasonListCache(c); err != nil { err = nil mc = false } if len(n) > 0 { return } if n, err = s.dao.ReasonList(c); err != nil { return } if mc && len(n) > 0 { s.addCache(func() { s.dao.SetReasonListCache(context.TODO(), n) }) } return } // KPIList get kpi list. func (s *Service) KPIList(c context.Context, mid int64) (res []*model.KPI, err error) { var ( j *model.BlockedJury kpiData []*model.KPIData rr *model.KPI ) res = []*model.KPI{} if kpiData, err = s.dao.KPIList(c, mid); err != nil { return } if j, err = s.JuryInfoCache(c, mid); err != nil { return } for _, r := range kpiData { rr = &r.KPI rr.VoteTotal = r.VoteRealTotal rr.Number = j.ID rr.TermEnd = r.Day rr.TermStart = xtime.Time(r.Day.Time().AddDate(0, 0, -30).Unix()) res = append(res, rr) } return } // VoteOpinion get vote opinion. func (s *Service) VoteOpinion(c context.Context, cid, pn, ps int64, otype int8) (ops []*model.Opinion, count int, err error) { var ( start = ps * (pn - 1) end = ps*pn - 1 ok bool ids []int64 ) ok, _ = s.dao.ExpireVoteIdx(c, cid, otype) if ok { count, err = s.dao.LenVoteIdx(c, cid, otype) if err != nil { return } ids, err = s.dao.VoteOpIdxCache(c, cid, start, end, otype) if err != nil { log.Error("s.VoteIdxCache err(%v)", err) return } } else { var ( allops []*model.Opinion ruleIdx []int64 breakIdx []int64 ) allops, err = s.dao.OpinionIdx(c, cid) if err != nil { return } for _, op := range allops { if op.Vote == model.VoteBanned || op.Vote == model.VoteDel { breakIdx = append(breakIdx, op.OpID) } else if op.Vote == model.VoteRule { ruleIdx = append(ruleIdx, op.OpID) } } s.addCache(func() { s.dao.LoadVoteOpIdxs(context.TODO(), cid, model.OpinionRule, ruleIdx) s.dao.LoadVoteOpIdxs(context.TODO(), cid, model.OpinonBreak, breakIdx) }) if otype == model.OpinionRule { count = len(ruleIdx) if len(ruleIdx) > int(ps) { ids = ruleIdx[:ps] } else { ids = ruleIdx[:] } } else { count = len(breakIdx) if len(breakIdx) > int(ps) { ids = breakIdx[:ps] } else { ids = breakIdx[:] } } } ops, err = s.opinion(c, ids, false) return } // CaseOpinion get case opinion. func (s *Service) CaseOpinion(c context.Context, cid, pn, ps int64) (ops []*model.Opinion, count int, err error) { var ( start = ps * (pn - 1) end = ps*pn - 1 ids []int64 ok bool ) ok, _ = s.dao.ExpireCaseIdx(c, cid) if ok { count, err = s.dao.LenCaseIdx(c, cid) if err != nil { return } ids, err = s.dao.CaseOpIdxCache(c, cid, start, end) if err != nil { return } } else { var ( allops []*model.Opinion allIdx []int64 ) allops, err = s.dao.OpinionCaseIdx(c, cid) if err != nil { return } count = len(allops) s.addCache(func() { s.dao.LoadCaseIdxs(context.TODO(), cid, allops) }) for _, op := range allops { allIdx = append(allIdx, op.OpID) } switch { case len(allIdx) < int(start): ids = nil case len(allIdx) <= int(end): ids = allIdx[start:] default: ids = allIdx[start : end+1] } } ops, err = s.opinion(c, ids, true) return } // DelOpinion del opinion. func (s *Service) DelOpinion(c context.Context, cid, opid int64) (err error) { err = s.dao.DelOpinion(c, opid) if err != nil { return } s.dao.DelCaseIdx(c, cid) s.dao.DelVoteIdx(c, cid) return } func (s *Service) opinion(c context.Context, ids []int64, needAcc bool) (ops []*model.Opinion, err error) { if len(ids) == 0 { return } var ( miss []int64 tops []*model.Opinion mids []int64 opsmap map[int64]*model.Opinion infos *accmdl.InfosReply ) opsmap, miss, err = s.dao.OpinionsCache(c, ids) if err != nil { return } if len(miss) > 0 { if tops, err = s.dao.Opinions(c, miss); err != nil { log.Error("s.dao.Opinions err(%v)", err) return } for _, top := range tops { opsmap[top.OpID] = top } s.addCache(func() { for _, top := range tops { s.dao.AddOpinionCache(context.TODO(), top) } }) } if needAcc && len(opsmap) > 0 { for _, mop := range opsmap { mids = append(mids, mop.Mid) } arg := &accmdl.MidsReq{ Mids: mids, } if infos, err = s.accountClient.Infos3(c, arg); err != nil { log.Error("s.accountClient.Infos err(%v)", err) err = nil // ignore error } } for _, opid := range ids { if op, ok := opsmap[opid]; ok { if needAcc && infos.Infos != nil { if info, ok := infos.Infos[op.Mid]; ok { op.Name = info.Name op.Face = info.Face } } if op.Attr != model.BlockedOpinionAttrOn { op.Mid = 0 op.Name = "" op.Face = "" } ops = append(ops, op) } } return } // AddBlockedCases batch add blocked cases. func (s *Service) AddBlockedCases(c context.Context, bc []*model.ArgJudgeCase) (err error) { if len(bc) > model.MaxAddCaseNum { err = ecode.RequestErr log.Error("s.AddBlockedCases maxaddCaseNum(%d) err(%v)", len(bc), err) return } var bcsn []*model.ArgJudgeCase for _, b := range bc { switch int8(b.OType) { case model.OriginReply: if b.RPID == 0 || b.Type == 0 || b.OID == 0 { err = ecode.RequestErr return } b.RelationID = fmt.Sprintf("%d-%d-%d", b.RPID, b.Type, b.OID) b.ReasonType = int64(model.BlockedReasonTypeByReply(int8(b.ReasonType))) case model.OriginTag: if b.TagID == 0 || b.AID == 0 { err = ecode.RequestErr return } b.RelationID = fmt.Sprintf("%d-%d", b.TagID, b.AID) b.ReasonType = int64(model.BlockedReasonTypeByTag(int8(b.ReasonType))) case model.OriginDM: if b.AID == 0 || b.RPID == 0 || b.OID == 0 || b.Page == 0 { err = ecode.RequestErr return } b.RelationID = fmt.Sprintf("%d-%d-%d-%d", b.AID, b.RPID, b.OID, b.Page) } var count int64 if count, err = s.dao.CaseRelationIDCount(c, int8(b.OType), b.RelationID); err != nil { log.Error("ss.dao.CaseRelationIDCount(%d,%s) err(%v)", b.OType, b.RelationID, err) return } if count > 0 { log.Warn("otype(%d) relationID(%s) is alreadly juge", int8(b.OType), b.RelationID) continue } var total int64 total, err = s.dao.BlockTotalTime(c, b.MID, time.Now().AddDate(-1, 0, 0)) if err != nil { return } if total == 0 { b.PunishResult = model.Block7Days b.BlockedDays = 7 } else if total == 1 { b.PunishResult = model.Block15Days b.BlockedDays = 15 } else if total > 1 { b.PunishResult = model.BlockForever b.BlockedDays = 0 } bcsn = append(bcsn, b) } if len(bcsn) <= 0 { log.Warn("no case submit!") return } if err = s.dao.AddBlockedCases(c, bcsn); err != nil { return } return } // CaseObtainByID obtain case by case id. // NOTE: just for specific case. func (s *Service) CaseObtainByID(c context.Context, mid, cid int64) (err error) { juryInfo, err := s.JuryInfoCache(c, mid) if err != nil { return } if juryInfo.MID == 0 { err = ecode.CreditNotJury return } if juryInfo.Status != model.JuryStatusEffect || int64(juryInfo.Expired) < time.Now().Unix() { err = ecode.CreditJuryExpired return } if juryInfo.VoteTotal > 3 && (float64(juryInfo.VoteRight)/float64(juryInfo.VoteTotal)*100 < float64(s.c.Judge.JuryRatio)) { err = ecode.CreditUnderVoteRate return } if cid, err = s.caseVoteID(c, mid, cid); err != nil { return } if cid == 0 { err = ecode.CreditNoCase return } return } // SpJuryCase get specific jury case info. // NOTE : just for specific case for boss. func (s *Service) SpJuryCase(c context.Context, mid int64, cid int64) (res *model.BlockedCase, err error) { var ca *model.BlockedCase if ca, err = s.CaseInfoCache(c, cid); err != nil { return } if ca.ID == 0 { err = ecode.CreditCaseNotExist return } if !model.IsCaseTypePublic(ca.CaseType) { err = ecode.CreditCaseNotExist return } res = &model.BlockedCase{} *res = *ca var info *accmdl.InfoReply if info, err = s.accountClient.Info3(c, &accmdl.MidReq{Mid: res.MID}); err != nil { log.Error("s.accountClient.Info3(%d) error(%+v)", res.MID, err) err = nil } if info.Info != nil { res.Uname = info.Info.Name res.Face = info.Info.Face } s._caseExpland(cid, res) s._buildVoteInfo(c, mid, cid, res) return } func (s *Service) _caseExpland(cid int64, bc *model.BlockedCase) { bc.ID = cid bc.JudgeType = 0 // set status to dealing and result to 0. if bc.Status > model.CaseStatusGrantStop { bc.Status = model.CaseStatusDealing } bc.StatusTitle = fmt.Sprintf("封禁%d天", bc.BlockedDays) bc.PunishTitle = fmt.Sprintf("在%s中%s", model.OriginTypeDesc(bc.OriginType), model.ReasonTypeDesc(bc.ReasonType)) } func (s *Service) _buildVoteInfo(c context.Context, mid, cid int64, bc *model.BlockedCase) { var ( err error vi *model.VoteInfo ) if vi, err = s.VoteInfoCache(c, mid, cid); err == nil && vi.MID != 0 { bc.Vote = vi.Vote if vi.Vote == 0 { bc.ExpiredMillis = int64(vi.Expired)*1000 - time.Now().UnixNano()/1e6 } } } // VoteInfoCache use vote cid info. func (s *Service) VoteInfoCache(c context.Context, mid, cid int64) (vi *model.VoteInfo, err error) { var mc = true if vi, err = s.dao.VoteInfoCache(c, mid, cid); err != nil { err = nil mc = false } if vi != nil { return } if vi, err = s.dao.VoteInfo(c, mid, cid); err != nil { return } if vi == nil { vi = &model.VoteInfo{} } if mc { s.addCache(func() { s.dao.SetVoteInfoCache(context.TODO(), mid, cid, vi) }) } return } // JuryInfos mutli get jurys info. func (s *Service) JuryInfos(c context.Context, mids []int64) (res map[int64]*model.ResJuryerStatus, err error) { res = make(map[int64]*model.ResJuryerStatus, len(mids)) mbj, err := s.dao.JuryInfos(c, mids) if err != nil { err = errors.Wrap(err, "s.dao.JuryInfos") return } for mid, bj := range mbj { res[mid] = &model.ResJuryerStatus{ Expired: bj.Expired, Mid: mid, Status: bj.Status, } } return } // BatchBLKCases get batch blocked cases by ids. func (s *Service) BatchBLKCases(c context.Context, ids []int64) (cases map[int64]*model.BlockedCase, err error) { if cases, err = s.dao.CaseInfoIDs(c, ids); err != nil { err = errors.Wrapf(err, "s.dao.CaseInfoIDs(%+v)", ids) return } for _, item := range cases { item.Build() } return } // JuryInfoCache JuryInfo cache . func (s *Service) JuryInfoCache(c context.Context, mid int64) (bj *model.BlockedJury, err error) { var mc = true if bj, err = s.dao.JuryInfoCache(c, mid); err != nil { err = nil mc = false } if bj != nil { return } if bj, err = s.dao.JuryInfo(c, mid); err != nil { return } if bj == nil { bj = &model.BlockedJury{} } else { if bj.CaseTotal, err = s.dao.CountCaseVote(c, mid); err != nil { return } } if mc { s.addCache(func() { if err = s.dao.SetJuryInfoCache(context.TODO(), mid, bj); err != nil { log.Error("s.dao.SetJuryInfoCache error(%+v)", err) } }) } return } // CaseInfoCache . func (s *Service) CaseInfoCache(c context.Context, cid int64) (bc *model.BlockedCase, err error) { var mc = true if bc, err = s.dao.CaseInfoCache(c, cid); err != nil { err = nil mc = false } if bc != nil { return } if bc, err = s.dao.CaseInfo(c, cid); err != nil { return } if bc == nil { bc = &model.BlockedCase{} } if mc { s.addCache(func() { if err = s.dao.SetCaseInfoCache(context.TODO(), cid, bc); err != nil { log.Error("s.dao.SetCaseInfoCache error(%+v)", err) } }) } return } // CaseListCache . func (s *Service) CaseListCache(c context.Context, mid, pn, ps int64) (bs []*model.BlockedCase, err error) { if pn*ps <= 100 { bs, err = s.caseVoteTopCache(c, mid, pn, ps) return } var vids, cids []int64 if vids, cids, err = s.dao.CaseVoteIDMID(c, mid, pn, ps); err != nil { return } bs, err = s.buildBlockedCase(c, vids, cids) return } // caseVoteTopCache . func (s *Service) caseVoteTopCache(c context.Context, mid, pn, ps int64) (res []*model.BlockedCase, err error) { var ( mc = true vids, cids []int64 bs []*model.BlockedCase end = pn * ps start = (pn - 1) * ps ) defer func() { bl := len(bs) if err == nil && bl != 0 { switch { case bl <= int(start): res = _emptyBlockedCase case bl <= int(end): res = bs[start:] default: res = bs[start:end] } } }() if bs, err = s.dao.CaseVoteTopCache(c, mid); err != nil { err = nil mc = false } if bs != nil { return } if vids, cids, err = s.dao.CaseVoteIDTop(c, mid); err != nil { return } if bs, err = s.buildBlockedCase(c, vids, cids); err != nil { return } if mc { s.addCache(func() { if err = s.dao.SetCaseVoteTopCache(context.TODO(), mid, bs); err != nil { log.Error("s.dao.SetCaseVoteTopCache error(%+v)", err) } }) } return } // buildBlockedCase . func (s *Service) buildBlockedCase(c context.Context, vids, cids []int64) (bs []*model.BlockedCase, err error) { var ( ok bool vo *model.VoteInfo bc *model.BlockedCase mvo map[int64]*model.VoteInfo mbc map[int64]*model.BlockedCase ) if len(vids) == 0 || len(cids) == 0 { bs = _emptyBlockedCase return } if mvo, err = s.dao.CaseVotesMID(c, vids); err != nil { return } if mbc, err = s.dao.CaseVoteIDs(c, cids); err != nil { return } if mvo == nil || mbc == nil { bs = _emptyBlockedCase return } for _, cid := range cids { if bc, ok = mbc[cid]; !ok { continue } if vo, ok = mvo[cid]; !ok { continue } bc.Vote = vo.Vote bc.VoteTime = vo.Mtime bs = append(bs, bc) } if len(bs) == 0 { bs = _emptyBlockedCase } return }