refactor: 礼物功能,优化用户获取逻辑,优化排行榜逻辑,优化调用逻辑,优化结构。

main
NorthLan 3 years ago
parent 310a2dcb5c
commit 0e7b79a083

@ -2,7 +2,8 @@
@echo ?????????????? @echo ??????????????
::set tables=user,user_platform ::set tables=user,user_platform
set tables=rank_pvp ::set tables=rank_pvp
set tables=gift
set targetDir=.\model set targetDir=.\model
set templateDir=..\..\doc\template set templateDir=..\..\doc\template

@ -0,0 +1,67 @@
package model
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"gorm.io/gorm"
)
var _ GiftModel = (*customGiftModel)(nil)
type (
// GiftModel is an interface to be customized, add more methods here,
// and implement the added methods in customGiftModel.
GiftModel interface {
giftModel
// Transaction 开启事务,传入方法即可
Transaction(ctx context.Context, tx *gorm.DB, fn func(tx *gorm.DB) error) error
// InsertTx 事务插入
InsertTx(ctx context.Context, tx *gorm.DB, data *Gift) error
// UpdateTx 事务更新
UpdateTx(ctx context.Context, tx *gorm.DB, data *Gift) error
FindByPlatformGift(ctx context.Context, platform string, giftId string) (*Gift, error)
}
customGiftModel struct {
*defaultGiftModel
}
)
// NewGiftModel returns a model for the database table.
func NewGiftModel(conn *gorm.DB) GiftModel {
return &customGiftModel{
defaultGiftModel: newGiftModel(conn),
}
}
func (m *customGiftModel) Transaction(ctx context.Context, tx *gorm.DB, fn func(tx *gorm.DB) error) error {
return withTx(ctx, m.conn, tx).Transaction(func(tx *gorm.DB) error {
return fn(tx)
})
}
func (m *customGiftModel) InsertTx(ctx context.Context, tx *gorm.DB, data *Gift) error {
err := withTx(ctx, m.conn, tx).Create(&data).Error
return err
}
func (m *customGiftModel) UpdateTx(ctx context.Context, tx *gorm.DB, data *Gift) error {
err := withTx(ctx, m.conn, tx).Save(data).Error
return err
}
func (m *customGiftModel) FindByPlatformGift(ctx context.Context, platform string, giftId string) (*Gift, error) {
var resp Gift
db := m.conn.WithContext(ctx)
err := db.Model(&Gift{}).
Where("platform = ? AND gift_id = ?", platform, giftId).
Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}

@ -0,0 +1,81 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"time"
"gorm.io/gorm"
)
type (
giftModel interface {
Insert(ctx context.Context, data *Gift) error
FindOne(ctx context.Context, id int64) (*Gift, error)
Update(ctx context.Context, data *Gift) error
Delete(ctx context.Context, id int64) error
}
defaultGiftModel struct {
conn *gorm.DB
table string
}
Gift struct {
Id int64 `gorm:"column:id;primaryKey"` // 主键
GiftId string `gorm:"column:gift_id"` // 礼物ID不同平台可能类型都不同用varchar
GiftName string `gorm:"column:gift_name"` // 礼物名
Platform string `gorm:"column:platform"` // 平台
PPriceFree int64 `gorm:"column:p_price_free"` // 平台免费价值单价B站: 银瓜子虎牙: 银豆
Price float64 `gorm:"column:price"` // 转换后的礼物价值1RMB:1000(p)
CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间
PPricePaid int64 `gorm:"column:p_price_paid"` // 平台收费价值单价B站: 金瓜子虎牙: 金豆
}
)
func newGiftModel(conn *gorm.DB) *defaultGiftModel {
return &defaultGiftModel{
conn: conn,
table: "`gift`",
}
}
func (m *defaultGiftModel) Insert(ctx context.Context, data *Gift) error {
err := m.conn.WithContext(ctx).Create(&data).Error
return err
}
func (m *defaultGiftModel) FindOne(ctx context.Context, id int64) (*Gift, error) {
var resp Gift
err := m.conn.WithContext(ctx).Model(&Gift{}).Where("`id` = ?", id).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultGiftModel) Update(ctx context.Context, data *Gift) error {
err := m.conn.WithContext(ctx).Save(data).Error
return err
}
func (m *defaultGiftModel) Delete(ctx context.Context, id int64) error {
err := m.conn.WithContext(ctx).Delete(&Gift{}, id).Error
return err
}
func (m *defaultGiftModel) tableName() string {
return m.table
}
func (Gift) TableName() string {
model := newGiftModel(nil)
return model.tableName()
}

