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,27 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/live/resource/api/grpc/v1:all-srcs",
"//app/service/live/resource/api/grpc/v2:all-srcs",
"//app/service/live/resource/api/http/v1:all-srcs",
"//app/service/live/resource/cmd:all-srcs",
"//app/service/live/resource/conf:all-srcs",
"//app/service/live/resource/dao:all-srcs",
"//app/service/live/resource/lrucache:all-srcs",
"//app/service/live/resource/model:all-srcs",
"//app/service/live/resource/sdk:all-srcs",
"//app/service/live/resource/server/grpc:all-srcs",
"//app/service/live/resource/server/http:all-srcs",
"//app/service/live/resource/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,15 @@
# v1.0.2
1.添加直播配置中心service
2.增加用户头像框管理
3.配置中心update
4.配置中心增加权限维度
5.fix 内部接口统一转发规则
6.titansSdk
7.kv配置增加tree_id级缓存
8.fix rows close
# v1.0.1
1. 添加live-check
# v1.0.0
1. 上线功能xxx

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,67 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"api.bm.go",
"client.go",
"livecheck.bm.go",
"titans.bm.go",
],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/live/resource/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster: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"],
)
proto_library(
name = "v1_proto",
srcs = [
"api.proto",
"livecheck.proto",
"titans.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/resource/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)

View File

@@ -0,0 +1,57 @@
##获取有效banner配置
`GET http://api.live.bilibili.com/xlive/resource/v1/banner/GetBlinkBanner`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|build|是|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
}
```
##获取有效banner配置
`GET http://api.live.bilibili.com/xlive/resource/v1/banner/GetBanner`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|build|是|integer||
|type|是|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
]
}
}
```

View File

@@ -0,0 +1,223 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/grpc/v1/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/grpc/v1/api.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
// ==================
// Resource Interface
// ==================
type Resource interface {
// Add 添加资源接口
Add(ctx context.Context, req *AddReq) (resp *AddResp, err error)
// Add 添加资源接口(不限制位置和平台)
AddEx(ctx context.Context, req *AddReq) (resp *AddResp, err error)
// Edit 编辑资源接口
Edit(ctx context.Context, req *EditReq) (resp *EditResp, err error)
// Offline 下线资源接口
Offline(ctx context.Context, req *OfflineReq) (resp *OfflineResp, err error)
// GetList 获取资源列表
GetList(ctx context.Context, req *GetListReq) (resp *GetListResp, err error)
// 获取平台列表
GetPlatformList(ctx context.Context, req *GetPlatformListReq) (resp *GetPlatformListResp, err error)
// GetListEx 获取资源列表
GetListEx(ctx context.Context, req *GetListExReq) (resp *GetListExResp, err error)
}
var v1ResourceSvc Resource
// @params AddReq
// @router GET /xlive/resource/v1/resource/Add
// @response AddResp
func resourceAdd(c *bm.Context) {
p := new(AddReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.Add(c, p)
c.JSON(resp, err)
}
// @params AddReq
// @router GET /xlive/resource/v1/resource/AddEx
// @response AddResp
func resourceAddEx(c *bm.Context) {
p := new(AddReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.AddEx(c, p)
c.JSON(resp, err)
}
// @params EditReq
// @router GET /xlive/resource/v1/resource/Edit
// @response EditResp
func resourceEdit(c *bm.Context) {
p := new(EditReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.Edit(c, p)
c.JSON(resp, err)
}
// @params OfflineReq
// @router GET /xlive/resource/v1/resource/Offline
// @response OfflineResp
func resourceOffline(c *bm.Context) {
p := new(OfflineReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.Offline(c, p)
c.JSON(resp, err)
}
// @params GetListReq
// @router GET /xlive/resource/v1/resource/GetList
// @response GetListResp
func resourceGetList(c *bm.Context) {
p := new(GetListReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.GetList(c, p)
c.JSON(resp, err)
}
// @params GetPlatformListReq
// @router GET /xlive/resource/v1/resource/GetPlatformList
// @response GetPlatformListResp
func resourceGetPlatformList(c *bm.Context) {
p := new(GetPlatformListReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.GetPlatformList(c, p)
c.JSON(resp, err)
}
// @params GetListExReq
// @router GET /xlive/resource/v1/resource/GetListEx
// @response GetListExResp
func resourceGetListEx(c *bm.Context) {
p := new(GetListExReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1ResourceSvc.GetListEx(c, p)
c.JSON(resp, err)
}
// RegisterV1ResourceService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1ResourceService(e *bm.Engine, svc Resource, midMap map[string]bm.HandlerFunc) {
v1ResourceSvc = svc
e.GET("/xlive/resource/v1/resource/Add", resourceAdd)
e.GET("/xlive/resource/v1/resource/AddEx", resourceAddEx)
e.GET("/xlive/resource/v1/resource/Edit", resourceEdit)
e.GET("/xlive/resource/v1/resource/Offline", resourceOffline)
e.GET("/xlive/resource/v1/resource/GetList", resourceGetList)
e.GET("/xlive/resource/v1/resource/GetPlatformList", resourceGetPlatformList)
e.GET("/xlive/resource/v1/resource/GetListEx", resourceGetListEx)
}
// ================
// Splash Interface
// ================
type Splash interface {
// 获取有效闪屏配置
GetInfo(ctx context.Context, req *GetInfoReq) (resp *GetInfoResp, err error)
}
var v1SplashSvc Splash
// @params GetInfoReq
// @router GET /xlive/resource/v1/splash/GetInfo
// @response GetInfoResp
func splashGetInfo(c *bm.Context) {
p := new(GetInfoReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1SplashSvc.GetInfo(c, p)
c.JSON(resp, err)
}
// RegisterV1SplashService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1SplashService(e *bm.Engine, svc Splash, midMap map[string]bm.HandlerFunc) {
v1SplashSvc = svc
e.GET("/xlive/resource/v1/splash/GetInfo", splashGetInfo)
}
// ================
// Banner Interface
// ================
type Banner interface {
// 获取有效banner配置
GetBlinkBanner(ctx context.Context, req *GetInfoReq) (resp *GetInfoResp, err error)
// 获取有效banner配置
GetBanner(ctx context.Context, req *GetBannerReq) (resp *GetBannerResp, err error)
}
var v1BannerSvc Banner
// @params GetInfoReq
// @router GET /xlive/resource/v1/banner/GetBlinkBanner
// @response GetInfoResp
func bannerGetBlinkBanner(c *bm.Context) {
p := new(GetInfoReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1BannerSvc.GetBlinkBanner(c, p)
c.JSON(resp, err)
}
// @params GetBannerReq
// @router GET /xlive/resource/v1/banner/GetBanner
// @response GetBannerResp
func bannerGetBanner(c *bm.Context) {
p := new(GetBannerReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1BannerSvc.GetBanner(c, p)
c.JSON(resp, err)
}
// RegisterV1BannerService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1BannerService(e *bm.Engine, svc Banner, midMap map[string]bm.HandlerFunc) {
v1BannerSvc = svc
e.GET("/xlive/resource/v1/banner/GetBlinkBanner", bannerGetBlinkBanner)
e.GET("/xlive/resource/v1/banner/GetBanner", bannerGetBanner)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
syntax = "proto3";
package live.resource.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// addReq
message AddReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
string title = 2 [(gogoproto.moretags) = 'form:"title" validate:"required"'];
string jumpPath = 3 [(gogoproto.moretags) = 'form:"jumpPath"'];
int64 jumpTime = 4 [(gogoproto.moretags) = 'form:"jumpTime"'];
string type = 5 [(gogoproto.moretags) = 'form:"type" validate:"required"'];
string device = 6 [(gogoproto.moretags) = 'form:"device" validate:"required"'];
string startTime = 7 [(gogoproto.moretags) = 'form:"startTime" validate:"required"'];
string endTime = 8 [(gogoproto.moretags) = 'form:"endTime" validate:"required"'];
string imageUrl = 9 [(gogoproto.moretags) = 'form:"imageUrl" validate:"required"'];
int64 jumpPathType = 10 [(gogoproto.moretags) = 'form:"jumpPathType"'];
}
// addResp
message AddResp {
repeated int64 id = 1 [(gogoproto.jsontag) = "id"];
}
// editReq
message EditReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 id = 2 [(gogoproto.moretags) = 'form:"id" validate:"required"'];
string title = 3 [(gogoproto.moretags) = 'form:"title"'];
string jumpPath = 4 [(gogoproto.moretags) = 'form:"jumpPath"'];
int64 jumpTime = 5 [(gogoproto.moretags) = 'form:"jumpTime"'];
string startTime = 7 [(gogoproto.moretags) = 'form:"startTime"'];
string endTime = 8 [(gogoproto.moretags) = 'form:"endTime"'];
string imageUrl = 9 [(gogoproto.moretags) = 'form:"imageUrl"'];
int64 jumpPathType = 10 [(gogoproto.moretags) = 'form:"jumpPathType"'];
}
// editResp
message EditResp {
}
//下线闪屏
message OfflineReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 id = 2 [(gogoproto.moretags) = 'form:"id" validate:"required"'];
}
message OfflineResp {
}
//获取闪屏配置列表
message GetListReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 page = 2 [(gogoproto.moretags) = 'form:"page"'];
int64 pageSize = 3 [(gogoproto.moretags) = 'form:"pageSize"'];
string type = 4 [(gogoproto.moretags) = 'form:"type" validate:"required"'];
}
message GetListResp {
int64 currentPage = 1 [(gogoproto.jsontag) = "currentPage"];
int64 totalCount = 2 [(gogoproto.jsontag) = "totalCount"];
repeated List list = 3 [(gogoproto.jsontag) = "list"];
message List {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string title = 2 [(gogoproto.jsontag) = "title"];
string jumpPath = 3 [(gogoproto.jsontag) = "jumpPath"];
string device_platform = 4 [(gogoproto.jsontag) = "device_platform"];
int64 device_build = 5 [(gogoproto.jsontag) = "device_build"];
string startTime = 6 [(gogoproto.jsontag) = "startTime"];
string endTime = 7 [(gogoproto.jsontag) = "endTime"];
int64 status = 8 [(gogoproto.jsontag) = "status"];
int64 device_limit =9 [(gogoproto.jsontag) = "device_limit"];
string imageUrl = 10 [(gogoproto.jsontag) = "imageUrl"];
int64 jumpPathType = 11 [(gogoproto.jsontag) = "jumpPathType"];
int64 jumpTime = 12 [(gogoproto.jsontag) = "jumpTime"];
}
}
// 获取当前有效闪屏配置(客户端)
message GetInfoReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 build = 2 [(gogoproto.moretags) = 'form:"build" validate:"required"'];
}
message GetInfoResp {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string title = 2 [(gogoproto.jsontag) = "title"];
string jumpPath = 3 [(gogoproto.jsontag) = "jumpPath"];
int64 jumpTime = 4 [(gogoproto.jsontag) = "jumpTime"];
int64 jumpPathType = 5 [(gogoproto.jsontag) = "jumpPathType"];
string imageUrl = 6 [(gogoproto.jsontag) = "imageUrl"];
}
// 获取当前有效banner配置(客户端)
message GetBlinkBannerReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 build = 2 [(gogoproto.moretags) = 'form:"build" validate:"required"'];
}
message GetBlinkBannerResp {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string title = 2 [(gogoproto.jsontag) = "title"];
string jumpPath = 3 [(gogoproto.jsontag) = "jumpPath"];
int64 jumpTime = 4 [(gogoproto.jsontag) = "jumpTime"];
int64 jumpPathType = 5 [(gogoproto.jsontag) = "jumpPathType"];
string imageUrl = 6 [(gogoproto.jsontag) = "imageUrl"];
}
// 获取banner配置(客户端)
message GetBannerReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 build = 2 [(gogoproto.moretags) = 'form:"build" validate:"required"'];
string type = 3 [(gogoproto.moretags) = 'form:"type" validate:"required"'];
}
message GetBannerResp {
repeated List list = 1 [(gogoproto.jsontag) = "list"];
message List {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string title = 2 [(gogoproto.jsontag) = "title"];
string jumpPath = 3 [(gogoproto.jsontag) = "jumpPath"];
int64 jumpTime = 4 [(gogoproto.jsontag) = "jumpTime"];
int64 jumpPathType = 5 [(gogoproto.jsontag) = "jumpPathType"];
string imageUrl = 6 [(gogoproto.jsontag) = "imageUrl"];
}
}
message GetPlatformListReq {
int64 type=1 [(gogoproto.jsontag) = "type"];
}
message GetPlatformListResp {
repeated string platform =1 [(gogoproto.jsontag) = "platform"];
}
message GetListExReq {
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
int64 page = 2 [(gogoproto.moretags) = 'form:"page"'];
int64 pageSize = 3 [(gogoproto.moretags) = 'form:"pageSize"'];
repeated string type = 4 [(gogoproto.moretags) = 'form:"type" validate:"required"'];
string device_platform = 5 [(gogoproto.moretags) = 'form:"device_platform"'];
string status = 6 [(gogoproto.moretags) = 'form:"status"'];
string startTime = 7 [(gogoproto.moretags) = 'form:"startTime"'];
string endTime = 8 [(gogoproto.moretags) = 'form:"endTime"'];
}
message GetListExResp {
int64 currentPage = 1 [(gogoproto.jsontag) = "currentPage"];
int64 totalCount = 2 [(gogoproto.jsontag) = "totalCount"];
repeated List list = 3 [(gogoproto.jsontag) = "list"];
message List {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string title = 2 [(gogoproto.jsontag) = "title"];
string jumpPath = 3 [(gogoproto.jsontag) = "jumpPath"];
string device_platform = 4 [(gogoproto.jsontag) = "device_platform"];
int64 device_build = 5 [(gogoproto.jsontag) = "device_build"];
string startTime = 6 [(gogoproto.jsontag) = "startTime"];
string endTime = 7 [(gogoproto.jsontag) = "endTime"];
int64 status = 8 [(gogoproto.jsontag) = "status"];
int64 device_limit =9 [(gogoproto.jsontag) = "device_limit"];
string imageUrl = 10 [(gogoproto.jsontag) = "imageUrl"];
int64 jumpPathType = 11 [(gogoproto.jsontag) = "jumpPathType"];
int64 jumpTime = 12 [(gogoproto.jsontag) = "jumpTime"];
string type = 13 [(gogoproto.jsontag) = "type"];
}
}
service Resource {
//Add 添加资源接口
rpc Add(AddReq) returns (AddResp);
//Add 添加资源接口(不限制位置和平台)
rpc AddEx(AddReq) returns (AddResp);
//Edit 编辑资源接口
rpc Edit(EditReq) returns (EditResp);
//Offline 下线资源接口
rpc Offline(OfflineReq) returns (OfflineResp);
//GetList 获取资源列表
rpc GetList(GetListReq) returns (GetListResp);
//获取平台列表
rpc GetPlatformList(GetPlatformListReq) returns (GetPlatformListResp);
//GetListEx 获取资源列表
rpc GetListEx(GetListExReq) returns (GetListExResp);
}
service Splash {
//获取有效闪屏配置
rpc GetInfo(GetInfoReq) returns (GetInfoResp);
}
service Banner {
//获取有效banner配置
rpc GetBlinkBanner(GetInfoReq) returns (GetInfoResp);
//获取有效banner配置
rpc GetBanner(GetBannerReq) returns (GetBannerResp);
}

View File

@@ -0,0 +1,216 @@
##Add 添加资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Add`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|title|是|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|type|是|string||
|device|是|string||
|startTime|是|string||
|endTime|是|string||
|imageUrl|是|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": [
0
]
}
}
```
##Add 添加资源接口(不限制位置和平台)
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/AddEx`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|title|是|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|type|是|string||
|device|是|string||
|startTime|是|string||
|endTime|是|string||
|imageUrl|是|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": [
0
]
}
}
```
##Edit 编辑资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Edit`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|id|是|integer||
|title|否|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|startTime|否|string||
|endTime|否|string||
|imageUrl|否|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```
##Offline 下线资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Offline`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|id|是|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```
##GetList 获取资源列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|page|否|integer||
|pageSize|否|integer||
|type|是|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"currentPage": 0,
"totalCount": 0,
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"device_platform": "",
"device_build": 0,
"startTime": "",
"endTime": "",
"status": 0,
"device_limit": 0,
"imageUrl": "",
"jumpPathType": 0,
"jumpTime": 0
}
]
}
}
```
##获取平台列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetPlatformList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|type|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"platform": [
""
]
}
}
```
##GetListEx 获取资源列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetListEx`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|page|否|integer||
|pageSize|否|integer||
|type|是|多个string||
|device_platform|否|string||
|status|否|string||
|startTime|否|string||
|endTime|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"currentPage": 0,
"totalCount": 0,
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"device_platform": "",
"device_build": 0,
"startTime": "",
"endTime": "",
"status": 0,
"device_limit": 0,
"imageUrl": "",
"jumpPathType": 0,
"jumpTime": 0,
"type": ""
}
]
}
}
```

View File

@@ -0,0 +1,26 @@
##获取有效闪屏配置
`GET http://api.live.bilibili.com/xlive/resource/v1/splash/GetInfo`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string||
|build|是|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
}
```

View File

@@ -0,0 +1,35 @@
package v1
import (
"context"
"google.golang.org/grpc"
"go-common/library/net/rpc/warden"
)
const AppID = "live.resource"
type Client struct {
ResourceClient
SplashClient
BannerClient
LiveCheckClient
TitansClient
}
// NewClient new resource 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.ResourceClient = NewResourceClient(conn)
cli.SplashClient = NewSplashClient(conn)
cli.BannerClient = NewBannerClient(conn)
cli.LiveCheckClient = NewLiveCheckClient(conn)
cli.TitansClient = NewTitansClient(conn)
return cli, nil
}

View File

@@ -0,0 +1,83 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/grpc/v1/livecheck.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/grpc/v1/livecheck.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
// ===================
// LiveCheck Interface
// ===================
type LiveCheck interface {
// 客户端获取能否直播接口
LiveCheck(ctx context.Context, req *LiveCheckReq) (resp *LiveCheckResp, err error)
// 后台查询所有配置设备黑名单
GetLiveCheckList(ctx context.Context, req *GetLiveCheckListReq) (resp *GetLiveCheckListResp, err error)
// 后台添加能否直播设备黑名单
AddLiveCheck(ctx context.Context, req *AddLiveCheckReq) (resp *AddLiveCheckResp, err error)
}
var v1LiveCheckSvc LiveCheck
// @params LiveCheckReq
// @router GET /xlive/resource/v1/liveCheck/LiveCheck
// @response LiveCheckResp
func liveCheckLiveCheck(c *bm.Context) {
p := new(LiveCheckReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1LiveCheckSvc.LiveCheck(c, p)
c.JSON(resp, err)
}
// @params GetLiveCheckListReq
// @router GET /xlive/resource/v1/liveCheck/GetLiveCheckList
// @response GetLiveCheckListResp
func liveCheckGetLiveCheckList(c *bm.Context) {
p := new(GetLiveCheckListReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1LiveCheckSvc.GetLiveCheckList(c, p)
c.JSON(resp, err)
}
// @params AddLiveCheckReq
// @router GET /xlive/resource/v1/liveCheck/AddLiveCheck
// @response AddLiveCheckResp
func liveCheckAddLiveCheck(c *bm.Context) {
p := new(AddLiveCheckReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1LiveCheckSvc.AddLiveCheck(c, p)
c.JSON(resp, err)
}
// RegisterV1LiveCheckService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1LiveCheckService(e *bm.Engine, svc LiveCheck, midMap map[string]bm.HandlerFunc) {
v1LiveCheckSvc = svc
e.GET("/xlive/resource/v1/liveCheck/LiveCheck", liveCheckLiveCheck)
e.GET("/xlive/resource/v1/liveCheck/GetLiveCheckList", liveCheckGetLiveCheckList)
e.GET("/xlive/resource/v1/liveCheck/AddLiveCheck", liveCheckAddLiveCheck)
}

View File

@@ -0,0 +1,81 @@
##客户端获取能否直播接口
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/LiveCheck`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|是|string| 平台|
|system|是|string| 操作系统|
|mobile|是|string| 设备|
```json
{
"code": 0,
"message": "ok",
"data": {
"is_live": 0
}
}
```
##后台查询所有配置设备黑名单
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/GetLiveCheckList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
```json
{
"code": 0,
"message": "ok",
"data": {
// android
"android": [
{
// os
"system": "",
// device
"mobile": [
""
]
}
],
// ios
"ios": [
{
// os
"system": "",
// device
"mobile": [
""
]
}
]
}
}
```
##后台添加能否直播设备黑名单
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/AddLiveCheck`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|live_check|是|string||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
syntax = "proto3";
package live.resource.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
//LiveCheck 移动端请求接口
message LiveCheckReq {
// 平台
string platform = 1 [(gogoproto.moretags) = 'form:"platform" validate:"required"'];
// 操作系统
string system = 2 [(gogoproto.moretags) = 'form:"system" validate:"required"'];
// 设备
string mobile = 3 [(gogoproto.moretags) = 'form:"mobile" validate:"required"'];
}
message LiveCheckResp {
int64 is_live = 1 [(gogoproto.jsontag) = "is_live"];
}
//提供给后台查询开播设备黑名单
message GetLiveCheckListReq {
}
message GetLiveCheckListResp {
// android
repeated Platform android = 1 [(gogoproto.jsontag) = "android"];
// ios
repeated Platform ios = 2 [(gogoproto.jsontag) = "ios"];
message Platform {
// os
string system = 1 [(gogoproto.jsontag) = "system"];
// device
repeated string mobile = 2 [(gogoproto.jsontag) = "mobile"];
}
}
//提供给后台新增live_check添加黑名单
message AddLiveCheckReq {
string live_check = 1 [(gogoproto.moretags) = 'form:"live_check" validate:"required"'];
}
message AddLiveCheckResp {
}
service LiveCheck {
//客户端获取能否直播接口
rpc LiveCheck (LiveCheckReq) returns (LiveCheckResp);
//后台查询所有配置设备黑名单
rpc GetLiveCheckList (GetLiveCheckListReq) returns (GetLiveCheckListResp);
//后台添加能否直播设备黑名单
rpc AddLiveCheck (AddLiveCheckReq) returns (AddLiveCheckResp);
}

View File

@@ -0,0 +1,115 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/grpc/v1/titans.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/grpc/v1/titans.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
// ================
// Titans Interface
// ================
type Titans interface {
// 获取team下某个keyword的配置 `internal:"true"`
GetConfigByKeyword(ctx context.Context, req *GetConfigReq) (resp *GetConfigResp, err error)
// 设置team下某个keyword配置 `internal:"true"`
SetConfigByKeyword(ctx context.Context, req *SetConfigReq) (resp *SetConfigResp, err error)
// 管理后台根据条件获取配置 `internal:"true"`
GetConfigsByParams(ctx context.Context, req *ParamsConfigReq) (resp *ParamsConfigResp, err error)
// 获取discover_id对应的全部配置 `internal:"true"`
GetByTreeId(ctx context.Context, req *TreeIdReq) (resp *TreeIdResp, err error)
// 获取多个team或索引的的全部配置 `internal:"true"`
GetConfigsByLikes(ctx context.Context, req *LikesConfigReq) (resp *LikesConfigResp, err error)
}
var v1TitansSvc Titans
// @params GetConfigReq
// @router GET /xlive/internal/resource/v1/titans/get_config_by_keyword
// @response GetConfigResp
func titansGetConfigByKeyword(c *bm.Context) {
p := new(GetConfigReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1TitansSvc.GetConfigByKeyword(c, p)
c.JSON(resp, err)
}
// @params SetConfigReq
// @router GET /xlive/internal/resource/v1/titans/set_config_by_keyword
// @response SetConfigResp
func titansSetConfigByKeyword(c *bm.Context) {
p := new(SetConfigReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1TitansSvc.SetConfigByKeyword(c, p)
c.JSON(resp, err)
}
// @params ParamsConfigReq
// @router GET /xlive/internal/resource/v1/titans/get_configs_by_params
// @response ParamsConfigResp
func titansGetConfigsByParams(c *bm.Context) {
p := new(ParamsConfigReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1TitansSvc.GetConfigsByParams(c, p)
c.JSON(resp, err)
}
// @params TreeIdReq
// @router GET /xlive/internal/resource/v1/titans/getByTreeId
// @response TreeIdResp
func titansGetByTreeId(c *bm.Context) {
p := new(TreeIdReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1TitansSvc.GetByTreeId(c, p)
c.JSON(resp, err)
}
// @params LikesConfigReq
// @router GET /xlive/internal/resource/v1/titans/get_configs_by_likes
// @response LikesConfigResp
func titansGetConfigsByLikes(c *bm.Context) {
p := new(LikesConfigReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v1TitansSvc.GetConfigsByLikes(c, p)
c.JSON(resp, err)
}
// RegisterV1TitansService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1TitansService(e *bm.Engine, svc Titans, midMap map[string]bm.HandlerFunc) {
v1TitansSvc = svc
e.GET("/xlive/internal/resource/v1/titans/get_config_by_keyword", titansGetConfigByKeyword)
e.GET("/xlive/internal/resource/v1/titans/set_config_by_keyword", titansSetConfigByKeyword)
e.GET("/xlive/internal/resource/v1/titans/get_configs_by_params", titansGetConfigsByParams)
e.GET("/xlive/internal/resource/v1/titans/getByTreeId", titansGetByTreeId)
e.GET("/xlive/internal/resource/v1/titans/get_configs_by_likes", titansGetConfigsByLikes)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
syntax = "proto3";
package live.resource.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
service titans {
//获取team下某个keyword的配置 `internal:"true"`
rpc get_config_by_keyword(GetConfigReq) returns (GetConfigResp);
//设置team下某个keyword配置 `internal:"true"`
rpc set_config_by_keyword(SetConfigReq) returns (SetConfigResp);
//管理后台根据条件获取配置 `internal:"true"`
rpc get_configs_by_params(ParamsConfigReq) returns (ParamsConfigResp);
//获取discover_id对应的全部配置 `internal:"true"`
rpc getByTreeId(TreeIdReq) returns (TreeIdResp);
//获取多个team或索引的的全部配置 `internal:"true"`
rpc get_configs_by_likes(LikesConfigReq) returns (LikesConfigResp);
}
message GetConfigReq {
//team
int64 team = 1 [(gogoproto.moretags) = 'form:"team"'];
//索引名称
string keyword = 2 [(gogoproto.moretags) = 'form:"keyword"'];
//id
int64 id = 3 [(gogoproto.moretags) = 'form:"id"'];
}
message GetConfigResp {
//team
int64 team = 1 [(gogoproto.jsontag) = "team"];
//索引名称
string keyword = 2 [(gogoproto.jsontag) = "keyword"];
//配置值
string value = 3 [(gogoproto.jsontag) = "value"];
//配置解释
string name = 4 [(gogoproto.jsontag) = "name"];
//创建时间
string ctime = 5 [(gogoproto.jsontag) = "ctime"];
//最近更新时间
string mtime = 6 [(gogoproto.jsontag) = "mtime"];
//状态
int64 status = 7 [(gogoproto.jsontag) = "status"];
//状态
int64 id = 8 [(gogoproto.jsontag) = "id"];
}
message SetConfigReq {
//team
int64 team = 1 [(gogoproto.moretags) = 'form:"team"'];
//索引名称
string keyword = 2 [(gogoproto.moretags) = 'form:"keyword" validate:"required"'];
//配置值
string value = 3 [(gogoproto.moretags) = 'form:"value" validate:"required"'];
//配置解释
string name = 4 [(gogoproto.moretags) = 'form:"name"'];
//编辑时id
int64 id = 5 [(gogoproto.moretags) = 'form:"id"'];
//记录状态 新增时默认为0
int64 status = 6 [(gogoproto.moretags) = 'form:"status"'];
}
message SetConfigResp {
int64 id = 1 [(gogoproto.jsontag) = "id"];
}
message ParamsConfigReq{
int64 team = 1 [(gogoproto.moretags) = 'form:"team"'];
string keyword = 2 [(gogoproto.moretags) = 'form:"keyword"'];
string name = 3 [(gogoproto.moretags) = 'form:"name"'];
int64 status = 4 [(gogoproto.moretags) = 'form:"status"'];
int64 page = 5 [(gogoproto.moretags) = 'form:"page" validate:"required"'];
//页量
int64 page_size = 6 [(gogoproto.moretags) = 'form:"page_size" validate:"required"'];
//id
int64 id = 7 [(gogoproto.moretags) = 'form:"id"'];
}
message ParamsConfigResp{
//数据列表
repeated List list = 1 [(gogoproto.jsontag) = "list"];
//记录总数
int64 total_num = 2 [(gogoproto.jsontag) = "total_num"];
}
message List {
//Id
int64 id = 1 [(gogoproto.jsontag) = "id"];
//team
int64 team = 2 [(gogoproto.jsontag) = "team"];
//索引名称
string keyword = 3 [(gogoproto.jsontag) = "keyword"];
//配置值
string value = 4 [(gogoproto.jsontag) = "value"];
//配置解释
string name = 5 [(gogoproto.jsontag) = "name"];
//创建时间
string ctime = 6 [(gogoproto.jsontag) = "ctime"];
//最近更新时间
string mtime = 7 [(gogoproto.jsontag) = "mtime"];
//状态
int64 status = 8 [(gogoproto.jsontag) = "status"];
}
message LikesConfigReq{
repeated string params = 1 [(gogoproto.moretags) = 'form:"params" validate:"required"'];
}
message LikesConfigResp{
map<int64, Child> list = 1 [(gogoproto.jsontag) = "list"];
}
message Child {
map<string, string> keys = 1 [(gogoproto.jsontag) = "keys"];
}
message TreeIdReq{
int64 tree_id = 1 [(gogoproto.moretags) = 'form:"tree_id" validate:"required"'];
}
message TreeIdResp{
map<string, string> list = 1 [(gogoproto.jsontag) = "list"];
}

View File

@@ -0,0 +1,158 @@
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/get_config_by_keyword`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|team|否|integer|team|
|keyword|否|string|索引名称|
|id|否|integer|id|
```json
{
"code": 0,
"message": "ok",
"data": {
// team
"team": 0,
// 索引名称
"keyword": "",
// 配置值
"value": "",
// 配置解释
"name": "",
// 创建时间
"ctime": "",
// 最近更新时间
"mtime": "",
// 状态
"status": 0,
// 状态
"id": 0
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/set_config_by_keyword`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|team|否|integer|team|
|keyword|是|string|索引名称|
|value|是|string|配置值|
|name|否|string|配置解释|
|id|否|integer|编辑时id|
|status|否|integer|记录状态 新增时默认为0|
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/get_configs_by_params`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|team|否|integer||
|keyword|否|string||
|name|否|string||
|status|否|integer||
|page|是|integer||
|page_size|是|integer|页量|
|id|否|integer|id|
```json
{
"code": 0,
"message": "ok",
"data": {
// 数据列表
"list": [
{
// Id
"id": 0,
// team
"team": 0,
// 索引名称
"keyword": "",
// 配置值
"value": "",
// 配置解释
"name": "",
// 创建时间
"ctime": "",
// 最近更新时间
"mtime": "",
// 状态
"status": 0
}
],
// 记录总数
"total_num": 0
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getByTreeId`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|tree_id|是|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": {
"mapKey": ""
}
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/get_configs_by_likes`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|params|是|多个string||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": {
"1": {
"keys": {
"mapKey": ""
}
}
}
}
}
```

View File

@@ -0,0 +1,61 @@
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 = "v2_proto",
srcs = ["user_resource.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v2_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/live/resource/api/grpc/v2",
proto = ":v2_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"client.go",
"user_resource.bm.go",
],
embed = [":v2_go_proto"],
importpath = "go-common/app/service/live/resource/api/grpc/v2",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster: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,29 @@
package v2
import (
"context"
"google.golang.org/grpc"
"go-common/library/net/rpc/warden"
)
// AppID 应用程序标识
const AppID = "live.resource"
// Client 对外服务接口
type Client struct {
UserResourceClient
}
// NewClient 用户资源 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.UserResourceClient = NewUserResourceClient(conn)
return cli, nil
}

View File

@@ -0,0 +1,115 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/grpc/v2/user_resource.proto
/*
Package v2 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/grpc/v2/user_resource.proto
*/
package v2
import (
"context"
bm "go-common/library/net/http/blademaster"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
// ======================
// UserResource Interface
// ======================
type UserResource interface {
// Add 添加资源接口
Add(ctx context.Context, req *AddReq) (resp *AddResp, err error)
// Edit 编辑现有资源
Edit(ctx context.Context, req *EditReq) (resp *EditResp, err error)
// Query 请求单个资源
Query(ctx context.Context, req *QueryReq) (resp *QueryResp, err error)
// List 获取资源列表
List(ctx context.Context, req *ListReq) (resp *ListResp, err error)
// SetStatus 更改资源状态
SetStatus(ctx context.Context, req *SetStatusReq) (resp *SetStatusResp, err error)
}
var v2UserResourceSvc UserResource
// @params AddReq
// @router GET /xlive/resource/v2/userResource/Add
// @response AddResp
func userResourceAdd(c *bm.Context) {
p := new(AddReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v2UserResourceSvc.Add(c, p)
c.JSON(resp, err)
}
// @params EditReq
// @router GET /xlive/resource/v2/userResource/Edit
// @response EditResp
func userResourceEdit(c *bm.Context) {
p := new(EditReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v2UserResourceSvc.Edit(c, p)
c.JSON(resp, err)
}
// @params QueryReq
// @router GET /xlive/resource/v2/userResource/Query
// @response QueryResp
func userResourceQuery(c *bm.Context) {
p := new(QueryReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v2UserResourceSvc.Query(c, p)
c.JSON(resp, err)
}
// @params ListReq
// @router GET /xlive/resource/v2/userResource/List
// @response ListResp
func userResourceList(c *bm.Context) {
p := new(ListReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v2UserResourceSvc.List(c, p)
c.JSON(resp, err)
}
// @params SetStatusReq
// @router GET /xlive/resource/v2/userResource/SetStatus
// @response SetStatusResp
func userResourceSetStatus(c *bm.Context) {
p := new(SetStatusReq)
if err := c.Bind(p); err != nil {
return
}
resp, err := v2UserResourceSvc.SetStatus(c, p)
c.JSON(resp, err)
}
// RegisterV2UserResourceService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV2UserResourceService(e *bm.Engine, svc UserResource, midMap map[string]bm.HandlerFunc) {
v2UserResourceSvc = svc
e.GET("/xlive/resource/v2/userResource/Add", userResourceAdd)
e.GET("/xlive/resource/v2/userResource/Edit", userResourceEdit)
e.GET("/xlive/resource/v2/userResource/Query", userResourceQuery)
e.GET("/xlive/resource/v2/userResource/List", userResourceList)
e.GET("/xlive/resource/v2/userResource/SetStatus", userResourceSetStatus)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
syntax = "proto3";
package live.resource.v2;
option go_package = "v2";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// 请求创建资源
message AddReq {
//资源类型
int32 res_type = 1 [(gogoproto.moretags) = 'form:"res_type" validate:"required"'];
//名称
string title = 2 [(gogoproto.moretags) = 'form:"title" validate:"required"'];
//URL
string url = 3 [(gogoproto.moretags) = 'form:"url" validate:"required"'];
//权重
int32 weight = 4 [(gogoproto.moretags) = 'form:"weight" validate:"required"'];
//创建人
string creator = 5 [(gogoproto.moretags) = 'form:"creator" validate:"required"'];
}
// 返回创建结果
message AddResp {
//ID
int32 id = 1 [(gogoproto.jsontag) = "id"];
//资源类型
int32 res_type = 2 [(gogoproto.jsontag) = "res_type"];
//资源ID
int32 custom_id = 3 [(gogoproto.jsontag) = "custom_id"];
//名称
string title = 4 [(gogoproto.jsontag) = "title"];
//URL
string url = 5 [(gogoproto.jsontag) = "url"];
//权重
int32 weight = 6 [(gogoproto.jsontag) = "weight"];
//创建人
string creator = 7 [(gogoproto.jsontag) = "creator"];
//"状态1.上线中2.下线"
int32 status = 8 [(gogoproto.jsontag) = "status"];
//创建时刻
string ctime = 9 [(gogoproto.jsontag) = "ctime"];
//修改时刻
string mtime = 10 [(gogoproto.jsontag) = "mtime"];
}
// 请求编辑资源
message EditReq {
//资源类型
int32 res_type = 1 [(gogoproto.moretags) = 'form:"res_type" validate:"required"'];
//资源ID
int32 custom_id = 2 [(gogoproto.moretags) = 'form:"custom_id" validate:"required"'];
//名称
string title = 3 [(gogoproto.moretags) = 'form:"title"'];
//URL
string url = 4 [(gogoproto.moretags) = 'form:"url"'];
//权重
int32 weight = 5 [(gogoproto.moretags) = 'form:"weight"'];
}
// 返回编辑结果
message EditResp {
//ID
int32 id = 1 [(gogoproto.jsontag) = "id"];
//资源类型
int32 res_type = 2 [(gogoproto.jsontag) = "res_type"];
//资源ID
int32 custom_id = 3 [(gogoproto.jsontag) = "custom_id"];
//名称
string title = 4 [(gogoproto.jsontag) = "title"];
//URL
string url = 5 [(gogoproto.jsontag) = "url"];
//权重
int32 weight = 6 [(gogoproto.jsontag) = "weight"];
//创建人
string creator = 7 [(gogoproto.jsontag) = "creator"];
//"状态1.上线中2.下线"
int32 status = 8 [(gogoproto.jsontag) = "status"];
//创建时刻
string ctime = 9 [(gogoproto.jsontag) = "ctime"];
//修改时刻
string mtime = 10 [(gogoproto.jsontag) = "mtime"];
}
// 请求单个资源
message QueryReq {
//资源类型
int32 res_type = 1 [(gogoproto.moretags) = 'form:"res_type" validate:"required"'];
//资源ID
int32 custom_id = 2 [(gogoproto.moretags) = 'form:"custom_id" validate:"required"'];
}
// 返回单个资源
message QueryResp {
//ID
int32 id = 1 [(gogoproto.jsontag) = "id"];
//资源类型
int32 res_type = 2 [(gogoproto.jsontag) = "res_type"];
//资源ID
int32 custom_id = 3 [(gogoproto.jsontag) = "custom_id"];
//名称
string title = 4 [(gogoproto.jsontag) = "title"];
//URL
string url = 5 [(gogoproto.jsontag) = "url"];
//权重
int32 weight = 6 [(gogoproto.jsontag) = "weight"];
//创建人
string creator = 7 [(gogoproto.jsontag) = "creator"];
//"状态1.上线中2.下线"
int32 status = 8 [(gogoproto.jsontag) = "status"];
//创建时刻
string ctime = 9 [(gogoproto.jsontag) = "ctime"];
//修改时刻
string mtime = 10 [(gogoproto.jsontag) = "mtime"];
}
// 请求资源列表
message ListReq {
//资源类型
int32 res_type = 1 [(gogoproto.moretags) = 'form:"res_type" validate:"required"'];
//页码
int32 page = 2 [(gogoproto.moretags) = 'form:"page"'];
//每页数据量
int32 page_size = 3 [(gogoproto.moretags) = 'form:"page_size"'];
}
// 返回资源列表
message ListResp {
int32 currentPage = 1 [(gogoproto.jsontag) = "currentPage"];
int32 totalCount = 2 [(gogoproto.jsontag) = "totalCount"];
repeated List list = 3 [(gogoproto.jsontag) = "list"];
message List {
//ID
int32 id = 1 [(gogoproto.jsontag) = "id"];
//资源类型
int32 res_type = 2 [(gogoproto.jsontag) = "res_type"];
//资源ID
int32 custom_id = 3 [(gogoproto.jsontag) = "custom_id"];
//名称
string title = 4 [(gogoproto.jsontag) = "title"];
//URL
string url = 5 [(gogoproto.jsontag) = "url"];
//权重
int32 weight = 6 [(gogoproto.jsontag) = "weight"];
//创建人
string creator = 7 [(gogoproto.jsontag) = "creator"];
//"状态1.上线中2.下线"
int32 status = 8 [(gogoproto.jsontag) = "status"];
//创建时刻
string ctime = 9 [(gogoproto.jsontag) = "ctime"];
//修改时刻
string mtime = 10 [(gogoproto.jsontag) = "mtime"];
}
}
// 请求变更资源状态
message SetStatusReq {
//资源类型
int32 res_type = 1 [(gogoproto.moretags) = 'form:"res_type" validate:"required"'];
//页码
int32 custom_id = 2 [(gogoproto.moretags) = 'form:"custom_id" validate:"required"'];
//每页数据量
int32 status = 3 [(gogoproto.moretags) = 'form:"status" validate:"required"'];
}
// 返回变更结果
message SetStatusResp {
}
service UserResource {
//Add 添加资源接口
rpc Add(AddReq) returns (AddResp);
//Edit 编辑现有资源
rpc Edit(EditReq) returns (EditResp);
//Query 请求单个资源
rpc Query(QueryReq) returns (QueryResp);
//List 获取资源列表
rpc List(ListReq) returns (ListResp);
//SetStatus 更改资源状态
rpc SetStatus(SetStatusReq) returns (SetStatusResp);
}

View File

@@ -0,0 +1,194 @@
##Add 添加资源接口
`GET http://api.live.bilibili.com/xlive/resource/v2/userResource/Add`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|res_type|是|integer|资源类型|
|title|是|string|名称|
|url|是|string|URL|
|weight|是|integer|权重|
|creator|是|string|创建人|
```json
{
"code": 0,
"message": "ok",
"data": {
// ID
"id": 0,
// 资源类型
"res_type": 0,
// 资源ID
"custom_id": 0,
// 名称
"title": "",
// URL
"url": "",
// 权重
"weight": 0,
// 创建人
"creator": "",
// "状态1.上线中2.下线"
"status": 0,
// 创建时刻
"ctime": "",
// 修改时刻
"mtime": ""
}
}
```
##Edit 编辑现有资源
`GET http://api.live.bilibili.com/xlive/resource/v2/userResource/Edit`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|res_type|是|integer|资源类型|
|custom_id|是|integer|资源ID|
|title|否|string|名称|
|url|否|string|URL|
|weight|否|integer|权重|
```json
{
"code": 0,
"message": "ok",
"data": {
// ID
"id": 0,
// 资源类型
"res_type": 0,
// 资源ID
"custom_id": 0,
// 名称
"title": "",
// URL
"url": "",
// 权重
"weight": 0,
// 创建人
"creator": "",
// "状态1.上线中2.下线"
"status": 0,
// 创建时刻
"ctime": "",
// 修改时刻
"mtime": ""
}
}
```
##Query 请求单个资源
`GET http://api.live.bilibili.com/xlive/resource/v2/userResource/Query`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|res_type|是|integer|资源类型|
|custom_id|是|integer|资源ID|
```json
{
"code": 0,
"message": "ok",
"data": {
// ID
"id": 0,
// 资源类型
"res_type": 0,
// 资源ID
"custom_id": 0,
// 名称
"title": "",
// URL
"url": "",
// 权重
"weight": 0,
// 创建人
"creator": "",
// "状态1.上线中2.下线"
"status": 0,
// 创建时刻
"ctime": "",
// 修改时刻
"mtime": ""
}
}
```
##List 获取资源列表
`GET http://api.live.bilibili.com/xlive/resource/v2/userResource/List`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|res_type|是|integer|资源类型|
|page|否|integer|页码|
|page_size|否|integer|每页数据量|
```json
{
"code": 0,
"message": "ok",
"data": {
"currentPage": 0,
"totalCount": 0,
"list": [
{
// ID
"id": 0,
// 资源类型
"res_type": 0,
// 资源ID
"custom_id": 0,
// 名称
"title": "",
// URL
"url": "",
// 权重
"weight": 0,
// 创建人
"creator": "",
// "状态1.上线中2.下线"
"status": 0,
// 创建时刻
"ctime": "",
// 修改时刻
"mtime": ""
}
]
}
}
```
##SetStatus 更改资源状态
`GET http://api.live.bilibili.com/xlive/resource/v2/userResource/SetStatus`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|res_type|是|integer|资源类型|
|custom_id|是|integer|页码|
|status|是|integer|每页数据量|
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

