Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"local_equip_test.go",
"memcache_test.go",
"mysql_test.go",
"pay_test.go",
"redis_test.go",
"vip_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/usersuit/conf:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"local_equip.go",
"memcache.go",
"mysql.go",
"pay.go",
"redis.go",
"vip.go",
],
importpath = "go-common/app/service/main/usersuit/dao/pendant",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/usersuit/conf:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/bluele/gcache:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,79 @@
package pendant
import (
"context"
"time"
"go-common/app/service/main/usersuit/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"github.com/bluele/gcache"
)
const (
_info = "/internal/v1/user/"
)
// Dao struct info of Dao.
type Dao struct {
db *sql.DB
c *conf.Config
client *bm.Client
// redis
redis *redis.Pool
pendantExpire int32
// memcache
mc *memcache.Pool
pointExpire int32
vipInfoURL string
payURL string
notifyURL string
// equipStore
equipStore gcache.Cache
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.MySQL),
client: bm.NewClient(c.HTTPClient),
// redis
redis: redis.NewPool(c.Redis.Config),
pendantExpire: int32(time.Duration(c.Redis.PendantExpire) / time.Second),
// memcache
mc: memcache.NewPool(c.Memcache.Config),
pointExpire: int32(time.Duration(c.Memcache.PointExpire) / time.Second),
vipInfoURL: c.VipURI + _info,
payURL: c.PayURL,
notifyURL: c.NotifyURL,
equipStore: gcache.New(c.EquipCache.Size).LFU().Build(),
}
return
}
// Ping ping health.
func (d *Dao) Ping(c context.Context) (err error) {
return d.pingRedis(c)
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.redis != nil {
d.redis.Close()
}
if d.db != nil {
d.db.Close()
}
}
func (d *Dao) pingRedis(c context.Context) (err error) {
conn := d.redis.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}

View File

