go-common/app/interface/openplatform/article/dao/redis.go
2019-04-22 18:49:16 +08:00

485 lines
13 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package dao
import (
"context"
"encoding/json"
"fmt"
"strconv"
"go-common/app/interface/openplatform/article/model"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_prefixUpper = "art_u_%d" // upper's article list
_prefixSorted = "art_sort_%d_%d" // sorted aids sort_category_field
_prefixRank = "art_ranks_%d" // ranks by cid
_prefixMaxLike = "art_mlt_%d" // like message number
_readPingSet = "art:readping" // reading start set
_prefixReadPing = "art:readping:%s:%d" // reading during on some device for some article
_blank = int64(-1)
)
func upperKey(mid int64) string {
return fmt.Sprintf(_prefixUpper, mid)
}
func sortedKey(categoryID int64, field int) string {
return fmt.Sprintf(_prefixSorted, categoryID, field)
}
func rankKey(cid int64) string {
return fmt.Sprintf(_prefixRank, cid)
}
func hotspotKey(typ int8, id int64) string {
return fmt.Sprintf("art_hotspot%d_%d", typ, id)
}
func authorCategoriesKey(mid int64) string {
return fmt.Sprintf("author:categories:%d", mid)
}
func recommendsAuthorsKey(category int64) string {
return fmt.Sprintf("recommends:authors:%d", category)
}
func readPingSetKey() string {
return _readPingSet
}
func readPingKey(buvid string, aid int64) string {
return fmt.Sprintf(_prefixReadPing, buvid, aid)
}
// pingRedis ping redis.
func (d *Dao) pingRedis(c context.Context) (err error) {
conn := d.redis.Get(c)
if _, err = conn.Do("SET", "PING", "PONG"); err != nil {
PromError("redis: ping remote")
log.Error("remote redis: conn.Do(SET,PING,PONG) error(%+v)", err)
}
conn.Close()
return
}
// ExpireUpperCache expire the upper key.
func (d *Dao) ExpireUpperCache(c context.Context, mid int64) (ok bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", upperKey(mid), d.redisUpperExpire)); err != nil {
PromError("redis:up主设定过期")
log.Error("conn.Send(EXPIRE, %s) error(%+v)", upperKey(mid), err)
}
return
}
// ExpireUppersCache expire the upper key.
func (d *Dao) ExpireUppersCache(c context.Context, mids []int64) (res map[int64]bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
res = make(map[int64]bool, len(mids))
for _, mid := range mids {
if err = conn.Send("EXPIRE", upperKey(mid), d.redisUpperExpire); err != nil {
PromError("redis:up主设定过期")
log.Error("conn.Send(EXPIRE, %s) error(%+v)", upperKey(mid), err)
return
}
}
if err = conn.Flush(); err != nil {
PromError("redis:up主flush")
log.Error("conn.Flush error(%+v)", err)
return
}
var ok bool
for _, mid := range mids {
if ok, err = redis.Bool(conn.Receive()); err != nil {
PromError("redis:up主receive")
log.Error("conn.Receive() error(%+v)", err)
return
}
res[mid] = ok
}
return
}
// UppersCaches batch get new articles of uppers by cache.
func (d *Dao) UppersCaches(c context.Context, mids []int64, start, end int) (res map[int64][]int64, err error) {
conn := d.redis.Get(c)
defer conn.Close()
res = make(map[int64][]int64, len(mids))
for _, mid := range mids {
if err = conn.Send("ZREVRANGE", upperKey(mid), start, end); err != nil {
PromError("redis:获取up主")
log.Error("conn.Send(%s) error(%+v)", upperKey(mid), err)
return
}
}
if err = conn.Flush(); err != nil {
PromError("redis:获取up主flush")
log.Error("conn.Flush error(%+v)", err)
return
}
for _, mid := range mids {
aids, err := redis.Int64s(conn.Receive())
if err != nil {
PromError("redis:获取up主receive")
log.Error("conn.Send(ZREVRANGE, %d) error(%+v)", mid, err)
}
l := len(aids)
if l == 0 {
continue
}
if aids[l-1] == _blank {
aids = aids[:l-1]
}
res[mid] = aids
}
cachedCount.Add("up", int64(len(res)))
return
}
// AddUpperCache adds passed article of upper.
func (d *Dao) AddUpperCache(c context.Context, mid, aid int64, ptime int64) (err error) {
art := map[int64][][2]int64{mid: [][2]int64{[2]int64{aid, ptime}}}
err = d.AddUpperCaches(c, art)
return
}
// AddUpperCaches batch add passed article of upper.
func (d *Dao) AddUpperCaches(c context.Context, idsm map[int64][][2]int64) (err error) {
var (
mid, aid, ptime int64
arts [][2]int64
conn = d.redis.Get(c)
count int
)
defer conn.Close()
for mid, arts = range idsm {
key := upperKey(mid)
if len(arts) == 0 {
arts = [][2]int64{[2]int64{_blank, _blank}}
}
for _, art := range arts {
aid = art[0]
ptime = art[1]
if err = conn.Send("ZADD", key, "CH", ptime, aid); err != nil {
PromError("redis:增加up主缓存")
log.Error("conn.Send(ZADD, %s, %d, %d) error(%+v)", key, aid, err)
return
}
count++
}
if err = conn.Send("EXPIRE", key, d.redisUpperExpire); err != nil {
PromError("redis:增加up主expire")
log.Error("conn.Expire error(%+v)", err)
return
}
count++
}
if err = conn.Flush(); err != nil {
PromError("redis:增加up主flush")
log.Error("conn.Flush error(%+v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
PromError("redis:增加up主receive")
log.Error("conn.Receive error(%+v)", err)
return
}
}
return
}
// DelUpperCache delete article of upper cache.
func (d *Dao) DelUpperCache(c context.Context, mid int64, aid int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("ZREM", upperKey(mid), aid); err != nil {
PromError("redis:删除up主")
log.Error("conn.Do(ZERM, %s, %d) error(%+v)", upperKey(mid), aid, err)
}
return
}
// UpperArtsCountCache get upper articles count
func (d *Dao) UpperArtsCountCache(c context.Context, mid int64) (res int, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if res, err = redis.Int(conn.Do("ZCOUNT", upperKey(mid), 0, "+inf")); err != nil {
PromError("redis:up主文章计数")
log.Error("conn.Do(ZCARD, %s) error(%+v)", upperKey(mid), err)
}
return
}
// MoreArtsCaches batch get early articles of upper by publish time.
func (d *Dao) MoreArtsCaches(c context.Context, mid, ptime int64, num int) (before []int64, after []int64, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("ZREVRANGEBYSCORE", upperKey(mid), fmt.Sprintf("(%d", ptime), "-inf", "LIMIT", 0, num); err != nil {
PromError("redis:获取up主更早文章")
log.Error("conn.Send(%s) error(%+v)", upperKey(mid), err)
return
}
if err = conn.Send("ZRANGEBYSCORE", upperKey(mid), fmt.Sprintf("(%d", ptime), "+inf", "LIMIT", 0, num); err != nil {
PromError("redis:获取up主更晚文章")
log.Error("conn.Send(%s) error(%+v)", upperKey(mid), err)
return
}
if err = conn.Flush(); err != nil {
PromError("redis:获取up主更晚文章")
log.Error("conn.Flush error(%+v)", err)
return
}
if before, err = redis.Int64s(conn.Receive()); err != nil {
PromError("redis:获取up主更早文章")
log.Error("conn.Receive error(%+v)", err)
return
}
if after, err = redis.Int64s(conn.Receive()); err != nil {
PromError("redis:获取up主更晚文章")
log.Error("conn.Receive error(%+v)", err)
return
}
l := len(before)
if l == 0 {
return
}
if before[l-1] == _blank {
before = before[:l-1]
}
return
}
// ExpireRankCache expire rank cache
func (d *Dao) ExpireRankCache(c context.Context, cid int64) (res bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
var ttl int64
if ttl, err = redis.Int64(conn.Do("TTL", rankKey(cid))); err != nil {
PromError("redis:排行榜expire")
log.Error("ExpireRankCache(ttl %s) error(%+v)", rankKey(cid), err)
return
}
if ttl > (d.redisRankTTL - d.redisRankExpire) {
res = true
return
}
return
}
// RankCache get rank cache
func (d *Dao) RankCache(c context.Context, cid int64) (res model.RankResp, err error) {
conn := d.redis.Get(c)
defer conn.Close()
key := rankKey(cid)
var s string
if s, err = redis.String(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
PromError("redis:获取排行榜")
log.Error("dao.RankCache zrevrange(%s) err: %+v", key, err)
return
}
err = json.Unmarshal([]byte(s), &res)
return
}
// AddRankCache add rank cache
func (d *Dao) AddRankCache(c context.Context, cid int64, arts model.RankResp) (err error) {
var (
key = rankKey(cid)
conn = d.redis.Get(c)
count int
)
defer conn.Close()
if len(arts.List) == 0 {
return
}
if err = conn.Send("DEL", key); err != nil {
PromError("redis:删除排行榜缓存")
log.Error("conn.Send(DEL, %s) error(%+v)", key, err)
return
}
count++
value, _ := json.Marshal(arts)
if err = conn.Send("SET", key, value); err != nil {
PromError("redis:增加排行榜缓存")
log.Error("conn.Send(SET, %s, %s) error(%+v)", key, value, err)
return
}
count++
if err = conn.Send("EXPIRE", key, d.redisRankTTL); err != nil {
PromError("redis:expire排行榜")
log.Error("conn.Send(EXPIRE, %s, %v) error(%+v)", key, d.redisRankTTL, err)
return
}
count++
if err = conn.Flush(); err != nil {
PromError("redis:增加排行榜flush")
log.Error("conn.Flush error(%+v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
PromError("redis:增加排行榜主receive")
log.Error("conn.Receive error(%+v)", err)
return
}
}
return
}
// AddCacheHotspotArts .
func (d *Dao) AddCacheHotspotArts(c context.Context, typ int8, id int64, arts [][2]int64, replace bool) (err error) {
var (
key = hotspotKey(typ, id)
conn = d.redis.Get(c)
count int
)
defer conn.Close()
if len(arts) == 0 {
return
}
if replace {
if err = conn.Send("DEL", key); err != nil {
PromError("redis:删除热点标签缓存")
log.Error("conn.Send(DEL, %s) error(%+v)", key, err)
return
}
count++
}
for _, art := range arts {
id := art[0]
score := art[1]
if err = conn.Send("ZADD", key, "CH", score, id); err != nil {
PromError("redis:增加热点标签缓存")
log.Error("conn.Send(ZADD, %s, %d, %v) error(%+v)", key, score, id, err)
return
}
count++
}
if err = conn.Send("EXPIRE", key, d.redisHotspotExpire); err != nil {
PromError("redis:热点标签设定过期")
log.Error("conn.Send(EXPIRE, %s, %d) error(%+v)", key, d.redisHotspotExpire, err)
return
}
count++
if err = conn.Flush(); err != nil {
PromError("redis:增加热点标签缓存flush")
log.Error("conn.Flush error(%+v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
PromError("redis:增加热点标签缓存receive")
log.Error("conn.Receive error(%+v)", err)
return
}
}
return
}
// HotspotArtsCache .
func (d *Dao) HotspotArtsCache(c context.Context, typ int8, id int64, start, end int) (res []int64, err error) {
key := hotspotKey(typ, id)
conn := d.redis.Get(c)
defer conn.Close()
res, err = redis.Int64s(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
PromError("redis:获取热点标签列表receive")
log.Error("conn.Send(ZREVRANGE, %s) error(%+v)", key, err)
}
return
}
// HotspotArtsCacheCount .
func (d *Dao) HotspotArtsCacheCount(c context.Context, typ int8, id int64) (res int64, err error) {
key := hotspotKey(typ, id)
conn := d.redis.Get(c)
defer conn.Close()
res, err = redis.Int64(conn.Do("ZCARD", key))
if err != nil {
PromError("redis:获取热点标签计数")
log.Error("conn.Send(ZCARD, %s) error(%+v)", key, err)
}
return
}
// ExpireHotspotArtsCache .
func (d *Dao) ExpireHotspotArtsCache(c context.Context, typ int8, id int64) (ok bool, err error) {
key := hotspotKey(typ, id)
conn := d.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.redisHotspotExpire)); err != nil {
PromError("redis:热点运营设定过期")
log.Error("conn.Send(EXPIRE, %s) error(%+v)", key, err)
}
return
}
// DelHotspotArtsCache .
func (d *Dao) DelHotspotArtsCache(c context.Context, typ int8, hid int64, aid int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
key := hotspotKey(typ, hid)
if _, err = conn.Do("ZREM", key, aid); err != nil {
PromError("redis:删除热点运营文章")
log.Error("conn.Do(ZERM, %s, %d) error(%+v)", key, aid, err)
}
return
}
// AuthorMostCategories .
func (d *Dao) AuthorMostCategories(c context.Context, mid int64) (categories []int64, err error) {
var (
categoriesInts []string
category int64
)
conn := d.redis.Get(c)
defer conn.Close()
key := authorCategoriesKey(mid)
if categoriesInts, err = redis.Strings(conn.Do("SMEMBERS", key)); err != nil {
PromError("redis:获取作者分区")
log.Error("conn.Do(GET, %s) error(%+v)", key, err)
}
for _, categoryInt := range categoriesInts {
if category, err = strconv.ParseInt(categoryInt, 10, 64); err != nil {
PromError("redis:获取作者分区")
log.Error("strconv.Atoi(%s) error(%+v)", categoryInt, err)
return
}
categories = append(categories, category)
}
return
}
// CategoryAuthors .
func (d *Dao) CategoryAuthors(c context.Context, category int64, count int) (authors []int64, err error) {
var (
authorsInts []string
author int64
)
conn := d.redis.Get(c)
defer conn.Close()
key := recommendsAuthorsKey(category)
if authorsInts, err = redis.Strings(conn.Do("SRANDMEMBER", key, count)); err != nil {
PromError("redis:获取分区作者")
log.Error("conn.Do(GET, %s) error(%+v)", key, err)
}
for _, authorInt := range authorsInts {
if author, err = strconv.ParseInt(authorInt, 10, 64); err != nil {
PromError("redis:获取作者分区")
log.Error("strconv.Atoi(%s) error(%+v)", authorInt, err)
return
}
authors = append(authors, author)
}
return
}