@ -5,21 +5,11 @@ package model
import ( import (
"context" "context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc" "git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"strings"
"time" "time"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stringx"
"gorm.io/gorm" "gorm.io/gorm"
) )
var (
rankPvpFieldNames = builder.RawFieldNames(&RankPvp{})
rankPvpRows = strings.Join(rankPvpFieldNames, ",")
rankPvpRowsExpectAutoSet = strings.Join(stringx.Remove(rankPvpFieldNames, "`create_time`", "`update_time`"), ",")
rankPvpRowsWithPlaceHolder = strings.Join(stringx.Remove(rankPvpFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
)
type ( type (
rankPvpModel interface { rankPvpModel interface {
Insert(ctx context.Context, data *RankPvp) error Insert(ctx context.Context, data *RankPvp) error

@ -145,16 +145,17 @@ func (m *customStatisticsPvpModel) FindGreaterByScore(ctx context.Context, score
limit = MaxRankN limit = MaxRankN
} }
whereSql := fmt.Sprintf("%s.%s >= %d", m.table, scoreType, score) whereSql := fmt.Sprintf("%s.%s >= ?", m.table, scoreType)
// 0 不入榜 // 0 不入榜
if score == 0 { if score == 0 {
whereSql = fmt.Sprintf("%s.%s > %d", m.table, scoreType, score) whereSql = fmt.Sprintf("%s.%s > ?", m.table, scoreType)
} }
whereSql = fmt.Sprintf("%s AND user_id > 0", whereSql)
var result []UserAndScore var result []UserAndScore
err := db.Table(m.table). err := db.Table(m.table).
Select(fmt.Sprintf("%s.user_id, %s.%s AS score", m.table, m.table, scoreType)). Select(fmt.Sprintf("%s.user_id, %s.%s AS score", m.table, m.table, scoreType)).
Where(fmt.Sprintf("%s AND user_id > 0", whereSql)). Where(whereSql, score).
Order("score desc"). Order(fmt.Sprintf("%s.%s desc", m.table, scoreType)).
Limit(limit).Find(&result).Error Limit(limit).Find(&result).Error
switch err { switch err {
case nil: case nil:

@ -5,21 +5,11 @@ package model
import ( import (
"context" "context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc" "git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"strings"
"time" "time"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stringx"
"gorm.io/gorm" "gorm.io/gorm"
) )
var (
statisticsPvpFieldNames = builder.RawFieldNames(&StatisticsPvp{})
statisticsPvpRows = strings.Join(statisticsPvpFieldNames, ",")
statisticsPvpRowsExpectAutoSet = strings.Join(stringx.Remove(statisticsPvpFieldNames, "`create_time`", "`update_time`"), ",")
statisticsPvpRowsWithPlaceHolder = strings.Join(stringx.Remove(statisticsPvpFieldNames, "`user_id`", "`create_time`", "`update_time`"), "=?,") + "=?"
)
type ( type (
statisticsPvpModel interface { statisticsPvpModel interface {
Insert(ctx context.Context, data *StatisticsPvp) error Insert(ctx context.Context, data *StatisticsPvp) error

@ -0,0 +1,26 @@
package model
import (
"gorm.io/gorm"
)
var _ UserGiftModel = (*customUserGiftModel)(nil)
type (
// UserGiftModel is an interface to be customized, add more methods here,
// and implement the added methods in customUserGiftModel.
UserGiftModel interface {
userGiftModel
}
customUserGiftModel struct {
*defaultUserGiftModel
}
)
// NewUserGiftModel returns a model for the database table.
func NewUserGiftModel(conn *gorm.DB) UserGiftModel {
return &customUserGiftModel{
defaultUserGiftModel: newUserGiftModel(conn),
}
}

@ -0,0 +1,83 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"time"
"gorm.io/gorm"
)
type (
userGiftModel interface {
Insert(ctx context.Context, data *UserGift) error
FindOne(ctx context.Context, id int64) (*UserGift, error)
Update(ctx context.Context, data *UserGift) error
Delete(ctx context.Context, id int64) error
}
defaultUserGiftModel struct {
conn *gorm.DB
table string
}
UserGift struct {
Id int64 `gorm:"column:id;primaryKey"` // 主键ID
UserId int64 `gorm:"column:user_id"` // 用户ID
Platform string `gorm:"column:platform"` // 直播平台使用varchar兼容更多平台
RoomId string `gorm:"column:room_id"` // 直播间ID使用varchar兼容更多平台
GiftId string `gorm:"column:gift_id"` // 礼物ID使用varchar兼容更多平台
GiftName string `gorm:"column:gift_name"` // 礼物名称
Price int64 `gorm:"column:price"` // 价值(收费礼物,平台货币)
FreePrice int64 `gorm:"column:free_price"` // 价值(免费)
Num int64 `gorm:"column:num"` // 单次送礼数量
CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间
}
)
func newUserGiftModel(conn *gorm.DB) *defaultUserGiftModel {
return &defaultUserGiftModel{
conn: conn,
table: "`user_gift`",
}
}
func (m *defaultUserGiftModel) Insert(ctx context.Context, data *UserGift) error {
err := m.conn.WithContext(ctx).Create(&data).Error
return err
}
func (m *defaultUserGiftModel) FindOne(ctx context.Context, id int64) (*UserGift, error) {
var resp UserGift
err := m.conn.WithContext(ctx).Model(&UserGift{}).Where("`id` = ?", id).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserGiftModel) Update(ctx context.Context, data *UserGift) error {
err := m.conn.WithContext(ctx).Save(data).Error
return err
}
func (m *defaultUserGiftModel) Delete(ctx context.Context, id int64) error {
err := m.conn.WithContext(ctx).Delete(&UserGift{}, id).Error
return err
}
func (m *defaultUserGiftModel) tableName() string {
return m.table
}
func (UserGift) TableName() string {
model := newUserGiftModel(nil)
return model.tableName()
}

@ -0,0 +1,76 @@
package model
import (
"context"
"fmt"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"github.com/pkg/errors"
"gorm.io/gorm"
)
var _ UserIntegralModel = (*customUserIntegralModel)(nil)
type (
// UserIntegralModel is an interface to be customized, add more methods here,
// and implement the added methods in customUserIntegralModel.
UserIntegralModel interface {
userIntegralModel
Transact(ctx context.Context, tx *gorm.DB, fn func(tx *gorm.DB) error) error
InsertTx(ctx context.Context, tx *gorm.DB, data *UserIntegral) error
UpdateIntegralTx(ctx context.Context, tx *gorm.DB, userId, addon int64) error
FindIntegral(ctx context.Context, tx *gorm.DB, userId int64) (int64, error)
}
customUserIntegralModel struct {
*defaultUserIntegralModel
}
)
// NewUserIntegralModel returns a model for the database table.
func NewUserIntegralModel(conn *gorm.DB) UserIntegralModel {
return &customUserIntegralModel{
defaultUserIntegralModel: newUserIntegralModel(conn),
}
}
func (m *customUserIntegralModel) Transact(ctx context.Context, tx *gorm.DB, fn func(tx *gorm.DB) error) error {
return withTx(ctx, m.conn, tx).Transaction(fn)
}
func (m *customUserIntegralModel) InsertTx(ctx context.Context, tx *gorm.DB, data *UserIntegral) error {
err := withTx(ctx, m.conn, tx).Create(&data).Error
return err
}
func (m *customUserIntegralModel) UpdateIntegralTx(ctx context.Context, tx *gorm.DB, userId, change int64) error {
if change < 0 {
return errors.New("无法将积分更新至负数")
}
db := withTx(ctx, m.conn, tx)
result := db.Table(m.table).
Where("user_id = ?", userId).
Update("integral", change)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return ErrRowsAffectedZero
}
return nil
}
func (m *customUserIntegralModel) FindIntegral(ctx context.Context, tx *gorm.DB, userId int64) (int64, error) {
var resp int64
err := withTx(ctx, m.conn, tx).Table(m.table).
Select(fmt.Sprintf("%s.integral", m.table)).
Where("user_id = ?", userId).Take(&resp).Error
switch err {
case nil:
return resp, nil
case gormc.ErrNotFound:
return 0, ErrNotFound
default:
return 0, err
}
}

@ -0,0 +1,77 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"time"
"gorm.io/gorm"
)
type (
userIntegralModel interface {
Insert(ctx context.Context, data *UserIntegral) error
FindOne(ctx context.Context, integral int64) (*UserIntegral, error)
Update(ctx context.Context, data *UserIntegral) error
Delete(ctx context.Context, integral int64) error
}
defaultUserIntegralModel struct {
conn *gorm.DB
table string
}
UserIntegral struct {
UserId int64 `gorm:"column:user_id;primaryKey"` // 用户ID
Integral int64 `gorm:"column:integral"` // 用户积分1 RMB1000
CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间
UpdateTime time.Time `gorm:"column:update_time;default:null"` // 更新时间
}
)
func newUserIntegralModel(conn *gorm.DB) *defaultUserIntegralModel {
return &defaultUserIntegralModel{
conn: conn,
table: "`user_integral`",
}
}
func (m *defaultUserIntegralModel) Insert(ctx context.Context, data *UserIntegral) error {
err := m.conn.WithContext(ctx).Create(&data).Error
return err
}
func (m *defaultUserIntegralModel) FindOne(ctx context.Context, integral int64) (*UserIntegral, error) {
var resp UserIntegral
err := m.conn.WithContext(ctx).Model(&UserIntegral{}).Where("`integral` = ?", integral).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserIntegralModel) Update(ctx context.Context, data *UserIntegral) error {
err := m.conn.WithContext(ctx).Save(data).Error
return err
}
func (m *defaultUserIntegralModel) Delete(ctx context.Context, integral int64) error {
err := m.conn.WithContext(ctx).Delete(&UserIntegral{}, integral).Error
return err
}
func (m *defaultUserIntegralModel) tableName() string {
return m.table
}
func (UserIntegral) TableName() string {
model := newUserIntegralModel(nil)
return model.tableName()
}

@ -0,0 +1,26 @@
package model
import (
"gorm.io/gorm"
)
var _ UserNobilityModel = (*customUserNobilityModel)(nil)
type (
// UserNobilityModel is an interface to be customized, add more methods here,
// and implement the added methods in customUserNobilityModel.
UserNobilityModel interface {
userNobilityModel
}
customUserNobilityModel struct {
*defaultUserNobilityModel
}
)
// NewUserNobilityModel returns a model for the database table.
func NewUserNobilityModel(conn *gorm.DB) UserNobilityModel {
return &customUserNobilityModel{
defaultUserNobilityModel: newUserNobilityModel(conn),
}
}

@ -0,0 +1,83 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"time"
"gorm.io/gorm"
)
const (
TableNameUserNobility = "`user_nobility`"
)
type (
userNobilityModel interface {
Insert(ctx context.Context, data *UserNobility) error
FindOne(ctx context.Context, userId int64) (*UserNobility, error)
Update(ctx context.Context, data *UserNobility) error
Delete(ctx context.Context, userId int64) error
}
defaultUserNobilityModel struct {
conn *gorm.DB
table string
}
UserNobility struct {
UserId int64 `gorm:"column:user_id;primaryKey"` // 用户ID
NobilityLevel int64 `gorm:"column:nobility_level"` // 贵族等级0表示非贵族
Forever BitBool `gorm:"forever"` // 是否永久贵族
StartTime time.Time `gorm:"start_time"` // 开始时间
EndTime time.Time `gorm:"end_time"` // 结束时间
CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间
UpdateTime time.Time `gorm:"column:update_time;default:null"` // 更新时间
}
)
func newUserNobilityModel(conn *gorm.DB) *defaultUserNobilityModel {
return &defaultUserNobilityModel{
conn: conn,
table: TableNameUserNobility,
}
}
func (m *defaultUserNobilityModel) Insert(ctx context.Context, data *UserNobility) error {
err := m.conn.WithContext(ctx).Create(&data).Error
return err
}
func (m *defaultUserNobilityModel) FindOne(ctx context.Context, userId int64) (*UserNobility, error) {
var resp UserNobility
err := m.conn.WithContext(ctx).Model(&UserNobility{}).Where("`user_id` = ?", userId).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserNobilityModel) Update(ctx context.Context, data *UserNobility) error {
err := m.conn.WithContext(ctx).Save(data).Error
return err
}
func (m *defaultUserNobilityModel) Delete(ctx context.Context, userId int64) error {
err := m.conn.WithContext(ctx).Delete(&UserNobility{}, userId).Error
return err
}
func (m *defaultUserNobilityModel) tableName() string {
return m.table
}
func (UserNobility) TableName() string {
return TableNameUserNobility
}

@ -20,12 +20,18 @@ type (
InsertTx(ctx context.Context, tx *gorm.DB, data *UserPlatform) error InsertTx(ctx context.Context, tx *gorm.DB, data *UserPlatform) error
// FindOneByPlatformAndPUid 查询平台用户 // FindOneByPlatformAndPUid 查询平台用户
FindOneByPlatformAndPUid(ctx context.Context, tx *gorm.DB, platform, pUid string) (*UserPlatform, error) FindOneByPlatformAndPUid(ctx context.Context, tx *gorm.DB, platform, pUid string) (*UserPlatform, error)
// FindFullByPlatform 查询系统用户信息(包括平台用户)
FindFullByPlatform(ctx context.Context, tx *gorm.DB, platform, pUid string) (*FullUser, error)
// FindEmptyList 查询从未更新过平台信息的用户 // FindEmptyList 查询从未更新过平台信息的用户
FindEmptyList(ctx context.Context, num int64) ([]UserPlatform, error) FindEmptyList(ctx context.Context, num int64) ([]UserPlatform, error)
// FindUpdatableList 查询过期需要更新信息的用户 // FindUpdatableList 查询过期需要更新信息的用户
FindUpdatableList(ctx context.Context, duration int64, num int64) ([]UserPlatform, error) FindUpdatableList(ctx context.Context, duration int64, num int64) ([]UserPlatform, error)
// FindOneForRankByUserId 查找用户信息 用于排行榜展示 // FindOneForRankByUserId 查找用户信息 用于排行榜展示
FindOneForRankByUserId(ctx context.Context, uid int64) (*UserPlatformForRank, error) FindOneForRankByUserId(ctx context.Context, uid int64) (*UserPlatformForRank, error)
// UpdateNobilityByPUid 更新贵族数据
UpdateNobilityByPUid(ctx context.Context, pUid int64, nobility int64) error
// FindUserIdByPlatform 根据平台与平台用户ID获取系统用户ID
FindUserIdByPlatform(ctx context.Context, platform, pUid string) (int64, error)
} }
UserPlatformForRank struct { UserPlatformForRank struct {
@ -34,15 +40,17 @@ type (
PAvatar string // 平台用户头像地址 PAvatar string // 平台用户头像地址
} }
FullUser struct {
UserPlatform
UserNobility UserNobility `gorm:"foreignKey:UserId;references:UserId"`
UserIntegral UserIntegral `gorm:"foreignKey:UserId;references:UserId"`
}
customUserPlatformModel struct { customUserPlatformModel struct {
*defaultUserPlatformModel *defaultUserPlatformModel
} }
) )
func (m *customUserPlatformModel) InsertTx(ctx context.Context, tx *gorm.DB, data *UserPlatform) error {
return withTx(ctx, m.conn, tx).Create(data).Error
}
// NewUserPlatformModel returns a model for the database table. // NewUserPlatformModel returns a model for the database table.
func NewUserPlatformModel(conn *gorm.DB) UserPlatformModel { func NewUserPlatformModel(conn *gorm.DB) UserPlatformModel {
return &customUserPlatformModel{ return &customUserPlatformModel{
@ -56,6 +64,10 @@ func (m *customUserPlatformModel) Transaction(ctx context.Context, tx *gorm.DB,
}) })
} }
func (m *customUserPlatformModel) InsertTx(ctx context.Context, tx *gorm.DB, data *UserPlatform) error {
return withTx(ctx, m.conn, tx).Create(data).Error
}
func (m *customUserPlatformModel) FindOneByPlatformAndPUid(ctx context.Context, tx *gorm.DB, platform, pUid string) (*UserPlatform, error) { func (m *customUserPlatformModel) FindOneByPlatformAndPUid(ctx context.Context, tx *gorm.DB, platform, pUid string) (*UserPlatform, error) {
db := withTx(ctx, m.conn, tx) db := withTx(ctx, m.conn, tx)
@ -71,6 +83,24 @@ func (m *customUserPlatformModel) FindOneByPlatformAndPUid(ctx context.Context,
} }
} }
func (m *customUserPlatformModel) FindFullByPlatform(ctx context.Context, tx *gorm.DB, platform, pUid string) (*FullUser, error) {
db := withTx(ctx, m.conn, tx)
var resp FullUser
err := db.
Joins("UserNobility").
Joins("UserIntegral").
Where("platform = ? AND p_uid = ?", platform, pUid).
Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *customUserPlatformModel) FindEmptyList(ctx context.Context, num int64) ([]UserPlatform, error) { func (m *customUserPlatformModel) FindEmptyList(ctx context.Context, num int64) ([]UserPlatform, error) {
var resp []UserPlatform var resp []UserPlatform
err := m.conn.WithContext(ctx). err := m.conn.WithContext(ctx).
@ -119,3 +149,26 @@ func (m *customUserPlatformModel) FindOneForRankByUserId(ctx context.Context, ui
return nil, err return nil, err
} }
} }
func (m *customUserPlatformModel) UpdateNobilityByPUid(ctx context.Context, pUid int64, nobility int64) error {
return m.conn.WithContext(ctx).
Model(&UserPlatform{}).
Where("p_uid", pUid).
Update("p_nobility_level", nobility).Error
}
func (m *customUserPlatformModel) FindUserIdByPlatform(ctx context.Context, platform, pUid string) (int64, error) {
var resp int64
err := m.conn.WithContext(ctx).
Table(m.table).
Select(fmt.Sprintf("%s.user_id", m.table)).
Where("platform = ? AND p_uid = ?", platform, pUid).Take(&resp).Error
switch err {
case nil:
return resp, nil
case gormc.ErrNotFound:
return 0, ErrNotFound
default:
return 0, err
}
}

@ -5,19 +5,13 @@ package model
import ( import (
"context" "context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc" "git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"strings"
"time" "time"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stringx"
"gorm.io/gorm" "gorm.io/gorm"
) )
var ( const (
userPlatformFieldNames = builder.RawFieldNames(&UserPlatform{}) TableNameUserPlatform = "`user_platform`"
userPlatformRows = strings.Join(userPlatformFieldNames, ",")
userPlatformRowsExpectAutoSet = strings.Join(stringx.Remove(userPlatformFieldNames, "`create_time`", "`update_time`"), ",")
userPlatformRowsWithPlaceHolder = strings.Join(stringx.Remove(userPlatformFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
) )
type ( type (
@ -42,6 +36,7 @@ type (
PUname string `gorm:"column:p_uname"` // 平台用户名 PUname string `gorm:"column:p_uname"` // 平台用户名
PInfo string `gorm:"column:p_info"` // 平台用户原始信息(json) PInfo string `gorm:"column:p_info"` // 平台用户原始信息(json)
PAvatar string `gorm:"column:p_avatar"` // 平台用户头像地址 PAvatar string `gorm:"column:p_avatar"` // 平台用户头像地址
PNobilityLevel int32 `gorm:"p_nobility_level"` // 平台贵族等级 根据平台不同等级有所不同,代码逻辑判断 0代表不是贵族
CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间 CreateTime time.Time `gorm:"column:create_time;default:null"` // 创建时间
UpdateTime time.Time `gorm:"column:update_time;default:null"` // 更新时间 UpdateTime time.Time `gorm:"column:update_time;default:null"` // 更新时间
} }
@ -50,7 +45,7 @@ type (
func newUserPlatformModel(conn *gorm.DB) *defaultUserPlatformModel { func newUserPlatformModel(conn *gorm.DB) *defaultUserPlatformModel {
return &defaultUserPlatformModel{ return &defaultUserPlatformModel{
conn: conn, conn: conn,
table: "`user_platform`", table: TableNameUserPlatform,
} }
} }
@ -88,6 +83,5 @@ func (m *defaultUserPlatformModel) tableName() string {
} }
func (UserPlatform) TableName() string { func (UserPlatform) TableName() string {
model := newUserPlatformModel(nil) return TableNameUserPlatform
return model.tableName()
} }

@ -1,9 +1,35 @@
package model package model
import ( import (
"database/sql/driver"
"errors" "errors"
"gorm.io/gorm" "gorm.io/gorm"
) )
var ErrNotFound = gorm.ErrRecordNotFound var ErrNotFound = gorm.ErrRecordNotFound
var ErrRowsAffectedZero = errors.New("RowsAffected zero") var ErrRowsAffectedZero = errors.New("RowsAffected zero")
// BitBool is an implementation of a bool for the MySQL type BIT(1).
// This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT.
type BitBool bool
// Value implements the driver.Valuer interface,
// and turns the BitBool into a bitfield (BIT(1)) for MySQL storage.
func (b BitBool) Value() (driver.Value, error) {
if b {
return []byte{1}, nil
} else {
return []byte{0}, nil
}
}
// Scan implements the sql.Scanner interface,
// and turns the bitfield incoming from MySQL into a BitBool
func (b *BitBool) Scan(src interface{}) error {
v, ok := src.([]byte)
if !ok {
return errors.New("bad []byte type assertion")
}
*b = v[0] == 1
return nil
}

@ -1,20 +1,47 @@
Name: usercenter.rpc Name: usercenter.rpc
ListenOn: 127.0.0.1:30001 ListenOn: 127.0.0.1:30001
Timeout: 5000
Etcd: Etcd:
Hosts: Hosts:
- 127.0.0.1:2379 - 127.0.0.1:2379
Key: usercenter.rpc.dev Key: usercenter.rpc.dev
Timeout: 5000 # default is 2000 Timeout: 5000 # default is 2000
NonBlock: true NonBlock: true
Log:
Mode: console
KeepDays: 7
Level: info
DB: DB:
#DataSource: root:root@tcp(192.168.1.100:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true #DataSource: root:root@tcp(192.168.1.100:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true
DataSource: root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true DataSource: root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true
UserRetriever: UserRetriever:
Enabled: false Enabled: false
UpdateDuration: 720 # 720 hours = 30 Day = 1 Month UpdateDuration: 720 # 720 hours = 30 Day = 1 Month
Cron:
PlatformUser: "0 0/5 * * * ?" # 每隔5分钟执行一次
Nobility: "0 0/10 * * * ?" # 每隔10分钟执行一次
NobilityPlatforms: [ "bilibili" ] # 需要获取贵族的平台列表
Bilibili:
RoomId: 8722013
Mid: 6704420
RoomShortInfoApi: https://api.live.bilibili.com/room/v1/Room/room_init
TopListApi: https://api.live.bilibili.com/guard/topList
Rank: Rank:
Enabled: false
Cron:
Update: "0/10 * * * * ?" # 10s一次
Persistence: "0 0/10 * * * ?" # 10min一次
GiftCollector:
Enabled: true Enabled: true
Log: Platforms: [ "bilibili" ]
Mode: console Cron:
KeepDays: 7 CollectGift: "0 0 0/6 * * ?" # 每隔6小时执行一次
Level: info Integral:
# RMB到积分的转换
RMBToIntegral: 1000
# 平台礼物到RMB的转换
GiftToRMB:
bilibili: 0.001
# 平台免费礼物到积分的转换
FreeToIntegral:
bilibili: 0.0001

@ -1,11 +1,16 @@
Name: usercenter.rpc Name: usercenter.rpc
ListenOn: 127.0.0.1:10001 ListenOn: 127.0.0.1:10001
Timeout: 5000
Etcd: Etcd:
Hosts: Hosts:
- 127.0.0.1:2379 - 127.0.0.1:2379
Key: usercenter.rpc Key: usercenter.rpc
Timeout: 5000 # default is 2000 Timeout: 5000 # default is 2000
NonBlock: true NonBlock: true
Log:
Mode: file
KeepDays: 7
Level: error
DB: DB:
#DataSource: root:root@tcp(192.168.1.100:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true #DataSource: root:root@tcp(192.168.1.100:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true
DataSource: root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true DataSource: root:root@tcp(127.0.0.1:3306)/dmgame?charset=utf8mb4&loc=Asia%2FShanghai&parseTime=true
@ -14,7 +19,3 @@ UserRetriever:
UpdateDuration: 720 # 720 hours = 30 Day = 1 Month UpdateDuration: 720 # 720 hours = 30 Day = 1 Month
Rank: Rank:
Enabled: true Enabled: true
Log:
Mode: file
KeepDays: 7
Level: error

@ -25,10 +25,38 @@ type (
UserRetriever struct { UserRetriever struct {
Enabled bool // 是否开启 Enabled bool // 是否开启
UpdateDuration int64 // 用户信息更新最短间隔 单位 h UpdateDuration int64 // 用户信息更新最短间隔 单位 h
NobilityPlatforms []string // 需要获取贵族的平台
Cron struct {
PlatformUser string
Nobility string
}
Bilibili struct {
RoomId int64 // 直播房间号
Mid int64 `json:",optional"` // 主播UID 不输入就通过API获取
RoomShortInfoApi string // 房间简短信息API
TopListApi string
}
} }
Rank struct { Rank struct {
Enabled bool // 是否开启 Enabled bool // 是否开启
Cron struct {
Update string // 更新榜单
Persistence string // 持久化
}
}
GiftCollector struct {
Enabled bool // 是否开启
Platforms []string // 需搜集的平台
Cron struct {
CollectGift string
}
}
Integral struct {
RMBToIntegral float64 // RMB到积分的转换
GiftToRMB map[string]float64 // 平台礼物到RMB的转换
FreeToIntegral map[string]float64 // 平台免费礼物到积分的转换
} }
} }
) )

@ -0,0 +1,32 @@
package gift
import (
"context"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type UserBuyNobilityLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewUserBuyNobilityLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserBuyNobilityLogic {
return &UserBuyNobilityLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// UserBuyNobility 用户购买贵族
// 1. 记录送礼
// 2. 新增积分
func (l *UserBuyNobilityLogic) UserBuyNobility(in *pb.UserBuyNobilityReq) (*pb.UserBuyNobilityResp, error) {
// TODO 未完成
return &pb.UserBuyNobilityResp{}, nil
}

@ -0,0 +1,91 @@
package gift
import (
"context"
"git.noahlan.cn/northlan/ntools-go/uuid"
"live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/logic/gift_collect"
"live-service/app/user_center/rpc/internal/logic/integral"
"live-service/app/user_center/rpc/internal/logic/platform_user"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"strconv"
"github.com/zeromicro/go-zero/core/logx"
)
type UserSendGiftLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewUserSendGiftLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserSendGiftLogic {
return &UserSendGiftLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// UserSendGift 用户赠送礼物
// 1. 记录用户赠送信息
// 2. 新增用户积分
func (l *UserSendGiftLogic) UserSendGift(in *pb.UserSendGiftReq) (*pb.UserSendGiftResp, error) {
// 首先获取用户id
var err error
sysUser, err := platform_user.NewRetrievePlatformUserLogic(l.ctx, l.svcCtx).RetrievePlatformUser(&pb.PlatformUserReq{
Platform: in.Platform,
PUid: in.PUid,
})
if err != nil {
return nil, err
}
resp := &pb.UserSendGiftResp{
User: sysUser.User,
}
// 记录送礼信息
{
dbUserGift := &model.UserGift{
Id: uuid.NextId(),
UserId: sysUser.User.Id,
Platform: in.Platform,
RoomId: in.RoomId,
GiftId: strconv.FormatInt(in.GiftId, 10),
GiftName: in.GiftName,
Num: in.Num,
}
if in.IsPaid {
dbUserGift.Price = in.Price
} else {
dbUserGift.FreePrice = in.Price
}
if err = l.svcCtx.UserGiftModel.Insert(l.ctx, dbUserGift); err != nil {
l.Logger.Errorf("记录用户[%d]送礼信息 [%d:%s:%d] 失败,操作继续...", sysUser.User.Id, in.GiftId, in.GiftName, in.Num)
}
}
// 积分
{
// 待增加的积分
addonIntegral := calcIntegral(l.svcCtx.Config, in.Platform, in.IsPaid, float64(in.Price), in.Num)
if tmpMap, ok := gift_collect.Service.GetCacheByPlatform(in.Platform); ok {
if tmpData, ok := tmpMap[in.GiftId]; ok {
addonIntegral = calcIntegral(l.svcCtx.Config, in.Platform, tmpData.IsPaid, tmpData.Price, in.Num)
}
}
newIntegral, err := integral.NewChangeIntegralLogic(l.ctx, l.svcCtx).ChangeIntegral(&pb.ChangeIntegralReq{
UserId: sysUser.User.Id,
Change: addonIntegral,
})
if err != nil {
return nil, err
}
resp.Integral = newIntegral
}
return resp, nil
}

@ -0,0 +1,25 @@
package gift
import (
"github.com/shopspring/decimal"
"live-service/app/user_center/rpc/internal/config"
)
func calcIntegral(cfg config.Config, platform string, isPaid bool, price float64, num int64) int64 {
giftToRMBRadio, _ := cfg.Integral.GiftToRMB[platform]
freeToIntegralRadio, _ := cfg.Integral.FreeToIntegral[platform]
rmbToIntegral := cfg.Integral.RMBToIntegral
var newPrice float64
if isPaid {
newPrice = price * giftToRMBRadio
} else {
newPrice = price * freeToIntegralRadio
}
decimal.DivisionPrecision = 2
return decimal.NewFromFloat(newPrice).
Mul(decimal.NewFromInt(num)).
Mul(decimal.NewFromFloat(rmbToIntegral)).
Round(0).IntPart()
}

@ -0,0 +1,83 @@
package gift_collect
import (
"context"
"github.com/robfig/cron/v3"
"github.com/zeromicro/go-zero/core/logx"
pbMq "live-service/app/pb/mq"
"live-service/app/user_center/rpc/internal/svc"
)
var Service *GiftCollector
type (
GiftData struct {
Id int64 // 礼物ID
Name string // 礼物名称
Price float64 // 礼物单价(rmb)
IsPaid bool // 是否收费礼物
}
GiftCollector struct {
ctx context.Context
svcCtx *svc.ServiceContext
cron *cron.Cron
collectorMapper map[string]CollectorFunc
// cacheGift 礼物缓存 platform:giftId:giftData
cacheGift map[string]map[int64]GiftData
logx.Logger
}
CollectorFunc func(ctx context.Context, svcCtx *svc.ServiceContext) (ret map[int64]GiftData, err error)
)
func InitCollector(svcCtx *svc.ServiceContext) {
ctx := context.Background()
Service = &GiftCollector{
ctx: context.Background(),
svcCtx: svcCtx,
cron: cron.New(cron.WithSeconds()),
collectorMapper: map[string]CollectorFunc{
pbMq.Platform_name[int32(pbMq.Platform_bilibili)]: GiftCollectorBilibili,
},
Logger: logx.WithContext(ctx),
}
if !svcCtx.Config.GiftCollector.Enabled {
return
}
Service.startJob()
}
func (c *GiftCollector) startJob() {
cfg := c.svcCtx.Config.GiftCollector
// 先执行一次
c.collectGift(cfg.Platforms...)
_, _ = c.cron.AddFunc(cfg.Cron.CollectGift, func() {
c.collectGift(cfg.Platforms...)
})
c.cron.Start()
}
func (c *GiftCollector) collectGift(platforms ...string) {
for _, platform := range platforms {
if handle, ok := c.collectorMapper[platform]; ok {
ret, err := handle(c.ctx, c.svcCtx)
if err != nil {
// TODO 打印
continue
}
// caching
c.cacheGift[platform] = ret
}
}
}
// GetCacheByPlatform 获取缓存中的礼物信息
func (c *GiftCollector) GetCacheByPlatform(platform string) (map[int64]GiftData, bool) {
data, ok := c.cacheGift[platform]
return data, ok
}

@ -0,0 +1,117 @@
package gift_collect
import (
"context"
"encoding/json"
"git.noahlan.cn/northlan/ntools-go/uuid"
"github.com/pkg/errors"
"gorm.io/gorm"
"io/ioutil"
"live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc"
"net/http"
"strconv"
)
const (
CoinTypeGold = "gold"
CoinTypeSilver = "silver"
)
type (
bilibiliGift struct {
Id int64 `json:"id"` // 礼物ID
Name string `json:"name"` // 礼物名称
Price int64 `json:"price"` // 礼物单价
CoinType string `json:"coin_type"` // 瓜子类型 gold金瓜子 silver银瓜子
}
)
func isPaidGift(coinType string) bool {
if coinType == CoinTypeGold {
return true
}
if coinType == CoinTypeSilver {
return false
}
return false
}
func GiftCollectorBilibili(ctx context.Context, svcCtx *svc.ServiceContext) (ret map[int64]GiftData, err error) {
const platform = "bilibili"
radio, _ := svcCtx.Config.Integral.GiftToRMB[platform]
// 1. 读取API
httpResp, err := http.Get("https://api.live.bilibili.com/xlive/web-room/v1/giftPanel/giftConfig?platform=app")
if err != nil {
return
}
resBody, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return
}
var responseData struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []bilibiliGift `json:"list"`
} `json:"data"`
}
err = json.Unmarshal(resBody, &responseData)
if err != nil {
return
}
// 2. 事务分批入库 限定每次分批入库数量
batchSize := 50
dataLen := len(responseData.Data.List)
batches := dataLen / batchSize
if dataLen%batchSize != 0 {
batches += 1
}
ret = make(map[int64]GiftData)
for i := 0; i < batches; i++ {
// TODO 错误处理
_ = svcCtx.GiftModel.Transaction(ctx, nil, func(tx *gorm.DB) error {
lenJ := (i + 1) * batchSize
if lenJ > dataLen {
lenJ = dataLen
}
for j := i * batchSize; j < lenJ; j++ {
gift := responseData.Data.List[j]
dbGift := &model.Gift{
Id: uuid.NextId(),
GiftId: strconv.FormatInt(gift.Id, 10),
GiftName: gift.Name,
Platform: platform,
}
giftData := GiftData{
Id: gift.Id,
Name: gift.Name,
}
if isPaidGift(gift.CoinType) {
dbGift.PPricePaid = gift.Price
dbGift.Price = float64(gift.Price) * float64(radio)
giftData.IsPaid = true
giftData.Price = dbGift.Price
} else {
dbGift.PPriceFree = gift.Price
giftData.IsPaid = false
giftData.Price = float64(dbGift.PPriceFree)
}
ret[giftData.Id] = giftData
if err = svcCtx.GiftModel.UpdateTx(ctx, tx, dbGift); err != nil {
if errors.Is(err, model.ErrRowsAffectedZero) {
err = nil
_ = svcCtx.GiftModel.InsertTx(ctx, tx, dbGift)
}
}
}
return nil
})
}
return
}

@ -0,0 +1,48 @@
package gift_collect
import (
"fmt"
"testing"
)
func TestA(t *testing.T) {
count := 10
batchSize := 5
batches := 0
if count%batchSize == 0 {
batches = count / batchSize
} else {
batches = count/batchSize + 1
}
for i := 0; i < batches; i++ {
fmt.Println()
fmt.Println(i)
fmt.Println()
lenJ := (i + 1) * batchSize
if lenJ > count {
lenJ = count
}
for j := i * batchSize; j < lenJ; j++ {
fmt.Println(j)
}
}
fmt.Printf("count: %d size: %d batches: %d\n", count, batchSize, batches)
fmt.Printf("求余: %v", count%batchSize)
//data := make([]int, 0, 322)
//for i := 0; i < 322; i++ {
// data = append(data, i)
//}
//
//batchSize := 50
//tmpList := make([]int, 0, batchSize)
//for i, gift := range data {
// tmpList = append(tmpList, gift)
// if (i+1)%batchSize == 0 || (i+1) == len(data) {
// // 一次
// fmt.Printf("%d 次 %+v\n", (i+1)%batchSize, tmpList)
// tmpList = make([]int, 0, batchSize)
// }
//}
}

@ -0,0 +1,74 @@
package integral
import (
"context"
"github.com/pkg/errors"
"gorm.io/gorm"
"live-service/app/user_center/model"
"live-service/common/nerr"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type ChangeIntegralLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewChangeIntegralLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChangeIntegralLogic {
return &ChangeIntegralLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// ChangeIntegral 新增用户积分
func (l *ChangeIntegralLogic) ChangeIntegral(in *pb.ChangeIntegralReq) (*pb.ChangeIntegralResp, error) {
if err := l.svcCtx.UserIntegralModel.Transact(l.ctx, nil, func(tx *gorm.DB) error {
integral, err := l.svcCtx.UserIntegralModel.FindIntegral(l.ctx, tx, in.UserId)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
if in.Change < 0 {
return errors.New("用户积分不足")
}
// 用户积分记录不存在,进行插入
if err = l.svcCtx.UserIntegralModel.InsertTx(l.ctx, tx, &model.UserIntegral{
UserId: in.UserId,
Integral: in.Change,
}); err != nil {
return errors.Wrap(err, "插入用户积分失败")
}
return nil
} else {
return errors.Wrap(err, "获取当前用户积分失败")
}
}
if integral+in.Change < 0 {
return errors.New("用户积分不足")
}
if err = l.svcCtx.UserIntegralModel.UpdateIntegralTx(l.ctx, tx, in.UserId, integral+in.Change); err != nil {
return errors.Wrap(err, "更新用户积分失败")
}
return nil
}); err != nil {
return nil, errors.Wrapf(nerr.NewWithErr(err), "记录积分-事务执行失败, err:%+v", err)
}
// 查询当前用户积分
integral, err := l.svcCtx.UserIntegralModel.FindIntegral(l.ctx, nil, in.UserId)
if err != nil {
return nil, errors.Wrapf(nerr.NewWithMsg("查询用户积分失败"), "查询用户积分失败, err:%+v", err)
}
return &pb.ChangeIntegralResp{
UserId: in.UserId,
Change: in.Change,
Integral: integral,
}, nil
}

@ -0,0 +1,40 @@
package integral
import (
"context"
"github.com/pkg/errors"
"live-service/common/nerr"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserIntegralLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetUserIntegralLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserIntegralLogic {
return &GetUserIntegralLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// GetUserIntegral 获取用户积分
func (l *GetUserIntegralLogic) GetUserIntegral(in *pb.UserIdResp) (*pb.UserIntegralResp, error) {
// 查询当前用户积分
integral, err := l.svcCtx.UserIntegralModel.FindIntegral(l.ctx, nil, in.UserId)
if err != nil {
return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "查询用户积分失败, err:%+v", err)
}
return &pb.UserIntegralResp{
UserId: in.UserId,
Integral: integral,
}, nil
}

@ -0,0 +1,38 @@
package platform_user
import (
"context"
"github.com/pkg/errors"
"live-service/common/nerr"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserIdByPUidLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetUserIdByPUidLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserIdByPUidLogic {
return &GetUserIdByPUidLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// GetUserIdByPUid 通过平台用户id获取系统用户ID
func (l *GetUserIdByPUidLogic) GetUserIdByPUid(in *pb.PlatformUserReq) (*pb.UserIdResp, error) {
sysUserId, err := l.svcCtx.UserPlatformModel.FindUserIdByPlatform(l.ctx, in.Platform, in.PUid)
if err != nil {
return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "获取系统用户ID失败, err:%+v", err)
}
return &pb.UserIdResp{
UserId: sysUserId,
}, nil
}

@ -7,62 +7,94 @@ import (
pbMq "live-service/app/pb/mq" pbMq "live-service/app/pb/mq"
"live-service/app/user_center/model" "live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"strconv"
"time" "time"
) )
// PlatformUser 仅提取需要的部分,其余的json后装到p_info // PlatformUser 仅提取需要的部分,其余的json后装到p_info
type ( type (
PlatformUser struct { PlatformUser struct {
PUid string PUid string // 平台用户ID
PName string PName string // 平台用户名
PAvatar string PAvatar string // 平台头像
PInfo string PInfo string // 平台原始信息
}
// NobilityData 贵族信息
NobilityData struct {
PUid string // 平台用户ID
PAvatar string // 平台用户头像(及时更新贵族头像)
Level int // 贵族等级
} }
UserRetriever struct { UserRetriever struct {
ctx context.Context ctx context.Context
svcCtx *svc.ServiceContext svcCtx *svc.ServiceContext
retrieveMapper map[string]RetrieveFunc // platformRetrieverMapper 平台用户信息获取方法 platform:fn
platformRetrieverMapper map[string]RetrieveFunc
nobilityMapper map[string]NobilityFunc
logx.Logger logx.Logger
} }
) )
type RetrieveFunc func(pUid string) (*PlatformUser, error) type RetrieveFunc func(pUid string) (*PlatformUser, error)
type NobilityFunc func(svcCtx *svc.ServiceContext) ([]NobilityData, error)
func NewUserRetriever(svcCtx *svc.ServiceContext) *UserRetriever { func InitUserRetriever(svcCtx *svc.ServiceContext) {
cfg := svcCtx.Config.UserRetriever
if !cfg.Enabled {
return
}
ctx := context.Background() ctx := context.Background()
result := &UserRetriever{ result := &UserRetriever{
ctx: ctx, ctx: ctx,
svcCtx: svcCtx, svcCtx: svcCtx,
retrieveMapper: map[string]RetrieveFunc{ platformRetrieverMapper: map[string]RetrieveFunc{
pbMq.Platform_name[int32(pbMq.Platform_bilibili)]: RetrieveBilibili, pbMq.Platform_name[int32(pbMq.Platform_bilibili)]: RetrieveBilibili,
}, },
nobilityMapper: map[string]NobilityFunc{
pbMq.Platform_name[int32(pbMq.Platform_bilibili)]: NobilityBilibili,
},
Logger: logx.WithContext(ctx), Logger: logx.WithContext(ctx),
} }
return result result.initJob()
} }
func (r *UserRetriever) retrieveUser(platform, pUid string) *PlatformUser { func (r *UserRetriever) initJob() {
if handle, ok := r.retrieveMapper[platform]; ok { logx.Info("开启用户数据采集服务...")
if p, err := handle(pUid); err != nil {
r.Logger.Errorf("获取平台用户信息错误: err: %s\n", err.Error()) cfg := r.svcCtx.Config.UserRetriever
} else { c := cron.New(cron.WithSeconds())
return p // 获取平台用户信息
_, _ = c.AddFunc(cfg.Cron.PlatformUser, func() {
r.retrievePlatformUser()
})
// 获取主播贵族信息
_, _ = c.AddFunc(cfg.Cron.Nobility, func() {
r.retrieveNobility(cfg.NobilityPlatforms...)
})
c.Start()
}
func (r *UserRetriever) retrieveNobility(platform ...string) {
for _, plat := range platform {
if handle, ok := r.nobilityMapper[plat]; ok {
list, err := handle(r.svcCtx)
if err != nil {
r.Logger.Errorf("获取贵族列表失败, err: %+v\n", err)
return
}
for _, data := range list {
pUid, _ := strconv.ParseInt(data.PUid, 10, 64)
_ = r.svcCtx.UserPlatformModel.UpdateNobilityByPUid(r.ctx, pUid, int64(data.Level))
} }
} }
return &PlatformUser{
PUid: pUid,
PName: "",
PAvatar: "",
PInfo: "{}", // 空json
} }
} }
func (r *UserRetriever) Scheduler() { func (r *UserRetriever) retrievePlatformUser() {
logx.Info("开启用户数据采集服务...")
c := cron.New()
_, _ = c.AddFunc("@every 1s", func() {
var list []model.UserPlatform var list []model.UserPlatform
var err error var err error
if list, err = r.svcCtx.UserPlatformModel.FindEmptyList(r.ctx, 5); err != nil { if list, err = r.svcCtx.UserPlatformModel.FindEmptyList(r.ctx, 5); err != nil {
@ -77,8 +109,6 @@ func (r *UserRetriever) Scheduler() {
} }
r.retrieveList(list) r.retrieveList(list)
} }
})
c.Start()
} }
func (r *UserRetriever) retrieveList(list []model.UserPlatform) { func (r *UserRetriever) retrieveList(list []model.UserPlatform) {
@ -94,3 +124,19 @@ func (r *UserRetriever) retrieveList(list []model.UserPlatform) {
_ = r.svcCtx.UserPlatformModel.Update(r.ctx, &dbModel) _ = r.svcCtx.UserPlatformModel.Update(r.ctx, &dbModel)
} }
} }
func (r *UserRetriever) retrieveUser(platform, pUid string) *PlatformUser {
if handle, ok := r.platformRetrieverMapper[platform]; ok {
if p, err := handle(pUid); err != nil {
r.Logger.Errorf("获取平台用户信息错误: err: %s\n", err.Error())
} else {
return p
}
}
return &PlatformUser{
PUid: pUid,
PName: "",
PAvatar: "",
PInfo: "{}", // 空json
}
}

@ -5,9 +5,12 @@ import (
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"io" "io"
"io/ioutil"
"live-service/app/user_center/rpc/internal/svc"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"time"
) )
type MyProxy struct { type MyProxy struct {
@ -80,3 +83,142 @@ func RetrieveBilibili(pUid string) (*PlatformUser, error) {
return nil, errors.New(resp.Message) return nil, errors.New(resp.Message)
} }
} }
type (
topList struct {
Code int `json:"code"`
Data struct {
Info struct {
Num int `json:"num"`
Page int `json:"page"`
Now int `json:"now"`
} `json:"info"`
List []guardItem `json:"list"`
Top3 []guardItem `json:"top3"`
} `json:"data"`
}
/**
{
"uid": 11309307,
"ruid": 14890801,
"rank": 4,
"username": "288号花店店长",
"face": "http://i0.hdslb.com/bfs/face/b86499c02ed5b02ced46ed82813251bdf61aae60.jpg",
"is_alive": 0,
"guard_level": 2,
"guard_sub_level": 0,
"medal_info": {
"medal_name": "耐久",
"medal_level": 30,
"medal_color_start": 2951253,
"medal_color_end": 10329087,
"medal_color_border": 16771156
}
},
*/
guardItem struct {
Uid int64 `json:"uid"`
Avatar string `json:"face"`
Level int `json:"guard_level"`
}
)
func NobilityBilibili(svcCtx *svc.ServiceContext) ([]NobilityData, error) {
cfg := svcCtx.Config.UserRetriever.Bilibili
if cfg.Mid == 0 {
if mId, err := fetchMid(cfg.RoomShortInfoApi, cfg.RoomId); err != nil {
return nil, err
} else {
cfg.Mid = mId
}
}
if cfg.Mid == 0 {
return nil, errors.New("获取UP主ID失败无法获取舰长信息")
}
// 获取第一页
tl, err := getNobilityByPage(cfg.TopListApi, cfg.RoomId, cfg.Mid, 1)
if err != nil {
return nil, err
}
totalNum := tl.Data.Info.Num
totalPage := tl.Data.Info.Page
result := make([]NobilityData, 0, totalNum)
appendArrFn := func(items []guardItem) {
for _, item := range items {
result = append(result, NobilityData{
PUid: strconv.FormatInt(item.Uid, 10),
PAvatar: item.Avatar,
Level: item.Level,
})
}
}
// 数据小于1页
if totalPage <= 1 {
// num > 3, list 为准, 否则取top3
if totalNum <= 3 {
appendArrFn(tl.Data.Top3)
} else {
appendArrFn(tl.Data.Top3)
}
} else {
// 数据需要翻页 2 -> totalPage
for i := 2; i <= totalPage; i++ {
tl, err = getNobilityByPage(cfg.TopListApi, cfg.RoomId, cfg.Mid, i)
if err != nil {
continue
}
appendArrFn(tl.Data.List)
// 睡眠50ms,暂缓b站封ip
time.Sleep(50 * time.Millisecond)
}
}
return result, nil
}
func fetchMid(api string, roomId int64) (mId int64, err error) {
// 获取mid
httpResp, err := http.Get(fmt.Sprintf("%s?id=%d", api, roomId))
if err != nil {
return
}
res, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return
}
var roomInfo struct {
Code int `json:"code"`
Msg string `json:"msg"`
Message string `json:"message"`
Data struct {
RoomId int64 `json:"room_id"`
Uid int64 `json:"uid"`
} `json:"data"`
}
err = json.Unmarshal(res, &roomInfo)
if err != nil {
return
}
mId = roomInfo.Data.Uid
return
}
func getNobilityByPage(api string, roomId, mId int64, page int) (*topList, error) {
// 获取舰长列表
TopListApiFormat := api + "?roomid=%d&ruid=%d&page=%d"
httpResp, err := http.Get(fmt.Sprintf(TopListApiFormat, roomId, mId, page))
if err != nil {
return nil, err
}
res, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return nil, err
}
var tl topList
err = json.Unmarshal(res, &tl)
if err != nil {
return nil, err
}
return &tl, nil
}

