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

4
app/service/live/userexp/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
debug
.idea
*.iml
.vscode

View File

@@ -0,0 +1,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/live/userexp/cmd:all-srcs",
"//app/service/live/userexp/conf:all-srcs",
"//app/service/live/userexp/dao:all-srcs",
"//app/service/live/userexp/http:all-srcs",
"//app/service/live/userexp/model:all-srcs",
"//app/service/live/userexp/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,59 @@
### userexp-live service
### Version 1.0.18
> 1. 修正reviewer
### Version 1.0.17
> 1. 修正reviewer
### Version 1.0.16
> 1. 修正reviewer
### Version 1.0.15
> 1. 添加经验变更行为日志
### Version 1.0.14
> 1. saga test
### Version 1.0.13
> 1. saga test
### Version 1.0.12
> 1. saga test
### Version 1.0.11
> 1. owner test
### Version 1.0.10
> 1. owner test
### Version 1.0.9
> 1. 添加db查询开关
### Version 1.0.8
> 1. 测试owner
### Version 1.0.7
> 1. 修复用户负经验
### Version 1.0.6
> 1. 移交owner
### Version 1.0.5
> 1. 临时去除缓存
### Version 1.0.4
> 1. fix context.TODO
> 2. fix db init while add
### Version 1.0.3
> 1. add trace in main
### Version 1.0.2
> 1. fix trace conf
### Version 1.0.1
> 1. 开放addUexp与addRexp的负数校验逻辑兼容老业务
#### Version 1.0.0
> 1. 新增服务模块

View File

@@ -0,0 +1,8 @@
# Owner
xiehaishen
# Author
lidongyang
# Reviewer
xiehaishen

View File

@@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- lidongyang
- xiehaishen
labels:
- live
- service
- service/live/userexp
options:
no_parent_owners: true
reviewers:
- lidongyang
- xiehaishen

View File

@@ -0,0 +1,8 @@
#### userexp-live service
从直播用户服务中抽离出的单元数据模块、负责用户经验查询、存储。
##### 依赖环境
Go 1.7.5或更高版本
##### API文档
TODO example code api

View File

@@ -0,0 +1,43 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["live-userexp-service.toml"],
importpath = "go-common/app/service/live/userexp/cmd",
tags = ["automanaged"],
visibility = ["//visibility:private"],
deps = [
"//app/service/live/userexp/conf:go_default_library",
"//app/service/live/userexp/http:go_default_library",
"//app/service/live/userexp/service:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/syscall:go_default_library",
],
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
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,136 @@
# This is a TOML document. Boom.
version = "1.0.0"
user = "root"
pid = "/tmp/live-userexp-service.pid"
dir = "./"
perf = "0.0.0.0:20101"
family = "live-userexp-service"
[log]
dir = "/data/log/live-userexp-service"
[db]
[db.exp]
addr = "172.16.33.69:3306"
dsn = "live:oWni@ElNs0P0C(dphdj*F1y4@tcp(172.16.33.69:3306)/live_user_exp?timeout=5s&readTimeout=30s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[db.exp.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
expExpire = "3s"
[memcache.exp]
name = "live-userexp-service/exp"
proto = "tcp"
addr = "172.16.33.251:11211"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[bm]
[bm.inner]
addr = "0.0.0.0:8801"
maxListen = 10
timeout = "1s"
[bm.local]
addr = "0.0.0.0:8802"
maxListen = 10
timeout = "1s"
[httpClient]
[httpClient.read]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "1s"
timeout = "4s"
keepAlive = "60s"
timer = 1000
[httpClient.read.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.write]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[httpClient.write.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[app]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
[Report]
key = "2511663d546f1413"
secret = "cde3b480836cc76df3d635470f991caa"
group = "LogUserAction-MainSearch-P"
topic = "LogUserAction-T"
action = "pub"
buffer = 10240
name = "log-user-action/log-sub"
proto = "tcp"
addr = "172.18.33.50:6205"
active = 100
idle = 100
dialTimeout = "200ms"
readTimeout = "200ms"
writeTimeout = "200ms"
idleTimeout = "80s"
[identify]
whiteAccessKey = ""
whiteMid = 0
csrfOn = false
[identify.app]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
[identify.memcache]
name = "go-business/identify"
proto = "tcp"
addr = "172.16.33.251:11211"
active = 5
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify.host]
auth = "http://passport.bilibili.co"
secret = "http://open.bilibili.co"
[identify.httpClient]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "30ms"
timeout = "100ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://open.bilibili.co/api/getsecret" = {timeout = "500ms"}

