You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
600 lines
14 KiB
600 lines
14 KiB
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 |
|
}
|
|
|