Commit 85e94860 authored by vicotor's avatar vicotor

add cache data

parent 606fb2eb
package cachedata
import (
"context"
lru "github.com/hashicorp/golang-lru"
"github.com/odysseus/payment/model"
goredislib "github.com/redis/go-redis/v9"
)
type CacheData struct {
rdb *goredislib.Client
pathLru *lru.Cache
ctx context.Context
cancel context.CancelFunc
taskType model.TaskTypeRepository
userRepo model.UserRepository
userLevel model.UserLevelRepository
userAndTaskRepo model.UserLevelTaskTypeRepository
}
func NewCacheData(ctx context.Context, options goredislib.Options) *CacheData {
rdb := goredislib.NewClient(&options)
pathLru, _ := lru.New(10000)
cache := &CacheData{
rdb: rdb,
pathLru: pathLru,
taskType: model.NewTaskTypeRepository(),
userRepo: model.NewUserRepository(),
userLevel: model.NewUserLevelRepository(),
userAndTaskRepo: model.NewUserLevelTaskTypeRepository(),
}
cache.ctx, cache.cancel = context.WithCancel(ctx)
return cache
}
package cachedata
import (
"encoding/json"
"github.com/odysseus/payment/model"
"strconv"
)
func (c *CacheData) GetTaskWithPath(path string) (*model.TaskType, error) {
// get from local cache
if v, exist := c.pathLru.Get(path); exist {
return v.(*model.TaskType), nil
}
// get id from redis and then get task from redis by id.
pathIdKey := "path-id:" + path
if taskIdKey, err := c.getTaskIdFromRedis(pathIdKey); err == nil {
// get task from redis by id
if task, err := c.getTaskFromRedis(taskIdKey); err == nil {
// set task to local cache
c.pathLru.Add(path, task)
return task, nil
}
}
// get task from db by path and then set task to redis.
if task, err := c.getTaskFromDbByPath(path); err == nil {
// set task to redis
taskIdKey := "task-id-" + strconv.FormatInt(task.ID, 10)
if data, err := json.Marshal(task); err == nil {
if err = c.rdb.Set(c.ctx, taskIdKey, string(data), 0).Err(); err == nil {
// set taskIdKey to redis
if err = c.rdb.Set(c.ctx, pathIdKey, taskIdKey, 0).Err(); err == nil {
// set task to local cache
c.pathLru.Add(path, task)
return task, nil
} else {
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
}
}
func (c *CacheData) getTaskFromRedis(taskIdKey string) (*model.TaskType, error) {
if data, err := c.rdb.Get(c.ctx, taskIdKey).Result(); err == nil {
var task = new(model.TaskType)
if err = json.Unmarshal([]byte(data), task); err == nil {
return task, nil
}
return nil, err
} else {
return nil, err
}
}
func (c *CacheData) getTaskIdFromRedis(key string) (string, error) {
// get from redis
taskIdKey, err := c.rdb.Get(c.ctx, key).Result()
return taskIdKey, err
}
func (c *CacheData) getTaskFromDbByPath(path string) (*model.TaskType, error) {
return c.taskType.GetByApiPath(path)
}
func (c *CacheData) getTaskFromDbById(id int64) (*model.TaskType, error) {
return c.taskType.GetById(id)
}
func (c *CacheData) GetTaskWithId(id int64) (*model.TaskType, error) {
// get from redis
taskIdKey := "task-id-" + strconv.FormatInt(id, 10)
// get task from redis by id
if task, err := c.getTaskFromRedis(taskIdKey); err == nil {
return task, nil
}
// get task from db by id and then set task to redis.
if task, err := c.getTaskFromDbById(id); err == nil {
// set task to redis
if data, err := json.Marshal(task); err == nil {
if err = c.rdb.Set(c.ctx, taskIdKey, string(data), 0).Err(); err == nil {
return task, nil
} else {
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
}
}
package cachedata
import (
"encoding/json"
"github.com/odysseus/payment/model"
"strconv"
)
func (c *CacheData) getUserLevelFromRedis(level int64) (*model.UserLevel, error) {
ulk := "level-info:" + strconv.FormatInt(level, 10)
if data, err := c.rdb.Get(c.ctx, ulk).Result(); err == nil {
var userLevel = new(model.UserLevel)
if err = json.Unmarshal([]byte(data), userLevel); err == nil {
return userLevel, nil
}
return nil, err
} else {
return nil, err
}
}
func (c *CacheData) getUserLevelFromDb(levelId int64) (*model.UserLevel, error) {
if userLevel, err := c.userLevel.GetById(levelId); err == nil {
return userLevel, nil
} else {
return nil, err
}
}
// implement setUserLevelToRedis
func (c *CacheData) setUserLevelToRedis(d *model.UserLevel) error {
ulk := "level-info:" + strconv.FormatInt(d.ID, 10)
if data, err := json.Marshal(d); err == nil {
if err = c.rdb.Set(c.ctx, ulk, string(data), 0).Err(); err == nil {
return nil
}
return err
} else {
return err
}
}
func (c *CacheData) GetUserLevelInfoByLevelId(levelId int64) (*model.UserLevel, error) {
// get from redis by level.
// if not found in redis, get from db and then add to redis.
if userLevel, err := c.getUserLevelFromRedis(levelId); err == nil {
return userLevel, nil
}
if userLevel, err := c.getUserLevelFromDb(levelId); err == nil {
if err = c.setUserLevelToRedis(userLevel); err == nil {
return userLevel, nil
}
return nil, err
} else {
return nil, err
}
}
package cachedata
import (
"encoding/json"
"github.com/odysseus/payment/model"
"strconv"
)
func (c *CacheData) getUserLevelAndTaskTypeFromRedis(levelId int64, taskTypeId int64) (*model.UserLevelTaskType, error) {
ulk := "level-task-type:" + strconv.FormatInt(levelId, 10) + "-" + strconv.FormatInt(taskTypeId, 10)
if data, err := c.rdb.Get(c.ctx, ulk).Result(); err == nil {
var userLevelAndTaskType = new(model.UserLevelTaskType)
if err = json.Unmarshal([]byte(data), userLevelAndTaskType); err == nil {
return userLevelAndTaskType, nil
}
return nil, err
} else {
return nil, err
}
}
func (c *CacheData) getUserLevelAndTaskTypeFromDb(levelId int64, taskTypeId int64) (*model.UserLevelTaskType, error) {
if userLevelAndTaskType, err := c.userAndTaskRepo.GetByTaskTypeAndUserLevelId(taskTypeId, levelId); err == nil {
return userLevelAndTaskType, nil
} else {
return nil, err
}
}
func (c *CacheData) setUserLevelAndTaskTypeToRedis(d *model.UserLevelTaskType) error {
ulk := "level-task-type:" + strconv.FormatInt(d.UserLevelId, 10) + "-" + strconv.FormatInt(d.TaskTypeId, 10)
if data, err := json.Marshal(d); err == nil {
if err = c.rdb.Set(c.ctx, ulk, string(data), 0).Err(); err == nil {
return nil
}
return err
} else {
return err
}
}
func (c *CacheData) GetUserLevelAndTaskTypeByLevelIdAndTaskTypeId(levelId int64, taskTypeId int64) (*model.UserLevelTaskType, error) {
// get from redis by level.
// if not found in redis, get from db and then add to redis.
if userLevelAndTaskType, err := c.getUserLevelAndTaskTypeFromRedis(levelId, taskTypeId); err == nil {
return userLevelAndTaskType, nil
}
if userLevelAndTaskType, err := c.getUserLevelAndTaskTypeFromDb(levelId, taskTypeId); err == nil {
if err = c.setUserLevelAndTaskTypeToRedis(userLevelAndTaskType); err == nil {
return userLevelAndTaskType, nil
}
return nil, err
} else {
return nil, err
}
}
package model
import (
"fmt"
"github.com/astaxie/beego/orm"
log "github.com/sirupsen/logrus"
)
type DbConfig struct {
User string
Passwd string
Host string
Port string
DbName string
}
func DbInit(dbconf DbConfig) {
// Set up database
datasource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", dbconf.User, dbconf.Passwd, dbconf.Host, dbconf.Port, dbconf.DbName)
orm.RegisterDriver("mysql", orm.DRMySQL)
err := orm.RegisterDataBase("default", "mysql", datasource)
if err != nil {
log.WithError(err).Fatal("failed to connect to database")
}
orm.RegisterModel(new(User))
orm.RegisterModel(new(TaskType))
orm.RegisterModel(new(UserLevel))
orm.RegisterModel(new(UserLevelTaskType))
}
......@@ -28,6 +28,7 @@ func (TaskType) TableName() string {
type TaskTypeRepository interface {
Create(taskType *TaskType) error
GetById(id int64) (*TaskType, error)
GetByApiPath(path string) (*TaskType, error)
GetListByFilter(filters ...interface{}) []*TaskType
Update(taskType *TaskType) error
Delete(taskType *TaskType) error
......@@ -69,6 +70,15 @@ func (repo *taskTypeRepositoryImpl) GetById(id int64) (*TaskType, error) {
return &taskType, nil
}
func (repo *taskTypeRepositoryImpl) GetByApiPath(path string) (*TaskType, error) {
taskType := TaskType{ApiPath: path}
err := repo.o.Read(&taskType)
if err != nil {
return nil, err
}
return &taskType, nil
}
func (repo *taskTypeRepositoryImpl) Update(taskType *TaskType) error {
_, err := repo.o.Update(taskType)
return err
......
......@@ -32,6 +32,7 @@ func (UserLevel) TableName() string {
type UserLevelRepository interface {
Create(user *UserLevel) error
GetById(uid int64) (*UserLevel, error)
GetByLevel(level int64) (*UserLevel, error)
GetListByFilter(filters ...interface{}) []*UserLevel
Update(user *UserLevel) error
Delete(user *UserLevel) error
......@@ -73,6 +74,15 @@ func (repo *userLevelRepositoryImpl) GetById(uid int64) (*UserLevel, error) {
return &user, nil
}
func (repo *userLevelRepositoryImpl) GetByLevel(level int64) (*UserLevel, error) {
user := UserLevel{Level: level}
err := repo.o.Read(&user)
if err != nil {
return nil, err
}
return &user, nil
}
func (repo *userLevelRepositoryImpl) Update(user *UserLevel) error {
_, err := repo.o.Update(user)
return err
......
......@@ -25,7 +25,7 @@ type UserLevelTaskTypeRepository interface {
Create(user *UserLevelTaskType) error
GetById(uid int64) (*UserLevelTaskType, error)
GetListByFilter(filters ...interface{}) []*UserLevelTaskType
GetByTaskTypeAndUserLevel(taskType int64, userLevel int64) (*UserLevelTaskType, error)
GetByTaskTypeAndUserLevelId(taskType int64, userLevel int64) (*UserLevelTaskType, error)
Update(user *UserLevelTaskType) error
Delete(user *UserLevelTaskType) error
}
......@@ -58,8 +58,8 @@ func (repo *userLevelTaskTypeRepositoryImpl) GetListByFilter(filters ...interfac
return list
}
func (repo *userLevelTaskTypeRepositoryImpl) GetByTaskTypeAndUserLevel(taskType int64, userLevel int64) (*UserLevelTaskType, error) {
user := UserLevelTaskType{TaskTypeId: taskType, UserLevelId: userLevel}
func (repo *userLevelTaskTypeRepositoryImpl) GetByTaskTypeAndUserLevelId(taskType int64, userLevelId int64) (*UserLevelTaskType, error) {
user := UserLevelTaskType{TaskTypeId: taskType, UserLevelId: userLevelId}
err := repo.o.Read(&user)
if err != nil {
return nil, err
......
package redisService
import goredislib "github.com/redis/go-redis/v9"
func GetRedis(param goredislib.Options) *goredislib.Client {
return goredislib.NewClient(&param)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment