123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218 |
- package relation
- import (
- "context"
- "fmt"
- "hash/crc32"
- "sort"
- "strconv"
- "sync"
- "go-common/app/interface/main/account/conf"
- "go-common/app/interface/main/account/dao/relation"
- "go-common/app/interface/main/account/model"
- acml "go-common/app/service/main/account/model"
- account "go-common/app/service/main/account/rpc/client"
- archive "go-common/app/service/main/archive/api/gorpc"
- mrl "go-common/app/service/main/relation/model"
- rlrpc "go-common/app/service/main/relation/rpc/client"
- "go-common/library/ecode"
- "go-common/library/log"
- "go-common/library/net/metadata"
- )
- var (
- _emptyFollowings = []*model.Following{}
- _emptyTagInfos = []*model.Tag{}
- _emptyTags = make(map[int64]string)
- _allTagsStr = "all"
- _specialTagsStr = "special"
- _defaultTagsStr = "default"
- _listTagsStr = "list"
- _emptySpList = []int64{}
- )
- // Service struct of service.
- type Service struct {
- // conf
- c *conf.Config
- // rpc
- relationRPC *rlrpc.Service
- accountRPC *account.Service3
- archiveRPC *archive.Service2
- // dao
- dao *relation.Dao
- }
- // New create service instance and return.
- func New(c *conf.Config) (s *Service) {
- s = &Service{
- c: c,
- relationRPC: rlrpc.New(c.RPCClient2.Relation),
- accountRPC: account.New3(c.RPCClient2.Account),
- archiveRPC: archive.New2(c.RPCClient2.Archive),
- dao: relation.New(c),
- }
- return
- }
- // Modify modify user relation.
- func (s *Service) Modify(c context.Context, mid, fid int64, act int8, src uint8, ric map[string]string) (err error) {
- if act < mrl.ActAddFollowing || act > mrl.ActDelFollower {
- err = ecode.RequestErr
- return
- }
- arg := &mrl.ArgFollowing{Mid: mid, Fid: fid, Source: src, Action: act, Infoc: ric}
- if err = s.relationRPC.ModifyRelation(c, arg); err != nil {
- log.Error("s.relationRPC.ModifyRelation(mid:%d,fid:%d,src:%d,act:%d) err(%v)", mid, fid, act, src, err)
- }
- return
- }
- // BatchModify batch modify user relation.
- func (s *Service) BatchModify(c context.Context, mid int64, fids []int64, act int8, src uint8, ric map[string]string) (result *model.BatchModifyResult, err error) {
- if len(fids) > 50 {
- err = ecode.RequestErr
- return
- }
- for _, fid := range fids {
- if fid <= 0 || fid == mid {
- err = ecode.RequestErr
- return
- }
- }
- // luoweiling: 把非加关注的动作全部拒绝掉
- if act != mrl.ActAddFollowing {
- err = ecode.RequestErr
- return
- }
- if act < mrl.ActAddFollowing || act > mrl.ActDelFollower {
- err = ecode.RequestErr
- return
- }
- // zhangsusu: 批量关注里保持悄悄关注的状态
- whispers, err := s.relationRPC.Whispers(c, &mrl.ArgMid{
- Mid: mid,
- RealIP: "",
- })
- if err != nil {
- log.Error("Failed to get user whispers: mid: %d: %+v", mid, err)
- return
- }
- whispersmap := make(map[int64]struct{}, len(whispers))
- for _, w := range whispers {
- whispersmap[w.Mid] = struct{}{}
- }
- filteredFids := make([]int64, 0, len(fids))
- for _, fid := range fids {
- if _, ok := whispersmap[fid]; ok {
- continue
- }
- filteredFids = append(filteredFids, fid)
- }
- raiseErr := func(in error) error {
- shouldRaise := map[int]struct{}{
- ecode.RelFollowAlreadyBlack.Code(): {},
- ecode.RelFollowReachTelLimit.Code(): {},
- ecode.RelFollowReachMaxLimit.Code(): {},
- }
- ec := ecode.Cause(in)
- if _, ok := shouldRaise[ec.Code()]; ok {
- return ec
- }
- return nil
- }
- lock := sync.Mutex{}
- result = &model.BatchModifyResult{
- FailedFids: []int64{},
- }
- wg := sync.WaitGroup{}
- for _, fid := range filteredFids {
- fid := fid
- wg.Add(1)
- go func() {
- defer wg.Done()
- arg := &mrl.ArgFollowing{Mid: mid, Fid: fid, Source: src, Action: act, Infoc: ric}
- rerr := s.relationRPC.ModifyRelation(c, arg)
- if rerr == nil {
- return
- }
- lock.Lock()
- defer lock.Unlock()
- err = raiseErr(rerr)
- log.Error("s.relationRPC.ModifyRelation(mid:%d,fid:%d,src:%d,act:%d) err(%v)", mid, fid, act, src, rerr)
- result.FailedFids = append(result.FailedFids, fid)
- }()
- }
- wg.Wait()
- return
- }
- // Relation get user relation.
- func (s *Service) Relation(c context.Context, mid, fid int64) (f *mrl.Following, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgRelation{Mid: mid, Fid: fid, RealIP: ip}
- if f, err = s.relationRPC.Relation(c, arg); err != nil {
- log.Error("s.Relation(mid %d,fid %d) err(%v)", mid, fid, err)
- }
- return
- }
- // Relations get relations between users.
- func (s *Service) Relations(c context.Context, mid int64, fids []int64) (f map[int64]*mrl.Following, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}
- if f, err = s.relationRPC.Relations(c, arg); err != nil {
- log.Error("s.Relations(mid %d,fids %d) err(%v)", mid, fids, err)
- }
- return
- }
- // Blacks get user black list.
- func (s *Service) Blacks(c context.Context, mid int64, version uint64, pn, ps int64) (f []*model.Following, crc32v uint32, total int, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- fr, err := s.relationRPC.Blacks(c, arg)
- if err != nil {
- log.Error("s.Blacks(mid %d) err(%v)", mid, err)
- return
- }
- total = len(fr)
- stat, err := s.relationRPC.Stat(c, arg)
- if err != nil {
- log.Error("s.Stat(mid %d) err(%v)", mid, err)
- return
- }
- total = int(stat.Black)
- start, end := (pn-1)*ps, pn*ps
- switch {
- case start >= int64(len(fr)):
- fr = fr[:0]
- case end >= int64(len(fr)):
- fr = fr[start:]
- default:
- fr = fr[start:end]
- }
- if len(fr) == 0 {
- f = _emptyFollowings
- return
- }
- temp := []byte(fmt.Sprintf("%s", fr))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == version {
- err = ecode.NotModified
- return
- }
- var (
- mids []int64
- infos map[int64]*acml.Info
- fi *mrl.Following
- )
- for _, fi = range fr {
- mids = append(mids, fi.Mid)
- }
- accArg := &acml.ArgMids{Mids: mids}
- if infos, err = s.accountRPC.Infos3(c, accArg); err != nil {
- log.Error("s.accountRPC.Infos3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi = range fr {
- tmp := &model.Following{Following: fi}
- info, ok := infos[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch infos with mid: %d", fi.Mid)
- continue
- }
- tmp.Face = info.Face
- tmp.Uname = info.Name
- tmp.Sign = info.Sign
- f = append(f, tmp)
- }
- return
- }
- // Whispers get user Whispers.
- func (s *Service) Whispers(c context.Context, mid int64, pn, ps int64, version uint64) (f []*model.Following, crc32v uint32, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- fr, err := s.relationRPC.Whispers(c, arg)
- if err != nil {
- log.Error("s.Whispers(mid %d) err(%v)", mid, err)
- return
- }
- start, end := (pn-1)*ps, pn*ps
- switch {
- case start >= int64(len(fr)):
- fr = fr[:0]
- case end >= int64(len(fr)):
- fr = fr[start:]
- default:
- fr = fr[start:end]
- }
- if len(fr) == 0 {
- f = _emptyFollowings
- return
- }
- temp := []byte(fmt.Sprintf("%s", fr))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == version {
- err = ecode.NotModified
- return
- }
- var (
- mids []int64
- cards map[int64]*acml.Card
- fi *mrl.Following
- )
- for _, fi = range fr {
- mids = append(mids, fi.Mid)
- }
- accArg := &acml.ArgMids{Mids: mids}
- if cards, err = s.accountRPC.Cards3(c, accArg); err != nil {
- log.Error("s.accountRPC(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi = range fr {
- tmp := &model.Following{Following: fi}
- card, ok := cards[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", mid)
- continue
- }
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- // tmp.Vip = cards[fi.Mid].Vip
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- f = append(f, tmp)
- }
- return
- }
- // Friends get user friends list: follow eachother.
- func (s *Service) Friends(c context.Context, mid int64, version uint64) (f []*model.Following, crc32v uint32, err error) {
- var (
- mids []int64
- cards map[int64]*acml.Card
- fi *mrl.Following
- fo, fs []*mrl.Following
- ip = metadata.String(c, metadata.RemoteIP)
- )
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- if fo, err = s.relationRPC.Followings(c, arg); err != nil {
- log.Error("s.Followings(mid %d) err(%v)", mid, err)
- return
- }
- for _, fi = range fo {
- if mrl.Attr(fi.Attribute) == mrl.AttrFriend {
- fs = append(fs, fi)
- }
- }
- if len(fs) == 0 {
- f = _emptyFollowings
- return
- }
- temp := []byte(fmt.Sprintf("%s", fo))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == version {
- err = ecode.NotModified
- return
- }
- for _, fi = range fs {
- mids = append(mids, fi.Mid)
- }
- accArg := &acml.ArgMids{Mids: mids}
- if cards, err = s.accountRPC.Cards3(c, accArg); err != nil {
- log.Error("s.accountRPC.Cards3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi = range fs {
- tmp := &model.Following{Following: fi}
- card, ok := cards[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", fi.Mid)
- continue
- }
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- // tmp.OfficialVerify = cards[fi.Mid].Official
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- // tmp.Vip = infos[fi.Mid].Vip
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- f = append(f, tmp)
- }
- return
- }
- // Followers get user followings.
- func (s *Service) Followers(c context.Context, vmid, mid, pn, ps int64, version uint64) (f []*model.Following, crc32v uint32, total int, err error) {
- var (
- mids []int64
- cards map[int64]*acml.Card
- fi *mrl.Following
- ip = metadata.String(c, metadata.RemoteIP)
- )
- arg := &mrl.ArgMid{Mid: vmid, RealIP: ip}
- fr, err := s.relationRPC.Followers(c, arg)
- if err != nil {
- log.Error("s.Followers(mid %d) err(%v)", vmid, err)
- return
- }
- stat, err := s.relationRPC.Stat(c, arg)
- if err != nil {
- log.Error("s.Stat(mid %d) err(%v)", vmid, err)
- return
- }
- total = int(stat.Follower)
- start, end := (pn-1)*ps, pn*ps
- switch {
- case start >= int64(len(fr)):
- fr = fr[:0]
- case end >= int64(len(fr)):
- fr = fr[start:]
- default:
- fr = fr[start:end]
- }
- if len(fr) == 0 {
- f = _emptyFollowings
- return
- }
- for _, fi = range fr {
- mids = append(mids, fi.Mid)
- }
- // !self, compute !self user and up's followings' attr
- var frs map[int64]*mrl.Following
- if mid != 0 {
- argfrs := &mrl.ArgRelations{Mid: mid, Fids: mids, RealIP: ip}
- frs, err = s.relationRPC.Relations(c, argfrs)
- if err != nil {
- log.Error("s.relationRPC.Relations(c, %v) error(%v)", argfrs, err)
- return
- }
- }
- temp := []byte(fmt.Sprintf("%s", fr))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == version {
- err = ecode.NotModified
- return
- }
- accArg := &acml.ArgMids{Mids: mids}
- if cards, err = s.accountRPC.Cards3(c, accArg); err != nil {
- log.Error("s.accountRPC.Cards3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi = range fr {
- tmp := &model.Following{Following: fi}
- card, ok := cards[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", mid)
- continue
- }
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- if frst, ok := frs[fi.Mid]; ok {
- tmp.Attribute = frst.Attribute
- } else {
- tmp.Attribute = mrl.AttrNoRelation
- }
- // tmp.OfficialVerify = cards[fi.Mid].Official
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- // tmp.Vip = infos[fi.Mid].Vip
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- f = append(f, tmp)
- }
- return
- }
- // Followings get user followings list.
- func (s *Service) Followings(c context.Context, vmid, mid, pn, ps int64, version uint64, order string) (f []*model.Following, crc32v uint32, total int, err error) {
- var (
- mids []int64
- cards map[int64]*acml.Card
- fi *mrl.Following
- ip = metadata.String(c, metadata.RemoteIP)
- )
- arg := &mrl.ArgMid{Mid: vmid, RealIP: ip}
- fr, err := s.relationRPC.Followings(c, arg)
- if err != nil {
- log.Error("s.Followings(mid %d) err(%v)", vmid, err)
- return
- }
- stat, err := s.relationRPC.Stat(c, arg)
- if err != nil {
- log.Error("s.Stat(mid %d) err(%v)", vmid, err)
- return
- }
- total = int(stat.Following)
- if order == "asc" {
- sort.Sort(ByMTime(fr))
- }
- start, end := (pn-1)*ps, pn*ps
- switch {
- case start >= int64(len(fr)):
- fr = fr[:0]
- case end >= int64(len(fr)):
- fr = fr[start:]
- default:
- fr = fr[start:end]
- }
- if len(fr) == 0 {
- f = _emptyFollowings
- return
- }
- for _, fi = range fr {
- mids = append(mids, fi.Mid)
- }
- // !self, compute !self user and up's followings' attr
- var frs map[int64]*mrl.Following
- if mid != vmid && mid != 0 {
- argfrs := &mrl.ArgRelations{Mid: mid, Fids: mids, RealIP: ip}
- frs, err = s.relationRPC.Relations(c, argfrs)
- if err != nil {
- log.Error("s.relationRPC.Relations(c, %v) error(%v)", argfrs, err)
- return
- }
- }
- temp := []byte(fmt.Sprintf("%s", fr))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == version {
- err = ecode.NotModified
- return
- }
- accArg := &acml.ArgMids{Mids: mids}
- if cards, err = s.accountRPC.Cards3(c, accArg); err != nil {
- log.Error("s.accountRPC.Cards3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi = range fr {
- tmp := &model.Following{Following: fi}
- card, ok := cards[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", mid)
- continue
- }
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- if mid != vmid {
- if frst, ok := frs[fi.Mid]; ok {
- tmp.Attribute = frst.Attribute
- } else {
- tmp.Attribute = mrl.AttrNoRelation
- }
- }
- // tmp.OfficialVerify = cards[fi.Mid].Official
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- // tmp.Vip = infos[fi.Mid].Vip
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- f = append(f, tmp)
- }
- return
- }
- // Stat get user relation stat.
- func (s *Service) Stat(c context.Context, mid int64, self bool) (st *mrl.Stat, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- if st, err = s.relationRPC.Stat(c, arg); err != nil {
- log.Error("s.Stat(mid %d) err(%v)", mid, err)
- return
- }
- if !self {
- st.Whisper = 0
- st.Black = 0
- }
- return
- }
- // Stats get users relation stat.
- func (s *Service) Stats(c context.Context, mids []int64) (st map[int64]*mrl.Stat, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMids{Mids: mids, RealIP: ip}
- return s.relationRPC.Stats(c, arg)
- }
- // Ping check server ok.
- func (s *Service) Ping(c context.Context) (err error) {
- return
- }
- // ByMTime implements sort.Interface for []model.Following based on the MTime field.
- type ByMTime []*mrl.Following
- func (mt ByMTime) Len() int { return len(mt) }
- func (mt ByMTime) Swap(i, j int) { mt[i], mt[j] = mt[j], mt[i] }
- func (mt ByMTime) Less(i, j int) bool { return mt[i].MTime < mt[j].MTime }
- // Tag get tag info by tag.
- func (s *Service) Tag(c context.Context, mid int64, tagid int64, pn int64, ps int64) (tagInfo []*model.Tag, err error) {
- var (
- mids []int64
- cards map[int64]*acml.Card
- ip = metadata.String(c, metadata.RemoteIP)
- )
- arg := &mrl.ArgTagId{Mid: mid, TagId: tagid, RealIP: ip}
- if mids, err = s.relationRPC.Tag(c, arg); err != nil {
- log.Error("s.relationRPC(%d).Arg(%v) error(%v)", mid, arg, err)
- return
- }
- var tmpMids []int64
- start, end := (pn-1)*ps, pn*ps
- switch {
- case start >= int64(len(mids)):
- tmpMids = mids[:0]
- case end >= int64(len(mids)):
- tmpMids = mids[start:]
- default:
- tmpMids = mids[start:end]
- }
- if len(tmpMids) == 0 {
- tagInfo = _emptyTagInfos
- return
- }
- accArg := &acml.ArgMids{Mids: mids}
- if cards, err = s.accountRPC.Cards3(c, accArg); err != nil {
- log.Error("s.accountRPC.Cards3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, mid = range tmpMids {
- tmp := &model.Tag{Mid: mid}
- card, ok := cards[mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", mid)
- continue
- }
- tmp.Mid = mid
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- // tmp.OfficialVerify = cards[mid].Official
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- // tmp.Vip = infos[mid].Vip
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- tagInfo = append(tagInfo, tmp)
- }
- return
- }
- // Tags is.
- func (s *Service) Tags(c context.Context, mid int64) (tagsCount []*mrl.TagCount, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- if tagsCount, err = s.relationRPC.Tags(c, arg); err != nil {
- log.Error("s.relationRPC(%d).Arg(%v) error(%v)", mid, arg, err)
- return
- }
- return
- }
- // MobileTags is.
- func (s *Service) MobileTags(c context.Context, mid int64) (tagsCount map[string][]*mrl.TagCount, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgMid{Mid: mid, RealIP: ip}
- tags, err := s.relationRPC.Tags(c, arg)
- if err != nil {
- log.Error("s.relationRPC(%d).Arg(%v) error(%v)", mid, arg, err)
- return
- }
- var st *mrl.Stat
- argStat := &mrl.ArgMid{Mid: mid, RealIP: ip}
- if st, err = s.relationRPC.Stat(c, argStat); err != nil {
- log.Error("s.Stat(mid %d) err(%v)", mid, err)
- return
- }
- tagsCount = map[string][]*mrl.TagCount{
- _allTagsStr: {{
- Tagid: -1,
- Name: "公开关注",
- Count: st.Following,
- }},
- _specialTagsStr: {{
- Tagid: -10,
- Name: "特别关注",
- Count: 0,
- }},
- _listTagsStr: make([]*mrl.TagCount, 0, len(tags)),
- _defaultTagsStr: make([]*mrl.TagCount, 0, 1),
- }
- for _, v := range tags {
- if v.Tagid == 0 {
- tagsCount[_defaultTagsStr] = append(tagsCount[_defaultTagsStr], v)
- } else if v.Tagid == -10 {
- tagsCount[_specialTagsStr][0].Count = v.Count
- } else {
- tagsCount[_listTagsStr] = append(tagsCount[_listTagsStr], v)
- }
- }
- return
- }
- // UserTag is.
- func (s *Service) UserTag(c context.Context, mid int64, fid int64) (tags map[int64]string, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgRelation{Mid: mid, Fid: fid, RealIP: ip}
- if tags, err = s.relationRPC.UserTag(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- if tags == nil {
- tags = _emptyTags
- }
- return
- }
- // CreateTag is.
- func (s *Service) CreateTag(c context.Context, mid int64, tag string) (tagInfo int64, err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTag{Mid: mid, Tag: tag, RealIP: ip}
- if tagInfo, err = s.relationRPC.CreateTag(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // UpdateTag is.
- func (s *Service) UpdateTag(c context.Context, mid int64, tagID int64, new string) (err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTagUpdate{Mid: mid, TagId: tagID, New: new, RealIP: ip}
- if err = s.relationRPC.UpdateTag(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // DelTag is.
- func (s *Service) DelTag(c context.Context, mid int64, tagID int64) (err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTagDel{Mid: mid, TagId: tagID, RealIP: ip}
- if err = s.relationRPC.DelTag(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // TagsAddUsers is.
- func (s *Service) TagsAddUsers(c context.Context, mid int64, tagIds string, fids string) (err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTagsMoveUsers{Mid: mid, BeforeID: 0, AfterTagIds: tagIds, Fids: fids, RealIP: ip}
- if err = s.relationRPC.TagsAddUsers(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // TagsCopyUsers is.
- func (s *Service) TagsCopyUsers(c context.Context, mid int64, tagIds string, fids string) (err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTagsMoveUsers{Mid: mid, BeforeID: 0, AfterTagIds: tagIds, Fids: fids, RealIP: ip}
- if err = s.relationRPC.TagsCopyUsers(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // TagsMoveUsers is.
- func (s *Service) TagsMoveUsers(c context.Context, mid, beforeid int64, afterTagIdsStr, fidsStr string) (err error) {
- ip := metadata.String(c, metadata.RemoteIP)
- arg := &mrl.ArgTagsMoveUsers{Mid: mid, BeforeID: beforeid, AfterTagIds: afterTagIdsStr, Fids: fidsStr, RealIP: ip}
- if err = s.relationRPC.TagsMoveUsers(c, arg); err != nil {
- log.Error("s.relationRPC.Arg(%v) error(%v)", arg, err)
- return
- }
- return
- }
- // Prompt report and get prompt status.
- func (s *Service) Prompt(c context.Context, arg *mrl.ArgPrompt) (b bool, err error) {
- return s.relationRPC.Prompt(c, arg)
- }
- // ClosePrompt close prompt.
- func (s *Service) ClosePrompt(c context.Context, arg *mrl.ArgPrompt) (err error) {
- return s.relationRPC.ClosePrompt(c, arg)
- }
- // AddSpecial add fid into special.
- func (s *Service) AddSpecial(c context.Context, arg *mrl.ArgFollowing) (err error) {
- return s.relationRPC.AddSpecial(c, arg)
- }
- // DelSpecial del fid from sepcial.
- func (s *Service) DelSpecial(c context.Context, arg *mrl.ArgFollowing) (err error) {
- return s.relationRPC.DelSpecial(c, arg)
- }
- // Special get user special list.
- func (s *Service) Special(c context.Context, mid int64) (l []int64, err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- }
- l, err = s.relationRPC.Special(c, arg)
- if len(l) == 0 {
- l = _emptySpList
- }
- return
- }
- // Unread check unread status, for the 'show red point' function.
- func (s *Service) Unread(c context.Context, mid int64, disableAutoReset bool) (show bool, err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- }
- // if !disableAutoReset {
- // defer s.ResetUnread(c, mid)
- // }
- return s.relationRPC.FollowersUnread(c, arg)
- }
- // ResetUnread is
- func (s *Service) ResetUnread(c context.Context, mid int64) (err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- }
- return s.relationRPC.ResetFollowersUnread(c, arg)
- }
- // UnreadCount unread count.
- func (s *Service) UnreadCount(c context.Context, mid int64, disableAutoReset bool) (count int64, err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- }
- // if !disableAutoReset {
- // defer func() {
- // s.ResetUnread(c, mid)
- // s.ResetUnreadCount(c, mid)
- // }()
- // }
- return s.relationRPC.FollowersUnreadCount(c, arg)
- }
- // ResetUnreadCount is
- func (s *Service) ResetUnreadCount(c context.Context, mid int64) (err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- }
- return s.relationRPC.ResetFollowersUnreadCount(c, arg)
- }
- // RecommendTagSuggestDetail is
- func (s *Service) RecommendTagSuggestDetail(c context.Context, arg *model.ArgTagSuggestRecommend) (*model.TagSuggestRecommendInfo, error) {
- result, err := s.RecommendTagSuggest(c, arg)
- if err != nil {
- return nil, err
- }
- if len(result) <= 0 {
- empty := &model.TagSuggestRecommendInfo{
- TagName: arg.TagName,
- UpList: []*model.RecommendInfo{},
- MatchCnt: 0,
- }
- return empty, nil
- }
- detail := result[0]
- upMids := func() []int64 {
- mids := make([]int64, 0, len(detail.UpList))
- for _, up := range detail.UpList {
- mid, perr := strconv.ParseInt(up.Mid, 10, 64)
- if perr != nil {
- log.Warn("Failed to parse mid: %s: %+v", up.Mid, perr)
- continue
- }
- mids = append(mids, mid)
- }
- return mids
- }()
- rels, err := s.relationRPC.Relations(c, &mrl.ArgRelations{
- Mid: arg.Mid,
- Fids: upMids,
- RealIP: arg.RemoteIP,
- })
- if err != nil {
- return nil, err
- }
- for _, up := range detail.UpList {
- mid, err := strconv.ParseInt(up.Mid, 10, 64)
- if err != nil {
- log.Warn("Failed to parse mid: %s: %+v", err, up.Mid)
- continue
- }
- r, ok := rels[mid]
- if !ok {
- log.Warn("Failed to get relation between %d and %d", arg.Mid, mid)
- up.Relation = &mrl.Following{Mid: mid} // empty relation
- continue
- }
- up.Relation = r
- }
- return detail, nil
- }
- // RecommendTagSuggest is
- func (s *Service) RecommendTagSuggest(c context.Context, arg *model.ArgTagSuggestRecommend) ([]*model.TagSuggestRecommendInfo, error) {
- resp, err := s.dao.TagSuggestRecommend(c, arg.Mid, arg.ContextID, arg.TagName, arg.Device, arg.PageSize, arg.RemoteIP)
- if err != nil {
- return nil, err
- }
- allrecs := make([]*model.RecommendContent, 0)
- for _, rec := range resp.Data {
- allrecs = append(allrecs, rec.UpList...)
- }
- allrecinfos, err := s.collectionAsRecommendUserInfo(c, allrecs, resp.TrackID, arg.RemoteIP)
- if err != nil {
- return nil, err
- }
- allrecinfomap := make(map[string]*model.RecommendInfo, len(allrecinfos))
- for _, recinfo := range allrecinfos {
- allrecinfomap[recinfo.Mid] = recinfo
- }
- getRecInfos := func(mids ...int64) []*model.RecommendInfo {
- out := make([]*model.RecommendInfo, 0, len(mids))
- for _, mid := range mids {
- smid := strconv.FormatInt(mid, 10)
- recinfo, ok := allrecinfomap[smid]
- if !ok {
- log.Warn("Failed to get user info with mid: %d", mid)
- continue
- }
- out = append(out, recinfo)
- }
- return out
- }
- result := make([]*model.TagSuggestRecommendInfo, 0, len(resp.Data))
- for _, rec := range resp.Data {
- trecinfo := &model.TagSuggestRecommendInfo{
- TagName: rec.TagName,
- MatchCnt: rec.MatchCnt,
- }
- rinfos := getRecInfos(rec.UpIDs()...)
- trecinfo.UpList = rinfos
- if len(rinfos) != len(rec.UpIDs()) {
- log.Warn("Inconsistent user info and recommend match count: %d, %d", len(rinfos), len(rec.UpIDs()))
- trecinfo.MatchCnt -= int64(len(rec.UpIDs()) - len(rinfos))
- }
- result = append(result, trecinfo)
- }
- return result, nil
- }
- // RecommendFollowlistEmpty is
- func (s *Service) RecommendFollowlistEmpty(c context.Context, arg *model.ArgRecommend) ([]*model.RecommendInfo, error) {
- return s.recommend(c, "followlist_empty", arg)
- }
- // RecommendAnswerOK is
- func (s *Service) RecommendAnswerOK(c context.Context, arg *model.ArgRecommend) ([]*model.RecommendInfo, error) {
- return s.recommend(c, "answer_ok", arg)
- }
- func (s *Service) collectionAsRecommendUserInfo(c context.Context, recs []*model.RecommendContent, trackID string, ip string) ([]*model.RecommendInfo, error) {
- recmap := make(map[int64]*model.RecommendContent, len(recs))
- mids := make([]int64, 0, len(recs))
- for _, r := range recs {
- mids = append(mids, r.UpID)
- recmap[r.UpID] = r
- }
- cards, err := s.accountRPC.Cards3(c, &acml.ArgMids{Mids: mids})
- if err != nil {
- return nil, err
- }
- stats, err := s.relationRPC.Stats(c, &mrl.ArgMids{Mids: mids, RealIP: ip})
- if err != nil {
- return nil, err
- }
- // TODO: cache types
- types, err := s.archiveRPC.Types2(c)
- if err != nil {
- return nil, err
- }
- typeName := func(tid int16) string {
- t := types[tid]
- if t == nil {
- return ""
- }
- return t.Name
- }
- ris := make([]*model.RecommendInfo, 0, len(recs))
- for _, rec := range recs {
- if rec == nil {
- log.Warn("Invalid recommend content: %+v", rec)
- continue
- }
- card, ok := cards[rec.UpID]
- if !ok {
- log.Warn("Failed to get user card with mid: %d", rec.UpID)
- continue
- }
- stat, ok := stats[rec.UpID]
- if !ok {
- log.Warn("Failed to get stat with mid: %d", rec.UpID)
- continue
- }
- ri := &model.RecommendInfo{}
- ri.FromCard(card)
- ri.RecommendContent = *rec
- ri.TrackID = trackID
- ri.Fans = stat.Follower
- ri.TypeName = typeName(ri.Tid)
- ri.SecondTypeName = typeName(ri.SecondTid)
- // zhangsusu: 拼粉丝数作为推荐理由(后来又下线了)
- // fs := followerString(stat.Follower)
- // if fs != "" {
- // parts := []string{}
- // if ri.RecReason != "" {
- // parts = append(parts, ri.RecReason)
- // }
- // parts = append(parts, fs)
- // ri.RecReason = strings.Join(parts, ",")
- // }
- ris = append(ris, ri)
- }
- return ris, nil
- }
- func (s *Service) recommend(c context.Context, serviceArea string, arg *model.ArgRecommend) ([]*model.RecommendInfo, error) {
- resp, err := s.dao.Recommend(c, arg.Mid, serviceArea, arg.MainTids, arg.SubTids, arg.Device, arg.PageSize, arg.RemoteIP)
- if err != nil {
- return nil, err
- }
- return s.collectionAsRecommendUserInfo(c, resp.Data, resp.TrackID, arg.RemoteIP)
- }
- // func followerString(follower int64) string {
- // if follower <= 0 {
- // return ""
- // }
- // if follower < 10000 {
- // return fmt.Sprintf("%d粉丝", follower)
- // }
- // return fmt.Sprintf("%.1f万粉丝", float64(follower)/float64(10000))
- // }
- // AchieveGet is
- func (s *Service) AchieveGet(c context.Context, arg *model.ArgAchieveGet) (*mrl.AchieveGetReply, error) {
- rpcArg := &mrl.ArgAchieveGet{
- Award: arg.Award,
- Mid: arg.Mid,
- }
- return s.relationRPC.AchieveGet(c, rpcArg)
- }
- // Achieve is
- func (s *Service) Achieve(c context.Context, arg *model.ArgAchieve) (*model.AchieveReply, error) {
- rpcArg := &mrl.ArgAchieve{
- AwardToken: arg.AwardToken,
- }
- achieve, err := s.relationRPC.Achieve(c, rpcArg)
- if err != nil {
- return nil, err
- }
- reply := &model.AchieveReply{
- Achieve: *achieve,
- Metadata: make(map[string]interface{}),
- }
- info, err := s.accountRPC.Info3(c, &acml.ArgMid{Mid: achieve.Mid})
- if err != nil {
- return nil, err
- }
- reply.Metadata["mid"] = info.Mid
- reply.Metadata["name"] = info.Name
- return reply, nil
- }
- // FollowerNotifySetting get new-follower-notification setting
- func (s *Service) FollowerNotifySetting(c context.Context, mid int64) (followerNotify *mrl.FollowerNotifySetting, err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- RealIP: metadata.String(c, metadata.RemoteIP),
- }
- return s.relationRPC.FollowerNotifySetting(c, arg)
- }
- // EnableFollowerNotify enable new-follower-notification
- func (s *Service) EnableFollowerNotify(c context.Context, mid int64) (err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- RealIP: metadata.String(c, metadata.RemoteIP),
- }
- return s.relationRPC.EnableFollowerNotify(c, arg)
- }
- // DisableFollowerNotify enable new-follower-notification
- func (s *Service) DisableFollowerNotify(c context.Context, mid int64) (err error) {
- arg := &mrl.ArgMid{
- Mid: mid,
- RealIP: metadata.String(c, metadata.RemoteIP),
- }
- return s.relationRPC.DisableFollowerNotify(c, arg)
- }
- // SameFollowings is
- func (s *Service) SameFollowings(c context.Context, arg *model.ArgSameFollowing) (f []*model.Following, crc32v uint32, total int, err error) {
- sfArg := &mrl.ArgSameFollowing{Mid1: arg.VMid, Mid2: arg.Mid}
- fr, err := s.relationRPC.SameFollowings(c, sfArg)
- if err != nil {
- log.Error("s.SameFollowings(%+v) err(%v)", arg, err)
- return
- }
- total = len(fr)
- if arg.Order == "asc" {
- // 直接倒序即可
- for i := len(fr)/2 - 1; i >= 0; i-- {
- opp := len(fr) - 1 - i
- fr[i], fr[opp] = fr[opp], fr[i]
- }
- }
- start, end := (arg.PN-1)*arg.PS, arg.PN*arg.PS
- switch {
- case start >= int64(len(fr)):
- fr = fr[:0]
- case end >= int64(len(fr)):
- fr = fr[start:]
- default:
- fr = fr[start:end]
- }
- if len(fr) == 0 {
- f = _emptyFollowings
- return
- }
- mids := make([]int64, 0, len(fr))
- for _, fi := range fr {
- mids = append(mids, fi.Mid)
- }
- temp := []byte(fmt.Sprintf("%s", fr))
- crc32v = crc32.Checksum(temp, crc32.IEEETable)
- if uint64(crc32v) == arg.ReVersion {
- err = ecode.NotModified
- return
- }
- accArg := &acml.ArgMids{Mids: mids}
- cards, err := s.accountRPC.Cards3(c, accArg)
- if err != nil {
- log.Error("s.accountRPC.Cards3(mid:%v) err(%v)", accArg, err)
- return
- }
- for _, fi := range fr {
- tmp := &model.Following{Following: fi}
- card, ok := cards[fi.Mid]
- if !ok {
- log.Warn("Failed to fetch card with mid: %d", fi.Mid)
- continue
- }
- tmp.Face = card.Face
- tmp.Uname = card.Name
- tmp.Sign = card.Sign
- of := card.Official
- if of.Role == 0 {
- tmp.OfficialVerify.Type = -1
- } else {
- if of.Role <= 2 {
- tmp.OfficialVerify.Type = 0
- } else {
- tmp.OfficialVerify.Type = 1
- }
- tmp.OfficialVerify.Desc = of.Title
- }
- tmp.Vip.Type = int(card.Vip.Type)
- tmp.Vip.VipStatus = int(card.Vip.Status)
- tmp.Vip.DueDate = card.Vip.DueDate
- f = append(f, tmp)
- }
- return
- }
|