View File

@@ -0,0 +1,51 @@
package main
import (
"flag"
"go-common/library/queue/databus/report"
"os"
"os/signal"
"time"
"go-common/app/service/live/userexp/conf"
"go-common/app/service/live/userexp/http"
"go-common/app/service/live/userexp/service"
"go-common/library/log"
"go-common/library/net/trace"
"go-common/library/syscall"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
// report
report.InitUser(conf.Conf.Report)
log.Info("live-userexp-service start")
// service init
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
// signal handler
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT, syscall.SIGSTOP)
for {
s := <-c
log.Info("live-userexp-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
time.Sleep(time.Second * 2)
log.Info("live-userexp-service exit")
return
case syscall.SIGHUP:
log.Info("TODO: reload for syscall.SIGHUP")
return
default:
return
}
}
}

View File

@@ -0,0 +1,37 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/live/userexp/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time: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,124 @@
package conf
import (
"errors"
"flag"
"go-common/library/queue/databus"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// Config struct of conf.
type Config struct {
// base
// log
Log *log.Config
// db
DB *DB
// mc
Memcache *Memcache
LevelExpire int32
// http
BM *HTTPServers
// http client
HTTPClient HTTPClient
// app
App *bm.App
// tracer
Tracer *trace.Config
// switch
Switch *ConfigSwitch
// report
Report *databus.Config
}
// ConfigSwitch switch config.
type ConfigSwitch struct {
QueryExp uint64
}
// DB db config.
type DB struct {
Exp *sql.Config
}
// Memcache config
type Memcache struct {
Exp *memcache.Config
ExpExpire time.Duration
}
// HTTPServers Http Servers
type HTTPServers struct {
Inner *bm.ServerConfig
Local *bm.ServerConfig
}
// HTTPClient config
type HTTPClient struct {
Read *bm.ClientConfig
Write *bm.ClientConfig
}
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 event")
}
}()
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
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init int config
func Init() error {
if confPath != "" {
return local()
}
return remote()
}

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)
}
}

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"exp.go",
"http.go",
],
importpath = "go-common/app/service/live/userexp/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/userexp/conf:go_default_library",
"//app/service/live/userexp/model:go_default_library",
"//app/service/live/userexp/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/xstr:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["http_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",
"//app/service/live/userexp/service:go_default_library",
"//library/net/http/blademaster: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,112 @@
package http
import (
"go-common/app/service/live/userexp/conf"
"go-common/app/service/live/userexp/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
"strconv"
)
func level(c *bm.Context) {
uidStr := c.Request.Form.Get("uid")
// check params
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil || uid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(expSvr.Level(c, uid))
}
func multiGetLevel(c *bm.Context) {
uidsStr := c.Request.Form.Get("uids")
// check params
uids, err := xstr.SplitInts(uidsStr)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
levels, err := expSvr.MultiGetLevel(c, uids)
if err != nil {
log.Error("[http.exp|multiGetLevel] expSvr.MultiGetLevel(%v) error(%v)", uids, err)
c.JSON(nil, err)
return
}
levelInfo := make(map[string]*model.Level, len(levels))
for _, v := range levels {
levelInfo[strconv.FormatInt(v.Uid, 10)] = v
}
c.JSON(levelInfo, nil)
}
func addUexp(c *bm.Context) {
uidStr := c.Request.Form.Get("uid")
uexpStr := c.Request.Form.Get("uexp")
var exp *model.Exp
// check params
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil || uid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
uexp, err := strconv.ParseInt(uexpStr, 10, 64)
if err != nil || uexp <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
ric := infocArg(c)
err = expSvr.AddUexp(c, uid, uexp, ric)
if err != nil {
log.Error("[http.exp|addUexp] expSvr.AddUexp1(%u) error(%v)", uid, err)
}
LogSwitch := conf.Conf.Switch
if LogSwitch != nil {
var QueryConfig = conf.Conf.Switch.QueryExp
if QueryConfig == 1 {
exp, err = expSvr.Exp(c, uid)
log.Info("addUexpUpdate uid:%d,Uexp:%d,Uexp:%d,delta:%d", exp.Uid, exp.Uexp, exp.Rexp, uexp)
}
}
err = expSvr.AddUExpLog(c, uid, uexp, exp.Uexp, exp.Rexp, ric)
c.JSON(nil, err)
}
func addRexp(c *bm.Context) {
uidStr := c.Request.Form.Get("uid")
rexpStr := c.Request.Form.Get("rexp")
var exp *model.Exp
// check params
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil || uid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
rexp, err := strconv.ParseInt(rexpStr, 10, 64)
if err != nil || rexp <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
ric := infocArg(c)
err = expSvr.AddRexp(c, uid, rexp, ric)
if err != nil {
log.Error("[http.exp|addRexp] expSvr.AddRexp(%u) error(%v)", uid, err)
}
LogSwitch := conf.Conf.Switch
if LogSwitch != nil {
var QueryConfig = conf.Conf.Switch.QueryExp
if QueryConfig == 1 {
exp, err = expSvr.Exp(c, uid)
log.Info("addRexpUpdate uid:%d,Uexp:%d,Rexp:%d,delta:%d", exp.Uid, exp.Uexp, exp.Rexp, rexp)
}
}
err = expSvr.AddRExpLog(c, uid, rexp, exp.Uexp, exp.Rexp, ric)
c.JSON(nil, err)
}

