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,2 @@
# v1.0.0
1. 上线功能xxx

View File

@@ -0,0 +1,14 @@
# Owner
zhaohailin
wangyao
zhangwei01
# Author
zhaohailin
wangyao
zhangwei01
# Reviewer
zhaohailin
wangyao
zhangwei01

View File

@@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wangyao
- zhangwei01
- zhaohailin
labels:
- live
- service
- service/live/dao-anchor
options:
no_parent_owners: true
reviewers:
- wangyao
- zhangwei01
- zhaohailin

View File

@@ -0,0 +1,12 @@
# dao-anchor-service
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,62 @@
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 = "v0_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v0_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/live/dao-anchor/api/grpc/v0",
proto = ":v0_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"api.bm.go",
"client.go",
],
embed = [":v0_go_proto"],
importpath = "go-common/app/service/live/dao-anchor/api/grpc/v0",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding: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",
"@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"],
)

View File

@@ -0,0 +1,191 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api.proto
/*
Package v0 is a generated blademaster stub package.
This code was generated with go-common/app/tool/bmgen/protoc-gen-bm v0.1.
It is generated from these files:
api.proto
*/
package v0
import (
"context"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
var PathCreateDataCreateCacheList = "/live.daoanchor.v0.CreateData/CreateCacheList"
var PathCreateDataCreateLiveCacheList = "/live.daoanchor.v0.CreateData/CreateLiveCacheList"
var PathCreateDataGetContentMap = "/live.daoanchor.v0.CreateData/GetContentMap"
var PathCreateDataCreateDBData = "/live.daoanchor.v0.CreateData/CreateDBData"
var PathPopularityGetAnchorGradeList = "/live.daoanchor.v0.Popularity/GetAnchorGradeList"
var PathPopularityEditAnchorGrade = "/live.daoanchor.v0.Popularity/EditAnchorGrade"
var PathPopularityGetContentList = "/live.daoanchor.v0.Popularity/GetContentList"
var PathPopularityAddContent = "/live.daoanchor.v0.Popularity/AddContent"
var PathPopularityEditContent = "/live.daoanchor.v0.Popularity/EditContent"
var PathPopularityDeleteContent = "/live.daoanchor.v0.Popularity/DeleteContent"
// ====================
// CreateData Interface
// ====================
type CreateDataBMServer interface {
// CreateCacheList 生成历史数据缓存列表
CreateCacheList(ctx context.Context, req *CreateCacheListReq) (resp *CreateCacheListResp, err error)
// CreateLiveCacheList 生成开播历史数据缓存列表
CreateLiveCacheList(ctx context.Context, req *CreateLiveCacheListReq) (resp *CreateLiveCacheListResp, err error)
// GetContentMap 获取需要生成历史数据的对象列表
GetContentMap(ctx context.Context, req *GetContentMapReq) (resp *GetContentMapResp, err error)
CreateDBData(ctx context.Context, req *CreateDBDataReq) (resp *CreateDBDataResp, err error)
}
var v0CreateDataSvc CreateDataBMServer
func createDataCreateCacheList(c *bm.Context) {
p := new(CreateCacheListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0CreateDataSvc.CreateCacheList(c, p)
c.JSON(resp, err)
}
func createDataCreateLiveCacheList(c *bm.Context) {
p := new(CreateLiveCacheListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0CreateDataSvc.CreateLiveCacheList(c, p)
c.JSON(resp, err)
}
func createDataGetContentMap(c *bm.Context) {
p := new(GetContentMapReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0CreateDataSvc.GetContentMap(c, p)
c.JSON(resp, err)
}
func createDataCreateDBData(c *bm.Context) {
p := new(CreateDBDataReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0CreateDataSvc.CreateDBData(c, p)
c.JSON(resp, err)
}
// RegisterCreateDataBMServer Register the blademaster route
func RegisterCreateDataBMServer(e *bm.Engine, server CreateDataBMServer) {
v0CreateDataSvc = server
e.GET("/live.daoanchor.v0.CreateData/CreateCacheList", createDataCreateCacheList)
e.GET("/live.daoanchor.v0.CreateData/CreateLiveCacheList", createDataCreateLiveCacheList)
e.GET("/live.daoanchor.v0.CreateData/GetContentMap", createDataGetContentMap)
e.GET("/live.daoanchor.v0.CreateData/CreateDBData", createDataCreateDBData)
}
// ====================
// Popularity Interface
// ====================
// 人气相关接口
type PopularityBMServer interface {
// GetAnchorGradeList 获取人气值主播评级列表
GetAnchorGradeList(ctx context.Context, req *GetAnchorGradeListReq) (resp *GetAnchorGradeListResp, err error)
// EditAnchorGrade 编辑主播评级对应的人气值数据
EditAnchorGrade(ctx context.Context, req *EditAnchorGradeReq) (resp *EditAnchorGradeResp, err error)
// GetContentList 人气内容系数列表
GetContentList(ctx context.Context, req *GetContentListReq) (resp *GetContentListResp, err error)
// AddContent 添加内容系数
AddContent(ctx context.Context, req *AddContentReq) (resp *AddContentResp, err error)
// EditContent 编辑内容系数
EditContent(ctx context.Context, req *EditContentReq) (resp *EditContentResp, err error)
// DeleteContent 删除内容系数
DeleteContent(ctx context.Context, req *DeleteContentReq) (resp *DeleteContentResp, err error)
}
var v0PopularitySvc PopularityBMServer
func popularityGetAnchorGradeList(c *bm.Context) {
p := new(GetAnchorGradeListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.GetAnchorGradeList(c, p)
c.JSON(resp, err)
}
func popularityEditAnchorGrade(c *bm.Context) {
p := new(EditAnchorGradeReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.EditAnchorGrade(c, p)
c.JSON(resp, err)
}
func popularityGetContentList(c *bm.Context) {
p := new(GetContentListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.GetContentList(c, p)
c.JSON(resp, err)
}
func popularityAddContent(c *bm.Context) {
p := new(AddContentReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.AddContent(c, p)
c.JSON(resp, err)
}
func popularityEditContent(c *bm.Context) {
p := new(EditContentReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.EditContent(c, p)
c.JSON(resp, err)
}
func popularityDeleteContent(c *bm.Context) {
p := new(DeleteContentReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v0PopularitySvc.DeleteContent(c, p)
c.JSON(resp, err)
}
// RegisterPopularityBMServer Register the blademaster route
func RegisterPopularityBMServer(e *bm.Engine, server PopularityBMServer) {
v0PopularitySvc = server
e.GET("/live.daoanchor.v0.Popularity/GetAnchorGradeList", popularityGetAnchorGradeList)
e.GET("/live.daoanchor.v0.Popularity/EditAnchorGrade", popularityEditAnchorGrade)
e.GET("/live.daoanchor.v0.Popularity/GetContentList", popularityGetContentList)
e.GET("/live.daoanchor.v0.Popularity/AddContent", popularityAddContent)
e.GET("/live.daoanchor.v0.Popularity/EditContent", popularityEditContent)
e.GET("/live.daoanchor.v0.Popularity/DeleteContent", popularityDeleteContent)
}

View File

@@ -0,0 +1,100 @@
<!-- package=live.daoanchor.v0 -->
- [/live.daoanchor.v0.CreateData/CreateCacheList](#live.daoanchor.v0.CreateDataCreateCacheList) CreateCacheList 生成历史数据缓存列表
- [/live.daoanchor.v0.CreateData/CreateLiveCacheList](#live.daoanchor.v0.CreateDataCreateLiveCacheList) CreateLiveCacheList 生成开播历史数据缓存列表
- [/live.daoanchor.v0.CreateData/GetContentMap](#live.daoanchor.v0.CreateDataGetContentMap) GetContentMap 获取需要生成历史数据的对象列表
- [/live.daoanchor.v0.CreateData/CreateDBData](#live.daoanchor.v0.CreateDataCreateDBData)
## /live.daoanchor.v0.CreateData/CreateCacheList
### CreateCacheList 生成历史数据缓存列表
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_ids|否|多个integer||
|content|否|string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```
## /live.daoanchor.v0.CreateData/CreateLiveCacheList
### CreateLiveCacheList 生成开播历史数据缓存列表
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_ids|否|多个integer||
|content|否|string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```
## /live.daoanchor.v0.CreateData/GetContentMap
### GetContentMap 获取需要生成历史数据的对象列表
#### 方法GET
#### 请求参数
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"list": {
"mapKey": 0
}
}
}
```
## /live.daoanchor.v0.CreateData/CreateDBData
### 无标题
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_ids|否|多个integer||
|content|否|string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
<!-- package=live.daoanchor.v0 -->
- [/live.daoanchor.v0.Popularity/GetAnchorGradeList](#live.daoanchor.v0.PopularityGetAnchorGradeList) GetAnchorGradeList 获取人气值主播评级列表
- [/live.daoanchor.v0.Popularity/EditAnchorGrade](#live.daoanchor.v0.PopularityEditAnchorGrade) EditAnchorGrade 编辑主播评级对应的人气值数据
- [/live.daoanchor.v0.Popularity/GetContentList](#live.daoanchor.v0.PopularityGetContentList) GetContentList 人气内容系数列表
- [/live.daoanchor.v0.Popularity/AddContent](#live.daoanchor.v0.PopularityAddContent) AddContent 添加内容系数
- [/live.daoanchor.v0.Popularity/EditContent](#live.daoanchor.v0.PopularityEditContent) EditContent 编辑内容系数
- [/live.daoanchor.v0.Popularity/DeleteContent](#live.daoanchor.v0.PopularityDeleteContent) DeleteContent 删除内容系数
## /live.daoanchor.v0.Popularity/GetAnchorGradeList
### GetAnchorGradeList 获取人气值主播评级列表
#### 方法GET
#### 请求参数
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
// 主播评级id 1=>S;2=>A;3=>B...
"grade_id": 0,
// 主播评级名称 S;A;B...
"grade_name": "",
// 人数基数
"online_base": 0,
// 人气倍数
"popularity_rate": 0
}
]
}
}
```
## /live.daoanchor.v0.Popularity/EditAnchorGrade
### EditAnchorGrade 编辑主播评级对应的人气值数据
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|grade_id|是|integer||
|online_base|是|integer||
|popularity_rate|是|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```
## /live.daoanchor.v0.Popularity/GetContentList
### GetContentList 人气内容系数列表
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|page|否|integer||
|page_size|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"page": 0,
"page_size": 0,
"total_count": 0,
"list": [
{
// 父分区id
"parent_area_id": 0,
// 父分区名称
"parent_area_name": "",
// 二级分区信息<id,name>
"area_list": {
"1": ""
},
// 人气倍率系数
"popularity_rate": 0
}
]
}
}
```
## /live.daoanchor.v0.Popularity/AddContent
### AddContent 添加内容系数
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|parent_id|是|integer||
|list|是|多个integer||
|popularity_rate|是|integer||
|is_all|是|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```
## /live.daoanchor.v0.Popularity/EditContent
### EditContent 编辑内容系数
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|id|是|integer||
|popularity_rate|否|integer||
|list|否|多个integer||
|parent_id|否|integer||
|is_all|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```
## /live.daoanchor.v0.Popularity/DeleteContent
### DeleteContent 删除内容系数
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|id|是|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
}
}
```

View File

@@ -0,0 +1,143 @@
syntax = "proto3";
package live.daoanchor.v0;
option go_package = "v0";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message CreateCacheListReq {
repeated int64 room_ids = 1;
string content = 2;
}
message CreateCacheListResp {
}
message CreateLiveCacheListReq {
repeated int64 room_ids = 1;
string content = 2;
}
message CreateLiveCacheListResp {
}
message GetContentMapReq {
}
message GetContentMapResp {
map<string,int64> list = 1;
}
message CreateDBDataReq {
repeated int64 room_ids = 1;
string content = 2;
}
message CreateDBDataResp {
}
service CreateData {
// CreateCacheList 生成历史数据缓存列表
rpc CreateCacheList(CreateCacheListReq) returns (CreateCacheListResp);
// CreateLiveCacheList 生成开播历史数据缓存列表
rpc CreateLiveCacheList(CreateLiveCacheListReq) returns (CreateLiveCacheListResp);
// GetContentMap 获取需要生成历史数据的对象列表
rpc GetContentMap(GetContentMapReq) returns (GetContentMapResp);
rpc CreateDBData(CreateDBDataReq) returns (CreateDBDataResp);
}
message GetAnchorGradeListReq {
}
message GetAnchorGradeListResp {
repeated List list = 1 [(gogoproto.jsontag) = 'list'];
message List {
//主播评级id 1=>S;2=>A;3=>B...
int64 grade_id = 1 [(gogoproto.jsontag) = 'grade_id'];
//主播评级名称 S;A;B...
string grade_name = 2 [(gogoproto.jsontag) = 'grade_name'];
//人数基数
int64 base_online =3 [(gogoproto.jsontag) = 'online_base'];
//人气倍数
int64 popularity_rate =4 [(gogoproto.jsontag) = 'popularity_rate'];
}
}
message EditAnchorGradeReq {
int64 grade_id =1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 online_base = 2 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 popularity_rate = 3 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
}
message EditAnchorGradeResp {
}
message AddAnchorGradeReq {
int64 id =1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 online_base = 2 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 popularity_rate = 3 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
}
message AddAnchorGradeResp {
}
message GetContentListReq {
int64 page = 1;
int64 page_size = 2;
}
message GetContentListResp {
int64 page = 1;
int64 page_size = 2;
int64 total_count = 3;
repeated List list = 4 [(gogoproto.jsontag) = 'list'];
message List {
//父分区id
int64 parent_area_id = 1 [(gogoproto.jsontag) = 'parent_area_id'];
//父分区名称
string parent_area_name =2 [(gogoproto.jsontag) = 'parent_area_name'];
//二级分区信息<id,name>
map<int64,string> area_list = 3 [(gogoproto.jsontag) = 'area_list'];
//人气倍率系数
int64 popularity_rate =4 [(gogoproto.jsontag) = 'popularity_rate'];
}
}
message EditContentReq {
int64 id = 1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 popularity_rate = 2;
repeated int64 list =3;
int64 parent_id = 4;
int64 is_all =5;
}
message EditContentResp {
}
message AddContentReq {
int64 parent_id = 1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
repeated int64 list = 2 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 popularity_rate = 3 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 is_all =4 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
}
message AddContentResp {
}
message DeleteContentReq {
int64 id = 1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
}
message DeleteContentResp {
}
//人气相关接口
service Popularity {
// GetAnchorGradeList 获取人气值主播评级列表
rpc GetAnchorGradeList(GetAnchorGradeListReq) returns (GetAnchorGradeListResp);
// EditAnchorGrade 编辑主播评级对应的人气值数据
rpc EditAnchorGrade(EditAnchorGradeReq) returns (EditAnchorGradeResp);
// GetContentList 人气内容系数列表
rpc GetContentList(GetContentListReq) returns (GetContentListResp);
// AddContent 添加内容系数
rpc AddContent(AddContentReq) returns (AddContentResp);
// EditContent 编辑内容系数
rpc EditContent(EditContentReq) returns (EditContentResp);
// DeleteContent 删除内容系数
rpc DeleteContent(DeleteContentReq) returns (DeleteContentResp);
}

View File

@@ -0,0 +1,27 @@
package v0
import (
"context"
"google.golang.org/grpc"
"go-common/library/net/rpc/warden"
)
const AppID = "live.daoanchor"
type Client struct {
CreateDataClient
}
// NewClient new anchor grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (*Client, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
cli := &Client{}
cli.CreateDataClient = NewCreateDataClient(conn)
return cli, nil
}

View File

@@ -0,0 +1,62 @@
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 = ["@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/live/dao-anchor/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"api.bm.go",
"client.go",
],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/live/dao-anchor/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding: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",
"@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"],
)

View File

@@ -0,0 +1,331 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api.proto
/*
Package v1 is a generated blademaster stub package.
This code was generated with go-common/app/tool/bmgen/protoc-gen-bm v0.1.
It is generated from these files:
api.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
var PathDaoAnchorFetchRoomByIDs = "/live.daoanchor.v1.DaoAnchor/FetchRoomByIDs"
var PathDaoAnchorRoomOnlineList = "/live.daoanchor.v1.DaoAnchor/RoomOnlineList"
var PathDaoAnchorRoomOnlineListByArea = "/live.daoanchor.v1.DaoAnchor/RoomOnlineListByArea"
var PathDaoAnchorRoomOnlineListByAttrs = "/live.daoanchor.v1.DaoAnchor/RoomOnlineListByAttrs"
var PathDaoAnchorRoomCreate = "/live.daoanchor.v1.DaoAnchor/RoomCreate"
var PathDaoAnchorRoomUpdate = "/live.daoanchor.v1.DaoAnchor/RoomUpdate"
var PathDaoAnchorRoomBatchUpdate = "/live.daoanchor.v1.DaoAnchor/RoomBatchUpdate"
var PathDaoAnchorRoomExtendUpdate = "/live.daoanchor.v1.DaoAnchor/RoomExtendUpdate"
var PathDaoAnchorRoomExtendBatchUpdate = "/live.daoanchor.v1.DaoAnchor/RoomExtendBatchUpdate"
var PathDaoAnchorRoomExtendIncre = "/live.daoanchor.v1.DaoAnchor/RoomExtendIncre"
var PathDaoAnchorRoomExtendBatchIncre = "/live.daoanchor.v1.DaoAnchor/RoomExtendBatchIncre"
var PathDaoAnchorRoomTagCreate = "/live.daoanchor.v1.DaoAnchor/RoomTagCreate"
var PathDaoAnchorRoomAttrCreate = "/live.daoanchor.v1.DaoAnchor/RoomAttrCreate"
var PathDaoAnchorRoomAttrSetEx = "/live.daoanchor.v1.DaoAnchor/RoomAttrSetEx"
var PathDaoAnchorAnchorUpdate = "/live.daoanchor.v1.DaoAnchor/AnchorUpdate"
var PathDaoAnchorAnchorBatchUpdate = "/live.daoanchor.v1.DaoAnchor/AnchorBatchUpdate"
var PathDaoAnchorAnchorIncre = "/live.daoanchor.v1.DaoAnchor/AnchorIncre"
var PathDaoAnchorAnchorBatchIncre = "/live.daoanchor.v1.DaoAnchor/AnchorBatchIncre"
var PathDaoAnchorFetchAreas = "/live.daoanchor.v1.DaoAnchor/FetchAreas"
var PathDaoAnchorFetchAttrByIDs = "/live.daoanchor.v1.DaoAnchor/FetchAttrByIDs"
var PathDaoAnchorDeleteAttr = "/live.daoanchor.v1.DaoAnchor/DeleteAttr"
// ===================
// DaoAnchor Interface
// ===================
type DaoAnchorBMServer interface {
// FetchRoomByIDs 查询房间信息
FetchRoomByIDs(ctx context.Context, req *RoomByIDsReq) (resp *RoomByIDsResp, err error)
// RoomOnlineList 在线房间列表
RoomOnlineList(ctx context.Context, req *RoomOnlineListReq) (resp *RoomOnlineListResp, err error)
// RoomOnlineListByArea 分区在线房间列表(只返回room_id列表不传分区默认查找所有)
RoomOnlineListByArea(ctx context.Context, req *RoomOnlineListByAreaReq) (resp *RoomOnlineListByAreaResp, err error)
// RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
RoomOnlineListByAttrs(ctx context.Context, req *RoomOnlineListByAttrsReq) (resp *RoomOnlineListByAttrsResp, err error)
// RoomCreate 房间创建
RoomCreate(ctx context.Context, req *RoomCreateReq) (resp *RoomCreateResp, err error)
// RoomUpdate 房间信息更新
RoomUpdate(ctx context.Context, req *RoomUpdateReq) (resp *UpdateResp, err error)
// RoomBatchUpdate 房间信息批量更新
RoomBatchUpdate(ctx context.Context, req *RoomBatchUpdateReq) (resp *UpdateResp, err error)
// RoomExtendUpdate 房间扩展信息更新
RoomExtendUpdate(ctx context.Context, req *RoomExtendUpdateReq) (resp *UpdateResp, err error)
// RoomExtendBatchUpdate 房间扩展信息批量更新
RoomExtendBatchUpdate(ctx context.Context, req *RoomExtendBatchUpdateReq) (resp *UpdateResp, err error)
// RoomExtendIncre 房间信息增量更新
RoomExtendIncre(ctx context.Context, req *RoomExtendIncreReq) (resp *UpdateResp, err error)
// RoomExtendBatchIncre 房间信息批量增量更新
RoomExtendBatchIncre(ctx context.Context, req *RoomExtendBatchIncreReq) (resp *UpdateResp, err error)
// RoomTagCreate 房间Tag创建
RoomTagCreate(ctx context.Context, req *RoomTagCreateReq) (resp *UpdateResp, err error)
// RoomAttrCreate 房间Attr创建
RoomAttrCreate(ctx context.Context, req *RoomAttrCreateReq) (resp *UpdateResp, err error)
// RoomAttrSetEx 房间Attr更新
RoomAttrSetEx(ctx context.Context, req *RoomAttrSetExReq) (resp *UpdateResp, err error)
// AnchorUpdate 主播信息更新
AnchorUpdate(ctx context.Context, req *AnchorUpdateReq) (resp *UpdateResp, err error)
// AnchorBatchUpdate 主播信息批量更新
AnchorBatchUpdate(ctx context.Context, req *AnchorBatchUpdateReq) (resp *UpdateResp, err error)
// AnchorIncre 主播信息增量更新
AnchorIncre(ctx context.Context, req *AnchorIncreReq) (resp *UpdateResp, err error)
// AnchorBatchIncre 主播信息批量增量更新
AnchorBatchIncre(ctx context.Context, req *AnchorBatchIncreReq) (resp *UpdateResp, err error)
// FetchAreas 根据父分区号查询子分区
FetchAreas(ctx context.Context, req *FetchAreasReq) (resp *FetchAreasResp, err error)
// FetchAttrByIDs 批量根据房间号查询指标
FetchAttrByIDs(ctx context.Context, req *FetchAttrByIDsReq) (resp *FetchAttrByIDsResp, err error)
// DeleteAttr 删除某一个指标
DeleteAttr(ctx context.Context, req *DeleteAttrReq) (resp *UpdateResp, err error)
}
var v1DaoAnchorSvc DaoAnchorBMServer
func daoAnchorFetchRoomByIDs(c *bm.Context) {
p := new(RoomByIDsReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.FetchRoomByIDs(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomOnlineList(c *bm.Context) {
p := new(RoomOnlineListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomOnlineList(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomOnlineListByArea(c *bm.Context) {
p := new(RoomOnlineListByAreaReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomOnlineListByArea(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomOnlineListByAttrs(c *bm.Context) {
p := new(RoomOnlineListByAttrsReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomOnlineListByAttrs(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomCreate(c *bm.Context) {
p := new(RoomCreateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomCreate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomUpdate(c *bm.Context) {
p := new(RoomUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomBatchUpdate(c *bm.Context) {
p := new(RoomBatchUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomBatchUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomExtendUpdate(c *bm.Context) {
p := new(RoomExtendUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomExtendUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomExtendBatchUpdate(c *bm.Context) {
p := new(RoomExtendBatchUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomExtendBatchUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomExtendIncre(c *bm.Context) {
p := new(RoomExtendIncreReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomExtendIncre(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomExtendBatchIncre(c *bm.Context) {
p := new(RoomExtendBatchIncreReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomExtendBatchIncre(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomTagCreate(c *bm.Context) {
p := new(RoomTagCreateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomTagCreate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomAttrCreate(c *bm.Context) {
p := new(RoomAttrCreateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomAttrCreate(c, p)
c.JSON(resp, err)
}
func daoAnchorRoomAttrSetEx(c *bm.Context) {
p := new(RoomAttrSetExReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.RoomAttrSetEx(c, p)
c.JSON(resp, err)
}
func daoAnchorAnchorUpdate(c *bm.Context) {
p := new(AnchorUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.AnchorUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorAnchorBatchUpdate(c *bm.Context) {
p := new(AnchorBatchUpdateReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.AnchorBatchUpdate(c, p)
c.JSON(resp, err)
}
func daoAnchorAnchorIncre(c *bm.Context) {
p := new(AnchorIncreReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.AnchorIncre(c, p)
c.JSON(resp, err)
}
func daoAnchorAnchorBatchIncre(c *bm.Context) {
p := new(AnchorBatchIncreReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.AnchorBatchIncre(c, p)
c.JSON(resp, err)
}
func daoAnchorFetchAreas(c *bm.Context) {
p := new(FetchAreasReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.FetchAreas(c, p)
c.JSON(resp, err)
}
func daoAnchorFetchAttrByIDs(c *bm.Context) {
p := new(FetchAttrByIDsReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.FetchAttrByIDs(c, p)
c.JSON(resp, err)
}
func daoAnchorDeleteAttr(c *bm.Context) {
p := new(DeleteAttrReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1DaoAnchorSvc.DeleteAttr(c, p)
c.JSON(resp, err)
}
// RegisterDaoAnchorBMServer Register the blademaster route
func RegisterDaoAnchorBMServer(e *bm.Engine, server DaoAnchorBMServer) {
v1DaoAnchorSvc = server
e.GET("/live.daoanchor.v1.DaoAnchor/FetchRoomByIDs", daoAnchorFetchRoomByIDs)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomOnlineList", daoAnchorRoomOnlineList)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomOnlineListByArea", daoAnchorRoomOnlineListByArea)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomOnlineListByAttrs", daoAnchorRoomOnlineListByAttrs)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomCreate", daoAnchorRoomCreate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomUpdate", daoAnchorRoomUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomBatchUpdate", daoAnchorRoomBatchUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomExtendUpdate", daoAnchorRoomExtendUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomExtendBatchUpdate", daoAnchorRoomExtendBatchUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomExtendIncre", daoAnchorRoomExtendIncre)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomExtendBatchIncre", daoAnchorRoomExtendBatchIncre)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomTagCreate", daoAnchorRoomTagCreate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomAttrCreate", daoAnchorRoomAttrCreate)
e.GET("/live.daoanchor.v1.DaoAnchor/RoomAttrSetEx", daoAnchorRoomAttrSetEx)
e.GET("/live.daoanchor.v1.DaoAnchor/AnchorUpdate", daoAnchorAnchorUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/AnchorBatchUpdate", daoAnchorAnchorBatchUpdate)
e.GET("/live.daoanchor.v1.DaoAnchor/AnchorIncre", daoAnchorAnchorIncre)
e.GET("/live.daoanchor.v1.DaoAnchor/AnchorBatchIncre", daoAnchorAnchorBatchIncre)
e.GET("/live.daoanchor.v1.DaoAnchor/FetchAreas", daoAnchorFetchAreas)
e.GET("/live.daoanchor.v1.DaoAnchor/FetchAttrByIDs", daoAnchorFetchAttrByIDs)
e.GET("/live.daoanchor.v1.DaoAnchor/DeleteAttr", daoAnchorDeleteAttr)
}

View File

@@ -0,0 +1,835 @@
<!-- package=live.daoanchor.v1 -->
- [/live.daoanchor.v1.DaoAnchor/FetchRoomByIDs](#live.daoanchor.v1.DaoAnchorFetchRoomByIDs) FetchRoomByIDs 查询房间信息
- [/live.daoanchor.v1.DaoAnchor/RoomOnlineList](#live.daoanchor.v1.DaoAnchorRoomOnlineList) RoomOnlineList 在线房间列表
- [/live.daoanchor.v1.DaoAnchor/RoomOnlineListByArea](#live.daoanchor.v1.DaoAnchorRoomOnlineListByArea) RoomOnlineListByArea 分区在线房间列表(只返回room_id列表不传分区默认查找所有)
- [/live.daoanchor.v1.DaoAnchor/RoomOnlineListByAttrs](#live.daoanchor.v1.DaoAnchorRoomOnlineListByAttrs) RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
- [/live.daoanchor.v1.DaoAnchor/RoomCreate](#live.daoanchor.v1.DaoAnchorRoomCreate) RoomCreate 房间创建
- [/live.daoanchor.v1.DaoAnchor/RoomUpdate](#live.daoanchor.v1.DaoAnchorRoomUpdate) RoomUpdate 房间信息更新
- [/live.daoanchor.v1.DaoAnchor/RoomBatchUpdate](#live.daoanchor.v1.DaoAnchorRoomBatchUpdate) RoomBatchUpdate 房间信息批量更新
- [/live.daoanchor.v1.DaoAnchor/RoomExtendUpdate](#live.daoanchor.v1.DaoAnchorRoomExtendUpdate) RoomExtendUpdate 房间扩展信息更新
- [/live.daoanchor.v1.DaoAnchor/RoomExtendBatchUpdate](#live.daoanchor.v1.DaoAnchorRoomExtendBatchUpdate) RoomExtendBatchUpdate 房间扩展信息批量更新
- [/live.daoanchor.v1.DaoAnchor/RoomExtendIncre](#live.daoanchor.v1.DaoAnchorRoomExtendIncre) RoomExtendIncre 房间信息增量更新
- [/live.daoanchor.v1.DaoAnchor/RoomExtendBatchIncre](#live.daoanchor.v1.DaoAnchorRoomExtendBatchIncre) RoomExtendBatchIncre 房间信息批量增量更新
- [/live.daoanchor.v1.DaoAnchor/RoomTagCreate](#live.daoanchor.v1.DaoAnchorRoomTagCreate) RoomTagCreate 房间Tag创建
- [/live.daoanchor.v1.DaoAnchor/RoomAttrCreate](#live.daoanchor.v1.DaoAnchorRoomAttrCreate) RoomAttrCreate 房间Attr创建
- [/live.daoanchor.v1.DaoAnchor/RoomAttrSetEx](#live.daoanchor.v1.DaoAnchorRoomAttrSetEx) RoomAttrSetEx 房间Attr更新
- [/live.daoanchor.v1.DaoAnchor/AnchorUpdate](#live.daoanchor.v1.DaoAnchorAnchorUpdate) AnchorUpdate 主播信息更新
- [/live.daoanchor.v1.DaoAnchor/AnchorBatchUpdate](#live.daoanchor.v1.DaoAnchorAnchorBatchUpdate) AnchorBatchUpdate 主播信息批量更新
- [/live.daoanchor.v1.DaoAnchor/AnchorIncre](#live.daoanchor.v1.DaoAnchorAnchorIncre) AnchorIncre 主播信息增量更新
- [/live.daoanchor.v1.DaoAnchor/AnchorBatchIncre](#live.daoanchor.v1.DaoAnchorAnchorBatchIncre) AnchorBatchIncre 主播信息批量增量更新
- [/live.daoanchor.v1.DaoAnchor/FetchAreas](#live.daoanchor.v1.DaoAnchorFetchAreas) FetchAreas 根据父分区号查询子分区
- [/live.daoanchor.v1.DaoAnchor/FetchAttrByIDs](#live.daoanchor.v1.DaoAnchorFetchAttrByIDs) FetchAttrByIDs 批量根据房间号查询指标
- [/live.daoanchor.v1.DaoAnchor/DeleteAttr](#live.daoanchor.v1.DaoAnchorDeleteAttr) DeleteAttr 删除某一个指标
## /live.daoanchor.v1.DaoAnchor/FetchRoomByIDs
### FetchRoomByIDs 查询房间信息
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_ids|否|多个integer||
|uids|否|多个integer||
|fields|否|多个string||
|default_fields|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"room_data_set": {
"1": {
"uid": 0,
"room_id": 0,
"short_id": 0,
"title": "",
"cover": "",
"tags": "",
"background": "",
"description": "",
"live_status": 0,
"live_start_time": 0,
"live_screen_type": 0,
"live_mark": 0,
"lock_status": 0,
"lock_time": 0,
"hidden_status": 0,
"hidden_time": 0,
"area_id": 0,
"area_name": "",
"parent_area_id": 0,
"parent_area_name": "",
"keyframe": "",
"popularity_count": 0,
"tag_list": [
{
"tag_id": 0,
"tag_sub_id": 0,
"tag_value": 0,
"tag_ext": "",
"tag_expire_at": 0
}
],
"anchor_profile_type": 0,
"anchor_level": {
// 当前等级
"level": 0,
// 当前等级颜色
"color": 0,
// 当前积分
"score": 0,
// 当前等级最小积分
"left": 0,
// 当前等级最大积分
"right": 0,
// 最大等级
"max_level": 0
},
"anchor_round_switch": 0,
"anchor_round_status": 0,
"anchor_record_switch": 0,
"anchor_record_status": 0,
"anchor_san": 0,
// 0默认 1摄像头直播 2录屏直播 3语音直播
"live_type": 0
}
}
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomOnlineList
### RoomOnlineList 在线房间列表
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|filter|否|string||
|sort|否|string||
|page|否|integer||
|page_size|否|integer||
|fields|否|多个string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"room_data_list": {
"1": {
"uid": 0,
"room_id": 0,
"short_id": 0,
"title": "",
"cover": "",
"tags": "",
"background": "",
"description": "",
"live_status": 0,
"live_start_time": 0,
"live_screen_type": 0,
"live_mark": 0,
"lock_status": 0,
"lock_time": 0,
"hidden_status": 0,
"hidden_time": 0,
"area_id": 0,
"area_name": "",
"parent_area_id": 0,
"parent_area_name": "",
"keyframe": "",
"popularity_count": 0,
"tag_list": [
{
"tag_id": 0,
"tag_sub_id": 0,
"tag_value": 0,
"tag_ext": "",
"tag_expire_at": 0
}
],
"anchor_profile_type": 0,
"anchor_level": {
// 当前等级
"level": 0,
// 当前等级颜色
"color": 0,
// 当前积分
"score": 0,
// 当前等级最小积分
"left": 0,
// 当前等级最大积分
"right": 0,
// 最大等级
"max_level": 0
},
"anchor_round_switch": 0,
"anchor_round_status": 0,
"anchor_record_switch": 0,
"anchor_record_status": 0,
"anchor_san": 0,
// 0默认 1摄像头直播 2录屏直播 3语音直播
"live_type": 0
}
}
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomOnlineListByArea
### RoomOnlineListByArea 分区在线房间列表(只返回room_id列表不传分区默认查找所有)
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|area_ids|否|多个integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"room_ids": [
0
]
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomOnlineListByAttrs
### RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
#### 方法GET
#### 请求参数
```javascript
{
"attrs": [
{
"attr_id": 0,
"attr_sub_id": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"attrs": {
"1": {
"uid": 0,
"room_id": 0,
"area_id": 0,
"parent_area_id": 0,
"tag_list": [
{
"tag_id": 0,
"tag_sub_id": 0,
"tag_value": 0,
"tag_ext": "",
"tag_expire_at": 0
}
],
"attr_list": [
{
"room_id": 0,
"attr_id": 0,
"attr_sub_id": 0,
"attr_value": 0
}
],
"popularity_count": 0,
"anchor_profile_type": 0
}
}
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomCreate
### RoomCreate 房间创建
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|是|integer||
|room_id|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"room_id": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomUpdate
### RoomUpdate 房间信息更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|fields|是|多个string||
|room_id|是|integer||
|title|否|string||
|cover|否|string||
|tags|否|string||
|background|否|string||
|description|否|string||
|live_start_time|否|integer||
|live_screen_type|否|integer||
|lock_status|否|integer||
|lock_time|否|integer||
|hidden_time|否|integer||
|area_id|否|integer||
|anchor_round_switch|否|integer||
|anchor_record_switch|否|integer||
|live_type|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomBatchUpdate
### RoomBatchUpdate 房间信息批量更新
#### 方法GET
#### 请求参数
```javascript
{
"reqs": [
{
"fields": [
""
],
"room_id": 0,
"title": "",
"cover": "",
"tags": "",
"background": "",
"description": "",
"live_start_time": 0,
"live_screen_type": 0,
"lock_status": 0,
"lock_time": 0,
"hidden_time": 0,
"area_id": 0,
"anchor_round_switch": 0,
"anchor_record_switch": 0,
"live_type": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomExtendUpdate
### RoomExtendUpdate 房间扩展信息更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|fields|是|多个string||
|room_id|是|integer||
|keyframe|否|string||
|danmu_count|否|integer||
|popularity_count|否|integer||
|audience_count|否|integer||
|gift_count|否|integer||
|gift_gold_amount|否|integer||
|gift_gold_count|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomExtendBatchUpdate
### RoomExtendBatchUpdate 房间扩展信息批量更新
#### 方法GET
#### 请求参数
```javascript
{
"reqs": [
{
"fields": [
""
],
"room_id": 0,
"keyframe": "",
"danmu_count": 0,
"popularity_count": 0,
"audience_count": 0,
"gift_count": 0,
"gift_gold_amount": 0,
"gift_gold_count": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomExtendIncre
### RoomExtendIncre 房间信息增量更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|req_id|是|string||
|fields|是|多个string||
|room_id|是|integer||
|danmu_count|否|integer||
|popularity_count|否|integer||
|audience_count|否|integer||
|gift_count|否|integer||
|gift_gold_amount|否|integer||
|gift_gold_count|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomExtendBatchIncre
### RoomExtendBatchIncre 房间信息批量增量更新
#### 方法GET
#### 请求参数
```javascript
{
"reqs": [
{
"req_id": "",
"fields": [
""
],
"room_id": 0,
"danmu_count": 0,
"popularity_count": 0,
"audience_count": 0,
"gift_count": 0,
"gift_gold_amount": 0,
"gift_gold_count": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomTagCreate
### RoomTagCreate 房间Tag创建
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_id|是|integer||
|tag_id|是|integer||
|tag_sub_id|否|integer||
|tag_value|否|integer||
|tag_ext|否|string||
|tag_expire_at|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomAttrCreate
### RoomAttrCreate 房间Attr创建
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_id|是|integer||
|attr_id|是|integer||
|attr_sub_id|否|integer||
|attr_value|否|integer||
|attr_ext|否|string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/RoomAttrSetEx
### RoomAttrSetEx 房间Attr更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_id|是|integer||
|attr_id|是|integer||
|attr_sub_id|否|integer||
|attr_value|否|integer||
|attr_ext|否|string||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/AnchorUpdate
### AnchorUpdate 主播信息更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|fields|是|多个string||
|uid|是|integer||
|profile_type|否|integer||
|san_score|否|integer||
|round_status|否|integer||
|record_status|否|integer||
|exp|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/AnchorBatchUpdate
### AnchorBatchUpdate 主播信息批量更新
#### 方法GET
#### 请求参数
```javascript
{
"reqs": [
{
"fields": [
""
],
"uid": 0,
"profile_type": 0,
"san_score": 0,
"round_status": 0,
"record_status": 0,
"exp": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/AnchorIncre
### AnchorIncre 主播信息增量更新
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|req_id|是|string||
|fields|是|多个string||
|uid|是|integer||
|san_score|否|integer||
|exp|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/AnchorBatchIncre
### AnchorBatchIncre 主播信息批量增量更新
#### 方法GET
#### 请求参数
```javascript
{
"reqs": [
{
"req_id": "",
"fields": [
""
],
"uid": 0,
"san_score": 0,
"exp": 0
}
]
}
```
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```
## /live.daoanchor.v1.DaoAnchor/FetchAreas
### FetchAreas 根据父分区号查询子分区
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|area_id|否|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"info": {
"area_id": 0,
"area_name": ""
},
"areas": [
{
"area_id": 0,
"area_name": ""
}
]
}
}
```
## /live.daoanchor.v1.DaoAnchor/FetchAttrByIDs
### FetchAttrByIDs 批量根据房间号查询指标
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_ids|是|多个integer||
|attr_id|是|integer||
|attr_sub_id|是|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"attrs": {
"1": {
"room_id": 0,
"attr_id": 0,
"attr_sub_id": 0,
"attr_value": 0
}
}
}
}
```
## /live.daoanchor.v1.DaoAnchor/DeleteAttr
### DeleteAttr 删除某一个指标
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|attr_id|是|integer||
|attr_sub_id|是|integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
"affected_rows": 0
}
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,322 @@
syntax = "proto3";
package live.daoanchor.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message AnchorLevel {
// 当前等级
int64 level = 1;
// 当前等级颜色
int64 color = 2;
// 当前积分
int64 score = 3;
// 当前等级最小积分
int64 left = 4;
// 当前等级最大积分
int64 right = 5;
// 最大等级
int64 max_level = 6;
}
message TagData {
int64 tag_id = 1;
int64 tag_sub_id = 2;
int64 tag_value = 3;
string tag_ext = 4;
int64 tag_expire_at = 5;
}
message RoomData {
int64 uid = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 room_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 short_id = 3 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
string title = 4 [(gogoproto.moretags) = "validate:\"required\""];
string cover = 5;
string tags = 6;
string background = 7;
string description = 8;
int64 live_status = 9 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 live_start_time = 10 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 live_screen_type = 11 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 live_mark = 12;
int64 lock_status = 13;
int64 lock_time = 14;
int64 hidden_status = 15 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 hidden_time = 16;
int64 area_id = 17 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
string area_name = 18 [(gogoproto.moretags) = "validate:\"required\""];
int64 parent_area_id = 19 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
string parent_area_name = 20 [(gogoproto.moretags) = "validate:\"required\""];
string keyframe = 21;
int64 popularity_count = 22;
repeated TagData tag_list = 23;
int64 anchor_profile_type = 25;
AnchorLevel anchor_level = 26;
int64 anchor_round_switch = 27;
int64 anchor_round_status = 28;
int64 anchor_record_switch = 29;
int64 anchor_record_status = 30;
int64 anchor_san = 31;
// 0默认 1摄像头直播 2录屏直播 3语音直播
int64 live_type = 32;
}
message RoomByIDsReq {
repeated int64 room_ids = 1;
repeated int64 uids = 2;
repeated string fields = 3;
int64 default_fields = 4;
}
message RoomByIDsResp {
map<int64, RoomData> room_data_set = 1;
}
message RoomOnlineListReq {
string filter = 1;
string sort = 2;
int64 page = 3;
int64 page_size = 4;
repeated string fields = 5;
}
message RoomOnlineListResp {
map<int64, RoomData> room_data_list = 1;
}
message RoomOnlineListByAreaReq {
repeated int64 area_ids = 1;
}
message RoomOnlineListByAreaResp {
repeated int64 room_ids = 1;
}
message RoomCreateReq {
int64 uid = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 room_id = 2;
}
message RoomCreateResp {
int64 room_id = 1;
}
message UpdateResp {
int64 affected_rows = 1;
}
message RoomUpdateReq {
repeated string fields = 1 [(gogoproto.moretags) = "validate:\"required\""];
int64 room_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
string title = 3;
string cover = 4;
string tags = 5;
string background = 6;
string description = 7;
int64 live_start_time = 8;
int64 live_screen_type = 9;
int64 lock_status = 10;
int64 lock_time = 11;
int64 hidden_time = 12;
int64 area_id = 13;
int64 anchor_round_switch = 14;
int64 anchor_record_switch = 15;
int64 live_type = 16;
}
message RoomBatchUpdateReq {
repeated RoomUpdateReq reqs = 1 [(gogoproto.moretags) = "validate:\"required\""];
}
message AnchorUpdateReq {
repeated string fields = 1 [(gogoproto.moretags) = "validate:\"required\""];
int64 uid = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 profile_type = 3;
int64 san_score = 4;
int64 round_status = 5;
int64 record_status = 6;
int64 exp = 7;
}
message AnchorBatchUpdateReq {
repeated AnchorUpdateReq reqs = 1 [(gogoproto.moretags) = "validate:\"required\""];
}
message AnchorIncreReq {
string req_id = 1 [(gogoproto.moretags) = "validate:\"required\""];
repeated string fields = 2 [(gogoproto.moretags) = "validate:\"required\""];
int64 uid = 3 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 san_score = 4;
int64 exp = 5;
}
message AnchorBatchIncreReq {
repeated AnchorIncreReq reqs = 1 [(gogoproto.moretags) = "validate:\"required\""];
}
message RoomExtendUpdateReq {
repeated string fields = 1 [(gogoproto.moretags) = "validate:\"required\""];
int64 room_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
string keyframe = 3;
int64 danmu_count = 4;
int64 popularity_count = 5;
int64 audience_count = 6;
int64 gift_count = 7;
int64 gift_gold_amount = 8;
int64 gift_gold_count = 9;
}
message RoomExtendBatchUpdateReq {
repeated RoomExtendUpdateReq reqs = 1 [(gogoproto.moretags) = "validate:\"required\""];
}
message RoomExtendIncreReq {
string req_id = 1 [(gogoproto.moretags) = "validate:\"required\""];
repeated string fields = 2 [(gogoproto.moretags) = "validate:\"required\""];
int64 room_id = 3 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 danmu_count = 4;
int64 popularity_count = 5;
int64 audience_count = 6;
int64 gift_count = 7;
int64 gift_gold_amount = 8;
int64 gift_gold_count = 9;
}
message RoomExtendBatchIncreReq {
repeated RoomExtendIncreReq reqs = 1 [(gogoproto.moretags) = "validate:\"required\""];
}
message RoomTagCreateReq {
int64 room_id = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 tag_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 tag_sub_id = 3;
int64 tag_value = 4;
string tag_ext = 5;
int64 tag_expire_at = 6;
}
message RoomAttrCreateReq {
int64 room_id = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_sub_id = 3;
int64 attr_value = 4;
string attr_ext = 5;
}
message RoomAttrSetExReq {
int64 room_id = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_sub_id = 3;
int64 attr_value = 4;
string attr_ext = 5;
}
message FetchAreasReq {
int64 area_id = 1;
}
message AreaInfo {
int64 area_id = 1;
string area_name = 2;
}
message FetchAreasResp {
AreaInfo info = 1;
repeated AreaInfo areas = 2;
}
message FetchAttrByIDsReq {
repeated int64 room_ids = 1 [(gogoproto.moretags) = "validate:\"dive,gt=0,required\""];
int64 attr_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_sub_id = 3 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
}
message AttrData {
int64 room_id = 1;
int64 attr_id = 2;
int64 attr_sub_id = 3;
int64 attr_value = 4;
}
message FetchAttrByIDsResp {
map<int64, AttrData> attrs = 1;
}
message AttrReq {
int64 attr_id = 1;
int64 attr_sub_id = 2;
}
message RoomOnlineListByAttrsReq {
repeated AttrReq attrs = 1;
}
message AttrResp {
int64 uid = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 room_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 area_id = 3 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 parent_area_id = 4 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
repeated TagData tag_list = 5;
repeated AttrData attr_list = 6;
int64 popularity_count = 7;
int64 anchor_profile_type = 8;
}
message RoomOnlineListByAttrsResp {
map<int64, AttrResp> attrs = 1;
}
message DeleteAttrReq {
int64 attr_id = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
int64 attr_sub_id = 2 [(gogoproto.moretags) = "validate:\"gt=0,required\""];
}
service DaoAnchor {
// FetchRoomByIDs 查询房间信息
rpc FetchRoomByIDs(RoomByIDsReq) returns (RoomByIDsResp);
// RoomOnlineList 在线房间列表
rpc RoomOnlineList(RoomOnlineListReq) returns (RoomOnlineListResp);
// RoomOnlineListByArea 分区在线房间列表(只返回room_id列表不传分区默认查找所有)
rpc RoomOnlineListByArea(RoomOnlineListByAreaReq) returns (RoomOnlineListByAreaResp);
// RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
rpc RoomOnlineListByAttrs(RoomOnlineListByAttrsReq) returns (RoomOnlineListByAttrsResp);
// RoomCreate 房间创建
rpc RoomCreate(RoomCreateReq) returns (RoomCreateResp);
// RoomUpdate 房间信息更新
rpc RoomUpdate(RoomUpdateReq) returns (UpdateResp);
// RoomBatchUpdate 房间信息批量更新
rpc RoomBatchUpdate(RoomBatchUpdateReq) returns (UpdateResp);
// RoomExtendUpdate 房间扩展信息更新
rpc RoomExtendUpdate(RoomExtendUpdateReq) returns (UpdateResp);
// RoomExtendBatchUpdate 房间扩展信息批量更新
rpc RoomExtendBatchUpdate(RoomExtendBatchUpdateReq) returns (UpdateResp);
// RoomExtendIncre 房间信息增量更新
rpc RoomExtendIncre(RoomExtendIncreReq) returns (UpdateResp);
// RoomExtendBatchIncre 房间信息批量增量更新
rpc RoomExtendBatchIncre(RoomExtendBatchIncreReq) returns (UpdateResp);
// RoomTagCreate 房间Tag创建
rpc RoomTagCreate(RoomTagCreateReq) returns (UpdateResp);
// RoomAttrCreate 房间Attr创建
rpc RoomAttrCreate(RoomAttrCreateReq) returns (UpdateResp);
// RoomAttrSetEx 房间Attr更新
rpc RoomAttrSetEx(RoomAttrSetExReq) returns (UpdateResp);
// AnchorUpdate 主播信息更新
rpc AnchorUpdate(AnchorUpdateReq) returns (UpdateResp);
// AnchorBatchUpdate 主播信息批量更新
rpc AnchorBatchUpdate(AnchorBatchUpdateReq) returns (UpdateResp);
// AnchorIncre 主播信息增量更新
rpc AnchorIncre(AnchorIncreReq) returns (UpdateResp);
// AnchorBatchIncre 主播信息批量增量更新
rpc AnchorBatchIncre(AnchorBatchIncreReq) returns (UpdateResp);
// FetchAreas 根据父分区号查询子分区
rpc FetchAreas(FetchAreasReq) returns (FetchAreasResp);
// FetchAttrByIDs 批量根据房间号查询指标
rpc FetchAttrByIDs(FetchAttrByIDsReq) returns (FetchAttrByIDsResp);
// DeleteAttr 删除某一个指标
rpc DeleteAttr(DeleteAttrReq) returns (UpdateResp);
}

View File

@@ -0,0 +1,27 @@
package v1
import (
"context"
"google.golang.org/grpc"
"go-common/library/net/rpc/warden"
)
const AppID = "live.daoanchor"
type Client struct {
DaoAnchorClient
}
// NewClient new anchor grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (*Client, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
cli := &Client{}
cli.DaoAnchorClient = NewDaoAnchorClient(conn)
return cli, nil
}

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/live/dao-anchor/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/server/grpc:go_default_library",
"//app/service/live/dao-anchor/server/http:go_default_library",
"//app/service/live/dao-anchor/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,60 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/server/grpc"
"go-common/app/service/live/dao-anchor/server/http"
"go-common/app/service/live/dao-anchor/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()
log.Info("dao-anchor-service start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
svc := service.New(conf.Conf)
http.Init(conf.Conf)
// start grpc server
svr, err := grpc.New(svc)
if err != nil {
panic(fmt.Sprintf("start dao-anchor grpc server fail! %s", err))
}
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()
if svr != nil {
svr.Shutdown(context.Background())
}
log.Info("dao-anchor-service exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,180 @@
[Common]
ExpireTime = 86400
[Log]
Stdout = true
[LRUCache]
InstCnt = 1
Bucket = 1
Capacity = 1024
Timeout = 10
[client]
timeout = "10s"
[mysql]
addr = "172.16.38.158:3312"
dsn = "live:oWni@ElNs0P0C(dphdj*F1y4@tcp(172.16.38.158:3312)/xanchor?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["live:oWni@ElNs0P0C(dphdj*F1y4@tcp(172.16.38.158:3312)/xanchor?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[LiveAppMySQL]
dsn = "live:oWni@ElNs0P0C(dphdj*F1y4@tcp(172.16.38.158:3312)/live-app?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout = "4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[redis]
name = "dao-anchor-service"
proto = "tcp"
addr = "172.16.38.158:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[memcache]
name = "dao-anchor-service"
proto = "tcp"
addr = ""
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[liveDanmuSub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveDanmuSend-LiveLive-Daoanchor-S"
topic = "LiveDanmuSend-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[liveGiftSendByPaySub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveGiftSendByPay-LiveLive-Daoanchor-S"
topic = "LiveGiftSendByPay-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[liveGiftSendByFreeSub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "liveGiftSendByFree-LiveLive-Daoanchor-S"
topic = "LiveGiftSendByFree-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[LiveGuardBuySub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveGuardBuy-LiveLive-Daoanchor-S"
topic = "LiveGuardBuy-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[livePopularitySub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LivePopularity-LiveLive-Daoanchor-S"
topic = "LivePopularity-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[liveValidLiveDaysSub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveValidLiveDays-LiveLive-Daoanchor-S"
topic = "LiveValidLiveDays-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[liveRoomTagSub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveRoomTag-LiveLive-Daoanchor-S"
topic = "LiveRoomTag-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"
[liveRankListSub]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveRankList-LiveLive-Daoanchor-S"
topic = "LiveRankList-T"
action ="sub"
name = "service/dao-anchor"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 10
active = 100
dialTimeout = "10s"
readTimeout = "40s"
writeTimeout = "10s"
idleTimeout = "60s"

View File

@@ -0,0 +1,40 @@
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/live/dao-anchor/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,116 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// CommonConfig .
type CommonConfig struct {
ExpireTime int64
}
// LRUConfig .
type LRUConfig struct {
InstCnt int
Bucket int
Capacity int
Timeout int64
}
type AreaInfo struct {
Name string
}
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
Redis *redis.Config
MySQL *sql.Config
LiveAppMySQL *sql.Config
Ecode *ecode.Config
LiveDanmuSub *databus.Config //发送弹幕回调配置
LiveGiftSendByPaySub *databus.Config
LiveGiftSendByFreeSub *databus.Config
LiveGuardBuySub *databus.Config
LivePopularitySub *databus.Config
LiveValidLiveDaysSub *databus.Config
LiveRoomTagSub *databus.Config
LiveRankListSub *databus.Config
Common *CommonConfig
LRUCache *LRUConfig
FirstAreas map[string]*AreaInfo
}
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,66 @@
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",
"mysql.go",
"redis.go",
"redisKey.go",
],
importpath = "go-common/app/service/live/dao-anchor/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/common/live/library/lrucache:go_default_library",
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup:go_default_library",
"//vendor/github.com/json-iterator/go: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",
"mysql_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,874 @@
package dao
import (
"context"
"fmt"
"go-common/app/common/live/library/lrucache"
jsonitor "github.com/json-iterator/go"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus"
"go-common/library/sync/errgroup"
)
const (
INFO_ROOM = 1 << iota
INFO_ROOM_EXT
INFO_TAG
INFO_ANCHOR
INFO_SHORT_ID
INFO_AREA_INFO
)
const (
INFO_ALL = (INFO_ROOM | INFO_ROOM_EXT | INFO_TAG | INFO_ANCHOR | INFO_SHORT_ID | INFO_AREA_INFO)
)
const (
FETCH_PAGE_SIZE = 100
)
//消费类型常量 定义
const (
//弹幕
//DANMU_NUM 当前弹幕累计数量
DANMU_NUM = "danmu_num"
//DANMU_MINUTE_NUM_15 最近15分钟弹幕数量
DANMU_MINUTE_NUM_15 = "danmu_minute_num_15"
//DANMU_MINUTE_NUM_30 ...
DANMU_MINUTE_NUM_30 = "danmu_minute_num_30"
//DANMU_MINUTE_NUM_45 ...
DANMU_MINUTE_NUM_45 = "danmu_minute_num_45"
//DANMU_MINUTE_NUM_60 ...
DANMU_MINUTE_NUM_60 = "danmu_minute_num_60"
//人气
//POPULARITY 当前实时人气
POPULARITY = "popularity"
//POPULARITY_MAX_TO_ARG_7 7日峰值人气的均值
POPULARITY_MAX_TO_ARG_7 = "popularity_max_to_avg_7"
//POPULARITY_MAX_TO_ARG_30 30日人气峰值的均值
POPULARITY_MAX_TO_ARG_30 = "popularity_max_to_avg_30"
//送礼
//GIFT_NUM 实时送礼数
GIFT_NUM = "gift_num_current_total"
//GIFT_GOLD_AMOUNT 实时消费金瓜子数
GIFT_GOLD_NUM = "gift_gold_num"
//GIFT_GOLD_AMOUNT 实时消费金瓜子金额
GIFT_GOLD_AMOUNT = "gift_gold_amount"
//GIFT_GOLD_AMOUNT_MINUTE_15 最近15分钟金瓜子金额
GIFT_GOLD_AMOUNT_MINUTE_15 = "gift_gold_num_minute_15"
//GIFT_GOLD_AMOUNT_MINUTE_30 最近30分钟金瓜子金额
GIFT_GOLD_AMOUNT_MINUTE_30 = "gift_gold_num_minute_30"
//GIFT_GOLD_AMOUNT_MINUTE_45 ...
GIFT_GOLD_AMOUNT_MINUTE_45 = "gift_gold_num_minute_45"
//GIFT_GOLD_AMOUNT_MINUTE_60 ...
GIFT_GOLD_AMOUNT_MINUTE_60 = "gift_gold_num_minute_60"
//有效开播天数
//VALID_LIVE_DAYS_TYPE_1_DAY_7 7日内有效开播天数有效开播:一次开播大于5分钟
VALID_LIVE_DAYS_TYPE_1_DAY_7 = "valid_days_type_1_day_7"
//VALID_LIVE_DAYS_TYPE_1_DAY_14 14日内有效开播天数有效开播:一次开播大于5分钟
VALID_LIVE_DAYS_TYPE_1_DAY_14 = "valid_days_type_1_day_14"
//VALID_LIVE_DAYS_TYPE_2_DAY_7 7日内有效开播天数有效开播:大于等于120分钟
VALID_LIVE_DAYS_TYPE_2_DAY_7 = "valid_days_type_2_day_7"
//VALID_LIVE_DAYS_TYPE_2_DAY_30 14日内有效开播天数有效开播:大于等于120分钟
VALID_LIVE_DAYS_TYPE_2_DAY_30 = "valid_days_type_2_day_30"
//房间状态
//ROOM_TAG_CURRENT 房间实时标签
ROOM_TAG_CURRENT = "room_tag_current"
//榜单
//RANK_LIST_CURRENT 排行榜相关数据
RANK_LIST_CURRENT = "rank_list_current"
//DAU
DAU = "dau"
)
const (
_RoomIdMappingCacheCapacity = 1024
)
// Dao dao
type Dao struct {
c *conf.Config
redis *redis.Pool
db *xsql.DB
dbLiveApp *xsql.DB
shortIDMapping *lrucache.SyncCache
areaInfoMapping *lrucache.SyncCache
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
redis: redis.NewPool(c.Redis),
db: xsql.NewMySQL(c.MySQL),
dbLiveApp: xsql.NewMySQL(c.LiveAppMySQL),
shortIDMapping: lrucache.NewSyncCache(c.LRUCache.Bucket, c.LRUCache.Capacity, c.LRUCache.Timeout),
areaInfoMapping: lrucache.NewSyncCache(c.LRUCache.Bucket, c.LRUCache.Capacity, c.LRUCache.Timeout),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.redis.Close()
d.db.Close()
return
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
// TODO: if you need use mc,redis, please add
return d.db.Ping(c)
}
// FetchRoomByIDs implementation
// FetchRoomByIDs 查询房间信息
func (d *Dao) FetchRoomByIDs(ctx context.Context, req *v1pb.RoomByIDsReq) (resp *v1pb.RoomByIDsResp, err error) {
if len(req.RoomIds) > 0 {
req.RoomIds, err = d.dbNormalizeRoomIDs(ctx, req.RoomIds)
if err != nil {
log.Error("[dao.dao-anchor.mysql|dbFetchRoomByIDs] normalize ids error(%v), req(%v)", err, req)
return nil, err
}
}
// TODO 处理部分fields的情况需要考虑特殊status的依赖问题
if len(req.RoomIds) > 0 {
resp = &v1pb.RoomByIDsResp{
RoomDataSet: make(map[int64]*v1pb.RoomData),
}
idsDB := make([]int64, 0, len(req.RoomIds))
// 从redis获取房间所有信息
for _, id := range req.RoomIds {
data, err := d.redisGetRoomInfo(ctx, id, _allRoomInfoFields)
if err != nil {
idsDB = append(idsDB, id)
} else {
d.dbDealWithStatus(ctx, data)
resp.RoomDataSet[id] = data
}
}
// 需要回源DB取数据
if len(idsDB) > 0 {
// 分段处理
for start := 0; start < len(idsDB); start += FETCH_PAGE_SIZE {
end := start + FETCH_PAGE_SIZE
if end > len(idsDB) {
end = len(idsDB)
}
reqRoom := &v1pb.RoomByIDsReq{
RoomIds: idsDB[start:end],
Fields: _allRoomInfoFields,
}
respRoom, err := d.dbFetchRoomByIDs(ctx, reqRoom)
if err != nil {
log.Error("[RoomOnlineList] dbFetchRoomByIDs error(%v), reqRoom(%v)", err, reqRoom)
return nil, err
}
// 回写房间信息到redis
for _, id := range idsDB[start:end] {
resp.RoomDataSet[id] = respRoom.RoomDataSet[id]
d.redisSetRoomInfo(ctx, id, _allRoomInfoFields, respRoom.RoomDataSet[id], false)
}
}
}
} else if len(req.Uids) > 0 {
// TODO 根据主播ID查询房间号的场景较少暂不优化后续先转房间号
resp, err = d.dbFetchRoomByIDs(ctx, req)
}
return
}
// RoomOnlineList implementation
// RoomOnlineList 在线房间列表
func (d *Dao) RoomOnlineList(ctx context.Context, req *v1pb.RoomOnlineListReq) (resp *v1pb.RoomOnlineListResp, err error) {
log.Info("[dao|RoomOnlineList] req(%v)", err, req)
ids, err := d.redisGetOnlineList(ctx, _onlineListAllArea)
if err != nil || len(ids) <= 0 {
ids, err = d.dbOnlineListByArea(ctx, _onlineListAllArea)
if err != nil {
log.Error("[RoomOnlineListByAttrs] dbOnlineListByArea error(%v), req(%v)", err, req)
return nil, err
}
d.redisSetOnlineList(ctx, _onlineListAllArea, ids)
}
resp = &v1pb.RoomOnlineListResp{
RoomDataList: make(map[int64]*v1pb.RoomData),
}
// 分页逻辑
start := int(req.Page * req.PageSize)
size := len(ids)
if start >= size {
return
}
end := start + int(req.PageSize)
if end > size {
end = size
}
ids = ids[start:end]
idsDB := make([]int64, 0, len(ids))
// 从redis获取房间信息
for _, id := range ids {
data, err := d.redisGetRoomInfo(ctx, id, req.Fields)
if err != nil {
idsDB = append(idsDB, id)
} else {
d.dbDealWithStatus(ctx, data)
resp.RoomDataList[id] = data
}
}
// 需要回源DB取数据
if len(idsDB) > 0 {
reqRoom := &v1pb.RoomByIDsReq{
RoomIds: idsDB,
Fields: _allRoomInfoFields,
}
respRoom, err := d.dbFetchRoomByIDs(ctx, reqRoom)
if err != nil {
log.Error("[RoomOnlineList] dbFetchRoomByIDs error(%v), reqRoom(%v)", err, reqRoom)
return nil, err
}
// 回写房间信息到redis
for _, id := range idsDB {
resp.RoomDataList[id] = respRoom.RoomDataSet[id]
d.redisSetRoomInfo(ctx, id, _allRoomInfoFields, respRoom.RoomDataSet[id], false)
}
}
return
}
// RoomOnlineListByArea implementation
// RoomOnlineListByArea 分区在线房间列表
func (d *Dao) RoomOnlineListByArea(ctx context.Context, req *v1pb.RoomOnlineListByAreaReq) (resp *v1pb.RoomOnlineListByAreaResp, err error) {
idSet := make(map[int64]bool)
idsDB := make([]int64, 0)
if len(req.AreaIds) <= 0 {
req.AreaIds = []int64{0}
}
for _, areaID := range req.AreaIds {
ids, err := d.redisGetOnlineList(ctx, areaID)
if err != nil {
idsDB = append(idsDB, areaID)
} else {
for _, id := range ids {
idSet[id] = true
}
}
}
// 需要回源DB取数据
if len(idsDB) > 0 {
for _, areaID := range idsDB {
roomIds, err := d.dbOnlineListByArea(ctx, areaID)
if err != nil {
log.Error("[RoomOnlineListByArea] dbOnlineListByArea error(%v), areaID(%v)", err, areaID)
return nil, err
}
d.redisSetOnlineList(ctx, areaID, roomIds)
for _, id := range roomIds {
idSet[id] = true
}
}
}
resp = &v1pb.RoomOnlineListByAreaResp{
RoomIds: make([]int64, 0, len(idSet)),
}
for id := range idSet {
resp.RoomIds = append(resp.RoomIds, id)
}
return
}
var (
_fields = []string{"uid", "area_id", "parent_area_id", "popularity_count", "anchor_profile_type"}
)
// RoomOnlineListByAttrs implementation
// RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
func (d *Dao) RoomOnlineListByAttrs(ctx context.Context, req *v1pb.RoomOnlineListByAttrsReq) (resp *v1pb.RoomOnlineListByAttrsResp, err error) {
ids, err := d.redisGetOnlineList(ctx, _onlineListAllArea)
if err != nil || len(ids) <= 0 {
ids, err = d.dbOnlineListByArea(ctx, _onlineListAllArea)
if err != nil {
log.Error("[RoomOnlineListByAttrs] dbOnlineListByArea error(%v), req(%v)", err, req)
return nil, err
}
d.redisSetOnlineList(ctx, _onlineListAllArea, ids)
}
resp = &v1pb.RoomOnlineListByAttrsResp{
Attrs: make(map[int64]*v1pb.AttrResp),
}
idsDB := make([]int64, 0, len(ids))
for _, id := range ids {
// 从redis获取房间基础信息
data, err := d.redisGetRoomInfo(ctx, id, _fields)
if err != nil {
idsDB = append(idsDB, id)
} else {
resp.Attrs[id] = &v1pb.AttrResp{
Uid: data.Uid,
RoomId: id,
AreaId: data.AreaId,
ParentAreaId: data.ParentAreaId,
PopularityCount: data.PopularityCount,
AnchorProfileType: data.AnchorProfileType,
}
}
}
// 需要回源DB取数据
if len(idsDB) > 0 {
eg := errgroup.Group{}
// 分段处理
for start := 0; start < len(idsDB); start += FETCH_PAGE_SIZE {
end := start + FETCH_PAGE_SIZE
if end > len(idsDB) {
end = len(idsDB)
}
eg.Go(func(idsDB []int64, start, end int) func() error {
return func() (err error) {
reqRoom := &v1pb.RoomByIDsReq{
RoomIds: idsDB[start:end],
Fields: _allRoomInfoFields,
}
respRoom, err := d.dbFetchRoomByIDs(ctx, reqRoom)
if err != nil {
log.Error("[RoomOnlineList] dbFetchRoomByIDs error(%v), reqRoom(%v)", err, reqRoom)
return err
}
// 回写房间信息到redis
for _, id := range idsDB[start:end] {
resp.Attrs[id] = &v1pb.AttrResp{
Uid: respRoom.RoomDataSet[id].Uid,
RoomId: id,
AreaId: respRoom.RoomDataSet[id].AreaId,
ParentAreaId: respRoom.RoomDataSet[id].ParentAreaId,
PopularityCount: respRoom.RoomDataSet[id].PopularityCount,
AnchorProfileType: respRoom.RoomDataSet[id].AnchorProfileType,
TagList: respRoom.RoomDataSet[id].TagList,
AttrList: make([]*v1pb.AttrData, 0, len(req.Attrs)),
}
d.redisSetRoomInfo(ctx, id, _allRoomInfoFields, respRoom.RoomDataSet[id], false)
d.redisSetTagList(ctx, id, respRoom.RoomDataSet[id].TagList)
}
return
}
}(idsDB, start, end))
}
eg.Wait()
}
// 重置回源数组
idsDB = make([]int64, 0, len(ids))
for _, id := range ids {
if resp.Attrs[id].TagList == nil {
// 从redis获取房间Tag信息
data, err := d.redisGetTagList(ctx, id)
if err != nil {
idsDB = append(idsDB, id)
} else {
resp.Attrs[id].TagList = data
}
}
}
// 需要回源DB取数据
if len(idsDB) > 0 {
eg := errgroup.Group{}
// 分段处理
for start := 0; start < len(idsDB); start += FETCH_PAGE_SIZE {
end := start + FETCH_PAGE_SIZE
if end > len(idsDB) {
end = len(idsDB)
}
eg.Go(func(idsDB []int64, start, end int) func() error {
return func() (err error) {
respRoom := make(map[int64]*v1pb.RoomData)
err = d.dbFetchTagInfo(ctx, idsDB[start:end], respRoom)
if err != nil {
log.Error("[RoomOnlineList] dbFetchTagInfo error(%v), idsDB[start:end](%v)", err, idsDB[start:end])
return err
}
// 回写房间Tag信息到redis
for _, id := range idsDB[start:end] {
if tag, ok := respRoom[id]; ok {
resp.Attrs[id].TagList = tag.TagList
} else {
resp.Attrs[id].TagList = make([]*v1pb.TagData, 0, len(req.Attrs))
}
d.redisSetTagList(ctx, id, resp.Attrs[id].TagList)
}
return
}
}(idsDB, start, end))
}
eg.Wait()
}
// TODO 从redis获取attr列表
// TODO 批量从db获取attr列表
if len(req.Attrs) > 0 {
eg := errgroup.Group{}
for _, attr := range req.Attrs {
// 实时人气值特殊处理
if attr.AttrId == ATTRID_POPULARITY && attr.AttrSubId == ATTRSUBID_POPULARITY_REALTIME {
for _, attrResp := range resp.Attrs {
resp.Attrs[attrResp.RoomId].AttrList = append(resp.Attrs[attrResp.RoomId].AttrList, &v1pb.AttrData{
RoomId: attrResp.RoomId,
AttrId: attr.AttrId,
AttrSubId: attr.AttrSubId,
AttrValue: attrResp.PopularityCount,
})
}
continue
}
eg.Go(func(attr *v1pb.AttrReq) func() error {
return func() (err error) {
reqAttr := &v1pb.FetchAttrByIDsReq{
AttrId: attr.AttrId,
AttrSubId: attr.AttrSubId,
RoomIds: ids,
}
respAttr, err := d.FetchAttrByIDs(ctx, reqAttr)
if err != nil {
log.Error("[RoomOnlineListByAttrs] FetchAttrByIDs from db error(%v), reqAttr(%v)", err, reqAttr)
return err
}
for _, attr := range respAttr.Attrs {
resp.Attrs[attr.RoomId].AttrList = append(resp.Attrs[attr.RoomId].AttrList, attr)
}
return
}
}(attr))
}
eg.Wait()
}
return
}
// RoomCreate implementation
// RoomCreate 房间创建
func (d *Dao) RoomCreate(ctx context.Context, req *v1pb.RoomCreateReq) (resp *v1pb.RoomCreateResp, err error) {
return d.roomCreate(ctx, req)
}
// RoomUpdate implementation
// RoomUpdate 房间更新
func (d *Dao) RoomUpdate(ctx context.Context, req *v1pb.RoomUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.roomUpdate(ctx, req)
if err == nil {
fields := make([]string, 0, len(req.Fields))
data := &v1pb.RoomData{
RoomId: req.RoomId,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range req.Fields {
switch f {
case "title":
data.Title = req.Title
case "cover":
data.Cover = req.Cover
case "tags":
data.Tags = req.Tags
case "background":
data.Background = req.Background
case "description":
data.Description = req.Description
case "live_start_time":
data.LiveStartTime = req.LiveStartTime
// 更新在播列表
var areaID int64
reqRoom := &v1pb.RoomByIDsReq{
RoomIds: []int64{req.RoomId},
Fields: _allRoomInfoFields,
}
respRoom, err := d.FetchRoomByIDs(ctx, reqRoom)
if err != nil {
log.Error("[RoomOnlineList] dbFetchRoomByIDs error(%v), reqRoom(%v)", err, reqRoom)
} else {
if respRoom.RoomDataSet[req.RoomId] != nil {
areaID = respRoom.RoomDataSet[req.RoomId].AreaId
}
}
if req.LiveStartTime > 0 {
d.redisAddOnlineList(ctx, _onlineListAllArea, req.RoomId)
d.redisAddOnlineList(ctx, areaID, req.RoomId)
} else {
d.redisDelOnlineList(ctx, _onlineListAllArea, req.RoomId)
d.redisDelOnlineList(ctx, areaID, req.RoomId)
}
// TODO 更新开播状态
case "live_screen_type":
data.LiveScreenType = req.LiveScreenType
case "live_type":
data.LiveType = req.LiveType
case "lock_status":
data.LockStatus = req.LockStatus
case "lock_time":
data.LockTime = req.LockTime
case "hidden_time":
data.HiddenTime = req.HiddenTime
// TODO 更新隐藏状态
case "area_id":
data.AreaId = req.AreaId
if req.AreaId > 0 {
areaInfo, err := d.dbFetchAreaInfo(ctx, req.AreaId)
if err != nil {
log.Error("[dao.dao-anchor.mysql|roomUpdate] fetch area info error(%v), req(%v)", err, req)
err = ecode.InvalidParam
return nil, err
}
data.ParentAreaId = areaInfo.ParentAreaID
fields = append(fields, "parent_area_id")
}
default:
continue
}
fields = append(fields, f)
}
d.redisSetRoomInfo(ctx, data.RoomId, fields, data, true)
}
return
}
// RoomBatchUpdate implementation
// RoomBatchUpdate 房间更新
func (d *Dao) RoomBatchUpdate(ctx context.Context, req *v1pb.RoomBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp = &v1pb.UpdateResp{}
for _, r := range req.Reqs {
res, err := d.RoomUpdate(ctx, r)
if err != nil {
log.Error("[dao.dao-anchor.mysql|RoomBatchUpdate] update room record error(%v), req(%v)", err, r)
return nil, err
}
resp.AffectedRows += res.AffectedRows
}
return
}
// RoomExtendUpdate implementation
// RoomExtendUpdate 房间更新
func (d *Dao) RoomExtendUpdate(ctx context.Context, req *v1pb.RoomExtendUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.roomExtendUpdate(ctx, req)
if err == nil {
fields := make([]string, 0, len(req.Fields))
data := &v1pb.RoomData{
RoomId: req.RoomId,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range req.Fields {
switch f {
case "keyframe":
data.Keyframe = req.Keyframe
case "popularity_count":
data.PopularityCount = req.PopularityCount
default:
continue
}
fields = append(fields, f)
}
d.redisSetRoomInfo(ctx, data.RoomId, fields, data, true)
}
return
}
// RoomExtendBatchUpdate implementation
// RoomExtendBatchUpdate 房间更新
func (d *Dao) RoomExtendBatchUpdate(ctx context.Context, req *v1pb.RoomExtendBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp = &v1pb.UpdateResp{}
for _, r := range req.Reqs {
res, err := d.RoomExtendUpdate(ctx, r)
if err != nil {
log.Error("[dao.dao-anchor.mysql|RoomExtendBatchUpdate] update room extend record error(%v), req(%v)", err, r)
return nil, err
}
resp.AffectedRows += res.AffectedRows
}
return
}
// RoomExtendIncre implementation
// RoomExtendIncre 房间增量更新
func (d *Dao) RoomExtendIncre(ctx context.Context, req *v1pb.RoomExtendIncreReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.roomExtendIncre(ctx, req)
if err == nil {
fields := make([]string, 0, len(req.Fields))
data := &v1pb.RoomData{
RoomId: req.RoomId,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range req.Fields {
switch f {
case "popularity_count":
data.PopularityCount = req.PopularityCount
default:
continue
}
fields = append(fields, f)
}
if len(fields) > 0 {
d.redisIncreRoomInfo(ctx, data.RoomId, fields, data)
}
}
return
}
// RoomExtendBatchIncre implementation
// RoomExtendBatchIncre 房间增量更新
func (d *Dao) RoomExtendBatchIncre(ctx context.Context, req *v1pb.RoomExtendBatchIncreReq) (resp *v1pb.UpdateResp, err error) {
resp = &v1pb.UpdateResp{}
for _, r := range req.Reqs {
res, err := d.RoomExtendIncre(ctx, r)
if err != nil {
log.Error("[dao.dao-anchor.mysql|RoomExtendBatchIncre] update room extend increment record error(%v), req(%v)", err, r)
return nil, err
}
resp.AffectedRows += res.AffectedRows
}
return
}
// RoomTagCreate implementation
// RoomTagCreate 房间Tag创建
func (d *Dao) RoomTagCreate(ctx context.Context, req *v1pb.RoomTagCreateReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.roomTagCreate(ctx, req)
if err == nil {
tag := &v1pb.TagData{
TagId: req.TagId,
TagSubId: req.TagSubId,
TagValue: req.TagValue,
TagExt: req.TagExt,
TagExpireAt: req.TagExpireAt,
}
d.redisAddTag(ctx, req.RoomId, tag)
}
return
}
// RoomAttrCreate implementation
// RoomAttrCreate 房间Attr创建
func (d *Dao) RoomAttrCreate(ctx context.Context, req *v1pb.RoomAttrCreateReq) (resp *v1pb.UpdateResp, err error) {
return d.roomAttrCreate(ctx, req)
}
// RoomAttrSetEx implementation
// RoomAttrSetEx 房间Attr更新
func (d *Dao) RoomAttrSetEx(ctx context.Context, req *v1pb.RoomAttrSetExReq) (resp *v1pb.UpdateResp, err error) {
return d.roomAttrSetEx(ctx, req)
}
// AnchorUpdate implementation
// AnchorUpdate 主播更新
func (d *Dao) AnchorUpdate(ctx context.Context, req *v1pb.AnchorUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.anchorUpdate(ctx, req)
if err == nil {
roomID := d.dbFetchRoomIDByUID(ctx, req.Uid)
if roomID == 0 {
return
}
fields := make([]string, 0, len(req.Fields))
data := &v1pb.RoomData{
RoomId: roomID,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range req.Fields {
switch f {
case "profile_type":
f = "anchor_profile_type"
data.AnchorProfileType = req.ProfileType
case "san_score":
f = "anchor_san"
data.AnchorSan = req.SanScore
case "round_status":
f = "anchor_round_switch"
data.AnchorRoundSwitch = req.RoundStatus
case "record_status":
f = "anchor_record_switch"
data.AnchorRecordSwitch = req.RecordStatus
case "exp":
f = "anchor_exp"
data.AnchorLevel.Score = req.Exp
default:
log.Error("[dao.dao-anchor.mysql|anchorUpdate] unsupported field(%v), req(%s)", f, req)
err = ecode.InvalidParam
return
}
fields = append(fields, f)
}
d.redisSetRoomInfo(ctx, data.RoomId, fields, data, true)
}
return
}
// AnchorBatchUpdate implementation
// AnchorBatchUpdate 主播更新
func (d *Dao) AnchorBatchUpdate(ctx context.Context, req *v1pb.AnchorBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
resp = &v1pb.UpdateResp{}
for _, r := range req.Reqs {
res, err := d.AnchorUpdate(ctx, r)
if err != nil {
log.Error("[dao.dao-anchor.mysql|AnchorBatchUpdate] update anchor record error(%v), req(%v)", err, r)
return nil, err
}
resp.AffectedRows += res.AffectedRows
}
return
}
// AnchorIncre implementation
// AnchorIncre 主播增量更新
func (d *Dao) AnchorIncre(ctx context.Context, req *v1pb.AnchorIncreReq) (resp *v1pb.UpdateResp, err error) {
resp, err = d.anchorIncre(ctx, req)
if err == nil {
roomID := d.dbFetchRoomIDByUID(ctx, req.Uid)
if roomID == 0 {
return
}
fields := make([]string, 0, len(req.Fields))
data := &v1pb.RoomData{
RoomId: roomID,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range req.Fields {
switch f {
case "san_score":
f = "anchor_san"
data.AnchorSan = req.SanScore
case "exp":
f = "anchor_exp"
data.AnchorLevel.Score = req.Exp
default:
continue
}
fields = append(fields, f)
}
if len(fields) > 0 {
d.redisIncreRoomInfo(ctx, data.RoomId, fields, data)
}
}
return
}
// AnchorBatchIncre implementation
// AnchorBatchIncre 主播增量更新
func (d *Dao) AnchorBatchIncre(ctx context.Context, req *v1pb.AnchorBatchIncreReq) (resp *v1pb.UpdateResp, err error) {
resp = &v1pb.UpdateResp{}
for _, r := range req.Reqs {
res, err := d.AnchorIncre(ctx, r)
if err != nil {
log.Error("[dao.dao-anchor.mysql|AnchorBatchIncre] update anchor increment record error(%v), req(%v)", err, r)
return nil, err
}
resp.AffectedRows += res.AffectedRows
}
return
}
// FetchAreas implementation
// FetchAreas 根据父分区号查询子分区
func (d *Dao) FetchAreas(ctx context.Context, req *v1pb.FetchAreasReq) (resp *v1pb.FetchAreasResp, err error) {
return d.fetchAreas(ctx, req)
}
// FetchAttrByIDs implementation
// FetchAttrByIDs 批量根据房间号查询指标
func (d *Dao) FetchAttrByIDs(ctx context.Context, req *v1pb.FetchAttrByIDsReq) (resp *v1pb.FetchAttrByIDsResp, err error) {
return d.fetchAttrByIDs(ctx, req)
}
// DeleteAttr implementation
// DeleteAttr 删除一个指标
func (d *Dao) DeleteAttr(ctx context.Context, req *v1pb.DeleteAttrReq) (resp *v1pb.UpdateResp, err error) {
return d.deleteAttr(ctx, req)
}
type msgVal struct {
MsgID string `json:"msg_id"`
}
func getConsumedKey(topic string, msgID string) string {
return fmt.Sprintf("consumed:%s:%s", topic, msgID)
}
// 清除消费过的记录,主要用于测试
func (d *Dao) clearConsumed(ctx context.Context, msg *databus.Message) {
val := &msgVal{}
err := jsonitor.Unmarshal(msg.Value, val)
if err != nil {
return
}
conn := d.redis.Get(ctx)
defer conn.Close()
conn.Do("DEL", getConsumedKey(msg.Topic, val.MsgID))
}
// CanConsume 是否可以消费
func (d *Dao) CanConsume(ctx context.Context, msg *databus.Message) bool {
val := &msgVal{}
err := jsonitor.Unmarshal(msg.Value, val)
if err != nil {
log.Error("unmarshal msg value error %+v, value: %s", err, string(msg.Value))
return true
}
if val.MsgID == "" {
log.Warn("msg_id is empty ; value: %s", string(msg.Value))
return true
}
conn := d.redis.Get(ctx)
defer conn.Close()
var key = getConsumedKey(msg.Topic, val.MsgID)
reply, err := conn.Do("SET", key, "1", "NX", "EX", 86400) // 24 hours
if err == nil {
if reply == nil {
log.Info("Already consumed key:%s", key)
return false
} else {
return true
}
}
if err == redis.ErrNil {
//already consumed
log.Info("Already consumed key:%s", key)
return false
}
// other redis error happenned, let it pass
log.Error("redis error when resolve CanConsume %+v", err)
return true
}

View File

@@ -0,0 +1,61 @@
package dao
import (
"context"
"encoding/json"
"flag"
//"fmt"
"os"
"testing"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/service/live/dao-anchor/conf"
"go-common/library/log"
"go-common/library/queue/databus"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
// TODO: other environments?
flag.Set("conf", "../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestCanConsume(t *testing.T) {
flag.Set("conf", "../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
Convey("", t, func(c C) {
ctx := context.TODO()
d := New(conf.Conf)
msg := &databus.Message{
Topic: "test-topic",
Value: json.RawMessage(`{"msg_id":"test-msg-id", "other_key":"value"}`),
}
d.clearConsumed(ctx, msg)
can := d.CanConsume(ctx, msg)
So(can, ShouldBeTrue)
can = d.CanConsume(ctx, msg)
So(can, ShouldBeFalse)
d.clearConsumed(ctx, msg)
can = d.CanConsume(ctx, msg)
So(can, ShouldBeTrue)
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/model"
)
func TestDaoNormalizeRoomIDs(t *testing.T) {
var (
c = context.TODO()
inputIDs = []int64{5910, 5901, 63, 53, 5010, 115, 666}
turnedFlags = []bool{false, false, true, true, false, true, true}
)
convey.Convey("When normalize a given list of ids", t, func(ctx convey.C) {
normalized, err := d.dbNormalizeRoomIDs(c, inputIDs)
ctx.Convey("Then short-id is turned into room-id while room-id keeps untouched", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(normalized), convey.ShouldEqual, len(inputIDs))
for i, turned := range turnedFlags {
if turned {
ctx.So(normalized[i] > inputIDs[i], convey.ShouldBeTrue)
} else {
ctx.So(normalized[i] == inputIDs[i], convey.ShouldBeTrue)
}
}
// ctx.So(d.shortIDMapping.caches[0].Len(), convey.ShouldEqual, len(inputIDs))
})
ctx.Convey("Then order of result will be preserved", func(ctx convey.C) {
roomIds := []int64{5901, 57796, 5010, 1011}
results, err := d.dbNormalizeRoomIDs(c, roomIds)
ctx.So(err, convey.ShouldBeNil)
for i := range results {
ctx.So(roomIds[i], convey.ShouldEqual, results[i])
}
})
})
}
func TestDaoFetchAreas(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("When given a valid main area id", t, func(ctx convey.C) {
req := &v1.FetchAreasReq{
AreaId: 3,
}
resp, err := d.fetchAreas(c, req)
ctx.Convey("Then we will get a list of its subarea's info along with its info", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(resp.Info.AreaId, convey.ShouldEqual, req.AreaId)
ctx.So(resp.Info.AreaName, convey.ShouldNotBeEmpty)
ctx.So(resp.Areas, convey.ShouldNotBeEmpty)
})
})
convey.Convey("When given a non-existed main area id", t, func(ctx convey.C) {
req := &v1.FetchAreasReq{
AreaId: 999,
}
_, err := d.fetchAreas(c, req)
ctx.Convey("Then we will get nothing", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
}
func TestDaoFetchAnchorInfo(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("When to fetch anchor info for a given uid", t, func(ctx convey.C) {
uid := []int64{2}
const RoomID = 1024
resp := make(map[int64]*v1.RoomData)
err := d.dbFetchAnchorInfo(c, uid, resp, false)
ctx.Convey("Then we will get room data for the anchor", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(resp, convey.ShouldNotBeEmpty)
data, ok := resp[RoomID]
ctx.So(ok, convey.ShouldBeTrue)
alv := data.AnchorLevel
ctx.So(alv.MaxLevel, convey.ShouldEqual, model.MaxAnchorLevel)
ctx.So(alv.Level, convey.ShouldEqual, 1)
ctx.So(alv.Color, convey.ShouldEqual, 0)
ctx.So(alv.Left, convey.ShouldEqual, 0)
ctx.So(alv.Right, convey.ShouldEqual, 49)
})
})
}

View File

@@ -0,0 +1,754 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
)
//实时消费缓存设计,异步落地
const VALUE = "value"
const DATE = "date" //是否最新消息是为1(需要刷新到DB) 否为0(不需要刷新到DB)
const DATE_1 = "1"
type ListIntValueInfo struct {
Value int64 `json:"value"`
Time int64 `json:"time"`
}
//Set 设置实时数据
func (d *Dao) Set(ctx context.Context, redisKey string, value string, timeOut int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("HMSET", redisKey, VALUE, value, DATE, DATE_1); err != nil {
log.Error("redis_set_err:key=%s;value=%s;err=%v", redisKey, value, err)
return
}
conn.Do("EXPIRE", redisKey, timeOut)
return
}
//Incr 设置增加数据
func (d *Dao) Incr(ctx context.Context, redisKey string, value int64, timeOut int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if err = conn.Send("HINCRBY", redisKey, VALUE, value); err != nil {
log.Error("redis_incr_err:key=%s;value=%d;err=%v", redisKey, value, err)
return
}
if err = conn.Send("HSET", redisKey, DATE, DATE_1); err != nil {
log.Error("redis_hset_err:key=%s;date_value=%s;err=%v", redisKey, DATE_1, err)
return
}
conn.Send("EXPIRE", redisKey, timeOut)
if err = conn.Flush(); err != nil {
log.Error("redisIncreRoomInfo conn.Flush error(%v)", err)
return
}
_, err = conn.Receive()
_, err = conn.Receive()
_, err = conn.Receive()
return
}
func (d *Dao) HGet(ctx context.Context, redisKey string) (resp int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
resp, err = redis.Int64(conn.Do("HGET", redisKey, VALUE))
if err != nil {
log.Error("redis_incr_err:key=%s;reply=%d;err=%v", redisKey, resp, err)
return
}
return
}
func (d *Dao) SetList(ctx context.Context, redisKey string, value string, timeOut int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("LPUSH", redisKey, value); err != nil {
log.Error("redis_setList_error:key=%s;value=%s;err=%v", redisKey, value, err)
return
}
conn.Do("EXPIRE", redisKey, timeOut)
return
}
func (d *Dao) GetList(ctx context.Context, redisKey string, start int, end int) (resp []*ListIntValueInfo, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
res, err := redis.Values(conn.Do("LRANGE", redisKey, start, end))
if err != nil {
log.Error("redis_getList_error:key=%s;err=%v", redisKey, err)
return
}
for _, sList := range res {
list := &ListIntValueInfo{}
if err = json.Unmarshal(sList.([]byte), &list); err != nil {
log.Error("GetList_json_error")
continue
}
resp = append(resp, list)
}
return
}
// GetRoomRecordsCurrent return a list of records corresponding to `content`.
func (d *Dao) GetRoomRecordsCurrent(ctx context.Context, content string, roomIds []int64) (list []int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
for _, roomId := range roomIds {
key := d.SRoomRecordCurrent(content, roomId)
if err = conn.Send("HGET", key.RedisKey, VALUE); err != nil {
log.Error("GetRoomRecordsCurrent conn.Send(HGET, %s, %s) error(%v)", key.RedisKey, VALUE, err)
return nil, err
}
}
if err = conn.Flush(); err != nil {
log.Error("GetRoomRecordsCurrent conn.Flush error(%v)", err)
return nil, err
}
for i := 0; i < len(roomIds); i++ {
var data int64
if data, err = redis.Int64(conn.Receive()); err != nil {
if err != redis.ErrNil {
log.Error("GetRoomRecordsCurrent conn.Receive() %d error(%v)", i, err)
return nil, err
}
}
list = append(list, data)
}
return
}
func (d *Dao) DelRoomRecordsCurrent(ctx context.Context, content string, roomIds []int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
args := make([]interface{}, len(roomIds))
for i, roomId := range roomIds {
args[i] = d.SRoomRecordCurrent(content, roomId)
}
if _, err = conn.Do("DEL", args...); err != nil {
log.Error("DelRoomRecordsCurrent_del_error:%v;roomIds=%v", err, roomIds)
return
}
return
}
func (d *Dao) SetRoomRecordsList(ctx context.Context, roomIds []int64, keys map[int64]interface{}, values map[int64]string) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
for _, roomId := range roomIds {
keyInfo := keys[roomId].(*redisKeyResp)
value := values[roomId]
if err = conn.Send("LPUSH", keyInfo.RedisKey, value); err != nil {
log.Error("SetRoomRecordsList conn.Send(LPUSH, %s, %s) error(%v)", keyInfo.RedisKey, value, err)
return err
}
if err = conn.Send("EXPIRE", keyInfo.RedisKey, keyInfo.TimeOut); err != nil {
log.Error("SetRoomRecordsList conn.Send(EXPIRE, %s, %d) error(%v)", keyInfo.RedisKey, keyInfo.TimeOut, err)
return err
}
}
if err = conn.Flush(); err != nil {
log.Error("SetRoomRecordsList conn.Flush() error(%v)", err)
return err
}
for range roomIds {
conn.Receive()
conn.Receive()
}
return
}
// GetRoomLiveRecordsRange can partially succeed, and in this case, err is still nil.
func (d *Dao) GetRoomLiveRecordsRange(ctx context.Context, content string, roomIds []int64, liveTime int64, start, end int) (resp map[int64][]*ListIntValueInfo, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
okRoomIds := make([]int64, 0, len(roomIds))
for _, roomId := range roomIds {
keyInfo := d.LRoomLiveRecordList(content, roomId, liveTime)
if err = conn.Send("LRANGE", keyInfo.RedisKey, start, end); err != nil {
log.Error("GetRoomLiveRecordsRange conn.Send(LRANGE, %s, %d, %d) error(%v)", keyInfo.RedisKey, start, end, err)
continue
}
okRoomIds = append(okRoomIds, roomId)
}
if err = conn.Flush(); err != nil {
log.Error("GetRoomLiveRecordsRange conn.Flush() error(%v)", err)
return nil, err
}
resp = make(map[int64][]*ListIntValueInfo)
for i := 0; i < len(okRoomIds); i++ {
values, err := redis.Values(conn.Receive())
if err != nil {
log.Error("GetRoomLiveRecordsRange redis.Values(conn.Receive()) error(%v)", err)
continue
}
roomId := okRoomIds[i]
for _, info := range values {
valueInfo := &ListIntValueInfo{}
if err = json.Unmarshal(info.([]byte), &valueInfo); err != nil {
log.Error("GetRoomLiveRecordsRange json unmarshall error(%v)", err)
continue
}
resp[roomId] = append(resp[roomId], valueInfo)
}
}
return resp, nil
}
const (
_roomInfoKey = "room_info_v3:%d"
_anchorInfoKey = "anchor_info:%d"
_onlineListKey = "online_list_v3:%d"
_tagListKey = "tag_list_v3:%d"
_onlineListAllArea = 0
)
var (
_allRoomInfoFields = []string{"uid", "title", "cover", "tags", "background", "description", "live_start_time", "live_status", "live_screen_type", "live_type", "lock_status", "lock_time", "hidden_time", "hidden_status", "area_id", "parent_area_id", "anchor_profile_type", "anchor_round_switch", "anchor_record_switch", "anchor_exp", "popularity_count", "keyframe"}
)
func (d *Dao) filterOutTagList(fields []string) (resp []string, needTagList bool) {
resp = make([]string, 0, len(fields))
for _, f := range fields {
if f == "tag_list" {
needTagList = true
} else {
resp = append(resp, f)
}
}
return
}
func (d *Dao) redisGetRoomInfo(ctx context.Context, roomID int64, fields []string) (data *v1pb.RoomData, err error) {
if len(fields) <= 0 {
return
}
conn := d.redis.Get(ctx)
defer conn.Close()
roomKey := fmt.Sprintf(_roomInfoKey, roomID)
ok, err := redis.Bool(conn.Do("EXPIRE", roomKey, d.c.Common.ExpireTime))
if err != nil && err != redis.ErrNil {
log.Error("redisGetRoomInfo conn.Do(EXPIRE, %s) error(%v)", roomKey, err)
return
}
if !ok {
err = ecode.RoomNotFound
return
}
for _, f := range fields {
if f == "room_id" {
continue
}
if err = conn.Send("HGET", roomKey, f); err != nil {
log.Error("redisGetRoomInfo conn.Send(HGET, %s, %s) error(%v)", roomKey, f, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("redisGetRoomInfo conn.Flush error(%v)", err)
return
}
data = &v1pb.RoomData{
RoomId: roomID,
AnchorLevel: new(v1pb.AnchorLevel),
}
for _, f := range fields {
if f == "room_id" {
continue
}
reply, err := conn.Receive()
if e, ok := err.(*redis.Error); ok && strings.Index(e.Error(), "WRONGTYPE") != -1 {
return data, err
}
switch f {
case "uid":
data.Uid, err = redis.Int64(reply, err)
case "title":
data.Title, err = redis.String(reply, err)
case "cover":
data.Cover, err = redis.String(reply, err)
case "tags":
data.Tags, err = redis.String(reply, err)
case "background":
data.Background, err = redis.String(reply, err)
case "description":
data.Description, err = redis.String(reply, err)
case "live_start_time":
data.LiveStartTime, err = redis.Int64(reply, err)
case "live_status":
data.LiveStatus, err = redis.Int64(reply, err)
case "live_screen_type":
data.LiveScreenType, err = redis.Int64(reply, err)
case "live_type":
data.LiveType, err = redis.Int64(reply, err)
case "lock_status":
data.LockStatus, err = redis.Int64(reply, err)
case "lock_time":
data.LockTime, err = redis.Int64(reply, err)
case "hidden_time":
data.HiddenTime, err = redis.Int64(reply, err)
case "hidden_status":
data.HiddenStatus, err = redis.Int64(reply, err)
case "area_id":
data.AreaId, err = redis.Int64(reply, err)
case "parent_area_id":
data.ParentAreaId, err = redis.Int64(reply, err)
case "anchor_san":
data.AnchorSan, err = redis.Int64(reply, err)
case "anchor_profile_type":
data.AnchorProfileType, err = redis.Int64(reply, err)
case "anchor_round_switch":
data.AnchorRoundSwitch, err = redis.Int64(reply, err)
case "anchor_record_switch":
data.AnchorRecordSwitch, err = redis.Int64(reply, err)
case "anchor_exp":
data.AnchorLevel.Score, err = redis.Int64(reply, err)
case "popularity_count":
data.PopularityCount, err = redis.Int64(reply, err)
case "keyframe":
data.Keyframe, err = redis.String(reply, err)
default:
log.Error("redisGetRoomInfo unsupported field(%v), roomID(%d)", f, roomID)
err = ecode.InvalidParam
return nil, err
}
if err != nil {
log.Warn("redisGetRoomInfo conn.Receive() field(%v), error(%v)", f, err)
return nil, err
}
}
return
}
func (d *Dao) redisSetRoomInfo(ctx context.Context, roomID int64, fields []string, data *v1pb.RoomData, fastfail bool) (err error) {
if len(fields) <= 0 {
return
}
conn := d.redis.Get(ctx)
defer conn.Close()
roomKey := fmt.Sprintf(_roomInfoKey, roomID)
ok, err := redis.Bool(conn.Do("EXPIRE", roomKey, d.c.Common.ExpireTime))
if err != nil && err != redis.ErrNil {
log.Error("redisSetRoomInfo conn.Do(EXPIRE, %s) error(%v)", roomKey, err)
return
}
if !ok && fastfail {
return
}
args := make([]interface{}, len(fields)*2+1)
args[0] = roomKey
for i, f := range fields {
var v interface{}
switch f {
case "roomid":
v = data.RoomId
case "uid":
v = data.Uid
case "title":
v = data.Title
case "cover":
v = data.Cover
case "tags":
v = data.Tags
case "background":
v = data.Background
case "description":
v = data.Description
case "live_start_time":
v = data.LiveStartTime
case "live_status":
v = data.LiveStatus
case "live_screen_type":
v = data.LiveScreenType
case "live_type":
v = data.LiveType
case "lock_status":
v = data.LockStatus
case "lock_time":
v = data.LockTime
case "hidden_time":
v = data.HiddenTime
case "hidden_status":
v = data.HiddenStatus
case "area_id":
v = data.AreaId
case "parent_area_id":
v = data.ParentAreaId
case "anchor_san":
v = data.AnchorSan
case "anchor_profile_type":
v = data.AnchorProfileType
case "anchor_round_switch":
v = data.AnchorRoundSwitch
case "anchor_record_switch":
v = data.AnchorRecordSwitch
case "anchor_exp":
v = data.AnchorRecordSwitch
case "popularity_count":
v = data.PopularityCount
case "keyframe":
v = data.Keyframe
default:
log.Error("redisSetRoomInfo unsupported field(%v), roomID(%d)", f, roomID)
return ecode.InvalidParam
}
args[i*2+1] = f
args[i*2+2] = v
}
if _, err = conn.Do("HMSET", args...); err != nil {
log.Error("redisSetRoomInfo conn.Do(HMSET, %v) error(%v)", args, err)
return
}
return
}
func (d *Dao) redisIncreRoomInfo(ctx context.Context, roomID int64, fields []string, data *v1pb.RoomData) (err error) {
if len(fields) <= 0 {
return
}
conn := d.redis.Get(ctx)
defer conn.Close()
roomKey := fmt.Sprintf(_roomInfoKey, roomID)
ok, err := redis.Bool(conn.Do("EXPIRE", roomKey, d.c.Common.ExpireTime))
if err != nil && err != redis.ErrNil {
log.Error("redisIncreRoomInfo conn.Do(EXPIRE, %s) error(%v)", roomKey, err)
return
}
// fast fail if key not exists
if !ok {
return
}
for _, f := range fields {
var v int64
switch f {
case "anchor_san":
v = data.AnchorSan
case "anchor_exp":
v = data.AnchorRecordSwitch
case "popularity_count":
v = data.PopularityCount
default:
log.Error("redisIncreRoomInfo unsupported field(%v), roomID(%d)", f, roomID)
return ecode.InvalidParam
}
if err = conn.Send("HINCRBY", roomKey, f, v); err != nil {
log.Error("redisIncreRoomInfo conn.Send(HINCRBY, %s, %s, %d) error(%v)", roomKey, f, v, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("redisIncreRoomInfo conn.Flush error(%v)", err)
return
}
for _, f := range fields {
_, err = conn.Receive()
if err != nil && err != redis.ErrNil {
log.Error("redisIncreRoomInfo conn.Receive() field(%v), error(%v)", f, err)
return
}
}
return
}
func (d *Dao) redisGetOnlineList(ctx context.Context, areaID int64) (list []int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_onlineListKey, areaID)
ok, err := redis.Bool(conn.Do("EXPIRE", key, d.c.Common.ExpireTime))
if err != nil && err != redis.ErrNil {
log.Error("redisGetOnlineList conn.Do(EXPIRE, %s) error(%v)", key, err)
return
}
if !ok {
// 不存在或者在播列表为空都会重新去DB获取
return
}
list = make([]int64, 0)
roomids, err := redis.Strings(conn.Do("SMEMBERS", key))
if err != nil && err != redis.ErrNil {
if e, ok := err.(*redis.Error); ok && strings.Index(e.Error(), "WRONGTYPE") == -1 {
log.Error("redisGetOnlineList conn.Do(SMEMBERS, %s) error(%v)", key, err)
return
}
return list, nil
}
for _, id := range roomids {
roomid, err := strconv.ParseInt(id, 10, 64)
if err != nil {
log.Warn("redisGetOnlineList ParseInt(%d) error(%v)", roomid, err)
return nil, err
}
list = append(list, roomid)
}
return
}
func (d *Dao) redisSetOnlineList(ctx context.Context, areaID int64, list []int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_onlineListKey, areaID)
if len(list) <= 0 {
// 设置哨兵
if _, err = conn.Do("SETEX", key, d.c.Common.ExpireTime, "emptylist"); err != nil {
log.Error("redisSetOnlineList conn.Do(SETEX, %s, %v) error(%v)", key, list, err)
}
return
}
if _, err = conn.Do("DEL", key); err != nil && err != redis.ErrNil {
log.Error("redisSetOnlineList conn.Do(DEL, %s) error(%v)", key, err)
return
}
args := make([]interface{}, len(list)+1)
args[0] = key
for i, id := range list {
args[i+1] = id
}
if _, err = conn.Do("SADD", args...); err != nil {
log.Error("redisSetOnlineList conn.Do(SADD, %s, %v) error(%v)", key, list, err)
return
}
return
}
func (d *Dao) redisAddOnlineList(ctx context.Context, areaID int64, roomID int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_onlineListKey, areaID)
typ, err := redis.String(conn.Do("TYPE", key))
if err != nil && err != redis.ErrNil {
log.Error("redisAddOnlineList conn.Do(TYPE, %s) error(%v)", key, err)
return
}
if strings.ToLower(typ) == "none" {
// 不存在就不处理
return
} else if strings.ToLower(typ) != "set" {
if _, err = conn.Do("DEL", key); err != nil && err != redis.ErrNil {
log.Error("redisAddOnlineList conn.Do(DEL, %s) error(%v)", key, err)
return
}
}
if _, err = conn.Do("SADD", key, roomID); err != nil {
log.Error("redisAddOnlineList conn.Do(SADD, %s, %d) error(%v)", key, roomID, err)
return
}
return
}
func (d *Dao) redisDelOnlineList(ctx context.Context, areaID int64, roomID int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_onlineListKey, areaID)
typ, err := redis.String(conn.Do("TYPE", key))
if err != nil && err != redis.ErrNil {
log.Error("redisDelOnlineList conn.Do(TYPE, %s) error(%v)", key, err)
return
}
if strings.ToLower(typ) != "set" {
// 不存在就不处理
return
}
if _, err = conn.Do("SREM", key, roomID); err != nil {
log.Error("redisDelOnlineList conn.Do(SADD, %s, %d) error(%v)", key, roomID, err)
return
}
return
}
func (d *Dao) redisGetTagList(ctx context.Context, roomID int64) (list []*v1pb.TagData, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_tagListKey, roomID)
ok, err := redis.Bool(conn.Do("EXPIRE", key, d.c.Common.ExpireTime))
if err != nil && err != redis.ErrNil {
log.Error("redisGetTagList conn.Do(EXPIRE, %s) error(%v)", key, err)
return nil, err
}
if !ok {
err = ecode.RoomNotFound
return
}
list = make([]*v1pb.TagData, 0)
tags, err := redis.Strings(conn.Do("SMEMBERS", key))
if err != nil && err != redis.ErrNil {
if e, ok := err.(*redis.Error); ok && strings.Index(e.Error(), "WRONGTYPE") == -1 {
log.Error("redisGetTagList conn.Do(SMEMBERS, %s) error(%v)", key, err)
return
}
return list, nil
}
for _, tag := range tags {
seg := strings.Split(tag, ":")
if len(seg) < 5 {
log.Error("redisGetTagList Split(%s) error(%v)", tag, err)
return nil, err
}
data := &v1pb.TagData{
TagExt: strings.Join(seg[4:], ":"),
}
data.TagExpireAt, _ = strconv.ParseInt(seg[3], 10, 64)
if data.TagExpireAt > time.Now().Unix() {
data.TagId, _ = strconv.ParseInt(seg[0], 10, 64)
data.TagSubId, _ = strconv.ParseInt(seg[1], 10, 64)
data.TagValue, _ = strconv.ParseInt(seg[2], 10, 64)
list = append(list, data)
}
}
return
}
func (d *Dao) redisAddTag(ctx context.Context, roomID int64, tag *v1pb.TagData) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_tagListKey, roomID)
typ, err := redis.String(conn.Do("TYPE", key))
if err != nil && err != redis.ErrNil {
log.Error("redisAddTag conn.Do(TYPE, %s) error(%v)", key, err)
return
}
if strings.ToLower(typ) == "none" {
// 不存在就不处理
return
} else if strings.ToLower(typ) != "set" {
if _, err = conn.Do("DEL", key); err != nil && err != redis.ErrNil {
log.Error("redisAddTag conn.Do(DEL, %s) error(%v)", key, err)
return
}
}
tagVal := fmt.Sprintf("%d:%d:%d:%d:%s", tag.TagId, tag.TagSubId, tag.TagValue, tag.TagExpireAt, tag.TagExt)
if _, err = conn.Do("SADD", key, tagVal); err != nil {
log.Error("redisAddTag conn.Do(SADD, %s, %s) error(%v)", key, tagVal, err)
return
}
return
}
func (d *Dao) redisSetTagList(ctx context.Context, roomID int64, list []*v1pb.TagData) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := fmt.Sprintf(_tagListKey, roomID)
if len(list) <= 0 {
// 设置哨兵
if _, err = conn.Do("SETEX", key, d.c.Common.ExpireTime, "emptylist"); err != nil {
log.Error("redisSetTagList conn.Do(SETEX, %s, %v) error(%v)", key, list, err)
}
return
}
if _, err = conn.Do("DEL", key); err != nil && err != redis.ErrNil {
log.Error("redisSetTagList conn.Do(DEL, %s) error(%v)", key, err)
return
}
args := make([]interface{}, len(list)+1)
args[0] = key
for i, tag := range list {
args[i+1] = fmt.Sprintf("%d:%d:%d:%d:%s", tag.TagId, tag.TagSubId, tag.TagValue, tag.TagExpireAt, tag.TagExt)
}
if _, err = conn.Do("SADD", args...); err != nil {
log.Error("redisSetTagList conn.Do(SADD, %s, %v) error(%v)", key, list, err)
return
}
return
}

View File

@@ -0,0 +1,80 @@
package dao
import (
"context"
"fmt"
"strconv"
"go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/library/log"
)
type redisKeyResp struct {
RedisKey string `json:"redis_key"`
TimeOut int `json:"time_out"`
}
//RoomRecordListForLive 房间侧开播记录相关历史数据存3天
func (d *Dao) LRoomLiveRecordList(content string, roomId int64, liveTime int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
if liveTime <= 0 {
roomInfo, err := d.FetchRoomByIDs(context.TODO(), &v1.RoomByIDsReq{RoomIds: []int64{roomId}, Fields: []string{"live_start_time"}})
if err != nil || roomInfo.RoomDataSet == nil {
log.Error("LRoomLiveRecordList_err:err=%v;info=%v", err, roomInfo)
return
}
liveTime = roomInfo.RoomDataSet[roomId].LiveStartTime
}
contentType := content + "_" + strconv.Itoa(int(liveTime))
resp.RedisKey = fmt.Sprintf(contentType+"_list_%d", roomId)
resp.TimeOut = 24 * 60 * 60 * 3
return
}
//RoomRecordList 房间侧记录相关历史数据存1天
func (d *Dao) LRoomRecordList(contentType string, roomId int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
resp.RedisKey = fmt.Sprintf(contentType+"_list_%d", roomId)
resp.TimeOut = 24 * 60 * 60
return
}
//RoomRecordCurrent 房间侧实时数据记录,存一个小时
func (d *Dao) SRoomRecordCurrent(content string, roomId int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
resp.RedisKey = fmt.Sprintf(content+"_key_%d", roomId)
resp.TimeOut = 60 * 60
return
}
//主播侧开播记录相关历史数据存3天
func (d *Dao) LUserLiveRecordList(content string, uid int64, liveTime int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
if liveTime <= 0 {
roomInfo, err := d.FetchRoomByIDs(context.TODO(), &v1.RoomByIDsReq{Uids: []int64{uid}, Fields: []string{"live_start_time"}})
if err != nil {
log.Error("LRoomLiveRecordList_err:err=%v;info=%v", err, roomInfo)
return
}
}
contentType := content + "_" + strconv.Itoa(int(liveTime))
resp.RedisKey = fmt.Sprintf(contentType+"_list_%d", uid)
resp.TimeOut = 24 * 60 * 60 * 3
return
}
//主播侧记录相关历史数据存1天
func (d *Dao) LUserRecordList(contentType string, uid int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
resp.RedisKey = fmt.Sprintf(contentType+"_list_%d", uid)
resp.TimeOut = 24 * 60 * 60
return
}
//UserRecordCurrent 主播侧实时数据记录,存一个小时
func (d *Dao) SUserRecordCurrent(content string, uid int64) (resp *redisKeyResp) {
resp = &redisKeyResp{}
resp.RedisKey = fmt.Sprintf(content+"_key_%d", uid)
resp.TimeOut = 60 * 60
return
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"anchor_level.go",
"databusMsg.go",
"model.go",
],
importpath = "go-common/app/service/live/dao-anchor/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,107 @@
package model
import (
"errors"
"math"
)
const MaxAnchorLevel = 40
var anchorLevelScoreTable = []int64{
0,
50,
200,
470,
920,
2100,
4060,
7160,
11760,
18060,
27160,
39610,
56410,
78810,
109810,
154810,
226810,
319810,
442810,
602810,
816810,
1138810,
1594810,
2214810,
3004810,
3984810,
5229810,
6909810,
9013810,
11883810,
15613810,
20613810,
27313810,
36413810,
47813810,
62013810,
79513810,
99513810,
122013810,
147013810,
int64(math.MaxInt64),
}
// Returns the index of first element that **greater** than the given value.
func upperBound(list []int64, value int64) int {
count := len(list)
first:= 0
for count > 0 {
i := first
step := count / 2
i += step
if value >= list[i] {
first = i + 1
count -= step + 1
} else {
count = step
}
}
return first
}
// GetAnchorLevel returns anchor level, i.e. Lv1 ~ Lv40, corresponding to the given score.
func GetAnchorLevel(score int64) (int64, error) {
if score < 0 {
return 0, errors.New("invalid anchor score")
}
return int64(upperBound(anchorLevelScoreTable, score)), nil
}
// GetLevelScoreInfo returns left & right score of a given level.
func GetLevelScoreInfo(lv int64) (left, right int64, err error) {
if lv < 1 || lv >= int64(len(anchorLevelScoreTable)) {
return 0, 0, errors.New("invalid request level")
}
left = anchorLevelScoreTable[lv-1]
right = anchorLevelScoreTable[lv] - 1
return
}
// GetAnchorLevelColor returns level color.
func GetAnchorLevelColor(lv int64) (int64, error) {
if lv < 1 || lv > MaxAnchorLevel {
return 0, errors.New("invalid request level")
}
q := lv / 10
r := lv % 10
if r == 0 {
q -= 1
}
return q, nil
}

View File

@@ -0,0 +1,78 @@
package model
//MessageValue php 格式
type MessageValue struct {
Topic string `json:"topic"`
MsgID string `json:"msg_id"`
MsgContent string `json:"msg_content"`
}
//MessageWithoutMsgId golang投递
type MessageWithoutMsgId struct {
Topic string `json:"topic"`
Value string `json:"value"`
}
//DMSendMessageContent
type DMSendMsgContent struct {
RoomId int64 `json:"room_id"`
//Uid int64 `json:"uid"`
//Uname string `json:"uname"`
//UserLevel int64 `json:"user_level"`
//Color string `json:"color"`
//Content string `json:"content"`
}
type GiftSendMsgContent struct {
Body BodyMsg `json:"body"`
}
//BodyMsg
type BodyMsg struct {
MsgID string `json:"msg_id"`
Uid int64 `json:"uid"`
Ruid int64 `json:"ruid"`
RoomId int64 `json:"roomid"`
GiftId int64 `json:"giftid"`
PayCoin int64 `json:"pay_coin"`
Num int64 `json:"num"`
CoinType string `json:"coinType"`
}
// GuardBuyMessageContent
type GuardBuyMessageContent struct {
Uid int64 `json:"uid"`
Ruid int64 `json:"ruid"`
RoomId int64 `json:"roomid"`
Privilege int64 `json:"privilege"`
Coin int64 `json:"coin"`
Num int64 `json:"num"`
Type string `json:"type"`
Platform string `json:"platform"`
IsNew bool `json:"is_new"`
}
type TopicCommonMsg struct {
MsgId string `json:"msg_id"`
RoomId int64 `json:"room_id"`
Value int64 `json:"value"`
Cycle int64 `json:"cycle"`
Type int64 `json:"type"`
}
type LiveRoomTagMsg struct {
MsgId string `json:"msg_id"`
RoomId int64 `json:"room_id"`
TagId int64 `json:"tag_id"`
TagSubId int64 `json:"tag_sub_id"`
TagValue int64 `json:"tag_value"`
TagExt string `json:"tag_ext"`
ExpireTime int64 `json:"expire_time"`
}
type LiveRankListMsg struct {
RankId int64 `json:"rank_id"`
RankType string `json:"rank_type"`
RankList map[int64]int64 `json:"rank_list"`
ExpireTime int64 `json:"expire_time"`
}

View File

@@ -0,0 +1,7 @@
package model
type AreaInfo struct {
AreaID int64
AreaName string
ParentAreaID int64
}

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/live/dao-anchor/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v0:go_default_library",
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/service:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/time:go_default_library",
"@org_golang_google_grpc//: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,25 @@
package grpc
import (
"time"
v0pb "go-common/app/service/live/dao-anchor/api/grpc/v0"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/service"
"go-common/library/net/rpc/warden"
xtime "go-common/library/time"
"google.golang.org/grpc"
)
// New new grpc server
func New(svc *service.Service) (wsvr *warden.Server, err error) {
wsvr = warden.NewServer(&warden.ServerConfig{Timeout: xtime.Duration(time.Second * 10)}, grpc.MaxRecvMsgSize(1024*1024*1024), grpc.MaxSendMsgSize(1024*1024*1024))
v0pb.RegisterCreateDataServer(wsvr.Server(), svc.CreateDataSvc())
// v0pb.RegisterPopularityServer(wsvr.Server(), svc.PopularitySvc())
v1pb.RegisterDaoAnchorServer(wsvr.Server(), svc.V1Svc())
if wsvr, err = wsvr.Start(); err != nil {
return
}
return
}

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/service/live/dao-anchor/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,56 @@
package http
import (
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
srv *service.Service
vfy *verify.Verify
)
// Init init
func Init(c *conf.Config) {
vfy = verify.New(c.Verify)
initService(c)
engine := bm.DefaultServer(c.BM)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%v)", err)
panic(err)
}
}
func initService(c *conf.Config) {
srv = service.New(c)
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/xlive/dao-anchor")
{
g.GET("/start", vfy.Verify, howToStart)
}
}
func ping(c *bm.Context) {
// TODO
/*if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}*/
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["service.go"],
importpath = "go-common/app/service/live/dao-anchor/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao:go_default_library",
"//app/service/live/dao-anchor/service/consumer/v1:go_default_library",
"//app/service/live/dao-anchor/service/v0:go_default_library",
"//app/service/live/dao-anchor/service/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/live/dao-anchor/service/consumer/v1:all-srcs",
"//app/service/live/dao-anchor/service/v0:all-srcs",
"//app/service/live/dao-anchor/service/v1:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,69 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"danmu.go",
"dataBusNotify.go",
"gift.go",
"guard.go",
"popularity.go",
"rankList.go",
"roomTag.go",
"validDays.go",
],
importpath = "go-common/app/service/live/dao-anchor/service/consumer/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao:go_default_library",
"//app/service/live/dao-anchor/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/prometheus/common/log: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 = [
"popularity_test.go",
"rankList_test.go",
"roomTag_test.go",
"validDays_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,30 @@
package v1
import (
"context"
"encoding/json"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
//消费弹幕消息的业务逻辑
//DanmuCountStatistics 弹幕数统计
func (s *ConsumerService) DanmuCountStatistics(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
//@todo 等弹幕加了msg_id 再换
msgInfo := new(model.DMSendMsgContent)
if err = json.Unmarshal(msg.Value, &msgInfo); err != nil {
log.Error("DanmuCountStatistics_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgInfo)
return
}
log.Info("DanmuCountStatistics:msgInfo=%v", string(msg.Value))
roomId := msgInfo.RoomId
redisKeyInfo := s.dao.SRoomRecordCurrent(dao.DANMU_NUM, roomId)
s.dao.Incr(ctx, redisKeyInfo.RedisKey, 1, redisKeyInfo.TimeOut)
return
}

View File

@@ -0,0 +1,135 @@
package v1
import (
"context"
"fmt"
"reflect"
"runtime"
"sync"
"time"
"github.com/pkg/errors"
"github.com/prometheus/common/log"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/queue/databus"
)
type attrInfo struct {
AttrSubId int64 `json:"attr_sub_id"`
ContentType string `json:"content_type"`
}
//ConsumerService struct
type ConsumerService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
wg sync.WaitGroup
liveDanmuSub *databus.Databus
liveGiftSendByPaySub *databus.Databus
liveGiftSendByFreeSub *databus.Databus
liveGuardBuySub *databus.Databus
livePopularitySub *databus.Databus
liveValidLiveDays *databus.Databus
liveRoomTag *databus.Databus
liveRankList *databus.Databus
}
//NewConsumerService init 统计类数据同步落地,实时数据异步落地
func NewConsumerService(c *conf.Config) (s *ConsumerService) {
s = &ConsumerService{
conf: c,
dao: dao.New(c),
liveDanmuSub: databus.New(c.LiveDanmuSub),
liveGiftSendByPaySub: databus.New(c.LiveGiftSendByPaySub),
liveGiftSendByFreeSub: databus.New(c.LiveGiftSendByFreeSub),
liveGuardBuySub: databus.New(c.LiveGuardBuySub),
livePopularitySub: databus.New(c.LivePopularitySub),
liveValidLiveDays: databus.New(c.LiveValidLiveDaysSub),
liveRoomTag: databus.New(c.LiveRoomTagSub),
liveRankList: databus.New(c.LiveRankListSub),
}
s.wg.Add(1)
go s.LiveMessageContent(context.TODO())
return s
}
//LiveMessageContent ...
func (s *ConsumerService) LiveMessageContent(ctx context.Context) {
log.Info("LiveMessageContent_notify_start")
defer func() {
log.Warn("LiveMessageContent exists")
s.wg.Done()
}()
//接收消息
liveRankListMsgs := s.liveRankList.Messages()
livePopularityMsgs := s.livePopularitySub.Messages()
liveRoomTagMsgs := s.liveRoomTag.Messages()
validLiveDaysMsgs := s.liveValidLiveDays.Messages()
liveDanmuSendMsgs := s.liveDanmuSub.Messages()
liveGiftSendByPayMsgs := s.liveGiftSendByPaySub.Messages()
liveGiftSendByFreeMsgs := s.liveGiftSendByFreeSub.Messages()
liveGuardBuyMsgs := s.liveGuardBuySub.Messages()
for {
select {
case msg, ok := <-liveRankListMsgs:
if err := s.doConsume(ctx, msg, ok, s.LiveRankList); err != nil {
return
}
case msg, ok := <-livePopularityMsgs:
if err := s.doConsume(ctx, msg, ok, s.PopularityStatistics); err != nil {
return
}
case msg, ok := <-liveRoomTagMsgs:
if err := s.doConsume(ctx, msg, ok, s.LiveRoomTag); err != nil {
return
}
case msg, ok := <-validLiveDaysMsgs:
if err := s.doConsume(ctx, msg, ok, s.ValidDaysStatistics); err != nil {
return
}
case msg, ok := <-liveDanmuSendMsgs:
if err := s.doConsume(ctx, msg, ok, s.DanmuCountStatistics); err != nil {
return
}
case msg, ok := <-liveGiftSendByPayMsgs:
if err := s.doConsume(ctx, msg, ok, s.GiftCount); err != nil {
return
}
case msg, ok := <-liveGiftSendByFreeMsgs:
if err := s.doConsume(ctx, msg, ok, s.GiftCount); err != nil {
return
}
case msg, ok := <-liveGuardBuyMsgs:
if err := s.doConsume(ctx, msg, ok, s.GuardBuyStatistics); err != nil {
return
}
default:
time.Sleep(time.Second * 2)
continue
}
}
log.Info("LiveMessageContent_notify_end")
}
func (s *ConsumerService) doConsume(ctx context.Context, msg *databus.Message, ok bool,
fn func(context.Context, *databus.Message) error) (err error) {
name := getFunctionName(fn)
if msg == nil || !ok {
err = errors.New(fmt.Sprintf("consume error ; msg:%v, ok:%v", msg, ok))
log.Error("%s_notify_error:msg=%v", name, msg)
return
}
log.Info("%s:key=%v;offset=%v;msg=%v", name, msg.Key, msg.Offset, msg.Value)
if s.dao.CanConsume(ctx, msg) {
fn(ctx, msg)
}
return
}
func getFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

View File

@@ -0,0 +1,47 @@
package v1
import (
"context"
"encoding/json"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
//消费礼物消息的业务逻辑
//GiftCountStatistics 实时礼物相关统计,异步落地
func (s *ConsumerService) GiftCount(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
msgInfo := new(model.MessageValue)
if err = json.Unmarshal(msg.Value, &msgInfo); err != nil {
log.Error("GiftCountStatistics_Unmarshal_error:msg=%v;err=%v;msgInfo=%v", msg.Value, err, msgInfo)
return
}
log.Info("GiftCount:msgInfo=%v", string(msg.Value))
msgContent := new(model.GiftSendMsgContent)
if err = json.Unmarshal([]byte(msgInfo.MsgContent), &msgContent); err != nil {
log.Error("GiftCountStatistics_Unmarshal_error:err=%v;bodyInfo=%v", err, msgContent)
return
}
bodyInfo := msgContent.Body
roomId := bodyInfo.RoomId
num := bodyInfo.Num
payCoin := bodyInfo.PayCoin
//增加礼物数
GiftNumKeyInfo := s.dao.SRoomRecordCurrent(dao.GIFT_NUM, roomId)
s.dao.Incr(ctx, GiftNumKeyInfo.RedisKey, num, GiftNumKeyInfo.TimeOut)
//增加金瓜子数量
if bodyInfo.CoinType == "gold" {
GiftGoldNumKeyInfo := s.dao.SRoomRecordCurrent(dao.GIFT_GOLD_NUM, roomId)
s.dao.Incr(ctx, GiftGoldNumKeyInfo.RedisKey, num, GiftGoldNumKeyInfo.TimeOut)
}
//增加礼物金额
if bodyInfo.CoinType == "gold" {
GiftGoldAmountKeyInfo := s.dao.SRoomRecordCurrent(dao.GIFT_GOLD_AMOUNT, roomId)
s.dao.Incr(ctx, GiftGoldAmountKeyInfo.RedisKey, payCoin, GiftGoldAmountKeyInfo.TimeOut)
}
return
}

View File

@@ -0,0 +1,39 @@
package v1
import (
"context"
"encoding/json"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
func (s *ConsumerService) GuardBuyStatistics(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
msgInfo := new(model.MessageValue)
if err = json.Unmarshal(msg.Value, &msgInfo); err != nil {
log.Error("GuardBuyStatistics_unmarshal_message_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgInfo)
return
}
log.Info("GuardBuyStatistics:msgInfo=%v", string(msg.Value))
msgContent := new(model.GuardBuyMessageContent)
if err = json.Unmarshal([]byte(msgInfo.MsgContent), &msgContent); err != nil {
log.Error("GuardBuyStatistics_unmarshal_msgcontent_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgInfo)
return
}
roomId := msgContent.RoomId
num := msgContent.Num
coin := msgContent.Coin
goldNumKeyInfo := s.dao.SRoomRecordCurrent(dao.GIFT_GOLD_NUM, roomId)
s.dao.Incr(ctx, goldNumKeyInfo.RedisKey, num, goldNumKeyInfo.TimeOut)
goldAmountKeyInfo := s.dao.SRoomRecordCurrent(dao.GIFT_GOLD_AMOUNT, roomId)
s.dao.Incr(ctx, goldAmountKeyInfo.RedisKey, coin, goldAmountKeyInfo.TimeOut)
return
}

View File

@@ -0,0 +1,87 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus"
)
//PopularityStatistics 离线人气相关统计,同步落地
func (s *ConsumerService) PopularityStatistics(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
return s.internalPopularityStatistics(ctx, msg)
}
func (s *ConsumerService) internalPopularityStatistics(ctx context.Context, msg *databus.Message) (err error) {
msgContent := new(model.TopicCommonMsg)
if err = json.Unmarshal(msg.Value, &msgContent); err != nil {
log.Error("PopularityStatistics_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgContent)
return
}
log.Info("PopularityStatistics:msgInfo=%v", string(msg.Value))
cycle := msgContent.Cycle
value := msgContent.Value
roomId := msgContent.RoomId
attrId := dao.ATTRID_POPULARITY
//expireTime := time.Now().Unix()
//人气过渡时间先消费databus,若为1分钟则为实时人气插入extend表
if cycle == 60 {
req := &v1pb.RoomExtendUpdateReq{
RoomId: roomId,
PopularityCount: value,
Fields: []string{"popularity_count"},
}
s.dao.RoomExtendUpdate(ctx, req)
return
}
reply, err := getPopularityAttrInfo(cycle)
if err != nil {
log.Error("PopularityStatistics_check_attr_sub_id_error")
return
}
attrSubId := reply.AttrSubId
//contentType := reply.ContentType
//redisKeyInfo := s.dao.SRoomRecordCurrent(contentType, roomId)
//s.dao.Incr(ctx, redisKeyInfo.RedisKey, 1, redisKeyInfo.TimeOut)
if attrSubId == dao.ATTRSUBID_POPULARITY_MAX_TO_ARG_7 ||
attrSubId == dao.ATTRSUBID_POPULARITY_MAX_TO_ARG_30 {
//@todo 增加过期标记
req := &v1pb.RoomAttrCreateReq{
RoomId: roomId,
AttrId: int64(attrId),
AttrSubId: attrSubId,
AttrValue: value,
}
resp, err := s.dao.RoomAttrCreate(ctx, req)
if err != nil || resp.AffectedRows <= 0 {
log.Error("PopularityStatistics: msg=%v; err=%v; req=%v", msg, err, req)
}
}
return
}
func getPopularityAttrInfo(cycle int64) (resp *attrInfo, err error) {
days := cycle / 60 / 60 / 24
resp = &attrInfo{}
switch days {
case 7:
resp.AttrSubId = dao.ATTRSUBID_POPULARITY_MAX_TO_ARG_7
resp.ContentType = dao.POPULARITY_MAX_TO_ARG_7
break
case 30:
resp.AttrSubId = dao.ATTRSUBID_POPULARITY_MAX_TO_ARG_30
resp.ContentType = dao.POPULARITY_MAX_TO_ARG_30
break
default:
err = ecode.DaoAnchorCheckAttrSubIdERROR
break
}
return
}

View File

@@ -0,0 +1,235 @@
package v1
import (
"context"
"flag"
"testing"
. "github.com/smartystreets/goconvey/convey"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/log"
"go-common/library/queue/databus"
)
func TestPopularityStatistics(t *testing.T) {
flag.Set("conf", "../../../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
Convey("Test consume real pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
// 测试实时人气值
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":3000,
"cycle":60,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.RoomByIDsReq{
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchRoomByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.RoomDataSet), ShouldEqual, 1)
So(resp.RoomDataSet[460654], ShouldNotBeNil)
So(resp.RoomDataSet[460654].PopularityCount, ShouldEqual, 3000)
})
Convey("Test update real pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
// 测试实时人气值
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":6000,
"cycle":60,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.RoomByIDsReq{
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchRoomByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.RoomDataSet), ShouldEqual, 1)
So(resp.RoomDataSet[460654], ShouldNotBeNil)
So(resp.RoomDataSet[460654].PopularityCount, ShouldEqual, 6000)
})
Convey("Test consume 7 day pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":5000,
"cycle":604800,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 1,
AttrSubId: 2,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 1)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 2)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 5000)
})
Convey("Test update 7 day pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":88000,
"cycle":604800,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 1,
AttrSubId: 2,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 1)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 2)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 88000)
})
Convey("Test consume 30 day pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":5000,
"cycle":2592000,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 1,
AttrSubId: 3,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 1)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 3)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 5000)
})
Convey("Test update 30 day pc", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalPopularityStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":88000,
"cycle":2592000,
"type":88888
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 1,
AttrSubId: 3,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 1)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 3)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 88000)
})
}

View File

@@ -0,0 +1,57 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
//LiveRoomTag 房间实时标签,同步落地
func (s *ConsumerService) LiveRankList(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
return s.internalLiveRankList(ctx, msg)
}
func (s *ConsumerService) internalLiveRankList(ctx context.Context, msg *databus.Message) (err error) {
msgContent := new(model.LiveRankListMsg)
if err = json.Unmarshal(msg.Value, &msgContent); err != nil {
log.Error("LiveRankList_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgContent)
return
}
log.Info("LiveRankList:msgInfo=%v", string(msg.Value))
//expireTime := msgContent.ExpireTime // todo @wangyao
attrId := dao.ATTRID_RANK_LIST
attrSubId := msgContent.RankId
rankList := msgContent.RankList
if rankList == nil || len(rankList) <= 0 {
log.Error("LiveRankList_get_rank_list_error:msg=%v", msgContent)
return
}
deleteReq := &v1pb.DeleteAttrReq{
AttrId: int64(attrId),
AttrSubId: attrSubId,
}
_, err = s.dao.DeleteAttr(ctx, deleteReq)
if err != nil {
log.Error("LiveRankList_DeleteAttr_Error: msg=%v; err=%v; deleteReq=%v", msg, err, deleteReq)
return
}
for roomId, value := range rankList {
req := &v1pb.RoomAttrSetExReq{
RoomId: roomId,
AttrId: int64(attrId),
AttrSubId: attrSubId,
AttrValue: value,
}
_, err := s.dao.RoomAttrSetEx(ctx, req)
if err != nil {
log.Error("LiveRankList: msg=%v; err=%v; req=%v", string(msg.Value), err, req)
}
}
return
}

View File

@@ -0,0 +1,141 @@
package v1
import (
"context"
"flag"
"testing"
. "github.com/smartystreets/goconvey/convey"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/log"
"go-common/library/queue/databus"
)
func TestLiveRankList(t *testing.T) {
flag.Set("conf", "../../../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
Convey("Test consume ranklist", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
// 测试小时榜
err := s.internalLiveRankList(ctx, &databus.Message{
Value: []byte(`
{
"rank_id":1,
"rank_type":"RANK_HOUR",
"rank_list":{"460654":1,"460785":2},
"expire_time":1549542517
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 4,
AttrSubId: 1,
RoomIds: []int64{460654, 460785},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 2)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 4)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 1)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 1)
So(resp.Attrs[460785], ShouldNotBeNil)
So(resp.Attrs[460785].AttrId, ShouldEqual, 4)
So(resp.Attrs[460785].AttrSubId, ShouldEqual, 1)
So(resp.Attrs[460785].AttrValue, ShouldEqual, 2)
})
Convey("Test update ranklist", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
// 测试小时榜
err := s.internalLiveRankList(ctx, &databus.Message{
Value: []byte(`
{
"rank_id":1,
"rank_type":"RANK_HOUR",
"rank_list":{"460767":1,"460796":2},
"expire_time":1549542517
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 4,
AttrSubId: 1,
RoomIds: []int64{460654, 460785, 460767, 460796},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 2)
So(resp.Attrs[460767], ShouldNotBeNil)
So(resp.Attrs[460767].AttrId, ShouldEqual, 4)
So(resp.Attrs[460767].AttrSubId, ShouldEqual, 1)
So(resp.Attrs[460767].AttrValue, ShouldEqual, 1)
So(resp.Attrs[460796], ShouldNotBeNil)
So(resp.Attrs[460796].AttrId, ShouldEqual, 4)
So(resp.Attrs[460796].AttrSubId, ShouldEqual, 1)
So(resp.Attrs[460796].AttrValue, ShouldEqual, 2)
})
Convey("Test update ranklist", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
// 测试小时榜
err := s.internalLiveRankList(ctx, &databus.Message{
Value: []byte(`
{
"rank_id":1,
"rank_type":"RANK_HOUR",
"rank_list":{"460796":1},
"expire_time":1549542517
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 4,
AttrSubId: 1,
RoomIds: []int64{460654, 460785, 460767, 460796},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460796], ShouldNotBeNil)
So(resp.Attrs[460796].AttrId, ShouldEqual, 4)
So(resp.Attrs[460796].AttrSubId, ShouldEqual, 1)
So(resp.Attrs[460796].AttrValue, ShouldEqual, 1)
})
}

View File

@@ -0,0 +1,39 @@
package v1
import (
"context"
"encoding/json"
"go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
//LiveRoomTag 房间实时标签,同步落地
func (s *ConsumerService) LiveRoomTag(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
return s.internalLiveRoomTag(ctx, msg)
}
func (s *ConsumerService) internalLiveRoomTag(ctx context.Context, msg *databus.Message) (err error) {
msgContent := new(model.LiveRoomTagMsg)
if err = json.Unmarshal(msg.Value, &msgContent); err != nil {
log.Error("LiveRoomTag_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgContent)
return
}
log.Info("LiveRoomTag:msgInfo=%v", string(msg.Value))
req := &v1.RoomTagCreateReq{
RoomId: msgContent.RoomId,
TagId: msgContent.TagId,
TagSubId: msgContent.TagSubId,
TagExt: msgContent.TagExt,
TagExpireAt: msgContent.ExpireTime,
TagValue: msgContent.TagValue,
}
resp, err := s.dao.RoomTagCreate(ctx, req)
if err != nil || resp.AffectedRows <= 0 {
log.Error("LiveRoomTag: msg=%v; err=%v; req=%v", msg, err, req)
}
return
}

View File

@@ -0,0 +1,107 @@
package v1
import (
"context"
"flag"
"testing"
. "github.com/smartystreets/goconvey/convey"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/log"
"go-common/library/queue/databus"
)
func TestLiveRoomTag(t *testing.T) {
flag.Set("conf", "../../../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
Convey("Test consume room tag", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalLiveRoomTag(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"tag_id":3,
"tag_sub_id":2,
"tag_value":1,
"tag_ext":"",
"expire_time":1549542517
}`),
})
So(err, ShouldBeNil)
req := &v1pb.RoomByIDsReq{
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchRoomByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.RoomDataSet), ShouldEqual, 1)
So(resp.RoomDataSet[460654], ShouldNotBeNil)
So(len(resp.RoomDataSet[460654].TagList), ShouldBeGreaterThanOrEqualTo, 1)
So(resp.RoomDataSet[460654].TagList, ShouldContain, &v1pb.TagData{
TagId: 3,
TagSubId: 2,
TagValue: 1,
TagExt: "",
TagExpireAt: 1549542517,
})
})
Convey("Update", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalLiveRoomTag(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"tag_id":3,
"tag_sub_id":1,
"tag_value":2,
"tag_ext":"asd",
"expire_time":1549000000
}`),
})
So(err, ShouldBeNil)
req := &v1pb.RoomByIDsReq{
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchRoomByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.RoomDataSet), ShouldEqual, 1)
So(resp.RoomDataSet[460654], ShouldNotBeNil)
So(len(resp.RoomDataSet[460654].TagList), ShouldBeGreaterThanOrEqualTo, 1)
So(resp.RoomDataSet[460654].TagList, ShouldContain, &v1pb.TagData{
TagId: 3,
TagSubId: 1,
TagValue: 2,
TagExt: "asd",
TagExpireAt: 1549000000,
})
})
}

View File

@@ -0,0 +1,87 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/dao"
"go-common/app/service/live/dao-anchor/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus"
)
//ValidDaysStatistics 有效天数相关数据(同步落地)
func (s *ConsumerService) ValidDaysStatistics(ctx context.Context, msg *databus.Message) (err error) {
defer msg.Commit()
return s.internalValidDaysStatistics(ctx, msg)
}
func (s *ConsumerService) internalValidDaysStatistics(ctx context.Context, msg *databus.Message) (err error) {
msgContent := new(model.TopicCommonMsg)
if err = json.Unmarshal(msg.Value, &msgContent); err != nil {
log.Error("ValidDaysStatistics_error:msg=%v;err=%v;msgInfo=%v", msg, err, msgContent)
return
}
log.Info("ValidDaysStatistics:msgInfo=%v", string(msg.Value))
cycle := msgContent.Cycle
value := msgContent.Value
roomId := msgContent.RoomId
attrId := dao.ATTRID_VALID_LIVE_DAYS
typ := msgContent.Type
reply, err := getValidDaysAttrInfo(cycle, typ)
if err != nil {
log.Error("ValidDaysStatistics_check_attr_sub_id_error")
return
}
attrSubId := reply.AttrSubId
//contentType := reply.ContentType
//redisKeyInfo := s.dao.SRoomRecordCurrent(contentType, roomId)
//s.dao.Incr(ctx, redisKeyInfo.RedisKey, 1, redisKeyInfo.TimeOut)
//有效开播天数为离线计算数据,直接入库
req := &v1pb.RoomAttrCreateReq{
RoomId: roomId,
AttrId: int64(attrId),
AttrSubId: attrSubId,
AttrValue: value,
}
resp, err := s.dao.RoomAttrCreate(ctx, req)
if err != nil || resp.AffectedRows <= 0 {
log.Error("ValidDaysStatistics: msg=%v; err=%v; req=%v", msg, err, req)
}
return
}
func getValidDaysAttrInfo(cycle int64, typ int64) (resp *attrInfo, err error) {
days := cycle / 60 / 60 / 24
resp = &attrInfo{}
switch days {
case 7:
if typ == dao.VALID_LIVE_DAYS_TYPE_1 {
resp.AttrSubId = dao.ATTRSUBID_VALID_LIVE_DAYS_TYPE_1_DAY_7
resp.ContentType = dao.VALID_LIVE_DAYS_TYPE_1_DAY_7
} else if typ == dao.VALID_LIVE_DAYS_TYPE_2 {
resp.AttrSubId = dao.ATTRSUBID_VALID_LIVE_DAYS_TYPE_2_DAY_7
resp.ContentType = dao.VALID_LIVE_DAYS_TYPE_2_DAY_7
}
break
case 14:
if typ == dao.VALID_LIVE_DAYS_TYPE_1 {
resp.AttrSubId = dao.ATTRSUBID_VALID_LIVE_DAYS_TYPE_1_DAY_14
resp.ContentType = dao.VALID_LIVE_DAYS_TYPE_1_DAY_14
}
case 30:
if typ == dao.VALID_LIVE_DAYS_TYPE_2 {
resp.AttrSubId = dao.ATTRSUBID_VALID_LIVE_DAYS_TYPE_2_DAY_30
resp.ContentType = dao.VALID_LIVE_DAYS_TYPE_2_DAY_30
}
break
default:
err = ecode.DaoAnchorCheckAttrSubIdERROR
break
}
return
}

View File

@@ -0,0 +1,169 @@
package v1
import (
"context"
"flag"
"testing"
. "github.com/smartystreets/goconvey/convey"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/log"
"go-common/library/queue/databus"
)
func TestValidDaysStatistics(t *testing.T) {
flag.Set("conf", "../../../cmd/test.toml")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
Convey("Test consume 7 day vd", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalValidDaysStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":5000,
"cycle":604800,
"type":2
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 5,
AttrSubId: 3,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 5)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 3)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 5000)
})
Convey("Test update 7 day vd", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalValidDaysStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":88000,
"cycle":604800,
"type":2
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 5,
AttrSubId: 3,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 5)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 3)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 88000)
})
Convey("Test consume 30 day vd", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalValidDaysStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":5000,
"cycle":2592000,
"type":2
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 5,
AttrSubId: 4,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 5)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 4)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 5000)
})
Convey("Test update 30 day vd", t, func(c C) {
ctx := context.TODO()
s := &ConsumerService{
conf: conf.Conf,
dao: dao.New(conf.Conf),
}
So(s, ShouldNotBeNil)
err := s.internalValidDaysStatistics(ctx, &databus.Message{
Value: []byte(`
{
"msg_id":"1111",
"room_id":460654,
"value":88000,
"cycle":2592000,
"type":2
}`),
})
So(err, ShouldBeNil)
req := &v1pb.FetchAttrByIDsReq{
AttrId: 5,
AttrSubId: 4,
RoomIds: []int64{460654},
}
// 检查插入数据
resp, err := dao.New(conf.Conf).FetchAttrByIDs(ctx, req)
So(err, ShouldBeNil)
So(len(resp.Attrs), ShouldEqual, 1)
So(resp.Attrs[460654], ShouldNotBeNil)
So(resp.Attrs[460654].AttrId, ShouldEqual, 5)
So(resp.Attrs[460654].AttrSubId, ShouldEqual, 4)
So(resp.Attrs[460654].AttrValue, ShouldEqual, 88000)
})
}

