bilibili-backup/app/service/openplatform/anti-fraud/dao/cache.go
2019-04-22 02:59:20 +00:00

601 lines
14 KiB
Go

package dao
import (
"context"
"encoding/json"
"fmt"
"time"
"go-common/app/service/openplatform/anti-fraud/model"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_keyBankQuestions = "AntiFraud:BANK_%d:QUESTIONS"
_keyQuestionFetchTime = "AntiFraud:USER_%s:ITEM_%d_%d_%s_PLATFORM:%d_Date"
// 上次调起组件的id
_keyComponentID = "AntiFraud:USER_%s:ITEM_%d_%d_%s_PLATFORM:%d_COMID"
// 回答过的问题 id
_keyAnsweredIds = "AntiFraud:USER_%s:ITEM_%d_%d_%s_PLATFORM:%d_ANSWER_IDS"
// 组件内获取题目次数
_keyBindBank = "AntiFraud:BIND_BANK_ITEM_%s"
_keyComponentTimes = "AntiFraud:USER_%s:ITEM_%d_%d_%s_PLATFORM:%d_ANSWERTIMES"
_keyBankID = "AntiFraud:BANKID_%d"
//答案ids缓存
_keyAnswerIds = "AntiFraud:AnswerIds_%d"
// 图片id
_keyPicID = "AntiFraud:AnswerAllPic"
// 缓存所有图片id
_keyPicIds = "AntiFraud:AnswerPic_%d"
//默认100条数据
_limit = 100
// 缓存问题
_keyQusInfo = "AntiFraud:QusInfo_%d"
// 缓存图片
_keyAnswerPicID = "AntiFraud:USER_%s:ITEM_%d_%d_%s_AnswerPic:%d_COMID"
//答题日志list
_keyAddLog = "AntiFraud:AddLog"
//答案缓存
_keyAnswer = "AntiFraud:Answer_%d"
// 5分钟缓存
_fiveMinuts = 5 * time.Minute
)
// PingRedis check redis connection
func (d *Dao) PingRedis(c context.Context) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
_, err = conn.Do("PING")
return
}
// GetUserQuestionCache get
func (d *Dao) GetUserQuestionCache(c context.Context, args *model.ArgGetQuestion, bankID int64) {
key := fmt.Sprintf("USER_%s_ITEM_%d_%d_%s_PLATFORM_%d_BANK_%d", args.UID, args.Source, args.TargetItemType, args.TargetItem, args.Platform, bankID)
d.RedisDo(c, "GET", key)
}
// RedisDo redis cmd
func (d *Dao) RedisDo(c context.Context, cmd string, args ...interface{}) (reply interface{}, err error) {
conn := d.redis.Get(c)
defer conn.Close()
return conn.Do(cmd, args...)
}
// SetBankQuestionsCache 将题库下的全部问题存入缓存
func (d *Dao) SetBankQuestionsCache(c context.Context, bankID int64, ids []int64) (err error) {
key := fmt.Sprintf(_keyBankQuestions, bankID)
err = d.SetObj(c, key, ids, time.Hour)
if err != nil {
log.Error("d.SetBankQuestionsCache() error(%v)", err)
return
}
return
}
// GetBankQuestionsCache 从缓存获取题库下的全部问题
func (d *Dao) GetBankQuestionsCache(c context.Context, bankID int64) (ids []int64) {
key := fmt.Sprintf(_keyBankQuestions, bankID)
reply, err := redis.Bytes(d.RedisDo(c, "GET", key))
if err == redis.ErrNil {
return
}
if err != nil {
log.Error("查询 redis 出错 d.GetBankQuestionsCache(%d) error(%v)", bankID, err)
return
}
err = json.Unmarshal(reply, &ids)
if err != nil {
return
}
return
}
// QusFetchTime 上次题目拉取时间
func (d *Dao) QusFetchTime(c context.Context, args *model.ArgGetQuestion) (ts int64) {
ts, _ = redis.Int64(d.RedisDo(c, "GET", d.GetQusKey(_keyQuestionFetchTime, args)))
return
}
// SetQusFetchTime 设置上次题目拉取时间
func (d *Dao) SetQusFetchTime(c context.Context, args *model.ArgGetQuestion, ts int64) (err error) {
err = d.Setex(c, d.GetQusKey(_keyQuestionFetchTime, args), ts, _fiveMinuts)
if err != nil {
log.Error("d.SetQusFetchTime(%v, %d) error(%v)", args, ts, err)
}
return
}
// GetQusKey getkey
func (d *Dao) GetQusKey(format string, args *model.ArgGetQuestion) (s string) {
s = fmt.Sprintf(format, args.UID, args.Source, args.TargetItemType, args.TargetItem, args.Platform)
return
}
// Setex set
func (d *Dao) Setex(c context.Context, key string, data interface{}, exp time.Duration) error {
log.Info(" d.setex(%s, %v, %d)", key, data, exp)
_, err := d.RedisDo(c, "SETEX", key, int(exp/1e9), data)
if err != nil {
log.Error("d.Setex(%s, %v) error(%v)", key, data, err)
}
return err
}
// SetObj set
func (d *Dao) SetObj(c context.Context, key string, obj interface{}, exp time.Duration) error {
log.Info(" d.setex(%s, %v, %d)", key, obj, exp)
data, err := json.Marshal(obj)
if err != nil {
return err
}
_, err = d.RedisDo(c, "SETEX", key, int(exp/1e9), data)
if err != nil {
log.Error("d.Setex(%s, %v) error(%v)", key, string(data), err)
}
return err
}
//GetObj get
func (d *Dao) GetObj(c context.Context, key string, obj interface{}) (err error) {
reply, err := redis.Bytes(d.RedisDo(c, "GET", key))
if err != nil {
return
}
err = json.Unmarshal(reply, obj)
if err != nil {
return
}
return
}
// GetAnsweredID 获取已回答问题
func (d *Dao) GetAnsweredID(c context.Context, args *model.ArgGetQuestion) (ids []int64) {
key := d.GetQusKey(_keyAnsweredIds, args)
ids, err := redis.Int64s(d.RedisDo(c, "SMEMBERS", key))
if err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("d.GetAnsweredID(%v) error(%v)", args, err)
}
}
return
}
// SetAnsweredID 设置已回答问题
func (d *Dao) SetAnsweredID(c context.Context, args *model.ArgGetQuestion, questionID int64) (err error) {
key := d.GetQusKey(_keyAnsweredIds, args)
_, err = d.RedisDo(c, "SADD", key, questionID)
if err != nil {
log.Error("d.SetAnsweredID(%v, %d) error(%v)", args, questionID, err)
}
_, err = d.RedisDo(c, "EXPIRE", key, int(_fiveMinuts/1e9))
if err != nil {
log.Error("d.SetAnsweredID expire (%v, %d) error(%v)", args, questionID, err)
}
return
}
// RmAnsweredID 删除已回答问题
func (d *Dao) RmAnsweredID(c context.Context, args *model.ArgGetQuestion) (err error) {
key := d.GetQusKey(_keyAnsweredIds, args)
_, err = d.RedisDo(c, "DEL", key)
if err != nil {
log.Error("d.SetAnsweredID(%v, %d) error(%v)", args, err)
}
return
}
// GetComponentID 获取组件id
func (d *Dao) GetComponentID(c context.Context, args *model.ArgGetQuestion) (cID int, err error) {
key := d.GetQusKey(_keyComponentID, args)
if cID, err = redis.Int(d.RedisDo(c, "GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("d.GetComponentID(%v) error(%v)", args, err)
}
}
return
}
// SetComponentID 设置组件id
func (d *Dao) SetComponentID(c context.Context, args *model.ArgGetQuestion) (err error) {
key := d.GetQusKey(_keyComponentID, args)
err = d.Setex(c, key, args.ComponentID, _fiveMinuts)
if err != nil {
log.Error("d.SetComponentID(%v) error(%v)", args, err)
}
return
}
// GetComponentTimes 获取组件答题次数
func (d *Dao) GetComponentTimes(c context.Context, args *model.ArgGetQuestion) (cID int64, err error) {
key := d.GetQusKey(_keyComponentTimes, args)
if cID, err = redis.Int64(d.RedisDo(c, "GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("d.GetComponentTimes(%v) error(%v)", args, err)
}
}
return
}
// SetComponentTimes 设置组件答题次数
func (d *Dao) SetComponentTimes(c context.Context, args *model.ArgGetQuestion) (err error) {
key := d.GetQusKey(_keyComponentTimes, args)
err = d.Setex(c, key, 0, _fiveMinuts)
if err != nil {
log.Error("d.SetComponentID(%v) error(%v)", args, err)
}
return
}
// IncrComponentTimes 组件计数
func (d *Dao) IncrComponentTimes(c context.Context, args *model.ArgGetQuestion) (err error) {
key := d.GetQusKey(_keyComponentTimes, args)
_, err = d.RedisDo(c, "INCR", key)
if err != nil {
log.Error("d.GetComponentTimes(%v) error(%v)", args, err)
}
return
}
// GetQusBankInfoCache get
func (d *Dao) GetQusBankInfoCache(c context.Context, qbid int64) (oi *model.QuestionBank, err error) {
oi = &model.QuestionBank{}
key := fmt.Sprintf(_keyBankID, qbid)
err = d.GetObj(c, key, oi)
if err == redis.ErrNil {
err = nil
oi, err = d.GetQusBankInfo(c, qbid)
if err != nil {
log.Error("d.GetQusBankInfoCache error(%v)", err)
return
}
err = d.SetObj(c, key, oi, _fiveMinuts)
}
return
}
// GetBindBankInfo get
func (d *Dao) GetBindBankInfo(c context.Context, source, targetItemType int8, targetItem string) (bind *model.QuestionBankBind, err error) {
bind = &model.QuestionBankBind{}
key := fmt.Sprintf(_keyBindBank, targetItem)
err = d.GetObj(c, key, bind)
if err == redis.ErrNil {
//err = nil
binds, err1 := d.GetBindBank(c, source, targetItemType, []string{targetItem})
if err1 != nil {
log.Error("s.GetQuestion(%v) error(%v)", targetItem, err)
err = err1
return
}
if len(binds) < 1 {
log.Warn("s.GetQuestion(%v) 未找到题库绑定关系", targetItem)
err = ecode.BindBankNotFound
return
}
bind = binds[0]
if bind.QuestionBank == nil {
log.Error("s.GetQuestion(%v) 未找到已绑定的题库", targetItem)
err = ecode.QusbNotFound
return
}
err = d.SetObj(c, key, bind, time.Hour)
//return
}
return
}
// CorrectAnswerIds id
func (d *Dao) CorrectAnswerIds(c context.Context, qid int64) (ids []int64, err error) {
key := fmt.Sprintf(_keyAnswerIds, qid)
err = d.GetObj(c, key, &ids)
if err == redis.ErrNil {
err = nil
answers, err1 := d.GetAnswerList(c, qid)
for _, answer := range answers {
if answer.IsCorrect == 1 {
ids = append(ids, answer.AnswerID)
}
}
if err1 != nil {
err = err1
log.Error("d.GetQusBankInfoCache error(%v)", err)
return
}
err1 = d.SetObj(c, key, ids, time.Hour)
err = err1
return
}
return
}
// GetRandPic 背景图
func (d *Dao) GetRandPic(c context.Context, args *model.ArgGetQuestion) (oi *model.QuestBkPic, err error) {
key := _keyPicID
cnt, err := redis.Int(d.RedisDo(c, "LLen", key))
if err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("GetStatisticsCache do(RPOP, %s) error(%v)", key, err)
}
return
}
if cnt == 0 {
err1 := d.PushAllPic(c)
if err1 != nil {
if err1 == redis.ErrNil {
err = nil
} else {
log.Error("PushAllPic do(RPOP, %s) error(%v)", key, err)
}
return
}
}
id, err := redis.Int(d.RedisDo(c, "RPOP", key))
if err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("GetStatisticsCache do(RPOP, %s) error(%v)", key, err)
}
return
}
oi, err = d.GetPic(c, id)
if err != nil {
return
}
//缓存坐标
picKey := d.GetQusKey(_keyAnswerPicID, args)
err = d.SetObj(c, picKey, oi, time.Hour)
if err != nil {
return
}
return
}
// PushAllPic 事先放入redis list中
func (d *Dao) PushAllPic(c context.Context) (err error) {
cnt, err := d.GetPicCount(c)
limit := _limit
page := (int)(cnt / limit)
for i := 0; i <= page; i++ {
key := _keyPicID
ids, _ := d.GetAllPicIds(c, i*limit, limit)
a := make([]interface{}, 0)
a = append(a, key)
for _, id := range ids {
a = append(a, id)
}
if len(a) > 1 {
_, err := d.RedisDo(c, "LPUSH", a...)
if err != nil {
log.Error("[PushAllPic]conn.Do(lpush, %s) error(%v)", key, err)
}
}
}
return
}
// GetPic 获取背景图
func (d *Dao) GetPic(c context.Context, id int) (oi *model.QuestBkPic, err error) {
key := fmt.Sprintf(_keyPicIds, id)
oi = &model.QuestBkPic{}
err = d.GetObj(c, key, oi)
if err == redis.ErrNil {
err = nil
picInfo, err1 := d.GetRandomPic(c, id)
if err1 != nil {
err = err1
log.Error("d.GetPic error(%v)", err1)
return
}
err1 = d.SetObj(c, key, picInfo, time.Hour)
oi = picInfo
err = err1
return
}
return
}
// PushAnswer push
func (d *Dao) PushAnswer(c context.Context, answer *model.ArgCheckAnswer, isCorrect int8) (affect int64, err error) {
ids := xstr.JoinInts(answer.Answers)
obj := model.AddLog{
UID: answer.UID,
QsID: answer.QsID,
Platform: answer.Platform,
Source: answer.Source,
Ids: ids,
IsCorrect: isCorrect,
}
data, err := json.Marshal(obj)
if err != nil {
return
}
_, err = d.RedisDo(c, "LPUSH", _keyAddLog, data)
if err != nil {
log.Error("[PushAllPic]conn.Do(RPOP,%s) error(%v)", "_keyAddLog", err)
}
affect = obj.QsID
return
}
// PopAnswer pop
func (d *Dao) PopAnswer(c context.Context) {
for {
reply, err := redis.Bytes(d.RedisDo(c, "RPOP", _keyAddLog))
if len(reply) > 0 && err == nil {
answer := &model.AddLog{}
err = json.Unmarshal(reply, answer)
if err == nil {
_, err = d.db.Exec(c, _addUserAnswerSQL, answer.UID, answer.QsID, answer.Platform, answer.Source, answer.Ids, answer.IsCorrect)
if err != nil {
log.Error("d.PopAnswer error(%v)", err)
time.Sleep(time.Second * 1)
continue
}
}
}
time.Sleep(time.Second * 5)
}
}
// GetCacheQus get
func (d *Dao) GetCacheQus(c context.Context, id int64) (oi *model.Question, err error) {
key := fmt.Sprintf(_keyQusInfo, id)
oi = &model.Question{}
err = d.GetObj(c, key, oi)
if err == redis.ErrNil {
err = nil
info, err1 := d.GetQusInfo(c, id)
if err1 != nil {
err = err1
log.Error("d.GetPic error(%v)", err1)
return
}
err1 = d.SetObj(c, key, info, time.Hour)
oi = info
err = err1
return
}
return
}
// GetCacheAnswerPic get
func (d *Dao) GetCacheAnswerPic(c context.Context, args *model.ArgGetQuestion) (oi *model.QuestBkPic, err error) {
picKey := d.GetQusKey(_keyAnswerPicID, args)
oi = &model.QuestBkPic{}
err = d.GetObj(c, picKey, oi)
if err != nil {
return
}
return
}
// DelTargetItemBindCache del cache
func (d *Dao) DelTargetItemBindCache(c context.Context, skuID string) (err error) {
key := fmt.Sprintf(_keyBindBank, skuID)
_, err = d.RedisDo(c, "DEL", key)
if err != nil {
if err != redis.ErrNil {
log.Error("d.DelTargetItemBind(%v, %d) error(%v)", skuID, err)
return
}
err = nil
}
return
}
// DelQusCache del cache
func (d *Dao) DelQusCache(c context.Context, id int64) (err error) {
key := fmt.Sprintf(_keyQusInfo, id)
_, err = d.RedisDo(c, "DEL", key)
if err != nil {
if err != redis.ErrNil {
log.Error("d.DelQusCache(%v, %d) error(%v)", id, err)
return
}
err = nil
}
return
}
// GetAnswersByCache cache
func (d *Dao) GetAnswersByCache(c context.Context, id int64) (oi []*model.Answer, err error) {
key := fmt.Sprintf(_keyAnswer, id)
err = d.GetObj(c, key, &oi)
if err == redis.ErrNil {
err = nil
info, err1 := d.GetAnswerList(c, id)
if err1 != nil {
err = err1
log.Error("d.GetPic error(%v)", err1)
return
}
err1 = d.SetObj(c, key, info, time.Hour)
oi = info
err = err1
return
}
return
}
// DelAnswerCache del cache
func (d *Dao) DelAnswerCache(c context.Context, id int64) (err error) {
key := fmt.Sprintf(_keyAnswer, id)
_, err = d.RedisDo(c, "DEL", key)
if err != nil {
if err != redis.ErrNil {
log.Error("d.DelAnswerCache(%v, %d) error(%v)", id, err)
return
}
err = nil
}
return
}
// DelQusBankCache del cache
func (d *Dao) DelQusBankCache(c context.Context, id int64) (err error) {
key := fmt.Sprintf(_keyBankID, id)
_, err = d.RedisDo(c, "DEL", key)
if err != nil {
if err != redis.ErrNil {
log.Error("d.DelQusBankCache(%v, %d) error(%v)", id, err)
return
}
err = nil
}
return
}