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,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/job/live/gift/internal/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/BurntSushi/toml: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,107 @@
package conf
import (
"errors"
"flag"
"go-common/library/log/infoc"
"go-common/library/queue/databus"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/trace"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
Redis *redis.Config
Memcache *memcache.Config
MySQL *sql.Config
Ecode *ecode.Config
Databus *Databus
Infoc map[string]*infoc.Config
Consumer *consumer
}
type consumer struct {
AddGift *consumeConfig
}
type consumeConfig struct {
Num int
}
//Databus Databus
type Databus struct {
AddGift *databus.Config
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mysql.go",
"redis.go",
],
importpath = "go-common/app/job/live/gift/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/satori/go.uuid: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,42 @@
package dao
import (
"context"
"go-common/app/job/live/gift/internal/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
redis *redis.Pool
db *xsql.DB
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache),
redis: redis.NewPool(c.Redis),
db: xsql.NewMySQL(c.MySQL),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(ctx context.Context) error {
// TODO: add mc,redis... if you use
return d.db.Ping(ctx)
}

View File

@@ -0,0 +1,79 @@
package dao
import (
"context"
"crypto/md5"
"database/sql"
"encoding/hex"
"fmt"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"strconv"
)
var (
_getBag = "SELECT id,gift_num FROM user_gift_%s WHERE uid = ? AND gift_id = ? AND expireat = ? LIMIT 1"
_getBagByID = "SELECT id,gift_num FROM user_gift_%s WHERE id = ?"
_updateBagNum = "UPDATE user_gift_%s SET gift_num = gift_num + ? WHERE id = ?"
_insertBag = "INSERT INTO user_gift_%s (uid,gift_id,gift_num,expireat) VALUES (?,?,?,?)"
)
// GetBag GetBag
func (d *Dao) GetBag(ctx context.Context, uid, giftID, expireAt int64) (res *model.BagInfo, err error) {
log.Info("GetBag,uid:%d,giftID:%d,expireAt:%d", uid, giftID, expireAt)
row := d.db.QueryRow(ctx, fmt.Sprintf(_getBag, getPostFix(uid)), uid, giftID, expireAt)
res = &model.BagInfo{}
if err = row.Scan(&res.ID, &res.GiftNum); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("GetBag row.Scan error(%v)", err)
}
return
}
// UpdateBagNum UpdateBagNum
func (d *Dao) UpdateBagNum(ctx context.Context, uid, id, num int64) (affected int64, err error) {
log.Info("UpdateBagNum,uid:%d,id:%d,num:%d", uid, id, num)
res, err := d.db.Exec(ctx, fmt.Sprintf(_updateBagNum, getPostFix(uid)), num, id)
if err != nil {
log.Error("UpdateBagNum error(%v)", err)
return
}
return res.RowsAffected()
}
// AddBag AddBag
func (d *Dao) AddBag(ctx context.Context, uid, giftID, giftNum, expireAt int64) (affected int64, err error) {
log.Info("AddBag,uid:%d,giftID:%d,giftNum:%d,expireAt:%d", uid, giftID, giftNum, expireAt)
res, err := d.db.Exec(ctx, fmt.Sprintf(_insertBag, getPostFix(uid)), uid, giftID, giftNum, expireAt)
if err != nil {
log.Error("AddBag error(%v)", err)
return
}
return res.LastInsertId()
}
// GetBagByID GetBagByID
func (d *Dao) GetBagByID(ctx context.Context, uid, id int64) (res *model.BagInfo, err error) {
log.Info("GetBagByID,uid:%d,id:%d", uid, id)
row := d.db.QueryRow(ctx, fmt.Sprintf(_getBagByID, getPostFix(uid)), id)
res = &model.BagInfo{}
if err = row.Scan(&res.ID, &res.GiftNum); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("GetBagByID row.Scan error(%v)", err)
}
return
}
func getPostFix(uid int64) string {
uidStr := strconv.Itoa(int(uid))
h := md5.New()
h.Write([]byte(uidStr))
md5Str := hex.EncodeToString(h.Sum(nil))
return md5Str[0:1]
}

View File