@ -0,0 +1,92 @@
package platform_user
import (
"context"
"git.noahlan.cn/northlan/ntools-go/uuid"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"live-service/common/nerr"
"time"
)
type RetrievePlatformUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewRetrievePlatformUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RetrievePlatformUserLogic {
return &RetrievePlatformUserLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// RetrievePlatformUser 查询或创建用户此时不通过API查询平台用户信息
func (l *RetrievePlatformUserLogic) RetrievePlatformUser(in *pb.PlatformUserReq) (*pb.PlatformUserResp, error) {
var dbFullUser *model.FullUser
var username string
if err := l.svcCtx.UserPlatformModel.Transaction(l.ctx, nil, func(tx *gorm.DB) error {
var err error
if dbFullUser, err = l.svcCtx.UserPlatformModel.FindFullByPlatform(l.ctx, tx, in.Platform, in.PUid); err != nil {
if !errors.Is(err, model.ErrNotFound) {
return nerr.NewWithCode(nerr.DBError)
}
}
if dbFullUser != nil {
if one, err := l.svcCtx.UserModel.FindOneTx(l.ctx, tx, dbFullUser.UserId); err != nil {
username = one.Username
}
return nil
}
// insert
newId := uuid.NextId()
if err := l.svcCtx.UserModel.InsertTx(l.ctx, tx, &model.User{Id: newId}); err != nil {
return errors.Wrap(nerr.NewWithCode(nerr.DBError), "插入用户数据失败")
}
dbPlatformUser := &model.UserPlatform{
Id: uuid.NextId(),
UserId: newId,
Platform: in.Platform,
PUid: in.PUid,
PInfo: "{}",
}
if err := l.svcCtx.UserPlatformModel.InsertTx(l.ctx, tx, dbPlatformUser); err != nil {
return errors.Wrap(nerr.NewWithCode(nerr.DBError), "插入平台用户数据失败")
}
return nil
}); err != nil {
return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "查询或创建用户-事务执行失败, err:%+v", err)
}
return &pb.PlatformUserResp{
User: l.buildPBUser(username, dbFullUser),
}, nil
}
func (l *RetrievePlatformUserLogic) buildPBUser(username string, dbFullUser *model.FullUser) *pb.User {
resp := &pb.User{
Id: dbFullUser.UserId,
Username: username,
Platform: dbFullUser.Platform,
PUid: dbFullUser.PUid,
PUname: dbFullUser.PUname,
PAvatar: dbFullUser.PAvatar,
NobilityLevel: int32(dbFullUser.UserNobility.NobilityLevel),
Integral: dbFullUser.UserIntegral.Integral,
}
// 贵族过期判断
if time.Now().After(dbFullUser.UserNobility.EndTime) {
if !dbFullUser.UserNobility.Forever {
// 贵族过期置为0
resp.NobilityLevel = 0
}
}
return resp
}