View File

@@ -0,0 +1,52 @@
package service
import (
"context"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
consumerV1 "go-common/app/service/live/dao-anchor/service/consumer/v1"
"go-common/app/service/live/dao-anchor/service/v0"
"go-common/app/service/live/dao-anchor/service/v1"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
v1svc *v1.DaoAnchorService
consumerSvc *consumerV1.ConsumerService
createCacheSvc *v0.CreateDataService
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
v1svc: v1.NewDaoAnchorService(c),
consumerSvc: consumerV1.NewConsumerService(c),
createCacheSvc: v0.NewCreateDataService(c),
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// CreateDataSvc return dao-anchor CreateDataService
func (s *Service) CreateDataSvc() *v0.CreateDataService {
return s.createCacheSvc
}
// V1Svc return dao-anchor v1 service
func (s *Service) V1Svc() *v1.DaoAnchorService {
return s.v1svc
}

View File

@@ -0,0 +1,51 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["createData_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v0:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["createData.go"],
importpath = "go-common/app/service/live/dao-anchor/service/v0",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v0:go_default_library",
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao:go_default_library",
"//library/cache/redis:go_default_library",
"//library/log: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,270 @@
package v0
import (
"context"
"encoding/json"
"time"
"go-common/library/cache/redis"
"go-common/app/service/live/dao-anchor/api/grpc/v0"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/log"
)
// CreateDataService struct
type CreateDataService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewCreateDataService init
func NewCreateDataService(c *conf.Config) (s *CreateDataService) {
s = &CreateDataService{
conf: c,
dao: dao.New(c),
}
return s
}
//job定制接口,内部调用
//需要定时入库的数据常量定义
var contentMap = map[string]int64{dao.DANMU_NUM: 1, dao.GIFT_GOLD_AMOUNT: 1}
//GetContentMap 需要定时入库的数据常量定义与job
//@todo 待优化逻辑
func (s *CreateDataService) GetContentMap(ctx context.Context, req *v0.GetContentMapReq) (resp *v0.GetContentMapResp, err error) {
resp = &v0.GetContentMapResp{}
resp.List = contentMap
return
}
//CreateCacheList 生成历史记录list
func (s *CreateDataService) CreateCacheList(ctx context.Context, req *v0.CreateCacheListReq) (resp *v0.CreateCacheListResp, err error) {
resp = &v0.CreateCacheListResp{}
content := req.Content
log.Info("createCacheList_start")
if contentMap[content] <= 0 {
log.Error("createCacheList_check_content_error:content=%s", content)
return
}
log.Info("createCacheList_end")
return
}
//CreateLiveCacheList 生成开播历史记录list
func (s *CreateDataService) CreateLiveCacheList(ctx context.Context, req *v0.CreateLiveCacheListReq) (resp *v0.CreateLiveCacheListResp, err error) {
resp = &v0.CreateLiveCacheListResp{}
content := req.Content
roomIds := req.RoomIds
log.Info("createLiveCacheList_start")
if contentMap[content] <= 0 {
log.Error("createLiveCacheList_check_content_error:content=%s", content)
return
}
roomReq := &v1.RoomByIDsReq{
RoomIds: roomIds,
Fields: []string{"live_status"},
}
reply, err := s.dao.FetchRoomByIDs(ctx, roomReq)
if err != nil || len(reply.RoomDataSet) <= 0 {
log.Error("createLiveCacheList_get_room_error:reply=%v;err=%v;", reply, err)
return
}
// Order of data in contentList is determined by `realRoomIds`.
contentList, err := s.dao.GetRoomRecordsCurrent(ctx, content, roomIds)
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("createLiveCacheList_get_room_content_records_error:err=%v", err)
return
}
toSetValues := make(map[int64]string)
// dao.redisKeyResp is private in dao package.
toSetKeys := make(map[int64]interface{})
toSetRoomIds := make([]int64, 0)
for i, roomId := range roomIds {
if reply.RoomDataSet[roomId] == nil {
log.Error("createLiveCacheList_find_room_error:%d", roomId)
continue
}
if reply.RoomDataSet[roomId].LiveStatus != dao.LIVE_OPEN {
log.Info("createLiveCacheList_room_is_close;room_id=%d", roomId)
continue
}
setValue := make(map[string]interface{})
setValue["time"] = time.Now().Unix()
setValue["value"] = contentList[i]
valueBytes, err := json.Marshal(setValue)
if err != nil {
panic(err)
}
toSetValues[roomId] = string(valueBytes)
liveTime := reply.RoomDataSet[roomId].LiveStartTime
setKey := s.dao.LRoomLiveRecordList(content, roomId, liveTime)
toSetKeys[roomId] = setKey
toSetRoomIds = append(toSetRoomIds, roomId)
}
err = s.dao.SetRoomRecordsList(ctx, toSetRoomIds, toSetKeys, toSetValues)
s.dao.DelRoomRecordsCurrent(ctx, content, toSetRoomIds)
if err != nil {
log.Error("createLiveCacheList_set_room_records_list:err=%v", err)
return
}
log.Info("createLiveCacheList_end")
return
}
func (s *CreateDataService) CreateDBData(ctx context.Context, req *v0.CreateDBDataReq) (resp *v0.CreateDBDataResp, err error) {
resp = &v0.CreateDBDataResp{}
content := req.Content
roomIds := req.RoomIds
log.Info("CreateDB_start")
if contentMap[content] <= 0 {
log.Error("CreateDB_check_content_error:content=%s", content)
return
}
attrId := int64(0)
switch content {
case dao.DAU:
//@todo
break
case dao.GIFT_NUM:
//@todo
break
case dao.GIFT_GOLD_NUM:
//@todo
break
case dao.GIFT_GOLD_AMOUNT:
attrId = dao.ATTRID_REVENUE
break
case dao.DANMU_NUM:
attrId = dao.ATTRID_DANMU
break
default:
break
}
recordsRange, err := s.dao.GetRoomLiveRecordsRange(ctx, content, roomIds, 0, 0, 59)
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("CreateDBData_redis_GetRoomLiveRecordsRange failed completely error(%v)", err)
return nil, err
}
if attrId < 0 {
return
}
for roomId, valueInfos := range recordsRange {
attrReq := &v1.RoomAttrCreateReq{
AttrId: attrId,
RoomId: roomId,
}
values := getAttrData(attrId, valueInfos)
for attrSubId, attrValue := range values {
attrReq.AttrSubId = attrSubId
attrReq.AttrValue = attrValue
s.dao.RoomAttrCreate(ctx, attrReq)
}
}
return
}
func (s *CreateDataService) CreateRoomExtendDBData(ctx context.Context, content string, roomIds []int64) (err error) {
log.Info("CreateDB_start")
if contentMap[content] <= 0 {
log.Error("CreateDB_check_content_error:content=%s", content)
return
}
RoomExtendReq, err := s.GetRoomExtendDataReq(content)
if err != nil {
log.Error("CreateDB_RoomExtendReq_error:content=%s;roomIds=%v", content, roomIds)
}
if err == nil && RoomExtendReq != nil {
for _, roomId := range roomIds {
RoomExtendReq.RoomId = roomId
}
s.dao.RoomExtendUpdate(ctx, RoomExtendReq)
}
return
}
func (s *CreateDataService) GetRoomExtendDataReq(content string) (resp *v1.RoomExtendUpdateReq, err error) {
resp = &v1.RoomExtendUpdateReq{}
switch content {
case dao.DAU:
resp.AudienceCount = 0
break
case dao.GIFT_NUM:
resp.GiftCount = 0
break
case dao.GIFT_GOLD_NUM:
resp.GiftGoldCount = 0
break
case dao.GIFT_GOLD_AMOUNT:
resp.GiftGoldAmount = 0
break
default:
break
}
return
}
func getAttrData(AttrId int64, listInfos []*dao.ListIntValueInfo) (value map[int64]int64) {
value = make(map[int64]int64)
switch AttrId {
case dao.ATTRID_DANMU:
for i, listInfo := range listInfos {
if i < 15 {
value[dao.ATTRSUBID_DANMU_MINUTE_NUM_15] += listInfo.Value
}
if i < 30 {
value[dao.ATTRSUBID_DANMU_MINUTE_NUM_30] += listInfo.Value
}
if i < 45 {
value[dao.ATTRSUBID_DANMU_MINUTE_NUM_45] += listInfo.Value
}
if i < 60 {
value[dao.ATTRSUBID_DANMU_MINUTE_NUM_60] += listInfo.Value
}
}
break
case dao.ATTRID_REVENUE:
for i, listInfo := range listInfos {
if i < 15 {
value[dao.ATTRSUBID_REVENUE_MINUTE_NUM_15] += listInfo.Value
}
if i < 30 {
value[dao.ATTRSUBID_REVENUE_MINUTE_NUM_30] += listInfo.Value
}
if i < 45 {
value[dao.ATTRSUBID_REVENUE_MINUTE_NUM_45] += listInfo.Value
}
if i < 60 {
value[dao.ATTRSUBID_REVENUE_MINUTE_NUM_60] += listInfo.Value
}
}
break
default:
break
}
return
}

