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,59 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"exp.go",
"exp_log.go",
"mc_level.go",
],
importpath = "go-common/app/service/live/userexp/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/userexp/conf:go_default_library",
"//app/service/live/userexp/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"exp_test.go",
"mc_level_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/live/userexp/conf:go_default_library",
"//app/service/live/userexp/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey: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,69 @@
package dao
import (
"context"
"go-common/app/service/live/userexp/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
"go-common/library/log"
)
// Dao struct userexp-service dao
type Dao struct {
c *conf.Config
// exp db
expDb *sql.DB
// memcache
expMc *memcache.Pool
cacheExpire int32
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
expDb: sql.NewMySQL(c.DB.Exp),
expMc: memcache.NewPool(c.Memcache.Exp),
cacheExpire: c.LevelExpire,
}
return
}
// Ping check service health.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.expDb.Ping(c); err != nil {
log.Error("PingDb error(%v)", err)
return
}
if err = d.pingMemcache(c); err != nil {
return
}
return
}
// PingMemcache check connection success.
func (d *Dao) pingMemcache(c context.Context) (err error) {
item := &memcache.Item{
Key: "ping",
Value: []byte{1},
Expiration: d.cacheExpire,
}
conn := d.expMc.Get(c)
err = conn.Set(item)
conn.Close()
if err != nil {
log.Error("PingMemcache conn.Set(%v) error(%v)", item, err)
}
return
}
// Close close memcache resource.
func (d *Dao) Close() {
if d.expMc != nil {
d.expMc.Close()
}
if d.expDb != nil {
d.expDb.Close()
}
}

View File