@ -67,6 +67,10 @@ func InitRankJob(svcCtx *svc.ServiceContext) {
deFirstBloodRank: zset.NewZSetInt(lessFunc, model.MaxRankN), deFirstBloodRank: zset.NewZSetInt(lessFunc, model.MaxRankN),
userCache: uc, userCache: uc,
} }
if !svcCtx.Config.Rank.Enabled {
return
}
Service.initJob() Service.initJob()
} }
@ -89,80 +93,81 @@ func (j *Job) initJob() {
j.initByType(model.RankTypeFirstBlood) j.initByType(model.RankTypeFirstBlood)
j.initByType(model.RankTypeDeFirstBlood) j.initByType(model.RankTypeDeFirstBlood)
cfg := j.svcCtx.Config.Rank
// job read and update // job read and update
c := cron.New() c := cron.New()
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDamage) j.readAndUpdate(model.RankTypeDamage)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDeDamage) j.readAndUpdate(model.RankTypeDeDamage)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeGeneral) j.readAndUpdate(model.RankTypeGeneral)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDeGeneral) j.readAndUpdate(model.RankTypeDeGeneral)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeKillUnit) j.readAndUpdate(model.RankTypeKillUnit)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDeKillUnit) j.readAndUpdate(model.RankTypeDeKillUnit)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeKillPlayer) j.readAndUpdate(model.RankTypeKillPlayer)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDeKillPlayer) j.readAndUpdate(model.RankTypeDeKillPlayer)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeWin) j.readAndUpdate(model.RankTypeWin)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeLost) j.readAndUpdate(model.RankTypeLost)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeFirstBlood) j.readAndUpdate(model.RankTypeFirstBlood)
}) })
_, _ = c.AddFunc("@every 10s", func() { _, _ = c.AddFunc(cfg.Cron.Update, func() {
j.readAndUpdate(model.RankTypeDeFirstBlood) j.readAndUpdate(model.RankTypeDeFirstBlood)
}) })
// persistence // persistence
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDamage) j.persistence(model.RankTypeDamage)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDeDamage) j.persistence(model.RankTypeDeDamage)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeGeneral) j.persistence(model.RankTypeGeneral)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDeGeneral) j.persistence(model.RankTypeDeGeneral)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeKillUnit) j.persistence(model.RankTypeKillUnit)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDeKillUnit) j.persistence(model.RankTypeDeKillUnit)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeKillPlayer) j.persistence(model.RankTypeKillPlayer)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDeKillPlayer) j.persistence(model.RankTypeDeKillPlayer)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeWin) j.persistence(model.RankTypeWin)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeLost) j.persistence(model.RankTypeLost)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeFirstBlood) j.persistence(model.RankTypeFirstBlood)
}) })
_, _ = c.AddFunc("@every 10m", func() { _, _ = c.AddFunc(cfg.Cron.Persistence, func() {
j.persistence(model.RankTypeDeFirstBlood) j.persistence(model.RankTypeDeFirstBlood)
}) })
c.Start() c.Start()
@ -244,18 +249,18 @@ func (j *Job) readAndUpdate(rankType int32) {
} }
rank := rankZSet.RangeByRank(1, model.MaxRankN) rank := rankZSet.RangeByRank(1, model.MaxRankN)
rankLen := len(rank)
var score int64 var score int64
if len(rank) == 0 { if rankLen == 0 {
score = 0 score = 0
} else { } else {
last := rank[len(rank)-1] // 取当前榜最后一名分数
score = last[1] score = rank[rankLen-1][1]
} }
// 若榜内数量不够,则直接取 max - current 数量的人 score排序一下 // 若榜内数量不够,则直接取 max - len 数量的人 score排序一下
limit := model.MaxRankN limit := model.MaxRankN
if len(rank) < model.MaxRankN { if rankLen < model.MaxRankN {
limit = model.MaxRankN - len(rank) limit = model.MaxRankN - rankLen + 1 // +1是避免取到自己后少取一位
score = 0
} }
// 末位 score // 末位 score