@@ -0,0 +1,48 @@
package pendant
import (
"context"
"flag"
"os"
"strings"
"testing"
"go-common/app/service/main/usersuit/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
c = context.Background()
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.usersuit-service")
flag.Set("conf_token", "BVWgBtBvS2pkTBbmxAl0frX6KRA14d5P")
flag.Set("tree_id", "6813")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/convey-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.client.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,85 @@
package pendant
import (
"context"
"time"
"go-common/app/service/main/usersuit/model"
"go-common/library/log"
"go-common/library/stat/prom"
"github.com/bluele/gcache"
"github.com/pkg/errors"
)
func (d *Dao) loadEquip(c context.Context, mid int64) (*model.PendantEquip, error) {
equip, err := d.equipCache(c, mid)
if err != nil {
return nil, err
}
d.storeEquip(mid, equip)
return equip, nil
}
func (d *Dao) storeEquip(mid int64, equip *model.PendantEquip) {
if equip == nil {
return
}
d.equipStore.SetWithExpire(mid, equip, time.Duration(d.c.EquipCache.Expire))
}
func (d *Dao) localEquip(mid int64) (*model.PendantEquip, error) {
prom.CacheHit.Incr("local_equip_cache")
item, err := d.equipStore.Get(mid)
if err != nil {
prom.CacheMiss.Incr("local_equip_cache")
return nil, err
}
equip, ok := item.(*model.PendantEquip)
if !ok {
prom.CacheMiss.Incr("local_equip_cache")
return nil, errors.New("Not a equip")
}
return equip, nil
}
// EquipCache get equip cache.
func (d *Dao) EquipCache(c context.Context, mid int64) (*model.PendantEquip, error) {
equip, err := d.localEquip(mid)
if err != nil {
if err != gcache.KeyNotFoundError {
log.Error("Failed to get equip from local: mid: %d: %+v", mid, err)
}
return d.loadEquip(c, mid)
}
return equip, nil
}
// EquipsCache get multi equip cache.
func (d *Dao) EquipsCache(c context.Context, mids []int64) (map[int64]*model.PendantEquip, []int64, error) {
equips := make(map[int64]*model.PendantEquip, len(mids))
lcMissed := make([]int64, 0, len(mids))
for _, mid := range mids {
equip, err := d.localEquip(mid)
if err != nil {
if err != gcache.KeyNotFoundError {
log.Error("Failed to get equip from local: mid: %d: %+v", mid, err)
}
lcMissed = append(lcMissed, mid)
continue
}
equips[equip.Mid] = equip
}
if len(lcMissed) == 0 {
return equips, nil, nil
}
rdsEquips, rdsMissed, err := d.equipsCache(c, lcMissed)
if err != nil {
return nil, nil, err
}
for _, equip := range rdsEquips {
d.storeEquip(equip.Mid, equip)
equips[equip.Mid] = equip
}
return equips, rdsMissed, nil
}

View File

@@ -0,0 +1,88 @@
package pendant
import (
"go-common/app/service/main/usersuit/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestPendantloadEquip(t *testing.T) {
convey.Convey("loadEquip", t, func(ctx convey.C) {
var (
mid = int64(650454)
info = &model.PendantEquip{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.AddEquipCache(c, mid, info)
p1, err := d.loadEquip(c, mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantstoreEquip(t *testing.T) {
convey.Convey("storeEquip", t, func(ctx convey.C) {
var (
mid = int64(650454)
equip = &model.PendantEquip{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.storeEquip(mid, equip)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestPendantlocalEquip(t *testing.T) {
convey.Convey("localEquip", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.localEquip(mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantEquipCache(t *testing.T) {
convey.Convey("EquipCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.EquipCache(c, mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantEquipsCache(t *testing.T) {
convey.Convey("EquipsCache", t, func(ctx convey.C) {
var (
mids = []int64{650454, 1}
info = &model.PendantEquip{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.AddEquipCache(c, int64(650454), info)
d.AddEquipCache(c, int64(1), info)
p1, p2, err := d.EquipsCache(c, mids)
ctx.Convey("Then err should be nil.p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,54 @@
package pendant
import (
"context"
"fmt"
gmc "go-common/library/cache/memcache"
)
const (
_prefixRedPointFlag = "r_p_f_%d"
)
func redPointFlagKey(mid int64) string {
return fmt.Sprintf(_prefixRedPointFlag, mid)
}
// RedPointCache get new pendant info red point cache.
func (d *Dao) RedPointCache(c context.Context, mid int64) (pid int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(redPointFlagKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
err = nil
}
return
}
err = conn.Scan(item, &pid)
return
}
// SetRedPointCache set red point cache.
func (d *Dao) SetRedPointCache(c context.Context, mid, pid int64) (err error) {
var (
item = &gmc.Item{Key: redPointFlagKey(mid), Object: pid, Expiration: d.pointExpire, Flags: gmc.FlagJSON}
conn = d.mc.Get(c)
)
defer conn.Close()
err = conn.Set(item)
return
}
// DelRedPointCache delete new pendant info red point cache.
func (d *Dao) DelRedPointCache(c context.Context, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(redPointFlagKey(mid)); err != nil {
if err == gmc.ErrNotFound {
err = nil
}
}
return
}

View File

@@ -0,0 +1,69 @@
package pendant
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestPendantredPointFlagKey(t *testing.T) {
convey.Convey("redPointFlagKey", t, func(ctx convey.C) {
var (
mid = int64(123)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := redPointFlagKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantRedPointCache(t *testing.T) {
convey.Convey("RedPointCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(123)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
pid, err := d.RedPointCache(c, mid)
ctx.Convey("Then err should be nil.pid should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(pid, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantSetRedPointCache(t *testing.T) {
convey.Convey("SetRedPointCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(123)
pid = int64(10)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetRedPointCache(c, mid, pid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantDelRedPointCache(t *testing.T) {
convey.Convey("DelRedPointCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(123)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelRedPointCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,515 @@
package pendant
import (
"bytes"
"context"
"database/sql"
"fmt"
"time"
"go-common/app/service/main/usersuit/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_getGroupOnlineSQL = "SELECT id,name,rank,status,image,image_model,frequency_limit,time_limit FROM pendant_group WHERE status = 1 or id in (30,31) ORDER BY rank"
_getGroupByIDSQL = "SELECT id,name,rank,status,image,image_model,frequency_limit,time_limit FROM pendant_group where id = ?"
_selGIDRefPIDSQL = "SELECT gid,pid FROM pendant_group_ref"
_getPendantInfoSQL = "SELECT id,name,image,image_model,status FROM pendant_info"
_getPendantInfoByIDSQL = "SELECT id,name,image,image_model,status FROM pendant_info where id = ? limit 1"
_getPendantInfosSQL = "SELECT id,name,image,image_model,status,rank FROM pendant_info ORDER BY rank"
_getPendantPriceSQL = "SELECT pid,type,price FROM pendant_price where pid = ? "
_getOrderHistorySQL = "SELECT mid,order_id,pay_id,appid,status,pid,time_length,cost,buy_time,is_callback,callback_time,pay_type FROM user_pendant_order WHERE %s"
_getUserPackageSQL = "SELECT mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? AND pid = ? "
_getUserPackageByMidSQL = "SELECT mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? AND expires >= ? AND status > 0 ORDER BY mtime DESC"
_countOrderHistorySQL = "SELECT count(1) FROM user_pendant_order WHERE %s"
_getPendantEquipByMidSQL = "SELECT mid,pid,expires FROM user_pendant_equip WHERE mid = ? and expires >= ?"
_getPendantEquipByMidsSQL = "SELECT mid,pid,expires FROM user_pendant_equip WHERE mid IN (%s) and expires >= ?"
_insertPendantPackageSQL = "INSERT INTO user_pendant_pkg(mid,pid,expires,type,status,is_vip) VALUES (?,?,?,?,?,?)"
_insertOrderHistory = "INSERT INTO user_pendant_order(mid,order_id,pay_id,appid,status,pid,time_length,cost,buy_time,is_callback,callback_time,pay_type) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)"
_insertOperationSQL = "INSERT INTO pendant_grant_history(mid,pid,source_type,operator_name,operator_action) VALUES (?,?,?,?,?)"
_insertEquipSQL = "INSERT INTO user_pendant_equip(mid,pid,expires) VALUES (?,?,?) ON DUPLICATE KEY UPDATE pid=VALUES(pid),expires=VALUES(expires)"
_updatePackageSQL = "UPDATE user_pendant_pkg %s WHERE mid=? AND pid=?"
_updatePackageExpireSQL = "UPDATE user_pendant_pkg SET status=0 WHERE mid=? AND expires<?"
_updateOrderInfoSQL = "UPDATE user_pendant_order SET status=?,pay_id=?,is_callback=?,callback_time=? WHERE order_id=?"
_updateEquipMIDSQL = "UPDATE user_pendant_equip SET pid=0,expires=0 WHERE mid=?"
)
//PendantGroupInfo return all group info
func (d *Dao) PendantGroupInfo(c context.Context) (res []*model.PendantGroupInfo, err error) {
var row *xsql.Rows
res = make([]*model.PendantGroupInfo, 0)
if row, err = d.db.Query(c, _getGroupOnlineSQL); err != nil {
log.Error("PendantGroupInfo query error %v", err)
return
}
defer row.Close()
for row.Next() {
info := new(model.PendantGroupInfo)
if err = row.Scan(&info.ID, &info.Name, &info.Rank, &info.Status, &info.Image, &info.ImageModel, &info.FrequencyLimit, &info.TimeLimit); err != nil {
log.Error("PendantGroupInfo scan error %v", err)
return
}
res = append(res, info)
}
return
}
// GroupByID return group info by id
func (d *Dao) GroupByID(c context.Context, gid int64) (res *model.PendantGroupInfo, err error) {
var row *xsql.Row
res = new(model.PendantGroupInfo)
row = d.db.QueryRow(c, _getGroupByIDSQL, gid)
if err = row.Scan(&res.ID, &res.Name, &res.Rank, &res.Status, &res.Image, &res.ImageModel, &res.FrequencyLimit, &res.TimeLimit); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
log.Error("PendantGroupInfo scan error %v", err)
return
}
return
}
// GIDRefPID gid relation of pid .
func (d *Dao) GIDRefPID(c context.Context) (gidMap map[int64][]int64, pidMap map[int64]int64, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selGIDRefPIDSQL); err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
gidMap = make(map[int64][]int64)
pidMap = make(map[int64]int64)
for rows.Next() {
var gid, pid int64
if err = rows.Scan(&gid, &pid); err != nil {
if err == xsql.ErrNoRows {
gidMap = nil
pidMap = nil
err = nil
return
}
err = errors.WithStack(err)
return
}
pidMap[pid] = gid
gidMap[gid] = append(gidMap[gid], pid)
}
return
}
// PendantList return pendant info
func (d *Dao) PendantList(c context.Context) (res []*model.Pendant, err error) {
var (
row *xsql.Rows
)
res = make([]*model.Pendant, 0)
if row, err = d.db.Query(c, _getPendantInfosSQL); err != nil {
log.Error("PendantInfo query error %v", err)
return
}
defer row.Close()
for row.Next() {
info := new(model.Pendant)
if err = row.Scan(&info.ID, &info.Name, &info.Image, &info.ImageModel, &info.Status, &info.Rank); err != nil {
log.Error("PendantInfo scan error %v", err)
return
}
res = append(res, info)
}
return
}
// Pendants return pendant info by ids
func (d *Dao) Pendants(c context.Context, pids []int64) (res []*model.Pendant, err error) {
var (
row *xsql.Rows
bf bytes.Buffer
)
res = make([]*model.Pendant, 0)
bf.WriteString(_getPendantInfoSQL)
bf.WriteString(" where id in(")
bf.WriteString(xstr.JoinInts(pids))
bf.WriteString(") and status = 1 ORDER BY rank")
if row, err = d.db.Query(c, bf.String()); err != nil {
log.Error("Pendants query error %v", err)
return
}
defer row.Close()
for row.Next() {
info := new(model.Pendant)
if err = row.Scan(&info.ID, &info.Name, &info.Image, &info.ImageModel, &info.Status); err != nil {
log.Error("Pendants scan error %v", err)
return
}
res = append(res, info)
}
return
}
// PendantInfo return pendant info by id
func (d *Dao) PendantInfo(c context.Context, pid int64) (res *model.Pendant, err error) {
var (
row *xsql.Row
)
res = new(model.Pendant)
row = d.db.QueryRow(c, _getPendantInfoByIDSQL, pid)
if err = row.Scan(&res.ID, &res.Name, &res.Image, &res.ImageModel, &res.Status); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
log.Error("Pendant scan error %v", err)
return
}
return
}
// PendantPrice return pendant price
func (d *Dao) PendantPrice(c context.Context, pid int64) (res map[int64]*model.PendantPrice, err error) {
var row *xsql.Rows
res = make(map[int64]*model.PendantPrice)
if row, err = d.db.Query(c, _getPendantPriceSQL, pid); err != nil {
log.Error("PendantPrice query error %v", err)
return
}
defer row.Close()
for row.Next() {
info := new(model.PendantPrice)
if err = row.Scan(&info.Pid, &info.Type, &info.Price); err != nil {
log.Error("PendantPrice scan error %v", err)
return
}
res[info.Type] = info
}
return
}
// getOrderInfoSQL return a sql string
func (d *Dao) getOrderInfoSQL(c context.Context, arg *model.ArgOrderHistory, tp string) (sql string, values []interface{}) {
values = make([]interface{}, 0, 5)
var cond bytes.Buffer
cond.WriteString("mid = ?")
values = append(values, arg.Mid)
if arg.OrderID != "" {
cond.WriteString(" AND order_id = ?")
values = append(values, arg.OrderID)
}
if arg.Pid != 0 {
cond.WriteString(" AND pid = ?")
values = append(values, arg.Pid)
}
if arg.Status != 0 {
cond.WriteString(" AND status = ?")
values = append(values, arg.Status)
}
if arg.PayType != 0 {
cond.WriteString(" AND pay_type = ?")
values = append(values, arg.PayType)
}
if arg.PayID != "" {
cond.WriteString(" AND pay_id = ?")
values = append(values, arg.PayID)
}
if arg.StartTime != 0 {
cond.WriteString(" AND buy_time >= ?")
values = append(values, arg.StartTime)
}
if arg.EndTime != 0 {
cond.WriteString(" AND buy_time <= ?")
values = append(values, arg.EndTime)
}
if tp == "info" {
cond.WriteString(" order by buy_time DESC LIMIT ?,20")
values = append(values, (arg.Page-1)*20)
sql = fmt.Sprintf(_getOrderHistorySQL, cond.String())
} else if tp == "count" {
sql = fmt.Sprintf(_countOrderHistorySQL, cond.String())
}
return
}
// OrderInfo return order info
func (d *Dao) OrderInfo(c context.Context, arg *model.ArgOrderHistory) (res []*model.PendantOrderInfo, count int64, err error) {
sqlstr, values := d.getOrderInfoSQL(c, arg, "info")
var (
row *xsql.Rows
r *xsql.Row
)
res = make([]*model.PendantOrderInfo, 0)
if row, err = d.db.Query(c, sqlstr, values...); err != nil {
log.Error("PendantOrderInfo query error %v", err)
return
}
defer row.Close()
cstr, values2 := d.getOrderInfoSQL(c, arg, "count")
r = d.db.QueryRow(c, cstr, values2...)
for row.Next() {
info := new(model.PendantOrderInfo)
if err = row.Scan(&info.Mid, &info.OrderID, &info.PayID, &info.AppID, &info.Stauts, &info.Pid, &info.TimeLength, &info.Cost, &info.BuyTime, &info.IsCallback, &info.CallbackTime, &info.PayType); err != nil {
log.Error("PendantOrderInfo scan error %v", err)
return
}
if info.PayType == 3 {
info.PayPrice = info.PayPrice / 100
}
res = append(res, info)
}
err = r.Scan(&count)
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
return
}
// OrderInfoByID return order info by order id
func (d *Dao) OrderInfoByID(c context.Context, orderID string) (res *model.PendantOrderInfo, err error) {
row := d.db.QueryRow(c, fmt.Sprintf(_getOrderHistorySQL, "order_id=?"), orderID)
res = new(model.PendantOrderInfo)
if err = row.Scan(&res.Mid, &res.OrderID, &res.PayID, &res.AppID, &res.Stauts, &res.Pid, &res.TimeLength, &res.Cost, &res.BuyTime, &res.IsCallback, &res.CallbackTime, &res.PayType); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
log.Error("OrderInfoByID scan error %v", err)
return
}
return
}
// AddOrderInfo add order log
func (d *Dao) AddOrderInfo(c context.Context, arg *model.PendantOrderInfo) (id int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _insertOrderHistory, arg.Mid, arg.OrderID, arg.PayID, arg.AppID, arg.Stauts, arg.Pid, arg.TimeLength, arg.Cost, arg.BuyTime, arg.IsCallback, arg.CallbackTime, arg.PayType); err != nil {
log.Error("AddOrderInfo insert error %v", err)
return
}
return res.LastInsertId()
}
// TxAddOrderInfo add order log
func (d *Dao) TxAddOrderInfo(c context.Context, arg *model.PendantOrderInfo, tx *xsql.Tx) (id int64, err error) {
var res sql.Result
if res, err = tx.Exec(_insertOrderHistory, arg.Mid, arg.OrderID, arg.PayID, arg.AppID, arg.Stauts, arg.Pid, arg.TimeLength, arg.Cost, arg.BuyTime, arg.IsCallback, arg.CallbackTime, arg.PayType); err != nil {
log.Error("TxAddOrderInfo insert error %v", err)
return
}
return res.LastInsertId()
}
// UpdateOrderInfo update order info
func (d *Dao) UpdateOrderInfo(c context.Context, arg *model.PendantOrderInfo) (id int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updateOrderInfoSQL, arg.Stauts, arg.PayID, arg.IsCallback, arg.CallbackTime, arg.OrderID); err != nil {
log.Error("UpdateOrderInfo update error %v", err)
return
}
return res.LastInsertId()
}
// TxUpdateOrderInfo update order info
func (d *Dao) TxUpdateOrderInfo(c context.Context, arg *model.PendantOrderInfo, tx *xsql.Tx) (id int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateOrderInfoSQL, arg.Stauts, arg.PayID, arg.IsCallback, arg.CallbackTime, arg.OrderID); err != nil {
log.Error("UpdateOrderInfo update error %v", err)
return
}
return res.LastInsertId()
}
// PackageByMid get pendant in user's package
func (d *Dao) PackageByMid(c context.Context, mid int64) (res []*model.PendantPackage, err error) {
var (
row *xsql.Rows
t = time.Now().Unix()
)
res = make([]*model.PendantPackage, 0)
if row, err = d.db.Query(c, _getUserPackageByMidSQL, mid, t); err != nil {
log.Error("Package query error %v", err)
return
}
defer row.Close()
for row.Next() {
info := new(model.PendantPackage)
if err = row.Scan(&info.Mid, &info.Pid, &info.Expires, &info.Type, &info.Status, &info.IsVIP); err != nil {
log.Error("Package scan error %v", err)
return
}
res = append(res, info)
}
return
}
// PackageByID get pendant in user's package
func (d *Dao) PackageByID(c context.Context, mid, pid int64) (res *model.PendantPackage, err error) {
var row *xsql.Row
res = new(model.PendantPackage)
row = d.db.QueryRow(c, _getUserPackageSQL, mid, pid)
if err = row.Scan(&res.Mid, &res.Pid, &res.Expires, &res.Type, &res.Status, &res.IsVIP); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
log.Error("Package scan error %v", err)
return
}
return
}
// EquipByMid obtain pendant equiped
func (d *Dao) EquipByMid(c context.Context, mid, t int64) (res *model.PendantEquip, noRow bool, err error) {
var row *xsql.Row
res = new(model.PendantEquip)
row = d.db.QueryRow(c, _getPendantEquipByMidSQL, mid, t)
if err = row.Scan(&res.Mid, &res.Pid, &res.Expires); err != nil {
if err == xsql.ErrNoRows {
noRow = true
res = nil
err = nil
return
}
err = errors.WithStack(err)
}
return
}
// EquipByMids obtain equipss by mids .
func (d *Dao) EquipByMids(c context.Context, mids []int64, t int64) (res map[int64]*model.PendantEquip, err error) {
res = make(map[int64]*model.PendantEquip)
rows, err := d.db.Query(c, fmt.Sprintf(_getPendantEquipByMidsSQL, xstr.JoinInts(mids)), t)
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
for rows.Next() {
pe := &model.PendantEquip{}
if err = rows.Scan(&pe.Mid, &pe.Pid, &pe.Expires); err != nil {
if err == xsql.ErrNoRows {
err = nil
return
}
err = errors.WithStack(err)
}
if _, ok := res[pe.Mid]; !ok {
res[pe.Mid] = pe
}
}
err = rows.Err()
return
}
// AddEquip add equip
func (d *Dao) AddEquip(c context.Context, arg *model.PendantEquip) (n int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _insertEquipSQL, arg.Mid, arg.Pid, arg.Expires); err != nil {
return 0, err
}
return res.RowsAffected()
}
// UpEquipMID uninstall user pid by mid.
func (d *Dao) UpEquipMID(c context.Context, mid int64) (n int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updateEquipMIDSQL, mid); err != nil {
return 0, err
}
return res.RowsAffected()
}
// TxUpdatePackageInfo update package info
func (d *Dao) TxUpdatePackageInfo(c context.Context, arg *model.PendantPackage, tx *xsql.Tx) (n int64, err error) {
var (
bf bytes.Buffer
values = make([]interface{}, 0, 4)
res sql.Result
)
if arg.Status != 0 && arg.Expires != 0 {
bf.WriteString("SET status=?,expires=?,type=?")
values = append(values, arg.Status)
values = append(values, arg.Expires)
values = append(values, arg.Type)
} else if arg.Status != 0 {
bf.WriteString("SET status=?,type=?")
values = append(values, arg.Status)
values = append(values, arg.Type)
} else if arg.Expires != 0 {
bf.WriteString("SET expires=?,type=?")
values = append(values, arg.Expires)
values = append(values, arg.Type)
}
values = append(values, arg.Mid)
values = append(values, arg.Pid)
if res, err = tx.Exec(fmt.Sprintf(_updatePackageSQL, bf.String()), values...); err != nil {
log.Error("TxUpdatePackageInfo update error %v", err)
return
}
return res.RowsAffected()
}
// CheckPackageExpire check expire items and update
func (d *Dao) CheckPackageExpire(c context.Context, mid, expires int64) (rows int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updatePackageExpireSQL, mid, expires); err != nil {
log.Error("CheckPackageExpire error %v", err)
return
}
return res.RowsAffected()
}
// BeginTran begin a tx.
func (d *Dao) BeginTran(c context.Context) (res *xsql.Tx, err error) {
if res, err = d.db.Begin(c); err != nil || res == nil {
log.Error("BeginTran error %v", err)
return
}
return
}
// TxAddPackage add a pendant in package
func (d *Dao) TxAddPackage(c context.Context, arg *model.PendantPackage, tx *xsql.Tx) (id int64, err error) {
var res sql.Result
if res, err = tx.Exec(_insertPendantPackageSQL, arg.Mid, arg.Pid, arg.Expires, arg.Type, arg.Status, arg.IsVIP); err != nil {
log.Error("TxAddPackage insert error %v", err)
return
}
return res.LastInsertId()
}
// TxAddHistory add a history of operation
func (d *Dao) TxAddHistory(c context.Context, arg *model.PendantHistory, tx *xsql.Tx) (id int64, err error) {
var res sql.Result
if res, err = tx.Exec(_insertOperationSQL, arg.Mid, arg.Pid, arg.SourceType, arg.OperatorName, arg.OperatorAction); err != nil {
log.Error("TxAddHistory insert error %v", err)
return
}
return res.LastInsertId()
}

View File

@@ -0,0 +1,372 @@
package pendant
import (
"strconv"
"testing"
"time"
"go-common/app/service/main/usersuit/model"
"github.com/smartystreets/goconvey/convey"
)
func TestPendantPendantGroupInfo(t *testing.T) {
convey.Convey("PendantGroupInfo", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PendantGroupInfo(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantGroupByID(t *testing.T) {
convey.Convey("GroupByID", t, func(ctx convey.C) {
var (
gid = int64(4)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GroupByID(c, gid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantGIDRefPID(t *testing.T) {
convey.Convey("GIDRefPID", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
gidMap, pidMap, err := d.GIDRefPID(c)
ctx.Convey("Then err should be nil.gidMap,pidMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(pidMap, convey.ShouldNotBeNil)
ctx.So(gidMap, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPendantList(t *testing.T) {
convey.Convey("PendantList", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PendantList(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPendants(t *testing.T) {
convey.Convey("Pendants", t, func(ctx convey.C) {
var (
pids = []int64{4}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Pendants(c, pids)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPendantInfo(t *testing.T) {
convey.Convey("PendantInfo", t, func(ctx convey.C) {
var (
pid = int64(4)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PendantInfo(c, pid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPendantPrice(t *testing.T) {
convey.Convey("PendantPrice", t, func(ctx convey.C) {
var (
pid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PendantPrice(c, pid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantgetOrderInfoSQL(t *testing.T) {
convey.Convey("getOrderInfoSQL", t, func(ctx convey.C) {
var (
arg = &model.ArgOrderHistory{}
tp = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
sql, values := d.getOrderInfoSQL(c, arg, tp)
ctx.Convey("Then sql,values should not be nil.", func(ctx convey.C) {
ctx.So(values, convey.ShouldNotBeNil)
ctx.So(sql, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantOrderInfo(t *testing.T) {
convey.Convey("OrderInfo", t, func(ctx convey.C) {
var (
arg = &model.ArgOrderHistory{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, count, err := d.OrderInfo(c, arg)
ctx.Convey("Then err should be nil.res,count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantOrderInfoByID(t *testing.T) {
convey.Convey("OrderInfoByID", t, func(ctx convey.C) {
var (
orderID = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.OrderInfoByID(c, orderID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantAddOrderInfo(t *testing.T) {
convey.Convey("AddOrderInfo", t, func(ctx convey.C) {
var (
arg = &model.PendantOrderInfo{Mid: 650454, OrderID: strconv.FormatInt(time.Now().Unix(), 10)}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.AddOrderInfo(c, arg)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantTxAddOrderInfo(t *testing.T) {
convey.Convey("TxAddOrderInfo", t, func(ctx convey.C) {
var (
arg = &model.PendantOrderInfo{Mid: 650454, OrderID: strconv.FormatInt(time.Now().UnixNano(), 10)}
tx, _ = d.BeginTran(c)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.TxAddOrderInfo(c, arg, tx)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantUpdateOrderInfo(t *testing.T) {
convey.Convey("UpdateOrderInfo", t, func(ctx convey.C) {
var (
arg = &model.PendantOrderInfo{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.UpdateOrderInfo(c, arg)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantTxUpdateOrderInfo(t *testing.T) {
convey.Convey("TxUpdateOrderInfo", t, func(ctx convey.C) {
var (
arg = &model.PendantOrderInfo{}
tx, _ = d.BeginTran(c)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.TxUpdateOrderInfo(c, arg, tx)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPackageByMid(t *testing.T) {
convey.Convey("PackageByMid", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PackageByMid(c, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantPackageByID(t *testing.T) {
convey.Convey("PackageByID", t, func(ctx convey.C) {
var (
mid = int64(650454)
pid = int64(21)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PackageByID(c, mid, pid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantEquipByMid(t *testing.T) {
convey.Convey("EquipByMid", t, func(ctx convey.C) {
var (
mid = int64(88888929)
no = int64(44)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, noRow, err := d.EquipByMid(c, mid, no)
ctx.Convey("Then err should be nil.res,noRow should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(noRow, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantEquipByMids(t *testing.T) {
convey.Convey("EquipByMids", t, func(ctx convey.C) {
var (
mids = []int64{650454}
no = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.EquipByMids(c, mids, no)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantAddEquip(t *testing.T) {
convey.Convey("AddEquip", t, func(ctx convey.C) {
var (
arg = &model.PendantEquip{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
n, err := d.AddEquip(c, arg)
ctx.Convey("Then err should be nil.n should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(n, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantTxUpdatePackageInfo(t *testing.T) {
convey.Convey("TxUpdatePackageInfo", t, func(ctx convey.C) {
var (
arg = &model.PendantPackage{Mid: 88888929, Pid: 2, Status: 1}
tx, _ = d.BeginTran(c)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
n, err := d.TxUpdatePackageInfo(c, arg, tx)
ctx.Convey("Then err should be nil.n should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(n, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantCheckPackageExpire(t *testing.T) {
convey.Convey("CheckPackageExpire", t, func(ctx convey.C) {
var (
mid = int64(650454)
expires = int64(2147483647)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.CheckPackageExpire(c, mid, expires)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantBeginTran(t *testing.T) {
convey.Convey("BeginTran", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.BeginTran(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantTxAddPackage(t *testing.T) {
convey.Convey("TxAddPackage", t, func(ctx convey.C) {
var (
arg = &model.PendantPackage{Mid: time.Now().Unix(), Pid: 4}
tx, _ = d.BeginTran(c)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.TxAddPackage(c, arg, tx)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantTxAddHistory(t *testing.T) {
convey.Convey("TxAddHistory", t, func(ctx convey.C) {
var (
arg = &model.PendantHistory{}
tx, _ = d.BeginTran(c)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.TxAddHistory(c, arg, tx)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,31 @@
package pendant
import (
"context"
"net/url"
"go-common/library/ecode"
"go-common/library/log"
)
// PayBcoin pay coin
func (d *Dao) PayBcoin(c context.Context, params url.Values, ip string) (orderNo, casherURL string, err error) {
var res struct {
Code int `json:"code"`
Ts string `json:"ts"`
OrderNum string `json:"order_no"`
CasherURL string `json:"cashier_url"`
}
if err = d.client.Post(c, d.payURL, ip, params, &res); err != nil {
log.Error("dao.client.Post(%s) error(%v)", d.payURL, err)
return
}
if res.Code != 0 {
log.Error("dao.client.Post(%s) error(%v)", d.payURL, res)
err = ecode.Int(res.Code)
return
}
orderNo = res.OrderNum
casherURL = res.CasherURL
return
}

View File

@@ -0,0 +1,41 @@
package pendant
import (
"fmt"
"net/url"
"strconv"
"testing"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestPendantPayBcoin(t *testing.T) {
convey.Convey("PayBcoin", t, func(ctx convey.C) {
var (
params = url.Values{}
ip = ""
_subject = "头像挂件"
)
params.Set("mid", "109228")
params.Set("out_trade_no", "2016050614625209018624230766")
params.Set("money", strconv.FormatFloat(2, 'f', 2, 64))
params.Set("subject", _subject)
params.Set("remark", fmt.Sprintf(_subject+" - %s%s个月", strconv.FormatInt(4, 10), strconv.FormatInt(1234, 10)))
params.Set("merchant_id", d.c.PayInfo.MerchantID)
params.Set("merchant_product_id", d.c.PayInfo.MerchantProductID)
params.Set("platform_type", "3")
params.Set("iap_pay_type", "0")
params.Set("notify_url", d.c.PayInfo.CallBackURL)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.payURL).Reply(0).JSON(`{"code":0}`)
orderNo, casherURL, err := d.PayBcoin(c, params, ip)
ctx.Convey("Then err should be nil.orderNo,casherURL should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(casherURL, convey.ShouldNotBeNil)
ctx.So(orderNo, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,286 @@
package pendant
import (
"context"
"strconv"
"encoding/json"
"go-common/app/service/main/usersuit/model"
"go-common/library/cache/redis"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_pendantPKG = "pkg_" // key of
_pendantEquip = "pe_"
)
func keyEquip(mid int64) string {
return _pendantEquip + strconv.FormatInt(mid, 10)
}
// encode
func (d *Dao) encode(mid, pid, expires, tp int64, status, isVIP int32, pendant *model.Pendant) (res []byte, err error) {
ft := &model.PendantPackage{Mid: mid, Pid: pid, Expires: expires, Type: tp, Status: status, IsVIP: isVIP, Pendant: pendant}
return json.Marshal(ft)
}
// decode
func (d *Dao) decode(src []byte, v *model.PendantPackage) (err error) {
return json.Unmarshal(src, v)
}
// AddPKGCache set package cache.
func (d *Dao) AddPKGCache(c context.Context, mid int64, info []*model.PendantPackage) (err error) {
var (
key = _pendantPKG + strconv.FormatInt(mid, 10)
args = redis.Args{}.Add(key)
)
for i := 0; i < len(info); i++ {
var ef []byte
if ef, err = d.encode(info[i].Mid, info[i].Pid, info[i].Expires, info[i].Type, info[i].Status, info[i].IsVIP, info[i].Pendant); err != nil {
return
}
args = args.Add(i, ef)
}
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("DEL", key); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", key, err)
return
}
if err = conn.Send("HMSET", args...); err != nil {
log.Error("conn.Send(HMSET, %s) error(%v)", key, err)
return
}
if err = conn.Send("EXPIRE", key, d.pendantExpire); err != nil {
log.Error("conn.Send(EXPIRE, %s) error(%v)", key, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v)", err)
return
}
for i := 0; i < 3; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() %d error(%v)", i+1, err)
break
}
}
return
}
// PKGCache get package cache.
func (d *Dao) PKGCache(c context.Context, mid int64) (info []*model.PendantPackage, err error) {
var (
key = _pendantPKG + strconv.FormatInt(mid, 10)
tmp = make(map[string]string, len(info))
)
conn := d.redis.Get(c)
defer conn.Close()
if tmp, err = redis.StringMap(conn.Do("HGETALL", key)); err != nil {
return
}
if err == nil && len(tmp) > 0 {
for i := 0; i < len(tmp); i++ {
s := strconv.FormatInt(int64(i), 10)
vf := &model.PendantPackage{}
vf.Pendant = &model.Pendant{}
if err = d.decode([]byte(tmp[s]), vf); err != nil {
return
}
info = append(info, &model.PendantPackage{
Mid: vf.Mid,
Pid: vf.Pid,
Expires: vf.Expires,
Type: vf.Type,
Status: vf.Status,
IsVIP: vf.IsVIP,
Pendant: vf.Pendant,
})
}
}
return
}
// DelPKGCache del package cache
func (d *Dao) DelPKGCache(c context.Context, mid int64) (err error) {
key := _pendantPKG + strconv.FormatInt(mid, 10)
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("DEL", key); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", key, err)
return
}
return
}
// equipCache return pendant info cache
func (d *Dao) equipCache(c context.Context, mid int64) (info *model.PendantEquip, err error) {
var (
item []byte
conn = d.redis.Get(c)
)
defer conn.Close()
if item, err = redis.Bytes(conn.Do("GET", keyEquip(mid))); err != nil {
if err == redis.ErrNil {
err = nil
}
return
}
if err = json.Unmarshal(item, &info); err != nil {
log.Error("json.Unmarshal(%v) err(%v)", item, err)
}
return
}
// equipsCache obtain equips from redis .
func (d *Dao) equipsCache(c context.Context, mids []int64) (map[int64]*model.PendantEquip, []int64, error) {
var (
err error
bss [][]byte
key string
args = redis.Args{}
conn = d.redis.Get(c)
)
for _, v := range mids {
key = keyEquip(v)
args = args.Add(key)
}
defer conn.Close()
if bss, err = redis.ByteSlices(conn.Do("MGET", args...)); err != nil {
if err == redis.ErrNil {
return nil, nil, nil
}
log.Error("Failed mget equip: keys: %+v: %+v", args, err)
return nil, nil, err
}
info := make(map[int64]*model.PendantEquip, len(mids))
for _, bs := range bss {
if bs == nil {
continue
}
pe := &model.PendantEquip{}
if err = json.Unmarshal(bs, pe); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bs), err)
err = nil
continue
}
info[pe.Mid] = pe
}
missed := make([]int64, 0, len(mids))
for _, mid := range mids {
if _, ok := info[mid]; !ok {
missed = append(missed, mid)
}
}
return info, missed, nil
}
// AddEquipCache set pendant info cache
func (d *Dao) AddEquipCache(c context.Context, mid int64, info *model.PendantEquip) (err error) {
var (
key = keyEquip(mid)
values []byte
conn = d.redis.Get(c)
)
defer conn.Close()
if values, err = json.Marshal(info); err != nil {
return
}
if err = conn.Send("SET", keyEquip(mid), values); err != nil {
log.Error("conn.Send(SET, %s, %d) error(%v)", key, values, err)
return
}
if err = conn.Send("EXPIRE", key, d.pendantExpire); err != nil {
log.Error("conn.Send(Expire, %s, %d) error(%v)", key, d.pendantExpire, err)
return
}
if err = conn.Flush(); err != nil {
err = errors.Wrap(err, "conn.Send Flush")
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
err = errors.Wrap(err, "conn.Send conn.Receive()")
return
}
}
return
}
// AddEquipsCache mset equips info to caache .
func (d *Dao) AddEquipsCache(c context.Context, equips map[int64]*model.PendantEquip) (err error) {
var (
bs []byte
key string
keys []string
argsMid = redis.Args{}
conn = d.redis.Get(c)
)
defer conn.Close()
for _, v := range equips {
if bs, err = json.Marshal(v); err != nil {
log.Error("json.Marshal err(%v)", err)
continue
}
key = keyEquip(v.Mid)
keys = append(keys, key)
argsMid = argsMid.Add(key).Add(string(bs))
}
if err = conn.Send("MSET", argsMid...); err != nil {
err = errors.Wrap(err, "conn.Send(MSET) error")
return
}
count := 1
for _, v := range keys {
count++
if err = conn.Send("EXPIRE", v, d.pendantExpire); err != nil {
err = errors.Wrap(err, "conn.Send error")
return
}
}
if err = conn.Flush(); err != nil {
err = errors.Wrap(err, "conn.Send Flush")
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
err = errors.Wrap(err, "conn.Send conn.Receive()")
return
}
}
return
}
// DelEquipCache set pendant info cache
func (d *Dao) DelEquipCache(c context.Context, mid int64) (err error) {
key := keyEquip(mid)
conn := d.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("DEL", key); err != nil {
log.Error("conn.Do(DEL, %s) error(%v)", key, err)
}
return
}
// DelEquipsCache del batch equip cache .
func (d *Dao) DelEquipsCache(c context.Context, mids []int64) (err error) {
var (
args = redis.Args{}
conn = d.redis.Get(c)
)
defer conn.Close()
for _, v := range mids {
args = args.Add(keyEquip(v))
}
if _, err = conn.Do("DEL", args...); err != nil {
log.Error("conn.Do(DEL, %s) error(%v)", args, err)
}
return
}

View File

@@ -0,0 +1,180 @@
package pendant
import (
"fmt"
"go-common/app/service/main/usersuit/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestPendantkeyEquip(t *testing.T) {
convey.Convey("keyEquip", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyEquip(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantencode(t *testing.T) {
convey.Convey("encode", t, func(ctx convey.C) {
var (
mid = int64(650454)
pid = int64(1)
expires = int64(1535970125)
tp = int64(0)
status = int32(1)
isVIP = int32(1)
pendant = &model.Pendant{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.encode(mid, pid, expires, tp, status, isVIP, pendant)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
fmt.Println(string(res))
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantdecode(t *testing.T) {
convey.Convey("decode", t, func(ctx convey.C) {
var (
src = []byte("\u007b\u0022\u0069\u0064\u0022\u003a\u0030\u002c\u0022\u006d\u0069\u0064\u0022\u003a\u0036\u0035\u0030\u0034\u0035\u0034\u002c\u0022\u0070\u0069\u0064\u0022\u003a\u0031\u002c\u0022\u0065\u0078\u0070\u0069\u0072\u0065\u0022\u003a\u0031\u0035\u0033\u0035\u0039\u0037\u0030\u0031\u0032\u0035\u002c\u0022\u0074\u0079\u0070\u0065\u0022\u003a\u0030\u002c\u0022\u0073\u0074\u0061\u0074\u0075\u0073\u0022\u003a\u0031\u002c\u0022\u0069\u0073\u0056\u0049\u0050\u0022\u003a\u0031\u002c\u0022\u0070\u0065\u006e\u0064\u0061\u006e\u0074\u0022\u003a\u007b\u0022\u0070\u0069\u0064\u0022\u003a\u0030\u002c\u0022\u006e\u0061\u006d\u0065\u0022\u003a\u0022\u0022\u002c\u0022\u0069\u006d\u0061\u0067\u0065\u0022\u003a\u0022\u0022\u002c\u0022\u0069\u006d\u0061\u0067\u0065\u005f\u006d\u006f\u0064\u0065\u006c\u0022\u003a\u0022\u0022\u002c\u0022\u0073\u0074\u0061\u0074\u0075\u0073\u0022\u003a\u0030\u002c\u0022\u0063\u006f\u0069\u006e\u0022\u003a\u0030\u002c\u0022\u0070\u006f\u0069\u006e\u0074\u0022\u003a\u0030\u002c\u0022\u0062\u0063\u006f\u0069\u006e\u0022\u003a\u0030\u002c\u0022\u0065\u0078\u0070\u0069\u0072\u0065\u0022\u003a\u0030\u002c\u0022\u0067\u0069\u0064\u0022\u003a\u0030\u002c\u0022\u0072\u0061\u006e\u006b\u0022\u003a\u0030\u007d\u007d")
v = &model.PendantPackage{Mid: 650454, Pid: 1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.decode(src, v)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantAddPKGCache(t *testing.T) {
convey.Convey("AddPKGCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
info = []*model.PendantPackage{}
pp = &model.PendantPackage{Mid: mid, Pid: int64(1)}
)
info = append(info, pp)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddPKGCache(c, mid, info)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantPKGCache(t *testing.T) {
convey.Convey("PKGCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
info, err := d.PKGCache(c, mid)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(info, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantDelPKGCache(t *testing.T) {
convey.Convey("DelPKGCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelPKGCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantAddEquipCache(t *testing.T) {
convey.Convey("AddEquipCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
info = &model.PendantEquip{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddEquipCache(c, mid, info)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantequipCache(t *testing.T) {
convey.Convey("equipCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
info, err := d.equipCache(c, mid)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(info, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantDelEquipCache(t *testing.T) {
convey.Convey("DelEquipCache", t, func(ctx convey.C) {
var (
mid = int64(650454)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelEquipCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPendantequipsCache(t *testing.T) {
convey.Convey("equipsCache", t, func(ctx convey.C) {
var (
mids = []int64{650454}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, p2, err := d.equipsCache(c, mids)
ctx.Convey("Then err should be nil.p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestPendantDelEquipsCache(t *testing.T) {
convey.Convey("DelEquipsCache", t, func(ctx convey.C) {
var (
mids = []int64{650454, 1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelEquipsCache(c, mids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,28 @@
package pendant
import (
"context"
"strconv"
"go-common/app/service/main/usersuit/model"
"go-common/library/ecode"
"github.com/pkg/errors"
)
// VipInfo get identify info by calling api.
func (d *Dao) VipInfo(c context.Context, mid int64, ip string) (idt *model.VipInfo, err error) {
var res struct {
Code int
Data *model.VipInfo
}
if err = d.client.Get(c, d.vipInfoURL+strconv.FormatInt(mid, 10), ip, nil, &res); err != nil {
return
}
if res.Code != 0 {
err = errors.WithStack(ecode.Int(res.Code))
return
}
idt = res.Data
return
}

View File

@@ -0,0 +1,23 @@
package pendant
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestPendantVipInfo(t *testing.T) {
convey.Convey("VipInfo", t, func(ctx convey.C) {
var (
mid = int64(650454)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
idt, err := d.VipInfo(c, mid, ip)
ctx.Convey("Then err should be nil.idt should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(idt, convey.ShouldNotBeNil)
})
})
})
}