@@ -0,0 +1,110 @@
package dao
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
"time"
"github.com/satori/go.uuid"
)
func bagIDCache(uid, giftID, expireAt int64) string {
return fmt.Sprintf("bag_id:%d:%d:%d", uid, giftID, expireAt)
}
// SetBagIDCache SetBagIDCache
func (d *Dao) SetBagIDCache(ctx context.Context, uid, giftID, expireAt, bagID, expire int64) (err error) {
key := bagIDCache(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("SETEX", key, expire, bagID)
if err != nil {
log.Error("conn.Do(SETEX, %s) error(%v)", key, err)
}
return
}
func bagListKey(uid int64) string {
return fmt.Sprintf("bag_list:%d", uid)
}
// ClearBagListCache ClearBagListCache
func (d *Dao) ClearBagListCache(ctx context.Context, uid int64) (err error) {
key := bagListKey(uid)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("DEL", key)
if err != nil {
log.Error("conn.Do(DEL, %s) error(%v)", key, err)
}
return
}
// GetBagIDCache GetBagIDCache
func (d *Dao) GetBagIDCache(ctx context.Context, uid, giftID, expireAt int64) (bagID int64, err error) {
key := bagIDCache(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
bagID, err = redis.Int64(conn.Do("GET", key))
if err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET, %s) error(%v)", key, err)
}
return
}
return
}
func bagNumKey(uid, giftID, expireAt int64) string {
return fmt.Sprintf("bag_num:%d:%d:%d", uid, giftID, expireAt)
}
// SetBagNumCache SetBagNumCache
func (d *Dao) SetBagNumCache(ctx context.Context, uid, giftID, expireAt, giftNum, expire int64) (err error) {
key := bagNumKey(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("SETEX", key, expire, giftNum)
if err != nil {
log.Error("conn.Do(SETEX, %s) error(%v)", key, err)
}
return
}
//Lock Lock
func (d *Dao) Lock(ctx context.Context, key string, ttl int, retry int, retryDelay int) (gotLock bool, lockValue string, err error) {
if retry <= 0 {
retry = 1
}
lockValue = uuid.NewV4().String()
retryTimes := 0
conn := d.redis.Get(ctx)
defer conn.Close()
realKey := lockKey(key)
for ; retryTimes < retry; retryTimes++ {
var res interface{}
res, err = conn.Do("SET", realKey, lockValue, "PX", ttl, "NX")
if err != nil {
log.Error("redis_lock failed:%s:%v", realKey, err)
break
}
if res != nil {
gotLock = true
break
}
time.Sleep(time.Duration(retryDelay) * time.Millisecond)
}
return
}
func lockKey(key string) string {
return fmt.Sprintf("gift_job_lock:%s", key)
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/job/live/gift/internal/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
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,17 @@
package model
//AddFreeGift AddFreeGift
type AddFreeGift struct {
UID int64 `json:"uid"`
GiftID int64 `json:"gift_id"`
GiftNum int64 `json:"gift_num"`
ExpireAt int64 `json:"expire_at"`
Source string `json:"source"`
MsgID string `json:"msg_id"`
}
// BagInfo BagInfo
type BagInfo struct {
ID int64 `json:"id"`
GiftNum int64 `json:"gift_num"`
}

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/job/live/gift/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,53 @@
package http
import (
"net/http"
"go-common/app/job/live/gift/internal/conf"
"go-common/app/job/live/gift/internal/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
vfy *verify.Verify
svc *service.Service
)
// Init init
func Init(c *conf.Config, s *service.Service) {
svc = s
vfy = verify.New(c.Verify)
engine := bm.DefaultServer(c.BM)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/gift")
{
g.GET("/start", vfy.Verify, howToStart)
}
}
func ping(ctx *bm.Context) {
if err := svc.Ping(ctx); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}

View File

@@ -0,0 +1,60 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"infoc.go",
"package.go",
"service.go",
],
importpath = "go-common/app/job/live/gift/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/api:go_default_library",
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/dao:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"infoc_test.go",
"package_test.go",
"service_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,121 @@
package service
import (
"go-common/library/log"
"go-common/library/log/infoc"
"strconv"
"time"
)
var inCh = make(chan interface{}, 10240)
const maxInt = int(^uint(0) >> 1)
type bagLogInfoc struct {
id string
uid string
bagID string
giftID string
num string
afterNum string
source string
infoType string
ctime string
}
type giftActionInfoc struct {
uid int64
roomid int64
item int64
value int64
change int64
describe string
extra string
ts int64
platform string
clientver string
buvid string
ua string
referer string
}
// bagLogInfoc 包裹日志打点
func (s *Service) bagLogInfoc(uid, bagID, giftID, num, afterNum int64, source string) {
s.infoc(bagLogInfoc{
id: MakeID(uid),
uid: strconv.FormatInt(uid, 10),
bagID: strconv.FormatInt(bagID, 10),
giftID: strconv.FormatInt(giftID, 10),
num: strconv.FormatInt(num, 10),
afterNum: strconv.FormatInt(afterNum, 10),
source: source,
infoType: "1",
ctime: time.Now().Format("2006-01-02 15:04:05"),
})
}
//giftActionInfoc 道具打点
func (s *Service) giftActionInfoc(uid, roomid, item, value, change int64, describe, platform string) {
s.infoc(giftActionInfoc{
uid: uid,
roomid: roomid,
item: item,
value: value,
change: change,
describe: describe,
extra: "",
ts: time.Now().Unix(),
platform: platform,
clientver: "",
buvid: "",
ua: "",
referer: "",
})
}
// MakeID MakeID
func MakeID(uid int64) string {
prefix := strconv.FormatInt(uid%10, 10)
postfix := strconv.Itoa(maxInt - int(time.Now().Unix()*10000))
uidStr := strconv.FormatInt(uid, 10)
l := len(uidStr)
var middle string
if l >= 10 {
middle = uidStr
} else {
var s string
for i := 0; i < (10 - l); i++ {
s += "0"
}
middle = s + uidStr
}
return prefix + middle + postfix
}
//infoc
func (s *Service) infoc(i interface{}) {
select {
case inCh <- i:
default:
log.Warn("infocproc chan full")
}
}
// infocproc
func (s *Service) infocproc() {
var bl = infoc.New(s.c.Infoc["bagLog"])
var ga = infoc.New(s.c.Infoc["giftAction"])
for {
i := <-inCh
switch v := i.(type) {
case bagLogInfoc:
err := bl.Info(v.id, v.uid, v.bagID, v.giftID, v.num, v.afterNum, v.source, v.infoType, v.ctime)
log.Info("bagLogInfoc info %v,ret:%v", v, err)
case giftActionInfoc:
err := ga.Info(v.uid, v.roomid, v.item, v.value, v.change, v.describe, v.extra, v.ts, v.platform, v.clientver, v.buvid, v.ua, v.referer)
log.Info("giftActionInfoc info %v,ret:%v", v, err)
default:
log.Warn("infocproc can't process the type")
}
}
}

View File

@@ -0,0 +1,58 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServicebagLogInfoc(t *testing.T) {
convey.Convey("bagLogInfoc", t, func(ctx convey.C) {
var (
uid = int64(0)
bagID = int64(0)
giftID = int64(0)
num = int64(0)
afterNum = int64(0)
source = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
s.bagLogInfoc(uid, bagID, giftID, num, afterNum, source)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServicegiftActionInfoc(t *testing.T) {
convey.Convey("giftActionInfoc", t, func(ctx convey.C) {
var (
uid = int64(0)
roomid = int64(0)
item = int64(0)
value = int64(0)
change = int64(0)
describe = ""
platform = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
s.giftActionInfoc(uid, roomid, item, value, change, describe, platform)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServiceMakeID(t *testing.T) {
convey.Convey("MakeID", t, func(ctx convey.C) {
var (
uid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := MakeID(uid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,99 @@
package service
import (
"context"
"errors"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// AddGift AddGift
func (s *Service) AddGift(ctx context.Context, m *model.AddFreeGift) (bagId int64, err error) {
uid := m.UID
giftID := m.GiftID
giftNum := m.GiftNum
expireAt := m.ExpireAt
source := m.Source
if uid == 0 || giftID == 0 || giftNum == 0 {
log.Error("add gift params error,uid:%d,giftID:%d,giftNum:%d", uid, giftID, giftNum)
err = errors.New("params error")
return
}
bagID, err := s.GetBagID(ctx, uid, giftID, expireAt)
if err != nil {
return
}
var (
affectNum int64
isUpdate = false
eg, _ = errgroup.WithContext(ctx)
)
if bagID != 0 {
isUpdate = true
affectNum, _ = s.dao.UpdateBagNum(ctx, uid, bagID, giftNum)
} else {
affectNum, _ = s.dao.AddBag(ctx, uid, giftID, giftNum, expireAt)
bagID = affectNum
eg.Go(
func() error {
s.dao.SetBagIDCache(ctx, uid, giftID, expireAt, bagID, 14400)
return nil
})
}
newNum := giftNum
if affectNum > 0 {
eg.Go(
func() error {
s.dao.ClearBagListCache(ctx, uid)
return nil
})
if isUpdate {
res, _ := s.dao.GetBagByID(ctx, uid, bagID)
newNum = res.GiftNum
//上报lancer TODO
s.bagLogInfoc(uid, bagID, giftID, giftNum, newNum, source)
}
}
// 更新免费礼物数量缓存
eg.Go(
func() error {
s.UpdateFreeGiftCache(ctx, uid, giftID, expireAt, newNum)
return nil
})
eg.Wait()
return
}
// GetBagID GetBagID
func (s *Service) GetBagID(ctx context.Context, uid, giftID, expireAt int64) (id int64, err error) {
id, err = s.dao.GetBagIDCache(ctx, uid, giftID, expireAt)
if err != nil {
return
}
if id == 0 {
//queryDB
var r *model.BagInfo
r, err = s.dao.GetBag(ctx, uid, giftID, expireAt)
if err != nil {
return
}
id = r.ID
}
// 缓存或数据库本身有,再更新缓存
if id != 0 {
s.dao.SetBagIDCache(ctx, uid, giftID, expireAt, id, 14400)
}
return
}
// UpdateFreeGiftCache UpdateFreeGiftCache
func (s *Service) UpdateFreeGiftCache(ctx context.Context, uid, giftID, expireAt, num int64) {
//giftInfo := s.GetGiftInfoByID(ctx, giftID)
//if giftInfo.Id == 0 || giftInfo.Type != 3 {
// return
//}
//s.dao.SetBagNumCache(ctx, uid, giftID, expireAt, num, 14400)
}

View File

@@ -0,0 +1,66 @@
package service
import (
"context"
"go-common/app/job/live/gift/internal/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceAddGift(t *testing.T) {
convey.Convey("AddGift", t, func(c convey.C) {
var (
ctx = context.Background()
m = &model.AddFreeGift{
UID: 1,
GiftID: 1,
GiftNum: 1,
ExpireAt: 0,
Source: "test",
}
)
c.Convey("When everything gose positive", func(c convey.C) {
bagId, err := s.AddGift(ctx, m)
c.Convey("Then err should be nil.bagId should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(bagId, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceGetBagID(t *testing.T) {
convey.Convey("GetBagID", t, func(c convey.C) {
var (
ctx = context.Background()
uid = int64(1)
giftID = int64(1)
expireAt = int64(0)
)
c.Convey("When everything gose positive", func(c convey.C) {
id, err := s.GetBagID(ctx, uid, giftID, expireAt)
c.Convey("Then err should be nil.id should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceUpdateFreeGiftCache(t *testing.T) {
convey.Convey("UpdateFreeGiftCache", t, func(c convey.C) {
var (
ctx = context.Background()
uid = int64(0)
giftID = int64(0)
expireAt = int64(0)
num = int64(0)
)
c.Convey("When everything gose positive", func(c convey.C) {
s.UpdateFreeGiftCache(ctx, uid, giftID, expireAt, num)
c.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,95 @@
package service
import (
"context"
"encoding/json"
"fmt"
"sync"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"go-common/library/queue/databus"
pb "go-common/app/job/live/gift/api"
"go-common/app/job/live/gift/internal/conf"
"go-common/app/job/live/gift/internal/dao"
"github.com/golang/protobuf/ptypes/empty"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
addFreeGift *databus.Databus
waiter sync.WaitGroup
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
addFreeGift: databus.New(c.Databus.AddGift),
}
go s.infocproc()
for i := 0; i < c.Consumer.AddGift.Num; i++ {
s.waiter.Add(1)
go s.addGiftConsumeProc()
}
return s
}
func (s *Service) addGiftConsumeProc() {
defer s.waiter.Done()
var err error
for {
msg, ok := <-s.addFreeGift.Messages()
if !ok {
log.Error("s.addFreeGift.Messages channel closed")
return
}
m := &model.AddFreeGift{}
if err = json.Unmarshal(msg.Value, &m); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", msg, err)
continue
}
ctx := context.Background()
// 消息幂等
if m.MsgID != "" {
key := m.MsgID + m.Source
gotLock, _, errLock := s.dao.Lock(ctx, key, 3600000, 0, 0)
if errLock != nil {
continue
}
if !gotLock {
log.Error("msg has been processed,%v", m)
continue
}
}
s.AddGift(ctx, m)
// 打点上报
s.giftActionInfoc(m.UID, 0, m.GiftID, 0, m.GiftNum, m.Source, "")
log.Info("consume addFreeGift topic:%s, Key:%s, Value:%s ", msg.Topic, msg.Key, msg.Value)
if err = msg.Commit(); err != nil {
log.Error("commit msg(%v) error(%v)", msg, err)
}
}
}
// SayHello grpc demo func
func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) {
reply = new(empty.Empty)
fmt.Printf("hello %s", req.Name)
return
}
// Ping Service
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,34 @@
package service
import (
"flag"
"go-common/app/job/live/gift/internal/conf"
"os"
"testing"
)
var (
s *Service
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
os.Exit(m.Run())
}