View File

@@ -0,0 +1,46 @@
package v0
import (
"context"
"flag"
"fmt"
"testing"
"go-common/app/service/live/dao-anchor/api/grpc/v0"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
"go-common/library/net/metadata"
. "github.com/smartystreets/goconvey/convey"
)
var s *CreateDataService
func init() {
flag.Set("conf", "../../cmd/test.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = NewCreateDataService(conf.Conf)
}
//group=qa01 DEPLOY_ENV=uat go test -run TestCreateCache
func TestCreateCache(t *testing.T) {
Convey("TestCreateCache", t, func() {
ctx := metadata.NewContext(context.TODO(), metadata.MD{})
replay, err := s.CreateLiveCacheList(ctx, &v0.CreateLiveCacheListReq{Content: dao.DANMU_NUM, RoomIds: []int64{1, 1003, 1005}})
fmt.Println(replay, err)
So(err, ShouldBeNil)
})
}
func TestCreateDBData(t *testing.T) {
Convey("TestCreateDBData", t, func() {
ctx := metadata.NewContext(context.TODO(), metadata.MD{})
reply, err := s.CreateDBData(ctx, &v0.CreateDBDataReq{Content: dao.DANMU_NUM, RoomIds: []int64{1003, 1005}})
fmt.Println(reply, err)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["daoAnchor.go"],
importpath = "go-common/app/service/live/dao-anchor/service/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/dao-anchor/api/grpc/v1:go_default_library",
"//app/service/live/dao-anchor/conf:go_default_library",
"//app/service/live/dao-anchor/dao: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,151 @@
package v1
import (
"context"
v1pb "go-common/app/service/live/dao-anchor/api/grpc/v1"
"go-common/app/service/live/dao-anchor/conf"
"go-common/app/service/live/dao-anchor/dao"
)
// DaoAnchorService struct
type DaoAnchorService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewDaoAnchorService init
func NewDaoAnchorService(c *conf.Config) (s *DaoAnchorService) {
s = &DaoAnchorService{
conf: c,
dao: dao.New(c),
}
return s
}
// FetchRoomByIDs implementation
// FetchRoomByIDs 查询房间信息
func (s *DaoAnchorService) FetchRoomByIDs(ctx context.Context, req *v1pb.RoomByIDsReq) (resp *v1pb.RoomByIDsResp, err error) {
return s.dao.FetchRoomByIDs(ctx, req)
}
// RoomOnlineList implementation
// RoomOnlineList 在线房间列表
func (s *DaoAnchorService) RoomOnlineList(ctx context.Context, req *v1pb.RoomOnlineListReq) (resp *v1pb.RoomOnlineListResp, err error) {
return s.dao.RoomOnlineList(ctx, req)
}
// RoomOnlineListByArea implementation
// RoomOnlineListByArea 分区在线房间列表
func (s *DaoAnchorService) RoomOnlineListByArea(ctx context.Context, req *v1pb.RoomOnlineListByAreaReq) (resp *v1pb.RoomOnlineListByAreaResp, err error) {
return s.dao.RoomOnlineListByArea(ctx, req)
}
// RoomOnlineListByAttrs implementation
// RoomOnlineListByAttrs 在线房间维度信息(不传attrs不查询attr)
func (s *DaoAnchorService) RoomOnlineListByAttrs(ctx context.Context, req *v1pb.RoomOnlineListByAttrsReq) (resp *v1pb.RoomOnlineListByAttrsResp, err error) {
return s.dao.RoomOnlineListByAttrs(ctx, req)
}
// RoomCreate implementation
// RoomCreate 房间创建
func (s *DaoAnchorService) RoomCreate(ctx context.Context, req *v1pb.RoomCreateReq) (resp *v1pb.RoomCreateResp, err error) {
return s.dao.RoomCreate(ctx, req)
}
// RoomUpdate implementation
// RoomUpdate 房间信息更新
func (s *DaoAnchorService) RoomUpdate(ctx context.Context, req *v1pb.RoomUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomUpdate(ctx, req)
}
// RoomBatchUpdate implementation
// RoomBatchUpdate 房间信息批量更新
func (s *DaoAnchorService) RoomBatchUpdate(ctx context.Context, req *v1pb.RoomBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomBatchUpdate(ctx, req)
}
// RoomExtendUpdate implementation
// RoomExtendUpdate 房间扩展信息更新
func (s *DaoAnchorService) RoomExtendUpdate(ctx context.Context, req *v1pb.RoomExtendUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomExtendUpdate(ctx, req)
}
// RoomExtendBatchUpdate implementation
// RoomExtendBatchUpdate 房间扩展信息批量更新
func (s *DaoAnchorService) RoomExtendBatchUpdate(ctx context.Context, req *v1pb.RoomExtendBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomExtendBatchUpdate(ctx, req)
}
// RoomExtendIncre implementation
// RoomExtendIncre 房间扩展信息增量更新
func (s *DaoAnchorService) RoomExtendIncre(ctx context.Context, req *v1pb.RoomExtendIncreReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomExtendIncre(ctx, req)
}
// RoomExtendBatchIncre implementation
// RoomExtendBatchIncre 房间扩展信息批量增量更新
func (s *DaoAnchorService) RoomExtendBatchIncre(ctx context.Context, req *v1pb.RoomExtendBatchIncreReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomExtendBatchIncre(ctx, req)
}
// RoomTagCreate implementation
// RoomTagCreate 房间Tag创建
func (s *DaoAnchorService) RoomTagCreate(ctx context.Context, req *v1pb.RoomTagCreateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomTagCreate(ctx, req)
}
// RoomAttrCreate implementation
// RoomAttrCreate 房间Attr创建
func (s *DaoAnchorService) RoomAttrCreate(ctx context.Context, req *v1pb.RoomAttrCreateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomAttrCreate(ctx, req)
}
// RoomAttrSetEx implementation
// RoomAttrSetEx 房间Attr更新
func (s *DaoAnchorService) RoomAttrSetEx(ctx context.Context, req *v1pb.RoomAttrSetExReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.RoomAttrSetEx(ctx, req)
}
// AnchorUpdate implementation
// AnchorUpdate 主播信息更新
func (s *DaoAnchorService) AnchorUpdate(ctx context.Context, req *v1pb.AnchorUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.AnchorUpdate(ctx, req)
}
// AnchorBatchUpdate implementation
// AnchorBatchUpdate 主播信息批量更新
func (s *DaoAnchorService) AnchorBatchUpdate(ctx context.Context, req *v1pb.AnchorBatchUpdateReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.AnchorBatchUpdate(ctx, req)
}
// AnchorIncre implementation
// AnchorIncre 主播信息增量更新
func (s *DaoAnchorService) AnchorIncre(ctx context.Context, req *v1pb.AnchorIncreReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.AnchorIncre(ctx, req)
}
// AnchorBatchIncre implementation
// AnchorBatchIncre 主播信息批量增量更新
func (s *DaoAnchorService) AnchorBatchIncre(ctx context.Context, req *v1pb.AnchorBatchIncreReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.AnchorBatchIncre(ctx, req)
}
// FetchAreas implementation
// FetchAreas 根据父分区号查询子分区
func (s *DaoAnchorService) FetchAreas(ctx context.Context, req *v1pb.FetchAreasReq) (resp *v1pb.FetchAreasResp, err error) {
return s.dao.FetchAreas(ctx, req)
}
// FetchAttrByIDs implementation
// FetchAttrByIDs 批量根据房间号查询指标
func (s *DaoAnchorService) FetchAttrByIDs(ctx context.Context, req *v1pb.FetchAttrByIDsReq) (resp *v1pb.FetchAttrByIDsResp, err error) {
return s.dao.FetchAttrByIDs(ctx, req)
}
// DeleteAttr implementation
// DeleteAttr 删除一个指标
func (s *DaoAnchorService) DeleteAttr(ctx context.Context, req *v1pb.DeleteAttrReq) (resp *v1pb.UpdateResp, err error) {
return s.dao.DeleteAttr(ctx, req)
}