Create & Init Project...

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

View File

@@ -0,0 +1,24 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/ugcpay-rank/api/http:all-srcs",
"//app/service/main/ugcpay-rank/api/v1:all-srcs",
"//app/service/main/ugcpay-rank/cmd:all-srcs",
"//app/service/main/ugcpay-rank/internal/conf:all-srcs",
"//app/service/main/ugcpay-rank/internal/dao:all-srcs",
"//app/service/main/ugcpay-rank/internal/model:all-srcs",
"//app/service/main/ugcpay-rank/internal/server/grpc:all-srcs",
"//app/service/main/ugcpay-rank/internal/server/http:all-srcs",
"//app/service/main/ugcpay-rank/internal/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,16 @@
# v1.2.0
1. 删除无用代码
2. 实装修复后的榜单排序规则
3. 优化ElecUserSetting读取方式
# v1.1.0
1. all av rank add message return
# v1.0.0
1. 增加 rank & prep_rank
2. 增加 rank & prep_rank 相互流转逻辑
3. 新增订阅 order binlog 并更新 prep_rank
2. 增加local cache功能允许rank通过配置使用
# v0.1.0
1. 服务基建

View File

@@ -0,0 +1,8 @@
# Owner
zhaogangtao
# Author
muyang
# Reviewer
zhaogangtao

View File

@@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- muyang
- zhaogangtao
labels:
- main
- service
- service/main/ugcpay-rank
options:
no_parent_owners: true
reviewers:
- muyang
- zhaogangtao

View File

@@ -0,0 +1,13 @@
# ugcpay-rank-interface
## 项目简介
1. 该项目提供 ugc 内容付费排行榜等数据接口
## 编译环境
golang > 1.10
## 依赖包
go-common
## 编译执行
go run ./cmd/main.go -conf test.toml

View File

@@ -0,0 +1,29 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/service/main/ugcpay-rank/api/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//app/service/main/ugcpay-rank/internal/model:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,181 @@
package http
import (
"go-common/app/service/main/ugcpay-rank/internal/model"
)
// Common .
type Common struct {
Code int `json:"code"`
Message string `json:"message"`
TTL int `json:"ttl"`
}
// RetRankElecAllAV .
type RetRankElecAllAV struct {
Common
Data *RespRankElecAllAV `json:"data,omitempty"`
}
// RetRankElecMonth .
type RetRankElecMonth struct {
Common
Data *RespRankElecMonth `json:"data,omitempty"`
}
// RetRankElecMonthUP .
type RetRankElecMonthUP struct {
Common
Data *RespRankElecMonthUP `json:"data,omitempty"`
}
// ArgRankElecMonth .
type ArgRankElecMonth struct {
UPMID int64 `form:"up_mid" validate:"required"` // up主MID
AVID int64 `form:"av_id" validate:"required"`
RankSize int `form:"rank_size"` // 榜单大小
}
// ArgRankElecMonthUP .
type ArgRankElecMonthUP struct {
UPMID int64 `form:"up_mid" validate:"required"` // up主MID
RankSize int `form:"rank_size"` // 榜单大小
}
// RespRankElecElement 榜单元素信息
type RespRankElecElement struct {
UName string `json:"uname"` // 用户名
Avatar string `json:"avatar"` // 头像
MID int64 `json:"mid"` // up主
PayMID int64 `json:"pay_mid"` // 金主爸爸
Rank int `json:"rank"` // 排名
TrendType uint8 `json:"trend_type"` // 上升趋势
VIP *RespVIPInfo `json:"vip_info"` // VIP 信息
}
// Parse .
func (r *RespRankElecElement) Parse(ele *model.RankElecElementProto, upMID int64) {
r.UName = ele.Nickname
r.Avatar = ele.Avatar
r.MID = upMID
r.PayMID = ele.MID
r.Rank = ele.Rank
r.TrendType = ele.TrendType
r.VIP = &RespVIPInfo{}
if ele.VIP != nil {
r.VIP.VIPDueMsec = ele.VIP.DueDate
r.VIP.VIPStatus = ele.VIP.Status
r.VIP.VIPType = ele.VIP.Type
}
}
// RespRankElecElementDetail 榜单元素详情
type RespRankElecElementDetail struct {
RespRankElecElement
Message string `json:"message"` // 留言
MessasgeHidden int `json:"message_hidden"` //
}
// Parse .
func (r *RespRankElecElementDetail) Parse(ele *model.RankElecElementProto, upMID int64) {
r.RespRankElecElement.Parse(ele, upMID)
if ele.Message != nil {
r.Message = ele.Message.Message
if ele.Message.Hidden {
r.MessasgeHidden = 1
} else {
r.MessasgeHidden = 0
}
}
}
// RespRankElecMonth .
type RespRankElecMonth struct {
AVCount int64 `json:"av_count"`
AVList []*RespRankElecElementDetail `json:"av_list"`
UPCount int64 `json:"up_count"`
UPList []*RespRankElecElementDetail `json:"up_list"`
ShowInfo *RespShowInfo `json:"show_info"`
TotalCount int64 `json:"total_count"`
}
// Parse .
func (r *RespRankElecMonth) Parse(avRank *model.RankElecAVProto, upRank *model.RankElecUPProto) {
r.AVCount = avRank.Count
r.AVList = make([]*RespRankElecElementDetail, 0)
for _, ele := range avRank.List {
data := &RespRankElecElementDetail{}
data.Parse(ele, avRank.UPMID)
r.AVList = append(r.AVList, data)
}
r.TotalCount = upRank.CountUPTotalElec
r.UPCount = upRank.Count
r.UPList = make([]*RespRankElecElementDetail, 0)
for _, ele := range upRank.List {
data := &RespRankElecElementDetail{}
data.Parse(ele, upRank.UPMID)
r.UPList = append(r.UPList, data)
}
r.ShowInfo = &RespShowInfo{
Show: true,
State: 0,
}
}
// RespRankElecMonthUP .
type RespRankElecMonthUP struct {
Count int64 `json:"count"` // UP主维度月充电数量
List []*RespRankElecElementDetail `json:"list"`
TotalCount int64 `json:"total_count"`
}
// Parse .
func (r *RespRankElecMonthUP) Parse(monthlyRank *model.RankElecUPProto) {
r.Count = monthlyRank.Count
r.List = make([]*RespRankElecElementDetail, 0)
for _, ele := range monthlyRank.List {
data := &RespRankElecElementDetail{}
data.Parse(ele, monthlyRank.UPMID)
r.List = append(r.List, data)
}
r.TotalCount = monthlyRank.CountUPTotalElec
}
// RespRankElecAllAV .
type RespRankElecAllAV struct {
TotalCount int64 `json:"total_count"`
List []*RespRankElecElementDetail `json:"list"`
}
// Parse .
func (r *RespRankElecAllAV) Parse(rank *model.RankElecAVProto) {
r.TotalCount = rank.Count
r.List = make([]*RespRankElecElementDetail, 0)
for _, ele := range rank.List {
data := &RespRankElecElementDetail{}
data.Parse(ele, rank.UPMID)
r.List = append(r.List, data)
}
}
// RespElecReply .
type RespElecReply struct {
ReplyMID int64 `json:"reply_mid"`
ReplyMSG string `json:"reply_msg"`
ReplyName string `json:"reply_name"`
ReplyTime int64 `json:"reply_time"`
}
// RespVIPInfo .
type RespVIPInfo struct {
VIPDueMsec int64 `json:"vipDueMsec"`
VIPStatus int32 `json:"vipStatus"`
VIPType int32 `json:"vipType"`
}
// RespShowInfo .
type RespShowInfo struct {
Show bool `json:"show"`
State int64 `json:"state"`
}

View File

