package action
import (
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/service"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/request"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/response"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
func (v *VipController) VipAdd() {
v.Execute(conf.VipAdd, func(ctx *utils.Context) (data interface{}, err error) {
req := &request.VipAddRequest{Request: request.Request{Ctx: ctx}}
if err = req.Valid(); err != nil {
ctx.L.Warn("[param is invalid] [err:%v]", err)
return
}
err = v.Service.AddVip(&service.VipAddParam{
UserId: req.UserId,
InitTime: req.InitTime,
EndTime: req.EndTime,
VipLevel: req.VipLevel,
VipType: req.VipType,
})
if err != nil {
ctx.L.Warn("[failed to add vip] [err:%v]", err)
return
}
resp := &response.VipAddResponse{Response: response.Response{Ctx: ctx}}
if err = resp.Format(); err != nil {
ctx.L.Warn("[failed to format result] [err:%v]", err)
}
return
})
}
package action
import (
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"runtime/debug"
"strings"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/framework"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/redis"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/service"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/request"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
const AuthKey = "4b46bd51702ba7473f2bcf906519e013"
type ApiCb func(context *utils.Context) (data interface{}, err error)
type Api struct {
framework.FwController
_ctx *utils.Context
Service service.VipOperator
RedisInstance redis.RedisOperator
}
type VipController struct {
Api
}
type ApiOperator interface {
Execute(apiName string, apiCb ApiCb)
execute(apiName string, apiCb ApiCb)
newContext(apiName string) error
checkAuth() error
initController() error
hitLimitControl(api string) error
finish(data []byte, err error)
record(apiName string) error
}
type Output struct {
Code string
Msg string
Data interface{}
}
func (a *Api) Execute(apiName string, apiCb ApiCb) {
var err error
var result interface{}
// 创建请求上下文
if err = a.newContext(apiName); err != nil {
a.finish(nil, err)
return
}
// 鉴权
if err = a.checkAuth(); err != nil {
a.finish(nil, err)
return
}
// 初始化MVC
if err = a.initController(); err != nil {
a.finish(nil, err)
return
}
// 判断是否命中api频度控制
if err = a.hitLimitControl(apiName); err != nil {
a.finish(nil, err)
return
}
// 回调执行业务逻辑
result, err = apiCb(a._ctx)
if err != nil {
a.finish(nil, err)
return
}
// 记录操作
if err = a.record(apiName); err != nil {
a.finish(nil, err)
return
}
a.finish(utils.JsonEncodeWithoutError(result), err)
return
}
func (a *Api) newContext(apiName string) error {
if len(apiName) == 0 {
return errors.New(conf.ERROR_PARAM_ERROR)
}
logId := a.Ctx.Input.Logid()
a._ctx = &utils.Context{
L: golog.New(),
Input: a.Ctx.Input,
Output: a.Ctx.Output,
LogId: logId,
}
userId, ok := request.QueryUint64(a._ctx, "user_id")
if !ok {
a._ctx.L.Warn("[user_id is null]")
return errors.New(conf.ERROR_PARAM_ERROR)
}
appId, ok := request.QueryInt(a._ctx, "app_id")
if !ok {
a._ctx.L.Warn("[app_id is null]")
return errors.New(conf.ERROR_PARAM_ERROR)
}
a._ctx.UserId = userId
a._ctx.AppId = appId
a._ctx.L.SetBaseInfo("api", apiName)
a._ctx.L.SetBaseInfo("logid", logId)
a._ctx.L.Info("[uri:%s]", a.Ctx.Input.Uri())
return nil
}
func (a *Api) checkAuth() error {
userId := a._ctx.UserId
pcsToken, ok := request.QueryString(a._ctx, "viptoken")
if !ok {
a._ctx.L.Warn("[viptoken is null]")
return errors.New(conf.ERROR_NULL_VIP_TOKEN)
}
pcsTt, ok := request.QueryString(a._ctx, "viptt")
if !ok {
a._ctx.L.Warn("[viptt is null]")
return errors.New(conf.ERROR_NULL_VIP_TT)
}
tmp := md5.Sum([]byte(fmt.Sprintf("%v%v%v", userId, AuthKey, pcsTt)))
md5Token := hex.EncodeToString(tmp[:])
if !strings.EqualFold(pcsToken, md5Token) {
a._ctx.L.Warn("[viptoken is incorrect]")
return errors.New(conf.ERROR_AUTH_FAILED)
}
return nil
}
func (a *Api) initController() error {
if a.Service == nil {
a.Service = &service.VipService{Ctx: a._ctx}
}
if err := a.Service.InitVip(); err != nil {
a._ctx.L.Warn("[failed to new vip service] [err:%v]", err)
return err
}
if a.RedisInstance == nil {
a.RedisInstance = &redis.RedisInstance{}
}
a.RedisInstance.InitRedisPoll()
return nil
}
func (a *Api) hitLimitControl(api string) error {
if limitCond, ok := conf.APILimit[api]; ok {
uid := a._ctx.UserId
appId := a._ctx.AppId
keyPrefix := conf.GlobalConf.RedisConf.KeyPrefix
method := utils.String(limitCond, "method")
interval := utils.Int(limitCond, "interval")
frequency := utils.Int(limitCond, "frequency")
key := fmt.Sprintf("%s-%s-%d-%d", keyPrefix, method, appId, uid)
redisInstance := a.RedisInstance
ttl, err := redisInstance.Ttl(key)
if err != nil {
a._ctx.L.Warn("[limit control] [ttl failed] [key:%s] [api:%s] [err:%v]", key, api, err)
return nil
}
if ttl < 0 {
_, err = redisInstance.SetEx(key, interval, "1")
if err != nil {
a._ctx.L.Warn("[failed to set redis] [key:%s] [interval:%v] [err:%v]", key, interval, err)
return err
}
} else {
hasCount, err := redisInstance.Incr(key)
if err != nil {
a._ctx.L.Warn("[limit control incr failed] [key:%s] [api:%s] [err:%v]", key, api, err)
return err
}
if hasCount > frequency {
a._ctx.L.Warn("[hit limit control] [count:%d] [key:%s] [api:%s]", hasCount, key, api)
return errors.New(conf.ERROR_PCS_REFUSE)
}
}
}
return nil
}
func (a *Api) finish(data []byte, err error) {
if r := recover(); r != nil {
a._ctx.L.Error("[panic!] [detail:%v] [stacktrace:%s]", r, string(debug.Stack()))
err = errors.New(conf.ERROR_NETWORK_ERROR)
}
// 如果错误码或错误msg在map中不存在,则转化为400,系统错误
// 500类错误不返回具体错误msg,统一返回系统错误
errCode := conf.GetErrorCode(err)
errMsg := conf.GetErrorMsg(err)
httpCode := conf.GetHttpCode(err)
resp := Output{Data: data, Code: errCode, Msg: errMsg}
a._ctx.L.Notice("http_code:%v", httpCode)
a._ctx.L.Notice("error_msg:%v", errMsg)
a._ctx.L.Notice("error_code:%v", errCode)
a._ctx.Output.SetStatus(httpCode)
a._ctx.Output.Header("status", resp.Code)
_, err = a._ctx.Output.Body(utils.JsonEncodeWithoutError(resp))
if err != nil {
a._ctx.L.Warn("[failed to finish][err:%v]", err)
return
}
}
func (a *Api) record(apiName string) error {
keyPrefix := conf.GlobalConf.RedisConf.KeyPrefix
reportKeyPrefix := conf.GlobalConf.ReportConf.RedisKeyPrefix
key := fmt.Sprintf("%v-%v-%v", keyPrefix, reportKeyPrefix, apiName)
redisInstance := a.RedisInstance
ttl, err := redisInstance.Ttl(key)
if err != nil {
a._ctx.L.Warn("[ttl failed] [key:%s] [api:%s] [err:%v]", key, apiName, err)
return nil
}
if ttl < 0 {
_, err = redisInstance.Set(key, "1")
if err != nil {
a._ctx.L.Warn("[failed to set redis] [key:%s] [err:%v]", key, err)
return err
}
} else {
_, err = redisInstance.Incr(key)
if err != nil {
a._ctx.L.Warn("[incr failed] [key:%s] [api:%s] [err:%v]", key, apiName, err)
return err
}
}
return nil
}
package action
import (
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/dao"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/request"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/response"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
func (v *VipController) VipInfo() {
v.Execute(conf.VipInfo, func(ctx *utils.Context) (data interface{}, err error) {
req := &request.VipInfoRequest{Request: request.Request{Ctx: ctx}}
if err = req.Valid(); err != nil {
ctx.L.Warn("[param is invalid] [err:%v]", err)
return
}
var info *dao.VipInfo
info, err = v.Service.GetVip(req.UserId)
if err != nil {
ctx.L.Warn("[failed to get vip info] [err:%v]", err)
return
}
resp := &response.VipInfoResponse{Response: response.Response{Ctx: ctx}}
if data, err = resp.Format(info); err != nil {
ctx.L.Warn("[failed to format result] [err:%v]", err)
}
return
})
}
package action
import (
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/service"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/request"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/response"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
func (v *VipController) VipUpdate() {
v.Execute(conf.VipUpdate, func(ctx *utils.Context) (data interface{}, err error) {
req := &request.VipUpdateRequest{Request: request.Request{Ctx: ctx}}
if err = req.Valid(); err != nil {
ctx.L.Warn("[param is invalid] [err:%v]", err)
return
}
err = v.Service.UpdateVip(&service.VipUpdateParam{
UserId: req.UserId,
Experience: req.Experiences,
EndTime: req.EndTime,
VipLevel: req.VipLevel,
VipType: req.VipType,
})
if err != nil {
ctx.L.Warn("[failed to update vip] [err:%v]", err)
return
}
resp := &response.VipUpdateResponse{Response: response.Response{Ctx: ctx}}
if err = resp.Format(); err != nil {
ctx.L.Warn("[failed to format result] [err:%v]", err)
}
return
})
}
package conf
import (
"errors"
"fmt"
"os"
"github.com/BurntSushi/toml"
)
var APILimit map[string]map[string]interface{}
const (
VipInfo = "action_vip_info"
VipUpdate = "action_vip_update"
VipAdd = "action_vip_add"
)
const (
ErrCode = "err_code"
)
type LimitControl struct {
Action string
Interval int
Requency int
Method string
}
func InitApiConf(path string) error {
pwd, err := os.Getwd()
if err != nil {
fmt.Println("[failed to get pwd]")
return err
}
if len(path) != 0 {
pwd = path
}
var limitControl map[string]interface{}
_, err = toml.DecodeFile(pwd+"/config/api.toml", &limitControl)
if err != nil {
fmt.Println("[failed to init config]")
return err
}
limitArr, ok := limitControl["limit"].([]map[string]interface{})
if !ok {
fmt.Println("[failed to unmarshal config]")
return errors.New(ERROR_CONF_INVALID)
}
APILimit = make(map[string]map[string]interface{})
for _, e := range limitArr {
action, ok := e["action"].(string)
if !ok {
fmt.Printf("[failed to unmarshal action] [limit:%v]", e)
return errors.New(ERROR_CONF_INVALID)
}
interval, ok := e["interval"].(int64)
if !ok {
fmt.Printf("[failed to unmarshal interval] [limit:%v]", e)
return errors.New(ERROR_CONF_INVALID)
}
requency, ok := e["requency"].(int64)
if !ok {
fmt.Printf("[failed to unmarshal requency] [limit:%v]", e)
return errors.New(ERROR_CONF_INVALID)
}
method, ok := e["method"].(string)
if !ok {
fmt.Printf("[failed to unmarshal method] [limit:%v]", e)
return errors.New(ERROR_CONF_INVALID)
}
APILimit[action] = map[string]interface{}{
"interval": int(interval),
"requency": int(requency),
"method": method,
}
}
return nil
}
package conf
import (
"fmt"
"os"
"github.com/BurntSushi/toml"
)
var GlobalConf Base
type Base struct {
ServiceConf ServiceConf
DBConf DBConf
RedisConf RedisConf
UfcConf UfcConf
LogConf LogConf
ReportConf ReportConf
}
type ServiceConf struct {
Port int `toml:"port"`
SelfUfcName string `toml:"self_ufc_name"`
}
type DBConf struct {
UserName string `toml:"user_name"`
Password string `toml:"password"`
DatabaseName string `toml:"database_name"`
UfcName string `toml:"ufc_name"`
ReadTimeoutMs int `toml:"read_timeout_ms"`
WriteTimeoutMs int `toml:"write_timeout_ms"`
MaxOpenConnections int `toml:"max_open_connections"`
MaxIdleConnections int `toml:"max_idle_connections"`
RetryNum int `toml:"retry_num"`
}
type RedisConf struct {
UfcName string `toml:"ufc_name"`
KeyPrefix string `toml:"key_prefix"`
ConnectTimeoutMs int `toml:"connect_timeout_ms"`
ReadTimeoutMs int `toml:"read_timeout_ms"`
WriteTimeoutMs int `toml:"write_timeout_ms"`
DefaultTimeoutMs int `toml:"default_timeout_s"`
MaxActiveConnections int `toml:"max_active_connections"`
MaxIdleConnections int `toml:"max_idle_connections"`
RetryNum int `toml:"retry_num"`
}
type UfcConf struct {
PoolSize int `toml:"pool_size"`
ConnectTimeoutMS int `toml:"connect_timeout_ms"`
ReadTimeoutMs int `toml:"read_timeout_ms"`
WriteTimeoutMs int `toml:"write_timeout_ms"`
RetryNum int `toml:"retry_num"`
}
type LogConf struct {
LogLevel int32 `toml:"log_level"`
LogFileName string `toml:"log_file_name"`
LogBackupCount int `toml:"log_backup_count"`
}
type ReportConf struct {
UfcName string `toml:"ufc_name"`
RedisKeyPrefix string `toml:"redis_key_prefix"`
FrequencyPerHour int `toml:"frequency_per_hour"`
}
func InitConf(path string) error {
pwd, err := os.Getwd()
if err != nil {
fmt.Println("[failed to get pwd]")
return err
}
if len(path) != 0 {
pwd = path
}
_, err = toml.DecodeFile(pwd+"/config/conf.toml", &GlobalConf)
if err != nil {
fmt.Println("[failed to init config]")
return err
}
return nil
}
package conf
const (
SUCCESS = "20000"
ERROR_PARAM_ERROR = "40001"
ERROR_AUTH_FAILED = "40010"
ERROR_NULL_USER_ID = "40011"
ERROR_NULL_VIP_TOKEN = "40012"
ERROR_NULL_VIP_TT = "40013"
ERROR_PCS_REFUSE = "40020"
ERROR_TIMEOUT = "40030"
ERROR_SYSTEM = "50000"
ERROR_CONF_INVALID = "50010"
ERROR_5XX_UFC = "50020"
ERROR_4XX_UFC = "50021"
ERROR_NETWORK_ERROR = "50030"
ERROR_GET_REDIS_ERROR = "50040"
)
var ArrErrorMessage = map[string]string{
ERROR_PARAM_ERROR: "请求参数错误",
ERROR_NULL_USER_ID: "user_id为空",
ERROR_NULL_VIP_TOKEN: "viptoken为空",
ERROR_NULL_VIP_TT: "viptt为空",
ERROR_AUTH_FAILED: "鉴权失败",
ERROR_PCS_REFUSE: "命中频控拒绝服务",
ERROR_TIMEOUT: "访问超时",
ERROR_SYSTEM: "系统错误",
ERROR_CONF_INVALID: "配置错误",
ERROR_5XX_UFC: "ufc访问500",
ERROR_4XX_UFC: "ufc访问400",
ERROR_NETWORK_ERROR: "网络错误",
ERROR_GET_REDIS_ERROR: "Redis获取失败",
}
var ArrHttpCode = map[string]int{
SUCCESS: 200,
ERROR_SYSTEM: 400,
ERROR_PARAM_ERROR: 400,
ERROR_NULL_USER_ID: 401,
ERROR_NULL_VIP_TOKEN: 401,
ERROR_NULL_VIP_TT: 401,
ERROR_AUTH_FAILED: 401,
ERROR_PCS_REFUSE: 403,
ERROR_TIMEOUT: 408,
ERROR_CONF_INVALID: 500,
ERROR_5XX_UFC: 500,
ERROR_4XX_UFC: 500,
ERROR_NETWORK_ERROR: 500,
ERROR_GET_REDIS_ERROR: 500,
}
func GetErrorCode(errCode error) string {
if errCode == nil {
return SUCCESS
}
if _, ok := ArrHttpCode[errCode.Error()]; ok {
return errCode.Error()
} else {
// 非预期错误转化为50000系统错误
return ERROR_SYSTEM
}
}
func GetHttpCode(errCode error) int {
if errCode == nil {
return ArrHttpCode[SUCCESS]
}
if httpCode, ok := ArrHttpCode[errCode.Error()]; ok {
return httpCode
} else {
// 非预期错误转化为http code 400
return 400
}
}
func GetErrorMsg(errCode error) string {
if errCode == nil {
return ""
}
if errMsg, ok := ArrErrorMessage[errCode.Error()]; ok {
return errMsg
} else {
// 非预期错误转化为"系统错误"
return ArrErrorMessage[ERROR_SYSTEM]
}
}
package redis
import (
"errors"
"time"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/redigo/redis"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/ufc"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
type RedisInstance struct {
RedisPool *redis.Pool
UfcInstance ufc.UfcOperator
}
type RedisOperator interface {
InitRedisPoll()
Incr(key string) (int, error)
Expire(key string, timeout int) (int, error)
Get(key string) (string, error)
Del(key string) (int, error)
Exists(key string) (bool, error)
Set(key string, value string) (bool, error)
SetEx(key string, timeout int, value string) (bool, error)
Ttl(key string) (int, error)
}
var (
timeout = conf.GlobalConf.RedisConf.DefaultTimeoutMs
)
func (r *RedisInstance) InitRedisPoll() {
if r.UfcInstance == nil {
r.UfcInstance = &ufc.UfcInstance{}
}
r.UfcInstance.InitUfcClient()
redisConf := conf.GlobalConf.RedisConf
serviceConf := conf.GlobalConf.ServiceConf
connectTimeout := time.Duration(conf.GlobalConf.RedisConf.ConnectTimeoutMs) * time.Millisecond
readTimeout := time.Duration(conf.GlobalConf.RedisConf.ReadTimeoutMs) * time.Millisecond
writeTimeout := time.Duration(conf.GlobalConf.RedisConf.WriteTimeoutMs) * time.Millisecond
retry := 3
pool := &redis.Pool{
MaxIdle: 200,
MaxActive: 400,
IdleTimeout: time.Duration(redisConf.DefaultTimeoutMs) * time.Millisecond,
Wait: false,
}
pool.Dial = func() (redis.Conn, error) {
var address string
i := 0
for {
if i > retry {
golog.Warn("[failed to init redis pool] [ufc:%v]", redisConf.UfcName)
return nil, errors.New(conf.ERROR_GET_REDIS_ERROR)
}
logid := utils.GenerateLogId()
ip, port, err := r.UfcInstance.GetServer(serviceConf.SelfUfcName, redisConf.UfcName, logid)
if err != nil {
golog.Warn("[get bns failed] [logid:%s] [bns:%v] [err:%s]", logid, redisConf.UfcName, err.Error())
time.Sleep(120 * time.Second)
continue
}
golog.Info("【redis pool dail get ufc address] [address:%s]", ip+":"+port)
break
}
golog.Info("[redis service:%s] [address:%s] [active:%d]", redisConf.UfcName, address, pool.ActiveCount())
c, err := redis.Dial("tcp", address, redis.DialConnectTimeout(connectTimeout),
redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
if err != nil {
return nil, err
}
return c, err
}
r.RedisPool = pool
}
func (r *RedisInstance) Incr(key string) (int, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return 0, err
}
value, err := redis.Int(conn.Do("INCR", key))
if err != nil {
return 0, err
}
_, err = r.Expire(key, timeout)
if err != nil {
golog.Warn("[Incr Expire failed] [key:%s]", key)
}
return value, nil
}
func (r *RedisInstance) Expire(key string, timeout int) (int, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return 0, err
}
expire, err := redis.Int(conn.Do("EXPIRE", key, timeout))
if err == nil {
return expire, nil
}
return 0, err
}
func (r *RedisInstance) Get(key string) (string, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return "", err
}
str, err := redis.String(conn.Do("GET", key))
if err == nil {
return str, nil
}
return "", err
}
func (r *RedisInstance) Del(key string) (int, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return 0, err
}
delLen, err := redis.Int(conn.Do("DEL", key))
if err == nil {
return delLen, nil
}
return 0, err
}
func (r *RedisInstance) Exists(key string) (bool, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return false, err
}
isExists, err := redis.Int(conn.Do("EXISTS", key))
if err == nil {
return !(isExists == 0), nil
}
return false, err
}
func (r *RedisInstance) Set(key string, value string) (bool, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return false, err
}
_, err := conn.Do("SET", key, value)
if err != nil {
return false, err
}
return true, nil
}
func (r *RedisInstance) SetEx(key string, timeout int, value string) (bool, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return false, err
}
_, err := conn.Do("SETEX", key, timeout, value)
if err != nil {
return false, err
}
return true, nil
}
func (r *RedisInstance) Ttl(key string) (int, error) {
conn := r.RedisPool.Get()
defer func(conn redis.Conn) {
_ = conn.Close()
}(conn)
if err := conn.Err(); err != nil {
return -1, err
}
res, err := conn.Do("TTL", key)
if err != nil {
return -1, err
}
resInt, err := redis.Int(res, err)
if err != nil {
return -1, err
}
return resInt, nil
}
// Code generated by MockGen. DO NOT EDIT.
// Source: redis.go
// Package redis is a generated GoMock package.
package redis
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockRedisOperator is a mock of RedisOperator interface.
type MockRedisOperator struct {
ctrl *gomock.Controller
recorder *MockRedisOperatorMockRecorder
}
// MockRedisOperatorMockRecorder is the mock recorder for MockRedisOperator.
type MockRedisOperatorMockRecorder struct {
mock *MockRedisOperator
}
// NewMockRedisOperator creates a new mock instance.
func NewMockRedisOperator(ctrl *gomock.Controller) *MockRedisOperator {
mock := &MockRedisOperator{ctrl: ctrl}
mock.recorder = &MockRedisOperatorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockRedisOperator) EXPECT() *MockRedisOperatorMockRecorder {
return m.recorder
}
// Del mocks base method.
func (m *MockRedisOperator) Del(key string) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Del", key)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Del indicates an expected call of Del.
func (mr *MockRedisOperatorMockRecorder) Del(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockRedisOperator)(nil).Del), key)
}
// Exists mocks base method.
func (m *MockRedisOperator) Exists(key string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Exists", key)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Exists indicates an expected call of Exists.
func (mr *MockRedisOperatorMockRecorder) Exists(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockRedisOperator)(nil).Exists), key)
}
// Expire mocks base method.
func (m *MockRedisOperator) Expire(key string, timeout int) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Expire", key, timeout)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Expire indicates an expected call of Expire.
func (mr *MockRedisOperatorMockRecorder) Expire(key, timeout interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Expire", reflect.TypeOf((*MockRedisOperator)(nil).Expire), key, timeout)
}
// Get mocks base method.
func (m *MockRedisOperator) Get(key string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", key)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockRedisOperatorMockRecorder) Get(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRedisOperator)(nil).Get), key)
}
// Incr mocks base method.
func (m *MockRedisOperator) Incr(key string) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Incr", key)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Incr indicates an expected call of Incr.
func (mr *MockRedisOperatorMockRecorder) Incr(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Incr", reflect.TypeOf((*MockRedisOperator)(nil).Incr), key)
}
// InitRedisPoll mocks base method.
func (m *MockRedisOperator) InitRedisPoll() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "InitRedisPoll")
}
// InitRedisPoll indicates an expected call of InitRedisPoll.
func (mr *MockRedisOperatorMockRecorder) InitRedisPoll() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitRedisPoll", reflect.TypeOf((*MockRedisOperator)(nil).InitRedisPoll))
}
// Set mocks base method.
func (m *MockRedisOperator) Set(key, value string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Set", key, value)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Set indicates an expected call of Set.
func (mr *MockRedisOperatorMockRecorder) Set(key, value interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockRedisOperator)(nil).Set), key, value)
}
// SetEx mocks base method.
func (m *MockRedisOperator) SetEx(key string, timeout int, value string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetEx", key, timeout, value)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SetEx indicates an expected call of SetEx.
func (mr *MockRedisOperatorMockRecorder) SetEx(key, timeout, value interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEx", reflect.TypeOf((*MockRedisOperator)(nil).SetEx), key, timeout, value)
}
// Ttl mocks base method.
func (m *MockRedisOperator) Ttl(key string) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ttl", key)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ttl indicates an expected call of Ttl.
func (mr *MockRedisOperatorMockRecorder) Ttl(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ttl", reflect.TypeOf((*MockRedisOperator)(nil).Ttl), key)
}
package ufc
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/ufc"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
)
type UfcInstance struct {
UfcClient *ufc.UFCClient
}
type UfcOperator interface {
InitUfcClient()
GetServer(selfService string, toService string, logId string) (ip string, port string, err error)
RequestPost(url string, body map[string]interface{}, headers map[string]string) (*http.Response, error)
}
func (u *UfcInstance) InitUfcClient() {
connectTimeout := time.Duration(conf.GlobalConf.UfcConf.ConnectTimeoutMS) * time.Millisecond
readWriteTimeout := time.Duration(conf.GlobalConf.UfcConf.ReadTimeoutMs) * time.Millisecond
poolSize := conf.GlobalConf.UfcConf.PoolSize
u.UfcClient = ufc.NewUFCClient(connectTimeout, readWriteTimeout, poolSize)
}
func (u *UfcInstance) GetServer(selfService string, toService string, logId string) (ip string, port string, err error) {
var rsp map[string]string
retry := conf.GlobalConf.UfcConf.RetryNum
for i := 0; i < retry; i++ {
rsp, err = u.UfcClient.GetServer(selfService, toService, logId, "0", nil)
if err == nil {
if status, ok := rsp["status"]; ok && status == "200" {
ip = rsp["host"]
port = rsp["port"]
return ip, port, nil
}
}
}
golog.Error("[ufc get server fail] [service:%s] [logid:%s] [err:%s]", toService, logId, err)
return "", "", errors.New(conf.ERROR_5XX_UFC)
}
func (u *UfcInstance) RequestPost(url string, body map[string]interface{}, headers map[string]string) (*http.Response, error) {
client := &http.Client{}
bodyData, err := json.Marshal(body)
if err != nil {
golog.Error("[marshal failed][body:%v][err:%v]", body, err)
return nil, err
}
req, err := http.NewRequest("POST", url, strings.NewReader(fmt.Sprintf("msg=%v", string(bodyData))))
if err != nil {
golog.Error("[new request failed][body:%v][err:%v]", string(bodyData), err)
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
for k, v := range headers {
req.Header.Set(k, v)
}
return client.Do(req)
}
// Code generated by MockGen. DO NOT EDIT.
// Source: ufc.go
// Package ufc is a generated GoMock package.
package ufc
import (
http "net/http"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockUfcOperator is a mock of UfcOperator interface.
type MockUfcOperator struct {
ctrl *gomock.Controller
recorder *MockUfcOperatorMockRecorder
}
// MockUfcOperatorMockRecorder is the mock recorder for MockUfcOperator.
type MockUfcOperatorMockRecorder struct {
mock *MockUfcOperator
}
// NewMockUfcOperator creates a new mock instance.
func NewMockUfcOperator(ctrl *gomock.Controller) *MockUfcOperator {
mock := &MockUfcOperator{ctrl: ctrl}
mock.recorder = &MockUfcOperatorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUfcOperator) EXPECT() *MockUfcOperatorMockRecorder {
return m.recorder
}
// GetServer mocks base method.
func (m *MockUfcOperator) GetServer(selfService, toService, logId string) (string, string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetServer", selfService, toService, logId)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// GetServer indicates an expected call of GetServer.
func (mr *MockUfcOperatorMockRecorder) GetServer(selfService, toService, logId interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServer", reflect.TypeOf((*MockUfcOperator)(nil).GetServer), selfService, toService, logId)
}
// InitUfcClient mocks base method.
func (m *MockUfcOperator) InitUfcClient() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "InitUfcClient")
}
// InitUfcClient indicates an expected call of InitUfcClient.
func (mr *MockUfcOperatorMockRecorder) InitUfcClient() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitUfcClient", reflect.TypeOf((*MockUfcOperator)(nil).InitUfcClient))
}
// RequestPost mocks base method.
func (m *MockUfcOperator) RequestPost(url string, body map[string]interface{}, headers map[string]string) (*http.Response, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RequestPost", url, body, headers)
ret0, _ := ret[0].(*http.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RequestPost indicates an expected call of RequestPost.
func (mr *MockUfcOperatorMockRecorder) RequestPost(url, body, headers interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestPost", reflect.TypeOf((*MockUfcOperator)(nil).RequestPost), url, body, headers)
}
package main
import (
"fmt"
"time"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/framework"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/action"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/service"
)
func main() {
Init("")
service.StartReport()
StartRouter()
}
func InitLog() {
err := golog.SetFile(conf.GlobalConf.LogConf.LogFileName)
if err != nil {
panic(err)
}
golog.SetLevel(conf.GlobalConf.LogConf.LogLevel)
golog.SetbackupCount(conf.GlobalConf.LogConf.LogBackupCount)
golog.EnableRotate(time.Hour)
}
func Init(path string) {
if err := conf.InitConf(path); err != nil {
panic(err)
}
InitLog()
}
func StartRouter() {
fw := framework.New()
fw.AddRouterByQsKey("method")
fw.AddAutoRouter("/rest/2.0/vip/", &action.VipController{})
fw.Run(fmt.Sprintf(":%d", conf.GlobalConf.ServiceConf.Port))
}
//+build !test
// Code generated by MockGen. DO NOT EDIT.
// Source: base.go
// Package dao is a generated GoMock package.
package dao
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockVipTableOperator is a mock of VipTableOperator interface.
type MockVipTableOperator struct {
ctrl *gomock.Controller
recorder *MockVipTableOperatorMockRecorder
}
// MockVipTableOperatorMockRecorder is the mock recorder for MockVipTableOperator.
type MockVipTableOperatorMockRecorder struct {
mock *MockVipTableOperator
}
// NewMockVipTableOperator creates a new mock instance.
func NewMockVipTableOperator(ctrl *gomock.Controller) *MockVipTableOperator {
mock := &MockVipTableOperator{ctrl: ctrl}
mock.recorder = &MockVipTableOperatorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockVipTableOperator) EXPECT() *MockVipTableOperatorMockRecorder {
return m.recorder
}
// GetVipInfo mocks base method.
func (m *MockVipTableOperator) GetVipInfo(userId uint64) (*VipInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetVipInfo", userId)
ret0, _ := ret[0].(*VipInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetVipInfo indicates an expected call of GetVipInfo.
func (mr *MockVipTableOperatorMockRecorder) GetVipInfo(userId interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVipInfo", reflect.TypeOf((*MockVipTableOperator)(nil).GetVipInfo), userId)
}
// InitTable mocks base method.
func (m *MockVipTableOperator) InitTable() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InitTable")
ret0, _ := ret[0].(error)
return ret0
}
// InitTable indicates an expected call of InitTable.
func (mr *MockVipTableOperatorMockRecorder) InitTable() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitTable", reflect.TypeOf((*MockVipTableOperator)(nil).InitTable))
}
// InsertVipInfo mocks base method.
func (m *MockVipTableOperator) InsertVipInfo(info *VipInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InsertVipInfo", info)
ret0, _ := ret[0].(error)
return ret0
}
// InsertVipInfo indicates an expected call of InsertVipInfo.
func (mr *MockVipTableOperatorMockRecorder) InsertVipInfo(info interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertVipInfo", reflect.TypeOf((*MockVipTableOperator)(nil).InsertVipInfo), info)
}
// UpdateVipInfo mocks base method.
func (m *MockVipTableOperator) UpdateVipInfo(info *VipInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateVipInfo", info)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateVipInfo indicates an expected call of UpdateVipInfo.
func (mr *MockVipTableOperatorMockRecorder) UpdateVipInfo(info interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateVipInfo", reflect.TypeOf((*MockVipTableOperator)(nil).UpdateVipInfo), info)
}
package dao
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/ufc"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
type VipInfoTableView struct {
Ctx *utils.Context
DB *sql.DB
UfcInstance ufc.UfcOperator
}
func (v *VipInfoTableView) InitTable() (err error) {
if v.UfcInstance == nil {
v.UfcInstance = &ufc.UfcInstance{}
}
v.UfcInstance.InitUfcClient()
var ip, port string
var db *sql.DB
dbConf := conf.GlobalConf.DBConf
for i := 0; i < dbConf.RetryNum; i++ {
ip, port, err = v.UfcInstance.GetServer("", dbConf.UfcName, v.Ctx.LogId)
if err != nil {
v.Ctx.L.Warn("[failed to get server by ufc] [ufc:%v]", dbConf.UfcName)
continue
}
host := fmt.Sprintf("%v:%v@tcp(%v:%v)", dbConf.UserName, dbConf.Password, ip, port)
dbSourceName := fmt.Sprintf("%v/%v?charset=utf8&readTimeout=%vs&writeTimeout=%vs",
host, dbConf.DatabaseName, dbConf.ReadTimeoutMs, dbConf.WriteTimeoutMs)
db, err = sql.Open("mysql", dbSourceName)
if err = db.Ping(); err != nil {
v.Ctx.L.Warn("[failed to connect to db] [source:%v]", dbSourceName)
continue
}
v.DB = db
break
}
return
}
func (v *VipInfoTableView) InsertVipInfo(info *VipInfo) error {
stmt, err := v.DB.Prepare("insert into vip_info (user_id, experiences, init_time,start_time,end_time," +
"vip_level,vip_type,extent_string1,extent_int1) values (?,?,?,?,?,?,?,?,?)")
if err != nil {
v.Ctx.L.Warn("[failed to prepare stmt] [err:%v]", err)
return err
}
defer func(stmt *sql.Stmt) {
_ = stmt.Close()
}(stmt)
_, err = stmt.Exec(info.UserId, info.Experiences, info.InitTime, info.StartTime, info.EndTime,
info.VipLevel, info.VipType, info.ExtentString1, info.ExtentInt1)
if err != nil {
v.Ctx.L.Warn("[failed to insert vip info] [err:%v]", err)
return err
}
return nil
}
func (v *VipInfoTableView) UpdateVipInfo(info *VipInfo) error {
stmt, err := v.DB.Prepare("update vip_info set experiences=?,end_time=?,vip_level=?,vip_type=? where user_id=?")
if err != nil {
v.Ctx.L.Warn("[failed to prepare stmt] [err:%v]", err)
return err
}
defer func(stmt *sql.Stmt) {
_ = stmt.Close()
}(stmt)
_, err = stmt.Exec(info.Experiences, info.EndTime, info.VipLevel, info.VipType, info.UserId)
if err != nil {
v.Ctx.L.Warn("[failed to update vip info] [err:%v]", err)
return err
}
return nil
}
func (v *VipInfoTableView) GetVipInfo(userId uint64) (*VipInfo, error) {
info := &VipInfo{}
stmt, err := v.DB.Prepare("select user_id,experiences,init_time,start_time,end_time,vip_level," +
"vip_type,extent_string1,extent_int1 from vip_info where user_id=?")
if err != nil {
v.Ctx.L.Warn("[failed to prepare stmt] [err:%v]", err)
return nil, err
}
defer func(stmt *sql.Stmt) {
_ = stmt.Close()
}(stmt)
row := stmt.QueryRow(userId)
err = row.Scan(&info.UserId, &info.Experiences, &info.InitTime, &info.StartTime, &info.EndTime,
&info.VipLevel, &info.VipType, &info.ExtentString1, &info.ExtentInt1)
if err != nil {
v.Ctx.L.Warn("[failed to scan rows] [err:%v]", err)
return nil, err
}
return info, nil
}
package service
import (
"encoding/json"
"fmt"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/dao"
)
const KeyPrefix = "vip-info"
func (v *VipService) SetVipToRedis(info *dao.VipInfo) error {
infoByte, err := json.Marshal(info)
if err != nil {
v.Ctx.L.Warn("[failed to marshal vip info] [err:%v]", err)
return err
}
userIdStr := v.generateKey(info.UserId)
_, err = v.RedisInstance.Set(userIdStr, string(infoByte))
if err != nil {
v.Ctx.L.Warn("[failed to set vip info to redis] [err:%v]", err)
return err
}
return nil
}
func (v *VipService) GetVipFromRedis(userId uint64) (*dao.VipInfo, error) {
userIdStr := v.generateKey(userId)
infoStr, err := v.RedisInstance.Get(userIdStr)
if err != nil {
v.Ctx.L.Warn("[failed to get vip info from redis] [err:%v]", err)
return nil, err
}
info := &dao.VipInfo{}
err = json.Unmarshal([]byte(infoStr), info)
if err != nil {
v.Ctx.L.Warn("[failed to unmarshal vip info] [err:%v]", err)
return nil, err
}
return info, nil
}
func (v *VipService) DeleteVipFromRedis(userId uint64) error {
userIdStr := v.generateKey(userId)
_, err := v.RedisInstance.Del(userIdStr)
if err != nil {
v.Ctx.L.Warn("[failed to delete vip info from redis] [err:%v]", err)
return err
}
return nil
}
func (v *VipService) CheckVipFromRedis(userId uint64) (bool, error) {
userIdStr := v.generateKey(userId)
isExists, err := v.RedisInstance.Exists(userIdStr)
if err != nil {
v.Ctx.L.Warn("[failed to delete vip info from redis] [err:%v]", err)
return false, err
}
return isExists, nil
}
func (v *VipService) generateKey(userId uint64) string {
return fmt.Sprintf("%v-%v-%v", conf.GlobalConf.RedisConf.KeyPrefix, KeyPrefix, userId)
}
package service
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/redis"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/ufc"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
type ReportService struct {
RedisInstance redis.RedisOperator
UfcInstance ufc.UfcOperator
}
var RedisConf = conf.GlobalConf.RedisConf
var ReportConf = conf.GlobalConf.ReportConf
var SelfName = conf.GlobalConf.ServiceConf.SelfUfcName
var ReportName = conf.GlobalConf.ReportConf.UfcName
func StartReport() {
reportService := &ReportService{}
reportService.InitReport()
go func() {
var err error
frequency := conf.GlobalConf.ReportConf.FrequencyPerHour
interval := time.Hour / time.Duration(frequency)
ticker := time.NewTicker(interval)
defer ticker.Stop()
// 出错仅进行记录
for range ticker.C {
err = reportService.SendReport()
if err != nil {
golog.Warn("[send report failed] [frequency:%v] [err:%v]", frequency, err)
}
}
}()
}
func (r *ReportService) InitReport() {
if r.RedisInstance == nil {
r.RedisInstance = &redis.RedisInstance{}
}
r.RedisInstance.InitRedisPoll()
if r.UfcInstance == nil {
r.UfcInstance = &ufc.UfcInstance{}
}
r.UfcInstance.InitUfcClient()
}
func (r *ReportService) SendReport() error {
var err error
logId := utils.GenerateLogId()
send := func() (*http.Response, error) {
defaultIp, defaultPort, err := r.UfcInstance.GetServer(SelfName, ReportName, logId)
if err != nil {
golog.Warn("[get server failed] [service:%v] [logid:%v] [err:%v]", ReportName, logId, err)
return nil, err
}
addNum, err := r.GetRecord(conf.VipAdd)
if err != nil {
golog.Warn("[get add num failed] [service:%v] [logid:%v] [err:%v]", ReportName, logId, err)
return nil, err
}
updateNum, err := r.GetRecord(conf.VipUpdate)
if err != nil {
golog.Warn("[get update num failed] [service:%v] [logid:%v] [err:%v]", ReportName, logId, err)
return nil, err
}
queryNum, err := r.GetRecord(conf.VipInfo)
if err != nil {
golog.Warn("[get query num failed] [service:%v] [logid:%v] [err:%v]", ReportName, logId, err)
return nil, err
}
host := defaultIp + ":" + defaultPort
uri := fmt.Sprintf("http://%v/rest/2.0/stat/request", host)
return r.UfcInstance.RequestPost(uri, map[string]interface{}{
"add": addNum,
"update": updateNum,
"query": queryNum,
}, nil)
}
for i := 0; i < 3; i++ {
resp, err := send()
if err != nil {
golog.Warn("[send failed] [count:%v] [logid:%v] [err:%v]", i, logId, err)
continue
}
response, err := ioutil.ReadAll(resp.Body)
if err != nil {
golog.Warn("[read all failed] [count:%v] [logid:%v] [err:%v]", i, logId, err)
continue
}
resultMap := make(map[string]interface{})
err = json.Unmarshal(response, &resultMap)
if err != nil {
golog.Warn("[read all failed] [count:%v] [logid:%v] [err:%v]", i, logId, err)
continue
}
// 如果report正常则返回
if errCode, ok := resultMap[conf.ErrCode].(float64); ok && errCode == 0 {
// 清理记录出错直接返回
err = r.ClearRecord()
if err != nil {
golog.Warn("[clear record failed] [count:%v] [logid:%v] [err:%v]", i, logId, err)
return err
}
return nil
}
// report失败,记录response
golog.Error("[report failed] [count:%v] [logid:%v] [response:%v]", i, logId, resultMap)
}
return err
}
func (r *ReportService) ClearRecord() error {
var err error
keyAdd := fmt.Sprintf("%v-%v-%v", RedisConf.KeyPrefix, ReportConf.RedisKeyPrefix, conf.VipAdd)
keyUpdate := fmt.Sprintf("%v-%v-%v", RedisConf.KeyPrefix, ReportConf.RedisKeyPrefix, conf.VipUpdate)
keyInfo := fmt.Sprintf("%v-%v-%v", RedisConf.KeyPrefix, ReportConf.RedisKeyPrefix, conf.VipInfo)
emptyValue := "0"
_, err = r.RedisInstance.Set(keyAdd, emptyValue)
if err != nil {
golog.Warn("[failed to set redis] [key:%s] [err:%v]", keyAdd, err)
return err
}
_, err = r.RedisInstance.Set(keyUpdate, emptyValue)
if err != nil {
golog.Warn("[failed to set redis] [key:%s] [err:%v]", keyUpdate, err)
return err
}
_, err = r.RedisInstance.Set(keyInfo, emptyValue)
if err != nil {
golog.Warn("[failed to set redis] [key:%s] [err:%v]", keyInfo, err)
return err
}
return nil
}
func (r *ReportService) GetRecord(apiName string) (string, error) {
key := fmt.Sprintf("%v-%v-%v", RedisConf.KeyPrefix, ReportConf.RedisKeyPrefix, apiName)
count, err := r.RedisInstance.Get(key)
if err != nil {
golog.Warn("[failed to get redis] [key:%s] [err:%v]", key, err)
return "", err
}
return count, nil
}
package service
import (
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/lib/redis"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/dao"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
type VipOperator interface {
InitVip() (err error)
AddVip(param *VipAddParam) error
GetVip(userId uint64) (*dao.VipInfo, error)
UpdateVip(param *VipUpdateParam) error
}
type VipService struct {
Ctx *utils.Context
View dao.VipTableOperator
RedisInstance redis.RedisOperator
}
type VipAddParam struct {
UserId uint64
InitTime int
EndTime int
VipLevel int
VipType string
}
type VipUpdateParam struct {
UserId uint64
Experience int
EndTime int
VipLevel int
VipType string
}
func (v *VipService) InitVip() (err error) {
if v.View == nil {
v.View = &dao.VipInfoTableView{Ctx: v.Ctx}
}
if err = v.View.InitTable(); err != nil {
v.Ctx.L.Warn("[failed to new vip info table view] [err:%v]", err)
}
if v.RedisInstance == nil {
v.RedisInstance = &redis.RedisInstance{}
}
v.RedisInstance.InitRedisPoll()
return
}
func (v *VipService) AddVip(param *VipAddParam) error {
// 根据表设计,insert时缓存中不存在数据,insert后将info插入缓存
info := &dao.VipInfo{
UserId: param.UserId,
InitTime: param.InitTime,
StartTime: param.InitTime,
EndTime: param.EndTime,
VipLevel: param.VipLevel,
VipType: param.VipType,
}
err := v.View.InsertVipInfo(info)
if err != nil {
v.Ctx.L.Warn("[failed to insert vip info] [err:%v]", err)
return err
}
err = v.SetVipToRedis(info)
if err != nil {
v.Ctx.L.Warn("[failed to set vip into redis] [err:%v]", err)
return err
}
return nil
}
func (v *VipService) GetVip(userId uint64) (*dao.VipInfo, error) {
isExist, err := v.CheckVipFromRedis(userId)
if err != nil {
v.Ctx.L.Warn("[failed to check vip from redis] [err:%v]", err)
return nil, err
}
// 如果缓存中存在,则使用缓存中的数据
if isExist {
info, err := v.GetVipFromRedis(userId)
if err != nil {
v.Ctx.L.Warn("[failed to get vip from redis] [err:%v]", err)
return nil, err
}
return info, nil
}
// 缓存中不存在,从db获取并更新缓存
info, err := v.View.GetVipInfo(userId)
if err != nil {
v.Ctx.L.Warn("[failed to insert vip info] [err:%v]", err)
return nil, err
}
err = v.SetVipToRedis(info)
if err != nil {
v.Ctx.L.Warn("[failed to set vip to redis] [err:%v]", err)
return nil, err
}
return info, nil
}
func (v *VipService) UpdateVip(param *VipUpdateParam) error {
// 更新数据库并删除缓存
err := v.View.UpdateVipInfo(&dao.VipInfo{
UserId: param.UserId,
Experiences: param.Experience,
EndTime: param.EndTime,
VipLevel: param.VipLevel,
VipType: param.VipType,
})
if err != nil {
v.Ctx.L.Warn("[failed to update vip info] [err:%v]", err)
return err
}
err = v.DeleteVipFromRedis(param.UserId)
if err != nil {
v.Ctx.L.Warn("[failed to delete vip info from redis] [err:%v]", err)
return err
}
return nil
}
//+build !test
// Code generated by MockGen. DO NOT EDIT.
// Source: vip.go
// Package service is a generated GoMock package.
package service
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
dao "icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/dao"
)
// MockVipOperator is a mock of VipOperator interface.
type MockVipOperator struct {
ctrl *gomock.Controller
recorder *MockVipOperatorMockRecorder
}
// MockVipOperatorMockRecorder is the mock recorder for MockVipOperator.
type MockVipOperatorMockRecorder struct {
mock *MockVipOperator
}
// NewMockVipOperator creates a new mock instance.
func NewMockVipOperator(ctrl *gomock.Controller) *MockVipOperator {
mock := &MockVipOperator{ctrl: ctrl}
mock.recorder = &MockVipOperatorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockVipOperator) EXPECT() *MockVipOperatorMockRecorder {
return m.recorder
}
// AddVip mocks base method.
func (m *MockVipOperator) AddVip(param *VipAddParam) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddVip", param)
ret0, _ := ret[0].(error)
return ret0
}
// AddVip indicates an expected call of AddVip.
func (mr *MockVipOperatorMockRecorder) AddVip(param interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddVip", reflect.TypeOf((*MockVipOperator)(nil).AddVip), param)
}
// GetVip mocks base method.
func (m *MockVipOperator) GetVip(userId uint64) (*dao.VipInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetVip", userId)
ret0, _ := ret[0].(*dao.VipInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetVip indicates an expected call of GetVip.
func (mr *MockVipOperatorMockRecorder) GetVip(userId interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVip", reflect.TypeOf((*MockVipOperator)(nil).GetVip), userId)
}
// InitVip mocks base method.
func (m *MockVipOperator) InitVip() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InitVip")
ret0, _ := ret[0].(error)
return ret0
}
// InitVip indicates an expected call of InitVip.
func (mr *MockVipOperatorMockRecorder) InitVip() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitVip", reflect.TypeOf((*MockVipOperator)(nil).InitVip))
}
// UpdateVip mocks base method.
func (m *MockVipOperator) UpdateVip(param *VipUpdateParam) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateVip", param)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateVip indicates an expected call of UpdateVip.
func (mr *MockVipOperatorMockRecorder) UpdateVip(param interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateVip", reflect.TypeOf((*MockVipOperator)(nil).UpdateVip), param)
}
package request
import (
"errors"
"strconv"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/utils"
)
type Request struct {
Ctx *utils.Context
UserId uint64 `json:"user_id"`
}
func (r *Request) Valid() error {
var ok bool
r.UserId, ok = QueryUint64(r.Ctx, "user_id")
if !ok {
r.Ctx.L.Warn("[user_id is null]")
return errors.New(conf.ERROR_PARAM_ERROR)
}
return nil
}
func query(ctx *utils.Context, key string) string {
if ctx == nil {
panic("request context not init")
}
return utils.Trim(ctx.Input.Query(key))
}
func QueryInt(ctx *utils.Context, key string) (res int, ok bool) {
value := query(ctx, key)
if len(value) == 0 {
return 0, false
}
res, _ = strconv.Atoi(value)
return res, true
}
func QueryUint64(ctx *utils.Context, key string) (res uint64, ok bool) {
value := query(ctx, key)
if len(value) == 0 {
return uint64(0), false
}
res, _ = strconv.ParseUint(value, 10, 64)
return res, true
}
func QueryString(ctx *utils.Context, key string) (res string, ok bool) {
res = query(ctx, key)
if len(res) == 0 {
return "", false
}
return res, true
}
package request
import (
"errors"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
)
type VipAddRequest struct {
Request
InitTime int
EndTime int
VipLevel int
VipType string
}
func (a *VipAddRequest) Valid() error {
var ok bool
if err := a.Request.Valid(); err != nil {
a.Ctx.L.Warn("[failed to valid request] [err:%v]", err)
return err
}
a.InitTime, ok = QueryInt(a.Ctx, "init_time")
if !ok || a.InitTime <= 0 {
a.Ctx.L.Warn("[init_time is not valid] [init_time:%v]", a.InitTime)
return errors.New(conf.ERROR_PARAM_ERROR)
}
a.EndTime, ok = QueryInt(a.Ctx, "end_time")
if !ok || a.EndTime <= 0 {
a.Ctx.L.Warn("[end_time is not valid] [end_time:%v]", a.EndTime)
return errors.New(conf.ERROR_PARAM_ERROR)
}
if a.EndTime <= a.InitTime {
a.Ctx.L.Warn("[end_time is not greater than init_time] [init_time:%v] [end_time:%v]", a.InitTime, a.EndTime)
return errors.New(conf.ERROR_PARAM_ERROR)
}
a.VipLevel, ok = QueryInt(a.Ctx, "vip_level")
if !ok || a.VipLevel <= 0 {
a.Ctx.L.Warn("[vip_level is not valid] [vip_level:%v]", a.VipLevel)
return errors.New(conf.ERROR_PARAM_ERROR)
}
a.VipType, ok = QueryString(a.Ctx, "vip_type")
if !ok || (a.VipType != "vip" && a.VipType != "super vip") {
a.Ctx.L.Warn("[vip_type is not valid] [vip_type:%v]", a.VipType)
return errors.New(conf.ERROR_PARAM_ERROR)
}
return nil
}
package request
type VipInfoRequest struct {
Request
}
func (i *VipInfoRequest) Valid() error {
if err := i.Request.Valid(); err != nil {
i.Ctx.L.Warn("[failed to valid request] [err:%v]", err)
return err
}
return nil
}
package request
import (
"errors"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
)
type VipUpdateRequest struct {
Request
Experiences int
EndTime int
VipLevel int
VipType string
}
func (u *VipUpdateRequest) Valid() error {
if err := u.Request.Valid(); err != nil {
return err
}
var ok bool
u.Experiences, ok = QueryInt(u.Ctx, "experience")
if !ok || u.Experiences <= 0 {
u.Ctx.L.Warn("[experience is not valid] [experience:%v]", u.Experiences)
return errors.New(conf.ERROR_PARAM_ERROR)
}
u.EndTime, ok = QueryInt(u.Ctx, "end_time")
if !ok || u.EndTime <= 0 {
u.Ctx.L.Warn("[end_time is not valid] [end_time:%v]", u.EndTime)
return errors.New(conf.ERROR_PARAM_ERROR)
}
u.VipLevel, ok = QueryInt(u.Ctx, "vip_level")
if !ok || u.VipLevel <= 0 {
u.Ctx.L.Warn("[vip_level is not valid] [vip_level:%v]", u.VipLevel)
return errors.New(conf.ERROR_PARAM_ERROR)
}
u.VipType, ok = QueryString(u.Ctx, "vip_type")
if !ok || (u.VipType != "vip" && u.VipType != "super vip") {
u.Ctx.L.Warn("[vip_type is not valid] [vip_type:%v]", u.VipType)
return errors.New(conf.ERROR_PARAM_ERROR)
}
return nil
}
package response
type VipAddResponse struct {
Response
}
func (r *VipAddResponse) Format() error {
return nil
}
package response
import "icode.baidu.com/baidu/goodcoder/chenjingqiao-go/models/dao"
type VipInfoResponse struct {
Response
}
func (r *VipInfoResponse) Format(info *dao.VipInfo) (interface{}, error) {
return info, nil
}
package response
type VipUpdateResponse struct {
Response
}
func (r *VipUpdateResponse) Format() error {
return nil
}
package utils
import (
"math/rand"
"strconv"
"sync"
"time"
"github.com/golang-collections/collections/stack"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/framework"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/golog"
"icode.baidu.com/baidu/netdisk/pcs-go-lib/isis"
)
type Context struct {
L *golog.Logger
Isis *isis.Isis
Input *framework.FwInput
Output *framework.FwOutput
DealErr error
UserId uint64
AppId int
CallId string
LogId string
Session map[string]interface{}
Callers *stack.Stack
costOpenClose bool
sync.RWMutex
}
func GenerateLogId() string {
now := time.Now()
firstDay := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.Local)
sec := now.Unix() - firstDay.Unix()
offset := sec * 1000
r := rand.New(rand.NewSource(time.Now().UnixNano()))
logid := offset<<28 + int64(r.Intn(134217727))
return strconv.FormatInt(logid, 10)
}
package utils
import (
"encoding/json"
"errors"
"strings"
"icode.baidu.com/baidu/goodcoder/chenjingqiao-go/conf"
)
func V(item map[string]interface{}, keys ...string) (value interface{}) {
defer func() {
if r := recover(); r != nil {
panic(errors.New(conf.ERROR_CONF_INVALID))
}
}()
if len(keys) == 0 {
return item
}
rootKey := keys[0]
if rootIns, ok := (item[rootKey]).(map[string]interface{}); ok {
if len(keys) > 1 {
otherKeys := keys[1:]
return V(rootIns, otherKeys...)
}
}
value = item[rootKey]
return
}
func Int(item interface{}, keys ...string) int {
if itemMI, ok := item.(map[string]interface{}); ok {
r := V(itemMI, keys...)
if rI, ok := r.(int); ok {
return rI
} else if rM, ok := r.(map[string]int); ok {
if len(keys) > 0 {
//fixme: no exist retrun 0, not -1
return rM[keys[len(keys)-1]]
}
}
return -1
} else if itemInt, ok := item.(int); ok {
return itemInt
}
return -1
}
func String(item interface{}, keys ...string) string {
if itemMI, ok := item.(map[string]interface{}); ok {
r := V(itemMI, keys...)
if rS, ok := r.(string); ok {
return rS
} else if rM, ok := r.(map[string]string); ok {
if len(keys) > 0 {
return rM[keys[len(keys)-1]]
}
}
return ""
} else if itemB, ok := item.(string); ok {
return itemB
}
return ""
}
func JsonEncodeWithoutError(v interface{}) (res []byte) {
tmp, err := json.Marshal(v)
if err == nil {
res = tmp
}
return
}
func Trim(str string, characterMask ...string) string {
mask := ""
if len(characterMask) == 0 {
return strings.TrimSpace(str)
}
mask = characterMask[0]
return strings.Trim(str, mask)
}