View File

@@ -0,0 +1 @@
# HTTP API文档

View File

@@ -0,0 +1,56 @@
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 = ["titans.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/resource/api/http/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["titans.bm.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/live/resource/api/http/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,57 @@
##获取有效banner配置
`GET http://api.live.bilibili.com/xlive/resource/v1/banner/GetBlinkBanner`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|build|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
}
```
##获取有效banner配置
`GET http://api.live.bilibili.com/xlive/resource/v1/banner/GetBanner`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|build|否|integer||
|type|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
]
}
}
```

View File

@@ -0,0 +1,27 @@
##Add 添加资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/history/Add`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|splashContent|否|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|type|否|integer||
|device|否|string||
|startTime|否|string||
|endTime|否|string||
|imageUrl|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

View File

@@ -0,0 +1,81 @@
##客户端获取能否直播接口
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/LiveCheck`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string| 平台|
|system|否|string| 操作系统|
|mobile|否|string| 设备|
```json
{
"code": 0,
"message": "ok",
"data": {
"is_live": 0
}
}
```
##后台查询所有配置设备黑名单
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/GetLiveCheckList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
```json
{
"code": 0,
"message": "ok",
"data": {
// android
"android": [
{
// os
"system": "",
// device
"mobile": [
""
]
}
],
// ios
"ios": [
{
// os
"system": "",
// device
"mobile": [
""
]
}
]
}
}
```
##后台添加能否直播设备黑名单
`GET http://api.live.bilibili.com/xlive/resource/v1/liveCheck/AddLiveCheck`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|live_check|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