@@ -0,0 +1,70 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = [
"//app/service/main/ugcpay-rank/internal/model:model_proto",
"@com_google_protobuf//:empty_proto",
"@gogo_special_proto//github.com/gogo/protobuf/gogoproto",
],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/main/ugcpay-rank/api/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = [
"//app/service/main/ugcpay-rank/internal/model:model_go_proto",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
go_library(
name = "go_default_library",
srcs = [
"client.go",
"generate.go",
],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/main/ugcpay-rank/api/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
syntax = "proto3";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
package ugcpay.service.rank.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "app/service/main/ugcpay-rank/internal/model/model.proto";
import "google/protobuf/empty.proto";
message RankElecAVReq{
int64 UPMID = 1 ;
int64 AVID = 2 ;
int64 RankSize = 3 [(gogoproto.casttype) = "int"];
}
message RankElecUPReq{
int64 UPMID = 1 ;
int64 RankSize = 2 [(gogoproto.casttype) = "int"];
}
message RankElecMonthReq{
int64 UPMID = 1 ;
int64 AVID = 2 ;
int64 RankSize = 3 [(gogoproto.casttype) = "int"];
}
message RankElecMonthResp{
main.account.ugcpay.service.model.RankElecUPProto UP = 1 ;
main.account.ugcpay.service.model.RankElecAVProto AV = 2 ;
}
message RankElecUPResp{
main.account.ugcpay.service.model.RankElecUPProto UP = 1 ;
}
message RankElecAVResp{
main.account.ugcpay.service.model.RankElecAVProto AV = 1 ;
}
message RankElecUpdateOrderReq{
int64 AVID = 1 ;
int64 UPMID = 2 ;
int64 PayMID = 3 ;
int64 Ver = 4 ;
int64 Fee = 5 ;
}
message RankElecUpdateMessageReq{
int64 AVID = 1 ;
int64 UPMID = 2 ;
int64 PayMID = 3 ;
int64 Ver = 4 ;
string Message = 5 ;
bool Hidden = 6 ;
}
service UGCPayRank {
rpc RankElecAllAV(RankElecAVReq) returns (RankElecAVResp);
rpc RankElecMonthAV(RankElecAVReq) returns (RankElecAVResp);
rpc RankElecMonthUP(RankElecUPReq) returns (RankElecUPResp);
rpc RankElecMonth(RankElecMonthReq) returns (RankElecMonthResp);
rpc RankElecUpdateOrder(RankElecUpdateOrderReq) returns (.google.protobuf.Empty);
rpc RankElecUpdateMessage(RankElecUpdateMessageReq) returns (.google.protobuf.Empty);
}

View File

@@ -0,0 +1,22 @@
package v1
import (
"context"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID unique app id for service discovery
const AppID = "ugcpay.service.rank"
// NewClient new identify grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (UGCPayRankClient, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
return NewUGCPayRankClient(conn), nil
}

View File

@@ -0,0 +1,4 @@
package v1
// 生成 gRPC 代码
//go:generate $GOPATH/src/go-common/app/tool/warden/protoc.sh

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["test.toml"],
importpath = "go-common/app/service/main/ugcpay-rank/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/server/grpc:go_default_library",
"//app/service/main/ugcpay-rank/internal/server/http:go_default_library",
"//app/service/main/ugcpay-rank/internal/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,49 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/server/grpc"
"go-common/app/service/main/ugcpay-rank/internal/server/http"
"go-common/app/service/main/ugcpay-rank/internal/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("ugcpay-rank-service start")
ecode.Init(conf.Conf.Ecode)
svc := service.New(conf.Conf)
http.Init(svc)
grpc.New(nil, svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
svc.Close()
log.Info("ugcpay-rank-service exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,54 @@
[mysql]
addr = "127.0.0.1:3306"
dsn = "test:test@tcp(127.0.0.1:3306)/bilibili_ugcrank?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["test:test@tcp(127.0.0.1:3306)/bilibili_ugcrank?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4","test:test@tcp(127.0.0.1:3306)/bilibili_ugcrank?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[elecmysql]
addr = "127.0.0.1:3306"
dsn = "test:test@tcp(127.0.0.1:3306)/bilibili_elec?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["test:test@tcp(127.0.0.1:3306)/bilibili_elec?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4","test:test@tcp(127.0.0.1:3306)/bilibili_elec?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[memcache]
name = "ugcpay-rank-interface"
proto = "tcp"
addr = "172.22.33.137:11220"
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[LocalCache]
ElecAVRankSize = 1024
ElecAVRankTTL = "5s"
ElecUPRankSize = 1024
ElecUPRankTTL = "5s"
[CacheTTL]
ElecUPRankTTL = 5
ElecAVRankTTL = 5
ElecPrepUPRankTTL = 300
ElecPrepAVRankTTL = 300
ElecUserSettingTTL = 300
[Biz]
ElecAVRankSize = 30
ElecUPRankSize = 30
RAMAVIDs = [2333]
RAMUPIDs = [6658426]
ReloadDuration = "10s"

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/main/ugcpay-rank/internal/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,119 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
Tracer *trace.Config
BM *bm.ServerConfig
Verify *verify.Config
Memcache *memcache.Config
MySQL *sql.Config
Ecode *ecode.Config
LocalCache *LocalCache
ArchiveGRPC *warden.ClientConfig
AccountGRPC *warden.ClientConfig
CacheTTL *CacheTTL
Biz *Biz
}
// Biz .
type Biz struct {
ElecAVRankSize int
ElecUPRankSize int
RAMAVIDs []int64
RAMUPIDs []int64
ReloadDuration xtime.Duration
}
// LocalCache prop.
type LocalCache struct {
ElecAVRankSize int
ElecAVRankTTL xtime.Duration
ElecUPRankSize int
ElecUPRankTTL xtime.Duration
}
// CacheTTL .
type CacheTTL struct {
ElecUPRankTTL int32
ElecAVRankTTL int32
ElecPrepUPRankTTL int32
ElecPrepAVRankTTL int32
ElecUserSettingTTL int32
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,70 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"grpc.go",
"localcache.go",
"mc.cache.go",
"mc.extra.go",
"mysql.go",
],
importpath = "go-common/app/service/main/ugcpay-rank/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/bluele/gcache:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"grpc_test.go",
"localcache_test.go",
"mc.cache_test.go",
"mc.extra_test.go",
"mysql_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,97 @@
package dao
import (
"context"
"fmt"
account "go-common/app/service/main/account/api"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/cache/memcache"
xsql "go-common/library/database/sql"
"github.com/bluele/gcache"
)
// Dao dao
type Dao struct {
mc *memcache.Pool
db *xsql.DB
accountAPI account.AccountClient
// local cache
elecAVRankLC gcache.Cache
elecUPRankLC gcache.Cache
}
// New init mysql db
func New() (dao *Dao) {
dao = &Dao{
mc: memcache.NewPool(conf.Conf.Memcache),
db: xsql.NewMySQL(conf.Conf.MySQL),
elecAVRankLC: gcache.New(conf.Conf.LocalCache.ElecAVRankSize).LFU().Build(),
elecUPRankLC: gcache.New(conf.Conf.LocalCache.ElecUPRankSize).LFU().Build(),
}
var err error
if dao.accountAPI, err = account.NewClient(conf.Conf.AccountGRPC); err != nil {
panic(err)
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(ctx context.Context) error {
return nil
}
func elecUPRankKey(upMID int64, ver int64) string {
return fmt.Sprintf("ur_eur_%d_%d", ver, upMID)
}
func elecPrepUPRankKey(upMID int64, ver int64) string {
return fmt.Sprintf("ur_epur_%d_%d", ver, upMID)
}
func elecAVRankKey(avID int64, ver int64) string {
return fmt.Sprintf("ur_ear_%d_%d", ver, avID)
}
func elecPrepAVRankKey(avID int64, ver int64) string {
return fmt.Sprintf("ur_epar_%d_%d", ver, avID)
}
//go:generate $GOPATH/src/go-common/app/tool/cache/mc
type _mc interface {
//mc: -key=elecUPRankKey -type=get
CacheElecUPRank(c context.Context, mid int64) (*model.RankElecUPProto, error)
//mc: -key=elecUPRankKey -expire=conf.Conf.CacheTTL.ElecUPRankTTL -encode=json
AddCacheElecUPRank(c context.Context, mid int64, value *model.RankElecUPProto) error
//mc: -key=elecUPRankKey
DelCacheElecUPRank(c context.Context, mid int64) error
//mc: -key=elecAVRankKey -type=get
CacheElecAVRank(c context.Context, avID int64) (*model.RankElecAVProto, error)
//mc: -key=elecAVRankKey -expire=conf.Conf.CacheTTL.ElecAVRankTTL -encode=json
AddCacheElecAVRank(c context.Context, avID int64, value *model.RankElecAVProto) error
//mc: -key=elecAVRankKey
DelCacheElecAVRank(c context.Context, avID int64) error
//mc: -key=elecPrepUPRankKey -type=get
CacheElecPrepUPRank(c context.Context, mid int64) (*model.RankElecPrepUPProto, error)
//mc: -key=elecPrepUPRankKey -expire=conf.Conf.CacheTTL.ElecPrepUPRankTTL -encode=json
AddCacheElecPrepUPRank(c context.Context, mid int64, value *model.RankElecPrepUPProto) error
//mc: -key=elecPrepUPRankKey
DelCacheElecPrepUPRank(c context.Context, mid int64) error
//mc: -key=elecPrepAVRankKey -type=get
CacheElecPrepAVRank(c context.Context, avID int64) (*model.RankElecPrepAVProto, error)
//mc: -key=elecPrepAVRankKey -expire=conf.Conf.CacheTTL.ElecPrepAVRankTTL -encode=json
AddCacheElecPrepAVRank(c context.Context, avID int64, value *model.RankElecPrepAVProto) error
//mc: -key=elecPrepAVRankKey
DelCacheElecPrepAVRank(c context.Context, avID int64) error
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/service/main/ugcpay-rank/internal/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.ugcpay-rank-service")
flag.Set("conf_token", "af0015c6e9072270c243e43df817cebf")
flag.Set("tree_id", "81367")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New()
os.Exit(m.Run())
}

View File

@@ -0,0 +1,23 @@
package dao
import (
"context"
acc "go-common/app/service/main/account/api"
accmdl "go-common/app/service/main/account/model"
)
// AccountCards get cards by mids
func (d *Dao) AccountCards(ctx context.Context, mids []int64) (cards map[int64]*accmdl.Card, err error) {
var (
req = &acc.MidsReq{
Mids: mids,
}
reply *acc.CardsReply
)
if reply, err = d.accountAPI.Cards3(ctx, req); err != nil {
return
}
cards = reply.Cards
return
}

View File

@@ -0,0 +1,24 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAccountCards(t *testing.T) {
convey.Convey("AccountCards", t, func(ctx convey.C) {
var (
c = context.Background()
mids = []int64{46333}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
cards, err := d.AccountCards(c, mids)
ctx.Convey("Then err should be nil.cards should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(cards, convey.ShouldHaveLength, 1)
})
})
})
}

View File

@@ -0,0 +1,65 @@
package dao
import (
"time"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
"github.com/bluele/gcache"
"github.com/pkg/errors"
)
// LCStoreElecUPRank .
func (d *Dao) LCStoreElecUPRank(upMID, ver int64, rank *model.RankElecUPProto) (err error) {
key := elecUPRankKey(upMID, ver)
if err = d.elecUPRankLC.SetWithExpire(key, rank, time.Duration(conf.Conf.LocalCache.ElecUPRankTTL)); err != nil {
err = errors.WithStack(err)
return
}
return
}
// LCStoreElecAVRank .
func (d *Dao) LCStoreElecAVRank(avID, ver int64, rank *model.RankElecAVProto) (err error) {
key := elecAVRankKey(avID, ver)
if err = d.elecAVRankLC.SetWithExpire(key, rank, time.Duration(conf.Conf.LocalCache.ElecAVRankTTL)); err != nil {
err = errors.WithStack(err)
return
}
return
}
// LCLoadElecUPRank .
func (d *Dao) LCLoadElecUPRank(upMID, ver int64) (rank *model.RankElecUPProto, err error) {
key := elecUPRankKey(upMID, ver)
item, err := d.elecUPRankLC.Get(key)
if err != nil {
if err == gcache.KeyNotFoundError {
err = nil
rank = nil
return
}
err = errors.WithStack(err)
return
}
rank = item.(*model.RankElecUPProto)
return
}
// LCLoadElecAVRank .
func (d *Dao) LCLoadElecAVRank(avID, ver int64) (rank *model.RankElecAVProto, err error) {
key := elecAVRankKey(avID, ver)
item, err := d.elecAVRankLC.Get(key)
if err != nil {
if err == gcache.KeyNotFoundError {
err = nil
rank = nil
return
}
err = errors.WithStack(err)
return
}
rank = item.(*model.RankElecAVProto)
return
}

View File

@@ -0,0 +1,150 @@
package dao
import (
"testing"
"time"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoLCLoadElecAVRankFromNil(t *testing.T) {
convey.Convey("loadElecAVRank", t, func(ctx convey.C) {
var (
avID = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecAVRank(avID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldBeNil)
})
})
})
}
func TestDaoLCStoreElecAVRank(t *testing.T) {
convey.Convey("storeElecAVRank", t, func(ctx convey.C) {
var (
avID = int64(233)
ver = int64(0)
rank = &model.RankElecAVProto{
AVID: 233,
}
)
conf.Conf.LocalCache.ElecAVRankTTL = xtime.Duration(time.Second)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.LCStoreElecAVRank(avID, ver, rank)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoLCLoadElecAVRank(t *testing.T) {
convey.Convey("loadElecAVRank", t, func(ctx convey.C) {
var (
avID = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecAVRank(avID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
ctx.So(rank.AVID, convey.ShouldEqual, avID)
})
})
})
}
func TestDaoLCLoadElecAVRankAfterTTL(t *testing.T) {
convey.Convey("loadElecAVRankAfterTTL", t, func(ctx convey.C) {
var (
avID = int64(233)
ver = int64(0)
)
<-time.After(time.Duration(conf.Conf.LocalCache.ElecAVRankTTL))
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecAVRank(avID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldBeNil)
})
})
})
}
func TestDaoLCLoadElecUPRankFromNil(t *testing.T) {
convey.Convey("loadElecUPRank", t, func(ctx convey.C) {
var (
upMID = int64(4633)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecUPRank(upMID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldBeNil)
})
})
})
}
func TestDaoLCStoreElecUPRank(t *testing.T) {
convey.Convey("storeElecUPRank", t, func(ctx convey.C) {
var (
upMID = int64(4633)
ver = int64(0)
rank = &model.RankElecUPProto{
Count: 100,
}
)
conf.Conf.LocalCache.ElecUPRankTTL = xtime.Duration(time.Second)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.LCStoreElecUPRank(upMID, ver, rank)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoLCLoadElecUPRank(t *testing.T) {
convey.Convey("loadElecUPRank", t, func(ctx convey.C) {
var (
upMID = int64(4633)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecUPRank(upMID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
ctx.So(rank.Count, convey.ShouldEqual, 100)
})
})
})
}
func TestDaoLCLoadElecUPRankAfterTTL(t *testing.T) {
convey.Convey("loadElecUPRankAfterTTL", t, func(ctx convey.C) {
var (
upMID = int64(4633)
ver = int64(0)
)
<-time.After(time.Duration(conf.Conf.LocalCache.ElecUPRankTTL))
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.LCLoadElecUPRank(upMID, ver)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,332 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
/*
Package dao is a generated mc cache package.
It is generated from:
type _mc interface {
//mc: -key=elecUPRankKey -type=get
CacheElecUPRank(c context.Context, mid int64) (*model.ElecUPRank, error)
//mc: -key=elecUPRankKey -expire=conf.Conf.CacheTTL.ElecUPRankTTL
AddCacheElecUPRank(c context.Context, mid int64, value *model.ElecUPRank) error
//mc: -key=elecUPRankKey
DelCacheElecUPRank(c context.Context, mid int64) error
//mc: -key=elecAVRankKey -type=get
CacheElecAVRank(c context.Context, avID int64) (*model.ElecAVRank, error)
//mc: -key=elecAVRankKey -expire=conf.Conf.CacheTTL.ElecAVRankTTL
AddCacheElecAVRank(c context.Context, avID int64, value *model.ElecAVRank) error
//mc: -key=elecAVRankKey
DelCacheElecAVRank(c context.Context, avID int64) error
//mc: -key=elecPrepUPRankKey -type=get
CacheElecPrepUPRank(c context.Context, mid int64) (*model.ElecPrepUPRank, error)
//mc: -key=elecPrepUPRankKey -expire=conf.Conf.CacheTTL.ElecPrepUPRankTTL
AddCacheElecPrepUPRank(c context.Context, mid int64, value *model.ElecPrepUPRank) error
//mc: -key=elecPrepUPRankKey
DelCacheElecPrepUPRank(c context.Context, mid int64) error
//mc: -key=elecPrepAVRankKey -type=get
CacheElecPrepAVRank(c context.Context, avID int64) (*model.ElecPrepAVRank, error)
//mc: -key=elecPrepAVRankKey -expire=conf.Conf.CacheTTL.ElecPrepAVRankTTL
AddCacheElecPrepAVRank(c context.Context, avID int64, value *model.ElecPrepAVRank) error
//mc: -key=elecPrepAVRankKey
DelCacheElecPrepAVRank(c context.Context, avID int64) error
}
*/
package dao
import (
"context"
"fmt"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
var _ _mc
// CacheElecUPRank get data from mc
func (d *Dao) CacheElecUPRank(c context.Context, upMID int64, ver int64) (res *model.RankElecUPProto, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecUPRankKey(upMID, ver)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheElecUPRank")
log.Errorv(c, log.KV("CacheElecUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &model.RankElecUPProto{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheElecUPRank")
log.Errorv(c, log.KV("CacheElecUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// SetCacheElecUPRank Set data to mc
func (d *Dao) SetCacheElecUPRank(c context.Context, upMID, ver int64, val *model.RankElecUPProto) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecUPRankKey(upMID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecUPRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:SetCacheElecUPRank")
log.Errorv(c, log.KV("SetCacheElecUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheElecUPRank delete data from mc
func (d *Dao) DelCacheElecUPRank(c context.Context, upMID, ver int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecUPRankKey(upMID, ver)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheElecUPRank")
log.Errorv(c, log.KV("DelCacheElecUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheElecAVRank get data from mc
func (d *Dao) CacheElecAVRank(c context.Context, avID, ver int64) (res *model.RankElecAVProto, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecAVRankKey(avID, ver)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheElecAVRank")
log.Errorv(c, log.KV("CacheElecAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &model.RankElecAVProto{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheElecAVRank")
log.Errorv(c, log.KV("CacheElecAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// SetCacheElecAVRank Set data to mc
func (d *Dao) SetCacheElecAVRank(c context.Context, avID, ver int64, val *model.RankElecAVProto) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecAVRankKey(avID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecAVRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:SetCacheElecAVRank")
log.Errorv(c, log.KV("SetCacheElecAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheElecAVRank delete data from mc
func (d *Dao) DelCacheElecAVRank(c context.Context, avID, ver int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecAVRankKey(avID, ver)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheElecAVRank")
log.Errorv(c, log.KV("DelCacheElecAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheElecPrepUPRank get data from mc
func (d *Dao) CacheElecPrepUPRank(c context.Context, upMID, ver int64) (res *model.RankElecPrepUPProto, item *memcache.Item, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepUPRankKey(upMID, ver)
item, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheElecPrepUPRank")
log.Errorv(c, log.KV("CacheElecPrepUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &model.RankElecPrepUPProto{}
err = conn.Scan(item, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheElecPrepUPRank")
log.Errorv(c, log.KV("CacheElecPrepUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// SetCacheElecPrepUPRank Set data to mc
func (d *Dao) SetCacheElecPrepUPRank(c context.Context, upMID, ver int64, val *model.RankElecPrepUPProto) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepUPRankKey(upMID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecPrepUPRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:SetCacheElecPrepUPRank")
log.Errorv(c, log.KV("SetCacheElecPrepUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheElecPrepUPRank delete data from mc
func (d *Dao) DelCacheElecPrepUPRank(c context.Context, upMID, ver int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepUPRankKey(upMID, ver)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheElecPrepUPRank")
log.Errorv(c, log.KV("DelCacheElecPrepUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheElecPrepAVRank get data from mc
func (d *Dao) CacheElecPrepAVRank(c context.Context, avID, ver int64) (res *model.RankElecPrepAVProto, item *memcache.Item, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepAVRankKey(avID, ver)
item, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheElecPrepAVRank")
log.Errorv(c, log.KV("CacheElecPrepAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &model.RankElecPrepAVProto{}
err = conn.Scan(item, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheElecPrepAVRank")
log.Errorv(c, log.KV("CacheElecPrepAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// SetCacheElecPrepAVRank Set data to mc
func (d *Dao) SetCacheElecPrepAVRank(c context.Context, avID, ver int64, val *model.RankElecPrepAVProto) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepAVRankKey(avID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecPrepAVRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:SetCacheElecPrepAVRank")
log.Errorv(c, log.KV("SetCacheElecPrepAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheElecPrepAVRank delete data from mc
func (d *Dao) DelCacheElecPrepAVRank(c context.Context, avID, ver int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepAVRankKey(avID, ver)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheElecPrepAVRank")
log.Errorv(c, log.KV("DelCacheElecPrepAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheElecPrepAVRank Set data to mc
func (d *Dao) AddCacheElecPrepAVRank(c context.Context, avID, ver int64, val *model.RankElecPrepAVProto) (ok bool, err error) {
ok = true
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepAVRankKey(avID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecPrepAVRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Add(item); err != nil {
if err == memcache.ErrNotStored {
ok = false
err = nil
return
}
prom.BusinessErrCount.Incr("mc:AddCacheElecPrepAVRank")
log.Errorv(c, log.KV("AddCacheElecPrepAVRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheElecPrepUPRank Set data to mc
func (d *Dao) AddCacheElecPrepUPRank(c context.Context, upMID, ver int64, val *model.RankElecPrepUPProto) (ok bool, err error) {
ok = true
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := elecPrepUPRankKey(upMID, ver)
item := &memcache.Item{Key: key, Object: val, Expiration: conf.Conf.CacheTTL.ElecPrepUPRankTTL, Flags: memcache.FlagProtobuf}
if err = conn.Set(item); err != nil {
if err == memcache.ErrNotStored {
ok = false
err = nil
return
}
prom.BusinessErrCount.Incr("mc:AddCacheElecPrepUPRank")
log.Errorv(c, log.KV("AddCacheElecPrepUPRank", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}

View File

@@ -0,0 +1,270 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/ugcpay-rank/internal/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSetCacheElecUPRank(t *testing.T) {
convey.Convey("SetCacheElecUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
val = &model.RankElecUPProto{
CountUPTotalElec: 233,
}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetCacheElecUPRank(c, id, ver, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheElecUPRank(t *testing.T) {
convey.Convey("CacheElecUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.CacheElecUPRank(c, id, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
res, err = d.CacheElecUPRank(c, 0, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoDelCacheElecUPRank(t *testing.T) {
convey.Convey("DelCacheElecUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelCacheElecUPRank(c, id, ver)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetCacheElecAVRank(t *testing.T) {
convey.Convey("SetCacheElecAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
val = &model.RankElecAVProto{
CountUPTotalElec: 233,
}
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetCacheElecAVRank(c, id, ver, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheElecAVRank(t *testing.T) {
convey.Convey("CacheElecAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.CacheElecAVRank(c, id, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
res, err = d.CacheElecAVRank(c, 0, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoDelCacheElecAVRank(t *testing.T) {
convey.Convey("DelCacheElecAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelCacheElecAVRank(c, id, ver)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetCacheElecPrepUPRank(t *testing.T) {
convey.Convey("SetCacheElecPrepUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
val = &model.RankElecPrepUPProto{
Count: 233,
}
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetCacheElecPrepUPRank(c, id, ver, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheElecPrepUPRank(t *testing.T) {
convey.Convey("CacheElecPrepUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, item, err := d.CacheElecPrepUPRank(c, id, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(item, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
res, item, err = d.CacheElecPrepUPRank(c, 0, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(item, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoDelCacheElecPrepUPRank(t *testing.T) {
convey.Convey("DelCacheElecPrepUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelCacheElecPrepUPRank(c, id, ver)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetCacheElecPrepAVRank(t *testing.T) {
convey.Convey("SetCacheElecPrepAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
val = &model.RankElecPrepAVProto{
AVID: 233,
}
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetCacheElecPrepAVRank(c, id, ver, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheElecPrepAVRank(t *testing.T) {
convey.Convey("CacheElecPrepAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, item, err := d.CacheElecPrepAVRank(c, id, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(item, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
res, item, err = d.CacheElecPrepAVRank(c, 0, ver)
ctx.So(err, convey.ShouldBeNil)
ctx.So(item, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoDelCacheElecPrepAVRank(t *testing.T) {
convey.Convey("DelCacheElecPrepAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelCacheElecPrepAVRank(c, id, ver)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoAddCacheElecPrepAVRank(t *testing.T) {
convey.Convey("AddCacheElecPrepAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
val = &model.RankElecPrepAVProto{
AVID: 233,
}
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
ok, err := d.AddCacheElecPrepAVRank(c, id, ver, val)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddCacheElecPrepUPRank(t *testing.T) {
convey.Convey("AddCacheElecPrepUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(233)
val = &model.RankElecPrepUPProto{
UPMID: 233,
}
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
ok, err := d.AddCacheElecPrepUPRank(c, id, ver, val)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"context"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/library/cache/memcache"
)
// CASCacheElecPrepRank cas的方式存储预备榜单防止分布式脏写
func (d *Dao) CASCacheElecPrepRank(c context.Context, val interface{}, rawItem *memcache.Item) (ok bool, err error) {
var (
conn = d.mc.Get(c)
)
defer conn.Close()
rawItem.Object = val
rawItem.Expiration = conf.Conf.CacheTTL.ElecPrepAVRankTTL
rawItem.Flags = memcache.FlagProtobuf
if err = conn.CompareAndSwap(rawItem); err != nil {
if err == memcache.ErrCASConflict { // CAS冲突, 则返回ok == false, 准备重试
err = nil
return
}
if err == memcache.ErrNotStored { // 如果CAS中恰好失效尝试Add
if err = conn.Add(rawItem); err != nil {
if err == memcache.ErrNotStored { // 在Add时恰好又被其他实例Add过, 则返回ok == false, 准备重试
err = nil
return
}
return // 在Add时发生未知错误
}
}
return // 在CAS时发生未知错误
}
ok = true
return
}

View File

@@ -0,0 +1,44 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/cache/memcache"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoCASCacheElecPrepRank(t *testing.T) {
convey.Convey("CASCacheElecPrepRank", t, func(ctx convey.C) {
var (
c = context.Background()
val = &model.RankElecPrepUPProto{
Count: 233,
UPMID: 233,
Size_: 10,
}
id int64 = 233
rawItem *memcache.Item
err error
ver = int64(0)
)
_, rawItem, err = d.CacheElecPrepUPRank(c, id, ver)
convey.So(err, convey.ShouldBeNil)
convey.So(rawItem, convey.ShouldNotBeNil)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
var ok bool
ok, err = d.CASCacheElecPrepRank(c, val, rawItem)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
data, _, err := d.CacheElecPrepUPRank(c, id, ver)
convey.So(err, convey.ShouldBeNil)
convey.So(data, convey.ShouldResemble, val)
})
}

View File

@@ -0,0 +1,270 @@
package dao
import (
"context"
"fmt"
"time"
"go-common/app/service/main/ugcpay-rank/internal/model"
xsql "go-common/library/database/sql"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_countElecUPRank = "SELECT count(1) FROM rank_elec_up WHERE up_mid=? AND ver=? AND hidden=0"
_countUPTotalElec = "SELECT count(1) FROM rank_elec_up WHERE up_mid=? AND ver<>0 AND hidden=0"
_selectElecUPRankList = "SELECT id,ver,up_mid,pay_mid,pay_amount,hidden,ctime,mtime FROM rank_elec_up WHERE up_mid=? AND ver=? AND hidden=0 ORDER BY pay_amount DESC,mtime ASC LIMIT ?"
_selectElecUPRank = "SELECT id,ver,up_mid,pay_mid,pay_amount,hidden,ctime,mtime FROM rank_elec_up WHERE up_mid=? AND ver=? AND pay_mid=? LIMIT 1"
_countElecAVRank = "SELECT count(1) FROM rank_elec_av WHERE avid=? AND ver=? AND hidden=0"
_selectElecAVRankList = "SELECT id,ver,avid,up_mid,pay_mid,pay_amount,hidden,ctime,mtime FROM rank_elec_av WHERE avid=? AND ver=? AND hidden=0 ORDER BY pay_amount DESC,mtime ASC LIMIT ?"
_selectElecAVRank = "SELECT id,ver,avid,up_mid,pay_mid,pay_amount,hidden,ctime,mtime FROM rank_elec_av WHERE avid=? AND ver=? AND pay_mid=? LIMIT 1"
_selectElecUPMessages = "SELECT id,ver,avid,up_mid,pay_mid,message,replied,hidden FROM elec_message WHERE pay_mid in (%s) AND up_mid=? AND ver=? ORDER BY ID ASC"
_selectElecAVMessagesByVer = "SELECT id,ver,avid,up_mid,pay_mid,message,replied,hidden FROM elec_message WHERE pay_mid in (%s) AND avid=? AND ver=? ORDER BY ID ASC"
_selectElecAVMessages = "SELECT id,ver,avid,up_mid,pay_mid,message,replied,hidden FROM elec_message WHERE pay_mid in (%s) AND avid=? ORDER BY ID ASC"
_selectElecUPUserRank = "SELECT count(1) FROM rank_elec_up WHERE up_mid=? AND ver=? AND pay_amount>? AND mtime<? LIMIT 1"
_selectElecAVUserRank = "SELECT count(1) FROM rank_elec_av WHERE avid=? AND ver=? AND pay_amount>? AND mtime<? LIMIT 1"
)
// BeginTran begin transcation.
func (d *Dao) BeginTran(c context.Context) (tx *xsql.Tx, err error) {
return d.db.Begin(c)
}
// RawElecUPRankList get elec up rank
func (d *Dao) RawElecUPRankList(ctx context.Context, upMID int64, ver int64, limit int) (list []*model.DBElecUPRank, err error) {
rows, err := d.db.Query(ctx, _selectElecUPRankList, upMID, ver, limit)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
data := &model.DBElecUPRank{}
if err = rows.Scan(&data.ID, &data.Ver, &data.UPMID, &data.PayMID, &data.PayAmount, &data.Hidden, &data.CTime, &data.MTime); err != nil {
return
}
list = append(list, data)
}
err = rows.Err()
return
}
// RawElecUPRank get elec up rank
func (d *Dao) RawElecUPRank(ctx context.Context, upMID int64, ver int64, payMID int64) (data *model.DBElecUPRank, err error) {
row := d.db.Master().QueryRow(ctx, _selectElecUPRank, upMID, ver, payMID)
if err != nil {
return
}
data = &model.DBElecUPRank{}
if err = row.Scan(&data.ID, &data.Ver, &data.UPMID, &data.PayMID, &data.PayAmount, &data.Hidden, &data.CTime, &data.MTime); err != nil {
if err == xsql.ErrNoRows {
err = nil
data = nil
}
return
}
return
}
// RawCountElecUPRank .
func (d *Dao) RawCountElecUPRank(ctx context.Context, upMID int64, ver int64) (count int64, err error) {
row := d.db.QueryRow(ctx, _countElecUPRank, upMID, ver)
if err = row.Scan(&count); err != nil {
if err == xsql.ErrNoRows {
err = nil
count = 0
}
return
}
return
}
// RawCountUPTotalElec stupid bug from prod.
func (d *Dao) RawCountUPTotalElec(ctx context.Context, upMID int64) (count int64, err error) {
row := d.db.QueryRow(ctx, _countUPTotalElec, upMID)
if err = row.Scan(&count); err != nil {
if err == xsql.ErrNoRows {
err = nil
count = 0
}
return
}
return
}
// RawElecAVRankList .
func (d *Dao) RawElecAVRankList(ctx context.Context, avID int64, ver int64, limit int) (list []*model.DBElecAVRank, err error) {
rows, err := d.db.Query(ctx, _selectElecAVRankList, avID, ver, limit)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
data := &model.DBElecAVRank{}
if err = rows.Scan(&data.ID, &data.Ver, &data.AVID, &data.UPMID, &data.PayMID, &data.PayAmount, &data.Hidden, &data.CTime, &data.MTime); err != nil {
return
}
list = append(list, data)
}
err = rows.Err()
return
}
// RawElecAVRank .
func (d *Dao) RawElecAVRank(ctx context.Context, avID int64, ver int64, payMID int64) (data *model.DBElecAVRank, err error) {
rows := d.db.Master().QueryRow(ctx, _selectElecAVRank, avID, ver, payMID)
if err != nil {
return
}
data = &model.DBElecAVRank{}
if err = rows.Scan(&data.ID, &data.Ver, &data.AVID, &data.UPMID, &data.PayMID, &data.PayAmount, &data.Hidden, &data.CTime, &data.MTime); err != nil {
if err == xsql.ErrNoRows {
err = nil
data = nil
}
return
}
return
}
// RawCountElecAVRank .
func (d *Dao) RawCountElecAVRank(ctx context.Context, avID int64, ver int64) (count int64, err error) {
row := d.db.QueryRow(ctx, _countElecAVRank, avID, ver)
if err = row.Scan(&count); err != nil {
if err == xsql.ErrNoRows {
err = nil
count = 0
}
return
}
return
}
// RawElecUPMessages .
func (d *Dao) RawElecUPMessages(ctx context.Context, payMIDs []int64, upMID int64, ver int64) (dataMap map[int64]*model.DBElecMessage, err error) {
dataMap = make(map[int64]*model.DBElecMessage)
if len(payMIDs) <= 0 {
return
}
sql := fmt.Sprintf(_selectElecUPMessages, xstr.JoinInts(payMIDs))
rows, err := d.db.Query(ctx, sql, upMID, ver)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
data := &model.DBElecMessage{}
if err = rows.Scan(&data.ID, &data.Ver, &data.AVID, &data.UPMID, &data.PayMID, &data.Message, &data.Replied, &data.Hidden); err != nil {
return
}
dataMap[data.PayMID] = data
}
return
}
// RawElecAVMessagesByVer .
func (d *Dao) RawElecAVMessagesByVer(ctx context.Context, payMIDs []int64, avID int64, ver int64) (dataMap map[int64]*model.DBElecMessage, err error) {
dataMap = make(map[int64]*model.DBElecMessage)
if len(payMIDs) <= 0 {
return
}
sql := fmt.Sprintf(_selectElecAVMessagesByVer, xstr.JoinInts(payMIDs))
rows, err := d.db.Query(ctx, sql, avID, ver)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
data := &model.DBElecMessage{}
if err = rows.Scan(&data.ID, &data.Ver, &data.AVID, &data.UPMID, &data.PayMID, &data.Message, &data.Replied, &data.Hidden); err != nil {
return
}
dataMap[data.PayMID] = data
}
return
}
// RawElecAVMessages .
func (d *Dao) RawElecAVMessages(ctx context.Context, payMIDs []int64, avID int64) (dataMap map[int64]*model.DBElecMessage, err error) {
dataMap = make(map[int64]*model.DBElecMessage)
if len(payMIDs) <= 0 {
return
}
sql := fmt.Sprintf(_selectElecAVMessages, xstr.JoinInts(payMIDs))
rows, err := d.db.Query(ctx, sql, avID)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
data := &model.DBElecMessage{}
if err = rows.Scan(&data.ID, &data.Ver, &data.AVID, &data.UPMID, &data.PayMID, &data.Message, &data.Replied, &data.Hidden); err != nil {
return
}
dataMap[data.PayMID] = data
}
return
}
// RawElecUPUserRank .
func (d *Dao) RawElecUPUserRank(ctx context.Context, upMID int64, ver int64, payAmount int64, mtime time.Time) (rank int, err error) {
row := d.db.QueryRow(ctx, _selectElecUPUserRank, upMID, ver, payAmount, mtime)
if err = row.Scan(&rank); err != nil {
if err == xsql.ErrNoRows {
err = nil
rank = 0
}
return
}
return
}
// RawElecAVUserRank .
func (d *Dao) RawElecAVUserRank(ctx context.Context, avID int64, ver int64, payAmount int64, mtime time.Time) (rank int, err error) {
row := d.db.QueryRow(ctx, _selectElecAVUserRank, avID, ver, payAmount, mtime)
if err = row.Scan(&rank); err != nil {
if err == xsql.ErrNoRows {
err = nil
rank = 0
}
return
}
return
}
const (
_elecUserSettingList = "SELECT id,mid,value FROM elec_user_setting WHERE id>? ORDER BY id ASC LIMIT ?"
)
// RawElecUserSettings .
func (d *Dao) RawElecUserSettings(ctx context.Context, id int, limit int) (res map[int64]model.ElecUserSetting, maxID int, err error) {
rows, err := d.db.Master().Query(ctx, _elecUserSettingList, id, limit)
if err != nil {
return
}
defer rows.Close()
res = make(map[int64]model.ElecUserSetting)
for rows.Next() {
var (
data model.ElecUserSetting
mid int64
id int
)
if err = rows.Scan(&id, &mid, &data); err != nil {
err = errors.WithStack(err)
return
}
res[mid] = data
if maxID < id {
maxID = id
}
}
if err = rows.Err(); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@@ -0,0 +1,254 @@
package dao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoBeginTran(t *testing.T) {
convey.Convey("BeginTran", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
tx, err := d.BeginTran(c)
ctx.Convey("Then err should be nil.tx should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecUPRankList(t *testing.T) {
convey.Convey("RawElecUPRankList", t, func(ctx convey.C) {
var (
c = context.Background()
upMID = int64(15555180)
ver = int64(0)
limit = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
list, err := d.RawElecUPRankList(c, upMID, ver, limit)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecUPRank(t *testing.T) {
convey.Convey("RawElecUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
upMID = int64(15555180)
ver = int64(0)
payMID = int64(14137123)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
data, err := d.RawElecUPRank(c, upMID, ver, payMID)
ctx.Convey("Then err should be nil.data should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawCountElecUPRank(t *testing.T) {
convey.Convey("RawCountElecUPRank", t, func(ctx convey.C) {
var (
c = context.Background()
upMID = int64(15555180)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
count, err := d.RawCountElecUPRank(c, upMID, ver)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecAVRankList(t *testing.T) {
convey.Convey("RawElecAVRankList", t, func(ctx convey.C) {
var (
c = context.Background()
avID = int64(4052629)
ver = int64(0)
limit = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
list, err := d.RawElecAVRankList(c, avID, ver, limit)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecAVRank(t *testing.T) {
convey.Convey("RawElecAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
avID = int64(4052629)
ver = int64(0)
payMID = int64(4780461)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
data, err := d.RawElecAVRank(c, avID, ver, payMID)
ctx.Convey("Then err should be nil.data should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawCountElecAVRank(t *testing.T) {
convey.Convey("RawCountElecAVRank", t, func(ctx convey.C) {
var (
c = context.Background()
avID = int64(4052629)
ver = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
count, err := d.RawCountElecAVRank(c, avID, ver)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecUPMessages(t *testing.T) {
convey.Convey("RawElecUPMessages", t, func(ctx convey.C) {
var (
c = context.Background()
payMIDs = []int64{27515316}
upMID = int64(27515241)
ver = int64(201705)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
dataMap, err := d.RawElecUPMessages(c, payMIDs, upMID, ver)
ctx.Convey("Then err should be nil.dataMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(dataMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecAVMessagesByVer(t *testing.T) {
convey.Convey("RawElecAVMessages", t, func(ctx convey.C) {
var (
c = context.Background()
payMIDs = []int64{27515316}
avID = int64(123)
ver = int64(201705)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
dataMap, err := d.RawElecAVMessagesByVer(c, payMIDs, avID, ver)
ctx.Convey("Then err should be nil.dataMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(dataMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecAVMessages(t *testing.T) {
convey.Convey("RawElecAVMessages", t, func(ctx convey.C) {
var (
c = context.Background()
payMIDs = []int64{27515316}
avID = int64(123)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
dataMap, err := d.RawElecAVMessages(c, payMIDs, avID)
ctx.Convey("Then err should be nil.dataMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(dataMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecUPUserRank(t *testing.T) {
convey.Convey("RawElecUPUserRank", t, func(ctx convey.C) {
var (
c = context.Background()
upMID = int64(15555180)
ver = int64(0)
payAmount = int64(200)
mtime = time.Now()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.RawElecUPUserRank(c, upMID, ver, payAmount, mtime)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecAVUserRank(t *testing.T) {
convey.Convey("RawElecAVUserRank", t, func(ctx convey.C) {
var (
c = context.Background()
avID = int64(4052629)
ver = int64(0)
payAmount = int64(200)
mtime = time.Now()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rank, err := d.RawElecAVUserRank(c, avID, ver, payAmount, mtime)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawCountUPTotalElec(t *testing.T) {
convey.Convey("RawCountUPTotalElec", t, func(ctx convey.C) {
var (
c = context.Background()
upMID = int64(46333)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
count, err := d.RawCountUPTotalElec(c, upMID)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawElecUserSettings(t *testing.T) {
convey.Convey("RawElecUserSetting", t, func(ctx convey.C) {
var (
c = context.Background()
id = 0
limit = 10
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
value, maxID, err := d.RawElecUserSettings(c, id, limit)
ctx.Convey("Then err should be nil.value should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(maxID, convey.ShouldBeGreaterThan, 0)
ctx.So(value, convey.ShouldNotBeNil)
ctx.So(value, convey.ShouldHaveLength, 10)
})
})
})
}

View File

@@ -0,0 +1,71 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"db.go",
"model.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/service/main/ugcpay-rank/internal/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/log:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["model_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
proto_library(
name = "model_proto",
srcs = ["model.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/service/main/ugcpay-rank/internal/model",
proto = ":model_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)

View File

@@ -0,0 +1,53 @@
package model
import (
"time"
)
// DBElecUPRank .
type DBElecUPRank struct {
ID int64
UPMID int64
PayMID int64
PayAmount int64
Ver int64
Hidden bool
CTime time.Time
MTime time.Time
}
// DBElecAVRank .
type DBElecAVRank struct {
ID int64
AVID int64
UPMID int64
PayMID int64
PayAmount int64
Ver int64
Hidden bool
CTime time.Time
MTime time.Time
}
// DBElecMessage .
type DBElecMessage struct {
ID int64
Ver int64
AVID int64
UPMID int64
PayMID int64
Message string
Replied bool
Hidden bool
CTime time.Time
MTime time.Time
}
// DBElecUserSetting .
type DBElecUserSetting struct {
ID int64
MID int64
Value int
CTime time.Time
MTime time.Time
}

View File

@@ -0,0 +1,155 @@
package model
import (
"encoding/json"
// "fmt"
// "time"
"go-common/library/log"
"github.com/pkg/errors"
)
// Trend enum
const (
TrendHold = 0
TrendUp = 1
TrendDown = 2
)
// Charge 充电amount: 总充电数
func (e *RankElecPrepUPProto) Charge(payMID int64, amount int64, newElecer bool) {
// 检查是否在榜,如果在榜直接更新
ele := e.Find(payMID)
if ele != nil {
ele.Amount = amount
e.update(ele)
return
}
if newElecer {
e.Count++
e.CountUPTotalElec++
}
// 排行榜列表为最大长度 且 榜单末位的充电数 >= 新的充电数,返回
if len(e.List) >= e.Size_ && e.List[len(e.List)-1].Amount >= amount {
return
}
// 没有在榜且可以上榜则插入原榜
newEle := &RankElecPrepElementProto{
Rank: -1,
MID: payMID,
TrendType: TrendHold,
Amount: amount,
}
e.insert(newEle)
}
// UpdateMessage 更新留言
func (e *RankElecPrepUPProto) UpdateMessage(payMID int64, message string, hidden bool) {
ele := e.Find(payMID)
if ele != nil {
ele.Message = &ElecMessageProto{
Message: message,
Hidden: hidden,
}
}
}
// Find 获得榜单中payMID的排名信息如果不存在则返回nil
func (e *RankElecPrepUPProto) Find(payMID int64) (ele *RankElecPrepElementProto) {
for _, r := range e.List {
if r.MID == payMID {
ele = r
return
}
}
return nil
}
// 更新排名
func (e *RankElecPrepUPProto) update(ele *RankElecPrepElementProto) {
for i := range e.List {
if e.List[i] == nil {
log.Error("ElecPrepUPRank: %s, index: %d, ele: %+v", e, i, ele)
}
if e.List[i].MID != ele.MID && e.List[i].Amount >= ele.Amount {
continue
}
newRank := e.List[i].Rank
if err := e.shift(i, ele.Rank-1); err != nil {
log.Error("ElecPrepUPRank.update err: %+v, ele: %+v in rank: %s ", err, ele, e)
return
}
ele.Rank = newRank
e.List[i] = ele
break
}
}
// 插入新排名到榜单
func (e *RankElecPrepUPProto) insert(ele *RankElecPrepElementProto) {
for i := range e.List {
if e.List[i].Amount >= ele.Amount {
continue
}
// 找到新排名的位置,并插入
ele.Rank = e.List[i].Rank
if len(e.List) >= e.Size_ { // 榜单已满
if err := e.shift(i, len(e.List)-1); err != nil {
log.Error("ElecPrepUPRank.insert err: %+v, ele: %+v in rank: %s ", err, ele, e)
return
}
} else { // 榜单未满
tailEle := e.List[len(e.List)-1]
if err := e.shift(i, len(e.List)-1); err != nil {
log.Error("ElecPrepUPRank.insert err: %+v, ele: %+v in rank: %s ", err, ele, e)
return
}
tailEle.Rank++
e.List = append(e.List, tailEle)
}
e.List[i] = ele
break
}
// 插入到末位
if ele.Rank < 0 {
e.List = append(e.List, ele)
ele.Rank = len(e.List)
}
}
// shift 将排名从 fromRank 起后移一位到 toRank原 toRank 会被丢弃,原 fromRank 将会空出
func (e *RankElecPrepUPProto) shift(fromIndex, toIndex int) (err error) {
if fromIndex > toIndex {
err = errors.Errorf("shift from(%d) > to(%d)", fromIndex, toIndex)
return
}
if len(e.List)-1 < toIndex {
err = errors.Errorf("shift out of range [%d,%d], just have: %d", fromIndex, toIndex, len(e.List))
return
}
lastEle := e.List[fromIndex]
e.List[fromIndex] = nil
for i := fromIndex + 1; i <= toIndex; i++ {
lastEle.Rank++
e.List[i], lastEle = lastEle, e.List[i]
}
return
}
// Message binlog databus msg.
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// ElecUserSetting .
type ElecUserSetting int32
// ShowMessage 充电榜单是否显示留言
func (e ElecUserSetting) ShowMessage() bool {
return (e & 0x1) > 0
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
syntax = "proto3";
package main.account.ugcpay.service.model;
option go_package = "model";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_getters_all) = false;
message RankElecPrepUPProto {
int64 CountUPTotalElec = 1;
int64 Count = 2;
int64 UPMID = 3;
int64 Size = 4 [(gogoproto.casttype) = "int"];
repeated RankElecPrepElementProto List = 5;
}
message RankElecPrepAVProto {
RankElecPrepUPProto RankElecPrepUPProto = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
int64 AVID = 2;
}
message RankElecPrepElementProto {
int64 MID = 1;
int64 Rank = 2 [(gogoproto.casttype) = "int"];
uint32 TrendType = 3 [(gogoproto.casttype) = "uint8"];
int64 Amount = 4;
ElecMessageProto Message = 5;
}
message RankElecUPProto {
int64 CountUPTotalElec = 1 ;
int64 Count = 2 ;
int64 UPMID = 3 ;
int64 Size = 4 [(gogoproto.casttype) = "int"];
repeated RankElecElementProto List = 5;
}
message RankElecAVProto {
int64 CountUPTotalElec = 1 ;
int64 Count = 2 ;
int64 AVID = 3 ;
int64 UPMID = 4 ;
int64 Size = 5 [(gogoproto.casttype) = "int"];
repeated RankElecElementProto List = 6;
}
message RankElecElementProto {
RankElecPrepElementProto RankElecPrepElementProto = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
VIPInfoProto VIP = 2;
string Nickname = 3;
string Avatar = 4;
}
message ElecMessageProto {
string Message = 1;
bool Hidden = 2;
}
message VIPInfoProto {
int32 Type = 1;
int32 Status = 2;
int64 DueDate = 3;
}

View File

@@ -0,0 +1,248 @@
package model
import (
"math/rand"
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/library/log"
)
func TestElecPrepUPRankShift(t *testing.T) {
convey.Convey("shift\n", t, func() {
rank := &RankElecPrepUPProto{
Count: 2,
UPMID: 1,
Size_: 100,
}
rank.List = []*RankElecPrepElementProto{
&RankElecPrepElementProto{
MID: 46333,
Rank: 1,
Amount: 100,
}, &RankElecPrepElementProto{
MID: 35858,
Rank: 2,
Amount: 99,
}, &RankElecPrepElementProto{
MID: 233,
Rank: 3,
Amount: 98,
}, &RankElecPrepElementProto{
MID: 2,
Rank: 4,
Amount: 1,
},
}
rank.shift(0, 2)
log.Info("%s", rank)
convey.So(rank.List, convey.ShouldHaveLength, 4)
convey.So(rank.List[0], convey.ShouldBeNil)
convey.So(rank.List[1].Amount, convey.ShouldEqual, 100)
convey.So(rank.List[2].Amount, convey.ShouldEqual, 99)
})
}
func TestElecPrepUPRankUpdate(t *testing.T) {
convey.Convey("shuffle\n", t, func() {
rank := &RankElecPrepUPProto{
Count: 2,
UPMID: 1,
Size_: 100,
}
rank.List = []*RankElecPrepElementProto{
&RankElecPrepElementProto{
MID: 46333,
Rank: 1,
Amount: 100,
}, &RankElecPrepElementProto{
MID: 35858,
Rank: 2,
Amount: 99,
}, &RankElecPrepElementProto{
MID: 233,
Rank: 3,
Amount: 98,
}, &RankElecPrepElementProto{
MID: 2,
Rank: 4,
Amount: 1,
},
}
rank.update(&RankElecPrepElementProto{
MID: 2,
Rank: 4,
Amount: 2,
})
log.Info("%s", rank)
})
}
func TestElecPrepUPRankInsert(t *testing.T) {
convey.Convey("shuffle\n", t, func() {
rank := &RankElecPrepUPProto{
Count: 2,
UPMID: 1,
Size_: 100,
}
rank.List = []*RankElecPrepElementProto{
&RankElecPrepElementProto{
MID: 46333,
Rank: 1,
Amount: 100,
}, &RankElecPrepElementProto{
MID: 35858,
Rank: 2,
Amount: 99,
}, &RankElecPrepElementProto{
MID: 233,
Rank: 3,
Amount: 98,
}, &RankElecPrepElementProto{
MID: 2,
Rank: 4,
Amount: 1,
},
}
rank.insert(&RankElecPrepElementProto{
MID: 322,
Rank: -1,
Amount: 101,
})
log.Info("%s", rank)
})
}
func TestElecPrepUPRankCharge(t *testing.T) {
convey.Convey("charge\n", t, func() {
rank := &RankElecPrepUPProto{
Count: 0,
UPMID: 2,
Size_: 3,
}
rank.Charge(35858, 100, true)
convey.So(len(rank.List), convey.ShouldEqual, 1)
convey.So(rank.List[0], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 35858,
Rank: 1,
Amount: 100,
})
rank.Charge(46333, 100, true)
convey.So(len(rank.List), convey.ShouldEqual, 2)
convey.So(rank.List[1], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 46333,
Rank: 2,
Amount: 100,
})
rank.Charge(233, 100, true)
convey.So(len(rank.List), convey.ShouldEqual, 3)
convey.So(rank.List[2], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 233,
Rank: 3,
Amount: 100,
})
log.Info("%s", rank)
rank.Charge(46333, 101, false)
log.Info("%s", rank)
convey.So(len(rank.List), convey.ShouldEqual, 3)
convey.So(rank.List[0], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 46333,
Rank: 1,
Amount: 101,
})
convey.So(rank.List[1], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 35858,
Rank: 2,
Amount: 100,
})
rank.Charge(233, 200, false)
convey.So(len(rank.List), convey.ShouldEqual, 3)
convey.So(rank.List[0], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 233,
Rank: 1,
Amount: 200,
})
convey.So(rank.List[1], convey.ShouldResemble, &RankElecPrepElementProto{
MID: 46333,
Rank: 2,
Amount: 101,
})
log.Info("%s", rank)
})
}
func TestElecPrepUPRankUpdateMessage(t *testing.T) {
convey.Convey("charge\n", t, func() {
rank := &RankElecPrepUPProto{
Count: 0,
UPMID: 2,
Size_: 3,
}
rank.Charge(35858, 100, true)
rank.Charge(46333, 100, true)
rank.Charge(233, 100, true)
rank.UpdateMessage(35858, "ut", false)
rank.UpdateMessage(46333, "ut", true)
rank.UpdateMessage(233, "ut-hello", false)
convey.So(rank.Find(35858), convey.ShouldNotBeNil)
convey.So(rank.Find(35858).Message, convey.ShouldNotBeNil)
convey.So(rank.Find(35858).Message.Message, convey.ShouldEqual, "ut")
convey.So(rank.Find(35858).Message.Hidden, convey.ShouldEqual, false)
})
}
func TestElecPrepUPRankChargeRandom(t *testing.T) {
rank := &RankElecPrepUPProto{
Count: 0,
UPMID: 1,
Size_: 100,
}
for i := 0; i < 100; i++ {
rank.Charge(randomEle())
}
log.Info("%s", rank)
}
func BenchmarkElecPrepUPRankCharge(b *testing.B) {
rank := &RankElecPrepUPProto{
Count: 0,
UPMID: 1,
Size_: 100,
}
for i := 0; i < b.N; i++ {
rank.Charge(randomEle())
}
log.Info("%s", rank)
}
var (
mids = []int64{2, 46333, 35858, 233}
i = 0
)
func randomEle() (mid int64, amount int64, isNew bool) {
mid = mids[rand.Intn(len(mids))]
i++
amount = int64(i)
isNew = true
return
}
func TestElecUserSetting(t *testing.T) {
convey.Convey("TestElecUserSetting", t, func() {
set := ElecUserSetting(2147483646)
convey.So(set.ShowMessage(), convey.ShouldBeFalse)
set = ElecUserSetting(0x7ffffff)
convey.So(set.ShowMessage(), convey.ShouldBeTrue)
set = ElecUserSetting(0x1)
convey.So(set.ShowMessage(), convey.ShouldBeTrue)
})
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["elec.go"],
importpath = "go-common/app/service/main/ugcpay-rank/internal/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/ugcpay-rank/api/v1:go_default_library",
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//app/service/main/ugcpay-rank/internal/service:go_default_library",
"//app/service/main/ugcpay-rank/internal/service/rank:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,164 @@
package grpc
import (
"context"
"go-common/app/service/main/ugcpay-rank/api/v1"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/app/service/main/ugcpay-rank/internal/service"
"go-common/app/service/main/ugcpay-rank/internal/service/rank"
"go-common/library/log"
"go-common/library/net/rpc/warden"
"github.com/golang/protobuf/ptypes/empty"
)
// New Identify warden rpc server
func New(cfg *warden.ServerConfig, s *service.Service) *warden.Server {
w := warden.NewServer(cfg)
v1.RegisterUGCPayRankServer(w.Server(), &UGCRankServer{s})
ws, err := w.Start()
if err != nil {
panic(err)
}
return ws
}
// UGCRankServer .
type UGCRankServer struct {
svr *service.Service
}
var _ v1.UGCPayRankServer = &UGCRankServer{}
// RankElecAllAV .
func (u *UGCRankServer) RankElecAllAV(ctx context.Context, req *v1.RankElecAVReq) (resp *v1.RankElecAVResp, err error) {
if req.AVID <= 0 {
return
}
if req.RankSize <= 0 || req.RankSize > conf.Conf.Biz.ElecAVRankSize {
req.RankSize = conf.Conf.Biz.ElecAVRankSize
}
r, err := u.svr.ElecTotalRankAV(ctx, req.UPMID, req.AVID, req.RankSize)
if err != nil {
return
}
resp = &v1.RankElecAVResp{
AV: r,
}
return
}
// RankElecMonthAV .
func (u *UGCRankServer) RankElecMonthAV(ctx context.Context, req *v1.RankElecAVReq) (resp *v1.RankElecAVResp, err error) {
if req.AVID <= 0 {
return
}
if req.RankSize <= 0 || req.RankSize > conf.Conf.Biz.ElecAVRankSize {
req.RankSize = conf.Conf.Biz.ElecAVRankSize
}
r, err := u.svr.ElecMonthRankAV(ctx, req.UPMID, req.AVID, req.RankSize)
if err != nil {
return
}
resp = &v1.RankElecAVResp{
AV: r,
}
return
}
// RankElecMonthUP .
func (u *UGCRankServer) RankElecMonthUP(ctx context.Context, req *v1.RankElecUPReq) (resp *v1.RankElecUPResp, err error) {
if req.UPMID <= 0 {
return
}
if req.RankSize <= 0 || req.RankSize > conf.Conf.Biz.ElecUPRankSize {
req.RankSize = conf.Conf.Biz.ElecUPRankSize
}
r, err := u.svr.ElecMonthRankUP(ctx, req.UPMID, req.RankSize)
if err != nil {
return
}
resp = &v1.RankElecUPResp{
UP: r,
}
return
}
// RankElecMonth .
func (u *UGCRankServer) RankElecMonth(ctx context.Context, req *v1.RankElecMonthReq) (resp *v1.RankElecMonthResp, err error) {
var (
up *model.RankElecUPProto
av *model.RankElecAVProto
)
if req.RankSize <= 0 || req.RankSize > conf.Conf.Biz.ElecAVRankSize {
req.RankSize = conf.Conf.Biz.ElecAVRankSize
}
if req.UPMID > 0 {
if up, err = u.svr.ElecMonthRankUP(ctx, req.UPMID, req.RankSize); err != nil {
return
}
}
if req.AVID > 0 {
if av, err = u.svr.ElecMonthRankAV(ctx, req.UPMID, req.AVID, req.RankSize); err != nil {
return
}
}
resp = &v1.RankElecMonthResp{
UP: up,
AV: av,
}
return
}
// RankElecUpdateOrder .
func (u *UGCRankServer) RankElecUpdateOrder(ctx context.Context, req *v1.RankElecUpdateOrderReq) (reply *empty.Empty, err error) {
reply = &empty.Empty{}
var (
prs = make([]rank.PrepRank, 0)
elecMonthlyPrepUPRank = rank.NewElecPrepUPRank(req.UPMID, conf.Conf.Biz.ElecUPRankSize, req.Ver, u.svr.Dao)
// elecTotalPrepUPRank = rank.NewElecPrepUPRank(req.UPMID, conf.Conf.Biz.ElecUPRankSize, 0, u.svr.Dao) 因为敖厂长所以不能及时更新up总榜否则很容易db超时
)
prs = append(prs, elecMonthlyPrepUPRank)
if req.AVID != 0 {
elecMonthlyPrepAVRank := rank.NewElecPrepAVRank(req.AVID, conf.Conf.Biz.ElecAVRankSize, req.Ver, u.svr.Dao)
elecTotalPrepAVRank := rank.NewElecPrepAVRank(req.AVID, conf.Conf.Biz.ElecAVRankSize, 0, u.svr.Dao)
prs = append(prs, elecMonthlyPrepAVRank, elecTotalPrepAVRank)
}
// 更新缓存Prep_Rank
u.svr.Asyncer.Do(ctx, func(ctx context.Context) {
for _, pr := range prs {
if theErr := u.svr.UpdateElecPrepRankFromOrder(ctx, pr, req.PayMID, req.Fee); theErr != nil {
log.Error("update prep_rank failed, pr: %s, payMID: %d, fee: %d, err: %+v", pr, req.PayMID, req.Fee, theErr)
continue
}
}
})
return
}
// RankElecUpdateMessage .
func (u *UGCRankServer) RankElecUpdateMessage(ctx context.Context, req *v1.RankElecUpdateMessageReq) (reply *empty.Empty, err error) {
reply = &empty.Empty{}
// 更新缓存Prep_Rank
var (
prs = make([]rank.PrepRank, 0)
)
if req.AVID != 0 {
prs = append(prs, rank.NewElecPrepAVRank(req.AVID, conf.Conf.Biz.ElecAVRankSize, req.Ver, u.svr.Dao))
prs = append(prs, rank.NewElecPrepAVRank(req.AVID, conf.Conf.Biz.ElecAVRankSize, 0, u.svr.Dao))
}
if req.UPMID != 0 {
prs = append(prs, rank.NewElecPrepUPRank(req.UPMID, conf.Conf.Biz.ElecUPRankSize, req.Ver, u.svr.Dao))
}
u.svr.Asyncer.Do(ctx, func(ctx context.Context) {
for _, pr := range prs {
if theErr := u.svr.UpdateElecPrepRankFromMessage(ctx, pr, req.PayMID, req.Message, req.Hidden); theErr != nil {
log.Error("update prep_rank failed, pr: %s, payMID: %d, message: %s, hidden: %t, err: %+v", pr, req.PayMID, req.Message, req.Hidden, theErr)
continue
}
}
})
return
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"elec.go",
"http.go",
],
importpath = "go-common/app/service/main/ugcpay-rank/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/ugcpay-rank/api/http:go_default_library",
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//app/service/main/ugcpay-rank/internal/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,108 @@
package http
import (
"net/http"
api "go-common/app/service/main/ugcpay-rank/api/http"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
bm "go-common/library/net/http/blademaster"
"github.com/json-iterator/go"
)
const (
_contentTypeJSON = "application/json; charset=utf-8"
)
func elecMonthUP(ctx *bm.Context) {
var (
err error
arg = &api.ArgRankElecMonthUP{}
resp = &api.RetRankElecMonthUP{
Data: &api.RespRankElecMonthUP{},
}
upRank *model.RankElecUPProto
bytes []byte
)
if err = ctx.Bind(arg); err != nil {
return
}
if arg.RankSize <= 0 || arg.RankSize > conf.Conf.Biz.ElecUPRankSize {
arg.RankSize = conf.Conf.Biz.ElecUPRankSize
}
if upRank, err = svc.ElecMonthRankUP(ctx, arg.UPMID, arg.RankSize); err != nil {
ctx.JSON(nil, err)
return
}
resp.Data.Parse(upRank)
if bytes, err = jsoniter.ConfigFastest.Marshal(resp); err != nil {
ctx.JSON(nil, err)
return
}
ctx.Bytes(http.StatusOK, _contentTypeJSON, bytes)
}
func elecMonth(ctx *bm.Context) {
var (
err error
arg = &api.ArgRankElecMonth{}
resp = &api.RetRankElecMonth{
Data: &api.RespRankElecMonth{},
}
upRank *model.RankElecUPProto
avRank *model.RankElecAVProto
bytes []byte
)
if err = ctx.Bind(arg); err != nil {
return
}
if arg.RankSize <= 0 || arg.RankSize > conf.Conf.Biz.ElecAVRankSize {
arg.RankSize = conf.Conf.Biz.ElecAVRankSize
}
if upRank, err = svc.ElecMonthRankUP(ctx, arg.UPMID, arg.RankSize); err != nil {
ctx.JSON(nil, err)
return
}
if avRank, err = svc.ElecMonthRankAV(ctx, arg.UPMID, arg.AVID, arg.RankSize); err != nil {
ctx.JSON(nil, err)
return
}
resp.Data.Parse(avRank, upRank)
if bytes, err = jsoniter.ConfigFastest.Marshal(resp); err != nil {
ctx.JSON(nil, err)
return
}
ctx.Bytes(http.StatusOK, _contentTypeJSON, bytes)
}
func elecAllAV(ctx *bm.Context) {
var (
err error
arg = &api.ArgRankElecMonth{}
resp = &api.RetRankElecAllAV{
Data: &api.RespRankElecAllAV{},
}
avRank *model.RankElecAVProto
bytes []byte
)
if err = ctx.Bind(arg); err != nil {
return
}
if arg.RankSize <= 0 || arg.RankSize > conf.Conf.Biz.ElecAVRankSize {
arg.RankSize = conf.Conf.Biz.ElecAVRankSize
}
if avRank, err = svc.ElecTotalRankAV(ctx, arg.UPMID, arg.AVID, arg.RankSize); err != nil {
ctx.JSON(nil, err)
return
}
resp.Data.Parse(avRank)
if bytes, err = jsoniter.ConfigFastest.Marshal(resp); err != nil {
ctx.JSON(nil, err)
return
}
ctx.Bytes(http.StatusOK, _contentTypeJSON, bytes)
}

View File

@@ -0,0 +1,39 @@
package http
import (
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
svc *service.Service
verifyM *verify.Verify
)
// Init init
func Init(s *service.Service) {
svc = s
verifyM = verify.New(conf.Conf.Verify)
engine := bm.DefaultServer(conf.Conf.BM)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%+v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(func(ctx *bm.Context) {})
g := e.Group("/x/internal/ugcpay-rank")
{
g1 := g.Group("/elec", verifyM.Verify)
{
g1.GET("/month/up", elecMonthUP)
g1.GET("/month", elecMonth)
g1.GET("/all/av", elecAllAV)
}
}
}

View File

@@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"elec.go",
"rank.go",
"service.go",
],
importpath = "go-common/app/service/main/ugcpay-rank/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/ugcpay-rank/internal/conf:go_default_library",
"//app/service/main/ugcpay-rank/internal/dao:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//app/service/main/ugcpay-rank/internal/service/rank:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/golang.org/x/sync/singleflight:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/ugcpay-rank/internal/service/rank:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,140 @@
package service
import (
"context"
"fmt"
"math"
"sync"
"time"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/app/service/main/ugcpay-rank/internal/service/rank"
"go-common/library/log"
"github.com/pkg/errors"
)
func sfElecRankAV(avID, ver int64, size int) string {
return fmt.Sprintf("sf_era_%d_%d_%d", avID, ver, size)
}
func sfElecRankUP(upMID, ver int64, size int) string {
return fmt.Sprintf("sf_eru_%d_%d_%d", upMID, ver, size)
}
// ElecTotalRankAV 历史av充电榜单
func (s *Service) ElecTotalRankAV(ctx context.Context, upMID int64, avID int64, rankSize int) (res *model.RankElecAVProto, err error) {
if res, err = s.elecRankAV(ctx, upMID, avID, conf.Conf.Biz.ElecAVRankSize, 0); err != nil {
return
}
if len(res.List) <= rankSize {
return
}
res.List = res.List[:rankSize]
return
}
// ElecMonthRankAV 本月av充电榜单
func (s *Service) ElecMonthRankAV(ctx context.Context, upMID int64, avID int64, rankSize int) (res *model.RankElecAVProto, err error) {
if res, err = s.elecRankAV(ctx, upMID, avID, conf.Conf.Biz.ElecAVRankSize, rank.MonthVer(time.Now())); err != nil {
return
}
if len(res.List) <= rankSize {
return
}
res.List = res.List[:rankSize]
return
}
func (s *Service) elecRankAV(ctx context.Context, upMID int64, avid int64, rankSize int, ver int64) (res *model.RankElecAVProto, err error) {
var (
pr = rank.NewElecPrepAVRank(avid, rankSize, ver, s.Dao)
r = rank.NewElecAVRank(avid, rankSize, ver, s.elecRankAVStorage(avid, ver), s.userSetting(ctx, upMID), s.Dao)
data interface{}
ok bool
)
if data, err = s.rank(ctx, sfElecRankAV(avid, ver, rankSize), r, pr); err != nil {
return
}
res, ok = data.(*model.RankElecAVProto)
if !ok {
err = errors.Errorf("ElecRankAV convert data: %T %+v to *model.ElecAVRank failed", data, data)
return
}
return
}
// ElecMonthRankUP 本月up充电榜单
func (s *Service) ElecMonthRankUP(ctx context.Context, upMID int64, rankSize int) (r *model.RankElecUPProto, err error) {
if r, err = s.elecRankUP(ctx, upMID, conf.Conf.Biz.ElecUPRankSize, rank.MonthVer(time.Now())); err != nil {
return
}
if len(r.List) <= rankSize {
return
}
r.List = r.List[:rankSize]
return
}
func (s *Service) elecRankUP(ctx context.Context, upMID int64, rankSize int, ver int64) (res *model.RankElecUPProto, err error) {
var (
pr = rank.NewElecPrepUPRank(upMID, rankSize, ver, s.Dao)
r = rank.NewElecUPRank(upMID, rankSize, ver, s.elecRankUPStorage(upMID, ver), s.userSetting(ctx, upMID), s.Dao)
data interface{}
ok bool
)
if data, err = s.rank(ctx, sfElecRankUP(upMID, ver, rankSize), r, pr); err != nil {
return
}
res, ok = data.(*model.RankElecUPProto)
if !ok {
err = errors.Errorf("ElecRankUP convert data: %T %+v to *model.ElecUPRank failed", data, data)
return
}
return
}
func (s *Service) elecRankUPStorage(upMID, ver int64) (storage rank.Storager) {
ramFlag := false
for _, id := range conf.Conf.Biz.RAMUPIDs {
if id == upMID {
ramFlag = true
break
}
}
if ramFlag {
log.Info("elecRankUPStorage choose RAM_storage, upMID: %d,ver: %d", upMID, ver)
return rank.NewElecUPRankRAMStorage(upMID, ver, s.Dao)
}
return rank.NewElecUPRankMCStorage(upMID, ver, s.Dao)
}
func (s *Service) elecRankAVStorage(avID int64, ver int64) (storage rank.Storager) {
ramFlag := false
for _, id := range conf.Conf.Biz.RAMAVIDs {
if id == avID {
ramFlag = true
break
}
}
if ramFlag {
log.Info("elecRankAVStorage choose RAM_storage, avID: %d,ver: %d", avID, ver)
return rank.NewElecAVRankRAMStorage(avID, ver, s.Dao)
}
return rank.NewElecAVRankMCStorage(avID, ver, s.Dao)
}
func (s *Service) userSetting(ctx context.Context, mid int64) (setting model.ElecUserSetting) {
defer func() {
log.Info("userSetting mid: %d, value: %d", mid, setting)
}()
// load from local cache, 类型转换报错依赖panic机制
userSettings := s.ElecUserSettings.Load().(*sync.Map)
if settingIF, ok := userSettings.Load(mid); ok {
setting = settingIF.(model.ElecUserSetting)
return
}
setting = model.ElecUserSetting(math.MaxInt32)
return
}

View File

@@ -0,0 +1,151 @@
package service
import (
"context"
"go-common/app/service/main/ugcpay-rank/internal/service/rank"
"go-common/library/log"
"go-common/library/stat/prom"
"github.com/pkg/errors"
"golang.org/x/sync/singleflight"
)
var (
sfRank = [1]*singleflight.Group{{}}
_ctx = context.Background()
)
func (s *Service) rank(ctx context.Context, sfKey string, r rank.Rank, pr rank.PrepRank) (data interface{}, err error) {
var (
theRank interface{}
thePrepRank interface{}
)
// load rank from cache
if theRank, err = r.Load(ctx); err != nil {
log.Error("%s, err: %+v", r, err)
err = nil
}
// if rank exist return
if theRank != nil {
prom.CacheHit.Incr("Rank")
data = theRank
return
}
// sf 闭包
fn := func() (res interface{}, ferr error) {
prom.CacheMiss.Incr("Rank")
if thePrepRank, ferr = s.prepRank(ctx, pr); ferr != nil {
log.Error("loadRank get prep_rank failed, err: %+v", ferr)
return
}
if thePrepRank == nil {
return
}
// rebuild rank
if theRank, ferr = r.Rebuild(ctx, thePrepRank); ferr != nil {
ferr = errors.WithMessage(ferr, "loadRank rebuild rank failed")
return
}
if theRank == nil {
err = errors.Errorf("loadRank rebuild rank failed, nil rank returned, r: %s, pr: %s", r, pr)
return
}
// save rank to cache
s.Asyncer.Do(_ctx, func(ctx context.Context) {
if theErr := r.Save(ctx, theRank); theErr != nil {
log.Error("loadRank save rank failed, err: %+v", theErr)
return
}
})
res = theRank
return
}
data, err, _ = sfRank[0].Do(sfKey, fn)
return
}
// UpdateElecPrepRankFromOrder .
func (s *Service) UpdateElecPrepRankFromOrder(ctx context.Context, pr rank.PrepRank, payMID int64, fee int64) (err error) {
var (
thePrepRank interface{}
updatedPrepRank interface{}
)
if thePrepRank, err = s.prepRank(ctx, pr); err != nil {
err = errors.WithMessage(err, "updatePrepRank load prep_rank failed")
return
}
if thePrepRank == nil {
return
}
if updatedPrepRank, err = pr.UpdateOrder(ctx, thePrepRank, payMID, fee); err != nil {
err = errors.WithMessage(err, "updatePrepRank update prep_rank failed")
return
}
if err = pr.Save(ctx, updatedPrepRank); err != nil {
err = errors.WithMessage(err, "updatePrepRank save prep_rank failed")
return
}
return
}
// UpdateElecPrepRankFromMessage .
func (s *Service) UpdateElecPrepRankFromMessage(ctx context.Context, pr rank.PrepRank, payMID int64, message string, hidden bool) (err error) {
var (
thePrepRank interface{}
updatedPrepRank interface{}
)
if thePrepRank, err = s.prepRank(ctx, pr); err != nil {
err = errors.WithMessage(err, "updatePrepRank load prep_rank failed")
return
}
if thePrepRank == nil {
return
}
if updatedPrepRank, err = pr.UpdateMessage(ctx, thePrepRank, payMID, message, hidden); err != nil {
err = errors.WithMessage(err, "updatePrepRank update prep_rank failed")
return
}
if err = pr.Save(ctx, updatedPrepRank); err != nil {
err = errors.WithMessage(err, "updatePrepRank save prep_rank failed")
return
}
return
}
// prepRank 一定返回非nil rank, 或非nil err
func (s *Service) prepRank(ctx context.Context, pr rank.PrepRank) (rank interface{}, err error) {
var (
thePrepRank interface{}
)
// load prep_rank from cache
if thePrepRank, err = pr.Load(ctx); err != nil {
log.Error("%s, err: %+v", pr, err)
err = nil
}
if thePrepRank != nil {
prom.CacheHit.Incr("PrepRank")
rank = thePrepRank
return
}
// if prep_rank = nil, rebuild prep_rank from db
prom.CacheMiss.Incr("PrepRank")
if thePrepRank, err = pr.Rebuild(ctx); err != nil {
err = errors.WithMessage(err, "loadRank rebuild prep_rank failed")
return
}
// if still prep_rank = nil, return err
if thePrepRank == nil {
err = errors.Errorf("loadRank rebuild prep_rank failed, nil prep_rank returned, pr: %s", pr)
return
}
rank = thePrepRank
// save prep_rank to cache
s.Asyncer.Do(_ctx, func(ctx context.Context) {
if theErr := pr.Save(ctx, thePrepRank); theErr != nil {
log.Error("loadRank save prep_rank failed, err: %+v", theErr)
return
}
})
return
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"av.go",
"av_storage.go",
"rank.go",
"tool.go",
"up.go",
"up_storage.go",
],
importpath = "go-common/app/service/main/ugcpay-rank/internal/service/rank",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/account/model:go_default_library",
"//app/service/main/ugcpay-rank/internal/dao:go_default_library",
"//app/service/main/ugcpay-rank/internal/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,276 @@
package rank
import (
"context"
"fmt"
accmdl "go-common/app/service/main/account/model"
"go-common/app/service/main/ugcpay-rank/internal/dao"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
// NewElecPrepAVRank .
func NewElecPrepAVRank(avID int64, size int, ver int64, d *dao.Dao) *ElecPrepAVRank {
return &ElecPrepAVRank{
avID: avID,
size: size,
ver: ver,
dao: d,
}
}
// ElecPrepAVRank 充电av预备榜单
type ElecPrepAVRank struct {
avID int64
size int
ver int64
dao *dao.Dao
}
func (e *ElecPrepAVRank) String() string {
return fmt.Sprintf("ElecPrepAVRank avID: %d, size: %d, ver: %d", e.avID, e.size, e.ver)
}
// Load 从cache中加载
func (e *ElecPrepAVRank) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecPrepAVProto
if data, _, err = e.dao.CacheElecPrepAVRank(ctx, e.avID, e.ver); err != nil {
return
}
if data != nil {
rank = data
}
return
}
// Save 存储到cache
func (e *ElecPrepAVRank) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecPrepAVProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepAVRank", rank, rank)
return
}
casFN := func() (fok bool, ferr error) {
var (
item *memcache.Item
data *model.RankElecPrepAVProto
)
if fok, ferr = e.dao.AddCacheElecPrepAVRank(ctx, e.avID, e.ver, r); ferr != nil {
return
}
if fok {
return
}
if data, item, ferr = e.dao.CacheElecPrepAVRank(ctx, e.avID, e.ver); ferr != nil {
return
}
if data == nil {
fok = false
return
}
if fok, ferr = e.dao.CASCacheElecPrepRank(ctx, r, item); ferr != nil {
return
}
return
}
err = tryHard(casFN, "ElecPrepAVRank:CAS", 3)
return
}
// Rebuild 从db重构
func (e *ElecPrepAVRank) Rebuild(ctx context.Context) (rank interface{}, err error) {
var (
theRank = &model.RankElecPrepAVProto{
AVID: e.avID,
}
dbData []*model.DBElecAVRank
payMIDs []int64
)
theRank.Size_ = e.size
if theRank.Count, err = e.dao.RawCountElecAVRank(ctx, e.avID, e.ver); err != nil {
return
}
if dbData, err = e.dao.RawElecAVRankList(ctx, e.avID, e.ver, e.size); err != nil {
return
}
for i, d := range dbData {
ele := &model.RankElecPrepElementProto{
MID: d.PayMID,
Rank: i + 1,
TrendType: model.TrendHold,
Amount: d.PayAmount,
}
payMIDs = append(payMIDs, d.PayMID)
theRank.List = append(theRank.List, ele)
theRank.UPMID = d.UPMID
}
// 填充充电总人数
if theRank.UPMID != 0 {
if theRank.CountUPTotalElec, err = e.dao.RawCountUPTotalElec(ctx, theRank.UPMID); err != nil {
err = nil
theRank.CountUPTotalElec = 0
log.Error("e.dao.RawCountUPTotalElec upMID: %d, err: %+v", theRank.UPMID, err)
}
}
log.Info("Rebuild ElecPrepAVRank avID: %d, upMID: %d, ver: %d, count: %d, upTotalCount: %d", e.avID, theRank.UPMID, e.ver, theRank.Count, theRank.CountUPTotalElec)
var (
messageMap map[int64]*model.DBElecMessage
)
if e.ver == 0 {
if messageMap, err = e.dao.RawElecAVMessages(ctx, payMIDs, e.avID); err != nil {
return
}
} else {
if messageMap, err = e.dao.RawElecAVMessagesByVer(ctx, payMIDs, e.avID, e.ver); err != nil {
return
}
}
for _, r := range theRank.List {
msg, ok := messageMap[r.MID]
if ok {
r.Message = &model.ElecMessageProto{
Message: msg.Message,
Hidden: msg.Hidden,
}
}
}
rank = theRank
return
}
// UpdateOrder 在内存态通过订单更新并返回
func (e *ElecPrepAVRank) UpdateOrder(ctx context.Context, raw interface{}, payMID int64, fee int64) (res interface{}, err error) {
r, ok := raw.(*model.RankElecPrepAVProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepAVRank", raw, raw)
return
}
var (
elecerRank *model.DBElecAVRank
payAmount = fee
)
if elecerRank, err = e.dao.RawElecAVRank(ctx, e.avID, e.ver, payMID); err != nil {
log.Error("e.dao.RawElecUPRank avID: %d, ver: %d, payMID: %d, err: %+v", e.avID, e.ver, payMID, err)
err = nil
}
log.Info("ElecPrepAVRank: %s, update elecerRank: %+v, from pay_mid: %d, fee: %d", e, elecerRank, payMID, fee)
if elecerRank != nil {
payAmount = elecerRank.PayAmount
}
r.Charge(payMID, payAmount, payAmount == fee)
log.Info("charge ElecPrepAVRank: payMID: %d, fee: %d, payAmount: %d, isNew: %t", payMID, fee, payAmount, payAmount == fee)
res = r
return
}
// UpdateMessage 在内存态通过留言更新并返回
func (e *ElecPrepAVRank) UpdateMessage(ctx context.Context, raw interface{}, payMID int64, message string, hidden bool) (res interface{}, err error) {
r, ok := raw.(*model.RankElecPrepAVProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepAVRank", raw, raw)
return
}
r.UpdateMessage(payMID, message, hidden)
res = r
return
}
// NewElecAVRank .
func NewElecAVRank(avID int64, size int, ver int64, storage Storager, userSetting model.ElecUserSetting, d *dao.Dao) *ElecAVRank {
ret := &ElecAVRank{
avID: avID,
size: size,
ver: ver,
userSetting: userSetting,
dao: d,
}
ret.Storager = storage
return ret
}
// ElecAVRank 充电av正式榜单
type ElecAVRank struct {
Storager
avID int64
size int
ver int64
userSetting model.ElecUserSetting
dao *dao.Dao
}
func (e *ElecAVRank) String() string {
return fmt.Sprintf("ElecAVRank avID: %d, size: %d", e.avID, e.size)
}
// Rebuild 从预备榜单重构
func (e *ElecAVRank) Rebuild(ctx context.Context, prepRank interface{}) (rank interface{}, err error) {
pr, ok := prepRank.(*model.RankElecPrepAVProto)
if !ok {
err = errors.Errorf("prepRank: %T %+v, can not convert to type: *model.ElecAVRank", prepRank, prepRank)
return
}
// 从 prepRank 填充数据
theRank := &model.RankElecAVProto{
CountUPTotalElec: pr.CountUPTotalElec,
Count: pr.Count,
UPMID: pr.UPMID,
AVID: pr.AVID,
Size_: e.size,
}
rank = theRank
var (
mids = make([]int64, 0)
accountMap map[int64]*accmdl.Card
)
for _, r := range pr.List {
if r == nil {
continue
}
mids = append(mids, r.MID)
rankEle := &model.RankElecElementProto{
RankElecPrepElementProto: *r,
}
// ^(用户设置允许展示留言 && top3用户留言)
if !e.userSetting.ShowMessage() || r.Rank > 3 {
log.Info("ElecAVRank add message, show_message: %t, rank: %d", e.userSetting.ShowMessage(), r.Rank)
rankEle.Message = nil
}
theRank.List = append(theRank.List, rankEle)
}
if len(theRank.List) <= 0 {
return
}
// 填充会员信息
if accountMap, err = e.dao.AccountCards(ctx, mids); err != nil {
log.Error("e.dao.AccountCards mids: %+v, err: %+v", mids, err)
err = nil
}
for _, r := range theRank.List {
card, ok := accountMap[r.MID]
if ok {
r.Nickname = card.Name
r.Avatar = card.Face
r.VIP = &model.VIPInfoProto{
Type: card.Vip.Type,
Status: card.Vip.Status,
// DueDate: card.Vip.DueDate,
}
}
}
return
}

View File

@@ -0,0 +1,90 @@
package rank
import (
"context"
"go-common/app/service/main/ugcpay-rank/internal/dao"
"go-common/app/service/main/ugcpay-rank/internal/model"
"github.com/pkg/errors"
)
// NewElecAVRankMCStorage .
func NewElecAVRankMCStorage(avID int64, ver int64, dao *dao.Dao) (e *ElecAVRankMCStorage) {
return &ElecAVRankMCStorage{
avID: avID,
ver: ver,
dao: dao,
}
}
// ElecAVRankMCStorage memcache storage
type ElecAVRankMCStorage struct {
avID int64
ver int64
dao *dao.Dao
}
// Load 从cache中加载
func (e *ElecAVRankMCStorage) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecAVProto
if data, err = e.dao.CacheElecAVRank(ctx, e.avID, e.ver); err != nil {
return
}
if data != nil {
rank = data
}
return
}
// Save 存储到cache
func (e *ElecAVRankMCStorage) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecAVProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecAVRank", rank, rank)
return
}
err = e.dao.SetCacheElecAVRank(ctx, e.avID, e.ver, r)
return
}
// NewElecAVRankRAMStorage .
func NewElecAVRankRAMStorage(avID int64, ver int64, dao *dao.Dao) (e *ElecAVRankRAMStorage) {
return &ElecAVRankRAMStorage{
avID: avID,
ver: ver,
dao: dao,
}
}
// ElecAVRankRAMStorage ram storage
type ElecAVRankRAMStorage struct {
avID int64
ver int64
dao *dao.Dao
}
// Load 从RAM中加载
func (e *ElecAVRankRAMStorage) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecAVProto
if data, err = e.dao.LCLoadElecAVRank(e.avID, e.ver); err != nil {
return
}
// log.Info("ElecAVRankRAMStorage load rank: %+v, avID: %d, ver: %d", data, e.avID, e.ver)
if data != nil {
rank = data
}
return
}
// Save 存储到RAM
func (e *ElecAVRankRAMStorage) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecAVProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecAVRank", rank, rank)
return
}
// log.Info("ElecAVRankRAMStorage save rank: %+v", rank)
err = e.dao.LCStoreElecAVRank(e.avID, e.ver, r)
return
}

View File

@@ -0,0 +1,64 @@
package rank
import (
"context"
"fmt"
"go-common/library/log"
)
var (
_ PrepRank = &ElecPrepUPRank{}
_ PrepRank = &ElecPrepAVRank{}
)
// PrepRank interface .
type PrepRank interface {
fmt.Stringer
// 从中间存储中拉取榜单数据
Load(ctx context.Context) (rank interface{}, err error)
// 从中间存储中存储榜单数据
Save(ctx context.Context, rank interface{}) (err error)
// 从DB中恢复榜单数据
Rebuild(ctx context.Context) (rank interface{}, err error)
// 从订单更新榜单
UpdateOrder(ctx context.Context, rank interface{}, payMID int64, fee int64) (res interface{}, err error)
// 从留言更新榜单
UpdateMessage(ctx context.Context, rank interface{}, payMID int64, message string, hidden bool) (res interface{}, err error)
}
// Rank interface .
type Rank interface {
// 榜单描述信息一般用于log输出调试信息
fmt.Stringer
Storager
// 从 prepRank 中恢复榜单数据
Rebuild(ctx context.Context, prepRank interface{}) (rank interface{}, err error)
}
// Storager .
type Storager interface {
// 从中间存储中拉取榜单数据
Load(ctx context.Context) (rank interface{}, err error)
// 从中间存储中存储榜单数据
Save(ctx context.Context, rank interface{}) (err error)
}
func tryHard(fn func() (ok bool, e error), fname string, tryTimes int) (err error) {
var ok bool
for tryTimes > 0 {
tryTimes--
ok, err = fn()
if err != nil {
log.Error("tryHard func: %s, ok: %t err: %+v, try times left: %d", fname, ok, err, tryTimes)
return
}
if !ok {
log.Error("tryHard func: %s, ok: %t err: %+v, try times left: %d", fname, ok, err, tryTimes)
continue
}
// log.Info("tryHard func: %s, run success, try times left: %d", fname, tryTimes)
return
}
return
}

View File

@@ -0,0 +1,10 @@
package rank
import (
"time"
)
// MonthVer return ver from time.Time
func MonthVer(t time.Time) int64 {
return int64(t.Year()*100 + int(t.Month()))
}

View File

@@ -0,0 +1,268 @@
package rank
import (
"context"
"fmt"
accmdl "go-common/app/service/main/account/model"
"go-common/app/service/main/ugcpay-rank/internal/dao"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
// NewElecPrepUPRank .
func NewElecPrepUPRank(upMID int64, size int, ver int64, d *dao.Dao) *ElecPrepUPRank {
return &ElecPrepUPRank{
upMID: upMID,
size: size,
ver: ver,
dao: d,
}
}
// ElecPrepUPRank 充电up预备榜单
type ElecPrepUPRank struct {
upMID int64
size int
ver int64
dao *dao.Dao
}
func (e *ElecPrepUPRank) String() string {
return fmt.Sprintf("ElecPrepUPRank up_mid: %d, size: %d", e.upMID, e.size)
}
// Load 从cache中加载
func (e *ElecPrepUPRank) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecPrepUPProto
if data, _, err = e.dao.CacheElecPrepUPRank(ctx, e.upMID, e.ver); err != nil {
return
}
if data != nil {
rank = data
}
return
}
// Save 存储到cache
func (e *ElecPrepUPRank) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecPrepUPProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepUPRank", rank, rank)
return
}
casFN := func() (fok bool, ferr error) {
var (
item *memcache.Item
data *model.RankElecPrepUPProto
)
if fok, ferr = e.dao.AddCacheElecPrepUPRank(ctx, e.upMID, e.ver, r); ferr != nil {
return
}
if fok {
return
}
if data, item, ferr = e.dao.CacheElecPrepUPRank(ctx, e.upMID, e.ver); ferr != nil {
return
}
if data == nil {
fok = false
return
}
if fok, ferr = e.dao.CASCacheElecPrepRank(ctx, data, item); ferr != nil {
return
}
return
}
err = tryHard(casFN, "ElecPrepUPRank:CAS", 3)
return
}
// Rebuild 从db重构
func (e *ElecPrepUPRank) Rebuild(ctx context.Context) (rank interface{}, err error) {
var (
theRank = &model.RankElecPrepUPProto{
UPMID: e.upMID,
Size_: e.size,
}
dbData []*model.DBElecUPRank
payMIDs []int64
)
if theRank.Count, err = e.dao.RawCountElecUPRank(ctx, e.upMID, e.ver); err != nil {
return
}
if dbData, err = e.dao.RawElecUPRankList(ctx, e.upMID, e.ver, e.size); err != nil {
return
}
for i, d := range dbData {
ele := &model.RankElecPrepElementProto{
MID: d.PayMID,
Rank: i + 1,
TrendType: model.TrendHold,
Amount: d.PayAmount,
}
payMIDs = append(payMIDs, d.PayMID)
theRank.List = append(theRank.List, ele)
}
// 填充充电总人数
if theRank.UPMID != 0 {
if theRank.CountUPTotalElec, err = e.dao.RawCountUPTotalElec(ctx, theRank.UPMID); err != nil {
err = nil
theRank.CountUPTotalElec = 0
log.Error("e.dao.RawCountUPTotalElec upMID: %d, err: %+v", theRank.UPMID, err)
}
}
log.Info("Rebuild ElecPrepUPRank upMID: %d, ver: %d, count: %d, upTotalCount: %d", theRank.UPMID, e.ver, theRank.Count, theRank.CountUPTotalElec)
// 填充留言信息
if e.ver != 0 {
var (
messageMap map[int64]*model.DBElecMessage
)
if messageMap, err = e.dao.RawElecUPMessages(ctx, payMIDs, e.upMID, e.ver); err != nil {
return
}
for _, r := range theRank.List {
msg, ok := messageMap[r.MID]
if ok {
r.Message = &model.ElecMessageProto{
Message: msg.Message,
Hidden: msg.Hidden,
}
}
}
}
rank = theRank
return
}
// UpdateOrder 在内存态通过订单更新并返回
func (e *ElecPrepUPRank) UpdateOrder(ctx context.Context, raw interface{}, payMID int64, fee int64) (res interface{}, err error) {
r, ok := raw.(*model.RankElecPrepUPProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepUPRank", raw, raw)
return
}
var (
elecerRank *model.DBElecUPRank
payAmount = fee
)
if elecerRank, err = e.dao.RawElecUPRank(ctx, e.upMID, e.ver, payMID); err != nil {
log.Error("e.dao.RawElecUPRank upMID: %d, ver: %d, payMID: %d, err: %+v", e.upMID, e.ver, payMID, err)
err = nil
}
log.Info("ElecPrepUPRank: %s, update elecerRank: %+v, from payMID : %d, fee: %d", e, elecerRank, payMID, fee)
if elecerRank != nil {
payAmount = elecerRank.PayAmount
}
r.Charge(payMID, payAmount, payAmount == fee)
log.Info("charge ElecPrepUPRank: payMID: %d, fee: %d, payAmount: %d, isNew: %t", payMID, fee, payAmount, payAmount == fee)
res = r
return
}
// UpdateMessage 在内存态通过留言更新并返回
func (e *ElecPrepUPRank) UpdateMessage(ctx context.Context, raw interface{}, payMID int64, message string, hidden bool) (res interface{}, err error) {
r, ok := raw.(*model.RankElecPrepUPProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecPrepUPRank", raw, raw)
return
}
r.UpdateMessage(payMID, message, hidden)
res = r
return
}
// NewElecUPRank .
func NewElecUPRank(upMID int64, size int, ver int64, storage Storager, userSetting model.ElecUserSetting, d *dao.Dao) *ElecUPRank {
ret := &ElecUPRank{
upMID: upMID,
size: size,
ver: ver,
userSetting: userSetting,
dao: d,
}
ret.Storager = storage
return ret
}
// ElecUPRank 充电up正式榜单
type ElecUPRank struct {
Storager
upMID int64
size int
ver int64
userSetting model.ElecUserSetting
dao *dao.Dao
}
func (e *ElecUPRank) String() string {
return fmt.Sprintf("ElecUPRank up_mid: %d, size: %d", e.upMID, e.size)
}
// Rebuild 从预备榜单重构
func (e *ElecUPRank) Rebuild(ctx context.Context, prepRank interface{}) (rank interface{}, err error) {
pr, ok := prepRank.(*model.RankElecPrepUPProto)
if !ok {
err = errors.Errorf("prepRank: %T %+v, can not convert to type: *model.ElecPrepUPRank", prepRank, prepRank)
return
}
// 从 prepRank 填充数据
theRank := &model.RankElecUPProto{
CountUPTotalElec: pr.CountUPTotalElec,
Count: pr.Count,
UPMID: pr.UPMID,
Size_: e.size,
}
rank = theRank
var (
mids = make([]int64, 0)
accountMap map[int64]*accmdl.Card
)
for _, r := range pr.List {
if r == nil {
continue
}
mids = append(mids, r.MID)
rankEle := &model.RankElecElementProto{
RankElecPrepElementProto: *r,
}
// ^(用户设置允许展示留言 && top3用户留言)
if !e.userSetting.ShowMessage() || r.Rank > 3 {
log.Info("ElecUPRank add message, mid: %d, show_message: %t, rank: %d", e.upMID, e.userSetting.ShowMessage(), r.Rank)
rankEle.Message = nil
}
theRank.List = append(theRank.List, rankEle)
}
if len(theRank.List) <= 0 {
return
}
// 填充会员信息
if accountMap, err = e.dao.AccountCards(ctx, mids); err != nil {
log.Error("e.dao.AccountCards mids: %+v, err: %+v", mids, err)
err = nil
}
for _, r := range theRank.List {
card, ok := accountMap[r.MID]
if ok {
r.Nickname = card.Name
r.Avatar = card.Face
r.VIP = &model.VIPInfoProto{
Type: card.Vip.Type,
Status: card.Vip.Status,
// DueDate: card.Vip.DueDate,
}
}
}
return
}

View File

@@ -0,0 +1,90 @@
package rank
import (
"context"
"go-common/app/service/main/ugcpay-rank/internal/dao"
"go-common/app/service/main/ugcpay-rank/internal/model"
"github.com/pkg/errors"
)
// NewElecUPRankMCStorage .
func NewElecUPRankMCStorage(upMID int64, ver int64, dao *dao.Dao) (e *ElecUPRankMCStorage) {
return &ElecUPRankMCStorage{
upMID: upMID,
ver: ver,
dao: dao,
}
}
// ElecUPRankMCStorage .
type ElecUPRankMCStorage struct {
upMID int64
ver int64
dao *dao.Dao
}
// Load 从cache中加载
func (e *ElecUPRankMCStorage) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecUPProto
if data, err = e.dao.CacheElecUPRank(ctx, e.upMID, e.ver); err != nil {
return
}
if data != nil {
rank = data
}
return
}
// Save 存储到cache
func (e *ElecUPRankMCStorage) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecUPProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecUPRank", rank, rank)
return
}
err = e.dao.SetCacheElecUPRank(ctx, e.upMID, e.ver, r)
return
}
// NewElecUPRankRAMStorage .
func NewElecUPRankRAMStorage(upMID int64, ver int64, dao *dao.Dao) (e *ElecUPRankRAMStorage) {
return &ElecUPRankRAMStorage{
upMID: upMID,
ver: ver,
dao: dao,
}
}
// ElecUPRankRAMStorage .
type ElecUPRankRAMStorage struct {
upMID int64
ver int64
dao *dao.Dao
}
// Load 从ram中加载
func (e *ElecUPRankRAMStorage) Load(ctx context.Context) (rank interface{}, err error) {
var data *model.RankElecUPProto
if data, err = e.dao.LCLoadElecUPRank(e.upMID, e.ver); err != nil {
return
}
// log.Info("ElecUPRankRAMStorage load rank: %+v, upMID: %d, ver: %d", data, e.upMID, e.ver)
if data != nil {
rank = data
}
return
}
// Save 存储到ram
func (e *ElecUPRankRAMStorage) Save(ctx context.Context, rank interface{}) (err error) {
r, ok := rank.(*model.RankElecUPProto)
if !ok {
err = errors.Errorf("rank: %T %+v, can not convert to type: *model.ElecUPRank", rank, rank)
return
}
// log.Info("ElecUPRankRAMStorage save rank: %+v", rank)
err = e.dao.LCStoreElecUPRank(e.upMID, e.ver, r)
return
}

View File

@@ -0,0 +1,78 @@
package service
import (
"context"
"runtime/debug"
"sync"
"sync/atomic"
"time"
"go-common/app/service/main/ugcpay-rank/internal/conf"
"go-common/app/service/main/ugcpay-rank/internal/dao"
"go-common/app/service/main/ugcpay-rank/internal/model"
"go-common/library/log"
"go-common/library/sync/pipeline/fanout"
)
// Service struct
type Service struct {
Dao *dao.Dao
ElecUserSettings atomic.Value
Asyncer *fanout.Fanout
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
Dao: dao.New(),
Asyncer: fanout.New("async_worker", fanout.Worker(10), fanout.Buffer(10240)),
}
s.ElecUserSettings.Store(&sync.Map{})
go s.reloadproc()
return
}
func (s *Service) reloadproc() {
defer func() {
if x := recover(); x != nil {
log.Error("reloadproc panic: %+v\n%s", x, debug.Stack())
s.reloadproc()
}
}()
log.Info("reloadproc start on every %s", time.Duration(conf.Conf.Biz.ReloadDuration))
ticker := time.NewTicker(time.Duration(conf.Conf.Biz.ReloadDuration))
for {
log.Info("reloadproc reload")
var (
limit = 1000
id = 0
m = map[int64]model.ElecUserSetting{-1: -1}
err error
count = 0
settings = &sync.Map{}
)
for len(m) > 0 {
if m, id, err = s.Dao.RawElecUserSettings(_ctx, id, limit); err != nil {
log.Error("s.Dao.RawElecUserSettings err: %+v", err)
break
}
for mid, setting := range m {
count++
settings.Store(mid, setting)
}
}
s.ElecUserSettings.Store(settings)
log.Info("reloadproc reload end, count: %d", count)
<-ticker.C
}
}
// Ping Service
func (s *Service) Ping(ctx context.Context) (err error) {
return s.Dao.Ping(ctx)
}
// Close Service
func (s *Service) Close() {
s.Dao.Close()
}