@ -1,83 +0,0 @@
package logic
import (
"context"
"git.noahlan.cn/northlan/ntools-go/uuid"
"github.com/pkg/errors"
"gorm.io/gorm"
"live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb"
"github.com/zeromicro/go-zero/core/logx"
)
type RetrievePlatformUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewRetrievePlatformUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RetrievePlatformUserLogic {
return &RetrievePlatformUserLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// RetrievePlatformUser 查询或创建用户(此时不查询平台用户信息)
func (l *RetrievePlatformUserLogic) RetrievePlatformUser(in *pb.PlatformUserReq) (*pb.PlatformUserResp, error) {
var username string
var dbPlatformUser *model.UserPlatform
err := l.svcCtx.UserPlatformModel.Transaction(l.ctx, nil, func(tx *gorm.DB) error {
var err error
if dbPlatformUser, err = l.svcCtx.UserPlatformModel.FindOneByPlatformAndPUid(l.ctx, tx, in.Platform, in.PUid); err != nil {
if !errors.Is(err, model.ErrNotFound) {
return err
}
}
if dbPlatformUser != nil {
if one, err := l.svcCtx.UserModel.FindOneTx(l.ctx, tx, dbPlatformUser.UserId); err != nil {
username = one.Username
}
return nil
}
// insert
newId := uuid.NextId()
if err := l.svcCtx.UserModel.InsertTx(l.ctx, tx, &model.User{Id: newId}); err != nil {
return errors.Wrap(err, "插入用户数据失败")
}
dbPlatformUser = &model.UserPlatform{
Id: uuid.NextId(),
UserId: newId,
Platform: in.Platform,
PUid: in.PUid,
PInfo: "{}",
}
if err := l.svcCtx.UserPlatformModel.InsertTx(l.ctx, tx, dbPlatformUser); err != nil {
return errors.Wrap(err, "插入平台用户数据失败")
}
return nil
})
if err != nil {
return nil, errors.Wrapf(err, "查询或创建用户-事务执行失败, err:%+v", err)
}
return &pb.PlatformUserResp{
User: l.buildPBUser(username, dbPlatformUser),
}, nil
}
func (l *RetrievePlatformUserLogic) buildPBUser(username string, dbPlatformUser *model.UserPlatform) *pb.User {
return &pb.User{
Id: dbPlatformUser.UserId,
Username: username,
Platform: dbPlatformUser.Platform,
PUid: dbPlatformUser.PUid,
PUname: dbPlatformUser.PUname,
PAvatar: dbPlatformUser.PAvatar,
PInfo: dbPlatformUser.PInfo,
}
}

@ -7,6 +7,7 @@ import (
"live-service/app/user_center/model" "live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
"live-service/common/nerr"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -66,7 +67,7 @@ func (l *StatPvpFirstBloodLogic) StatPvpFirstBlood(in *pb.StatPvPFirstBloodReq)
return nil return nil
}) })
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "一血报送-事务执行失败, err:%+v", err) return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "一血报送-事务执行失败, err:%+v", err)
} }
return &pb.Empty{}, nil return &pb.Empty{}, nil
} }