@@ -0,0 +1,111 @@
package dao
import (
"context"
"database/sql"
"fmt"
"go-common/app/service/live/userexp/model"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_shard = 10
_insExp = "INSERT IGNORE INTO user_exp_%d (uid,uexp,rexp) VALUES(?,?,?)"
_selExp = "SELECT uid,uexp,rexp FROM user_exp_%d where uid=?"
_inSelExp = "SELECT uid,uexp,rexp FROM user_exp_%d where uid IN (%s)"
_addUexp = "INSERT INTO user_exp_%d(uid,uexp,rexp) VALUES(?,?,0) ON DUPLICATE KEY UPDATE uexp=uexp+%d"
_addRexp = "INSERT INTO user_exp_%d(uid,uexp,rexp) VALUES(?,0,?) ON DUPLICATE KEY UPDATE rexp=rexp+%d"
)
// InitExp 初始化用户经验,用于首次查询
func (d *Dao) InitExp(c context.Context, uid int64, uexp int64, rexp int64) (row int64, err error) {
res, err := d.expDb.Exec(c, fmt.Sprintf(_insExp, uid%_shard), uid, uexp, rexp)
if err != nil {
log.Error("[dao.exp|InitExp] d.exp.Exec err: %v", err)
return
}
return res.RowsAffected()
}
// Exp 查询一条记录
func (d *Dao) Exp(c context.Context, uid int64) (exp *model.Exp, err error) {
row := d.expDb.QueryRow(c, fmt.Sprintf(_selExp, uid%_shard), uid)
exp = &model.Exp{}
if err = row.Scan(&exp.Uid, &exp.Uexp, &exp.Rexp); err == sql.ErrNoRows {
// 查询结果为空时,初始化数据
_, err = d.InitExp(c, uid, 0, 0)
}
if err != nil {
log.Error("[dao.exp|Exp] row.Scan err: %v", err)
return
}
return
}
// MultiExp 批量查询
func (d *Dao) MultiExp(c context.Context, uids []int64) (exps []*model.Exp, err error) {
var (
suffix int64
uidGroup [_shard][]int64
um = make(map[int64]struct{}, len(uids))
)
for _, uid := range uids {
suffix = uid % _shard
uidGroup[suffix] = append(uidGroup[suffix], uid)
um[uid] = struct{}{}
}
for index, uids := range uidGroup {
if 0 == len(uids) {
continue
}
rows, err1 := d.expDb.Query(c, fmt.Sprintf(_inSelExp, index, xstr.JoinInts(uids)))
if err1 != nil {
err = err1
log.Error("[dao.exp|MultiExp] d.exp.Query err: %v", err)
return
}
for rows.Next() {
ele := &model.Exp{}
if err = rows.Scan(&ele.Uid, &ele.Uexp, &ele.Rexp); err != nil {
log.Error("[dao.exp|MultiExp] rows.Scan err: %v", err)
return
}
exps = append(exps, ele)
delete(um, ele.Uid)
}
}
// 初始化不存在的数据,补齐数据
for uid := range um {
d.InitExp(c, uid, 0, 0)
ele := &model.Exp{Uid: uid, Uexp: 0, Rexp: 0}
exps = append(exps, ele)
}
return
}
// AddUexp 添加用户经验
func (d *Dao) AddUexp(c context.Context, uid int64, uexp int64) (affect int64, err error) {
upSQL := fmt.Sprintf(_addUexp, uid%_shard, uexp)
res, err := d.expDb.Exec(c, upSQL, uid, uexp)
if err != nil {
log.Error("db.Exec(%s) error(%v)", upSQL, err)
return
}
return res.RowsAffected()
}
// AddRexp 添加主播经验
func (d *Dao) AddRexp(c context.Context, uid int64, rexp int64) (affect int64, err error) {
upSQL := fmt.Sprintf(_addRexp, uid%_shard, rexp)
res, err := d.expDb.Exec(c, upSQL, uid, rexp)
if err != nil {
log.Error("db.Exec(%s) error(%v)", upSQL, err)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,48 @@
package dao
import (
"context"
"go-common/app/service/live/userexp/model"
"go-common/library/log"
"go-common/library/queue/databus/report"
"go-common/library/time"
)
// consts
const (
LiveUserExpID = 104 //http://info.bilibili.co/pages/viewpage.action?pageId=8731603
)
// AddUserExpLog 加用户等级经验行为日志 is
func (d *Dao) AddUserExpLog(ctx context.Context, expInfo *model.ExpLog) {
d.addLog(ctx, LiveUserExpID, "exp_change", expInfo, "增加用户经验")
}
// AddAnchorExpLog 加主播等级经验行为日志 is
func (d *Dao) AddAnchorExpLog(ctx context.Context, expInfo *model.ExpLog) {
d.addLog(ctx, LiveUserExpID, "exp_change", expInfo, "增加主播经验")
}
func (d *Dao) addLog(ctx context.Context, business int, action string, expInfo *model.ExpLog, desc string) {
t := time.Time(expInfo.Ts)
content := make(map[string]interface{}, len(expInfo.Content))
for k, v := range expInfo.Content {
content[k] = v
}
ui := &report.UserInfo{
Mid: expInfo.Mid,
Platform: desc,
Build: 0,
Buvid: expInfo.Buvid,
Business: business,
Type: 0,
Action: action,
Ctime: t.Time(),
IP: expInfo.Ip,
// extra
Index: []interface{}{int64(expInfo.Mid), 0, "", "", ""},
Content: content,
}
report.User(ui)
log.Info("add log to report: userexplog: %+v userinfo: %+v,error(%v)", expInfo, ui)
}

View File

@@ -0,0 +1,75 @@
package dao
import (
"context"
"sync"
"testing"
"time"
"go-common/app/service/live/userexp/conf"
"go-common/library/log"
. "github.com/smartystreets/goconvey/convey"
)
var (
once sync.Once
d *Dao
ctx = context.TODO()
)
func initConf() {
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
}
func startService() {
initConf()
d = New(conf.Conf)
time.Sleep(time.Second * 2)
}
func TestInitExp(t *testing.T) {
Convey("Init Exp", t, func() {
once.Do(startService)
_, err := d.InitExp(ctx, 10001, 0, 0)
So(err, ShouldBeNil)
})
}
func TestExp(t *testing.T) {
Convey("Init Exp", t, func() {
once.Do(startService)
rs, err := d.Exp(ctx, 10001)
So(err, ShouldBeNil)
t.Logf("QueryExp %v", rs)
})
}
func TestMultiExp(t *testing.T) {
Convey("Multi Exp", t, func() {
once.Do(startService)
rs, err := d.MultiExp(ctx, []int64{10001, 10002})
So(err, ShouldBeNil)
t.Logf("QueryExp rs=%v", rs)
})
}
func TestAddUexp(t *testing.T) {
Convey("Add Uexp", t, func() {
once.Do(startService)
_, err := d.AddUexp(ctx, 10001, 111)
So(err, ShouldBeNil)
})
}
func TestAddRexp(t *testing.T) {
Convey("Add Uexp", t, func() {
once.Do(startService)
_, err := d.AddRexp(ctx, 11111, 111)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,109 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/live/userexp/model"
mc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_expKey = "level:%d"
)
func key(uid int64) string {
return fmt.Sprintf(_expKey, uid)
}
// LevelCache 获取等级缓存
func (d *Dao) LevelCache(c context.Context, uid int64) (level *model.Level, err error) {
key := key(uid)
conn := d.expMc.Get(c)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
log.Error("[dao.mc_exp|LevelCache] conn.Get(%s) error(%v)", key, err)
return
}
level = &model.Level{}
if err = conn.Scan(r, level); err != nil {
log.Error("[dao.mc_exp|LevelCache] conn.Scan(%s) error(%v)", string(r.Value), err)
}
return
}
// SetLevelCache 设置等级缓存
func (d *Dao) SetLevelCache(c context.Context, level *model.Level) (err error) {
key := key(level.Uid)
conn := d.expMc.Get(c)
defer conn.Close()
if conn.Set(&mc.Item{
Key: key,
Object: level,
Flags: mc.FlagProtobuf,
Expiration: d.cacheExpire,
}); err != nil {
log.Error("[dao.mc_exp|SetLevelCache] conn.Set(%s, %v) error(%v)", key, level, err)
}
return
}
// DelLevelCache 删除等级缓存
func (d *Dao) DelLevelCache(c context.Context, uid int64) (err error) {
key := key(uid)
conn := d.expMc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err == mc.ErrNotFound {
err = nil
} else if err != nil {
log.Error("[dao.mc_exp|DelLevelCache] conn.Delete(%s) error(%v)", key, err)
}
return
}
// MultiLevelCache 批量获取等级缓存
func (d *Dao) MultiLevelCache(c context.Context, uids []int64) (level []*model.Level, missed []int64, err error) {
var keys []string
var um = make(map[int64]struct{}, len(uids))
for _, uid := range uids {
keys = append(keys, key(uid))
um[uid] = struct{}{}
}
conn := d.expMc.Get(c)
defer conn.Close()
r, err := conn.GetMulti(keys)
if err != nil {
log.Error("[dao.mc_exp|MultiLevelCache] conn.GetMulti error(%v)", err)
return
}
// 命中列表
for _, v := range r {
ele := &model.Level{}
if err = conn.Scan(v, ele); err != nil {
log.Error("[dao.mc_exp|MultiLevelCache] conn.Scan error(%v)", err)
return
}
level = append(level, ele)
delete(um, ele.Uid)
}
// MISS列表
if len(level) != 0 {
for uid := range um {
missed = append(missed, uid)
}
} else {
missed = uids
}
return
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"testing"
"go-common/app/service/live/userexp/model"
)
func TestLevelCache(t *testing.T) {
once.Do(startService)
rs, err := d.LevelCache(ctx, 10001)
if err != nil {
t.Error("d.LevelCache err:", err.Error())
} else {
t.Logf("LevelCache %v", rs)
}
}
func TestSetLevelCache(t *testing.T) {
once.Do(startService)
err := d.SetLevelCache(ctx, &model.Level{Uid: 10001, Uexp: 1000, Rexp: 100, Ulevel: 2, Rlevel: 1, Color: 12345})
if err != nil {
t.Error("d.SetLevelCache err:", err.Error())
} else {
t.Logf("SetLevelCache Succ!")
}
}
func TestDelLevelCache(t *testing.T) {
once.Do(startService)
err := d.DelLevelCache(ctx, 10001)
if err != nil {
t.Error("d.DelLevelCache err:", err.Error())
} else {
t.Logf("DelLevelCache Succ!")
}
}
func TestMuitiLevelCache(t *testing.T) {
once.Do(startService)
rs, _, err := d.MultiLevelCache(ctx, []int64{10001, 10002})
if err != nil {
t.Error("d.LevelCache err:", err.Error())
} else {
t.Logf("LevelCache %v", rs)
}
}