View File

@@ -0,0 +1,101 @@
package http
import (
"go-common/library/net/metadata"
"net/http"
"go-common/app/service/live/userexp/conf"
"go-common/app/service/live/userexp/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
expSvr *service.Service
)
// Init init account service.
func Init(c *conf.Config, s *service.Service) {
// init service
expSvr = s
// init external router
engineOut := bm.DefaultServer(c.BM.Inner)
innerRouter(engineOut)
// init Inner serve
if err := engineOut.Start(); err != nil {
log.Error("bm.DefaultServer error(%v)", err)
panic(err)
}
engineLocal := bm.DefaultServer(c.BM.Local)
localRouter(engineLocal)
// init Local serve
if err := engineLocal.Start(); err != nil {
log.Error("bm.DefaultServer error(%v)", err)
panic(err)
}
}
// outerRouter init outer router api path.
func innerRouter(e *bm.Engine) {
// init api
e.GET("/monitor/ping", ping)
group := e.Group("/x/internal/liveexp")
{
group.GET("/level/get", level)
group.GET("/level/mulGet", multiGetLevel)
group.GET("/level/addUexp", addUexp)
group.GET("/level/addRexp", addRexp)
}
}
// localRouter init local router.
func localRouter(e *bm.Engine) {
}
// ping check server ok.
func ping(c *bm.Context) {
if err := expSvr.Ping(c); err != nil {
log.Error("live-userexp http service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func infocArg(c *bm.Context) (arg map[string]string) {
var (
ua string
referer string
sid string
req = c.Request
)
ua = req.Header.Get(service.RelInfocUA)
referer = req.Header.Get(service.RelInfocReferer)
sidCookie, err := req.Cookie(service.RelInfocSid)
if err != nil {
//log.Warn("live-userexo infoc get sid failed error(%v)", err)
} else {
sid = sidCookie.Value
}
buvid := req.Header.Get(service.RelInfocHeaderBuvid)
if buvid == "" {
buvidCookie, _ := req.Cookie(service.RelInfocCookieBuvid)
if buvidCookie != nil {
buvid = buvidCookie.Value
}
}
arg = map[string]string{
service.RelInfocIP: metadata.String(c, metadata.RemoteIP),
service.RelInfocReferer: referer,
service.RelInfocSid: sid,
service.RelInfocBuvid: buvid,
service.RelInfocUA: ua,
}
return
}
//func checkHealth(c wctx.Context) {
// _, err := os.Stat(conf.Conf.CheckFile)
// if os.IsNotExist(err) {
// http.Error(c.Response(), http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
// }
// c.Cancel()
//}

View File

@@ -0,0 +1,135 @@
package http
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"sync"
"testing"
"go-common/app/service/live/userexp/conf"
"go-common/app/service/live/userexp/model"
"go-common/app/service/live/userexp/service"
httpx "go-common/library/net/http/blademaster"
)
const (
_getLevelURL = "http://localhost:8801/x/internal/liveexp/level/get"
_multiGetLevelURL = "http://localhost:8801/x/internal/liveexp/level/mulGet"
_addUexpURL = "http://localhost:8801/x/internal/liveexp/level/addUexp"
_addRexpURL = "http://localhost:8801/x/internal/liveexp/level/addRexp"
)
var (
once sync.Once
client *httpx.Client
)
func startHTTP() {
if err := conf.Init(); err != nil {
panic(fmt.Errorf("conf.Init() error(%v)", err))
}
svr := service.New(conf.Conf)
client = httpx.NewClient(conf.Conf.HTTPClient.Read)
Init(conf.Conf, svr)
}
func TestGetLevel(t *testing.T) {
once.Do(startHTTP)
params := url.Values{}
params.Set("uid", "10001")
var err error
var req *http.Request
if req, err = client.NewRequest("GET", _getLevelURL, "127.0.0.1", params); err != nil {
t.Errorf("http.NewRequest(GET, %s) error(%v)", _getLevelURL, err)
t.FailNow()
}
reqURI := req.URL.String()
t.Logf("req uri: %s\n", reqURI)
var res struct {
Code int `json:"code"`
Data *model.Level `json:"data"`
}
if err = client.Do(context.TODO(), req, &res); err != nil {
t.Errorf("client.Do() error(%v)", err)
t.FailNow()
}
str, _ := json.Marshal(res)
t.Logf("res: %+v", string(str))
}
func TestMultiGetLevel(t *testing.T) {
once.Do(startHTTP)
params := url.Values{}
params.Set("uids", "10001,10002,10003")
var err error
var req *http.Request
if req, err = client.NewRequest("GET", _multiGetLevelURL, "127.0.0.1", params); err != nil {
t.Errorf("http.NewRequest(GET, %s) error(%v)", _multiGetLevelURL, err)
t.FailNow()
}
reqURI := req.URL.String()
t.Logf("req uri: %s\n", reqURI)
var res struct {
Code int `json:"code"`
Data map[string]*model.Level `json:"data"`
}
if err = client.Do(context.TODO(), req, &res); err != nil {
t.Errorf("client.Do() error(%v)", err)
t.FailNow()
}
str, _ := json.Marshal(res)
t.Logf("res: %+v", string(str))
}
func TestAddUexp(t *testing.T) {
once.Do(startHTTP)
params := url.Values{}
params.Set("uid", "10001")
params.Set("uexp", "1234")
var err error
var req *http.Request
if req, err = client.NewRequest("GET", _addUexpURL, "127.0.0.1", params); err != nil {
t.Errorf("http.NewRequest(GET, %s) error(%v)", _addUexpURL, err)
t.FailNow()
}
reqURI := req.URL.String()
t.Logf("req uri: %s\n", reqURI)
var res struct {
Code int `json:"code"`
Data string `json:"data"`
}
if err = client.Do(context.TODO(), req, &res); err != nil {
t.Errorf("client.Do() error(%v)", err)
t.FailNow()
}
str, _ := json.Marshal(res)
t.Logf("res: %+v", string(str))
}
func TestAddRexp(t *testing.T) {
once.Do(startHTTP)
params := url.Values{}
params.Set("uid", "10001")
params.Set("rexp", "4321")
var err error
var req *http.Request
if req, err = client.NewRequest("GET", _addRexpURL, "127.0.0.1", params); err != nil {
t.Errorf("http.NewRequest(GET, %s) error(%v)", _addRexpURL, err)
t.FailNow()
}
reqURI := req.URL.String()
t.Logf("req uri: %s\n", reqURI)
var res struct {
Code int `json:"code"`
Data string `json:"data"`
}
if err = client.Do(context.TODO(), req, &res); err != nil {
t.Errorf("client.Do() error(%v)", err)
t.FailNow()
}
str, _ := json.Marshal(res)
t.Logf("res: %+v", string(str))
}

View File

@@ -0,0 +1,53 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
go_library(
name = "go_default_library",
srcs = ["exp.go"],
embed = [":model_go_proto"],
importpath = "go-common/app/service/live/userexp/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
proto_library(
name = "model_proto",
srcs = ["exp.proto"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/service/live/userexp/model",
proto = ":model_proto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["@com_github_gogo_protobuf//gogoproto: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,167 @@
package model
const (
_MasterLevelMax = int32(40)
_UserLevelMax = int32(60)
_ColorLevel1 = int32(9868950)
_ColorLevel2 = int32(6406234)
_ColorLevel3 = int32(5805790)
_ColorLevel4 = int32(9868950)
)
var (
_masterLevelMap = []int64{
0, // 0
5000, // 1
20000, // 2
47000, // 3
92000, // 4
210000, // 5
406000, // 6
716000, // 7
1176000, // 8
1806000, // 9
2716000, // 10
3961000, // 11
5641000, // 12
7881000, // 13
10981000, // 14
15481000, // 15
22681000, // 16
31981000, // 17
44281000, // 18
60281000, // 19
81681000, // 20
113881000, // 21
159481000, // 22
221481000, // 23
300481000, // 24
398481000, // 25
522981000, // 26
690981000, // 27
901381000, // 28
1188381000, // 29
1561381000, // 30
2061381000, // 31
2731381000, // 32
3641381000, // 33
4781381000, // 34
6201381000, // 35
7951381000, // 36
9951381000, // 37
12201381000, // 38
14701381000, // 39
}
_userLevelMap = []int64{
100000, // 0
200000, // 1
300000, // 2
400000, // 3
500000, // 4
600000, // 5
700000, // 6
800000, // 7
900000, // 8
1000000, // 9
1800000, // 10
2600000, // 11
3400000, // 12
4200000, // 13
5000000, // 14
6000000, // 15
7000000, // 16
8000000, // 17
9000000, // 18
10000000, // 19
18000000, // 20
26000000, // 21
34000000, // 22
42000000, // 23
50000000, // 24
60000000, // 25
70000000, // 26
80000000, // 27
90000000, // 28
100000000, // 29
110000000, // 30
120000000, // 31
130000000, // 32
140000000, // 33
150000000, // 34
180000000, // 35
210000000, // 36
240000000, // 37
270000000, // 38
300000000, // 39
340000000, // 40
380000000, // 41
420000000, // 42
460000000, // 43
500000000, // 44
550000000, // 45
600000000, // 46
700000000, // 47
800000000, // 48
1000000000, // 49
1200000000, // 50
1400000000, // 51
1600000000, // 52
1800000000, // 53
2000000000, // 54
2200000000, // 55
2400000000, // 56
2600000000, // 57
2800000000, // 58
3000000000, // 59
4000000000, // 60
}
)
// FormatLevel 计算等级
func FormatLevel(exp *Exp) (level *Level) {
level = &Level{Uid: exp.Uid, Uexp: exp.Uexp, Rexp: exp.Rexp, Ulevel: -1, Rlevel: -1, Color: 0}
level.Uid = exp.Uid
level.Uexp = exp.Uexp
level.Rexp = exp.Rexp
// 主播等级
for rlevel, v := range _masterLevelMap {
if exp.Rexp < v {
level.Rlevel = int32(rlevel)
level.Rnext = v - exp.Rexp
break
}
}
if level.Rlevel == -1 {
level.Rlevel = _MasterLevelMax
}
// 用户等级
for ulevel, v := range _userLevelMap {
if exp.Uexp < v {
level.Ulevel = int32(ulevel)
level.Unext = v - exp.Uexp
break
}
}
if level.Ulevel == -1 {
level.Ulevel = _UserLevelMax
}
// 等级颜色
switch {
case level.Ulevel <= 10:
level.Color = _ColorLevel1
case level.Ulevel <= 20:
level.Color = _ColorLevel2
case level.Ulevel <= 40:
level.Color = _ColorLevel3
case level.Ulevel < 50:
level.Color = _ColorLevel4
default:
level.Color = _ColorLevel4
}
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message Exp {
int64 Uid = 1 [(gogoproto.jsontag) = "uid"];
int64 Uexp = 2 [(gogoproto.jsontag) = "uexp"];
int64 Rexp = 3 [(gogoproto.jsontag) = "rexp"];
}
message ExpLog {
int64 mid= 1 [(gogoproto.jsontag) = "mid"];
int64 uexp = 2 [(gogoproto.jsontag) = "uexp"];
int64 rexp = 3 [(gogoproto.jsontag) = "rexp"];
int64 ts = 4 [(gogoproto.jsontag) = "ts"];
string ip = 5 [(gogoproto.jsontag) = "ip"];
string buvid = 6 [(gogoproto.jsontag) = "buvid"];
map<string, string> content = 7 [(gogoproto.jsontag) = "content"];
}
message Level {
int64 Uid = 1 [(gogoproto.jsontag) = "uid"];
int64 Uexp = 2 [(gogoproto.jsontag) = "uexp"];
int64 Rexp = 3 [(gogoproto.jsontag) = "rexp"];
int32 Ulevel = 4 [(gogoproto.jsontag) = "ulevel"];
int32 Rlevel = 5 [(gogoproto.jsontag) = "rlevel"];
int32 Color = 6 [(gogoproto.jsontag) = "color"];
int64 Unext = 7 [(gogoproto.jsontag) = "unext"];
int64 Rnext = 8 [(gogoproto.jsontag) = "rnext"];
}

View File

@@ -0,0 +1,50 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"exp.go",
"infoc.go",
"service.go",
],
importpath = "go-common/app/service/live/userexp/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/userexp/conf:go_default_library",
"//app/service/live/userexp/dao:go_default_library",
"//app/service/live/userexp/model:go_default_library",
"//library/cache:go_default_library",
"//library/log:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["exp_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/live/userexp/conf: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,138 @@
package service
import (
"context"
"go-common/app/service/live/userexp/model"
"go-common/library/log"
"strconv"
"time"
)
// Level 获取目标用户的等级信息
func (s *Service) Level(c context.Context, uid int64) (level *model.Level, err error) {
// 缓存查询
//cacheHealth := true
//level, err = s.dao.LevelCache(c, uid)
//if err != nil {
// // 缓存异常
// log.Error("[service.exp|level] s.dao.LevelCache error(%v)", err)
// cacheHealth = false
//}
//if level != nil && level.Uid != 0 {
// // 命中缓存直接返回
// return
//}
// DB查询
exp, err := s.dao.Exp(c, uid)
if err != nil {
log.Error("[service.exp|level] s.dao.Exp error(%v)", err)
return
}
// 格式化Level结构
level = model.FormatLevel(exp)
//// 写入缓存
//if cacheHealth {
// s.cache.Save(func() {
// s.dao.SetLevelCache(context.TODO(), level)
// })
//}
return
}
// Exp 获取目标用户的经验信息
func (s *Service) Exp(c context.Context, uid int64) (exp *model.Exp, err error) {
exp, err = s.dao.Exp(c, uid)
if err != nil {
log.Error("[service.Exp|level] s.dao.Exp error(%v)", err)
return
}
return
}
// MultiGetLevel 批量获取用户等级信息
func (s *Service) MultiGetLevel(c context.Context, uids []int64) (level []*model.Level, err error) {
// 缓存查询
//cacheHealth := true
//level, missUids, err := s.dao.MultiLevelCache(c, uids)
//if err != nil {
// // 缓存异常
// log.Error("[service.exp|MultiGetLevel] s.dao.MultiGetLevel error(%v)", err)
// cacheHealth = false
//} else if len(missUids) == 0 {
// // 缓存全命中直接返回
// return
//}
// DB查询
exps, err := s.dao.MultiExp(c, uids)
if err != nil {
log.Error("[service.exp|MultiGetLevel] s.dao.Exp error(%v)", err)
return
}
for _, exp := range exps {
// 格式化Level结构
lv := model.FormatLevel(exp)
//// 写入缓存
//if cacheHealth {
// s.cache.Save(func() {
// s.dao.SetLevelCache(c, lv)
// })
//}
// 追加数据
level = append(level, lv)
}
return
}
// AddUexp 添加主播经验
func (s *Service) AddUexp(c context.Context, uid int64, uexp int64, ric map[string]string) (err error) {
_, err = s.dao.AddUexp(c, uid, uexp)
return
}
func (s *Service) AddUExpLog(c context.Context, uid int64, uexp int64, nowuexp int64, nowrexp int64, ric map[string]string) (err error) {
logParams := &model.ExpLog{
Mid: uid,
Uexp: uexp,
Rexp: 0,
Ts: time.Now().Unix(),
Ip: ric[RelInfocIP],
Content: map[string]string{
"type": "增加用户经验",
"add_num": strconv.FormatInt(uexp, 10),
"uexp": strconv.FormatInt(nowuexp, 10),
"rexp": strconv.FormatInt(nowrexp, 10),
},
}
s.dao.AddUserExpLog(c, logParams)
return
}
func (s *Service) AddRExpLog(c context.Context, uid int64, rexp int64, nowuexp int64, nowrexp int64, ric map[string]string) (err error) {
logParams := &model.ExpLog{
Mid: uid,
Uexp: 0,
Rexp: rexp,
Ts: time.Now().Unix(),
Ip: ric[RelInfocIP],
Content: map[string]string{
"type": "增加主播经验",
"add_num": strconv.FormatInt(rexp, 10),
"uexp": strconv.FormatInt(nowuexp, 10),
"rexp": strconv.FormatInt(nowrexp, 10),
},
}
s.dao.AddAnchorExpLog(c, logParams)
return
}
// AddRexp 添加用户经验
func (s *Service) AddRexp(c context.Context, uid int64, rexp int64, ric map[string]string) (err error) {
_, err = s.dao.AddRexp(c, uid, rexp)
return
}

View File

@@ -0,0 +1,47 @@
package service
import (
"context"
"fmt"
"sync"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/service/live/userexp/conf"
)
var (
once sync.Once
s *Service
ctx = context.TODO()
)
func startService() {
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
s = New(conf.Conf)
}
func TestGetLevel(t *testing.T) {
Convey("GetLevel", t, func() {
once.Do(startService)
time.Sleep(time.Second)
level, err := s.Level(ctx, 10001)
So(err, ShouldBeNil)
t.Logf("level:%v", level)
})
}
func TestMultiGetLevel(t *testing.T) {
Convey("MultiGetLevel", t, func() {
once.Do(startService)
time.Sleep(time.Second)
level, err := s.MultiGetLevel(ctx, []int64{10001, 20002, 30003})
So(err, ShouldBeNil)
t.Logf("level:%v", level)
})
}

View File

@@ -0,0 +1,18 @@
package service
const (
// RelInfocIP map key string
RelInfocIP = "ip"
// RelInfocSid RelInfocSid
RelInfocSid = "sid"
// RelInfocBuvid RelInfocBuvid
RelInfocBuvid = "buvid"
// RelInfocHeaderBuvid RelInfocHeaderBuvid
RelInfocHeaderBuvid = "Buvid"
// RelInfocCookieBuvid RelInfocCookieBuvid
RelInfocCookieBuvid = "buvid3"
// RelInfocReferer RelInfocReferer
RelInfocReferer = "Referer"
// RelInfocUA RelInfocUA
RelInfocUA = "User-Agent"
)

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"go-common/app/service/live/userexp/conf"
"go-common/app/service/live/userexp/dao"
"go-common/library/cache"
)
// Service http service
type Service struct {
c *conf.Config
keys map[string]string
dao *dao.Dao
cache *cache.Cache
}
// New for new service obj
func New(c *conf.Config) *Service {
s := &Service{
c: c,
keys: map[string]string{},
dao: dao.New(c),
cache: cache.New(1, 1024),
}
return s
}
// Ping check server ok
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close dao
func (s *Service) Close() {
s.dao.Close()
}