@ -5,6 +5,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
"live-service/app/user_center/model" "live-service/app/user_center/model"
"live-service/common/nerr"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
@ -78,7 +79,7 @@ func (l *StatPvpKillLogic) StatPvpKill(in *pb.StatPvPKillReq) (*pb.Empty, error)
return nil return nil
}) })
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "击杀玩家-事务执行失败, err:%+v", err) return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "击杀玩家-事务执行失败, err:%+v", err)
} }
return &pb.Empty{}, nil return &pb.Empty{}, nil
} }

@ -8,6 +8,7 @@ import (
"live-service/app/user_center/model" "live-service/app/user_center/model"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
"live-service/common/nerr"
) )
type StatPvpReportLogic struct { type StatPvpReportLogic struct {
@ -58,7 +59,7 @@ func (l *StatPvpReportLogic) StatPvpReport(in *pb.StatPvPReportReq) (*pb.Empty,
}) })
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "PvP战报-事务执行失败 err: %+v", err) return nil, errors.Wrapf(nerr.NewWithCode(nerr.DBError), "PvP战报-事务执行失败 err: %+v", err)
} }
return &pb.Empty{}, nil return &pb.Empty{}, nil
} }

@ -5,10 +5,12 @@ package server
import ( import (
"context" "context"
"live-service/app/user_center/rpc/internal/logic/gift"
"live-service/app/user_center/rpc/internal/logic/integral"
"live-service/app/user_center/rpc/internal/logic/platform_user"
"live-service/app/user_center/rpc/internal/logic/rank" "live-service/app/user_center/rpc/internal/logic/rank"
"live-service/app/user_center/rpc/internal/logic/statistics" "live-service/app/user_center/rpc/internal/logic/statistics"
"live-service/app/user_center/rpc/internal/logic"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
) )
@ -24,13 +26,41 @@ func NewUserCenterServer(svcCtx *svc.ServiceContext) *UserCenterServer {
} }
} }
// user // retrievePlatformUser 新增或获取用户
func (s *UserCenterServer) RetrievePlatformUser(ctx context.Context, in *pb.PlatformUserReq) (*pb.PlatformUserResp, error) { func (s *UserCenterServer) RetrievePlatformUser(ctx context.Context, in *pb.PlatformUserReq) (*pb.PlatformUserResp, error) {
l := logic.NewRetrievePlatformUserLogic(ctx, s.svcCtx) l := platform_user.NewRetrievePlatformUserLogic(ctx, s.svcCtx)
return l.RetrievePlatformUser(in) return l.RetrievePlatformUser(in)
} }
// statistics // getUserIdByPUid 通过平台用户id获取系统用户ID
func (s *UserCenterServer) GetUserIdByPUid(ctx context.Context, in *pb.PlatformUserReq) (*pb.UserIdResp, error) {
l := platform_user.NewGetUserIdByPUidLogic(ctx, s.svcCtx)
return l.GetUserIdByPUid(in)
}
// ChangeIntegral 新增用户积分
func (s *UserCenterServer) ChangeIntegral(ctx context.Context, in *pb.ChangeIntegralReq) (*pb.ChangeIntegralResp, error) {
l := integral.NewChangeIntegralLogic(ctx, s.svcCtx)
return l.ChangeIntegral(in)
}
// GetUserIntegral 获取用户积分
func (s *UserCenterServer) GetUserIntegral(ctx context.Context, in *pb.UserIdResp) (*pb.UserIntegralResp, error) {
l := integral.NewGetUserIntegralLogic(ctx, s.svcCtx)
return l.GetUserIntegral(in)
}
// UserSendGift 用户赠送礼物
func (s *UserCenterServer) UserSendGift(ctx context.Context, in *pb.UserSendGiftReq) (*pb.UserSendGiftResp, error) {
l := gift.NewUserSendGiftLogic(ctx, s.svcCtx)
return l.UserSendGift(in)
}
func (s *UserCenterServer) UserBuyNobility(ctx context.Context, in *pb.UserBuyNobilityReq) (*pb.UserBuyNobilityResp, error) {
l := gift.NewUserBuyNobilityLogic(ctx, s.svcCtx)
return l.UserBuyNobility(in)
}
func (s *UserCenterServer) StatPvpKill(ctx context.Context, in *pb.StatPvPKillReq) (*pb.Empty, error) { func (s *UserCenterServer) StatPvpKill(ctx context.Context, in *pb.StatPvPKillReq) (*pb.Empty, error) {
l := statistics.NewStatPvpKillLogic(ctx, s.svcCtx) l := statistics.NewStatPvpKillLogic(ctx, s.svcCtx)
return l.StatPvpKill(in) return l.StatPvpKill(in)
@ -46,7 +76,7 @@ func (s *UserCenterServer) StatPvpReport(ctx context.Context, in *pb.StatPvPRepo
return l.StatPvpReport(in) return l.StatPvpReport(in)
} }
// rank // rankPvp pvp排行
func (s *UserCenterServer) RankPvp(ctx context.Context, in *pb.RankPvpReq) (*pb.RankPvpResp, error) { func (s *UserCenterServer) RankPvp(ctx context.Context, in *pb.RankPvpReq) (*pb.RankPvpResp, error) {
l := rank.NewRankPvpLogic(ctx, s.svcCtx) l := rank.NewRankPvpLogic(ctx, s.svcCtx)
return l.RankPvp(in) return l.RankPvp(in)

@ -16,8 +16,14 @@ type ServiceContext struct {
UserModel model.UserModel UserModel model.UserModel
UserPlatformModel model.UserPlatformModel UserPlatformModel model.UserPlatformModel
UserGiftModel model.UserGiftModel
UserIntegralModel model.UserIntegralModel
UserNobilityModel model.UserNobilityModel
StatisticsPvpModel model.StatisticsPvpModel StatisticsPvpModel model.StatisticsPvpModel
RankPvpModel model.RankPvpModel RankPvpModel model.RankPvpModel
GiftModel model.GiftModel
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -25,8 +31,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
Logger: logger.New( Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{ logger.Config{
SlowThreshold: 2 * time.Second, SlowThreshold: 5 * time.Second,
LogLevel: logger.Warn, LogLevel: logger.Info,
IgnoreRecordNotFoundError: true, IgnoreRecordNotFoundError: true,
Colorful: true, Colorful: true,
}, },
@ -39,7 +45,11 @@ func NewServiceContext(c config.Config) *ServiceContext {
Config: c, Config: c,
UserModel: model.NewUserModel(gormDb), UserModel: model.NewUserModel(gormDb),
UserPlatformModel: model.NewUserPlatformModel(gormDb), UserPlatformModel: model.NewUserPlatformModel(gormDb),
UserGiftModel: model.NewUserGiftModel(gormDb),
UserIntegralModel: model.NewUserIntegralModel(gormDb),
UserNobilityModel: model.NewUserNobilityModel(gormDb),
StatisticsPvpModel: model.NewStatisticsPvpModel(gormDb), StatisticsPvpModel: model.NewStatisticsPvpModel(gormDb),
RankPvpModel: model.NewRankPvpModel(gormDb), RankPvpModel: model.NewRankPvpModel(gormDb),
GiftModel: model.NewGiftModel(gormDb),
} }
} }

File diff suppressed because it is too large Load Diff

@ -13,7 +13,8 @@ message User {
string pUid = 4; string pUid = 4;
string pUname = 5; string pUname = 5;
string pAvatar = 6; string pAvatar = 6;
string pInfo = 7; int32 nobilityLevel = 7; //
int64 integral = 8; // ()
} }
message Empty {} message Empty {}
@ -28,6 +29,60 @@ message PlatformUserResp {
User user = 1; User user = 1;
} }
message UserIdResp {
int64 userId = 1;
}
message ChangeIntegralReq {
int64 userId = 1; // ID
int64 change = 2; //
}
message ChangeIntegralResp {
int64 userId = 1; // ID
int64 change = 2; //
int64 integral = 3; //
}
message UserIntegralResp {
int64 userId = 1; // ID
int64 integral = 2; //
}
message UserSendGiftReq {
string platform = 1; //
string pUid = 2; // ID
string roomId = 3; // ID
int64 giftId = 4; // ID
string giftName = 5; //
int64 num = 6; //
int64 price = 7; // (使)
bool isPaid = 8; //
}
message UserSendGiftResp {
User user = 1; //
ChangeIntegralResp integral = 10; //
}
message UserBuyNobilityReq {
string platform = 1; //
string pUid = 2; // ID
string roomId = 3; // ID
int64 giftId = 4; // ID
string giftName = 5; //
int64 num = 6; //
int64 price = 7; // (使)
int64 level = 8; //
int64 startTime = 9; //
int64 endTime = 10; //
}
message UserBuyNobilityResp {
User user = 1; //
ChangeIntegralResp integral = 10; //
}
// -PvP( statistics.pvp.kill // -PvP( statistics.pvp.kill
message StatPvPKillReq { message StatPvPKillReq {
int64 uid = 1; // ID int64 uid = 1; // ID
@ -74,14 +129,34 @@ message RankPvpResp {
} }
service userCenter { service userCenter {
// user /// @ZeroGroup: platform_user
// retrievePlatformUser
rpc retrievePlatformUser(PlatformUserReq) returns (PlatformUserResp); rpc retrievePlatformUser(PlatformUserReq) returns (PlatformUserResp);
// getUserIdByPUid idID
rpc getUserIdByPUid(PlatformUserReq) returns (UserIdResp);
/// @ZeroGroup: integral
//ChangeIntegral
rpc ChangeIntegral(ChangeIntegralReq) returns (ChangeIntegralResp);
//GetUserIntegral
rpc GetUserIntegral(UserIdResp) returns (UserIntegralResp);
/// @ZeroGroup: gift
// UserSendGift
rpc userSendGift(UserSendGiftReq) returns(UserSendGiftResp);
rpc userBuyNobility(UserBuyNobilityReq) returns(UserBuyNobilityResp);
/// @ZeroGroup: statistics
// statistics
rpc statPvpKill(StatPvPKillReq) returns (Empty); rpc statPvpKill(StatPvPKillReq) returns (Empty);
rpc statPvpFirstBlood(StatPvPFirstBloodReq) returns (Empty); rpc statPvpFirstBlood(StatPvPFirstBloodReq) returns (Empty);
rpc statPvpReport(StatPvPReportReq) returns (Empty); rpc statPvpReport(StatPvPReportReq) returns (Empty);
// rank /// @ZeroGroup: rank
// rankPvp pvp
rpc rankPvp(RankPvpReq) returns(RankPvpResp); rpc rankPvp(RankPvpReq) returns(RankPvpResp);
} }

@ -22,13 +22,21 @@ const _ = grpc.SupportPackageIsVersion7
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type UserCenterClient interface { type UserCenterClient interface {
// user // retrievePlatformUser 新增或获取用户
RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error) RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error)
// statistics // getUserIdByPUid 通过平台用户id获取系统用户ID
GetUserIdByPUid(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*UserIdResp, error)
//ChangeIntegral 新增用户积分
ChangeIntegral(ctx context.Context, in *ChangeIntegralReq, opts ...grpc.CallOption) (*ChangeIntegralResp, error)
//GetUserIntegral 获取用户积分
GetUserIntegral(ctx context.Context, in *UserIdResp, opts ...grpc.CallOption) (*UserIntegralResp, error)
// UserSendGift 用户赠送礼物
UserSendGift(ctx context.Context, in *UserSendGiftReq, opts ...grpc.CallOption) (*UserSendGiftResp, error)
UserBuyNobility(ctx context.Context, in *UserBuyNobilityReq, opts ...grpc.CallOption) (*UserBuyNobilityResp, error)
StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error)
StatPvpFirstBlood(ctx context.Context, in *StatPvPFirstBloodReq, opts ...grpc.CallOption) (*Empty, error) StatPvpFirstBlood(ctx context.Context, in *StatPvPFirstBloodReq, opts ...grpc.CallOption) (*Empty, error)
StatPvpReport(ctx context.Context, in *StatPvPReportReq, opts ...grpc.CallOption) (*Empty, error) StatPvpReport(ctx context.Context, in *StatPvPReportReq, opts ...grpc.CallOption) (*Empty, error)
// rank // rankPvp pvp排行
RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error) RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error)
} }
@ -49,6 +57,51 @@ func (c *userCenterClient) RetrievePlatformUser(ctx context.Context, in *Platfor
return out, nil return out, nil
} }
func (c *userCenterClient) GetUserIdByPUid(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*UserIdResp, error) {
out := new(UserIdResp)
err := c.cc.Invoke(ctx, "/pb.userCenter/getUserIdByPUid", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userCenterClient) ChangeIntegral(ctx context.Context, in *ChangeIntegralReq, opts ...grpc.CallOption) (*ChangeIntegralResp, error) {
out := new(ChangeIntegralResp)
err := c.cc.Invoke(ctx, "/pb.userCenter/ChangeIntegral", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userCenterClient) GetUserIntegral(ctx context.Context, in *UserIdResp, opts ...grpc.CallOption) (*UserIntegralResp, error) {
out := new(UserIntegralResp)
err := c.cc.Invoke(ctx, "/pb.userCenter/GetUserIntegral", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userCenterClient) UserSendGift(ctx context.Context, in *UserSendGiftReq, opts ...grpc.CallOption) (*UserSendGiftResp, error) {
out := new(UserSendGiftResp)
err := c.cc.Invoke(ctx, "/pb.userCenter/userSendGift", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userCenterClient) UserBuyNobility(ctx context.Context, in *UserBuyNobilityReq, opts ...grpc.CallOption) (*UserBuyNobilityResp, error) {
out := new(UserBuyNobilityResp)
err := c.cc.Invoke(ctx, "/pb.userCenter/userBuyNobility", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userCenterClient) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) { func (c *userCenterClient) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty) out := new(Empty)
err := c.cc.Invoke(ctx, "/pb.userCenter/statPvpKill", in, out, opts...) err := c.cc.Invoke(ctx, "/pb.userCenter/statPvpKill", in, out, opts...)
@ -89,13 +142,21 @@ func (c *userCenterClient) RankPvp(ctx context.Context, in *RankPvpReq, opts ...
// All implementations must embed UnimplementedUserCenterServer // All implementations must embed UnimplementedUserCenterServer
// for forward compatibility // for forward compatibility
type UserCenterServer interface { type UserCenterServer interface {
// user // retrievePlatformUser 新增或获取用户
RetrievePlatformUser(context.Context, *PlatformUserReq) (*PlatformUserResp, error) RetrievePlatformUser(context.Context, *PlatformUserReq) (*PlatformUserResp, error)
// statistics // getUserIdByPUid 通过平台用户id获取系统用户ID
GetUserIdByPUid(context.Context, *PlatformUserReq) (*UserIdResp, error)
//ChangeIntegral 新增用户积分
ChangeIntegral(context.Context, *ChangeIntegralReq) (*ChangeIntegralResp, error)
//GetUserIntegral 获取用户积分
GetUserIntegral(context.Context, *UserIdResp) (*UserIntegralResp, error)
// UserSendGift 用户赠送礼物
UserSendGift(context.Context, *UserSendGiftReq) (*UserSendGiftResp, error)
UserBuyNobility(context.Context, *UserBuyNobilityReq) (*UserBuyNobilityResp, error)
StatPvpKill(context.Context, *StatPvPKillReq) (*Empty, error) StatPvpKill(context.Context, *StatPvPKillReq) (*Empty, error)
StatPvpFirstBlood(context.Context, *StatPvPFirstBloodReq) (*Empty, error) StatPvpFirstBlood(context.Context, *StatPvPFirstBloodReq) (*Empty, error)
StatPvpReport(context.Context, *StatPvPReportReq) (*Empty, error) StatPvpReport(context.Context, *StatPvPReportReq) (*Empty, error)
// rank // rankPvp pvp排行
RankPvp(context.Context, *RankPvpReq) (*RankPvpResp, error) RankPvp(context.Context, *RankPvpReq) (*RankPvpResp, error)
mustEmbedUnimplementedUserCenterServer() mustEmbedUnimplementedUserCenterServer()
} }
@ -107,6 +168,21 @@ type UnimplementedUserCenterServer struct {
func (UnimplementedUserCenterServer) RetrievePlatformUser(context.Context, *PlatformUserReq) (*PlatformUserResp, error) { func (UnimplementedUserCenterServer) RetrievePlatformUser(context.Context, *PlatformUserReq) (*PlatformUserResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrievePlatformUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method RetrievePlatformUser not implemented")
} }
func (UnimplementedUserCenterServer) GetUserIdByPUid(context.Context, *PlatformUserReq) (*UserIdResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserIdByPUid not implemented")
}
func (UnimplementedUserCenterServer) ChangeIntegral(context.Context, *ChangeIntegralReq) (*ChangeIntegralResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ChangeIntegral not implemented")
}
func (UnimplementedUserCenterServer) GetUserIntegral(context.Context, *UserIdResp) (*UserIntegralResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserIntegral not implemented")
}
func (UnimplementedUserCenterServer) UserSendGift(context.Context, *UserSendGiftReq) (*UserSendGiftResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UserSendGift not implemented")
}
func (UnimplementedUserCenterServer) UserBuyNobility(context.Context, *UserBuyNobilityReq) (*UserBuyNobilityResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UserBuyNobility not implemented")
}
func (UnimplementedUserCenterServer) StatPvpKill(context.Context, *StatPvPKillReq) (*Empty, error) { func (UnimplementedUserCenterServer) StatPvpKill(context.Context, *StatPvPKillReq) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method StatPvpKill not implemented") return nil, status.Errorf(codes.Unimplemented, "method StatPvpKill not implemented")
} }
@ -150,6 +226,96 @@ func _UserCenter_RetrievePlatformUser_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _UserCenter_GetUserIdByPUid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PlatformUserReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserCenterServer).GetUserIdByPUid(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.userCenter/getUserIdByPUid",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserCenterServer).GetUserIdByPUid(ctx, req.(*PlatformUserReq))
}
return interceptor(ctx, in, info, handler)
}
func _UserCenter_ChangeIntegral_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ChangeIntegralReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserCenterServer).ChangeIntegral(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.userCenter/ChangeIntegral",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserCenterServer).ChangeIntegral(ctx, req.(*ChangeIntegralReq))
}
return interceptor(ctx, in, info, handler)
}
func _UserCenter_GetUserIntegral_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserIdResp)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserCenterServer).GetUserIntegral(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.userCenter/GetUserIntegral",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserCenterServer).GetUserIntegral(ctx, req.(*UserIdResp))
}
return interceptor(ctx, in, info, handler)
}
func _UserCenter_UserSendGift_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserSendGiftReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserCenterServer).UserSendGift(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.userCenter/userSendGift",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserCenterServer).UserSendGift(ctx, req.(*UserSendGiftReq))
}
return interceptor(ctx, in, info, handler)
}
func _UserCenter_UserBuyNobility_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserBuyNobilityReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserCenterServer).UserBuyNobility(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.userCenter/userBuyNobility",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserCenterServer).UserBuyNobility(ctx, req.(*UserBuyNobilityReq))
}
return interceptor(ctx, in, info, handler)
}
func _UserCenter_StatPvpKill_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _UserCenter_StatPvpKill_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StatPvPKillReq) in := new(StatPvPKillReq)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -233,6 +399,26 @@ var UserCenter_ServiceDesc = grpc.ServiceDesc{
MethodName: "retrievePlatformUser", MethodName: "retrievePlatformUser",
Handler: _UserCenter_RetrievePlatformUser_Handler, Handler: _UserCenter_RetrievePlatformUser_Handler,
}, },
{
MethodName: "getUserIdByPUid",
Handler: _UserCenter_GetUserIdByPUid_Handler,
},
{
MethodName: "ChangeIntegral",
Handler: _UserCenter_ChangeIntegral_Handler,
},
{
MethodName: "GetUserIntegral",
Handler: _UserCenter_GetUserIntegral_Handler,
},
{
MethodName: "userSendGift",
Handler: _UserCenter_UserSendGift_Handler,
},
{
MethodName: "userBuyNobility",
Handler: _UserCenter_UserBuyNobility_Handler,
},
{ {
MethodName: "statPvpKill", MethodName: "statPvpKill",
Handler: _UserCenter_StatPvpKill_Handler, Handler: _UserCenter_StatPvpKill_Handler,

@ -4,11 +4,13 @@ import (
"flag" "flag"
"fmt" "fmt"
"live-service/app/user_center/rpc/internal/config" "live-service/app/user_center/rpc/internal/config"
"live-service/app/user_center/rpc/internal/logic/gift_collect"
"live-service/app/user_center/rpc/internal/logic/platform_user" "live-service/app/user_center/rpc/internal/logic/platform_user"
"live-service/app/user_center/rpc/internal/logic/rank" "live-service/app/user_center/rpc/internal/logic/rank"
"live-service/app/user_center/rpc/internal/server" "live-service/app/user_center/rpc/internal/server"
"live-service/app/user_center/rpc/internal/svc" "live-service/app/user_center/rpc/internal/svc"
"live-service/app/user_center/rpc/pb" "live-service/app/user_center/rpc/pb"
"live-service/common/interceptor/rpcserver"
"github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/service" "github.com/zeromicro/go-zero/core/service"
@ -27,14 +29,9 @@ func main() {
ctx := svc.NewServiceContext(c) ctx := svc.NewServiceContext(c)
svr := server.NewUserCenterServer(ctx) svr := server.NewUserCenterServer(ctx)
if c.UserRetriever.Enabled { platform_user.InitUserRetriever(ctx)
platformUserRetriever := platform_user.NewUserRetriever(ctx)
platformUserRetriever.Scheduler()
}
if c.Rank.Enabled {
rank.InitRankJob(ctx) rank.InitRankJob(ctx)
} gift_collect.InitCollector(ctx)
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
pb.RegisterUserCenterServer(grpcServer, svr) pb.RegisterUserCenterServer(grpcServer, svr)
@ -43,6 +40,7 @@ func main() {
reflection.Register(grpcServer) reflection.Register(grpcServer)
} }
}) })
s.AddUnaryInterceptors(rpcserver.LoggerInterceptor)
defer s.Stop() defer s.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)

