123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- package dao
- import (
- "context"
- "fmt"
- "strconv"
- "go-common/app/admin/main/reply/model"
- "go-common/library/cache/redis"
- "go-common/library/log"
- )
- const (
- _prefixIdx = "i_"
- _prefixNewRootIdx = "ri_"
- _prefixAuditIdx = "ai_%d_%d"
- // 针对大忽悠时间被删除评论的人的MID
- _prefixAdminDelMid = "mid_%d"
- // f_{折叠类型,根评论还是评论区}_{评论区ID或者根评论ID}
- _foldedReplyFmt = "f_%s_%d"
- // dialog
- _prefixDialogIdx = "d_%d"
- _maxCount = 20000
- )
- func keyFolderIdx(kind string, ID int64) string {
- return fmt.Sprintf(_foldedReplyFmt, kind, ID)
- }
- func keyDelMid(mid int64) string {
- return fmt.Sprintf(_prefixAdminDelMid, mid)
- }
- // KeyMainIdx ...
- func keyMainIdx(oid int64, tp, sort int32) string {
- if oid > _oidOverflow {
- return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
- }
- return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
- }
- // keyDialogIdx ...
- func keyDialogIdx(dialog int64) string {
- return fmt.Sprintf(_prefixDialogIdx, dialog)
- }
- // KeyRootIdx ...
- func keyRootIdx(root int64) string {
- return _prefixNewRootIdx + strconv.FormatInt(root, 10)
- }
- func keyIdx(oid int64, tp, sort int32) string {
- if oid > _oidOverflow {
- return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
- }
- return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
- }
- func keyNewRootIdx(rpID int64) string {
- return _prefixNewRootIdx + strconv.FormatInt(rpID, 10)
- }
- func keyAuditIdx(oid int64, tp int32) string {
- return fmt.Sprintf(_prefixAuditIdx, oid, tp)
- }
- func (d *Dao) ExsistsDelMid(c context.Context, mid int64) (ok bool, err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- key := keyDelMid(mid)
- if ok, err = redis.Bool(conn.Do("EXISTS", key)); err != nil {
- log.Error("conn.Do(EXISTS, %s) error(%v)", key, err)
- }
- return
- }
- func (d *Dao) SetDelMid(c context.Context, mid int64) (err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- // 15天内
- if err = conn.Send("SETEX", keyDelMid(mid), 86400*15, 1); err != nil {
- log.Error("redis SETEX(%s) error(%v)", keyDelMid(mid), err)
- }
- return
- }
- // ExpireIndex set expire time for index.
- func (d *Dao) ExpireIndex(c context.Context, oid int64, typ, sort int32) (ok bool, err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- if ok, err = redis.Bool(conn.Do("EXPIRE", keyIdx(oid, typ, sort), d.redisExpire)); err != nil {
- log.Error("conn.Do(EXPIRE) error(%v)", err)
- }
- return
- }
- // ExpireNewChildIndex set expire time for root's index.
- func (d *Dao) ExpireNewChildIndex(c context.Context, root int64) (ok bool, err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- if ok, err = redis.Bool(conn.Do("EXPIRE", keyNewRootIdx(root), d.redisExpire)); err != nil {
- log.Error("conn.Do(EXPIRE) error(%v)", err)
- }
- return
- }
- // TopChildReply ...
- func (d *Dao) TopChildReply(c context.Context, root, child int64) (err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- if _, err = conn.Do("ZADD", keyNewRootIdx(root), 0, child); err != nil {
- return
- }
- return
- }
- // CountReplies get count of reply.
- func (d *Dao) CountReplies(c context.Context, oid int64, tp, sort int32) (count int, err error) {
- key := keyIdx(oid, tp, sort)
- conn := d.redis.Get(c)
- defer conn.Close()
- if count, err = redis.Int(conn.Do("ZCARD", key)); err != nil {
- log.Error("CountReplies error(%v)", err)
- }
- return
- }
- // MinScore get the lowest score from sorted set
- func (d *Dao) MinScore(c context.Context, oid int64, tp int32, sort int32) (score int32, err error) {
- key := keyIdx(oid, tp, sort)
- conn := d.redis.Get(c)
- defer conn.Close()
- values, err := redis.Values(conn.Do("ZRANGE", key, 0, 0, "WITHSCORES"))
- if err != nil {
- log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
- return
- }
- if len(values) != 2 {
- err = fmt.Errorf("redis zrange items(%v) length not 2", values)
- return
- }
- var id int64
- redis.Scan(values, &id, &score)
- return
- }
- // AddFloorIndex add index by floor.
- func (d *Dao) AddFloorIndex(c context.Context, rp *model.Reply) (err error) {
- min, err := d.MinScore(c, rp.Oid, rp.Type, model.SortByFloor)
- if err != nil {
- log.Error("s.dao.Redis.AddFloorIndex failed , oid(%d) type(%d) err(%v)", rp.Oid, rp.Type, err)
- } else if rp.Floor <= min {
- return
- }
- key := keyIdx(rp.Oid, rp.Type, model.SortByFloor)
- conn := d.redis.Get(c)
- defer conn.Close()
- if err = conn.Send("ZADD", key, rp.Floor, rp.ID); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive error(%v)", err)
- return
- }
- return
- }
- // AddCountIndex add index by count.
- func (d *Dao) AddCountIndex(c context.Context, rp *model.Reply) (err error) {
- if rp.IsTop() {
- return
- }
- var count int
- if count, err = d.CountReplies(c, rp.Oid, rp.Type, model.SortByCount); err != nil {
- return
- } else if count >= _maxCount {
- var min int32
- if min, err = d.MinScore(c, rp.Oid, rp.Type, model.SortByCount); err != nil {
- return
- }
- if rp.RCount <= min {
- return
- }
- }
- key := keyIdx(rp.Oid, rp.Type, model.SortByCount)
- conn := d.redis.Get(c)
- defer conn.Close()
- if err = conn.Send("ZADD", key, int64(rp.RCount)<<32|(int64(rp.Floor)&0xFFFFFFFF), rp.ID); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive error(%v)", err)
- return
- }
- return
- }
- // AddLikeIndex add index by like.
- func (d *Dao) AddLikeIndex(c context.Context, rp *model.Reply, rpt *model.Report) (err error) {
- if rp.IsTop() {
- return
- }
- var rptCn int32
- if rpt != nil {
- rptCn = rpt.Count
- }
- score := int64((float32(rp.Like+model.WeightLike) / float32(rp.Hate+model.WeightHate+rptCn)) * 100)
- score = score<<32 | (int64(rp.RCount) & 0xFFFFFFFF)
- var count int
- if count, err = d.CountReplies(c, rp.Oid, rp.Type, model.SortByLike); err != nil {
- return
- } else if count >= _maxCount {
- var min int32
- if min, err = d.MinScore(c, rp.Oid, rp.Type, model.SortByLike); err != nil {
- return
- }
- if score <= int64(min) {
- return
- }
- }
- key := keyIdx(rp.Oid, rp.Type, model.SortByLike)
- conn := d.redis.Get(c)
- defer conn.Close()
- if err = conn.Send("ZADD", key, score, rp.ID); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive() error(%v)", err)
- return
- }
- return
- }
- // DelIndexBySort delete index by sort.
- func (d *Dao) DelIndexBySort(c context.Context, rp *model.Reply, sort int32) (err error) {
- key := keyIdx(rp.Oid, rp.Type, sort)
- conn := d.redis.Get(c)
- defer conn.Close()
- if _, err = conn.Do("ZREM", key, rp.ID); err != nil {
- log.Error("conn.Do(ZREM) error(%v)", err)
- }
- return
- }
- // DelReplyIndex delete reply index.
- func (d *Dao) DelReplyIndex(c context.Context, rp *model.Reply) (err error) {
- var (
- key string
- n int
- )
- conn := d.redis.Get(c)
- defer conn.Close()
- if rp.Root == 0 {
- key = keyIdx(rp.Oid, rp.Type, model.SortByFloor)
- err = conn.Send("ZREM", key, rp.ID)
- key = keyIdx(rp.Oid, rp.Type, model.SortByCount)
- err = conn.Send("ZREM", key, rp.ID)
- key = keyIdx(rp.Oid, rp.Type, model.SortByLike)
- err = conn.Send("ZREM", key, rp.ID)
- n += 3
- } else {
- if rp.Dialog != 0 {
- key = keyDialogIdx(rp.Dialog)
- err = conn.Send("ZREM", key, rp.ID)
- n++
- }
- key = keyNewRootIdx(rp.Root)
- err = conn.Send("ZREM", key, rp.ID)
- n++
- }
- if err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- for i := 0; i < n; i++ {
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive error(%v)", err)
- return
- }
- }
- return
- }
- // AddNewChildIndex add root reply index by floor.
- func (d *Dao) AddNewChildIndex(c context.Context, rp *model.Reply) (err error) {
- key := keyNewRootIdx(rp.Root)
- conn := d.redis.Get(c)
- defer conn.Close()
- if err = conn.Send("ZADD", key, rp.Floor, rp.ID); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
- log.Error("conn.Send error(%v)", err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive() error(%v)", err)
- return
- }
- return
- }
- // DelAuditIndex delete audit reply cache.
- func (d *Dao) DelAuditIndex(c context.Context, rp *model.Reply) (err error) {
- key := keyAuditIdx(rp.Oid, rp.Type)
- conn := d.redis.Get(c)
- defer conn.Close()
- if err = conn.Send("ZREM", key, rp.ID); err != nil {
- log.Error("conn.Send(ZREM %s) error(%v)", key, err)
- return
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive() error(%v)", err)
- return
- }
- return
- }
- // RemReplyFromRedis ...
- func (d *Dao) RemReplyFromRedis(c context.Context, keyMapping map[string][]int64) (err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- count := 0
- for key, rpIDs := range keyMapping {
- if len(rpIDs) == 0 {
- continue
- }
- args := make([]interface{}, 0, 1+len(rpIDs))
- args = append(args, key)
- for _, rpID := range rpIDs {
- args = append(args, rpID)
- }
- if err = conn.Send("ZREM", args...); err != nil {
- log.Error("conn.Send(ZREM %s) error(%v)", key, err)
- return
- }
- count++
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- for i := 0; i < count; i++ {
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive() error(%v)", err)
- return
- }
- }
- return
- }
- // ExpireFolder ...
- func (d *Dao) ExpireFolder(c context.Context, kind string, ID int64) (ok bool, err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- if ok, err = redis.Bool(conn.Do("EXPIRE", keyFolderIdx(kind, ID), d.redisExpire)); err != nil {
- log.Error("conn.Do(EXPIRE) error(%v)", err)
- }
- return
- }
- // AddFolder ...
- func (d *Dao) AddFolder(c context.Context, keyMapping map[string][]*model.Reply) (err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- count := 0
- for key, rps := range keyMapping {
- var args []interface{}
- args = append(args, key)
- for _, rp := range rps {
- args = append(args, rp.Floor)
- args = append(args, rp.ID)
- }
- if err = conn.Send("ZADD", args...); err != nil {
- log.Error("conn.Send(ZADD %s) error(%v)", key, err)
- return
- }
- count++
- if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
- return
- }
- count++
- }
- if err = conn.Flush(); err != nil {
- log.Error("conn.Flush error(%v)", err)
- return
- }
- for i := 0; i < count; i++ {
- if _, err = conn.Receive(); err != nil {
- log.Error("conn.Receive() error(%v)", err)
- return
- }
- }
- return
- }
- // RemFolder ...
- func (d *Dao) RemFolder(c context.Context, kind string, ID, rpID int64) (err error) {
- conn := d.redis.Get(c)
- defer conn.Close()
- key := keyFolderIdx(kind, ID)
- if _, err = conn.Do("ZREM", key, rpID); err != nil {
- log.Error("conn.Do(ZREM) error(%v)", err)
- }
- return
- }
|