View File

@@ -0,0 +1,216 @@
##Add 添加资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Add`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|title|否|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|type|否|string||
|device|否|string||
|startTime|否|string||
|endTime|否|string||
|imageUrl|否|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": [
0
]
}
}
```
##Add 添加资源接口(不限制位置和平台)
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/AddEx`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|title|否|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|type|否|string||
|device|否|string||
|startTime|否|string||
|endTime|否|string||
|imageUrl|否|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": [
0
]
}
}
```
##Edit 编辑资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Edit`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|id|否|integer||
|title|否|string||
|jumpPath|否|string||
|jumpTime|否|integer||
|startTime|否|string||
|endTime|否|string||
|imageUrl|否|string||
|jumpPathType|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```
##Offline 下线资源接口
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/Offline`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|id|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```
##GetList 获取资源列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|page|否|integer||
|pageSize|否|integer||
|type|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"currentPage": 0,
"totalCount": 0,
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"device_platform": "",
"device_build": 0,
"startTime": "",
"endTime": "",
"status": 0,
"device_limit": 0,
"imageUrl": "",
"jumpPathType": 0,
"jumpTime": 0
}
]
}
}
```
##获取平台列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetPlatformList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|type|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"platform": [
""
]
}
}
```
##GetListEx 获取资源列表
`GET http://api.live.bilibili.com/xlive/resource/v1/resource/GetListEx`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|page|否|integer||
|pageSize|否|integer||
|type|否|多个string||
|device_platform|否|string||
|status|否|string||
|startTime|否|string||
|endTime|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"currentPage": 0,
"totalCount": 0,
"list": [
{
"id": 0,
"title": "",
"jumpPath": "",
"device_platform": "",
"device_build": 0,
"startTime": "",
"endTime": "",
"status": 0,
"device_limit": 0,
"imageUrl": "",
"jumpPathType": 0,
"jumpTime": 0,
"type": ""
}
]
}
}
```

View File

@@ -0,0 +1,26 @@
##获取有效闪屏配置
`GET http://api.live.bilibili.com/xlive/resource/v1/splash/GetInfo`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|platform|否|string||
|build|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0,
"title": "",
"jumpPath": "",
"jumpTime": 0,
"jumpPathType": 0,
"imageUrl": ""
}
}
```

View File

@@ -0,0 +1,149 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/http/v1/titans.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/http/v1/titans.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
// ================
// Titans Interface
// ================
type Titans interface {
// 获取配置 请求参数逗号隔开的字符串 返回`internal:"true"`
GetMultiConfigs(ctx context.Context, req *MultiConfigReq) (resp *MultiConfigResp, err error)
// 获取服务级配置 `internal:"true"`
GetServiceConfig(ctx context.Context, req *ServiceConfigReq) (resp *ServiceConfigResp, err error)
// 插入服务配置 `method:"POST" internal:"true"`
SetServiceConfig(ctx context.Context, req *SetReq) (resp *SetResp, err error)
// 获取服务级配置 `internal:"true"`
GetServiceConfigList(ctx context.Context, req *ServiceListReq) (resp *ServiceListResp, err error)
// 获取已配置的discoveryId `internal:"true"`
GetTreeIds(ctx context.Context, req *TreeIdsReq) (resp *TreeIdsResp, err error)
// 获取运营数据列表 `internal:"true"`
GetEasyList(ctx context.Context, req *EasyGetReq) (resp *EasyGetResp, err error)
// 设置运营列表 `method:"POST" internal:"true"`
SetEasyList(ctx context.Context, req *EasySetReq) (resp *EasySetResp, err error)
}
var v1TitansSvc Titans
// @params MultiConfigReq
// @router GET /xlive/internal/resource/v1/titans/getMultiConfigs
// @response MultiConfigResp
func titansGetMultiConfigs(c *bm.Context) {
p := new(MultiConfigReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.GetMultiConfigs(c, p)
c.JSON(resp, err)
}
// @params ServiceConfigReq
// @router GET /xlive/internal/resource/v1/titans/getServiceConfig
// @response ServiceConfigResp
func titansGetServiceConfig(c *bm.Context) {
p := new(ServiceConfigReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.GetServiceConfig(c, p)
c.JSON(resp, err)
}
// @params SetReq
// @router POST /xlive/internal/resource/v1/titans/setServiceConfig
// @response SetResp
func titansSetServiceConfig(c *bm.Context) {
p := new(SetReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.SetServiceConfig(c, p)
c.JSON(resp, err)
}
// @params ServiceListReq
// @router GET /xlive/internal/resource/v1/titans/getServiceConfigList
// @response ServiceListResp
func titansGetServiceConfigList(c *bm.Context) {
p := new(ServiceListReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.GetServiceConfigList(c, p)
c.JSON(resp, err)
}
// @params TreeIdsReq
// @router GET /xlive/internal/resource/v1/titans/getTreeIds
// @response TreeIdsResp
func titansGetTreeIds(c *bm.Context) {
p := new(TreeIdsReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.GetTreeIds(c, p)
c.JSON(resp, err)
}
// @params EasyGetReq
// @router GET /xlive/internal/resource/v1/titans/getEasyList
// @response EasyGetResp
func titansGetEasyList(c *bm.Context) {
p := new(EasyGetReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.GetEasyList(c, p)
c.JSON(resp, err)
}
// @params EasySetReq
// @router POST /xlive/internal/resource/v1/titans/setEasyList
// @response EasySetResp
func titansSetEasyList(c *bm.Context) {
p := new(EasySetReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1TitansSvc.SetEasyList(c, p)
c.JSON(resp, err)
}
// RegisterV1TitansService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1TitansService(e *bm.Engine, svc Titans, midMap map[string]bm.HandlerFunc) {
v1TitansSvc = svc
e.GET("/xlive/internal/resource/v1/titans/getMultiConfigs", titansGetMultiConfigs)
e.GET("/xlive/internal/resource/v1/titans/getServiceConfig", titansGetServiceConfig)
e.POST("/xlive/internal/resource/v1/titans/setServiceConfig", titansSetServiceConfig)
e.GET("/xlive/internal/resource/v1/titans/getServiceConfigList", titansGetServiceConfigList)
e.GET("/xlive/internal/resource/v1/titans/getTreeIds", titansGetTreeIds)
e.GET("/xlive/internal/resource/v1/titans/getEasyList", titansGetEasyList)
e.POST("/xlive/internal/resource/v1/titans/setEasyList", titansSetEasyList)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
syntax = "proto3";
package live.resource.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
service titans {
// 获取配置 请求参数逗号隔开的字符串 返回`internal:"true"`
rpc getMultiConfigs(MultiConfigReq) returns (MultiConfigResp);
// 获取服务级配置 `internal:"true"`
rpc getServiceConfig(ServiceConfigReq) returns (ServiceConfigResp);
//插入服务配置 `method:"POST" internal:"true"`
rpc setServiceConfig(SetReq) returns (SetResp);
// 获取服务级配置 `internal:"true"`
rpc getServiceConfigList(ServiceListReq) returns (ServiceListResp);
// 获取已配置的discoveryId `internal:"true"`
rpc getTreeIds(TreeIdsReq) returns (TreeIdsResp);
// 获取用户的应用树 `internal:"true"`
//rpc getMyTreeApps(TreeAppsReq) returns (TreeAppsResp);
// 获取运营数据列表 `internal:"true"`
rpc getEasyList(EasyGetReq) returns (EasyGetResp);
// 设置运营列表 `method:"POST" internal:"true"`
rpc setEasyList(EasySetReq) returns (EasySetResp);
}
message EasyGetReq{
int64 id = 1 [(gogoproto.moretags) = 'form:"id"'];
int64 page = 2 [(gogoproto.moretags) = 'form:"page"'];
}
message EasyGetResp{
repeated EasyList list = 1 [(gogoproto.jsontag) = "list"];
}
message EasyList{
string tree_name = 1 [(gogoproto.jsontag) = "tree_name"];
string tree_path = 2 [(gogoproto.jsontag) = "tree_path"];
int64 tree_id = 3 [(gogoproto.jsontag) = "tree_id"];
string keyword = 4 [(gogoproto.jsontag) = "keyword"];
string name = 5 [(gogoproto.jsontag) = "name"];
}
message EasySetReq{
int64 id = 1 [(gogoproto.moretags) = 'form:"id"'];
}
message EasySetResp{
int64 eId = 1 [(gogoproto.jsontag) = "eId"];
}
message TreeAppsReq{
string node = 1 [(gogoproto.moretags) = 'form:"node"'];
string team = 2 [(gogoproto.moretags) = 'form:"team"'];
}
message TreeAppsResp{
repeated Node list = 1 [(gogoproto.jsontag) = "list"];
}
message Node{
string name = 1 [(gogoproto.jsontag) = "name"];
string path = 2 [(gogoproto.jsontag) = "path"];
int64 tree_id = 3 [(gogoproto.jsontag) = "tree_id"];
}
message MultiConfigReq{
string values = 1 [(gogoproto.moretags) = 'form:"values"'];
}
message MultiConfigResp{
map<int64, mChild> list = 1 [(gogoproto.jsontag) = "list"];
}
message mChild {
map<string, string> keys = 1 [(gogoproto.jsontag) = "keys"];
}
message ServiceConfigReq {
int64 tree_id = 1 [(gogoproto.moretags) = 'form:"tree_id"'];
}
message ServiceConfigResp{
map<string, string> list = 1 [(gogoproto.jsontag) = "list"];
}
message SetReq {
string tree_name = 1 [(gogoproto.moretags) = 'form:"tree_name" required'];
string tree_path = 2 [(gogoproto.moretags) = 'form:"tree_path"'];
int64 tree_id = 3 [(gogoproto.moretags) = 'form:"tree_id" required'];
string service = 4 [(gogoproto.moretags) = 'form:"service"'];
string keyword = 5 [(gogoproto.moretags) = 'form:"keyword"'];
int64 template = 6 [(gogoproto.moretags) = 'form:"template"'];
string name = 7 [(gogoproto.moretags) = 'form:"name"'];
string value = 8 [(gogoproto.moretags) = 'form:"value"'];
int64 status = 9 [(gogoproto.moretags) = 'form:"status"'];
int64 id = 10 [(gogoproto.moretags) = 'form:"id"'];
}
message SetResp {
int64 id = 1 [(gogoproto.jsontag) = "id"];
}
message ServiceListReq{
string tree_name = 1 [(gogoproto.moretags) = 'form:"tree_name" required'];
int64 tree_id = 2 [(gogoproto.moretags) = 'form:"tree_id"'];
string service = 3 [(gogoproto.moretags) = 'form:"service"'];
string keyword = 4 [(gogoproto.moretags) = 'form:"keyword"'];
int64 page = 5 [(gogoproto.moretags) = 'form:"page"'];
int64 page_size = 6 [(gogoproto.moretags) = 'form:"page_size"'];
string name = 7 [(gogoproto.moretags) = 'form:"name"'];
int64 status = 8 [(gogoproto.moretags) = 'form:"status"'];
}
message ServiceListResp{
repeated mList list = 1 [(gogoproto.jsontag) = "list"];
int64 total_num = 2 [(gogoproto.jsontag) = "total_num"];
}
message mList {
//Id
int64 id = 1 [(gogoproto.jsontag) = "id"];
//tree_name
string tree_name = 2 [(gogoproto.jsontag) = "tree_name"];
string tree_path = 3 [(gogoproto.jsontag) = "tree_path"];
int64 tree_id = 4 [(gogoproto.jsontag) = "tree_id"];
string service = 5 [(gogoproto.jsontag) = "service"];
//索引名称
int64 template = 6 [(gogoproto.jsontag) = "template"];
string keyword = 7 [(gogoproto.jsontag) = "keyword"];
//配置值
string value = 8 [(gogoproto.jsontag) = "value"];
//配置解释
string name = 9 [(gogoproto.jsontag) = "name"];
//创建时间
string ctime = 10 [(gogoproto.jsontag) = "ctime"];
//最近更新时间
string mtime = 11 [(gogoproto.jsontag) = "mtime"];
//状态
int64 status = 12 [(gogoproto.jsontag) = "status"];
}
message TreeIdsReq {
string tree_name = 1 [(gogoproto.moretags) = 'form:"tree_name" required'];
}
message TreeIdsResp{
repeated int64 list = 1 [(gogoproto.jsontag) = "list"];
}

View File

@@ -0,0 +1,199 @@
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getMultiConfigs`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|values|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": {
"1": {
"keys": {
"mapKey": ""
}
}
}
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getServiceConfig`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|tree_id|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": {
"mapKey": ""
}
}
}
```
##
`POST http://api.live.bilibili.com/xlive/internal/resource/v1/titans/setServiceConfig`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|tree_name|否|string||
|tree_path|否|string||
|tree_id|否|integer||
|service|否|string||
|keyword|否|string||
|template|否|integer||
|name|否|string||
|value|否|string||
|status|否|integer||
|id|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"id": 0
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getServiceConfigList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|tree_name|否|string||
|tree_id|否|integer||
|service|否|string||
|keyword|否|string||
|page|否|integer||
|page_size|否|integer||
|name|否|string||
|status|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
// Id
"id": 0,
// tree_name
"tree_name": "",
"tree_path": "",
"tree_id": 0,
"service": "",
// 索引名称
"template": 0,
"keyword": "",
// 配置值
"value": "",
// 配置解释
"name": "",
// 创建时间
"ctime": "",
// 最近更新时间
"mtime": "",
// 状态
"status": 0
}
],
"total_num": 0
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getTreeIds`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|tree_name|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": [
0
]
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/resource/v1/titans/getEasyList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|id|否|integer||
|page|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
"tree_name": "",
"tree_path": "",
"tree_id": 0,
"keyword": "",
"name": ""
}
]
}
}
```
##
`POST http://api.live.bilibili.com/xlive/internal/resource/v1/titans/setEasyList`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|id|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
"eId": 0
}
}
```

View File

@@ -0,0 +1,48 @@
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 = [
"local.toml",
"test.toml",
],
importpath = "go-common/app/service/live/resource/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/server/grpc:go_default_library",
"//app/service/live/resource/server/http:go_default_library",
"//app/service/live/resource/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,38 @@
[mysql]
addr = "127.0.0.1:3306"
dsn = "root:123456@tcp(127.0.0.1:3306)/live_resource?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["root:123456@tcp(127.0.0.1:3306)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4","root:123456@tcp(127.0.0.1:3306)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[memcache]
name = "app.service/resource"
proto = "tcp"
addr = "127.0.0.1:11211"
idle = 10
active = 10
dialTimeout = "2s"
readTimeout = "2s"
writeTimeout = "2s"
idleTimeout = "7h"
expire = "24h"
confKvExpire = "24h"
[db]
[db.resource]
dsn = "root:123456@tcp(127.0.0.1:3306)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout = "4h"
# 从库
[db.resourceReader]
dsn = "root:123456@tcp(127.0.0.1:3306)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout = "4h"

View File

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

View File

@@ -0,0 +1,38 @@
[mysql]
addr = "172.22.34.101:3312"
dsn = "livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live_resource?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4","livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db]
[db.resource]
dsn = "livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout = "4h"
# 从库
[db.resourceReader]
dsn = "livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live_resource?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout = "4h"
[httpClient]
Key = "aaa"
Secret = "test"
Dial = "1s"
Timeout = "500ms"
KeepAlive = "5s"
[Breaker]
[URL]
[Host]
[log]
stdout = true

View File

@@ -0,0 +1,42 @@
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/resource/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/orm: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/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,109 @@
package conf
import (
"errors"
"flag"
"go-common/library/database/orm"
"go-common/library/cache/memcache"
"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/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
Redis *redis.Config
Memcache *Memcache
MySQL *sql.Config
Ecode *ecode.Config
DB *DB
CacheBucket int
CacheCapacity int
CacheTimeout int64
CacheInstCnt int
HttpClient *bm.ClientConfig
}
// Memcache struct
type Memcache struct {
*memcache.Config
ConfKvExpire time.Duration
}
// DB conf.
type DB struct {
Resource *orm.Config
ResourceReader *orm.Config
}
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,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"confkv.go",
"dao.go",
"resource.go",
"titans.go",
"tree.go",
"user_resource.go",
],
importpath = "go-common/app/service/live/resource/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/grpc/v1:go_default_library",
"//app/service/live/resource/api/http/v1:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/lrucache:go_default_library",
"//app/service/live/resource/model:go_default_library",
"//library/database/orm:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/siddontang/go-mysql/mysql: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,141 @@
package dao
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_findConfkvSQL = "SELECT `value` FROM `confkv` WHERE `key` = ?"
_addConfkvSQL = "INSERT INTO `confkv` (`key`,`value`) VALUES (?,?)"
_updateConfkvSQL = "UPDATE `confkv` SET `value`=? WHERE `key`=?"
)
const (
_confLiveCheck = "live_check"
_platformAndroid = "android"
_platformIos = "ios"
)
// GetLiveCheck live.app-interface call
// cache -> db
func (d *Dao) GetLiveCheck(c context.Context, platform, system, mobile string) (isLive int64) {
isLive = int64(1)
inst := 0
res, ok := d.sCache[inst].Get(cacheLiveCheckKey(platform, system, mobile))
if !ok {
value, err := d.ConfKv(c, _confLiveCheck)
if err != nil {
log.Error("[LiveCheck] get live check error by from source")
return
}
if value == "" {
log.Error("[LiveCheck] get live check error by source data empty")
return
}
list := &v1pb.GetLiveCheckListResp{}
err = json.Unmarshal([]byte(value), list)
if err != nil {
log.Error("[LiveCheck] get live check error by source data wrong format")
return
}
log.Info("[LiveCheck] live_check list is %v", list)
switch platform {
case _platformAndroid:
for _, v := range list.Android {
if v.System == system {
for _, m := range v.Mobile {
if m == mobile {
isLive = int64(0)
}
}
}
}
case _platformIos:
for _, v := range list.Ios {
if v.System == system {
for _, m := range v.Mobile {
log.Info("[LiveCheck] range m %v mobile %v", m, mobile)
if m == mobile {
isLive = int64(0)
}
}
}
}
}
d.sCache[inst].Put(cacheLiveCheckKey(platform, system, mobile), isLive)
return
}
isLive = res.(int64)
return
}
// ConfKv get data from cache if miss will call source method, then add to cache.
func (d *Dao) ConfKv(c context.Context, key string) (value string, err error) {
inst := 0
res, ok := d.sCache[inst].Get(cacheConfKey(key))
if !ok {
log.Info("[LiveCheck] conf cache miss")
value, err = d.RawConfKv(c, key)
if err != nil {
return
}
d.sCache[inst].Put(cacheConfKey(key), value)
return
}
log.Info("[LiveCheck] conf cache hit")
value = res.(string)
return
}
// SetLiveCheck set live_check conf
func (d *Dao) SetLiveCheck(c context.Context, value string) (err error) {
err = d.AddOrUpdateConfKv(c, _confLiveCheck, value)
return
}
// GetLiveCheckList get live_check conf
func (d *Dao) GetLiveCheckList(c context.Context) (value string, err error) {
value, err = d.RawConfKv(c, _confLiveCheck)
return
}
// RawConfKv get conf
func (d *Dao) RawConfKv(c context.Context, key string) (value string, err error) {
row := d.db.QueryRow(c, _findConfkvSQL, key)
if err = row.Scan(&value); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("[SelectConfKv] row.Scan() error(%v)", err)
}
return
}
// AddOrUpdateConfKv add or update conf
func (d *Dao) AddOrUpdateConfKv(c context.Context, key string, value string) (err error) {
oldValue, err := d.RawConfKv(c, key)
if err != nil {
return
}
if oldValue != "" {
//update
log.Info("[LiveCheck] update db value %v", value)
if _, err = d.db.Exec(c, _updateConfkvSQL, value, key); err != nil {
log.Error("[AddOrUpdateConfKv] UpdateConfKv:db.Exec(%v,$v) error(%v)", key, value, err)
}
return
}
//add
log.Info("[LiveCheck] add db value %v", value)
if _, err = d.db.Exec(c, _addConfkvSQL, key, value); err != nil {
log.Error("[AddOrUpdateConfKv] AddConfKv:db.Exec(%v,$v) error(%v)", key, value, err)
}
return
}

View File

@@ -0,0 +1,98 @@
package dao
import (
"context"
"fmt"
"go-common/library/net/http/blademaster"
"math/rand"
"time"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/lrucache"
"go-common/library/database/orm"
xsql "go-common/library/database/sql"
"github.com/jinzhu/gorm"
)
const (
_prefixResource = "live:res:"
_prefixLiveCheck = "live:check:"
_prefixConf = "live:conf:"
)
func cacheResourceKey(typ string, platform string, build int64) string {
return fmt.Sprintf("%s:%s:%s:%d", _prefixResource, typ, platform, build)
}
func cacheLiveCheckKey(platform, system, mobile string) string {
return fmt.Sprintf("%s:%s:%s:%s", _prefixLiveCheck, platform, system, mobile)
}
func cacheConfKey(key string) string {
return fmt.Sprintf("%s:%s", _prefixConf, key)
}
// Dao dao
type Dao struct {
c *conf.Config
db *xsql.DB
rsDB *gorm.DB
rsDBReader *gorm.DB
sCache []*lrucache.SyncCache
client *blademaster.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
if c.CacheCapacity <= 0 {
c.CacheCapacity = 100
}
if c.CacheBucket <= 0 {
c.CacheBucket = 100
}
if c.CacheInstCnt <= 0 {
c.CacheInstCnt = 10
}
if c.CacheTimeout <= 0 {
c.CacheTimeout = 60
}
sCache := make([]*lrucache.SyncCache, c.CacheInstCnt)
for i := range sCache {
sCache[i] = lrucache.NewSyncCache(c.CacheCapacity, c.CacheBucket, c.CacheTimeout)
}
dao = &Dao{
c: c,
db: xsql.NewMySQL(c.MySQL),
rsDB: orm.NewMySQL(c.DB.Resource),
rsDBReader: orm.NewMySQL(c.DB.ResourceReader),
sCache: sCache,
client: blademaster.NewClient(c.HttpClient),
}
rand.Seed(time.Now().UnixNano())
return
}
// mysql log
func (d *Dao) initORM() {
d.rsDB.LogMode(true)
d.rsDB.LogMode(true)
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
d.rsDB.Close()
d.rsDBReader.Close()
return
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) (err error) {
// TODO: if you need use mc,redis, please add
if err = d.db.Ping(c); err != nil {
return
}
return
//return d.pingRedis(c)
}

View File

@@ -0,0 +1,315 @@
package dao
import (
"context"
"database/sql"
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"go-common/app/service/live/resource/model"
"go-common/library/log"
"github.com/siddontang/go-mysql/mysql"
)
const (
_addResourceSQL = "INSERT INTO resource (`platform`,`build`,`limit_type`,`start_time`,`end_time`,`type`,`title`,`image_info`) values(?,?,?,?,?,?,?,?)"
)
// AddResource -
func (d *Dao) AddResource(c context.Context, insert *model.Resource) (row int64, err error) {
types := strings.Split(insert.Type, ",")
for _, t := range types {
insert.Type = t
row, err = d.addDBResource(c, insert)
if err != nil {
return row, err
}
}
return
}
// EditResource -
func (d *Dao) EditResource(c context.Context, id int64, update map[string]interface{}) (row int64, err error) {
return d.editDBResource(c, id, update)
}
// GetResourceList -
func (d *Dao) GetResourceList(c context.Context, typ string, page int64, pageSize int64) (resp []model.Resource, err error) {
return d.getDBResourceList(c, typ, page, pageSize)
}
// GetResourceListEx -
func (d *Dao) GetResourceListEx(c context.Context, typ []string, page int64, pageSize int64, devPlatform string, status string, startTime string, endTime string) (resp []model.Resource, count int64, err error) {
return d.getDBResourceListEx(c, typ, page, pageSize, devPlatform, status, startTime, endTime)
}
// OfflineResource -
func (d *Dao) OfflineResource(c context.Context, id int64) (row int64, err error) {
return d.offlineDBResource(c, id)
}
// SelectById -
func (d *Dao) SelectById(c context.Context, id int64) (resp *model.Resource, err error) {
return d.selectDBById(c, id)
}
// GetInfo -
func (d *Dao) GetInfo(ctx context.Context, typ string, platform string, build int64) (resp *model.Resource, err error) {
inst := rand.Intn(d.c.CacheInstCnt)
res, ok := d.sCache[inst].Get(cacheResourceKey(typ, platform, build))
if !ok {
resp, err = d.getDBInfo(ctx, typ, platform, build)
if err != nil {
return
}
var resNew []model.Resource
resNew = append(resNew, *resp)
d.sCache[inst].Put(cacheResourceKey(typ, platform, build), resNew)
return
}
r := res.([]model.Resource)
if len(r) > 0 {
return &r[0], nil
}
return nil, nil
}
// GetBanner -
func (d *Dao) GetBanner(ctx context.Context, platform string, build int64, t string) (resp []model.Resource, err error) {
inst := rand.Intn(d.c.CacheInstCnt)
res, ok := d.sCache[inst].Get(cacheResourceKey(t, platform, build))
if !ok {
resp, err = d.getDBBanner(ctx, platform, build, t)
if err != nil {
return
}
d.sCache[inst].Put(cacheResourceKey(t, platform, build), resp)
return
}
resp = res.([]model.Resource)
return
}
// SelectByTypeAndPlatform -
func (d *Dao) SelectByTypeAndPlatform(ctx context.Context, typ string, platform string) (resp *model.Resource, err error) {
return d.selectDBByTypeAndPlatform(ctx, typ, platform)
}
// GetDBCount -
func (d *Dao) GetDBCount(ctx context.Context, typ string) (resp int64, err error) {
return d.getDBCount(ctx, typ)
}
// get data from db source
// addSResource add resource to mysql
func (d *Dao) addDBResource(c context.Context, insert *model.Resource) (row int64, err error) {
if insert == nil {
return
}
var reply sql.Result
if _, err = d.db.Begin(c); err != nil {
log.Error("db.begin error(%v)", err)
return
}
reply, err = d.db.Exec(c, _addResourceSQL, insert.Platform, insert.Build, insert.LimitType, insert.StartTime, insert.EndTime, insert.Type, insert.Title, insert.ImageInfo)
if err != nil {
log.Error("resource.addSResource d.db.Exec err: %v", err)
return
}
row, err = reply.LastInsertId()
return
}
func (d *Dao) editDBResource(c context.Context, id int64, update map[string]interface{}) (row int64, err error) {
if update == nil || id < 0 {
return
}
var tx = d.rsDB
tableInfo := &model.Resource{}
var reply = tx.Model(tableInfo).Where("id=?", id).Update(update)
log.Info("effected rows: %d, id : %d", reply.RowsAffected, id)
if reply.Error != nil {
log.Error("resource.editResource error: %v", err)
return
}
row = reply.RowsAffected
return
}
func (d *Dao) getDBResourceList(c context.Context, typ string, page int64, pageSize int64) (resp []model.Resource, err error) {
if typ == "" {
return
}
var tx = d.rsDBReader
tableInfo := &model.Resource{}
err = tx.Model(tableInfo).
Select("`id`,`platform`,`build`,`limit_type`,`start_time`,`end_time`,`title`,`image_info`").
Where("type=?", typ).
Order("id DESC").
Limit(pageSize).
Offset((page - 1) * pageSize).
Find(&resp).Error
if err != nil {
log.Error("resource.editResource error: %v", err)
return
}
return
}
func (d *Dao) getDBResourceListEx(c context.Context, typ []string, page int64, pageSize int64, devPlatform string, status string, startTime string, endTime string) (resp []model.Resource, count int64, err error) {
if len(typ) <= 0 {
return
}
whereStr := "1=1"
for i, t := range typ {
if i != 0 {
whereStr += " or "
} else {
whereStr += " and ("
}
whereStr += fmt.Sprintf("`type` like \"%s%%\"", mysql.Escape(t))
}
whereStr += ")"
if devPlatform != "" {
whereStr += fmt.Sprintf(" and `platform`=\"%s\"", mysql.Escape(devPlatform))
}
if status != "" {
var i int
if i, err = strconv.Atoi(status); err != nil {
return
}
now := time.Now().Format("2006-01-02 15:04:05")
switch i {
case 0:
whereStr += fmt.Sprintf(" and `start_time`>=\"%s\"", now)
case 1:
whereStr += fmt.Sprintf(" and `start_time`<=\"%s\" and `end_time`>=\"%s\"", now, now)
case -1:
whereStr += fmt.Sprintf(" and `end_time`<=\"%s\"", now)
}
}
if startTime != "" {
whereStr += fmt.Sprintf(" and `start_time`>=\"%s\"", mysql.Escape(startTime))
}
if endTime != "" {
whereStr += fmt.Sprintf(" and `end_time`<=\"%s\"", mysql.Escape(endTime))
}
var tx = d.rsDBReader
tableInfo := &model.Resource{}
err = tx.Model(tableInfo).
Select("`id`,`platform`,`build`,`limit_type`,`start_time`,`end_time`,`title`,`image_info`,`type`").
Where(whereStr).
Order("id DESC").
Limit(pageSize).
Offset((page - 1) * pageSize).
Find(&resp).Error
if err != nil {
log.Error("resource.editResource error: %v", err)
return
}
err = tx.Model(tableInfo).
Select("`id`").
Where(whereStr).
Count(&count).Error
if err != nil {
log.Error("resource.editResource error: %v", err)
return
}
return
}
func (d *Dao) getDBCount(c context.Context, typ string) (resp int64, err error) {
if typ == "" {
return
}
var tx = d.rsDBReader
tableInfo := &model.Resource{}
err = tx.Model(tableInfo).
Select("`id`").
Where("type=?", typ).
Count(&resp).Error
if err != nil {
log.Error("resource.editResource error: %v", err)
return
}
return
}
func (d *Dao) offlineDBResource(c context.Context, id int64) (row int64, err error) {
if id == 0 {
return
}
reply, err := d.SelectById(c, id)
if err != nil || reply == nil {
log.Error("resource.OfflineResource select error: %v reply %v", err, reply)
return
}
var tx = d.rsDB
tableInfo := &model.Resource{}
var updateReply = tx.Model(tableInfo).Where("id=?", id).Update("end_time", time.Now())
if updateReply.Error != nil {
log.Error("resource.OfflineResource update error: %v", err)
return
}
return
}
func (d *Dao) selectDBById(c context.Context, id int64) (resp *model.Resource, err error) {
if id == 0 {
return
}
resp = &model.Resource{}
var tx = d.rsDBReader
var reply = tx.Model(&model.Resource{}).Where("id=?", id).Find(resp)
if reply.Error != nil {
log.Error("resource.SelectById error: %v", err)
return
}
return
}
func (d *Dao) getDBInfo(ctx context.Context, typ string, platform string, build int64) (resp *model.Resource, err error) {
if platform == "" || build == 0 {
return
}
resp = &model.Resource{}
var tx = d.rsDBReader
now := time.Now()
var reply = tx.Model(&model.Resource{}).Where("start_time<? and end_time>? and type=? and `platform`=? and ((`limit_type`=0 and `build`<=?) or (`limit_type`=1 and `build`=?) or (`limit_type`=2 and `build`>=?))", now, now, typ, platform, build, build, build).Limit(1).Find(resp)
if reply.Error != nil {
log.Error("resource.GetInfo error: %v", err)
return
}
return
}
func (d *Dao) getDBBanner(ctx context.Context, platform string, build int64, t string) (resp []model.Resource, err error) {
if platform == "" || build == 0 || t == "" {
return
}
var tx = d.rsDBReader
var reply = tx.Model(&model.Resource{}).Where("`start_time`<? and `end_time`>? and `type`=? and (`platform`='' or `platform`=?) and ((`limit_type`=0 and `build`<=?) or (`limit_type`=1 and `build`=?) or (`limit_type`=2 and `build`>=?))", time.Now(), time.Now(), t, platform, build, build, build).Order("mtime DESC").Find(&resp)
if reply.Error != nil {
log.Error("resource.GetBanner error: %v", err)
return
}
return
}
func (d *Dao) selectDBByTypeAndPlatform(ctx context.Context, typ string, platform string) (resp *model.Resource, err error) {
if typ == "" || platform == "" {
return
}
resp = &model.Resource{}
var tx = d.rsDBReader
now := time.Now()
var reply = tx.Model(&model.Resource{}).Where("`type`=? and `end_time`>? and `platform`=? ", typ, now, platform).Limit(1).Find(resp)
if reply.Error != nil {
resp = nil
log.Error("resource.SelectByTypeAndPlatform error: %v", err)
return
}
return
}

View File

@@ -0,0 +1,429 @@
package dao
import (
"context"
"github.com/jinzhu/gorm"
"go-common/app/service/live/resource/api/http/v1"
"go-common/app/service/live/resource/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "time"
)
var (
_statusDel = 4
_statusOn = 1
_statusOff = 2
)
// CheckParams 校验key及team
func (d *Dao) CheckParams(c context.Context, team int64, keyword string) (err error) {
err = nil
if "" == keyword {
err = ecode.ResourceParamErr
}
return err
}
// TeamKeyword 用于封装业务参数结构
type TeamKeyword struct {
Team int64
Keyword string
}
// SelectByTeamIndex 单个key的value查询
func (d *Dao) SelectByTeamIndex(c context.Context, team int64, keyword string, id int64) (res *model.SundryConfig, err error) {
res = &model.SundryConfig{}
resMid := &model.SundyConfigObject{}
if 0 != id {
err = d.rsDB.Model(&model.SundyConfigObject{}).Where("id=?", id).Where("status != ?", _statusDel).Find(&resMid).Error
} else {
err = d.rsDB.Model(&model.SundyConfigObject{}).Where("team=?", team).Where("keyword=?", keyword).Where("status != ?", _statusDel).Find(&resMid).Error
}
if err != nil && err != gorm.ErrRecordNotFound {
log.Error("[live.titans.dao| selectByGroupIndex] d.db.Exec err: %v", err)
return
}
res.Id = resMid.Id
res.Team = resMid.Team
res.Keyword = resMid.Keyword
res.Value = resMid.Value
res.Status = resMid.Status
res.Ctime = resMid.Ctime.Time().Format("2006-01-02 15:04:05")
res.Mtime = resMid.Mtime.Time().Format("2006-01-02 15:04:05")
err = nil
return
}
// SelectByParams 管理后台通过条件查询
func (d *Dao) SelectByParams(c context.Context, id int64, team int64, keyword string, name string, status int64, page int64, pageSize int64) (res []*model.SundryConfig, count int64, err error) {
var (
Items []*model.SundyConfigObject
)
condition := d.rsDB
//模型配置
if -1 == team {
condition = condition.Where("team = ?", 0)
}
//除模型配置外的全部配置
if 0 == team {
condition = condition.Where("team != ?", 0)
}
if 0 != team && -1 != team {
condition = condition.Where("team = ?", team)
}
if 0 != id {
condition = condition.Where("id = ?", id)
}
if "" != keyword {
condition = condition.Where("keyword = ?", keyword)
}
if "" != name {
condition = condition.Where("name like '%" + name + "%'")
}
if 0 != status {
condition = condition.Where("status = ?", status)
}
condition = condition.Where("status != ?", _statusDel)
sModel := condition.Model(&model.SundryConfig{})
sModel.Count(&count)
iOffset := (page - 1) * pageSize
err = sModel.Offset(iOffset).Limit(pageSize).Order("mtime DESC, id DESC").Find(&Items).Error
if err != nil && err != gorm.ErrRecordNotFound {
log.Error("[live.titans.dao| select by params] d.db.Exec err: %v", err)
return
}
for _, v := range Items {
item := &model.SundryConfig{
Id: v.Id,
Team: v.Team,
Keyword: v.Keyword,
Name: v.Name,
Value: v.Value,
Ctime: v.Ctime.Time().Format("2006-01-02 15:04:05"),
Mtime: v.Mtime.Time().Format("2006-01-02 15:04:05"),
Status: v.Status,
}
res = append(res, item)
}
return
}
// InsertRecord 管理后台插入/编辑一条记录
func (d *Dao) InsertRecord(c context.Context, team int64, keyword string, value string, name string, status int64, oid int64) (id int64, count int64, err error) {
//创建模板
if team == -1 {
team = 0
}
//查询唯一索引
err = d.rsDB.Model(&model.SundryConfig{}).Where("team=? and keyword=? and id != ?", team, keyword, oid).Count(&count).Error
if nil != err {
return
}
if 0 != count {
return
}
setMaps := &model.InsertMaps{
Team: team,
Keyword: keyword,
Value: value,
Name: name,
Status: status,
}
newRecord := &model.SundryConfig{}
//编辑
if oid != 0 {
err = d.rsDB.Model(&model.SundryConfig{}).Where("id = ?", oid).Update(setMaps).Error
id = oid
return
}
setMaps.Status = int64(_statusOff)
err = d.rsDB.Create(setMaps).Error
if err != nil {
log.Error("[live.titans.dao| insertRecord] d.db.Exec err: %v", err)
return
}
d.rsDB.Where("keyword = ?", keyword).Find(&newRecord)
id = newRecord.Id
return
}
// SelectByLikes 业务方的请求sql
func (d *Dao) SelectByLikes(c context.Context, teams []int64, teamKeys []*TeamKeyword) (Items []*model.SundyConfigObject, err error) {
Items = []*model.SundyConfigObject{}
if len(teams) == 0 && len(teamKeys) == 0 {
return
}
/** sql 式执行
sql := "select * from ap_sundry_config where status = 1"
if len(teams) != 0 {
teamStr := ""
for i, num := range teams {
teamStr += strconv.Itoa(int(num))
if i+1 != len(teams) {
teamStr += ","
}
}
sql += " and team in (" + teamStr + ") "
}
if len(teamKeys) != 0 {
for _, v := range teamKeys {
sql = sql + " or (team =" + strconv.Itoa(int(v.Team)) + " and keyword = '" + v.Keyword + "') "
}
}
rows, err := d.db.Query(c, sql)
if err != nil {
return
}
for rows.Next() {
resMid := &model.SundyConfigObject{}
rows.Scan(&resMid.Id, &resMid.Team, &resMid.Keyword, &resMid.Name, &resMid.Value, &resMid.Ctime, &resMid.Mtime, &resMid.Status)
Items = append(Items, resMid)
}*/
/** orm **/
condition := d.rsDB.Where("status = ?", 1)
if len(teams) != 0 {
condition = condition.Where("team in (?)", teams)
}
if len(teamKeys) != 0 {
for _, v := range teamKeys {
condition = condition.Or("team = ? and keyword = ?", v.Team, v.Keyword)
}
}
err = condition.Find(&Items).Error
return
}
// FormatTime 时间格式化
func (d *Dao) FormatTime(c context.Context, timeStrUtc string) (timeStr string) {
ctime, _ := xtime.ParseInLocation("2006-01-02T15:04:05+08:00", timeStrUtc, xtime.Local)
timeStr = ctime.Format("2006-01-02 15:04:05")
return timeStr
}
// InsertServiceConfig 插入服务配置
func (d *Dao) InsertServiceConfig(c context.Context, oid int64, treeName string, treePath string, treeId int64, service string, keyword string, template int64, name string, value string, status int64) (id int64, err error) {
checkRes := &model.ServiceConfigObject{}
err = d.rsDB.Model(&model.ServiceConfigObject{}).Where("tree_id=?", treeId).Where("keyword=?", keyword).Find(&checkRes).Error
if err != nil && err != gorm.ErrRecordNotFound {
log.Error("[live.titans.dao| insertServiceRecord] d.db.Exec err: %v", err)
return
}
if 0 != checkRes.Id && oid != checkRes.Id {
id = -1
return
}
if oid != 0 {
//编辑
updateMaps := &model.UpdateServiceConfig{
Service: service,
Keyword: keyword,
Template: template,
Value: value,
Name: name,
Status: status,
}
err = d.rsDB.Model(&model.ServiceConfigObject{}).Where("id=?", oid).Update(updateMaps).Error
id = oid
} else {
setMaps := &model.InsertServiceConfig{
TreeName: treeName,
TreePath: treePath,
TreeId: treeId,
Service: service,
Keyword: keyword,
Template: template,
Value: value,
Name: name,
Status: status,
}
err = d.rsDB.Model(&model.ServiceConfigObject{}).Create(setMaps).Error
newRecord := &model.ServiceConfigObject{}
d.rsDB.Model(&model.ServiceConfigObject{}).Where("tree_id = ?", treeId).Where("keyword=?", keyword).Find(&newRecord)
id = newRecord.Id
}
return
}
// GetServiceConfig 通过tree_id 获取配置
func (d *Dao) GetServiceConfig(c context.Context, treeId int64) (value map[string]string, err error) {
value = make(map[string]string)
res := []*model.ServiceConfigObject{}
err = d.rsDB.Model(&model.ServiceConfigObject{}).Where("tree_id = ?", treeId).Where("status= ?", _statusOn).Find(&res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return
}
for _, v := range res {
value[v.Keyword] = v.Value
}
return
}
// GetServiceConfigList 管理后台获取服务配置列表
func (d *Dao) GetServiceConfigList(c context.Context, treeName string, treeId int64, keyword string, service string, page int64, pageSize int64, name string, status int64) (list []*v1.MList, totalNum int64, err error) {
list = []*v1.MList{}
Items := make([]*model.ServiceConfigObject, 0)
totalNum = 0
condition := d.rsDB
condition = condition.Where("tree_name=?", treeName)
if 1 == status {
condition = condition.Where("status=?", status)
}
if status != 0 && status != int64(_statusOn) {
condition = condition.Where("status !=? ", _statusOn)
}
if 0 != treeId {
condition = condition.Where("tree_id =? ", treeId)
}
if "" != name {
condition = condition.Where("name like '%" + name + "%'")
}
if "" != keyword {
condition = condition.Where("keyword like '%" + keyword + "%'")
}
if "" != service {
condition = condition.Where("service =?", service)
}
sModel := condition.Model(&model.ServiceConfigObject{})
sModel.Count(&totalNum)
iOffset := (page - 1) * pageSize
err = sModel.Offset(iOffset).Limit(pageSize).Order("mtime DESC, id DESC").Find(&Items).Error
if nil != err {
log.Error("sql error select by params")
return
}
for _, v := range Items {
item := &v1.MList{
Id: v.Id,
TreeName: v.TreeName,
TreePath: v.TreePath,
TreeId: v.TreeId,
Service: v.Service,
Keyword: v.Keyword,
Template: v.Template,
Name: v.Name,
Value: v.Value,
Ctime: v.Ctime.Time().Format("2006-01-02 15:04:05"),
Mtime: v.Mtime.Time().Format("2006-01-02 15:04:05"),
Status: v.Status,
}
list = append(list, item)
}
return
}
// GetTreeIds 获取treeName对应的tree_ids
func (d *Dao) GetTreeIds(c context.Context, treeName string) (list []int64, err error) {
list = make([]int64, 0)
query := "select distinct tree_id from ap_services_config where status=1 and tree_name = ?"
rows, err := d.db.Query(c, query, treeName)
if err != nil && err != sql.ErrNoRows {
log.Error("[live.titans.dao| getDiscoveryIds] d.db.Exec err: %v", err)
return
}
defer rows.Close()
for rows.Next() {
item := &model.ServiceModel{}
err = rows.Scan(&item.TreeId)
if err != nil {
return
}
if item.TreeId != 0 {
list = append(list, item.TreeId)
}
}
return
}
// GetEasyRecord 获取运营配置
func (d *Dao) GetEasyRecord(c context.Context, treeName string) (list *v1.MList) {
list = &v1.MList{}
query := "select id, value from ap_services_config where tree_name = ? and tree_id = 0"
rows := d.db.QueryRow(c, query, treeName)
err := rows.Scan(&list.Id, &list.Value)
if err != nil {
log.Error("[live.titans.dao| GetEasyRecord] d.db.Exec err: %v", err)
return
}
return
}
// SetEasyRecord 设置运营配置
func (d *Dao) SetEasyRecord(c context.Context, treeName string, value string, id int64) (nId int64, err error) {
record := &model.InsertServiceConfig{
TreeName: treeName,
TreePath: treeName,
TreeId: 0,
Name: treeName + "运营操作列表",
Value: value,
Status: int64(_statusOn),
}
nId = id
if id != 0 {
err = d.rsDB.Model(&model.ServiceConfigObject{}).Where("id = ?", id).Update(record).Error
} else {
err = d.rsDB.Model(&model.ServiceConfigObject{}).Create(record).Error
if err != nil {
return
}
newRecord := &model.ServiceConfigObject{}
err = d.rsDB.Model(&model.ServiceConfigObject{}).Where("tree_name = ?", treeName).Where("tree_id = ?", 0).Find(&newRecord).Error
if err != nil {
return
}
nId = newRecord.Id
}
return
}
// GetListByIds 通过ids获取配置列表
func (d *Dao) GetListByIds(c context.Context, ids []int64) (list []*model.ServiceModel, err error) {
list = []*model.ServiceModel{}
Items := make([]*model.ServiceConfigObject, 0)
condition := d.rsDB
condition = condition.Where("id in (?)", ids)
sModel := condition.Model(&model.ServiceConfigObject{})
err = sModel.Find(&Items).Error
if nil != err {
log.Error("sql error select by params")
return
}
for _, v := range Items {
item := &model.ServiceModel{
Id: v.Id,
TreeName: v.TreeName,
TreePath: v.TreePath,
TreeId: v.TreeId,
Service: v.Service,
Keyword: v.Keyword,
Template: v.Template,
Name: v.Name,
Value: v.Value,
Ctime: v.Ctime.Time().Format("2006-01-02 15:04:05"),
Mtime: v.Mtime.Time().Format("2006-01-02 15:04:05"),
Status: v.Status,
}
list = append(list, item)
}
return
}

View File

@@ -0,0 +1,200 @@
package dao
import (
"bytes"
"context"
"fmt"
"go-common/app/service/live/resource/model"
"go-common/library/ecode"
"go-common/library/log"
"net/http"
"strings"
"time"
)
var (
tokenURI = "http://easyst.bilibili.co/v1/token"
dataURI = "http://easyst.bilibili.co/v1/node/apptree"
authURI = "http://easyst.bilibili.co/v1/auth"
nodeURI = "http://easyst.bilibili.co/v1/node/bilibili%s"
appsURI = "http://easyst.bilibili.co/v1/node/role/app"
prefix = []byte("bilibili.")
)
// Token get Token.
func (d *Dao) Token(c context.Context, body string) (msg map[string]interface{}, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("POST", tokenURI, strings.NewReader(body)); err != nil {
log.Error("Token url(%s) error(%v)", tokenURI, err)
return
}
var res struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Token url(%s) res(%+v) err(%v)", tokenURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", tokenURI, res)
return
}
msg = res.Data
return
}
// Auth get Token.
func (d *Dao) Auth(c context.Context, cookie string) (msg map[string]interface{}, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("GET", authURI, nil); err != nil {
log.Error("Token url(%s) error(%v)", tokenURI, err)
return
}
req.Header.Set("Cookie", cookie)
var res struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Token url(%s) res($s) err(%v)", tokenURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", tokenURI, res)
return
}
msg = res.Data
return
}
// Tree get service tree.
func (d *Dao) Tree(c context.Context, token string) (data interface{}, err error) {
var (
req *http.Request
tmp map[string]interface{}
ok bool
)
if req, err = http.NewRequest("GET", dataURI, nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data map[string]map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", dataURI, res)
return
}
if tmp, ok = res.Data["bilibili"]; ok {
data, ok = tmp["children"]
}
if !ok {
err = ecode.NothingFound
}
return
}
// Role get service tree.
func (d *Dao) Role(c context.Context, user, token string) (nodes *model.CacheData, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("GET", appsURI, nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data []*model.RoleNode `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", dataURI, res)
return
}
nodes = &model.CacheData{Data: make(map[int64]*model.RoleNode)}
nodes.CTime = time.Now()
for _, node := range res.Data {
if bytes.Equal(prefix, []byte(node.Path)[0:9]) {
node.Path = string([]byte(node.Path)[9:])
}
nodes.Data[node.ID] = node
}
return
}
// NodeTree get service tree.
func (d *Dao) NodeTree(c context.Context, token, bu, team string) (nodes []*model.Node, err error) {
var (
req *http.Request
node string
)
if len(bu) != 0 {
node = "." + bu
}
if len(team) != 0 {
node = "." + team
}
if len(node) == 0 {
nodes = append(nodes, &model.Node{Name: "main", Path: "main"})
nodes = append(nodes, &model.Node{Name: "ai", Path: "ai"})
return
}
if req, err = http.NewRequest("GET", fmt.Sprintf(nodeURI, node), nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data *model.Res `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
for _, tnode := range res.Data.Data {
if bytes.Equal(prefix, []byte(tnode.Path)[0:9]) {
tnode.Path = string([]byte(tnode.Path)[9:])
}
nodes = append(nodes, &model.Node{Name: tnode.Name, Path: tnode.Path})
}
return
}

View File

@@ -0,0 +1,187 @@
package dao
import (
"context"
"database/sql"
"go-common/app/service/live/resource/model"
"go-common/library/ecode"
"go-common/library/log"
"time"
"github.com/jinzhu/gorm"
)
var (
addSql = "INSERT INTO `user_resource`(`res_type`,`custom_id`,`title`,`url`,`weight`,`status`,`creator`) values (?,?,?,?,?,?,?);"
rowFields = "`id`, `res_type`,`custom_id`,`title`,`url`,`weight`,`status`,`creator`,UNIX_TIMESTAMP(`ctime`), UNIX_TIMESTAMP(`mtime`)"
)
// AddUserResource 添加用户资源到DB
func (d *Dao) AddUserResource(c context.Context, res *model.UserResource) (newRes model.UserResource, err error) {
if res == nil {
return
}
var reply sql.Result
if _, err = d.db.Begin(c); err != nil {
log.Error("初始化DB错误(%v)", err)
return
}
reply, err = d.db.Exec(c, addSql, res.ResType, res.CustomID, res.Title, res.URL, res.Weight, res.Status, res.Creator)
if err != nil {
log.Error("执行SQL语句 err: %v", err)
return
}
lastID_, _ := reply.LastInsertId()
newRes, err = d.GetUserResourceInfoByID(c, int32(lastID_))
return
}
// EditUserResource 编辑已有资源
func (d *Dao) EditUserResource(c context.Context, resType int32, customID int32, update map[string]interface{}) (effectRow int32, newRes model.UserResource, err error) {
if update == nil {
return
}
var tx = d.rsDB
tableInfo := &model.UserResource{}
var reply = tx.Model(tableInfo).
Where("`res_type` = ? AND `custom_id` = ?", resType, customID).
Update(update)
log.Info("effected rows: %d, res_type : %d custom_id : %d", reply.RowsAffected, resType, customID)
if reply.Error != nil {
log.Error("resource.editResource error: %v", err)
return
}
effectRow = int32(reply.RowsAffected)
newRes, err = d.GetUserResourceInfo(c, resType, customID)
return
}
// SetUserResourceStatus 设置资源状态
func (d *Dao) SetUserResourceStatus(c context.Context, resType int32, customID int32, status int32) (effectRow int32, err error) {
update := make(map[string]interface{})
update["status"] = status
effectRow, _, err = d.EditUserResource(c, resType, customID, update)
if err != nil {
log.Error("修改资源状态: %v", err)
}
return
}
// GetMaxCustomID 根据资源类型获取当前最大的资源ID
func (d *Dao) GetMaxCustomID(c context.Context, resType int32) (maxCustomID int32, err error) {
tableInfo := &model.UserResource{}
var ret sql.NullInt64
err = d.rsDB.Model(tableInfo).Debug().
Select("max(custom_id) as mcid").
Where("res_type=?", resType).
Row().Scan(&ret)
if err != nil {
log.Error("查找最大的资源ID res_type : %d : %v", resType, err)
return
}
maxCustomID = int32(ret.Int64)
log.Info("类型为 %d 最大的资源ID是 %d", resType, maxCustomID)
return
}
// getRowResult Helper方法
func getRowResult(queryResult *gorm.DB) (res model.UserResource, err error) {
var count int32
err = queryResult.Count(&count).Error
if err != nil {
log.Error("user_resource.GetUserResourceInfoByID %v", err)
err = ecode.SeltResErr
return
}
if count == 0 {
log.Info("user_resource.getRowResult 查询结果为空")
err = ecode.SeltResErr
return
}
var retID, retResType, retCustomID, retWeight, retStatus, retCtime, retMtime sql.NullInt64
var retTitle, retURL, retCreator sql.NullString
err = queryResult.Row().Scan(&retID, &retResType, &retCustomID, &retTitle, &retURL, &retWeight, &retStatus, &retCreator, &retCtime, &retMtime)
if err != nil {
log.Error("resource.GetUserResourceInfoByID error: %v", err)
err = ecode.SeltResErr
return
}
res.ID = int32(retID.Int64)
res.ResType = int32(retResType.Int64)
res.CustomID = int32(retCustomID.Int64)
res.Title = retTitle.String
res.URL = retURL.String
res.Weight = int32(retWeight.Int64)
res.Status = int32(retStatus.Int64)
res.Creator = retCreator.String
res.Ctime = time.Unix(retCtime.Int64, 0)
res.Ctime = time.Unix(retMtime.Int64, 0)
return
}
// GetUserResourceInfo 获取单个配置
func (d *Dao) GetUserResourceInfo(c context.Context, resType int32, customID int32) (res model.UserResource, err error) {
tableInfo := &model.UserResource{}
queryResult := d.rsDBReader.Model(tableInfo).Select(rowFields).
Where("res_type=? AND custom_id=?", resType, customID)
res, err = getRowResult(queryResult)
return
}
// GetUserResourceInfoByID 根据ID获取单个配置
func (d *Dao) GetUserResourceInfoByID(c context.Context, id int32) (res model.UserResource, err error) {
tableInfo := &model.UserResource{}
queryResult := d.rsDBReader.Model(tableInfo).Select(rowFields).
Where("id=?", id)
res, err = getRowResult(queryResult)
return
}
// ListUserResourceInfo 获取配置列表
func (d *Dao) ListUserResourceInfo(c context.Context, resType int32, page int32, pageSize int32) (list []model.UserResource, err error) {
var tx = d.rsDBReader
tableInfo := &model.UserResource{}
err = tx.Model(tableInfo).
Select("`id`, `res_type`,`custom_id`,`title`,`url`,`weight`,`status`,`creator`,`ctime`, `mtime`").
Where("res_type=?", resType).
Order("id ASC").
Limit(pageSize).
Offset((page - 1) * pageSize).
Find(&list).Error
if err != nil {
log.Error("resource.editResource error: %v", err)
return
}
return
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"lrucache_test.go",
"synccache_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"lrucache.go",
"synccache.go",
],
importpath = "go-common/app/service/live/resource/lrucache",
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,139 @@
package lrucache
// Element - node to store cache item
type Element struct {
prev, next *Element
Key interface{}
Value interface{}
}
// Next - fetch older element
func (e *Element) Next() *Element {
return e.next
}
// Prev - fetch newer element
func (e *Element) Prev() *Element {
return e.prev
}
// LRUCache - a data structure that is efficient to insert/fetch/delete cache items [both O(1) time complexity]
type LRUCache struct {
cache map[interface{}]*Element
head *Element
tail *Element
capacity int
}
// New - create a new lru cache object
func New(capacity int) *LRUCache {
return &LRUCache{make(map[interface{}]*Element), nil, nil, capacity}
}
// Put - put a cache item into lru cache
func (lc *LRUCache) Put(key interface{}, value interface{}) {
if e, ok := lc.cache[key]; ok {
e.Value = value
lc.refresh(e)
return
}
if lc.capacity == 0 {
return
} else if len(lc.cache) >= lc.capacity {
// evict the oldest item
delete(lc.cache, lc.tail.Key)
lc.remove(lc.tail)
}
e := &Element{nil, lc.head, key, value}
lc.cache[key] = e
if len(lc.cache) != 1 {
lc.head.prev = e
} else {
lc.tail = e
}
lc.head = e
}
// Get - get value of key from lru cache with result
func (lc *LRUCache) Get(key interface{}) (interface{}, bool) {
if e, ok := lc.cache[key]; ok {
lc.refresh(e)
return e.Value, ok
}
return nil, false
}
// Delete - delete item by key from lru cache
func (lc *LRUCache) Delete(key interface{}) {
if e, ok := lc.cache[key]; ok {
delete(lc.cache, key)
lc.remove(e)
}
}
// Range - calls f sequentially for each key and value present in the lru cache
func (lc *LRUCache) Range(f func(key, value interface{}) bool) {
for i := lc.head; i != nil; i = i.Next() {
if !f(i.Key, i.Value) {
break
}
}
}
// Update - inplace update
func (lc *LRUCache) Update(key interface{}, f func(value *interface{})) {
if e, ok := lc.cache[key]; ok {
f(&e.Value)
lc.refresh(e)
}
}
// Front - get front element of lru cache
func (lc *LRUCache) Front() *Element {
return lc.head
}
// Back - get back element of lru cache
func (lc *LRUCache) Back() *Element {
return lc.tail
}
// Len - length of lru cache
func (lc *LRUCache) Len() int {
return len(lc.cache)
}
// Capacity - capacity of lru cache
func (lc *LRUCache) Capacity() int {
return lc.capacity
}
func (lc *LRUCache) refresh(e *Element) {
if e.prev != nil {
e.prev.next = e.next
if e.next == nil {
lc.tail = e.prev
} else {
e.next.prev = e.prev
}
e.prev = nil
e.next = lc.head
lc.head.prev = e
lc.head = e
}
}
func (lc *LRUCache) remove(e *Element) {
if e.prev == nil {
lc.head = e.next
} else {
e.prev.next = e.next
}
if e.next == nil {
lc.tail = e.prev
} else {
e.next.prev = e.prev
}
}

View File

@@ -0,0 +1,257 @@
package lrucache
import (
"container/list"
"testing"
)
type Elem struct {
key int
value string
}
func Test_New(t *testing.T) {
lc := New(5)
if lc.Len() != 0 {
t.Error("case 1 failed")
}
}
func Test_Put(t *testing.T) {
lc := New(0)
lc.Put(1, "1")
if lc.Len() != 0 {
t.Error("case 1.1 failed")
}
lc = New(5)
lc.Put(1, "1")
lc.Put(2, "2")
lc.Put(1, "3")
if lc.Len() != 2 {
t.Error("case 2.1 failed")
}
l := list.New()
l.PushBack(&Elem{1, "3"})
l.PushBack(&Elem{2, "2"})
e := l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 2.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 2.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
lc.Put(3, "4")
lc.Put(4, "5")
lc.Put(5, "6")
lc.Put(2, "7")
if lc.Len() != 5 {
t.Error("case 3.1 failed")
}
l = list.New()
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{5, "6"})
l.PushBack(&Elem{4, "5"})
l.PushBack(&Elem{3, "4"})
l.PushBack(&Elem{1, "3"})
rl := list.New()
rl.PushBack(&Elem{1, "3"})
rl.PushBack(&Elem{3, "4"})
rl.PushBack(&Elem{4, "5"})
rl.PushBack(&Elem{5, "6"})
rl.PushBack(&Elem{2, "7"})
e = l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 3.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 3.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
e = rl.Front()
for c := lc.Back(); c != nil; c = c.Prev() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 3.4 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 3.5 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
lc.Put(6, "8")
if lc.Len() != 5 {
t.Error("case 4.1 failed")
}
l = list.New()
l.PushBack(&Elem{6, "8"})
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{5, "6"})
l.PushBack(&Elem{4, "5"})
l.PushBack(&Elem{3, "4"})
e = l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 4.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 4.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
}
func Test_Get(t *testing.T) {
lc := New(2)
lc.Put(1, "1")
lc.Put(2, "2")
if v, _ := lc.Get(1); v != "1" {
t.Error("case 1.1 failed")
}
lc.Put(3, "3")
if lc.Len() != 2 {
t.Error("case 1.2 failed")
}
l := list.New()
l.PushBack(&Elem{3, "3"})
l.PushBack(&Elem{1, "1"})
e := l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 1.3 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 1.4 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
}
func Test_Delete(t *testing.T) {
lc := New(5)
lc.Put(3, "4")
lc.Put(4, "5")
lc.Put(5, "6")
lc.Put(2, "7")
lc.Put(6, "8")
lc.Delete(5)
l := list.New()
l.PushBack(&Elem{6, "8"})
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{4, "5"})
l.PushBack(&Elem{3, "4"})
if lc.Len() != 4 {
t.Error("case 1.1 failed")
}
e := l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 1.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 1.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
lc.Delete(6)
l = list.New()
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{4, "5"})
l.PushBack(&Elem{3, "4"})
if lc.Len() != 3 {
t.Error("case 2.1 failed")
}
e = l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 2.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 2.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
lc.Delete(3)
l = list.New()
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{4, "5"})
if lc.Len() != 2 {
t.Error("case 3.1 failed")
}
e = l.Front()
for c := lc.Front(); c != nil; c = c.Next() {
v := e.Value.(*Elem)
if c.Key.(int) != v.key {
t.Error("case 3.2 failed: ", c.Key.(int), v.key)
}
if c.Value.(string) != v.value {
t.Error("case 3.3 failed: ", c.Value.(string), v.value)
}
e = e.Next()
}
}
func Test_Range(t *testing.T) {
lc := New(5)
lc.Put(3, "4")
lc.Put(4, "5")
lc.Put(5, "6")
lc.Put(2, "7")
lc.Put(6, "8")
l := list.New()
l.PushBack(&Elem{6, "8"})
l.PushBack(&Elem{2, "7"})
l.PushBack(&Elem{5, "6"})
l.PushBack(&Elem{4, "5"})
l.PushBack(&Elem{3, "4"})
e := l.Front()
lc.Range(
func(key, value interface{}) bool {
v := e.Value.(*Elem)
if key.(int) != v.key {
t.Error("case 1.1 failed: ", key.(int), v.key)
}
if value.(string) != v.value {
t.Error("case 1.2 failed: ", value.(string), v.value)
}
e = e.Next()
return true
})
if e != nil {
t.Error("case 1.3 failed: ", e.Value)
}
}

View File

@@ -0,0 +1,99 @@
package lrucache
import (
"hash/crc32"
"sync"
"time"
)
// hashCode hashes a string to a unique hashcode.
//
// crc32 returns a uint32, but for our use we need
// and non negative integer. Here we cast to an integer
// and invert it if the result is negative.
func hashCode(s string) (hc int) {
hc = int(crc32.ChecksumIEEE([]byte(s)))
if hc >= 0 {
return hc
}
if -hc >= 0 {
return -hc
}
// hc == MinInt
return hc
}
// SyncCache - concurrent cache structure
type SyncCache struct {
locks []sync.Mutex
caches []*LRUCache
mask int
timeout int64
}
type scValue struct {
Value interface{}
ts int64
}
func nextPowOf2(cap int) int {
if cap < 2 {
return 2
}
if cap&(cap-1) == 0 {
return cap
}
cap |= cap >> 1
cap |= cap >> 2
cap |= cap >> 4
cap |= cap >> 8
cap |= cap >> 16
return cap + 1
}
// NewSyncCache - create sync cache
// `capacity` is lru cache length of each bucket
// store `capacity * bucket` count of element in SyncCache at most
// `timeout` is in seconds
func NewSyncCache(capacity int, bucket int, timeout int64) *SyncCache {
size := nextPowOf2(bucket)
sc := SyncCache{make([]sync.Mutex, size), make([]*LRUCache, size), size - 1, timeout}
for i := range sc.caches {
sc.caches[i] = New(capacity)
}
return &sc
}
// Put - put a cache item into sync cache
func (sc *SyncCache) Put(key string, value interface{}) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
sc.caches[idx].Put(key, &scValue{value, time.Now().Unix()})
sc.locks[idx].Unlock()
}
// Get - get value of key from sync cache with result
func (sc *SyncCache) Get(key string) (interface{}, bool) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
v, b := sc.caches[idx].Get(key)
if !b {
sc.locks[idx].Unlock()
return nil, false
}
if time.Now().Unix()-v.(*scValue).ts >= sc.timeout {
sc.caches[idx].Delete(key)
sc.locks[idx].Unlock()
return nil, false
}
sc.locks[idx].Unlock()
return v.(*scValue).Value, b
}
// Delete - delete item by key from sync cache
func (sc *SyncCache) Delete(key string) {
idx := hashCode(key) & sc.mask
sc.locks[idx].Lock()
sc.caches[idx].Delete(key)
sc.locks[idx].Unlock()
}

View File

@@ -0,0 +1,85 @@
package lrucache
import (
"sync"
"testing"
"time"
)
func Test_hashCode(t *testing.T) {
/*if hashCode(-1) != 1 {
t.Error("case 1 failed")
}
if hashCode(0) != 0 {
t.Error("case 2 failed")
}
if hashCode(0x7FFFFFFF) != 0x7FFFFFFF {
t.Error("case 3 failed")
}*/
if hashCode("12345") != 3421846044 {
t.Error("case 4 failed")
}
if hashCode("abcdefghijklmnopqrstuvwxyz") != 1277644989 {
t.Error("case 5 failed")
}
/*if hashCode(123.45) != 123 {
t.Error("case 6 failed")
}
if hashCode(-15268.45) != 15268 {
t.Error("case 7 failed")
}*/
}
func Test_nextPowOf2(t *testing.T) {
if nextPowOf2(0) != 2 {
t.Error("case 1 failed")
}
if nextPowOf2(1) != 2 {
t.Error("case 2 failed")
}
if nextPowOf2(2) != 2 {
t.Error("case 3 failed")
}
if nextPowOf2(3) != 4 {
t.Error("case 4 failed")
}
if nextPowOf2(123) != 128 {
t.Error("case 5 failed")
}
if nextPowOf2(0x7FFFFFFF) != 0x80000000 {
t.Error("case 6 failed")
}
}
func Test_timeout(t *testing.T) {
sc := NewSyncCache(1, 2, 2)
sc.Put("1", "2")
if v, ok := sc.Get("1"); !ok || v != "2" {
t.Error("case 1 failed")
}
time.Sleep(2 * time.Second)
if _, ok := sc.Get("1"); ok {
t.Error("case 2 failed")
}
}
func Test_concurrent(t *testing.T) {
sc := NewSyncCache(1, 4, 2)
var wg sync.WaitGroup
for index := 0; index < 100000; index++ {
wg.Add(3)
go func() {
sc.Put("1", "2")
wg.Done()
}()
go func() {
sc.Get("1")
wg.Done()
}()
go func() {
sc.Delete("1")
wg.Done()
}()
}
wg.Wait()
}

View File

@@ -0,0 +1,61 @@
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 = "model_proto",
srcs = ["titans.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/live/resource/model",
proto = ":model_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"confkv.go",
"model.go",
"resource.go",
"tree.go",
"user_resource.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/service/live/resource/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,17 @@
package model
import "time"
// Confkv def
type Confkv struct {
ID int64 `json:"id" gorm:"column:id"`
Key string `json:"key" form:"key"`
Value string `json:"value" form:"value"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName resource
func (c Confkv) TableName() string {
return "confkv"
}

View File

@@ -0,0 +1,93 @@
package model
import "go-common/library/time"
// TableName is used to identify table name in gorm
func (cf *SundryConfig) TableName() string {
return "ap_sundry_config"
}
// TableName is used to identify table name in gorm
func (cf *SundyConfigObject) TableName() string {
return "ap_sundry_config"
}
// InsertMaps is used to insertDb format
type InsertMaps struct {
Team int64 `protobuf:"varint,2,opt,name=team,proto3" json:"team"`
Keyword string `protobuf:"bytes,3,opt,name=keyword,proto3" json:"keyword"`
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name"`
Value string `protobuf:"bytes,5,opt,name=value,proto3" json:"value"`
Status int64 `protobuf:"bytes,5,opt,name=value,proto3" json:"status"`
}
// TableName is used to identify table name in gorm
func (cf *InsertMaps) TableName() string {
return "ap_sundry_config"
}
// SundyConfigObject is used to format select
type SundyConfigObject struct {
Id int64 `json:"id" gorm:"comumn:id"`
Team int64 `json:"team" gorm:"comumn:team"`
Keyword string `json:"index" gorm:"comumn:keyword"`
Name string `json:"name" gorm:"comumn:name"`
Value string `json:"value" gorm:"comumn:value"`
Ctime time.Time `json:"ctime" gorm:"comumn:ctime"`
Mtime time.Time `json:"mtime" gorm:"comumn:mtime"`
Status int64 `json:"status" gorm:"comumn:status"`
}
// TableName is used to identify table name in gorm
func (cf *ServiceConfigObject) TableName() string {
return "ap_services_config"
}
// TableName is used to identify table name in gorm
func (cf *InsertServiceConfig) TableName() string {
return "ap_services_config"
}
// TableName is used to identify table name in gorm
func (cf *UpdateServiceConfig) TableName() string {
return "ap_services_config"
}
// ServiceConfigObject is used to format select
type ServiceConfigObject struct {
Id int64 `json:"id" gorm:"comumn:id"`
TreeName string `protobuf:"bytes,2,opt,name=tree_name,proto3" json:"tree_name"`
TreePath string `protobuf:"bytes,3,opt,name=tree_path,proto3" json:"tree_path"`
TreeId int64 `protobuf:"varint,4,opt,name=tree_id,proto3" json:"tree_id"`
Service string `protobuf:"bytes,5,opt,name=service,proto3" json:"service"`
Keyword string `protobuf:"bytes,6,opt,name=keyword,proto3" json:"keyword"`
Template int64 `protobuf:"varint,7,opt,name=template,proto3" json:"template"`
Value string `protobuf:"bytes,8,opt,name=value,proto3" json:"value"`
Name string `protobuf:"bytes,9,opt,name=name,proto3" json:"name"`
Status int64 `protobuf:"varint,10,opt,name=status,proto3" json:"status"`
Ctime time.Time `protobuf:"bytes,7,opt,name=ctime,proto3" json:"ctime"`
Mtime time.Time `protobuf:"bytes,8,opt,name=mtime,proto3" json:"mtime"`
}
// InsertServiceConfig is used to insertDb format
type InsertServiceConfig struct {
TreeName string `protobuf:"bytes,3,opt,name=tree_name,proto3" json:"tree_name"`
TreePath string `protobuf:"bytes,3,opt,name=tree_path,proto3" json:"tree_path"`
TreeId int64 `protobuf:"bytes,3,opt,name=tree_id,proto3" json:"tree_id"`
Service string `protobuf:"bytes,2,opt,name=service,json=servuce,proto3" `
Keyword string `protobuf:"bytes,3,opt,name=template,proto3" json:"keyword"`
Template int64 `protobuf:"bytes,3,opt,name=template,proto3" json:"template"`
Value string `protobuf:"bytes,4,opt,name=value,proto3" json:"value"`
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name"`
Status int64 `protobuf:"varint,6,opt,name=status,proto3" json:"status"`
}
// UpdateServiceConfig is used to insertDb format
type UpdateServiceConfig struct {
Service string `protobuf:"bytes,3,opt,name=service,proto3" json:"service"`
Keyword string `protobuf:"bytes,3,opt,name=template,proto3" json:"keyword"`
Template int64 `protobuf:"bytes,3,opt,name=template,proto3" json:"template"`
Value string `protobuf:"bytes,4,opt,name=value,proto3" json:"value"`
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name"`
Status int64 `protobuf:"varint,6,opt,name=status,proto3" json:"status"`
}

View File

@@ -0,0 +1,23 @@
package model
import "time"
// Resource def
type Resource struct {
ID int64 `json:"id" gorm:"column:id"`
Platform string `json:"platform" form:"platform"`
Build int64 `json:"build" form:"build"`
LimitType int64 `json:"limit" form:"limit_type"`
StartTime time.Time `json:"start_time" form:"start_time"`
EndTime time.Time `json:"end_time" form:"end_time"`
Type string `json:"type" form:"type"`
Title string `json:"title" form:"title"`
ImageInfo string `json:"image_info" form:"image_info"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName resource
func (c Resource) TableName() string {
return "resource"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message SundryConfig {
int64 id = 1 [(gogoproto.jsontag) = "id"];
int64 team = 2 [(gogoproto.jsontag) = "team"];
string keyword = 3 [(gogoproto.jsontag) = "keyword"];
string value = 4 [(gogoproto.jsontag) = "value"];
string name = 5 [(gogoproto.jsontag) = "name"];
int64 status = 6 [(gogoproto.jsontag) = "status"];
string ctime = 7 [(gogoproto.jsontag) = "ctime"];
string mtime = 8 [(gogoproto.jsontag) = "mtime"];
}
message ServiceModel {
int64 id = 1 [(gogoproto.jsontag) = "id"];
string tree_name = 2 [(gogoproto.jsontag) = "tree_name"];
string tree_path = 3 [(gogoproto.jsontag) = "tree_path"];
int64 tree_id = 4 [(gogoproto.jsontag) = "tree_id"];
string service = 5 [(gogoproto.jsontag) = "service"];
string keyword = 6 [(gogoproto.jsontag) = "keyword"];
int64 template = 7 [(gogoproto.jsontag) = "template"];
string value = 8 [(gogoproto.jsontag) = "value"];
string name = 9 [(gogoproto.jsontag) = "name"];
int64 status = 10 [(gogoproto.jsontag) = "status"];
string ctime = 11 [(gogoproto.jsontag) = "ctime"];
string mtime = 12 [(gogoproto.jsontag) = "mtime"];
}

View File

@@ -0,0 +1,164 @@
package model
import (
xtime "go-common/library/time"
"time"
)
//App app.
type App struct {
ID int64 `json:"id" gorm:"primary_key"`
Name string `json:"name"`
TreeID int64 `json:"tree_id"`
Env string `json:"env"`
Zone string `json:"zone"`
Token string `json:"token"`
Status int8 `json:"status"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
}
// TableName app
func (App) TableName() string {
return "app"
}
// Node node.
type Node struct {
Name string `json:"name"`
Path string `json:"path"`
TreeID int64 `json:"tree_id"`
}
// TreeNode TreeNode.
type TreeNode struct {
Alias string `json:"alias"`
CreatedAt string `json:"created_at"`
Name string `json:"name"`
Path string `json:"path"`
Tags interface{} `json:"tags"`
Type int `json:"type"`
}
// Res res.
type Res struct {
Count int `json:"count"`
Data []*TreeNode `json:"data"`
Page int `json:"page"`
Results int `json:"results"`
}
// AppPager app pager
type AppPager struct {
Total int64 `json:"total"`
Pn int64 `json:"pn"`
Ps int64 `json:"ps"`
Items []*App `json:"items"`
}
// Resp tree resp
type Resp struct {
Data map[string]*Tree `json:"data"`
}
// Tree node.
type Tree struct {
Name string `json:"name"`
Type int `json:"type"`
Path string `json:"path"`
Tags *TreeTag `json:"tags"`
Children map[string]*Tree `json:"children"`
}
//TreeTag tree tag.
type TreeTag struct {
Ops string `json:"ops"`
Rds string `json:"rds"`
}
//Env env.
type Env struct {
Name string `json:"name"`
NikeName string `json:"nike_name"`
Token string `json:"token"`
}
//RoleNode roleNode .
type RoleNode struct {
ID int64 `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Type int8 `json:"type"`
Role int8 `json:"role"`
}
//UpdateTokenReq ...
type UpdateTokenReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//CreateReq ...
type CreateReq struct {
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//AppListReq ...
type AppListReq struct {
AppName string `form:"app_name"`
Bu string `form:"bu"`
Team string `form:"team"`
Pn int64 `form:"pn" default:"1" validate:"min=1"`
Ps int64 `form:"ps" default:"20" validate:"min=1"`
Status int8 `form:"status"`
}
//EnvsByTeamReq ...
type EnvsByTeamReq struct {
AppName string `form:"app_name"`
Zone string `form:"zone"`
Team string `form:"team"`
}
//EnvsReq ...
type EnvsReq struct {
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Zone string `form:"zone" validate:"required"`
}
//NodeTreeReq ...
type NodeTreeReq struct {
Node string `form:"node"`
Team string `form:"team"`
}
//ZoneCopyReq ...
type ZoneCopyReq struct {
AppName string `form:"app_name" validate:"required"`
From string `form:"from_zone" validate:"required"`
To string `form:"to_zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//CasterEnvsReq ...
type CasterEnvsReq struct {
TreeID int64 `form:"tree_id" validate:"required"`
Zone string `form:"zone" validate:"required"`
Auth string `form:"auth" validate:"required"`
}
//CacheData ...
type CacheData struct {
Data map[int64]*RoleNode `json:"data"`
CTime time.Time `json:"ctime"`
}
//AppStatusReq ...
type AppStatusReq struct {
TreeID int64 `form:"tree_id" validate:"required"`
Status int8 `form:"status" default:"1"`
}

View File

@@ -0,0 +1,22 @@
package model
import "time"
// UserResource def
type UserResource struct {
ID int32 `json:"id" gorm:"id"`
ResType int32 `json:"res_type" form:"res_type"`
CustomID int32 `json:"custom_id" form:"custom_id"`
Title string `json:"title" form:"title"`
URL string `json:"url" form:"url"`
Weight int32 `json:"weight" form:"weight"`
Status int32 `json:"status" form:"status"`
Creator string `json:"creator" form:"creator"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName user_resource
func (c UserResource) TableName() string {
return "user_resource"
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["titansSdk.go"],
importpath = "go-common/app/service/live/resource/sdk",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/grpc/v1:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/warden: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,89 @@
package titansSdk
import (
"context"
"go-common/app/service/live/resource/api/grpc/v1"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/rpc/warden"
"sync/atomic"
"time"
)
// titansConfigSdk 初始化时 单实例对象
var titansConfigSdk = &titansSdk{}
// Config 服务可配置项
type Config struct {
// 服务的tree_id
TreeId int64
// 缓存的更新间隔单位为s不配置则为5s
Expire int64
}
// titansSdk sdk
type titansSdk struct {
client v1.TitansClient
cache atomic.Value
}
// Init 业务初始化sdk接口
func Init(titansConfig *Config) {
conf := &warden.ClientConfig{}
client := warden.NewClient(conf)
conn, err := client.Dial(context.Background(), "discovery://default/"+v1.AppID)
if err != nil {
panic("依赖TitansConfig, 但是Titans的Client没有创建成功")
}
if titansConfig.TreeId == 0 {
panic("依赖了TitansConfig, 但是titansConfig的treeId配置为空")
}
titansConfigSdk = &titansSdk{}
titansConfigSdk.client = v1.NewTitansClient(conn)
titansConfigSdk.cache.Store(make(map[string]string))
load(titansConfigSdk, titansConfig.TreeId)
go update(titansConfigSdk, titansConfig.TreeId, titansConfig.Expire)
}
// update 定时更新
func update(sdk *titansSdk, treeId int64, expire int64) {
if expire < 1 {
expire = 5
}
for {
load(sdk, treeId)
time.Sleep(time.Duration(expire) * time.Second)
}
}
// load grpc接口
func load(sdk *titansSdk, treeId int64) {
for {
resp, err := sdk.client.GetByTreeId(context.Background(), &v1.TreeIdReq{TreeId: treeId})
if err != nil {
log.Error("[SyncTitansConfig][call resource][error], err:%+v", err)
} else {
sdk.cache.Store(resp.List)
break
}
time.Sleep(1 * time.Second)
}
}
// Get 获取配置接口
func Get(keyword string) (res string, err error) {
res = ""
cache, ok := titansConfigSdk.cache.Load().(map[string]string)
if !ok {
log.Error("[GetTitansConfig][cache content exception][error] content assert failed")
err = ecode.GetConfAdminErr
return
}
res, ok = cache[keyword]
if !ok || res == "" {
log.Error("[GetTitansConfig][cache content empty][Warn], keyword:%s, cache:%v", keyword, cache)
err = ecode.GetConfAdminErr
return
}
return
}

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/resource/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/grpc/v1:go_default_library",
"//app/service/live/resource/api/grpc/v2:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/service/v1:go_default_library",
"//app/service/live/resource/service/v2:go_default_library",
"//library/net/rpc/warden: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,26 @@
package grpc
import (
pb "go-common/app/service/live/resource/api/grpc/v1"
v2pb "go-common/app/service/live/resource/api/grpc/v2"
"go-common/app/service/live/resource/conf"
svc "go-common/app/service/live/resource/service/v1"
v2svc "go-common/app/service/live/resource/service/v2"
"go-common/library/net/rpc/warden"
)
// New
func New(c *conf.Config) *warden.Server {
ws := warden.NewServer(nil)
pb.RegisterResourceServer(ws.Server(), svc.NewResourceService(c))
pb.RegisterSplashServer(ws.Server(), svc.NewSplashService(c))
pb.RegisterBannerServer(ws.Server(), svc.NewBannerService(c))
pb.RegisterLiveCheckServer(ws.Server(), svc.NewLiveCheckService(c))
pb.RegisterTitansServer(ws.Server(), svc.NewTitansService(c))
v2pb.RegisterUserResourceServer(ws.Server(), v2svc.NewUserResourceService(c))
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"titans.go",
],
importpath = "go-common/app/service/live/resource/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/http/v1:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/service:go_default_library",
"//app/service/live/resource/service/v1:go_default_library",
"//library/ecode: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,62 @@
package http
import (
"go-common/app/service/live/resource/api/http/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/service"
v12 "go-common/app/service/live/resource/service/v1"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"net/http"
)
var (
srv *service.Service
vfy *verify.Verify
titansService *v12.TitansService
)
// Init init
func Init(c *conf.Config, srv *service.Service) {
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)
titansService = v12.NewTitansService(c)
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
e.GET("/xlive/internal/resource/v1/titans/getMyTreeApps", getNodes)
g := e.Group("/xlive/resource")
{
g.GET("/start", vfy.Verify, howToStart)
}
v1.RegisterV1TitansService(e, titansService, map[string]bm.HandlerFunc{})
}
func ping(c *bm.Context) {
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,33 @@
package http
import (
"context"
"go-common/app/service/live/resource/api/http/v1"
"go-common/library/ecode"
"go-common/library/net/http/blademaster"
"time"
)
func getNodes(c *blademaster.Context) {
res := map[string]interface{}{}
res["data"] = ""
cookie := c.Request.Header.Get("Cookie")
team := c.Request.FormValue("team")
node := c.Request.FormValue("node")
username, err := c.Request.Cookie("username")
if err != nil || cookie == "" || username == nil {
err = ecode.Error(1, "cookie未获取到")
c.JSONMap(res, err)
return
}
ctx, cancel := context.WithTimeout(c, 800*time.Millisecond)
defer cancel()
sRes, err := titansService.GetMyTreeApps(ctx, &v1.TreeAppsReq{
Team: team,
Node: node,
}, cookie, username.Value)
res["msg"] = ""
res["message"] = ""
res["data"] = sRes
c.JSONMap(res, err)
}

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 = ["service.go"],
importpath = "go-common/app/service/live/resource/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/dao:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/live/resource/service/v1:all-srcs",
"//app/service/live/resource/service/v2:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(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()
}

View File

@@ -0,0 +1,63 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"banner_test.go",
"liveCheck_test.go",
"resource_test.go",
"splash_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/live/resource/api/grpc/v1:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"banner.go",
"liveCheck.go",
"resource.go",
"splash.go",
"titans.go",
"tree.go",
],
importpath = "go-common/app/service/live/resource/service/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/grpc/v1:go_default_library",
"//app/service/live/resource/api/http/v1:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/dao:go_default_library",
"//app/service/live/resource/lrucache:go_default_library",
"//app/service/live/resource/model:go_default_library",
"//library/ecode: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,97 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/library/ecode"
)
// BannerService struct
type BannerService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewBannerService init
func NewBannerService(c *conf.Config) (s *BannerService) {
s = &BannerService{
conf: c,
dao: dao.New(c),
}
return s
}
const typeBanner = "banner"
// GetBlinkBanner implementation
// 获取有效闪屏配置
func (s *BannerService) GetBlinkBanner(ctx context.Context, req *v1pb.GetInfoReq) (resp *v1pb.GetInfoResp, err error) {
resp = &v1pb.GetInfoResp{}
reply, err := s.dao.GetInfo(ctx, typeBanner, req.Platform, req.Build)
if err != nil {
err = ecode.GetBannerErr
return
}
if reply == nil || reply.ID < 1 {
err = ecode.NothingFound
return
}
type updateImage struct {
JumpPath string `json:"JumpPath"`
JumpPathType int64 `json:"JumpPathType"`
JumpTime int64 `json:"JumpTime"`
ImageUrl string `json:"ImageUrl"`
}
imageInfo := reply.ImageInfo
imageInfoArr := &updateImage{}
json.Unmarshal([]byte(imageInfo), imageInfoArr)
resp.Id = reply.ID
resp.Title = reply.Title
resp.ImageUrl = imageInfoArr.ImageUrl
resp.JumpTime = imageInfoArr.JumpTime
resp.JumpPath = imageInfoArr.JumpPath
resp.JumpPathType = imageInfoArr.JumpPathType
return
}
// GetBanner implementation
func (s *BannerService) GetBanner(ctx context.Context, req *v1pb.GetBannerReq) (resp *v1pb.GetBannerResp, err error) {
resp = &v1pb.GetBannerResp{}
banners, err := s.dao.GetBanner(ctx, req.Platform, req.Build, req.Type)
if err != nil {
err = ecode.GetBannerErr
return
}
type updateImage struct {
JumpPath string `json:"JumpPath"`
JumpPathType int64 `json:"JumpPathType"`
JumpTime int64 `json:"JumpTime"`
ImageUrl string `json:"ImageUrl"`
}
if banners == nil {
return
}
for _, banner := range banners {
if banner.ID < 1 {
continue
}
imageInfo := banner.ImageInfo
imageInfoArr := &updateImage{}
json.Unmarshal([]byte(imageInfo), imageInfoArr)
b := &v1pb.GetBannerResp_List{}
b.Id = banner.ID
b.Title = banner.Title
b.ImageUrl = imageInfoArr.ImageUrl
b.JumpTime = imageInfoArr.JumpTime
b.JumpPath = imageInfoArr.JumpPath
b.JumpPathType = imageInfoArr.JumpPathType
resp.List = append(resp.List, b)
}
return
}

View File

@@ -0,0 +1,53 @@
package v1
import (
"context"
"flag"
"fmt"
"testing"
pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
s1 *BannerService
)
func init() {
flag.Set("conf", "../../cmd/test.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s1 = NewBannerService(conf.Conf)
}
// go test -test.v -test.run TestGetBannerInfo
func TestGetBannerInfo(t *testing.T) {
Convey("TestGetInfo", t, func() {
res, err := s.GetInfo(context.TODO(), &pb.GetInfoReq{
Platform: "android",
Build: 53100,
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestGetBanner
func TestGetBanner(t *testing.T) {
Convey("TestGetInfo", t, func() {
res, err := s1.GetBanner(context.TODO(), &pb.GetBannerReq{
Platform: "android",
Build: 53100,
Type: "xxx",
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,88 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/library/ecode"
"go-common/library/log"
)
// LiveCheckService struct
type LiveCheckService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewLiveCheckService init
func NewLiveCheckService(c *conf.Config) (s *LiveCheckService) {
s = &LiveCheckService{
conf: c,
dao: dao.New(c),
}
return s
}
// LiveCheck implementation
// 客户端获取能否直播接口
func (s *LiveCheckService) LiveCheck(ctx context.Context, req *v1pb.LiveCheckReq) (resp *v1pb.LiveCheckResp, err error) {
resp = &v1pb.LiveCheckResp{}
log.Info("[LiveCheck] platform is %s system is %s mobile is %s", req.Platform, req.System, req.Mobile)
if req.Platform == "" || req.Mobile == "" || req.System == "" {
err = ecode.ResourceParamErr
return
}
resp.IsLive = s.dao.GetLiveCheck(ctx, req.Platform, req.System, req.Mobile)
return
}
// GetLiveCheckList implementation
// 后台查询所有配置设备黑名单
func (s *LiveCheckService) GetLiveCheckList(ctx context.Context, req *v1pb.GetLiveCheckListReq) (resp *v1pb.GetLiveCheckListResp, err error) {
resp = &v1pb.GetLiveCheckListResp{}
value, err := s.dao.GetLiveCheckList(ctx)
if err != nil {
err = ecode.GetConfAdminErr
return
}
if value == "" {
err = ecode.GetConfAdminErr
return
}
err = json.Unmarshal([]byte(value), resp)
if err != nil {
log.Error("[LiveCheck] admin get live check conf error by wrong format")
err = ecode.GetConfAdminErr
return
}
return
}
// AddLiveCheck implementation
// 后台添加能否直播设备黑名单
func (s *LiveCheckService) AddLiveCheck(ctx context.Context, req *v1pb.AddLiveCheckReq) (resp *v1pb.AddLiveCheckResp, err error) {
resp = &v1pb.AddLiveCheckResp{}
value := req.LiveCheck
if value == "" {
err = ecode.ResourceParamErr
return
}
list := &v1pb.GetLiveCheckListResp{}
err = json.Unmarshal([]byte(value), list)
if err != nil {
err = ecode.ResourceParamErr
return
}
jsonStr, _ := json.Marshal(list)
err = s.dao.SetLiveCheck(ctx, string(jsonStr))
if err != nil {
err = ecode.SetConfAdminErr
return
}
return
}

View File

@@ -0,0 +1,50 @@
package v1
import (
"context"
"flag"
"path/filepath"
"testing"
"go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
testLiveCheckService *LiveCheckService
)
func init() {
dir, _ := filepath.Abs("../../cmd/test.toml")
flag.Set("conf", dir)
conf.Init()
testLiveCheckService = NewLiveCheckService(conf.Conf)
}
func Test_LiveCheck(t *testing.T) {
Convey("LiveCheck", t, func() {
_, err := testLiveCheckService.LiveCheck(context.TODO(), &v1.LiveCheckReq{
Platform: "ios",
System: "12.0",
Mobile: "iPhone 8",
})
So(err, ShouldBeNil)
})
}
func Test_GetLiveCheckList(t *testing.T) {
Convey("GetLiveCheckList", t, func() {
_, err := testLiveCheckService.GetLiveCheckList(context.TODO(), &v1.GetLiveCheckListReq{})
So(err, ShouldBeNil)
})
}
func Test_AddLiveCheck(t *testing.T) {
Convey("AddLiveCheck", t, func() {
_, err := testLiveCheckService.AddLiveCheck(context.TODO(), &v1.AddLiveCheckReq{
LiveCheck: `{"android":[],"ios":[{"system":"9.0","mobile":["iPhone 2G","iPhone 3G","iPhone 3GS","iPhone 4","iPhone 4S","iPhone 5","iPhone 5c"]}]}`,
})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,389 @@
package v1
import (
"context"
"encoding/json"
"regexp"
"time"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/app/service/live/resource/model"
"go-common/library/ecode"
)
// ResourceService struct
type ResourceService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewResourceService init
func NewResourceService(c *conf.Config) (s *ResourceService) {
s = &ResourceService{
conf: c,
dao: dao.New(c),
}
return s
}
func checkURL(s string) (r bool) {
reg, _ := regexp.Compile("^(https|http)://")
r = reg.MatchString(s)
return
}
// Add implementation
// Add 添加资源接口
func (s *ResourceService) Add(ctx context.Context, req *v1pb.AddReq) (resp *v1pb.AddResp, err error) {
type device struct {
Platform string `json:"platform"`
Build int64 `json:"build"`
Limit int64 `json:"limit"`
}
deviceArrs := make([]device, 0)
e := json.Unmarshal([]byte(req.Device), &deviceArrs)
if e != nil {
err = ecode.DeviceError
return
}
imageArr := make(map[string]interface{})
if checkURL(req.ImageUrl) == false {
err = ecode.CheckURLErr
return
}
imageArr["imageUrl"] = req.ImageUrl
if req.JumpPath != "" {
if checkURL(req.JumpPath) == false {
err = ecode.CheckURLErr
return
}
imageArr["jumpPath"] = req.JumpPath
}
if req.JumpPathType != 0 {
imageArr["jumpPathType"] = req.JumpPathType
}
if req.JumpTime != 0 {
imageArr["jumpTime"] = req.JumpTime
}
b, err := json.Marshal(imageArr)
if err != nil {
err = ecode.ResourceParamErr
return
}
resp = &v1pb.AddResp{}
loc, _ := time.LoadLocation("Local")
startTime, stErr := time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, loc)
if stErr != nil {
err = ecode.TimeForErr
return
}
endTime, etErr := time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, loc)
if etErr != nil {
err = ecode.TimeForErr
return
}
for _, da := range deviceArrs {
existInfo, errSe := s.dao.SelectByTypeAndPlatform(ctx, req.Type, da.Platform)
if errSe != nil {
err = ecode.AddResourceErr
return
}
if existInfo != nil {
err = ecode.RepdAddErr
return
}
}
for _, deviceArr := range deviceArrs {
insert := &model.Resource{
Platform: deviceArr.Platform,
Build: deviceArr.Build,
LimitType: deviceArr.Limit,
StartTime: startTime,
EndTime: endTime,
Type: req.Type,
Title: req.Title,
ImageInfo: string(b),
}
reply, _ := s.dao.AddResource(ctx, insert)
if reply <= 0 {
err = ecode.AddResourceErr
return
}
resp.Id = append(resp.Id, reply)
}
return
}
// AddEx implementation
// AddEx 添加资源接口
func (s *ResourceService) AddEx(ctx context.Context, req *v1pb.AddReq) (resp *v1pb.AddResp, err error) {
type device struct {
Platform string `json:"platform"`
Build int64 `json:"build"`
Limit int64 `json:"limit"`
}
deviceArrs := make([]device, 0)
e := json.Unmarshal([]byte(req.Device), &deviceArrs)
if e != nil {
err = ecode.DeviceError
return
}
imageArr := make(map[string]interface{})
if checkURL(req.ImageUrl) == false {
err = ecode.CheckURLErr
return
}
imageArr["imageUrl"] = req.ImageUrl
if req.JumpPath != "" {
if checkURL(req.JumpPath) == false {
err = ecode.CheckURLErr
return
}
imageArr["jumpPath"] = req.JumpPath
}
if req.JumpPathType != 0 {
imageArr["jumpPathType"] = req.JumpPathType
}
if req.JumpTime != 0 {
imageArr["jumpTime"] = req.JumpTime
}
b, err := json.Marshal(imageArr)
if err != nil {
err = ecode.ResourceParamErr
return
}
resp = &v1pb.AddResp{}
loc, _ := time.LoadLocation("Local")
startTime, stErr := time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, loc)
if stErr != nil {
err = ecode.TimeForErr
return
}
endTime, etErr := time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, loc)
if etErr != nil {
err = ecode.TimeForErr
return
}
for _, deviceArr := range deviceArrs {
insert := &model.Resource{
Platform: deviceArr.Platform,
Build: deviceArr.Build,
LimitType: deviceArr.Limit,
StartTime: startTime,
EndTime: endTime,
Type: req.Type,
Title: req.Title,
ImageInfo: string(b),
}
reply, _ := s.dao.AddResource(ctx, insert)
if reply <= 0 {
err = ecode.AddResourceErr
return
}
resp.Id = append(resp.Id, reply)
}
return
}
//Edit implementation
//Edit 编辑资源接口
func (s *ResourceService) Edit(ctx context.Context, req *v1pb.EditReq) (resp *v1pb.EditResp, err error) {
resp = &v1pb.EditResp{}
update := make(map[string]interface{})
resourceInfo, err := s.dao.SelectById(ctx, req.Id)
if err != nil || resourceInfo == nil {
err = ecode.SeltResErr
return
}
if resourceInfo.ID == 0 {
err = ecode.SeltResErr
return
}
imageInfo := resourceInfo.ImageInfo
imageInfoArr := make(map[string]interface{})
e := json.Unmarshal([]byte(imageInfo), &imageInfoArr)
if e != nil {
err = ecode.ResourceParamErr
return
}
if req.Title != "" {
update["title"] = req.Title
}
loc, _ := time.LoadLocation("Local")
if req.StartTime != "" {
update["start_time"], _ = time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, loc)
}
if req.EndTime != "" {
update["end_time"], _ = time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, loc)
}
if req.JumpPath != "" {
if checkURL(req.JumpPath) == false {
err = ecode.CheckURLErr
return
}
imageInfoArr["jumpPath"] = req.JumpPath
}
if req.JumpPathType != 0 {
imageInfoArr["jumpPathType"] = req.JumpPathType
}
if req.JumpTime != 0 {
imageInfoArr["jumpTime"] = req.JumpTime
}
if req.ImageUrl != "" {
if checkURL(req.ImageUrl) == false {
err = ecode.CheckURLErr
return
}
imageInfoArr["imageUrl"] = req.ImageUrl
}
if imageInfoArr != nil {
b, e := json.Marshal(imageInfoArr)
if e != nil || b == nil {
err = ecode.ResourceParamErr
return
}
update["image_info"] = string(b)
}
reply, err := s.dao.EditResource(ctx, req.Id, update)
if err != nil || reply <= 0 {
err = ecode.EditResErr
return
}
return
}
// Offline implementation
// Offline 下线资源接口
func (s *ResourceService) Offline(ctx context.Context, req *v1pb.OfflineReq) (resp *v1pb.OfflineResp, err error) {
resp = &v1pb.OfflineResp{}
_, err = s.dao.OfflineResource(ctx, req.Id)
if err != nil {
err = ecode.OfflineResErr
return
}
return
}
// GetList implementation
// GetList 获取资源列表
func (s *ResourceService) GetList(ctx context.Context, req *v1pb.GetListReq) (resp *v1pb.GetListResp, err error) {
resp = &v1pb.GetListResp{}
reply, err := s.dao.GetResourceList(ctx, req.Type, req.Page, req.PageSize)
count, err := s.dao.GetDBCount(ctx, req.Type)
if err != nil {
err = ecode.GetListResErr
return
}
for _, v := range reply {
type updateImage struct {
JumpPath string `json:"JumpPath"`
JumpPathType int64 `json:"JumpPathType"`
JumpTime int64 `json:"JumpTime"`
ImageUrl string `json:"ImageUrl"`
}
ImageArr := &updateImage{}
e := json.Unmarshal([]byte(v.ImageInfo), ImageArr)
if e != nil {
continue
}
var status int64
if v.EndTime.Unix() <= time.Now().Unix() {
status = -1
}
if (v.StartTime.Unix() <= time.Now().Unix()) && v.EndTime.Unix() > time.Now().Unix() {
status = 1
}
list := &v1pb.GetListResp_List{}
list.Id = v.ID
list.ImageUrl = ImageArr.ImageUrl
list.JumpPath = ImageArr.JumpPath
list.StartTime = v.StartTime.Format("2006-01-02 15:04:05")
list.EndTime = v.EndTime.Format("2006-01-02 15:04:05")
list.DevicePlatform = v.Platform
list.DeviceBuild = v.Build
list.DeviceLimit = v.LimitType
list.Title = v.Title
list.Status = status
list.JumpPathType = ImageArr.JumpPathType
list.JumpTime = ImageArr.JumpTime
resp.List = append(resp.List, list)
}
resp.CurrentPage = req.Page
resp.TotalCount = count
return
}
// GetPlatformList implementation
// 获取平台列表
func (s *ResourceService) GetPlatformList(ctx context.Context, req *v1pb.GetPlatformListReq) (resp *v1pb.GetPlatformListResp, err error) {
resp = &v1pb.GetPlatformListResp{}
pList := []string{"ios", "ios_link", "android", "android_link", "ipad", "pc_link"}
resp = &v1pb.GetPlatformListResp{
Platform: pList,
}
return
}
// GetListEx implementation
// GetListEx 获取资源列表
func (s *ResourceService) GetListEx(ctx context.Context, req *v1pb.GetListExReq) (resp *v1pb.GetListExResp, err error) {
resp = &v1pb.GetListExResp{}
reply, count, err := s.dao.GetResourceListEx(ctx, req.Type, req.Page, req.PageSize, req.DevicePlatform, req.Status, req.StartTime, req.EndTime)
if err != nil {
err = ecode.GetListResErr
return
}
for _, v := range reply {
type updateImage struct {
JumpPath string `json:"JumpPath"`
JumpPathType int64 `json:"JumpPathType"`
JumpTime int64 `json:"JumpTime"`
ImageUrl string `json:"ImageUrl"`
}
ImageArr := &updateImage{}
e := json.Unmarshal([]byte(v.ImageInfo), ImageArr)
if e != nil {
continue
}
var status int64
if v.EndTime.Unix() <= time.Now().Unix() {
status = -1
}
if (v.StartTime.Unix() <= time.Now().Unix()) && v.EndTime.Unix() > time.Now().Unix() {
status = 1
}
list := &v1pb.GetListExResp_List{}
list.Id = v.ID
list.ImageUrl = ImageArr.ImageUrl
list.JumpPath = ImageArr.JumpPath
list.StartTime = v.StartTime.Format("2006-01-02 15:04:05")
list.EndTime = v.EndTime.Format("2006-01-02 15:04:05")
list.DevicePlatform = v.Platform
list.DeviceBuild = v.Build
list.DeviceLimit = v.LimitType
list.Title = v.Title
list.Status = status
list.JumpPathType = ImageArr.JumpPathType
list.JumpTime = ImageArr.JumpTime
list.Type = v.Type
resp.List = append(resp.List, list)
}
resp.CurrentPage = req.Page
resp.TotalCount = count
return
}

View File

@@ -0,0 +1,88 @@
package v1
import (
"context"
"flag"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
)
var (
srv *ResourceService
)
func init() {
flag.Set("conf", "../../cmd/test.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
srv = NewResourceService(conf.Conf)
}
// go test -test.v -test.run TestAdd
func TestAdd(t *testing.T) {
Convey("TestAdd", t, func() {
res, err := srv.Add(context.TODO(), &pb.AddReq{
Platform: "mng",
Title: "splash first",
JumpPath: "www.sina.com",
JumpPathType: 1,
JumpTime: 3,
Type: "splash",
Device: "[{\"platform\":\"pc\",\"build\":3,\"limit\":1}]",
StartTime: "2018-01-01 00:00:00",
EndTime: "2018-11-10 00:00:00",
ImageUrl: "www.baidu.com",
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
func TestEdit(t *testing.T) {
Convey("TestEdit", t, func() {
res, err := srv.Edit(context.TODO(), &pb.EditReq{
Platform: "mng",
Id: 23,
Title: "splash second",
JumpPath: "www.sina.com",
JumpPathType: 1,
JumpTime: 6,
StartTime: "2018-1-1 00:00:00",
EndTime: "2018-1-9 00:00:00",
ImageUrl: "www.sina.com",
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
func TestGetList(t *testing.T) {
Convey("TestGetList", t, func() {
res, err := srv.GetList(context.TODO(), &pb.GetListReq{
Platform: "mng",
Type: "splash",
Page: 1,
PageSize: 10,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
func TestOffline(t *testing.T) {
Convey("TestOffline", t, func() {
res, err := srv.Offline(context.TODO(), &pb.OfflineReq{
Platform: "mng",
Id: 23,
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,62 @@
package v1
import (
"context"
"encoding/json"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/library/ecode"
)
// SplashService struct
type SplashService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewSplashService init
func NewSplashService(c *conf.Config) (s *SplashService) {
s = &SplashService{
conf: c,
dao: dao.New(c),
}
return s
}
const typeSplash = "splash"
// GetInfo implementation
// 获取有效闪屏配置
func (s *SplashService) GetInfo(ctx context.Context, req *v1pb.GetInfoReq) (resp *v1pb.GetInfoResp, err error) {
resp = &v1pb.GetInfoResp{}
reply, err := s.dao.GetInfo(ctx, typeSplash, req.Platform, req.Build)
if err != nil {
err = ecode.GetSplashErr
return
}
if reply == nil || reply.ID < 1 {
err = ecode.NothingFound
return
}
type updateImage struct {
JumpPath string `json:"JumpPath"`
JumpPathType int64 `json:"JumpPathType"`
JumpTime int64 `json:"JumpTime"`
ImageUrl string `json:"ImageUrl"`
}
imageInfo := reply.ImageInfo
imageInfoArr := &updateImage{}
json.Unmarshal([]byte(imageInfo), imageInfoArr)
resp.Id = reply.ID
resp.Title = reply.Title
resp.ImageUrl = imageInfoArr.ImageUrl
resp.JumpTime = imageInfoArr.JumpTime
resp.JumpPath = imageInfoArr.JumpPath
resp.JumpPathType = imageInfoArr.JumpPathType
return
}

View File

@@ -0,0 +1,39 @@
package v1
import (
"context"
"flag"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
pb "go-common/app/service/live/resource/api/grpc/v1"
"go-common/app/service/live/resource/conf"
)
var (
s *SplashService
)
func init() {
flag.Set("conf", "../../cmd/test.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = NewSplashService(conf.Conf)
}
// go test -test.v -test.run TestAdd
func TestGetInfo(t *testing.T) {
Convey("TestGetInfo", t, func() {
res, err := s.GetInfo(context.TODO(), &pb.GetInfoReq{
Platform: "android",
Build: 53100,
})
fmt.Println(res, err)
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,505 @@
package v1
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/live/resource/lrucache"
"go-common/app/service/live/resource/model"
"go-common/library/log"
"strconv"
"strings"
"time"
v1pb "go-common/app/service/live/resource/api/grpc/v1"
v1hpb "go-common/app/service/live/resource/api/http/v1"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/library/ecode"
)
// TitansService struct
type TitansService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
//lruCache
treeCache *lrucache.SyncCache
titansCache *lrucache.SyncCache
}
// NewTitansService init
func NewTitansService(c *conf.Config) (s *TitansService) {
length := 10
treeCache := lrucache.NewSyncCache(length, 100, 600)
titansCache := lrucache.NewSyncCache(length, 100, 60)
s = &TitansService{
conf: c,
dao: dao.New(c),
treeCache: treeCache,
titansCache: titansCache,
}
//启动同步流程
go s.SyncConfig()
return s
}
const (
_titansLruCache = "titans_cache_treeId:%d"
)
// GetConfigByKeyword implementation
// http获取team下某个keyword的配置 `internal:"true"`
func (s *TitansService) GetConfigByKeyword(ctx context.Context, req *v1pb.GetConfigReq) (resp *v1pb.GetConfigResp, err error) {
resp = &v1pb.GetConfigResp{}
team := req.GetTeam()
keyword := req.GetKeyword()
if 0 == req.GetId() {
err = s.dao.CheckParams(ctx, team, keyword)
if err != nil {
err = ecode.Error(ecode.ParamInvalid, "必要参数不准为空")
return
}
}
res, err := s.dao.SelectByTeamIndex(ctx, team, keyword, req.GetId())
if err != nil {
//errors.Wrap(err, "系统错误")
return
}
resp = &v1pb.GetConfigResp{
Team: res.Team,
Keyword: res.Keyword,
// 配置值
Value: res.Value,
// 配置解释
Name: res.Name,
// 创建时间
Ctime: res.Ctime,
//最近更新时间
Mtime: res.Ctime,
Status: res.Status,
Id: res.Id,
}
return
}
// SetConfigByKeyword implementation
// http设置team下某个keyword配置 `internal:"true"`
func (s *TitansService) SetConfigByKeyword(ctx context.Context, req *v1pb.SetConfigReq) (resp *v1pb.SetConfigResp, err error) {
resp = &v1pb.SetConfigResp{}
if "" == req.GetKeyword() {
err = ecode.Error(ecode.ParamInvalid, "必要参数不准为空")
return
}
id, count, err := s.dao.InsertRecord(ctx, req.GetTeam(), req.GetKeyword(), req.GetValue(), req.GetName(), req.Status, req.GetId())
if nil != err {
err = ecode.Error(ecode.ServerErr, "系统错误")
return
}
if 0 != count {
err = ecode.Error(
11,
"分组"+strconv.Itoa(int(req.GetTeam()))+"内已存在"+req.GetKeyword()+"的配置",
)
return
}
resp.Id = id
return
}
// GetConfigsByParams implementation
// http管理后台根据条件获取配置 `internal:"true"`
func (s *TitansService) GetConfigsByParams(ctx context.Context, req *v1pb.ParamsConfigReq) (resp *v1pb.ParamsConfigResp, err error) {
resp = &v1pb.ParamsConfigResp{}
list, count, err := s.dao.SelectByParams(ctx, req.GetId(), req.GetTeam(), req.GetKeyword(), req.GetName(), req.GetStatus(), req.GetPage(), req.GetPageSize())
if nil != err {
err = ecode.Error(ecode.ServerErr, "系统错误")
return
}
resp.List = []*v1pb.List{}
for _, v := range list {
resp.List = append(resp.List, &v1pb.List{
Id: v.Id,
Team: v.Team,
Keyword: v.Keyword,
Name: v.Name,
Value: v.Value,
Ctime: v.Ctime,
Mtime: v.Mtime,
Status: v.Status,
})
}
resp.TotalNum = count
return
}
// GetConfigsByLikes implementation
// grpc获取多个team或索引的的全部配置 `internal:"true"`
func (s *TitansService) GetConfigsByLikes(ctx context.Context, req *v1pb.LikesConfigReq) (resp *v1pb.LikesConfigResp, err error) {
resp = &v1pb.LikesConfigResp{}
params := req.GetParams()
teams := make([]int64, 0)
teamKeys := make([]*dao.TeamKeyword, 0)
for _, v := range params {
strArr := strings.Split(v, ".")
team, _ := strconv.ParseInt(strArr[0], 10, 64)
if team != 0 && len(strArr) == 1 {
teams = append(teams, team)
}
if len(strArr) == 2 && team != 0 {
teamKeys = append(teamKeys, &dao.TeamKeyword{Team: team, Keyword: strArr[1]})
}
}
items, err := s.dao.SelectByLikes(ctx, teams, teamKeys)
if err != nil {
return
}
mapParent := make(map[int64]*v1pb.Child)
for _, v := range items {
parentSet(mapParent, v.Team, v.Keyword, v.Value)
}
resp.List = mapParent
return
}
// parentSet format数据
func parentSet(parent map[int64]*v1pb.Child, index int64, keyword string, value string) {
_, ok := parent[index]
if !ok {
parent[index] = &v1pb.Child{}
parent[index].Keys = make(map[string]string)
}
parent[index].Keys[keyword] = value
}
// parentHSet format数据
func parentHSet(parent map[int64]*v1hpb.MChild, index int64, keyword string, value string) {
_, ok := parent[index]
if !ok {
parent[index] = &v1hpb.MChild{}
parent[index].Keys = make(map[string]string)
}
parent[index].Keys[keyword] = value
}
// GetMultiConfigs implementation
// http获取配置 请求参数逗号隔开的字符串 返回`internal:"true"`
func (s *TitansService) GetMultiConfigs(ctx context.Context, req *v1hpb.MultiConfigReq) (resp *v1hpb.MultiConfigResp, err error) {
resp = &v1hpb.MultiConfigResp{}
params := strings.Split(req.GetValues(), ",")
teams := make([]int64, 0)
teamKeys := make([]*dao.TeamKeyword, 0)
for _, v := range params {
strArr := strings.Split(v, ".")
team, _ := strconv.ParseInt(strArr[0], 10, 64)
if team != 0 && len(strArr) == 1 {
teams = append(teams, team)
}
if len(strArr) == 2 && team != 0 {
teamKeys = append(teamKeys, &dao.TeamKeyword{Team: team, Keyword: strArr[1]})
}
}
items, err := s.dao.SelectByLikes(ctx, teams, teamKeys)
if err != nil {
return
}
mapParent := make(map[int64]*v1hpb.MChild)
for _, v := range items {
parentHSet(mapParent, v.Team, v.Keyword, v.Value)
}
resp.List = mapParent
return
}
// GetServiceConfig implementation
// http获取服务tree_id对应的配置 `internal:"true"`
func (s *TitansService) GetServiceConfig(ctx context.Context, req *v1hpb.ServiceConfigReq) (resp *v1hpb.ServiceConfigResp, err error) {
resp = &v1hpb.ServiceConfigResp{}
treeId := req.GetTreeId()
if 0 == treeId {
err = ecode.Error(ecode.InvalidParam, "tree_id 为空")
return
}
cacheKey := fmt.Sprintf(_titansLruCache, treeId)
// 读取lruCache
cacheValue, ok := s.titansCache.Get(cacheKey)
if ok {
resp.List = cacheValue.(map[string]string)
return
}
value, err := s.dao.GetServiceConfig(ctx, treeId)
if nil != err {
err = ecode.Error(ecode.ServerErr, "内部错误")
return
}
resp.List = value
// 存lruCache
s.titansCache.Put(cacheKey, value)
return
}
// SetServiceConfig implementation
// http插入服务配置 `method:"POST", internal:"true"`
func (s *TitansService) SetServiceConfig(ctx context.Context, req *v1hpb.SetReq) (resp *v1hpb.SetResp, err error) {
resp = &v1hpb.SetResp{}
if 0 == req.GetTreeId() || "" == req.GetTreeName() || "" == req.GetKeyword() {
err = ecode.Error(ecode.ParamInvalid, "服务的tree_name, tree_id, keyword必传")
return
}
if len(req.GetKeyword()) > 16 {
err = ecode.Error(ecode.ParamInvalid, "keyword长度不能超过16")
return
}
if len(req.GetValue()) > 4096 {
err = ecode.Error(ecode.ParamInvalid, "配置内容长度不能超过4096")
return
}
if "" != req.GetValue() {
if !json.Valid([]byte(req.GetValue())) {
err = ecode.Error(ecode.InvalidParam, "配置的内容必须为json")
return
}
}
id, err := s.dao.InsertServiceConfig(
ctx, req.GetId(),
req.GetTreeName(),
req.GetTreePath(),
req.GetTreeId(),
req.GetService(),
req.GetKeyword(),
req.GetTemplate(),
req.GetName(),
req.GetValue(),
req.GetStatus())
if nil != err {
err = ecode.Error(ecode.ServerErr, "内部错误")
return
}
if -1 == id {
err = ecode.Error(ecode.InvalidParam, "同一个tree_id下keyword配置重复请确认修改")
return
}
resp.Id = id
// 编辑操作后清一下lrucache
s.titansCache.Delete(fmt.Sprintf(_titansLruCache, req.GetTreeId()))
return
}
// GetServiceConfigList implementation
// http管理后台获取服务级配置 `internal:"true"`
func (s *TitansService) GetServiceConfigList(ctx context.Context, req *v1hpb.ServiceListReq) (resp *v1hpb.ServiceListResp, err error) {
resp = &v1hpb.ServiceListResp{}
if "" == req.GetTreeName() {
err = ecode.Error(ecode.InvalidParam, "服务树根名不能为空")
return
}
if req.GetTreeId() == 0 && (req.GetName() != "" || req.GetService() != "") {
err = ecode.Error(ecode.InvalidParam, "通过描述名称查询时tree_id不准为空")
return
}
page := req.GetPage()
pageSize := req.GetPageSize()
if pageSize == 0 {
pageSize = 30
}
if page == 0 {
page = 1
}
resp.List, resp.TotalNum, err = s.dao.GetServiceConfigList(ctx, req.GetTreeName(), req.GetTreeId(), req.GetKeyword(), req.GetService(), page, pageSize, req.GetName(), req.GetStatus())
return
}
// GetTreeIds implementation
// http获取已配置的discoveryId `internal:"true"`
func (s *TitansService) GetTreeIds(ctx context.Context, req *v1hpb.TreeIdsReq) (resp *v1hpb.TreeIdsResp, err error) {
resp = &v1hpb.TreeIdsResp{}
if "" == req.GetTreeName() {
err = ecode.Error(ecode.InvalidParam, "tree_name 为空")
return
}
resp.List, _ = s.dao.GetTreeIds(ctx, req.GetTreeName())
return
}
// GetByTreeId implementation
// grpc获取tree_id对应的全部配置 `internal:"true"`
func (s *TitansService) GetByTreeId(ctx context.Context, req *v1pb.TreeIdReq) (resp *v1pb.TreeIdResp, err error) {
resp = &v1pb.TreeIdResp{}
treeId := req.GetTreeId()
if 0 == treeId {
err = ecode.Error(ecode.InvalidParam, "tree_id 为空")
return
}
value, err := s.dao.GetServiceConfig(ctx, treeId)
if nil != err {
err = ecode.Error(ecode.ServerErr, "内部错误")
return
}
resp.List = value
return
}
// GetMyTreeApps implementation
// 获取用户的应用树
func (s *TitansService) GetMyTreeApps(ctx context.Context, req *v1hpb.TreeAppsReq, cookie string, user string) (resp *v1hpb.TreeAppsResp, err error) {
resp = &v1hpb.TreeAppsResp{}
resp.List, err = s.Nodes(ctx, user, req.Node, req.Team, cookie)
return
}
// SyncConfig job同步配置
func (s *TitansService) SyncConfig() {
nodesList := []string{"live"}
ctx := context.Background()
for {
// 获取tree_id列表
for _, node := range nodesList {
list, err := s.dao.GetTreeIds(ctx, node)
if err != nil {
log.Error("[Titans][syncConfig error][get tree_id list], err: %+v", err)
continue
}
//通过tree_id获取对应配置
if len(list) > 0 {
for _, treeId := range list {
value, err := s.dao.GetServiceConfig(ctx, treeId)
if err != nil {
log.Error("[Titans][syncConfig error][get tree_id config], tree_id"+strconv.Itoa(int(treeId))+"err: %+v", err)
continue
}
s.titansCache.Put(fmt.Sprintf(_titansLruCache, treeId), value)
}
}
log.Info("[Titans][syncConfig][sync success], node:" + node + ", tree_id num :" + strconv.Itoa(len(list)))
}
time.Sleep(30 * time.Second)
}
}
// GetEasyList implementation
// 获取运营数据列表 `internal:"true"`
func (s *TitansService) GetEasyList(ctx context.Context, req *v1hpb.EasyGetReq) (resp *v1hpb.EasyGetResp, err error) {
resp = &v1hpb.EasyGetResp{}
resp.List = []*v1hpb.EasyList{}
list := s.dao.GetEasyRecord(ctx, "live")
if list.Value == "" {
return
}
dbValue := map[string][]int64{}
err = json.Unmarshal([]byte(list.Value), &dbValue)
ids := dbValue["list"]
if err != nil || len(ids) == 0 {
return
}
pageSize := 100
dbIds := make([]int64, 0)
begin := (int(req.GetPage()) - 1) * pageSize
end := int(req.GetPage()) * pageSize
for k, v := range ids {
if req.GetId() == v {
dbIds = append(dbIds, v)
break
}
if k >= begin && k < end {
ids = append(ids, v)
}
}
if req.GetId() != 0 && len(dbIds) == 0 {
return
}
dbRes := []*model.ServiceModel{}
if req.GetId() != 0 && len(dbIds) != 0 {
dbRes, err = s.dao.GetListByIds(ctx, dbIds)
} else {
dbRes, err = s.dao.GetListByIds(ctx, ids)
}
if err != nil {
return
}
for _, v := range dbRes {
item := &v1hpb.EasyList{
TreeName: v.TreeName,
TreePath: v.TreePath,
TreeId: v.TreeId,
Keyword: v.Keyword,
Name: v.Name,
}
resp.List = append(resp.List, item)
}
return
}
// SetEasyList implementation
// 设置运营列表 `internal:"true"`
func (s *TitansService) SetEasyList(ctx context.Context, req *v1hpb.EasySetReq) (resp *v1hpb.EasySetResp, err error) {
resp = &v1hpb.EasySetResp{}
if req.GetId() == 0 {
err = ecode.Error(ecode.InvalidParam, "记录id不能为空")
return
}
ids := []int64{req.GetId()}
list, err := s.dao.GetListByIds(ctx, ids)
if err != nil {
return
}
if len(list) == 0 || list[0] == nil {
err = ecode.Error(ecode.InvalidParam, "记录信息为空")
return
}
template := list[0].Template
if template == 0 {
err = ecode.Error(ecode.InvalidParam, "同步到运营操作的记录必须选择个模型")
return
}
if list[0].Name == "" {
err = ecode.Error(ecode.InvalidParam, "同步到运营操作的记录必须加个描述")
return
}
treeName := list[0].TreeName
//获取easyList
easy := s.dao.GetEasyRecord(ctx, treeName)
easyValue := map[string][]int64{}
easyValue["list"] = make([]int64, 0)
if easy == nil || easy.Id == 0 {
//新增
easyValue["list"] = append(easyValue["list"], req.GetId())
} else {
err = json.Unmarshal([]byte(easy.Value), &easyValue)
if err != nil {
return
}
if easyValue["list"] == nil {
easyValue["list"] = append(easyValue["list"], req.GetId())
} else {
//编辑的时候,进行更新
for _, v := range easyValue["list"] {
if v == req.GetId() {
err = ecode.Error(ecode.InvalidParam, "已经在运营列表里了哟~")
return
}
}
easyValue["list"] = append(easyValue["list"], req.GetId())
}
}
value, err := json.Marshal(easyValue)
if err != nil {
return
}
valueDb := string(value)
//插入数据
resp.EId, err = s.dao.SetEasyRecord(ctx, treeName, valueDb, easy.Id)
return
}

View File

@@ -0,0 +1,133 @@
package v1
import (
"bytes"
"context"
"encoding/json"
"fmt"
"go-common/app/service/live/resource/api/http/v1"
"go-common/app/service/live/resource/model"
"go-common/library/ecode"
"go-common/library/log"
"strings"
"time"
)
const (
_treeNodes = "treeNodes_name:%s"
)
// Nodes node.
func (s *TitansService) Nodes(ctx context.Context, user, node, team, cookie string) (res []*v1.Node, err error) {
var nodes *model.CacheData
if nodes, err = s.AuthApps(ctx, user, cookie); err != nil {
return
}
//node list.
if node == "" && team == "" {
tmp := make(map[string]struct{})
for _, app := range nodes.Data {
idx := strings.Index(app.Path, ".")
bu := string([]byte(app.Path)[:idx])
if _, ok := tmp[bu]; ok {
continue
}
n := new(v1.Node)
n.Name = bu
n.Path = bu
res = append(res, n)
tmp[bu] = struct{}{}
}
return
}
//team list.
if node != "" && team == "" {
tmp := make(map[string]struct{})
for _, app := range nodes.Data {
s := []byte(app.Path)
sep := []byte(".")
fidx := bytes.Index(s, sep)
lidx := bytes.LastIndex(s, sep)
team = string(s[:lidx])
if node == string(s[:fidx]) {
if _, ok := tmp[team]; ok {
continue
}
n := new(v1.Node)
n.Name = string([]byte(app.Path)[fidx+1 : lidx])
n.Path = team
tmp[team] = struct{}{}
res = append(res, n)
}
}
return
}
//app list.
if team == "" {
return
}
for _, app := range nodes.Data {
s := []byte(app.Path)
sep := []byte(".")
lidx := bytes.LastIndex(s, sep)
t := string(s[:lidx])
if team != t {
continue
}
n := new(v1.Node)
n.Name = string(s[lidx+1:])
n.Path = app.Path
n.TreeId = app.ID
res = append(res, n)
}
return
}
// AuthApps 获取用户节点权限.
func (s *TitansService) AuthApps(ctx context.Context, user string, cookie string) (nodes *model.CacheData, err error) {
if len(user) == 0 {
err = ecode.NothingFound
return
}
var ok bool
cacheKey := fmt.Sprintf(_treeNodes, user)
nodesCache, ok := s.treeCache.Get(cacheKey)
cacheStr, _ := json.Marshal(nodesCache)
nodes = &model.CacheData{}
json.Unmarshal(cacheStr, nodes)
if !ok || (time.Since(nodes.CTime) > 60*time.Second) {
log.Info("[Titans][Tree] miss lruCache call for tree service")
nodes, err = s.SyncTree(ctx, user, cookie)
s.treeCache.Put(cacheKey, nodes)
}
return
}
//SyncTree syncTree.
func (s *TitansService) SyncTree(ctx context.Context, user string, cookie string) (nodes *model.CacheData, err error) {
var (
msg map[string]interface{}
tmp interface{}
token string
ok bool
)
if msg, err = s.dao.Auth(ctx, cookie); err != nil {
return
}
if tmp, ok = msg["token"]; !ok {
err = ecode.NothingFound
return
}
if token, ok = tmp.(string); !ok {
err = ecode.NothingFound
return
}
//data, _ := s.dao.Tree(ctx, token)
if nodes, err = s.dao.Role(ctx, user, token); err != nil {
return
}
return
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["userResource.go"],
importpath = "go-common/app/service/live/resource/service/v2",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/resource/api/grpc/v2:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//app/service/live/resource/dao:go_default_library",
"//app/service/live/resource/model:go_default_library",
"//library/ecode: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"],
)
go_test(
name = "go_default_test",
srcs = ["userResource_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/live/resource/api/grpc/v2:go_default_library",
"//app/service/live/resource/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,197 @@
package v2
import (
"context"
v2pb "go-common/app/service/live/resource/api/grpc/v2"
"go-common/app/service/live/resource/conf"
"go-common/app/service/live/resource/dao"
"go-common/app/service/live/resource/model"
"go-common/library/ecode"
"go-common/library/log"
)
// UserResourceService struct
type UserResourceService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
}
//NewUserResourceService init
func NewUserResourceService(c *conf.Config) (s *UserResourceService) {
s = &UserResourceService{
conf: c,
dao: dao.New(c),
}
return s
}
// Add implementation
// Add 添加资源接口
func (s *UserResourceService) Add(ctx context.Context, req *v2pb.AddReq) (resp *v2pb.AddResp, err error) {
resp = &v2pb.AddResp{}
// 查询新的资源新的资源ID = 现有的最大ID + 1
customID, err := s.dao.GetMaxCustomID(ctx, req.ResType)
if err != nil {
log.Error("查找最大的资源ID res_type : %d : %v", req.ResType, err)
return
}
customID++
res := &model.UserResource{
ResType: req.ResType,
CustomID: customID,
Title: req.Title,
URL: req.Url,
Weight: req.Weight,
Status: 0,
Creator: req.Creator,
}
// 插入新资源
info, err := s.dao.AddUserResource(ctx, res)
if err != nil {
log.Error("resource.addSResource d.db.Exec err: %v", err)
}
resp.Id = info.ID
resp.ResType = info.ResType
resp.CustomId = info.CustomID
resp.Title = info.Title
resp.Url = info.URL
resp.Weight = info.Weight
resp.Creator = info.Creator
resp.Status = info.Status
resp.Ctime = info.Ctime.Format("2006-01-02 15:04:05")
resp.Mtime = info.Mtime.Format("2006-01-02 15:04:05")
return
}
// Edit 编辑现有资源
func (s *UserResourceService) Edit(ctx context.Context, req *v2pb.EditReq) (resp *v2pb.EditResp, err error) {
resp = &v2pb.EditResp{}
info, err := s.dao.GetUserResourceInfo(ctx, req.ResType, req.CustomId)
if info.ID <= 0 {
err = ecode.EditResErr
return
}
update := make(map[string]interface{})
// 名称
if req.Title != "" {
update["title"] = req.Title
}
// 链接
if req.Url != "" {
update["url"] = req.Url
}
// 权重
if req.Weight > 0 {
update["weight"] = req.Weight
}
effectRow, info, err := s.dao.EditUserResource(ctx, req.ResType, req.CustomId, update)
if err != nil || effectRow <= 0 {
err = ecode.EditResErr
return
}
resp.Id = info.ID
resp.ResType = info.ResType
resp.CustomId = info.CustomID
resp.Title = info.Title
resp.Url = info.URL
resp.Weight = info.Weight
resp.Creator = info.Creator
resp.Status = info.Status
resp.Ctime = info.Ctime.Format("2006-01-02 15:04:05")
resp.Mtime = info.Mtime.Format("2006-01-02 15:04:05")
return
}
// Query 请求单个资源
func (s *UserResourceService) Query(ctx context.Context, req *v2pb.QueryReq) (resp *v2pb.QueryResp, err error) {
resp = &v2pb.QueryResp{}
info, err := s.dao.GetUserResourceInfo(ctx, req.ResType, req.CustomId)
if err != nil {
return
}
resp.Id = info.ID
resp.ResType = info.ResType
resp.CustomId = info.CustomID
resp.Title = info.Title
resp.Url = info.URL
resp.Weight = info.Weight
resp.Creator = info.Creator
resp.Status = info.Status
resp.Ctime = info.Ctime.Format("2006-01-02 15:04:05")
resp.Mtime = info.Mtime.Format("2006-01-02 15:04:05")
return
}
// List 获取资源列表
func (s *UserResourceService) List(ctx context.Context, req *v2pb.ListReq) (resp *v2pb.ListResp, err error) {
var Page int32 = 1
var pageSize int32 = 50
if req.Page > 0 {
Page = req.Page
}
if req.PageSize > 0 {
pageSize = req.PageSize
}
resp = &v2pb.ListResp{}
resp.CurrentPage = Page
resp.TotalCount, _ = s.dao.GetMaxCustomID(ctx, req.ResType)
list, err := s.dao.ListUserResourceInfo(ctx, req.ResType, Page, pageSize)
if len(list) <= 0 {
return
}
for _, v := range list {
elem := &v2pb.ListResp_List{}
elem.Id = v.ID
elem.ResType = v.ResType
elem.CustomId = v.CustomID
elem.Title = v.Title
elem.Url = v.URL
elem.Weight = v.Weight
elem.Creator = v.Creator
elem.Status = v.Status
elem.Ctime = v.Ctime.Format("2006-01-02 15:04:05")
elem.Mtime = v.Mtime.Format("2006-01-02 15:04:05")
resp.List = append(resp.List, elem)
}
return
}
// SetStatus implementation
// SetStatus 更改资源状态
func (s *UserResourceService) SetStatus(ctx context.Context, req *v2pb.SetStatusReq) (resp *v2pb.SetStatusResp, err error) {
resp = &v2pb.SetStatusResp{}
effectRow, err := s.dao.SetUserResourceStatus(ctx, req.ResType, req.CustomId, req.Status)
if err != nil || effectRow == 0 {
err = ecode.EditResErr
return
}
return
}

View File

@@ -0,0 +1,173 @@
package v2
import (
"context"
"flag"
"testing"
"time"
pb "go-common/app/service/live/resource/api/grpc/v2"
"go-common/app/service/live/resource/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
urs *UserResourceService
)
func init() {
flag.Set("conf", "../../cmd/user_resource.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
urs = NewUserResourceService(conf.Conf)
}
// go test -test.v -test.run TestAddUserResource
func TestAddUserResource(t *testing.T) {
Convey("TestAddUserResource", t, func() {
res, err := urs.Add(context.TODO(), &pb.AddReq{
ResType: 1,
Title: "resource",
Url: "http://www.bilibili.com",
Weight: 0,
Creator: "liutengda",
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestAddUserResource
func TestEditUserResource(t *testing.T) {
Convey("TestAddUserResource", t, func() {
res, err := urs.Add(context.TODO(), &pb.AddReq{
ResType: 1,
Title: "resource",
Url: "http://www.bilibili.com",
Weight: 0,
Creator: "liutengda",
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestEditUserResource", t, func() {
res, err := urs.Edit(context.TODO(), &pb.EditReq{
ResType: 1,
CustomId: 1,
Title: time.Now().Format("2006-01-02 15:04:05"),
Url: "http://www.bilibili.com",
Weight: 0,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestEditUserResource", t, func() {
res, err := urs.Edit(context.TODO(), &pb.EditReq{
ResType: 1,
CustomId: 200000,
Title: time.Now().Format("2006-01-02 15:04:05"),
Url: "http://www.bilibili.com/" + time.Now().Format("2006-01-02 15:04:05"),
Weight: 10,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeError)
})
Convey("TestEditUserResource", t, func() {
res, err := urs.Edit(context.TODO(), &pb.EditReq{
ResType: 2000,
CustomId: 2,
Title: time.Now().Format("2006-01-02 15:04:05"),
Url: "http://www.bilibili.com/" + time.Now().Format("2006-01-02 15:04:05"),
Weight: 10,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeError)
})
}
// go test -test.v -test.run TestQueryUserResource
func TestQueryUserResource(t *testing.T) {
Convey("TestAddUserResource", t, func() {
res, err := urs.Add(context.TODO(), &pb.AddReq{
ResType: 1,
Title: "resource",
Url: "http://www.bilibili.com",
Weight: 0,
Creator: "liutengda",
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestQueryUserResource", t, func() {
res, err := urs.Query(context.TODO(), &pb.QueryReq{
ResType: 1,
CustomId: 1,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestQueryUserResource", t, func() {
res, err := urs.Query(context.TODO(), &pb.QueryReq{
ResType: 1,
CustomId: 100,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeError)
})
}
// go test -test.v -test.run TestListUserResource
func TestListUserResource(t *testing.T) {
Convey("TestListUserResource", t, func() {
res, err := urs.List(context.TODO(), &pb.ListReq{
ResType: 1,
Page: 1,
PageSize: 10,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestListUserResource
func TestSetUserResourceStatus(t *testing.T) {
Convey("TestAddUserResource", t, func() {
res, err := urs.Add(context.TODO(), &pb.AddReq{
ResType: 1,
Title: "resource",
Url: "http://www.bilibili.co",
Weight: 0,
Creator: "liutengda",
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestSetUserResourceStatus", t, func() {
res, err := urs.SetStatus(context.TODO(), &pb.SetStatusReq{
ResType: 1,
CustomId: 1,
Status: 99,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
Convey("TestSetUserResourceStatus", t, func() {
res, err := urs.SetStatus(context.TODO(), &pb.SetStatusReq{
ResType: 1,
CustomId: 1,
Status: 10,
})
t.Logf("%v,%s", res, err)
So(err, ShouldBeNil)
})
}