@ -13,6 +13,8 @@ import (
) )
type ( type (
ChangeIntegralReq = pb.ChangeIntegralReq
ChangeIntegralResp = pb.ChangeIntegralResp
Empty = pb.Empty Empty = pb.Empty
PlatformUserReq = pb.PlatformUserReq PlatformUserReq = pb.PlatformUserReq
PlatformUserResp = pb.PlatformUserResp PlatformUserResp = pb.PlatformUserResp
@ -24,15 +26,29 @@ type (
StatPvPReportReq = pb.StatPvPReportReq StatPvPReportReq = pb.StatPvPReportReq
StatPvPReportReq_Item = pb.StatPvPReportReq_Item StatPvPReportReq_Item = pb.StatPvPReportReq_Item
User = pb.User User = pb.User
UserBuyNobilityReq = pb.UserBuyNobilityReq
UserBuyNobilityResp = pb.UserBuyNobilityResp
UserIdResp = pb.UserIdResp
UserIntegralResp = pb.UserIntegralResp
UserSendGiftReq = pb.UserSendGiftReq
UserSendGiftResp = pb.UserSendGiftResp
UserCenter interface { UserCenter interface {
// user // retrievePlatformUser 新增或获取用户
RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error) RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error)
// statistics // getUserIdByPUid 通过平台用户id获取系统用户ID
GetUserIdByPUid(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*UserIdResp, error)
// ChangeIntegral 新增用户积分
ChangeIntegral(ctx context.Context, in *ChangeIntegralReq, opts ...grpc.CallOption) (*ChangeIntegralResp, error)
// GetUserIntegral 获取用户积分
GetUserIntegral(ctx context.Context, in *UserIdResp, opts ...grpc.CallOption) (*UserIntegralResp, error)
// UserSendGift 用户赠送礼物
UserSendGift(ctx context.Context, in *UserSendGiftReq, opts ...grpc.CallOption) (*UserSendGiftResp, error)
UserBuyNobility(ctx context.Context, in *UserBuyNobilityReq, opts ...grpc.CallOption) (*UserBuyNobilityResp, error)
StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error)
StatPvpFirstBlood(ctx context.Context, in *StatPvPFirstBloodReq, opts ...grpc.CallOption) (*Empty, error) StatPvpFirstBlood(ctx context.Context, in *StatPvPFirstBloodReq, opts ...grpc.CallOption) (*Empty, error)
StatPvpReport(ctx context.Context, in *StatPvPReportReq, opts ...grpc.CallOption) (*Empty, error) StatPvpReport(ctx context.Context, in *StatPvPReportReq, opts ...grpc.CallOption) (*Empty, error)
// rank // rankPvp pvp排行
RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error) RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error)
} }
@ -47,13 +63,41 @@ func NewUserCenter(cli zrpc.Client) UserCenter {
} }
} }
// user // retrievePlatformUser 新增或获取用户
func (m *defaultUserCenter) RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error) { func (m *defaultUserCenter) RetrievePlatformUser(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*PlatformUserResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn()) client := pb.NewUserCenterClient(m.cli.Conn())
return client.RetrievePlatformUser(ctx, in, opts...) return client.RetrievePlatformUser(ctx, in, opts...)
} }
// statistics // getUserIdByPUid 通过平台用户id获取系统用户ID
func (m *defaultUserCenter) GetUserIdByPUid(ctx context.Context, in *PlatformUserReq, opts ...grpc.CallOption) (*UserIdResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn())
return client.GetUserIdByPUid(ctx, in, opts...)
}
// ChangeIntegral 新增用户积分
func (m *defaultUserCenter) ChangeIntegral(ctx context.Context, in *ChangeIntegralReq, opts ...grpc.CallOption) (*ChangeIntegralResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn())
return client.ChangeIntegral(ctx, in, opts...)
}
// GetUserIntegral 获取用户积分
func (m *defaultUserCenter) GetUserIntegral(ctx context.Context, in *UserIdResp, opts ...grpc.CallOption) (*UserIntegralResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn())
return client.GetUserIntegral(ctx, in, opts...)
}
// UserSendGift 用户赠送礼物
func (m *defaultUserCenter) UserSendGift(ctx context.Context, in *UserSendGiftReq, opts ...grpc.CallOption) (*UserSendGiftResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn())
return client.UserSendGift(ctx, in, opts...)
}
func (m *defaultUserCenter) UserBuyNobility(ctx context.Context, in *UserBuyNobilityReq, opts ...grpc.CallOption) (*UserBuyNobilityResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn())
return client.UserBuyNobility(ctx, in, opts...)
}
func (m *defaultUserCenter) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) { func (m *defaultUserCenter) StatPvpKill(ctx context.Context, in *StatPvPKillReq, opts ...grpc.CallOption) (*Empty, error) {
client := pb.NewUserCenterClient(m.cli.Conn()) client := pb.NewUserCenterClient(m.cli.Conn())
return client.StatPvpKill(ctx, in, opts...) return client.StatPvpKill(ctx, in, opts...)
@ -69,7 +113,7 @@ func (m *defaultUserCenter) StatPvpReport(ctx context.Context, in *StatPvPReport
return client.StatPvpReport(ctx, in, opts...) return client.StatPvpReport(ctx, in, opts...)
} }
// rank // rankPvp pvp排行
func (m *defaultUserCenter) RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error) { func (m *defaultUserCenter) RankPvp(ctx context.Context, in *RankPvpReq, opts ...grpc.CallOption) (*RankPvpResp, error) {
client := pb.NewUserCenterClient(m.cli.Conn()) client := pb.NewUserCenterClient(m.cli.Conn())
return client.RankPvp(ctx, in, opts...) return client.RankPvp(ctx, in, opts...)

@ -1,6 +1,9 @@
package nerr package nerr
import "fmt" import (
"fmt"
"github.com/pkg/errors"
)
type Error struct { type Error struct {
Code uint32 `json:"code"` Code uint32 `json:"code"`
@ -26,6 +29,15 @@ func NewWithCode(code uint32) error {
return NewError(code, MapErrMsg(code)) return NewError(code, MapErrMsg(code))
} }
func NewWithErr(err error) error {
cause := errors.Cause(err)
if e, ok := cause.(*Error); ok {
return e
} else {
return NewWithMsg(err.Error())
}
}
func (e *Error) Error() string { func (e *Error) Error() string {
return fmt.Sprintf("errorCode:%d, errorMsg:%s", e.Code, e.Msg) return fmt.Sprintf("errorCode:%d, errorMsg:%s", e.Code, e.Msg)
} }

@ -0,0 +1,14 @@
func (m *default{{.upperStartCamelObject}}Model) Delete(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error {
{{if .withCache}}{{if .containsIndexCache}}data, err:=m.FindOne(ctx, {{.lowerStartCamelPrimaryKey}})
if err!=nil{
return err
}
{{end}} {{.keys}}
err {{if .containsIndexCache}}={{else}}:={{end}} m.ExecCtx(ctx, func(conn *gorm.DB) *gorm.DB {
return conn.Delete(&{{.upperStartCamelObject}}{}, {{.lowerStartCamelPrimaryKey}})
}, {{.keyValues}}){{else}} err:= m.conn.WithContext(ctx).Delete(&{{.upperStartCamelObject}}{}, {{.lowerStartCamelPrimaryKey}}).Error
{{end}}
return err
}

@ -0,0 +1,5 @@
package {{.pkg}}
import "gorm.io/gorm"
var ErrNotFound = gorm.ErrRecordNotFound

@ -0,0 +1 @@
{{.name}} {{.type}} {{.tag}} {{if .hasComment}}// {{.comment}}{{end}}

@ -0,0 +1,8 @@
func (m *default{{.upperStartCamelObject}}Model) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", {{.primaryKeyLeft}}, primary)
}
func (m *default{{.upperStartCamelObject}}Model) queryPrimary(conn *gorm.DB, v, primary interface{}) error {
return conn.Model(&{{.upperStartCamelObject}}{}).Where("{{.originalPrimaryField}} = ?", primary).Take(v).Error
}

@ -0,0 +1,29 @@
func (m *default{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}(ctx context.Context, {{.in}}) (*{{.upperStartCamelObject}}, error) {
{{if .withCache}}{{.cacheKey}}
var resp {{.upperStartCamelObject}}
err := m.QueryRowIndexCtx(ctx, &resp, {{.cacheKeyVariable}}, m.formatPrimary, func(conn *gorm.DB, v interface{}) (interface{}, error) {
if err := conn.Model(&{{.upperStartCamelObject}}{}).Where("{{.originalField}}", {{.lowerStartCamelField}}).Take(&resp).Error; err != nil {
return nil, err
}
return resp.{{.upperStartCamelPrimaryKey}}, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}{{else}}var resp {{.upperStartCamelObject}}
err := m.conn.WithContext(ctx).Model(&{{.upperStartCamelObject}}{}).Where("{{.originalField}}", {{.lowerStartCamelField}}).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}{{end}}

@ -0,0 +1,25 @@
func (m *default{{.upperStartCamelObject}}Model) FindOne(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) {
{{if .withCache}}{{.cacheKey}}
var resp {{.upperStartCamelObject}}
err := m.QueryRowCtx(ctx, &resp, {{.cacheKeyVariable}}, func(conn *gorm.DB) *gorm.DB {
return conn.Where("id = ?", {{.lowerStartCamelPrimaryKey}})
})
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}{{else}}var resp {{.upperStartCamelObject}}
err := m.conn.WithContext(ctx).Model(&{{.upperStartCamelObject}}{}).Where("{{.originalPrimaryKey}} = ?", {{.lowerStartCamelPrimaryKey}}).Take(&resp).Error
switch err {
case nil:
return &resp, nil
case gormc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}{{end}}
}

@ -0,0 +1,10 @@
import (
"context"
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"strings"
{{if .time}}"time"{{end}}
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stringx"
"gorm.io/gorm"
)

@ -0,0 +1,12 @@
import (
"context"
"fmt"
"strings"
{{if .time}}"time"{{end}}
"git.noahlan.cn/northlan/ntools-go/gorm-zero/gormc"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stringx"
"gorm.io/gorm"
)

@ -0,0 +1,8 @@
func (m *default{{.upperStartCamelObject}}Model) Insert(ctx context.Context, data *{{.upperStartCamelObject}}) error {
{{if .withCache}}{{.keys}}
err := m.ExecCtx(ctx, func(conn *gorm.DB) *gorm.DB {
return conn.Create(&data)
}, {{.keyValues}}){{else}}err:=m.conn.WithContext(ctx).Create(&data).Error{{end}}
return err
}

@ -0,0 +1 @@
Delete(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error

@ -0,0 +1 @@
FindOneBy{{.upperField}}(ctx context.Context, {{.in}}) (*{{.upperStartCamelObject}}, error)

@ -0,0 +1 @@
FindOne(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error)

@ -0,0 +1 @@
Insert(ctx context.Context, data *{{.upperStartCamelObject}}) error

@ -0,0 +1 @@
Update(ctx context.Context, data *{{.upperStartCamelObject}}) error

@ -0,0 +1,13 @@
// Code generated by goctl. DO NOT EDIT!
package {{.pkg}}
{{.imports}}
{{.vars}}
{{.types}}
{{.new}}
{{.insert}}
{{.find}}
{{.update}}
{{.delete}}
{{.extraMethod}}
{{.tableName}}

@ -0,0 +1,7 @@
func new{{.upperStartCamelObject}}Model(conn *gorm.DB{{if .withCache}}, c cache.CacheConf{{end}}) *default{{.upperStartCamelObject}}Model {
return &default{{.upperStartCamelObject}}Model{
{{if .withCache}}CachedConn: gormc.NewConn(conn, c){{else}}conn:conn{{end}},
table: {{.table}},
}
}

@ -0,0 +1,32 @@
package {{.pkg}}
{{if .withCache}}
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"gorm.io/gorm"
)
{{else}}
import (
"gorm.io/gorm"
)
{{end}}
var _ {{.upperStartCamelObject}}Model = (*custom{{.upperStartCamelObject}}Model)(nil)
type (
// {{.upperStartCamelObject}}Model is an interface to be customized, add more methods here,
// and implement the added methods in custom{{.upperStartCamelObject}}Model.
{{.upperStartCamelObject}}Model interface {
{{.lowerStartCamelObject}}Model
}
custom{{.upperStartCamelObject}}Model struct {
*default{{.upperStartCamelObject}}Model
}
)
// New{{.upperStartCamelObject}}Model returns a model for the database table.
func New{{.upperStartCamelObject}}Model(conn *gorm.DB{{if .withCache}}, c cache.CacheConf{{end}}) {{.upperStartCamelObject}}Model {
return &custom{{.upperStartCamelObject}}Model{
default{{.upperStartCamelObject}}Model: new{{.upperStartCamelObject}}Model(conn{{if .withCache}}, c{{end}}),
}
}

@ -0,0 +1,9 @@
func (m *default{{.upperStartCamelObject}}Model) tableName() string {
return m.table
}
func ({{.upperStartCamelObject}}) TableName() string {
model := new{{.upperStartCamelObject}}Model(nil)
return model.tableName()
}

@ -0,0 +1 @@
`gorm:"column:{{.field}}"`

@ -0,0 +1,15 @@
type (
{{.lowerStartCamelObject}}Model interface{
{{.method}}
}
default{{.upperStartCamelObject}}Model struct {
{{if .withCache}}gormc.CachedConn{{else}}conn *gorm.DB{{end}}
table string
}
{{.upperStartCamelObject}} struct {
{{.fields}}
}
)

@ -0,0 +1,8 @@
func (m *default{{.upperStartCamelObject}}Model) Update(ctx context.Context, data *{{.upperStartCamelObject}}) error {
{{if .withCache}}{{.keys}}
err := m.ExecCtx(ctx, func(conn *gorm.DB) *gorm.DB {
return conn.Save(data)
}, {{.keyValues}}){{else}}err:=m.conn.WithContext(ctx).Save(data).Error{{end}}
return err
}

@ -0,0 +1,9 @@
var (
{{.lowerStartCamelObject}}FieldNames = builder.RawFieldNames(&{{.upperStartCamelObject}}{}{{if .postgreSql}},true{{end}})
{{.lowerStartCamelObject}}Rows = strings.Join({{.lowerStartCamelObject}}FieldNames, ",")
{{.lowerStartCamelObject}}RowsExpectAutoSet = {{if .postgreSql}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, {{if .autoIncrement}}"{{.originalPrimaryKey}}",{{end}} "create_time", "update_time"), ","){{else}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, {{if .autoIncrement}}"{{.originalPrimaryKey}}",{{end}} "`create_time`", "`update_time`"), ","){{end}}
{{.lowerStartCamelObject}}RowsWithPlaceHolder = {{if .postgreSql}}builder.PostgreSqlJoin(stringx.Remove({{.lowerStartCamelObject}}FieldNames, "{{.originalPrimaryKey}}", "create_time", "update_time")){{else}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, "{{.originalPrimaryKey}}", "`create_time`", "`update_time`"), "=?,") + "=?"{{end}}
{{if .withCache}}{{.cacheKeys}}{{end}}
)

@ -60,6 +60,7 @@ require (
github.com/prometheus/common v0.30.0 // indirect github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/procfs v0.7.3 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.2 // indirect go.etcd.io/etcd/api/v3 v3.5.2 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect

@ -402,6 +402,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=

Loading…
Cancel
Save