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,31 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/resource/api/v1:all-srcs",
"//app/service/main/resource/cmd:all-srcs",
"//app/service/main/resource/conf:all-srcs",
"//app/service/main/resource/dao/abtest:all-srcs",
"//app/service/main/resource/dao/ads:all-srcs",
"//app/service/main/resource/dao/alarm:all-srcs",
"//app/service/main/resource/dao/cpm:all-srcs",
"//app/service/main/resource/dao/manager:all-srcs",
"//app/service/main/resource/dao/resource:all-srcs",
"//app/service/main/resource/dao/show:all-srcs",
"//app/service/main/resource/http:all-srcs",
"//app/service/main/resource/model:all-srcs",
"//app/service/main/resource/rpc/client:all-srcs",
"//app/service/main/resource/rpc/server:all-srcs",
"//app/service/main/resource/server/grpc:all-srcs",
"//app/service/main/resource/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,326 @@
## 内容运营服务
### Version 2.25.5
##### Features
> 1.增加获取审核态接口
### Version 2.25.4
##### Features
> 1.科技区右侧推广栏输出标签
### Version 2.25.3
##### Features
> 1.sidebar增加Language
### Version 2.25.2
##### Features
> 1.修改resource表查询语句的排序
### Version 2.25.1
##### Features
> 1.更换地区限制方法
### Version 2.25.0
##### Bugfix
> 1.修复specialCache并发读写的问题
> 2.不需要的err报错改为warn
### Version 2.24.8
##### Features
> 1.接入grpc
> 2.pgc特殊卡片、相关推荐
### Version 2.24.7
##### Features
> 1.增加获取贴片视频cid接口
### Version 2.24.6
> 1.location的Zone接口修改为Info
### Version 2.24.5
##### Features
> 1.新增需要展示标签的位置
> 2.URL监测功能针对直播URL的安全校验做兼容
### Version 2.24.4
##### Bugfix
> 1.修改banner返回nil导致空指针异常的问题
### Version 2.24.3
##### Features
> 1.修改abtest逻辑大于等于改为大于
### Version 2.24.2
##### Features
> 1.修改abtest的buvid转换方法
### Version 2.24.1
##### Features
> 1.banner增加过滤逻辑降低广告请求频率(参数中的version不为空且等于本地hashcache时直接返回空)
### Version 2.24.0
##### Features
> 1.identify为grpc切换verify
### Version 2.23.1
##### Features
> 1.siderbar增加红点字段
### Version 2.23.0
##### Features
> 1.增加移动端“我的”数据接口
> 2.获取resource数据时去掉status筛选逻辑
> 3.增加abtest接口逻辑
> 4.增加rows.Err
### Version 2.22.12
##### Features
> 1.URL监控增加限速
### Version 2.22.11
##### Features
> 1.对被监控的稿件数据做格式兼容处理
### Version 2.22.10
##### Features
> 1.新增需要获取稿件信息的推广位id
### Version 2.22.9
##### Features
> 1.增加音频分区推荐卡片接口
### Version 2.22.8
##### Features
> 1.整合告警信息
> 2.URL监控告警逻辑简化
> 3.移动端banner数据增加build过滤逻辑
> 4.移动端banner输出数据增加stime字段
### Version 2.22.7
##### Features
> 1.优化稿件自动下线和监测、URL监测告警的逻辑
### Version 2.22.6
> 1.http default client add timeout
### Version 2.22.5 - 2018.05.25
##### Features
> 3.修改需要加label的位置ID
### Version 2.22.4 - 2018.05.24
##### Features
> 1.完善内容运营后台的投放内容自动下线和告警的逻辑
> 2.补充自动下线的各种日志
> 3.增加需要加label的位置ID
### Version 2.22.3 - 2018.05.23
##### Features
> 1.去掉投放内容自动下线逻辑中的多余log
### Version 2.22.2 - 2018.05.23
##### Features
> 1.对URL监控功能中的URL做处理
### Version 2.22.1 - 2018.05.22
##### Features
> 1.增加稿件和URL监控的开关
### Version 2.22.0 - 2018.05.22
##### Features
> 1.去掉无用的http接口assignment、defbanner
> 2.增加url类型模拟请求和告警
> 3.告警方式变为企业微信
> 4.根据稿件状态,自动下线内容运营数据
### Version 2.21.0 - 2018.05.03
##### Features
> 1.http切bm
### Version 2.20.1 - 2018.04.24
##### Features
> 1.接archive的discovery
> 2.推广内容告警触发条件改为:稿件状态变更且变更后的状态不是开发浏览
> 3.告警邮件标题
### Version 2.20.0 - 2018.04.24
##### Features
> 1.rpc lient 增加discovery new方法
### Version 2.19.1 - 2018.04.19
##### BugFix
> 1.修复creative_type赋值的问题
### Version 2.19.0 - 2018.04.18
##### Features
> 1.增加创作中心creative_type字段
### Version 2.18.2 - 2018.04.12
##### BugFix
> 1.修改banner排序逻辑
### Version 2.18.1 - 2018.04.12
##### Features
> 1.接discovery添加register接口
### Version 2.18.0 - 2018.04.09
##### Features
> 1.增加直播弹幕盒子接口
### Version 2.17.0 - 2018.02.27
##### Features
> 1.label恢复原有逻辑不再使用note临时替代
> 2.增加地区限制过滤
> 3.修改推荐池投放的优先级
### Version 2.16.2 - 2018.01.30
##### Features
> 1.未登录贴片增加aid和是否跳转
> 2.番剧贴片增加aid
### Version 2.16.1 - 2018.01.16
##### Features
> 1.优化video_ads相关逻辑删除无用的逻辑和接口
> 2.番剧贴片接口增加了跳转url字段
### Version 2.16.0 - 2018.01.15
##### Features
> 1.播放器控件添加Hash
> 2.修改resource和bannner的SQL
> 3.各目录增加单元测试
### Version 2.15.1 - 2018.01.05
##### BugFix & Features
> 1.优化编辑投放稿件状态变化告警邮件内容
> 2.修复map并发读写问题
> 3.修复推荐池会读取历史素材的问题
### Version 2.15.0 - 2018.01.05
##### Features
> 1.增加番剧获取贴片的接口
### Version 2.14.3 - 2018.01.02
##### BugFix
> 1.修复resource并发引起的slice越界问题
### Version 2.14.2 - 2017.12.29
##### BugFix
> 1.兼容旧逻辑返回给web的assignment数据的weight全部置为0
### Version 2.14.1 - 2017.12.29
##### Features
> 1.兼容旧逻辑修改resource_assignment表读的值(position->weight)
### Version 2.14.0 - 2017.12.29
##### Features
> 1.添加获取播放器控件接口
### Version 2.13.1 - 2017.12.28
##### Features
> 1.兼容部分旧逻辑
### Version 2.13.0 - 2017.12.28
##### Features
> 1.根据新的内容运营平台修改resource和banner逻辑
### Version 2.12.3 - 2017.12.20
##### Features
> 1.修改SQL确保读的是旧数据。防止新版后台预发添加新数据影响线上服务
### Version 2.12.2 - 2017.11.20
##### Features
> 1.banner限制总数修改
### Version 2.12.1 - 2017.11.20
##### Bug
> 1.修正对RPC方法PasterAPP的err的判断
### Version 2.12.0 - 2017.11.20
##### Bug
> 1.RPC方法DefBanner、Resource、PasterAPP增加返回值nil或err的判断
### Version 2.11.0 - 2017.11.13
##### Features
> 1.banner接口增加aid参数、增加透传字段ad_extra(替代原来lat、lng)
> 2.商业广告接口返回值增加透传字段extra
> 3.提供新接口,获取首页引导图
### Version 2.10.0 - 2017.11.7
##### Features
> 1.未登录贴片的投放目标ID(aid、season_id、type_id)进行数据库字段拆分
### Version 2.9.0 - 2017.11.3
##### Features
> 1.未登录贴片的投放目标ID改为支持逗号分隔
### Version 2.8.0 - 2017.11.1
##### Features
> 1.banner接口增加经纬度字段、增加open_event字段
### Version 2.7.0 - 2017.10.25
##### Features
> 1.增加获取登录引导贴片的接口
### Version 2.6.2 - 2017.10.17
##### Bug
> 1.修正bilibili_ads库的video_ads表aid为null的情况下逗号分隔报错导致初始化失败的问题
### Version 2.6.1 - 2017.10.17
##### Bug
> 1.修正bilibili_ads库的video_ads表部分数据default NULL导致panic的问题
### Version 2.6.0 - 2017.10.16
##### Features
> 1.banner接口增加传参(version)
> 2.修改banner的rpc和http接口返回值
> 3.banner的dao层修改查询条件
### Version 2.5.1 - 2017.10.13
##### Bug
> 1.修复banner逻辑初始化res的bug
### Version 2.5.0 - 2017.10.11
##### Features
> 1.banner接口改为批量接口接收多个resource_id
> 2.banner接口的plat参数改为接收调用方传参
> 3.banner接口增加is_ad参数判断是否调用广告接口
> 4.调用广告接口的方法去掉版本和mid判断
### Version 2.4.0 - 2017.10.11
##### Features
> 1.banner接口不再进行签名校验
> 2.banner接口返回值结构修改
> 3.banner调广告接口的逻辑添加mobile_app和build的判断逻辑
> 4.banner添加rpc接口
### Version 2.3.0 - 2017.09.27
##### Features
> 1.去掉ecode.Init
> 2.httpClient请求去掉app
### Version 2.2.0 - 2017.09.07
##### Features
> 1.app-show的banner逻辑整体迁移进来
### Version 2.1.0 - 2017.08.28
##### Features
> 1.添加获取bilibili_ads库video_ads表的方法(aid维度)
> 2.添加获取bilibili_ads库video_ads表的方法(seasonid维度)
> 2.广告接口调整目录(ad变为cpm)
### Version 2.0.0 - 2017.08.23
##### Features
> 1.添加全量获取resource表数据的RPC方法
> 2.添加全量获取resource_assignment表数据的RPC方法
> 3.添加default_one表查询接口(http/rpc)
> 4.添加单独和批量查询resource接口(http/rpc)
> 5.添加单独和批量查询assignment接口(http/rpc)
### Version 2.0.0 - 2017.07.21
##### Features
> 1.更新go-common v7
> 2.去掉go-business依赖
### Version 1.0.0
##### Features
> 1.广告获取接口(针对APP)
> 2.添加prom监控

View File

@@ -0,0 +1,11 @@
# Owner
haoguanwei
peiyifei
liweijia
# Author
yujia
# Reviewer
haoguanwei
peiyifei

View File

@@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- haoguanwei
- liweijia
- peiyifei
- yujia
labels:
- main
- service
- service/main/resource
options:
no_parent_owners: true
reviewers:
- haoguanwei
- peiyifei
- yujia

View File

@@ -0,0 +1,24 @@
#### resource-service
##### 项目简介
> 1.为移动端和WEB端提供广告相关接口
> 2.提供在线热数据配置和加载
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 编译执行
> 在主目录执行go build。
> 编译后可执行 ./resource -conf resource-service-test.toml 使用项目本地配置文件启动服务。
> 也可执行 -conf_appid=resource-service -conf_version=shsb-server-1 -conf_host=config.bilibili.co -conf_path=/data/conf/resource-service -conf_env=10 -conf_token=3DTSmKyHEwN6eYGcKhlIyqIM60yyyxQD 使用配置中心测试环境配置启动服务如无法启动可检查token是否正确。
##### RPC测试
> 具体的测试内容可修改rpc/rpc_test.go文件。
> 在rpc目录执行go test测试rpc接口。
##### 特别说明
> 1.model目录可能会被其他项目引用请谨慎请改并通知各方。
> 2.http接口文档可参考 http://info.bilibili.co/pages/viewpage.action?pageId=3690413

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
importpath = "go-common/app/service/main/resource/api/v1",
proto = ":v1_proto",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/main/resource/api/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/warden: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
syntax = "proto3";
// use {app_id}.{version} as package name
package resource.service.v1;
// specify golang package name
option go_package = "v1";
// The greeting service definition.
service Resource {
//相关推荐列表
//-400:RequestErr -404:NothingFound
rpc Relate(RelateRequest) returns (SpecialReply){};
}
//相关推荐请求参数
message RelateRequest{
//pgc seasonID
int64 id = 1;
string mobi_app = 2;
string device = 3;
int32 build = 4;
}
message SpecialReply{
//主键id
int64 id = 1;
//特殊卡片标题
string title = 2;
//特殊卡片描述
string desc = 3;
//特殊卡片单列封面
string cover = 4;
//特殊卡片双列封面
string scover = 5;
//跳转类型 URL:0 游戏小卡:1 稿件:2 番剧:3 直播:4 专栏:6 每日精选:7 歌单:8 歌曲:9 相簿:10 小视频:11
int32 re_type = 6;
//跳转参数
string re_value = 7;
//角标文字
string corner = 8;
//卡片类型 1特殊小卡 2特殊大卡 3置顶卡片
int32 card = 9;
//特殊大卡参数 如果是1020*300则封面比例为34 如果是1020*378则封面比例为27
string siz = 10;
//位置
int32 position = 11;
}

View File

@@ -0,0 +1,25 @@
package v1
import (
"context"
"fmt"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID .
const AppID = "resource.service"
// NewClient new grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (ResourceClient, error) {
client := warden.NewClient(cfg, opts...)
cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID))
if err != nil {
return nil, err
}
return NewResourceClient(cc), nil
}
//go:generate $GOPATH/src/go-common/app/tool/warden/protoc.sh

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["resource-service-test.toml"],
importpath = "go-common/app/service/main/resource/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/http:go_default_library",
"//app/service/main/resource/rpc/server:go_default_library",
"//app/service/main/resource/server/grpc:go_default_library",
"//app/service/main/resource/service: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,56 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/http"
rpc "go-common/app/service/main/resource/rpc/server"
grpc "go-common/app/service/main/resource/server/grpc"
"go-common/app/service/main/resource/service"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.XLog)
trace.Init(conf.Conf.Tracer)
defer trace.Close()
defer log.Close()
log.Info("resource-service start")
// service init
svr := service.New(conf.Conf)
rpcSvr := rpc.New(conf.Conf, svr)
grpcSvr := grpc.New(nil, svr)
http.Init(conf.Conf, svr)
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("resource-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
rpcSvr.Close()
grpcSvr.Shutdown(context.TODO())
time.Sleep(time.Second * 2)
log.Info("resource-service exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,145 @@
spLimit = "500ms"
hashNum = 1000000
monitorURL = true
monitorArchive = true
WeChatToken = "uYsRqXPjnbyXDCba"
WeChatSecret = "tUILeGIXJHFSUdwfLjBHDZJXmLgYpgEy"
WeChantUsers = ["zhaobingqing"]
[reload]
ad="10s"
[note]
noteNumber = 4
[Host]
bangumi = "http://bangumi.bilibili.com"
ad = "http://cm.bilibili.co"
dataPlat = "http://172.18.33.162:6193"
[xlog]
dir = "/data/log/resource-service/"
[httpClient]
key = "f022126a8a365e20"
secret = "b7b86838145d634b487e67b811b8fab2"
dial = "500ms"
timeout = "2s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.1
request = 10
[bm]
[bm.inner]
addr = "0.0.0.0:6421"
timeout = "1s"
[bm.local]
addr = "0.0.0.0:6423"
timeout = "1s"
[rpcServer2]
[[rpcServer2.servers]]
proto = "tcp"
addr = "0.0.0.0:6429"
weight = 10
[rpcServer2.zookeeper]
root = "/microservice/resource-service/"
addrs = ["172.18.33.50:2199","172.18.33.51:2199","172.18.33.52:2199"]
timeout = "30s"
[db]
[db.res]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_resource?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.res.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.ads]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_ads?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.ads.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.show]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_show?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.show.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.manager]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_manager?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 1
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.manager.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
[redis.ads]
name = "resource-service"
proto = "tcp"
#addr = "172.16.33.54:6379"
addr = "172.18.33.60:6975"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[archiveSub]
key = "8e27ab7e39270b59"
secret = "477df6a068d7332a163f95abbad2079c"
group = "Archive-MainAppSvr-2-S"
topic = "Archive-T"
action = "sub"
name = "archive-job/archivesub"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"

View File

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

View File

@@ -0,0 +1,136 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
xlog "go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf is global config
Conf *Config
)
// Config service config
type Config struct {
Version string `toml:"version"`
// reload
Reload *ReloadInterval
// rpc server2
RPCServer *rpc.ServerConfig
// verify
Verify *verify.Config
// http
BM *BM
// tracer
Tracer *trace.Config
// db
DB *DB
// httpClient
HTTPClient *bm.ClientConfig
// Host
Host *Host
// XLog
XLog *xlog.Config
// rpc
LocationRPC *rpc.ClientConfig
ArchiveRPC *rpc.ClientConfig
// redis
Redis *Redis
// hash number
HashNum int64
// databus
ArchiveSub *databus.Config
// qiye wechat
WeChatToken string
WeChatSecret string
WeChantUsers []string
// kai guan off line
MonitorArchive bool
MonitorURL bool
// sp limit
SpLimit time.Duration
}
// BM http
type BM struct {
Inner *bm.ServerConfig
Local *bm.ServerConfig
}
// ReloadInterval define reolad config
type ReloadInterval struct {
Ad time.Duration
}
// Host defeine host info
type Host struct {
DataPlat string
Ad string
}
// DB define MySQL config
type DB struct {
Res *sql.Config
Ads *sql.Config
Show *sql.Config
Manager *sql.Config
}
// Redis define Redis config
type Redis struct {
Ads *struct {
*redis.Config
Expire time.Duration
}
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config
func Init() (err error) {
if confPath != "" {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
err = configCenter()
return
}
// configCenter ugc
func configCenter() (err error) {
var (
client *conf.Client
c string
ok bool
)
if client, err = conf.New(); err != nil {
panic(err)
}
if c, ok = client.Toml2(); !ok {
err = errors.New("load config center error")
return
}
_, err = toml.Decode(c, &Conf)
go func() {
for e := range client.Event() {
xlog.Error("get config from config center error(%v)", e)
}
}()
return
}

View File

@@ -0,0 +1,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"abtest_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"abtest.go",
"dao.go",
],
importpath = "go-common/app/service/main/resource/dao/abtest",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,32 @@
package abtest
import (
"context"
"fmt"
"net/url"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
// AbTest get abtest data from data-platform.
func (d *Dao) AbTest(c context.Context, names, ipaddr string) (adr []*model.AbTest, err error) {
params := url.Values{}
params.Set("groupNames", names)
var res struct {
Code int `json:"code"`
Data []*model.AbTest `json:"expItems"`
Msg string `json:"msg"`
}
if err = d.httpClient.Get(c, d.testURL, ipaddr, params, &res); err != nil {
log.Error("AbTest url(%s) error(%v)", d.testURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = fmt.Errorf("AbTest api failed(%d)", res.Code)
log.Error("CpmsApp url(%s) res code(%d) or res.data(%v)", d.testURL+"?"+params.Encode(), res.Code, res.Data)
return
}
adr = res.Data
return
}

View File

@@ -0,0 +1,39 @@
package abtest
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestAbtestAbTest(t *testing.T) {
convey.Convey("Abtest", t, func() {
var (
c = context.Background()
names = "test"
ipaddr = "0.0.0.0"
)
convey.Convey("When everything is correct", func(ctx convey.C) {
adr, err := d.AbTest(context.TODO(), "", "")
ctx.Convey("Then error should be niladr should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(adr, convey.ShouldNotBeNil)
})
})
convey.Convey("When http request gets 404 error", func(ctx convey.C) {
httpMock("GET", d.testURL).Reply(404)
_, err := d.AbTest(c, names, ipaddr)
ctx.Convey("Then error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
convey.Convey("When http request gets code != 0", func(ctx convey.C) {
httpMock("GET", d.testURL).Reply(200).JSON(`{"code":-3,"message":"faild","data":{}}`)
_, err := d.AbTest(c, names, ipaddr)
ctx.Convey("Then error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,28 @@
package abtest
import (
"go-common/app/service/main/resource/conf"
httpx "go-common/library/net/http/blademaster"
)
// Dao define db struct
type Dao struct {
c *conf.Config
// cpt
httpClient *httpx.Client
testURL string
}
const (
_abTestURL = "/abserver/v1/app/query-exp"
)
// New init mysql db
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
httpClient: httpx.NewClient(c.HTTPClient),
testURL: c.Host.DataPlat + _abTestURL,
}
return
}

View File

@@ -0,0 +1,46 @@
package abtest
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/service/main/resource/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.httpClient.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,60 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"redis_test.go",
"vdoad_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"redis.go",
"vdoad.go",
],
importpath = "go-common/app/service/main/resource/dao/ads",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/dgryski/go-farm: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,40 @@
package ads
import (
"context"
"time"
"go-common/app/service/main/resource/conf"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
)
// Dao is resource dao.
type Dao struct {
db *xsql.DB
c *conf.Config
// redis
redis *redis.Pool
expire int32
}
// New init mysql db
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: xsql.NewMySQL(c.DB.Ads),
redis: redis.NewPool(c.Redis.Ads.Config),
expire: int32(time.Duration(c.Redis.Ads.Expire) / time.Second),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
}
// Ping check dao health.
func (d *Dao) Ping(c context.Context) error {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,64 @@
package ads
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/resource/conf"
"go-common/library/cache/redis"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
// func CleanCache() {
// pool := redis.NewPool(conf.Conf.Redis.Ads.Config)
// pool.Get(context.TODO()).Do("FLUSHDB")
// }
func WithDao(f func(d *Dao)) func() {
return func() {
convey.Reset(func() {
pool := redis.NewPool(conf.Conf.Redis.Ads.Config)
pool.Get(context.TODO()).Do("FLUSHDB")
})
f(d)
}
}
func TestDaoPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(context.TODO())
ctx.Convey("Err should be nil", func() {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,94 @@
package ads
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
"github.com/dgryski/go-farm"
)
const (
_prefixBuvid = "buvid:%d"
)
func (d *Dao) keyBuvid(buvid string) (key string) {
num := int64(farm.Hash32([]byte(buvid)))
key = fmt.Sprintf(_prefixBuvid, num%d.c.HashNum)
return
}
// ExistsAuth if existes buvid in redis.
func (d *Dao) ExistsAuth(c context.Context, key string) (ok bool, err error) {
var conn = d.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXISTS", key)); err != nil {
log.Error("EXISTS key(%s), error(%v)", key, err)
}
return
}
// BuvidCount get buvid count info from redis.
func (d *Dao) BuvidCount(c context.Context, faid int64, buvid string) (res int64, err error) {
var (
key = d.keyBuvid(buvid)
conn = d.redis.Get(c)
field = faid
)
defer conn.Close()
if res, err = redis.Int64(conn.Do("HGET", key, field)); err != nil {
if err != redis.ErrNil {
log.Error("BuvidCount conn.Send HGET(%v, %v) error(%v)", key, field, err)
return
}
err = nil
}
return
}
// AddBuvidCount add buvid count info into redis.
func (d *Dao) AddBuvidCount(c context.Context, buvidCounts map[string]map[int64]int64) (err error) {
var (
key string
count int
conn = d.redis.Get(c)
faid int64
playCount int64
ok bool
)
defer conn.Close()
for buvid, buvidCount := range buvidCounts {
key = d.keyBuvid(buvid)
if ok, err = d.ExistsAuth(c, key); err != nil {
log.Error("EXISTS key(%s) error(%v)", key, err)
return
}
for faid, playCount = range buvidCount {
if err = conn.Send("HSET", key, faid, playCount); err != nil {
log.Error("HSET key(%s) field(%d) playCount(%d) error(%v)", key, faid, playCount, err)
return
}
count++
}
if !ok {
if err = conn.Send("EXPIRE", key, d.expire); err != nil {
log.Error("EXPIRE key(%s) expire(%v) error(%v)", key, d.expire, err)
return
}
count++
}
}
if err = conn.Flush(); err != nil {
log.Error("BuvidCount conn.Flush error(%v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("BuvidCount conn.Receive error(%v)", err)
return
}
}
return
}

View File

@@ -0,0 +1,60 @@
package ads
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestAdsBuvidCache(t *testing.T) {
var (
buvidCache = map[string]map[int64]int64{
"123456": {
10097289: 1,
10097290: 5,
},
"234567": {
10097288: 3,
10098523: 1,
},
}
res int64
err error
)
convey.Convey("AddBuvidCount - add cache", t, WithDao(func(d *Dao) {
err = d.AddBuvidCount(context.Background(), buvidCache)
convey.Convey("Error should be nil", func() {
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("BuvidCount - get cache", func() {
convey.Convey("Case 1: faid = 10097290, buvid = 123456", func() {
res, err = d.BuvidCount(context.Background(), 10097290, "123456")
convey.Convey("Error should be nil, res should be 5", func() {
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldEqual, 5)
})
})
convey.Convey("Case 2: faid = 10097288, buvid = 234567", func() {
res, err := d.BuvidCount(context.Background(), 10097288, "234567")
convey.Convey("Error should be nil, res should be 3", func() {
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldEqual, 3)
})
})
})
convey.Convey("keyBuvid", func() {
key := d.keyBuvid("234567")
convey.Convey("key should not be nil", func() {
convey.So(key, convey.ShouldNotBeNil)
})
convey.Convey("ExistsAuth - expire cache", func() {
res, err := d.ExistsAuth(context.Background(), key)
convey.Convey("Error should be nil, res should be true", func() {
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldEqual, true)
})
})
})
}))
}

View File

@@ -0,0 +1,49 @@
package ads
import (
"context"
"database/sql"
"time"
"go-common/app/service/main/resource/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_videoAdsSQL = `SELECT name,contract_id,aid,season_id,typeid,ad_cid,ad_strategy,ad_url,ad_order,skipable,note,agency_name,agency_country,
agency_area,price,verified,state,front_aid,target,platform,type,user_set,play_count,mtime FROM video_ads WHERE state=0 AND verified=1 AND starttime<? AND endtime>? ORDER BY mtime,ctime ASC`
)
// VideoAds get video_ads
func (dao *Dao) VideoAds(c context.Context) (ads []*model.VideoAD, err error) {
var (
rows *xsql.Rows
now = time.Now()
)
if rows, err = dao.db.Query(c, _videoAdsSQL, now, now); err != nil {
log.Error("dao.Exec(%v, %v), err (%v)", now, now, err)
return
}
defer rows.Close()
for rows.Next() {
ad := &model.VideoAD{}
var (
agencyCountry sql.NullInt64
agencyArea sql.NullInt64
price sql.NullFloat64
)
if err = rows.Scan(&ad.Name, &ad.ContractID, &ad.Aids, &ad.SeasonID, &ad.TypeID, &ad.AdCid, &ad.AdStrategy,
&ad.AdURL, &ad.AdOrder, &ad.Skipable, &ad.Note, &ad.AgencyName, &agencyCountry, &agencyArea,
&price, &ad.Verified, &ad.State, &ad.FrontAid, &ad.Target, &ad.Platform, &ad.Type, &ad.UserSet, &ad.PlayCount, &ad.MTime); err != nil {
log.Error("rows.Scan(), err (%v)", err)
return
}
ad.AgencyCountry = int(agencyCountry.Int64)
ad.AgencyArea = int(agencyArea.Int64)
ad.Price = float32(price.Float64)
ads = append(ads, ad)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,35 @@
package ads
import (
"context"
"fmt"
"reflect"
"testing"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestAdsVideoAds(t *testing.T) {
convey.Convey("VideoAds", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
res, err := d.VideoAds(context.Background())
ctx.Convey("Error should be nil, res should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.SkipSo(res, convey.ShouldNotBeEmpty)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.VideoAds(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"wechat_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"wechat.go",
],
importpath = "go-common/app/service/main/resource/dao/alarm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,69 @@
package alarm
import (
"context"
"net/http"
"strings"
"time"
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/model"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
// Dao is redis dao.
type Dao struct {
c *conf.Config
netClient *http.Client
httpClient *httpx.Client
}
// New is new redis dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
httpClient: httpx.NewClient(c.HTTPClient),
netClient: &http.Client{
Timeout: 3 * time.Second,
},
}
return d
}
func (d *Dao) CheckURL(originURL string, wis []*model.ResWarnInfo) {
var (
url string
req *http.Request
resp *http.Response
err error
)
if strings.HasPrefix(originURL, "https://") {
log.Info("CheckURL url(%s) is https ,replace to http", originURL)
url = strings.Replace(originURL, "https://", "http://", -1)
} else if !strings.HasPrefix(originURL, "http://") {
log.Info("CheckURL url(%s) don't have https and http", originURL)
url = "http://" + originURL
} else {
url = originURL
}
if req, err = http.NewRequest("GET", url, nil); err != nil {
log.Error("CheckURL NewRequest(%v) error(%v)", url, err)
return
}
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36")
resp, err = d.netClient.Do(req)
if err != nil {
log.Error("CheckURL url(%s) originURL(%s) error(%v)", url, originURL, err)
} else if resp.StatusCode != http.StatusOK {
log.Error("CheckURL url(%s) originURL(%s) code(%v) not OK ", url, originURL, resp.StatusCode)
var sends = make(map[string][]*model.ResWarnInfo)
for _, wi := range wis {
sends[wi.UserName] = append(sends[wi.UserName], wi)
}
for userName, send := range sends {
d.sendWeChartURL(context.TODO(), resp.StatusCode, userName, send)
}
}
}

View File

@@ -0,0 +1,63 @@
package alarm
import (
"flag"
"os"
"strings"
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/model"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.httpClient.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}
func TestDaoCheckURL(t *testing.T) {
var (
originURL = "https://www.bilibili.com"
wis = []*model.ResWarnInfo{}
)
convey.Convey("CheckURL", t, func(ctx convey.C) {
httpMock("GET", "http://www.bilibili.com").Reply(200)
d.CheckURL(originURL, wis)
ctx.Convey("no return values", func() {
})
})
}

View File

@@ -0,0 +1,182 @@
package alarm
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
var (
_states = map[int8]string{
int8(0): "开放浏览",
int8(-1): "待审",
int8(-2): "打回稿件回收站",
int8(-3): "网警锁定删除",
int8(-4): "锁定稿件",
// -5: "锁定稿件开放浏览",
int8(-6): "修复待审",
int8(-7): "暂缓审核",
// -8: "补档待审",
int8(-9): "等待转码",
int8(-10): "延迟发布",
int8(-11): "视频源待修",
// -12: "上传失败",
int8(-13): "允许评论待审",
// -14: "临时回收站",
int8(-15): "分发中",
int8(-16): "转码失败",
int8(-30): "创建已提交",
int8(-40): "UP主定时发布",
int8(-100): "UP主删除",
}
_codes = map[int]string{
404: "页面未找到",
502: "服务端异常",
504: "SLB超时",
}
)
func stateDescribe(state int8) string {
des, ok := _states[state]
if ok {
return des
}
return strconv.Itoa(int(state))
}
const (
_warnTitle = `
【线上投放告警】您有一个投放发生了异常,请尽快确认是否影响投放。
%v
以上内容确认后,如有异常请联系相关人员手动处理。`
_offLineTitle = `
【线上投放下线告警】您有一个投放内容变不可见状态,已自动下线。请尽快补充投放。
%v
以上投放所涉及的排期申请已经置为 <申请未投放>。`
_archiveContent = `
投放ID%d
稿件ID%d
投放标题:%s
投放位置:%s (位置ID%d)
投放时间段:%s - %s
当前稿件状态:%s
`
_urlContent = `
投放ID%d
URL%v
投放标题:%s
投放位置:%s (位置ID%d)
投放时间段:%s - %s
错误信息:%v(错误码: %v)
`
)
type wxParams struct {
Username string `json:"username"`
Content string `json:"content"`
Token string `json:"token"`
Timestamp int64 `json:"timestamp"`
Sign string `json:"signature"`
}
type resp struct {
Status int64 `json:"status"`
Msg string `json:"msg"`
}
// SendWeChart send message to QYWX
func (d *Dao) SendWeChart(c context.Context, ns int8, userName string, res []*model.ResWarnInfo, titleType string) (err error) {
var (
users = append(d.c.WeChantUsers, userName)
newStateStr = stateDescribe(ns)
contents []string
)
for _, re := range res {
stime := re.STime.Time().Format("2006-01-02 15:04:05")
etime := re.ETime.Time().Format("2006-01-02 15:04:05")
contents = append(contents, fmt.Sprintf(_archiveContent, re.AssignmentID, re.AID, re.AssignmentName, re.ResourceName, re.ResourceID, stime, etime, newStateStr))
}
params := url.Values{}
params.Set("username", strings.Join(users, ","))
if titleType == "warn" {
params.Set("content", fmt.Sprintf(_warnTitle, strings.Join(contents, "")))
} else {
params.Set("content", fmt.Sprintf(_offLineTitle, strings.Join(contents, "")))
}
params.Set("token", d.c.WeChatToken)
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + d.c.WeChatSecret))
params.Set("signature", hex.EncodeToString(mh[:]))
p := &wxParams{
Username: params.Get("username"),
Content: params.Get("content"),
Token: params.Get("token"),
Sign: params.Get("signature"),
}
p.Timestamp, _ = strconv.ParseInt(params.Get("timestamp"), 10, 64)
bs, _ := json.Marshal(p)
payload := strings.NewReader(string(bs))
req, _ := http.NewRequest("POST", "http://bap.bilibili.co/api/v1/message/add", payload)
req.Header.Add("content-type", "application/json; charset=utf-8")
v := &resp{}
if err = d.httpClient.Do(context.TODO(), req, v); err != nil {
log.Error("s.httpClient.Do error(%v)", err)
}
return
}
// sendWeChartURL send message to QYWX
func (d *Dao) sendWeChartURL(c context.Context, code int, userName string, res []*model.ResWarnInfo) (err error) {
var (
users = append(d.c.WeChantUsers, userName)
codeInfo string
contents []string
)
if codeInfo = _codes[code]; codeInfo == "" {
codeInfo = "未知错误,请手动确认"
}
for _, re := range res {
stime := re.STime.Time().Format("2006-01-02 15:04:05")
etime := re.ETime.Time().Format("2006-01-02 15:04:05")
contents = append(contents, fmt.Sprintf(_urlContent, re.AssignmentID, re.URL, re.AssignmentName, re.ResourceName, re.ResourceID, stime, etime, codeInfo, code))
}
params := url.Values{}
params.Set("username", strings.Join(users, ","))
params.Set("content", fmt.Sprintf(_warnTitle, strings.Join(contents, "")))
params.Set("token", d.c.WeChatToken)
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + d.c.WeChatSecret))
params.Set("signature", hex.EncodeToString(mh[:]))
p := &wxParams{
Username: params.Get("username"),
Content: params.Get("content"),
Token: params.Get("token"),
Sign: params.Get("signature"),
}
p.Timestamp, _ = strconv.ParseInt(params.Get("timestamp"), 10, 64)
bs, _ := json.Marshal(p)
payload := strings.NewReader(string(bs))
req, _ := http.NewRequest("POST", "http://bap.bilibili.co/api/v1/message/add", payload)
req.Header.Add("content-type", "application/json; charset=utf-8")
v := &resp{}
if err = d.httpClient.Do(context.TODO(), req, v); err != nil {
log.Error("s.httpClient.Do error(%v)", err)
}
return
}

View File

@@ -0,0 +1,72 @@
package alarm
import (
"context"
"testing"
"go-common/app/service/main/resource/model"
"github.com/smartystreets/goconvey/convey"
)
func TestAlarmstateDescribe(t *testing.T) {
convey.Convey("stateDescribe", t, func(ctx convey.C) {
ctx.Convey("When state = 0 is in the const map", func(ctx convey.C) {
res := stateDescribe(0)
ctx.Convey("Then res should equal 开放浏览", func(ctx convey.C) {
ctx.So(res, convey.ShouldEqual, "开放浏览")
})
})
ctx.Convey("When state = -99 is not in the const map", func(ctx convey.C) {
res := stateDescribe(-99)
ctx.Convey("Then res should equal -99", func(ctx convey.C) {
ctx.So(res, convey.ShouldEqual, "-99")
})
})
})
}
func TestAlarmSendWeChart(t *testing.T) {
convey.Convey("SendWeChart", t, func() {
convey.Convey("When everything is correct", func(ctx convey.C) {
httpMock("POST", "http://bap.bilibili.co/api/v1/message/add").Reply(200).JSON("{}")
err := d.SendWeChart(context.Background(), 1, "", []*model.ResWarnInfo{{}}, "unit test msg")
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
convey.Convey("When set http request gets 404", func(ctx convey.C) {
httpMock("POST", "http://bap.bilibili.co/api/v1/message/add").Reply(404)
err := d.SendWeChart(context.Background(), 1, "", []*model.ResWarnInfo{{}}, "unit test msg")
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
convey.Convey("When set titleType == \"warn\"", func(ctx convey.C) {
httpMock("POST", "http://bap.bilibili.co/api/v1/message/add").Reply(200).JSON("{}")
err := d.SendWeChart(context.Background(), 1, "", []*model.ResWarnInfo{{}}, "warn")
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestAlarmsendWeChartURL(t *testing.T) {
convey.Convey("sendWeChartURL", t, func() {
convey.Convey("When everything is correct", func(ctx convey.C) {
httpMock("POST", "http://bap.bilibili.co/api/v1/message/add").Reply(200).JSON("{}")
err := d.sendWeChartURL(context.Background(), 1, "", []*model.ResWarnInfo{{}})
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
convey.Convey("When set http request gets 404", func(ctx convey.C) {
httpMock("POST", "http://bap.bilibili.co/api/v1/message/add").Reply(404)
err := d.sendWeChartURL(context.Background(), 1, "", []*model.ResWarnInfo{{}})
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"cpm_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/location/model:go_default_library",
"//app/service/main/resource/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"cpm.go",
"dao.go",
],
importpath = "go-common/app/service/main/resource/dao/cpm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/location/model:go_default_library",
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,63 @@
package cpm
import (
"context"
"fmt"
"net/url"
"strconv"
locmdl "go-common/app/service/main/location/model"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
// CpmsAPP get ads from cpm platform.
func (d *Dao) CpmsAPP(c context.Context, aid, mid int64, build int, resource, mobiApp, device, buvid, network, openEvent, adExtra string, ip *locmdl.Info) (adr *model.ADRequest, err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("build", strconv.Itoa(build))
params.Set("buvid", buvid)
params.Set("resource", resource)
params.Set("mobi_app", mobiApp)
params.Set("ip", ip.Addr)
if aid != 0 {
params.Set("aid", strconv.FormatInt(aid, 10))
}
if device != "" {
params.Set("device", device)
}
if ip.Country != "" {
params.Set("country", ip.Country)
}
if ip.Province != "" {
params.Set("province", ip.Province)
}
if ip.City != "" {
params.Set("city", ip.City)
}
if network != "" {
params.Set("network", network)
}
if openEvent != "" {
params.Set("open_event", openEvent)
}
if adExtra != "" {
params.Set("ad_extra", adExtra)
}
var res struct {
Code int `json:"code"`
Data *model.ADRequest `json:"data"`
Msg string `json:"message"`
}
if err = d.httpClient.Get(c, d.cpmAppURL, ip.Addr, params, &res); err != nil {
log.Error("CpmsAPP url(%s) error(%v)", d.cpmAppURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = fmt.Errorf("CpmsAPP api failed(%d)", res.Code)
log.Error("CpmsApp url(%s) res code(%d) or res.data(%v)", d.cpmAppURL+"?"+params.Encode(), res.Code, res.Data)
return
}
adr = res.Data
return
}

View File

@@ -0,0 +1,36 @@
package cpm
import (
"context"
"testing"
"go-common/app/service/main/location/model"
"github.com/smartystreets/goconvey/convey"
)
func TestCpmCpmsAPP(t *testing.T) {
convey.Convey("When cpm returns code = 0", t, func(ctx convey.C) {
data := `{"code":0,"message":"successed","data":{}}`
httpMock("GET", d.cpmAppURL).Reply(200).JSON(data)
_, err := d.CpmsAPP(context.Background(), 0, 182504479, 6190, "457", "iphone", "phone", "222", "wifi", "", "", &model.Info{Addr: "218.4.147.222"})
ctx.Convey("Then Error should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
convey.Convey("When cpm returns code != 0", t, func(ctx convey.C) {
data := `{"code":-3,"message":"faild","data":{}}`
httpMock("GET", d.cpmAppURL).Reply(200).JSON(data)
_, err := d.CpmsAPP(context.Background(), 0, 182504479, 6190, "457", "iphone", "phone", "222", "wifi", "", "", &model.Info{Addr: "218.4.147.222"})
ctx.Convey("Then Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
convey.Convey("When cpm http request gets 404", t, func(ctx convey.C) {
httpMock("GET", d.cpmAppURL).Reply(404)
_, err := d.CpmsAPP(context.Background(), 0, 182504479, 6190, "457", "iphone", "phone", "222", "wifi", "", "", &model.Info{Addr: "218.4.147.222"})
ctx.Convey("Then Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,31 @@
package cpm
import (
"go-common/app/service/main/resource/conf"
httpx "go-common/library/net/http/blademaster"
)
// Dao define db struct
type Dao struct {
c *conf.Config
// cpt
httpClient *httpx.Client
cpmPCURL string
cpmAppURL string
}
const (
_cpmPCURL = "/bce/api/bce/pc"
_cpmAppURL = "/bce/api/bce/wise"
)
// New init mysql db
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
httpClient: httpx.NewClient(c.HTTPClient),
cpmPCURL: c.Host.Ad + _cpmPCURL,
cpmAppURL: c.Host.Ad + _cpmAppURL,
}
return
}

View File

@@ -0,0 +1,46 @@
package cpm
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/service/main/resource/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.httpClient.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"special_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"special.go",
],
importpath = "go-common/app/service/main/resource/dao/manager",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/api/v1:go_default_library",
"//app/service/main/resource/conf:go_default_library",
"//library/database/sql: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,28 @@
package manager
import (
"go-common/app/service/main/resource/conf"
"go-common/library/database/sql"
)
//Dao manager dao
type Dao struct {
db *sql.DB
c *conf.Config
}
//New new manager dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.DB.Manager),
}
return
}
// Close close db resource.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
}

View File

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

View File

@@ -0,0 +1,30 @@
package manager
import (
"context"
pb "go-common/app/service/main/resource/api/v1"
)
const (
_specialSQL = "SELECT `id`,`title`,`desc`,`cover`,`scover`,`re_type`,`re_value`,`corner`,`size`,`card` FROM special_card"
)
//Specials get specials cars from DB
func (d *Dao) Specials(c context.Context) (sps map[int64]*pb.SpecialReply, err error) {
rows, err := d.db.Query(c, _specialSQL)
if err != nil {
return
}
defer rows.Close()
sps = make(map[int64]*pb.SpecialReply)
for rows.Next() {
sc := &pb.SpecialReply{}
if err = rows.Scan(&sc.Id, &sc.Title, &sc.Desc, &sc.Cover, &sc.Scover, &sc.ReType, &sc.ReValue, &sc.Corner, &sc.Siz, &sc.Card); err != nil {
return
}
sps[sc.Id] = sc
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,23 @@
package manager
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestManagerSpecials(t *testing.T) {
convey.Convey("Specials", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
sps, err := d.Specials(c)
ctx.Convey("Then err should be nil.sps should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(sps, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,57 @@
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",
"dao_test.go",
"resource_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"banner.go",
"dao.go",
"resource.go",
],
importpath = "go-common/app/service/main/resource/dao/resource",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/database/sql: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,102 @@
package resource
import (
"context"
"fmt"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
var (
_bannerSQL = `SELECT rm.id,ra.position_id,rm.name,rm.url,rm.pic,ra.position,ra.platform,ra.rule,ra.atype,ra.stime FROM resource_assignment AS ra,resource_material AS rm
WHERE ra.resource_group_id>0 AND ra.category=0 AND ra.stime<? AND ra.etime>? AND ra.state=0 AND ra.audit_state IN (2,3,4) AND
ra.id=rm.resource_assignment_id AND rm.audit_state=2 AND rm.category=0 ORDER BY ra.position ASC,ra.weight DESC,rm.ctime DESC`
_categorySQL = `SELECT rm.id,ra.resource_id,rm.name,rm.url,rm.pic,ra.position,ra.platform,ra.rule,ra.atype,ra.stime FROM resource_assignment AS ra,resource_material AS rm
WHERE ra.id=rm.resource_assignment_id AND rm.id IN (SELECT max(rm.id) FROM resource_assignment AS ra,resource_material AS rm WHERE ra.resource_group_id>0 AND ra.category=1
AND ra.stime<? AND ra.etime>? AND ra.state=0 AND ra.audit_state IN (2,3,4) AND ra.id=rm.resource_assignment_id AND rm.audit_state=2 AND rm.category=1 GROUP BY rm.resource_assignment_id) ORDER BY rand()`
_bannerLimitSQL = "SELECT rule FROM default_one WHERE id=2"
)
// Banner get active banner from new db.
func (d *Dao) Banner(c context.Context) (res map[int8]map[int][]*model.Banner, err error) {
var (
now = time.Now()
ok bool
pm map[string]string
)
rows, err := d.db.Query(c, _bannerSQL, now, now)
if err != nil {
log.Error("query error(%v)", err)
return
}
defer rows.Close()
res = map[int8]map[int][]*model.Banner{}
pm = make(map[string]string)
for rows.Next() {
b := &model.Banner{}
if err = rows.Scan(&b.ID, &b.ParentID, &b.Title, &b.Value, &b.Image, &b.Rank, &b.Plat, &b.Rule, &b.Type, &b.Start); err != nil {
log.Error("rows.Scan error(%v)", err)
res = nil
return
}
pindex := fmt.Sprintf("%d_%d_%d", b.Plat, b.ParentID, b.Rank)
if _, ok = pm[pindex]; ok {
continue
}
b.BannerChange()
if plm, ok := res[b.Plat]; ok {
plm[b.ParentID] = append(plm[b.ParentID], b)
} else {
res[b.Plat] = map[int][]*model.Banner{
b.ParentID: []*model.Banner{b},
}
}
pm[pindex] = pindex
}
err = rows.Err()
return
}
// Category get category banner from new db.
func (d *Dao) Category(c context.Context) (res map[int8]map[int][]*model.Banner, err error) {
var now = time.Now()
rows, err := d.db.Query(c, _categorySQL, now, now)
if err != nil {
log.Error("query error(%v)", err)
return
}
defer rows.Close()
res = map[int8]map[int][]*model.Banner{}
for rows.Next() {
b := &model.Banner{}
if err = rows.Scan(&b.ID, &b.ParentID, &b.Title, &b.Value, &b.Image, &b.Rank, &b.Plat, &b.Rule, &b.Type, &b.Start); err != nil {
log.Error("rows.Scan error(%v)", err)
res = nil
return
}
b.BannerChange()
if plm, ok := res[b.Plat]; ok {
plm[b.ParentID] = append(plm[b.ParentID], b)
} else {
res[b.Plat] = map[int][]*model.Banner{
b.ParentID: []*model.Banner{b},
}
}
}
err = rows.Err()
return
}
// Limit get app banner limit num.
func (d *Dao) Limit(c context.Context) (res map[int]int, err error) {
row := d.db.QueryRow(c, _bannerLimitSQL)
b := &model.Limit{}
if err = row.Scan(&b.Rule); err != nil {
log.Error("Limit row.Scan error(%v)", err)
return
}
res = b.LimitChange()
return
}

View File

@@ -0,0 +1,65 @@
package resource
import (
"context"
"fmt"
"reflect"
"testing"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestResourceBanner(t *testing.T) {
convey.Convey("Banner", t, func(ctx convey.C) {
ctx.Convey("When Everything is correct", func(ctx convey.C) {
_, err := d.Banner(context.Background())
ctx.Convey("Error shouold be nil, res should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.Banner(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestResourceCategory(t *testing.T) {
convey.Convey("Category", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
_, err := d.Category(context.Background())
ctx.Convey("Error shouold be nil, res should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.Category(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestResourceLimit(t *testing.T) {
convey.Convey("Limit", t, func(ctx convey.C) {
res, err := d.Limit(context.Background())
ctx.Convey("Error shouold be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}

View File

@@ -0,0 +1,38 @@
package resource
import (
"context"
"go-common/app/service/main/resource/conf"
xsql "go-common/library/database/sql"
)
// Dao is resource dao.
type Dao struct {
db *xsql.DB
c *conf.Config
}
// New init mysql db
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: xsql.NewMySQL(c.DB.Res),
}
return
}
// BeginTran begin transcation.
func (d *Dao) BeginTran(c context.Context) (tx *xsql.Tx, err error) {
return d.db.Begin(c)
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
}
// Ping check dao health.
func (d *Dao) Ping(c context.Context) error {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,58 @@
package resource
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/resource/conf"
"go-common/library/database/sql"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func WithReopenDB(f func(d *Dao)) func() {
return func() {
convey.Reset(func() {
d.db = sql.NewMySQL(d.c.DB.Res)
})
f(d)
}
}
func TestDaoPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(context.TODO())
ctx.Convey("Err should be nil", func() {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,269 @@
package resource
import (
"context"
"fmt"
"strings"
"time"
"database/sql"
"go-common/app/service/main/resource/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_headerResIds = "142,925,926,927,1576,1580,1584,1588,1592,1596,1600,1604,1608,1612,1616,1620,1622,1634,1920,2210,2260"
)
var (
_allResSQL = `SELECT id,platform,name,parent,counter,position,rule,size,preview,description,mark,ctime,mtime,level,type,is_ad FROM resource ORDER BY counter desc,position ASC`
_allAssignSQL = fmt.Sprintf(`SELECT id,name,contract_id,resource_id,pic,litpic,url,rule,weight,agency,price,atype,username FROM resource_assignment
WHERE resource_group_id=0 AND stime<? AND etime>? AND state=0 AND resource_id IN (%s) ORDER BY weight,stime desc`, _headerResIds)
_allAssignNewSQL = `SELECT ra.id,rm.id,rm.name,ra.contract_id,ra.resource_id,rm.pic,rm.litpic,rm.url,ra.rule,ra.position,
ra.agency,ra.price,ra.stime,ra.etime,ra.apply_group_id,rm.ctime,rm.mtime,rm.atype,ra.username,rm.player_category FROM resource_assignment AS ra,resource_material AS rm
WHERE ra.resource_group_id>0 AND ra.category=0 AND ra.stime<? AND ra.etime>? AND ra.state=0 AND ra.audit_state IN (2,3,4) AND
ra.id=rm.resource_assignment_id AND rm.audit_state=2 AND rm.category=0 ORDER BY ra.position ASC,ra.weight DESC,rm.mtime DESC`
_categoryAssignSQL = fmt.Sprintf(`SELECT ra.id,rm.id,rm.name,ra.contract_id,ra.resource_id,rm.pic,rm.litpic,rm.url,ra.rule,ra.position,ra.agency,ra.price,
ra.stime,ra.etime,ra.apply_group_id,rm.ctime,rm.mtime,rm.atype,ra.username,rm.player_category FROM resource_assignment AS ra,resource_material AS rm
WHERE ra.id=rm.resource_assignment_id AND rm.id IN (SELECT max(rm.id) FROM resource_assignment AS ra,resource_material AS rm WHERE ra.resource_group_id>0
AND ra.category=1 AND ra.position_id NOT IN (%s) AND ra.stime<? AND ra.etime>? AND ra.state=0 AND ra.audit_state IN (2,3,4) AND ra.id=rm.resource_assignment_id AND
rm.audit_state=2 AND rm.category=1 GROUP BY rm.resource_assignment_id) ORDER BY rand()`, _headerResIds)
_defBannerSQL = `SELECT id,name,contract_id,resource_id,pic,litpic,url,rule,weight,agency,price,atype,username FROM default_one WHERE state=0`
// index-icon
_indexIconSQL = `SELECT id,type,title,state,link,icon,weight,user_name,sttime,endtime,deltime,ctime,mtime FROM icon WHERE state=1 AND deltime=0 AND (type=1 OR (type=2 AND sttime>0))`
_playIconSQL = `SELECT icon1,hash1,icon2,hash2,stime FROM bar_icon WHERE stime<? AND etime>? AND is_deleted=0`
// cmtbox
_cmtboxSQL = `SELECT id,load_cid,server,port,size_factor,speed_factor,max_onscreen,style,style_param,top_margin,state,ctime,mtime FROM cmtbox WHERE state=1`
// update resource assignment etime
_updateResourceAssignmentEtime = `UPDATE resource_assignment SET etime=? WHERE id=?`
// update resource apply status
_updateResourceApplyStatus = `UPDATE resource_apply SET audit_state=? WHERE apply_group_id IN (%s)`
// insert resource logs
_inResourceLogger = `INSERT INTO resource_logger (uname,uid,module,oid,content) VALUES (?,?,?,?,?)`
)
// Resources get resource infos from db
func (d *Dao) Resources(c context.Context) (rscs []*model.Resource, err error) {
var size sql.NullString
rows, err := d.db.Query(c, _allResSQL)
if err != nil {
log.Error("d.Resources query error (%v)", err)
return
}
defer rows.Close()
for rows.Next() {
rsc := &model.Resource{}
if err = rows.Scan(&rsc.ID, &rsc.Platform, &rsc.Name, &rsc.Parent, &rsc.Counter, &rsc.Position, &rsc.Rule, &size, &rsc.Previce,
&rsc.Desc, &rsc.Mark, &rsc.CTime, &rsc.MTime, &rsc.Level, &rsc.Type, &rsc.IsAd); err != nil {
log.Error("Resources rows.Scan err (%v)", err)
return
}
rsc.Size = size.String
rscs = append(rscs, rsc)
}
err = rows.Err()
return
}
// Assignment get assigment from db
func (d *Dao) Assignment(c context.Context) (asgs []*model.Assignment, err error) {
rows, err := d.db.Query(c, _allAssignSQL, time.Now(), time.Now())
if err != nil {
log.Error("d.Assignment query error (%v)", err)
return
}
defer rows.Close()
for rows.Next() {
asg := &model.Assignment{}
if err = rows.Scan(&asg.ID, &asg.Name, &asg.ContractID, &asg.ResID, &asg.Pic, &asg.LitPic,
&asg.URL, &asg.Rule, &asg.Weight, &asg.Agency, &asg.Price, &asg.Atype, &asg.Username); err != nil {
log.Error("Assignment rows.Scan err (%v)", err)
return
}
asg.AsgID = asg.ID
asgs = append(asgs, asg)
}
err = rows.Err()
return
}
// AssignmentNew get resource_assigment from new db
func (d *Dao) AssignmentNew(c context.Context) (asgs []*model.Assignment, err error) {
var (
ok bool
pm map[string]string
)
rows, err := d.db.Query(c, _allAssignNewSQL, time.Now(), time.Now())
if err != nil {
log.Error("d.AssignmentNew query error (%v)", err)
return
}
defer rows.Close()
pm = make(map[string]string)
for rows.Next() {
asg := &model.Assignment{}
if err = rows.Scan(&asg.AsgID, &asg.ID, &asg.Name, &asg.ContractID, &asg.ResID, &asg.Pic, &asg.LitPic,
&asg.URL, &asg.Rule, &asg.Weight, &asg.Agency, &asg.Price, &asg.STime, &asg.ETime, &asg.ApplyGroupID, &asg.CTime, &asg.MTime, &asg.Atype, &asg.Username, &asg.PlayerCategory); err != nil {
log.Error("AssignmentNew rows.Scan err (%v)", err)
return
}
if (asg.ResID == 2054) || (asg.ResID == 2055) || (asg.ResID == 2056) ||
(asg.ResID == 2073) || (asg.ResID == 2074) || (asg.ResID == 2075) ||
(asg.ResID == 1671) || (asg.ResID == 1672) || (asg.ResID == 1673) ||
(asg.ResID == 2315) || (asg.ResID == 2316) || (asg.ResID == 2317) ||
(asg.ResID == 2489) || (asg.ResID == 2490) || (asg.ResID == 2491) ||
(asg.ResID == 2459) || (asg.ResID == 2460) || (asg.ResID == 2461) ||
(asg.ResID == 2469) || (asg.ResID == 2470) || (asg.ResID == 2471) ||
(asg.ResID == 2479) || (asg.ResID == 2480) || (asg.ResID == 2481) ||
(asg.ResID == 2499) || (asg.ResID == 2500) || (asg.ResID == 2501) ||
(asg.ResID == 2606) || (asg.ResID == 2607) || (asg.ResID == 2608) || (asg.ResID == 2609) || (asg.ResID == 2610) ||
(asg.ResID == 2618) || (asg.ResID == 2619) || (asg.ResID == 2620) || (asg.ResID == 2621) || (asg.ResID == 2622) || (asg.ResID == 2623) ||
(asg.ResID == 2556) || (asg.ResID == 2557) || (asg.ResID == 2558) || (asg.ResID == 2559) || (asg.ResID == 2560) ||
(asg.ResID == 2991) || (asg.ResID == 2992) || (asg.ResID == 2993) {
asg.ContractID = "rec_video"
}
pindex := fmt.Sprintf("%d_%d", asg.ResID, asg.Weight)
if _, ok = pm[pindex]; ok {
continue
}
asgs = append(asgs, asg)
pm[pindex] = pindex
}
err = rows.Err()
return
}
// CategoryAssignment get recommend resource_assigment from db
func (d *Dao) CategoryAssignment(c context.Context) (asgs []*model.Assignment, err error) {
rows, err := d.db.Query(c, _categoryAssignSQL, time.Now(), time.Now())
if err != nil {
log.Error("d.CategoryAssignment query error (%v)", err)
return
}
defer rows.Close()
for rows.Next() {
asg := &model.Assignment{}
if err = rows.Scan(&asg.AsgID, &asg.ID, &asg.Name, &asg.ContractID, &asg.ResID, &asg.Pic, &asg.LitPic,
&asg.URL, &asg.Rule, &asg.Weight, &asg.Agency, &asg.Price, &asg.STime, &asg.ETime, &asg.ApplyGroupID, &asg.CTime, &asg.MTime, &asg.Atype, &asg.Username, &asg.PlayerCategory); err != nil {
log.Error("CategoryAssignment rows.Scan err (%v)", err)
return
}
if (asg.ResID == 2048) || (asg.ResID == 2066) || (asg.ResID == 1670) || (asg.ResID == 2308) || (asg.ResID == 2521) || (asg.ResID == 2979) {
asg.ContractID = "rec_video"
}
asgs = append(asgs, asg)
}
err = rows.Err()
return
}
// DefaultBanner get default banner info
func (d *Dao) DefaultBanner(c context.Context) (asg *model.Assignment, err error) {
row := d.db.QueryRow(c, _defBannerSQL)
asg = &model.Assignment{}
if err = row.Scan(&asg.ID, &asg.Name, &asg.ContractID, &asg.ResID, &asg.Pic, &asg.LitPic,
&asg.URL, &asg.Rule, &asg.Weight, &asg.Agency, &asg.Price, &asg.Atype, &asg.Username); err != nil {
if err == sql.ErrNoRows {
asg = nil
err = nil
} else {
log.Error("d.DefaultBanner.Scan error(%v)", err)
}
}
return
}
// IndexIcon get index icon.
func (d *Dao) IndexIcon(c context.Context) (icons map[int][]*model.IndexIcon, err error) {
rows, err := d.db.Query(c, _indexIconSQL)
if err != nil {
log.Error("d.IndexIcon query error (%v)", err)
return
}
defer rows.Close()
icons = make(map[int][]*model.IndexIcon)
for rows.Next() {
var link string
icon := &model.IndexIcon{}
if err = rows.Scan(&icon.ID, &icon.Type, &icon.Title, &icon.State, &link, &icon.Icon,
&icon.Weight, &icon.UserName, &icon.StTime, &icon.EndTime, &icon.DelTime, &icon.CTime, &icon.MTime); err != nil {
log.Error("IndexIcon rows.Scan err (%v)", err)
return
}
icon.Links = strings.Split(link, ",")
icons[icon.Type] = append(icons[icon.Type], icon)
}
err = rows.Err()
return
}
// PlayerIcon get play icon
func (d *Dao) PlayerIcon(c context.Context) (re *model.PlayerIcon, err error) {
row := d.db.QueryRow(c, _playIconSQL, time.Now(), time.Now())
re = &model.PlayerIcon{}
if err = row.Scan(&re.URL1, &re.Hash1, &re.URL2, &re.Hash2, &re.CTime); err != nil {
if err == sql.ErrNoRows {
re = nil
err = nil
} else {
log.Error("d.PlayerIcon.Scan error(%v)", err)
}
}
return
}
// Cmtbox sql live danmaku box
func (d *Dao) Cmtbox(c context.Context) (res map[int64]*model.Cmtbox, err error) {
rows, err := d.db.Query(c, _cmtboxSQL)
if err != nil {
log.Error("d.db.Query error (%v)", err)
return
}
defer rows.Close()
res = make(map[int64]*model.Cmtbox)
for rows.Next() {
re := &model.Cmtbox{}
if err = rows.Scan(&re.ID, &re.LoadCID, &re.Server, &re.Port, &re.SizeFactor, &re.SpeedFactor, &re.MaxOnscreen,
&re.Style, &re.StyleParam, &re.TopMargin, &re.State, &re.CTime, &re.MTime); err != nil {
log.Error("Cmtbox rows.Scan err (%v)", err)
return
}
res[re.ID] = re
}
err = rows.Err()
return
}
// TxOffLine off line resource
func (d *Dao) TxOffLine(tx *xsql.Tx, id int) (row int64, err error) {
res, err := tx.Exec(_updateResourceAssignmentEtime, time.Now(), id)
if err != nil {
log.Error("TxOffLine tx.Exec() error(%v)", err)
return
}
row, err = res.RowsAffected()
return
}
// TxFreeApply free apply
func (d *Dao) TxFreeApply(tx *xsql.Tx, ids []string) (row int64, err error) {
res, err := tx.Exec(fmt.Sprintf(_updateResourceApplyStatus, strings.Join(ids, ",")), model.ApplyNoAssignment)
if err != nil {
log.Error("TxFreeApply tx.Exec() error(%v)", err)
return
}
row, err = res.RowsAffected()
return
}
// TxInResourceLogger add resource log
func (d *Dao) TxInResourceLogger(tx *xsql.Tx, module, content string, oid int) (row int64, err error) {
res, err := tx.Exec(_inResourceLogger, "rejob", 1203, module, oid, content)
if err != nil {
log.Error("TxInResourceLogger tx.Exec() error(%v)", err)
return
}
row, err = res.RowsAffected()
return
}

View File

@@ -0,0 +1,241 @@
package resource
import (
"context"
"database/sql"
"fmt"
"reflect"
"testing"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestResourceResources(t *testing.T) {
convey.Convey("Resources", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
res, err := d.Resources(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.Resources(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
// Set d.close() to get reversal case
func TestResourceAssignment(t *testing.T) {
convey.Convey("Assignment", t, func(ctx convey.C) {
convey.Convey("When everything is correct,", func(ctx convey.C) {
asgs, err := d.Assignment(context.Background())
ctx.Convey("Error should be nil, asgs should not be nil(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(asgs, convey.ShouldBeNil)
})
})
convey.Convey("When set db closed", WithReopenDB(func(d *Dao) {
d.Close()
_, err := d.Assignment(context.Background())
convey.Convey("Error should not be nil", func(ctx convey.C) {
convey.So(err, convey.ShouldNotBeNil)
})
}))
})
}
func TestResourceAssignmentNew(t *testing.T) {
convey.Convey("AssignmentNew", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
_, err := d.AssignmentNew(context.Background())
ctx.Convey("Error should be nil, asgs should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestResourceCategoryAssignment(t *testing.T) {
convey.Convey("CategoryAssignment", t, func(ctx convey.C) {
_, err := d.CategoryAssignment(context.Background())
ctx.Convey("Error should be nil, res should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.CategoryAssignment(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestResourceDefaultBanner(t *testing.T) {
convey.Convey("DefaultBanner", t, func(ctx convey.C) {
res, err := d.DefaultBanner(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}
func TestResourceIndexIcon(t *testing.T) {
convey.Convey("IndexIcon", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
_, err := d.IndexIcon(context.Background())
ctx.Convey("Error should be nil, res should not be empty(No Data)", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.IndexIcon(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestResourcePlayerIcon(t *testing.T) {
convey.Convey("PlayerIcon", t, func(ctx convey.C) {
res, err := d.PlayerIcon(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}
func TestResourceCmtbox(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("Cmtbox", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
res, err := d.Cmtbox(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.Cmtbox(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestResourceTxOffLine(t *testing.T) {
var (
tx, _ = d.BeginTran(context.TODO())
id = int(0)
)
convey.Convey("TxOffLine", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
row, err := d.TxOffLine(tx, id)
ctx.Convey("Then err should be nil.row should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(row, convey.ShouldNotBeNil)
})
})
ctx.Convey("When tx.Exec gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (sql.Result, error) {
return nil, fmt.Errorf("tx.Exec error")
})
defer guard.Unpatch()
_, err := d.TxOffLine(tx, id)
ctx.Convey("Then err should be not nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
tx.Rollback()
})
})
}
func TestResourceTxFreeApply(t *testing.T) {
var (
tx, _ = d.BeginTran(context.TODO())
ids = []string{"0", "1"}
)
convey.Convey("TxFreeApply", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
row, err := d.TxFreeApply(tx, ids)
ctx.Convey("Then err should be nil.row should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(row, convey.ShouldNotBeNil)
})
})
ctx.Convey("When tx.Exec gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (sql.Result, error) {
return nil, fmt.Errorf("tx.Exec error")
})
defer guard.Unpatch()
_, err := d.TxFreeApply(tx, ids)
ctx.Convey("Then err should be not nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
tx.Rollback()
})
})
}
func TestResourceTxInResourceLogger(t *testing.T) {
var (
tx, _ = d.BeginTran(context.TODO())
module = ""
content = ""
oid = int(0)
)
convey.Convey("TxInResourceLogger", t, func(ctx convey.C) {
ctx.Convey("When everyting is correct", func(ctx convey.C) {
row, err := d.TxInResourceLogger(tx, module, content, oid)
ctx.Convey("Then err should be nil.row should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(row, convey.ShouldNotBeNil)
})
})
ctx.Convey("When tx.Exec gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (sql.Result, error) {
return nil, fmt.Errorf("tx.Exec error")
})
defer guard.Unpatch()
_, err := d.TxInResourceLogger(tx, module, content, oid)
ctx.Convey("Then err should be not nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
tx.Rollback()
})
})
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"audit_test.go",
"card_test.go",
"dao_test.go",
"relate_test.go",
"sidebar_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"audit.go",
"card.go",
"dao.go",
"relate.go",
"sidebar.go",
],
importpath = "go-common/app/service/main/resource/dao/show",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/database/sql: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,35 @@
package show
import (
"context"
"go-common/library/log"
)
var (
_auditSQL = "SELECT mobi_app,build FROM audit"
)
// Audit get audit.
func (d *Dao) Audit(c context.Context) (res map[string][]int, err error) {
res = make(map[string][]int)
rows, err := d.db.Query(c, _auditSQL)
if err != nil {
log.Error("d.audit error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var (
mobiApp string
build int
)
if err = rows.Scan(&mobiApp, &build); err != nil {
log.Error("d.audit rows.Scan error(%v)", err)
res = nil
return
}
res[mobiApp] = append(res[mobiApp], build)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,36 @@
package show
import (
"context"
"fmt"
"reflect"
"testing"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
// TestDaoAudit test audit.
func TestDaoAudit(t *testing.T) {
convey.Convey("Audit", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
res, err := d.Audit(context.Background())
ctx.Convey("Error should be nil, res should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.Audit(context.Background())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,76 @@
package show
import (
"context"
"strconv"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
var (
_appPosRecSQL = "SELECT r.id,r.tab,r.resource_id,r.type,r.title,r.cover,r.re_type,r.re_value,r.plat_ver,r.desc,r.tag_id FROM app_pos_rec AS r WHERE r.stime<? AND r.etime>? AND r.state=1 AND r.resource_id=3 ORDER BY r.weight ASC"
_appContentRSQL = "SELECT c.id,c.module,c.rec_id,c.ctype,c.cvalue,c.ctitle,c.tag_id FROM app_content AS c, app_pos_rec AS r WHERE c.rec_id=r.id AND r.state=1 AND r.stime<? AND r.etime>? AND c.module=1"
)
// PosRecs get pos resrouce
func (d *Dao) PosRecs(c context.Context, now time.Time) (res map[int8][]*model.Card, err error) {
res = map[int8][]*model.Card{}
rows, err := d.db.Query(c, _appPosRecSQL, now, now)
if err != nil {
log.Error("d.PosRecs error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
card := &model.Card{}
if err = rows.Scan(&card.ID, &card.Tab, &card.RegionID, &card.Type, &card.Title, &card.Cover, &card.Rtype, &card.Rvalue, &card.PlatVer, &card.Desc, &card.TagID); err != nil {
log.Error("d.PosRecs rows.Scan error(%v)", err)
res = nil
return
}
for _, limit := range card.CardPlatChange() {
tmpc := &model.Card{}
*tmpc = *card
tmpc.Plat = limit.Plat
tmpc.Build = limit.Build
tmpc.Condition = limit.Condition
tmpc.PlatVer = ""
tmpc.TypeStr = model.GotoDaily
tmpc.Goto = model.GotoDaily
tmpc.Param = tmpc.Rvalue
tmpc.URI = model.FillURI(tmpc.Goto, tmpc.Param)
res[tmpc.Plat] = append(res[tmpc.Plat], tmpc)
}
}
err = rows.Err()
return
}
// RecContents get resource contents
func (d *Dao) RecContents(c context.Context, now time.Time) (res map[int][]*model.Content, aids map[int][]int64, err error) {
res = map[int][]*model.Content{}
aids = map[int][]int64{}
rows, err := d.db.Query(c, _appContentRSQL, now, now)
if err != nil {
log.Error("d.RecContents error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
card := &model.Content{}
if err = rows.Scan(&card.ID, &card.Module, &card.RecID, &card.Type, &card.Value, &card.Title, &card.TagID); err != nil {
log.Error("d.RecContents rows.Scan error(%v)", err)
res = nil
return
}
res[card.RecID] = append(res[card.RecID], card)
if card.Type == model.CardGotoAv {
aidInt, _ := strconv.ParseInt(card.Value, 10, 64)
aids[card.RecID] = append(aids[card.RecID], aidInt)
}
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,59 @@
package show
import (
"context"
"fmt"
"reflect"
"testing"
"time"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPosRecs(t *testing.T) {
convey.Convey("PosRecs", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
res, err := d.PosRecs(context.Background(), time.Now())
ctx.Convey("Error should be nil, res should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, err := d.PosRecs(context.Background(), time.Now())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRecContents(t *testing.T) {
convey.Convey("RecContents", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func() {
res, aids, err := d.RecContents(context.Background(), time.Now())
ctx.Convey("Error should be nil, res, aids should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
ctx.So(aids, convey.ShouldNotBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, _, err := d.RecContents(context.Background(), time.Now())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,33 @@
package show
import (
"context"
"go-common/app/service/main/resource/conf"
xsql "go-common/library/database/sql"
)
// Dao is resource dao.
type Dao struct {
db *xsql.DB
c *conf.Config
}
// New init mysql db
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: xsql.NewMySQL(c.DB.Show),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
}
// Ping check dao health.
func (d *Dao) Ping(c context.Context) error {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,48 @@
package show
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/resource/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.resource-service")
flag.Set("conf_token", "y79sErNhxggjvULS0O8Czas9PaxHBF5o")
flag.Set("tree_id", "3232")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/resource-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestDaoPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(context.TODO())
ctx.Convey("Err should be nil", func() {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,47 @@
package show
import (
"context"
"encoding/json"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
const (
_relateSQL = "SELECT `id`,`param`,`title`,`rec_reason`,`position`,`plat_ver`,`stime`,`etime`,`pgc_ids` FROM app_rcmd_pos WHERE `state`=1 AND `goto`='special' AND `pgc_relation`=1 AND `stime`<? AND `etime`>?"
)
// Relate get all relate rec.
func (d *Dao) Relate(c context.Context, now time.Time) (relates []*model.Relate, err error) {
rows, err := d.db.Query(c, _relateSQL, now, now)
if err != nil {
log.Error("d.Relate.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := &model.Relate{}
var verStr string
if err = rows.Scan(&r.ID, &r.Param, &r.Title, &r.RecReason, &r.Position, &verStr, &r.STime, &r.ETime, &r.PgcIDs); err != nil {
log.Error("d.Relate.rows.Scan error(%v)", err)
return
}
if verStr != "" {
var verStruct []*model.Version
if err = json.Unmarshal([]byte(verStr), &verStruct); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", verStr, err)
return
}
vm := make(map[int8][]*model.Version, len(verStruct))
for _, v := range verStruct {
vm[v.Plat] = append(vm[v.Plat], v)
}
r.Versions = vm
}
relates = append(relates, r)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,20 @@
package show
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoRelate(t *testing.T) {
convey.Convey("Relate", t, func(ctx convey.C) {
ctx.Convey("When everything is correct", func(ctx convey.C) {
_, err := d.Relate(context.Background(), time.Now())
ctx.Convey("Error should be nil, res should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,43 @@
package show
import (
"context"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
const (
_selSideSQL = `SELECT s.id,s.plat,s.module,s.name,s.logo,s.logo_white,s.param,s.rank,l.build,l.conditions,s.tip,s.need_login,s.white_url,s.logo_selected,s.tab_id,s.red_dot_url,lang.name FROM
sidebar AS s,sidebar_limit AS l,language AS lang WHERE s.state=1 AND s.id=l.s_id AND lang.id=s.lang_id AND s.online_time<? ORDER BY s.rank DESC,l.id ASC`
)
// SideBar get side bar.
func (d *Dao) SideBar(ctx context.Context, now time.Time) (ss []*model.SideBar, limits map[int64][]*model.SideBarLimit, err error) {
rows, err := d.db.Query(ctx, _selSideSQL, now)
if err != nil {
log.Error("d.db.Query error(%v)", err)
return
}
defer rows.Close()
limits = make(map[int64][]*model.SideBarLimit)
for rows.Next() {
s := &model.SideBar{}
if err = rows.Scan(&s.ID, &s.Plat, &s.Module, &s.Name, &s.Logo, &s.LogoWhite, &s.Param, &s.Rank, &s.Build, &s.Conditions, &s.Tip, &s.NeedLogin, &s.WhiteURL, &s.LogoSelected, &s.TabID, &s.Red, &s.Language); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
if _, ok := limits[s.ID]; !ok {
ss = append(ss, s)
}
limit := &model.SideBarLimit{
ID: s.ID,
Build: s.Build,
Condition: s.Conditions,
}
limits[s.ID] = append(limits[s.ID], limit)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,36 @@
package show
import (
"context"
"fmt"
"reflect"
"testing"
"time"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
// Test_SideBar test dao side bar
func TestDaoSideBar(t *testing.T) {
convey.Convey("SidebBar", t, func(ctx convey.C) {
ctx.Convey("When everyting is correct", func(ctx convey.C) {
_, _, err := d.SideBar(context.Background(), time.Now())
ctx.Convey("Error should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
ctx.Convey("When db.Query gets error", func(ctx convey.C) {
guard := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Query", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (*xsql.Rows, error) {
return nil, fmt.Errorf("db.Query error")
})
defer guard.Unpatch()
_, _, err := d.SideBar(context.Background(), time.Now())
ctx.Convey("Error should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"ads.go",
"banner.go",
"http.go",
"local.go",
"resource.go",
],
importpath = "go-common/app/service/main/resource/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//app/service/main/resource/service: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,70 @@
package http
import (
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
"go-common/app/service/main/resource/model"
)
// pasterAPP get paster for APP
func pasterAPP(c *bm.Context) {
var (
params = c.Request.Form
aid, typeID, buvid string
platform, adType int
err error
)
aid = params.Get("aid")
typeID = params.Get("type_id")
if aid == "" && typeID == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if buvid = params.Get("buvid"); buvid == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if platform, err = strconv.Atoi(params.Get("platform")); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if adType, err = strconv.Atoi(params.Get("type")); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(resSvc.PasterAPP(c, int8(platform), int8(adType), aid, typeID, buvid))
}
// pasterPGC get paster for PGC
func pasterPGC(c *bm.Context) {
var (
params = c.Request.Form
sid, platform, device string
adType int
plat int8
err error
)
sid = params.Get("season_id")
if _, err = strconv.ParseInt(sid, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if adType, err = strconv.Atoi(params.Get("type")); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if platform = params.Get("platform"); platform == "" {
c.JSON(nil, ecode.RequestErr)
return
}
device = params.Get("device")
if platform == "web" {
plat = model.PlatWEB
} else {
plat = model.Plat(platform, device)
}
c.JSON(resSvc.PasterPGC(c, plat, int8(adType), sid))
}

View File

@@ -0,0 +1,48 @@
package http
import (
"strconv"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// banner get banner
func banner(c *bm.Context) {
params := c.Request.Form
aid, _ := strconv.ParseInt(params.Get("aid"), 10, 64)
platStr := params.Get("plat")
plat, err := strconv.Atoi(platStr)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
mobiApp := params.Get("mobi_app")
resIds := params.Get("resource_ids")
buildStr := params.Get("build")
channel := params.Get("channel")
network := params.Get("network")
isAd, _ := strconv.ParseBool(params.Get("is_ad"))
// check params
build, err := strconv.Atoi(buildStr)
if err != nil {
log.Error("build(%s) error(%v)", buildStr, err)
c.JSON(nil, ecode.RequestErr)
return
}
var mid int64
if midInter, ok := c.Get("mid"); ok {
mid = midInter.(int64)
}
buvid := params.Get("buvid")
ip := params.Get("ip")
device := params.Get("device")
openEvent := params.Get("open_event")
version := params.Get("version")
adExtra := params.Get("ad_extra")
banner := resSvc.Banners(c, int8(plat), build, aid, mid, resIds, channel, ip, buvid, network, mobiApp, device, openEvent, adExtra, version, isAd)
if banner != nil {
c.JSON(banner.Banner, nil)
}
}

View File

@@ -0,0 +1,65 @@
package http
import (
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
vfySvc *verify.Verify
resSvc *service.Service
)
// Init int http service
func Init(c *conf.Config, s *service.Service) {
vfySvc = verify.New(c.Verify)
resSvc = s
// init internal router
engineInner := bm.DefaultServer(c.BM.Inner)
innerRouter(engineInner)
// init internal server
if err := engineInner.Start(); err != nil {
log.Error("engineInner.Start() error(%v) | config(%v)", err, c)
panic(err)
}
// init external router
engineLocal := bm.DefaultServer(c.BM.Local)
localRouter(engineLocal)
// init external server
if err := engineLocal.Start(); err != nil {
log.Error("engineLocal.Start() error(%v) | config(%v)", err, c)
panic(err)
}
}
// innerRouter init outer router api path.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
rs := e.Group("/x/internal/resource")
bn := rs.Group("/banner")
bn.GET("", banner)
ads := rs.Group("/ads")
ads.GET("/paster/app", vfySvc.Verify, pasterAPP)
ads.GET("/paster/pgc", vfySvc.Verify, pasterPGC)
res := rs.Group("/res")
res.GET("", vfySvc.Verify, resource)
res.GET("/resources", vfySvc.Verify, resources)
res.GET("/indexIcon", vfySvc.Verify, indexIcon)
res.GET("/playerIcon", vfySvc.Verify, playerIcon)
res.GET("/cmtbox", vfySvc.Verify, cmtbox)
res.GET("/regionCard", vfySvc.Verify, regionCard)
res.GET("/audit", vfySvc.Verify, audit)
}
// localRouter init local router api path.
func localRouter(e *bm.Engine) {
e.GET("/x/resource/version", version)
e.GET("/x/resource/monitor", monitor)
}

View File

@@ -0,0 +1,36 @@
package http
import (
"net/http"
"go-common/app/service/main/resource/conf"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// ping check server ok.
func ping(c *bm.Context) {
if err := resSvc.Ping(c); err != nil {
log.Error("resource service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// version check server version.
func version(c *bm.Context) {
data := map[string]interface{}{
"version": conf.Conf.Version,
}
c.JSONMap(data, nil)
}
// register for discovery
func register(c *bm.Context) {
c.JSON(nil, nil)
}
// monitor for monitorURL
func monitor(c *bm.Context) {
resSvc.Monitor(c)
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,86 @@
package http
import (
"strconv"
"strings"
"go-common/app/service/main/resource/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func resource(c *bm.Context) {
var (
params = c.Request.Form
rid int
err error
)
ridStr := params.Get("rid")
if rid, err = strconv.Atoi(ridStr); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(resSvc.Resource(c, rid), nil)
}
func resources(c *bm.Context) {
var (
params = c.Request.Form
rid int
rids []int
err error
)
ridsStr := params.Get("rids")
sArr := strings.Split(ridsStr, ",")
for _, s := range sArr {
if rid, err = strconv.Atoi(s); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
rids = append(rids, rid)
}
c.JSON(resSvc.Resources(c, rids), nil)
}
func indexIcon(c *bm.Context) {
c.JSON(resSvc.IndexIcon(c), nil)
}
func playerIcon(c *bm.Context) {
c.JSON(resSvc.PlayerIcon(c))
}
func cmtbox(c *bm.Context) {
var (
params = c.Request.Form
id int64
err error
)
if id, err = strconv.ParseInt(params.Get("id"), 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(resSvc.Cmtbox(c, id))
}
func regionCard(c *bm.Context) {
var (
params = c.Request.Form
err error
)
mobiApp := params.Get("mobi_app")
buildStr := params.Get("build")
// check params
build, err := strconv.Atoi(buildStr)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
device := params.Get("device")
plat := model.Plat(mobiApp, device)
c.JSON(resSvc.RegionCard(c, plat, build))
}
func audit(c *bm.Context) {
c.JSON(resSvc.Audit(c), nil)
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["resource_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"abtest.go",
"ads.go",
"archive.go",
"banner.go",
"const.go",
"cpm.go",
"databus.go",
"relate.go",
"resource.go",
"rpc.go",
"show.go",
],
importpath = "go-common/app/service/main/resource/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/app-view/model:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/log:go_default_library",
"//library/time: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,21 @@
package model
import "hash/crc32"
// AbTest struct
type AbTest struct {
ID int64 `json:"groupId"`
Name string `json:"groupName"`
Threshold int64 `json:"flowPercent"`
ParamValues string `json:"-"`
UTime int64 `json:"-"`
}
// AbTestIn check build in test
func (ab *AbTest) AbTestIn(buvid string) (ok bool) {
ration := crc32.ChecksumIEEE([]byte(buvid)) % 100
if ration < uint32(ab.Threshold) {
ok = true
}
return
}

View File

@@ -0,0 +1,79 @@
package model
import (
xtime "go-common/library/time"
avmdl "go-common/app/interface/main/app-view/model"
)
// ads const
const (
// ads plat
VdoAdsPC = int8(0)
VdoAdsIPhone = int8(1)
VdoAdsAndroid = int8(2)
VdoAdsIPad = int8(3)
// ads type
VdoAdsTypeBangumi = int8(0)
VdoAdsTypeNologin = int8(1)
VdoAdsTypeNothing = int8(2)
VdoAdsTypeOther = int8(3)
// ads target
VdoAdsTargetArchive = int8(1)
VdoAdsTargetBangumi = int8(2)
VdoAdsTargetType = int8(3)
)
// VideoAD is Ads of videos.
type VideoAD struct {
Name string `json:"name"`
ContractID string `json:"contract_id"`
Aid int64 `json:"aid"`
SeasonID int `json:"season_id"`
TypeID int16 `json:"type _id"`
AdCid int64 `json:"ad_cid"`
AdStrategy int `json:"ad_strategy"`
AdURL string `json:"ad_url"`
AdOrder int `json:"ad_order"`
Skipable int8 `json:"skipable"`
Note string `json:"note"`
AgencyName string `json:"agency_name"`
AgencyCountry int `json:"agency_country"`
AgencyArea int `json:"agency_area"`
Price float32 `json:"price"`
Verified int `json:"verified"`
State int `json:"state"`
FrontAid int64 `json:"front_aid"`
Target int8 `json:"target"`
Platform int8 `json:"platform"`
Type int8 `json:"type"`
UserSet int8 `json:"user_set"`
PlayCount int64 `json:"play_count"`
MTime xtime.Time `json:"mtime"`
Aids string `json:"-"`
}
// Paster struct
type Paster struct {
AID int64 `json:"aid"`
CID int64 `json:"cid"`
Duration int64 `json:"duration"`
Type int8 `json:"type"`
AllowJump int8 `json:"allow_jump"`
URL string `json:"url"`
}
// PasterPlat exchange plat to video_ads
func PasterPlat(plat int8) int8 {
switch plat {
case PlatWEB:
return VdoAdsPC
case avmdl.PlatIPad, avmdl.PlatIpadHD, avmdl.PlatIPadI: // 2、9、6 -> 3
return VdoAdsIPad
case avmdl.PlatIPhone, avmdl.PlatIPhoneI: // 1、5 -> 1
return VdoAdsIPhone
case avmdl.PlatAndroid, avmdl.PlatAndroidG, avmdl.PlatAndroidI, avmdl.PlatAndroidTV, avmdl.PlatWPhone: // 0、4、8、7、3 -> 2
return VdoAdsAndroid
}
return VdoAdsIPhone // 1
}

View File

@@ -0,0 +1,82 @@
package model
// resource archive const
const (
// StateOpen 开放浏览
StateOpen = int8(0)
// StateOrange 橙色通过
StateOrange = int8(1)
// StateForbidWait 待审
StateForbidWait = int8(-1)
// StateForbidRecycle 被打回
StateForbidRecycle = int8(-2)
// StateForbidPolice 网警锁定
StateForbidPolice = int8(-3)
// StateForbidLock 被锁定
StateForbidLock = int8(-4)
// StateForbidFackLock 管理员锁定(可浏览)
StateForbidFackLock = int8(-5)
// StateForbidFixed 修复待审
StateForbidFixed = int8(-6)
// StateForbidLater 暂缓审核
StateForbidLater = int8(-7)
// StateForbidPatched 补档待审
StateForbidPatched = int8(-8)
// StateForbidWaitXcode 等待转码
StateForbidWaitXcode = int8(-9)
// StateForbidAdminDelay 延迟审核
StateForbidAdminDelay = int8(-10)
// StateForbidFixing 视频源待修
StateForbidFixing = int8(-11)
// StateForbidStorageFail 转储失败
StateForbidStorageFail = int8(-12)
// StateForbidOnlyComment 允许评论待审
StateForbidOnlyComment = int8(-13)
// StateForbidTmpRecicle 临时回收站
StateForbidTmpRecicle = int8(-14)
// StateForbidDispatch 分发中
StateForbidDispatch = int8(-15)
// StateForbidXcodeFail 转码失败
StateForbidXcodeFail = int8(-16)
// StateForbitUpLoad 创建未提交
StateForbitUpLoad = int8(-20) // NOTE:spell body can judge to change state
// StateForbidSubmit 创建已提交
StateForbidSubmit = int8(-30)
// StateForbidUserDelay 定时发布
StateForbidUserDelay = int8(-40)
// StateForbidUpDelete 用户删除
StateForbidUpDelete = int8(-100)
// resource apply
ApplyFirstAudit = 0 // 待一审
ApplySecondAudit = 1 // 待二审
ApplyNoAssignment = 2 // 未投放
ApplyAssignment = 3 // 已投放
ApplyReject = -1 // 已驳回
ApplyRecall = -2 // 已撤回
)
// Archive archive struct
type Archive struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
TypeID int16 `json:"typeid"`
HumanRank int `json:"humanrank"`
Duration int `json:"duration"`
Title string `json:"title"`
Cover string `json:"cover"`
Content string `json:"content"`
Tag string `json:"tag"`
Attribute int32 `json:"attribute"`
Copyright int8 `json:"copyright"`
AreaLimit int8 `json:"arealimit"`
State int8 `json:"state"`
Author string `json:"author"`
Access int `json:"access"`
Forward int `json:"forward"`
PubTime string `json:"pubtime"`
Reason string `json:"reject_reason"`
Round int8 `json:"round"`
CTime string `json:"ctime"`
MTime string `json:"mtime"`
}

View File

@@ -0,0 +1,162 @@
package model
import (
"encoding/json"
"strconv"
xtime "go-common/library/time"
)
// Banners struct
type Banners struct {
Banner map[int][]*Banner
Version string
}
// Banner struct
type Banner struct {
ID int `json:"id"`
ParentID int `json:"-"`
Plat int8 `json:"-"`
Module string `json:"-"`
Position string `json:"-"`
Title string `json:"title"`
Image string `json:"image"`
Hash string `json:"hash"`
URI string `json:"uri"`
Goto string `json:"-"`
Value string `json:"-"`
Param string `json:"-"`
Channel string `json:"-"`
Build int `json:"-"`
Condition string `json:"-"`
Area string `json:"-"`
Rank int `json:"-"`
Rule string `json:"-"`
Type int8 `json:"-"`
Start xtime.Time `json:"stime"`
End xtime.Time `json:"-"`
MTime xtime.Time `json:"-"`
ResourceID int `json:"resource_id"`
RequestId string `json:"request_id,omitempty"`
CreativeId int `json:"creative_id,omitempty"`
SrcId int `json:"src_id,omitempty"`
IsAd bool `json:"is_ad"`
IsAdReplace bool `json:"-"`
IsAdLoc bool `json:"is_ad_loc,omitempty"`
CmMark int `json:"cm_mark"`
AdCb string `json:"ad_cb,omitempty"`
ShowUrl string `json:"show_url,omitempty"`
ClickUrl string `json:"click_url,omitempty"`
ClientIp string `json:"client_ip,omitempty"`
Index int `json:"index"`
ServerType int `json:"server_type"`
Extra json.RawMessage `json:"extra"`
CreativeType int `json:"creative_type"`
}
// JSONBanner bilibili_assignment rule
type JSONBanner struct {
Area string `json:"area"`
Hash string `json:"hash"`
Build int `json:"build"`
Condition string `json:"cond"`
Channel string `json:"channel"`
CreativeType int `json:"creative_type"`
}
// Limit limit
type Limit struct {
Rule string `json:"-"`
}
// JSONLimit limit
type JSONLimit struct {
Limit int `json:"limit"`
Resrc []string `json:"resrc"`
}
// BannerChange change banner
func (b *Banner) BannerChange() {
var tmp *JSONBanner
if err := json.Unmarshal([]byte(b.Rule), &tmp); err == nil {
b.Area = tmp.Area
b.Build = tmp.Build
b.Condition = tmp.Condition
if tmp.Channel == "" {
b.Channel = "*"
} else {
b.Channel = tmp.Channel
}
b.Hash = tmp.Hash
b.CreativeType = tmp.CreativeType
}
switch b.Plat {
case 1: // resource iphone
b.Plat = PlatIPhone
case 2: // resource android
b.Plat = PlatAndroid
case 3: // resource pad
b.Plat = PlatIPad
case 4: // resource iphoneg
b.Plat = PlatIPhoneI
case 5: // resource androidg
b.Plat = PlatAndroidG
case 6: // resource padg
b.Plat = PlatIPadI
case 8: // resource androidi
b.Plat = PlatAndroidI
}
if b.Value == "" {
return
}
switch b.Type {
case 7:
if b.Plat == PlatIPhone || b.Plat == PlatAndroid || b.Plat == PlatIPad || b.Plat == PlatIPhoneI || b.Plat == PlatAndroidG || b.Plat == PlatIPadI || b.Plat == PlatAndroidI {
b.URI = "bilibili://pegasus/channel/" + b.Value + "/"
} else {
b.URI = "http://www.bilibili.com/tag/" + b.Value
}
case 6:
//GotoAv
b.URI = "bilibili://video/" + b.Value
case 4:
//GotoLive
if b.Plat == PlatIPad {
b.URI = "bilibili://player/live/" + b.Value
} else {
b.URI = "bilibili://live/" + b.Value
}
case 3:
//GotoBangumi
b.URI = "bilibili://bangumi/season/" + b.Value
case 5:
//GotoGame
b.URI = "bilibili://game/" + b.Value
case 2:
//GotoWeb
b.URI = b.Value
}
}
// LimitChange change limit
func (l *Limit) LimitChange() (data map[int]int) {
data = map[int]int{}
var (
tmp = &JSONLimit{}
err error
resid int
)
if err = json.Unmarshal([]byte(l.Rule), tmp); err != nil {
return
}
l.Rule = ""
for _, residstr := range tmp.Resrc {
resid, err = strconv.Atoi(residstr)
if err != nil {
return
}
data[resid] = tmp.Limit
}
return
}

View File

@@ -0,0 +1,146 @@
package model
// resource const
const (
// PlatAndroid is int8 for android.
PlatAndroid = int8(0)
// PlatIPhone is int8 for iphone.
PlatIPhone = int8(1)
// PlatIPad is int8 for ipad.
PlatIPad = int8(2)
// PlatWPhone is int8 for wphone.
PlatWPhone = int8(3)
// PlatAndroidG is int8 for Android Googleplay.
PlatAndroidG = int8(4)
// PlatIPhoneI is int8 for Iphone Global.
PlatIPhoneI = int8(5)
// PlatIPadI is int8 for IPAD Global.
PlatIPadI = int8(6)
// PlatAndroidTV is int8 for AndroidTV Global.
PlatAndroidTV = int8(7)
// PlatAndroidI is int8 for Android Global.
PlatAndroidI = int8(8)
// PlatAndroidB is int8 for Android Bule.
PlatAndroidB = int8(9)
// PlatWEB is int8 for web.
PlatWEB = int8(99)
// goto
GotoAv = "av"
GotoWeb = "web"
GotoBangumi = "bangumi"
GotoBangumiWeb = "bangumi_web"
GotoSp = "sp"
GotoLive = "live"
GotoGame = "game"
GotoArticle = "article"
GotoActivity = "activity_new"
GotoTopic = "topic_new"
GotoDaily = "daily"
GotoRank = "rank"
GotoCard = "card"
GotoVeidoCard = "video_card"
GotoSpecialCard = "special_card"
GotoTagCard = "tag_card"
GotoColumn = "column"
GotoColumnStage = "column_stage"
GotoTagID = "tag_id"
CardGotoAv = int8(1)
CardGotoTopic = int8(2)
CardGotoActivity = int8(3)
)
// InvalidBuild check source build is not allow by config build and condition.
// eg: when condition is gt, means srcBuild must gt cfgBuild, otherwise is invalid srcBuild.
func InvalidBuild(srcBuild, cfgBuild int, cfgCond string) bool {
if cfgBuild != 0 && cfgCond != "" {
switch cfgCond {
case "gt":
if cfgBuild >= srcBuild {
return true
}
case "lt":
if cfgBuild <= srcBuild {
return true
}
case "eq":
if cfgBuild != srcBuild {
return true
}
case "ne":
if cfgBuild == srcBuild {
return true
}
}
}
return false
}
// InvalidChannel check source channel is not allow by config channel.
func InvalidChannel(plat int8, srcCh, cfgCh string) bool {
return plat == PlatAndroid && cfgCh != "*" && cfgCh != srcCh
}
// Plat return plat by platStr or mobiApp
func Plat(mobiApp, device string) int8 {
switch mobiApp {
case "iphone":
if device == "pad" {
return PlatIPad
}
return PlatIPhone
case "white":
return PlatIPhone
case "ipad":
return PlatIPad
case "android":
return PlatAndroid
case "win":
return PlatWPhone
case "android_G":
return PlatAndroidG
case "android_I":
return PlatAndroidI
case "iphone_I":
if device == "pad" {
return PlatIPadI
}
return PlatIPhoneI
case "ipad_I":
return PlatIPadI
case "android_tv":
return PlatAndroidTV
}
return PlatIPhone
}
// FillURI deal app schema.
func FillURI(gt, param string) (uri string) {
if param == "" {
return
}
switch gt {
case GotoAv, "":
uri = "bilibili://video/" + param
case GotoLive:
uri = "bilibili://live/" + param
case GotoBangumi:
uri = "bilibili://bangumi/season/" + param
case GotoBangumiWeb:
uri = "http://bangumi.bilibili.com/anime/" + param
case GotoGame:
uri = "bilibili://game/" + param
case GotoSp:
uri = "bilibili://splist/" + param
case GotoWeb:
uri = param
case GotoDaily:
uri = "bilibili://daily/" + param
case GotoColumn:
uri = "bilibili://pegasus/list/column/" + param
case GotoArticle:
uri = "bilibili://article/" + param
}
return
}

View File

@@ -0,0 +1,91 @@
package model
import (
"encoding/json"
"strconv"
"go-common/library/log"
)
// ADRequest cpm type
type ADRequest struct {
RequestID string `json:"request_id"`
ADIndexs map[string]map[string]*ADIndex `json:"ads_info"`
}
// ADIndex cpm type
type ADIndex struct {
Index int `json:"index"`
Info *ADInfo `json:"ad_info"`
IsAd bool `json:"is_ad"`
CmMark int `json:"cm_mark"`
}
// ADInfo cpm type
type ADInfo struct {
CreativeID int `json:"creative_id"`
CreativeType int `json:"creative_type"`
CreativeContent struct {
Title string `json:"title"`
Desc string `json:"description"`
VideoID int64 `json:"video_id"`
UserName string `json:"username"`
ImageURL string `json:"image_url"`
ImageMD5 string `json:"image_md5"`
LogURL string `json:"log_url"`
LogMD5 string `json:"log_md5"`
URL string `json:"url"`
ClickURL string `json:"click_url"`
ShowURL string `json:"show_url"`
} `json:"creative_content"`
AdCb string `json:"ad_cb"`
Extra json.RawMessage `json:"extra"`
}
// ConvertBanner expair cpm type
func (adr *ADRequest) ConvertBanner(ip, mobiApp string, build int) (banners map[int]map[int]*Banner) {
banners = map[int]map[int]*Banner{}
for resIDStr, sAdis := range adr.ADIndexs {
resID, _ := strconv.Atoi(resIDStr)
if len(sAdis) == 0 {
log.Info("mobi_app:%v-build:%v-resource:%v-is_ad_loc:%v", mobiApp, build, resID, false)
continue
}
for sidStr, adi := range sAdis {
sid, _ := strconv.Atoi(sidStr)
var bnnr = &Banner{
IsAdLoc: true,
IsAd: adi.IsAd,
IsAdReplace: false,
CmMark: adi.CmMark,
Rank: adi.Index,
SrcId: sid,
RequestId: adr.RequestID,
ClientIp: ip,
}
if adInfo := adi.Info; adInfo != nil {
bnnr.IsAdReplace = true
bnnr.CreativeId = adInfo.CreativeID
bnnr.AdCb = adInfo.AdCb
bnnr.ShowUrl = adInfo.CreativeContent.ShowURL
bnnr.ClickUrl = adInfo.CreativeContent.ClickURL
bnnr.Title = adInfo.CreativeContent.Title
bnnr.Image = adInfo.CreativeContent.ImageURL
bnnr.Hash = adInfo.CreativeContent.ImageMD5
bnnr.URI = adInfo.CreativeContent.URL
bnnr.Channel = "*"
bnnr.Extra = adInfo.Extra
bnnr.ServerType = 1
}
if _, ok := banners[resID]; ok {
banners[resID][bnnr.Rank] = bnnr
} else {
banners[resID] = map[int]*Banner{
bnnr.Rank: bnnr,
}
}
log.Info("mobi_app:%v-build:%v-source:%v-resource:%v-is_ad_loc:%v", mobiApp, build, sid, resID, true)
}
}
return
}

View File

@@ -0,0 +1,28 @@
package model
import "encoding/json"
// Message databus
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// databus const
const (
RouteFirstRoundForbid = "first_round_forbid"
RouteSecondRound = "second_round"
RouteAutoOpen = "auto_open"
RouteDelayOpen = "delay_open"
RouteDeleteArchive = "delete_archive"
RouteForceSync = "force_sync"
)
// Videoup message for videoup2BVC
type Videoup struct {
Route string `json:"route"`
Timestamp int64 `json:"timestamp"`
Aid int64 `json:"aid"`
}

View File

@@ -0,0 +1,27 @@
package model
import xtime "go-common/library/time"
//Version app version
type Version struct {
Plat int8 `json:"plat,omitempty"`
Build int `json:"build,omitempty"`
Condition string `json:"conditions,omitempty"`
}
//Relate relate card
type Relate struct {
ID int64 `json:"id,omitempty"`
Param int64 `json:"param,omitempty"`
Goto string `json:"goto,omitempty"`
Title string `json:"title,omitempty"`
ResourceIDs string `json:"resource_ids,omitempty"`
TagIDs string `json:"tag_ids,omitempty"`
ArchiveIDs string `json:"archive_ids,omitempty"`
RecReason string `json:"rec_reason,omitempty"`
Position int32 `json:"position,omitempty"`
STime xtime.Time `json:"stime,omitempty"`
ETime xtime.Time `json:"etime,omitempty"`
Versions map[int8][]*Version `json:"versions,omitempty"`
PgcIDs string
}

View File

@@ -0,0 +1,144 @@
package model
import (
xtime "go-common/library/time"
)
// resource const
const (
IconTypeFix = 1
IconTypeRandom = 2
IconTypeBangumi = 3
NoCategory = 0
IsCategory = 1
AsgTypePic = int8(0)
AsgTypeVideo = int8(1)
// pgc mobile
AsgTypeURL = int8(2)
AsgTypeBangumi = int8(3)
AsgTypeLive = int8(4)
AsgTypeGame = int8(5)
AsgTypeAv = int8(6)
)
// IconTypes icon_type
var IconTypes = map[int]string{
IconTypeFix: "fix",
IconTypeRandom: "random",
IconTypeBangumi: "bangumi",
}
// Rule resource_assignmen rule
type Rule struct {
Cover int32 `json:"is_cover"`
Style int32 `json:"style"`
Label string `json:"label"`
Intro string `json:"intro"`
}
// Resource struct
type Resource struct {
ID int `json:"id"`
Platform int `json:"platform"`
Name string `json:"name"`
Parent int `json:"parent"`
State int `json:"-"`
Counter int `json:"counter"`
Position int `json:"position"`
Rule string `json:"rule"`
Size string `json:"size"`
Previce string `json:"preview"`
Desc string `json:"description"`
Mark string `json:"mark"`
Assignments []*Assignment `json:"assignments"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
Level int64 `json:"level"`
Type int `json:"type"`
IsAd int `json:"is_ad"`
}
// Assignment struct
type Assignment struct {
ID int `json:"id"`
AsgID int `json:"-"`
Name string `json:"name"`
ContractID string `json:"contract_id"`
ResID int `json:"resource_id"`
Pic string `json:"pic"`
LitPic string `json:"litpic"`
URL string `json:"url"`
Rule string `json:"rule"`
Weight int `json:"weight"`
Agency string `json:"agency"`
Price float32 `json:"price"`
State int `json:"state"`
Atype int8 `json:"atype"`
Username string `json:"username"`
PlayerCategory int8 `json:"player_category"`
ApplyGroupID int `json:"-"`
STime xtime.Time `json:"stime"`
ETime xtime.Time `json:"etime"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}
// IndexIcon struct
type IndexIcon struct {
ID int64 `json:"id"`
Type int `json:"type"`
Title string `json:"title"`
State int `json:"state"`
Links []string `json:"links"`
Icon string `json:"icon"`
Weight int `json:"weight"`
UserName string `json:"-"`
StTime xtime.Time `json:"sttime"`
EndTime xtime.Time `json:"endtime"`
DelTime xtime.Time `json:"deltime"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}
// PlayerIcon struct
type PlayerIcon struct {
URL1 string `json:"url1"`
Hash1 string `json:"hash1"`
URL2 string `json:"url2"`
Hash2 string `json:"hash2"`
CTime xtime.Time `json:"ctime"`
}
// ResWarnInfo for email
type ResWarnInfo struct {
AID int64
URL string
AssignmentID int
AssignmentName string
ResourceName string
ResourceID int
MaterialID int
UserName string
STime xtime.Time `json:"stime"`
ETime xtime.Time `json:"etime"`
ApplyGroupID int
}
// Cmtbox live danmaku box
type Cmtbox struct {
ID int64 `json:"id"`
LoadCID int64 `json:"load_cid"`
Server string `json:"server"`
Port string `json:"port"`
SizeFactor string `json:"size_factor"`
SpeedFactor string `json:"speed_factor"`
MaxOnscreen string `json:"max_onscreen"`
Style string `json:"style"`
StyleParam string `json:"style_param"`
TopMargin string `json:"top_margin"`
State string `json:"state"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}

View File

@@ -0,0 +1,8 @@
package model
import (
"testing"
)
func TestCPM(t *testing.T) {
}

View File

@@ -0,0 +1,51 @@
package model
// ArgBanner for banner func
type ArgBanner struct {
Plat int8
Build int
AID int64
MID int64
ResIDs string
Channel string
IP string
Buvid string
Network string
MobiApp string
Device string
IsAd bool
OpenEvent string
AdExtra string
Version string
}
// ArgRes for resource func
type ArgRes struct {
ResID int
}
// ArgRess for resources func
type ArgRess struct {
ResIDs []int
}
// ArgPaster for paster func
type ArgPaster struct {
Platform int8
AdType int8
Aid string
TypeId string
TypeID string
Buvid string
}
// ArgCmtbox for ctmbox
type ArgCmtbox struct {
ID int64
}
// ArgAbTest for abTest
type ArgAbTest struct {
Groups string
IP string
}

View File

@@ -0,0 +1,216 @@
package model
import (
"encoding/json"
"strconv"
"go-common/app/service/main/archive/api"
xtime "go-common/library/time"
)
// Card audio card struct
type Card struct {
ID int `json:"-"`
Tab int `json:"-"`
RegionID int `json:"-"`
Type int `json:"-"`
Title string `json:"-"`
Cover string `json:"-"`
Rtype int `json:"-"`
Rvalue string `json:"-"`
PlatVer string `json:"-"`
Plat int8 `json:"-"`
Build int `json:"-"`
Condition string `json:"-"`
TypeStr string `json:"-"`
Goto string `json:"-"`
Param string `json:"-"`
URI string `json:"-"`
Desc string `json:"-"`
TagID int `json:"-"`
}
// Content audio content struct
type Content struct {
ID int `json:"-"`
Module int `json:"-"`
RecID int `json:"-"`
Type int8 `json:"-"`
Value string `json:"-"`
Title string `json:"-"`
TagID int `json:"-"`
}
// PlatLimit audio plat limit struct
type PlatLimit struct {
Plat int8 `json:"plat"`
Build int `json:"build"`
Condition string `json:"conditions"`
}
// ShowItem audio show item struct
type ShowItem struct {
Title string `json:"title"`
Cover string `json:"cover"`
URI string `json:"uri"`
NewURI string `json:"-"`
Param string `json:"param"`
Goto string `json:"goto"`
// up
Mid int64 `json:"mid,omitempty"`
Name string `json:"name,omitempty"`
Face string `json:"face,omitempty"`
Follower int `json:"follower,omitempty"`
Attribute int `json:"attribute,omitempty"`
OfficialVerify *OfficialVerify `json:"official_verify,omitempty"`
// stat
Play int `json:"play,omitempty"`
Danmaku int `json:"danmaku,omitempty"`
Reply int `json:"reply,omitempty"`
Fav int `json:"favourite,omitempty"`
// movie and bangumi badge
Status int8 `json:"status,omitempty"`
CoverMark string `json:"cover_mark,omitempty"`
// ranking
Pts int64 `json:"pts,omitempty"`
Children []*ShowItem `json:"children,omitempty"`
// av
PubDate xtime.Time `json:"pubdate"`
// av stat
Duration int64 `json:"duration,omitempty"`
// region
Rid int `json:"rid,omitempty"`
Rname string `json:"rname,omitempty"`
Reid int `json:"reid,omitempty"`
//new manager
Desc string `json:"desc,omitempty"`
Stime string `json:"stime,omitempty"`
Etime string `json:"etime,omitempty"`
Like int `json:"like,omitempty"`
}
// OfficialVerify audio verify struct
type OfficialVerify struct {
Type int `json:"type"`
Desc string `json:"desc"`
}
// Head audio struct
type Head struct {
CardID int `json:"card_id,omitempty"`
Title string `json:"title,omitempty"`
Cover string `json:"cover,omitempty"`
Type string `json:"type,omitempty"`
Date int64 `json:"date,omitempty"`
Plat int8 `json:"-"`
Build int `json:"-"`
Condition string `json:"-"`
URI string `json:"uri,omitempty"`
Goto string `json:"goto,omitempty"`
Param string `json:"param,omitempty"`
Body []*ShowItem `json:"body,omitempty"`
}
// CardPlatChange audio card change plat
func (c *Card) CardPlatChange() (platlinits []*PlatLimit) {
platlinits = platJSONChange(c.PlatVer)
return
}
// platJSONChange json change plat build condition
func platJSONChange(jsonStr string) (platlinits []*PlatLimit) {
var tmp []struct {
Plat string `json:"plat"`
Build string `json:"build"`
Condition string `json:"conditions"`
}
if err := json.Unmarshal([]byte(jsonStr), &tmp); err == nil {
for _, limit := range tmp {
platlinit := &PlatLimit{}
switch limit.Plat {
case "0": // resource android
platlinit.Plat = PlatAndroid
case "1": // resource iphone
platlinit.Plat = PlatIPhone
case "2": // resource pad
platlinit.Plat = PlatIPad
case "5": // resource iphone_i
platlinit.Plat = PlatIPhoneI
case "8": // resource android_i
platlinit.Plat = PlatAndroidI
}
platlinit.Build, _ = strconv.Atoi(limit.Build)
platlinit.Condition = limit.Condition
platlinits = append(platlinits, platlinit)
}
}
return
}
// FromArchivePB from archive archive.
func (i *ShowItem) FromArchivePB(a *api.Arc) {
i.Title = a.Title
i.Cover = a.Pic
i.Param = strconv.FormatInt(a.Aid, 10)
i.URI = FillURI(GotoAv, i.Param)
i.Goto = GotoAv
i.Play = int(a.Stat.View)
i.Danmaku = int(a.Stat.Danmaku)
i.Name = a.Author.Name
i.Reply = int(a.Stat.Reply)
i.Fav = int(a.Stat.Fav)
i.PubDate = a.PubDate
i.Rid = int(a.TypeID)
i.Rname = a.TypeName
i.Duration = a.Duration
i.Like = int(a.Stat.Like)
if a.Access > 0 {
i.Play = 0
}
}
// FillBuildURI fill url by plat build
func (h *Head) FillBuildURI(plat int8, build int) {
switch h.Goto {
case GotoDaily:
if (plat == PlatIPhone && build > 6670) || (plat == PlatAndroid && build > 5250000) {
h.URI = "bilibili://pegasus/list/daily/" + h.Param
}
}
}
// SideBars for side bars
type SideBars struct {
SideBar []*SideBar `json:"sidebar,omitempty"`
Limit map[int64][]*SideBarLimit `json:"limit,omitempty"`
}
// SideBar for side bar
type SideBar struct {
ID int64 `json:"id,omitempty"`
Tip int `json:"tip,omitempty"`
Rank int `json:"rank,omitempty"`
Logo string `json:"logo,omitempty"`
LogoWhite string `json:"logo_white,omitempty"`
Name string `json:"name,omitempty"`
Param string `json:"param,omitempty"`
Module int `json:"module,omitempty"`
Plat int8 `json:"-"`
Build int `json:"-"`
Conditions string `json:"-"`
OnlineTime xtime.Time `json:"online_time"`
NeedLogin int8 `json:"need_login,omitempty"`
WhiteURL string `json:"white_url,omitempty"`
Menu int8 `json:"menu,omitempty"`
LogoSelected string `json:"logo_selected,omitempty"`
TabID string `json:"tab_id,omitempty"`
Red string `json:"red_dot_url,omitempty"`
Language string `json:"language,omitempty"`
}
// SideBarLimit side bar limit
type SideBarLimit struct {
ID int64 `json:"-"`
Build int `json:"-"`
Condition string `json:"-"`
}

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["client_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//app/service/main/resource/model:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/app/service/main/resource/rpc/client",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/model:go_default_library",
"//library/net/rpc: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,126 @@
package client
import (
"context"
"go-common/app/service/main/resource/model"
"go-common/library/net/rpc"
)
var (
_noArg = &struct{}{}
)
const (
_resourceAll = "RPC.ResourceAll"
_assignmentAll = "RPC.AssignmentAll"
_defBanner = "RPC.DefBanner"
_resource = "RPC.Resource"
_resources = "RPC.Resources"
_banners = "RPC.Banners"
_pasterAPP = "RPC.PasterAPP"
_indexIcon = "RPC.IndexIcon"
_playerIcon = "RPC.PlayerIcon"
_cmtbox = "RPC.Cmtbox"
_sidebars = "RPC.SideBars"
_abtest = "RPC.AbTest"
_pasterCID = "RPC.PasterCID"
// app id
_appid = "resource.service"
)
// Service is resource rpc client.
type Service struct {
client *rpc.Client2
}
// New new a resource rpc client.
func New(c *rpc.ClientConfig) (s *Service) {
s = &Service{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return
}
// ResourceAll get all resource.
func (s *Service) ResourceAll(c context.Context) (res []*model.Resource, err error) {
err = s.client.Call(c, _resourceAll, _noArg, &res)
return
}
// AssignmentAll get all assignment.
func (s *Service) AssignmentAll(c context.Context) (res []*model.Assignment, err error) {
err = s.client.Call(c, _assignmentAll, _noArg, &res)
return
}
// DefBanner get default banner.
func (s *Service) DefBanner(c context.Context) (res *model.Assignment, err error) {
res = new(model.Assignment)
err = s.client.Call(c, _defBanner, _noArg, res)
return
}
// Resource get resource.
func (s *Service) Resource(c context.Context, arg *model.ArgRes) (res *model.Resource, err error) {
res = new(model.Resource)
err = s.client.Call(c, _resource, arg, res)
return
}
// Resources get resource.
func (s *Service) Resources(c context.Context, arg *model.ArgRess) (res map[int]*model.Resource, err error) {
err = s.client.Call(c, _resources, arg, &res)
return
}
// Banners get banners.
func (s *Service) Banners(c context.Context, arg *model.ArgBanner) (res *model.Banners, err error) {
err = s.client.Call(c, _banners, arg, &res)
return
}
// PasterAPP get paster.
func (s *Service) PasterAPP(c context.Context, arg *model.ArgPaster) (res *model.Paster, err error) {
res = new(model.Paster)
err = s.client.Call(c, _pasterAPP, arg, res)
return
}
// IndexIcon get index icons.
func (s *Service) IndexIcon(c context.Context) (res map[string][]*model.IndexIcon, err error) {
err = s.client.Call(c, _indexIcon, _noArg, &res)
return
}
// PlayerIcon get palyer config.
func (s *Service) PlayerIcon(c context.Context) (res *model.PlayerIcon, err error) {
res = new(model.PlayerIcon)
err = s.client.Call(c, _playerIcon, _noArg, res)
return
}
// Cmtbox get live box
func (s *Service) Cmtbox(c context.Context, arg *model.ArgCmtbox) (res *model.Cmtbox, err error) {
err = s.client.Call(c, _cmtbox, arg, &res)
return
}
// SideBars get side bar.
func (s *Service) SideBars(c context.Context) (res *model.SideBars, err error) {
res = new(model.SideBars)
err = s.client.Call(c, _sidebars, _noArg, res)
return
}
// AbTest get abtest.
func (s *Service) AbTest(c context.Context, arg *model.ArgAbTest) (res map[string]*model.AbTest, err error) {
err = s.client.Call(c, _abtest, arg, &res)
return
}
// PasterCID get all Paster's cid.
func (s *Service) PasterCID(c context.Context) (res map[int64]int64, err error) {
err = s.client.Call(c, _pasterCID, _noArg, &res)
return
}

View File

@@ -0,0 +1,191 @@
package client
import (
"context"
"testing"
"time"
"go-common/app/service/main/resource/model"
)
func TestResource(t *testing.T) {
s := New(nil)
time.Sleep(2 * time.Second)
testResourceAll(t, s)
testAssignmentAll(t, s)
testDefBanner(t, s)
testResource(t, s)
testResources(t, s)
testBanners(t, s)
testPasterAPP(t, s)
testIndexIcon(t, s)
testPlayerIcon(t, s)
testCmtbox(t, s)
testSideBars(t, s)
testAbTest(t, s)
testPasterCID(t, s)
}
// testResourceAll test rpc ResourceAll.
func testResourceAll(t *testing.T, s *Service) {
res, err := s.ResourceAll(context.TODO())
if err != nil {
t.Logf("testResourceAll error(%v) \n", err)
return
}
t.Logf("testResourceAll res: %+v \n", res)
}
// testAssignmentAll test rpc AssignmentAll.
func testAssignmentAll(t *testing.T, s *Service) {
res, err := s.AssignmentAll(context.TODO())
if err != nil {
t.Logf("testAssignmentAll error(%v) \n", err)
return
}
t.Logf("testAssignmentAll res: %+v \n", res)
}
// testDefBanner test rpc DefBanner.
func testDefBanner(t *testing.T, s *Service) {
res, err := s.DefBanner(context.TODO())
if err != nil {
t.Logf("testDefBanner error(%v) \n", err)
return
}
t.Logf("testDefBanner res: %+v \n", res)
}
// testResource test rpc Resource.
func testResource(t *testing.T, s *Service) {
p := &model.ArgRes{
ResID: 1233,
}
res, err := s.Resource(context.TODO(), p)
if err != nil {
t.Logf("testResource error(%v) \n", err)
return
}
t.Logf("testResource res: %+v \n", res)
}
// testResources test rpc Resources.
func testResources(t *testing.T, s *Service) {
p := &model.ArgRess{
ResIDs: []int{1187, 1639},
}
res, err := s.Resources(context.TODO(), p)
if err != nil {
t.Logf("testResources error(%v) \n", err)
return
}
t.Logf("testResources res: %+v \n", res)
}
// testBanners test rpc Banners.
func testBanners(t *testing.T, s *Service) {
ab := &model.ArgBanner{
Plat: 1,
ResIDs: "454,467",
Build: 508000,
MID: 1493031,
Channel: "abc",
IP: "211.139.80.6",
Buvid: "123",
Network: "wifi",
MobiApp: "iphone",
Device: "test",
IsAd: true,
OpenEvent: "abc",
}
res, err := s.Banners(context.TODO(), ab)
if err != nil {
t.Logf("testBanners error(%v) \n", err)
return
}
t.Logf("testBanners res: %+v \n", res)
}
// testPasterAPP test rpc Paster.
func testPasterAPP(t *testing.T, s *Service) {
p := &model.ArgPaster{
Platform: int8(4),
AdType: int8(1),
Aid: "10097274",
TypeId: "11",
Buvid: "666666",
}
res, err := s.PasterAPP(context.TODO(), p)
if err != nil {
t.Logf("testPasterAPP error(%v) \n", err)
return
}
t.Logf("testPaster res: %+v \n", res)
}
// testIndexIcon test rpc IndexIcon.
func testIndexIcon(t *testing.T, s *Service) {
res, err := s.IndexIcon(context.TODO())
if err != nil {
t.Logf("testIndexIcon error(%v) \n", err)
return
}
t.Logf("testIndexIcon res: %+v \n", res)
}
// testPlayerIcon test rpc PlayerIcon.
func testPlayerIcon(t *testing.T, s *Service) {
res, err := s.PlayerIcon(context.TODO())
if err != nil {
t.Logf("testPlayerIcon error(%v) \n", err)
return
}
t.Logf("testPlayerIcon res: %+v \n", res)
}
// testCmtbox test rpc Resource.
func testCmtbox(t *testing.T, s *Service) {
p := &model.ArgCmtbox{
ID: 1,
}
res, err := s.Cmtbox(context.TODO(), p)
if err != nil {
t.Logf("testCmtbox error(%v) \n", err)
return
}
t.Logf("testCmtbox res: %+v \n", res)
}
// testSideBars test rpc SideBars.
func testSideBars(t *testing.T, s *Service) {
res, err := s.SideBars(context.TODO())
if err != nil {
t.Logf("testSideBars error(%v) \n", err)
return
}
t.Logf("testSideBars res: %+v \n", res)
}
// testAbTest test rpc abtest.
func testAbTest(t *testing.T, s *Service) {
p := &model.ArgAbTest{
Groups: "不显示热门tab,显示热门tab",
IP: "127.0.0.1",
}
res, err := s.AbTest(context.TODO(), p)
if err != nil {
t.Logf("testAbTest error(%v) \n", err)
return
}
t.Logf("testAbTest res: %+v \n", res)
}
// testPasterCID test rpc PasterCID
func testPasterCID(t *testing.T, s *Service) {
res, err := s.PasterCID(context.TODO())
if err != nil {
t.Logf("testPasterCID error(%v) \n", err)
return
}
t.Logf("testPasterCID res: %+v \n", res)
}

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["server_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//app/service/main/resource/service:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/resource/rpc/server",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//app/service/main/resource/service:go_default_library",
"//library/ecode:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/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,131 @@
package server
import (
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/model"
"go-common/app/service/main/resource/service"
"go-common/library/ecode"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC struct
type RPC struct {
s *service.Service
}
// New init rpc server.
func New(c *conf.Config, s *service.Service) (svr *rpc.Server) {
r := &RPC{s: s}
svr = rpc.NewServer(c.RPCServer)
if err := svr.Register(r); err != nil {
panic(err)
}
return
}
// Ping check connection success.
func (r *RPC) Ping(c context.Context, arg *struct{}, res *struct{}) (err error) {
return
}
// ResourceAll get all resource.
func (r *RPC) ResourceAll(c context.Context, a *struct{}, res *[]*model.Resource) (err error) {
*res = r.s.ResourceAll(c)
return
}
// AssignmentAll get all assignment.
func (r *RPC) AssignmentAll(c context.Context, a *struct{}, res *[]*model.Assignment) (err error) {
*res = r.s.AssignmentAll(c)
return
}
// DefBanner get default banner.
func (r *RPC) DefBanner(c context.Context, a *struct{}, as *model.Assignment) (err error) {
res := r.s.DefBanner(c)
if res == nil {
err = ecode.NothingFound
return
}
*as = *res
return
}
// Resource get resource.
func (r *RPC) Resource(c context.Context, arg *model.ArgRes, res *model.Resource) (err error) {
rs := r.s.Resource(c, arg.ResID)
if rs == nil {
err = ecode.NothingFound
return
}
*res = *rs
return
}
// Resources get resource.
func (r *RPC) Resources(c context.Context, as *model.ArgRess, res *map[int]*model.Resource) (err error) {
*res = r.s.Resources(c, as.ResIDs)
return
}
// Banners get banners.
func (r *RPC) Banners(c context.Context, ab *model.ArgBanner, res *model.Banners) (err error) {
// func Banners already new rs, rs can not be nil.
rs := r.s.Banners(c, ab.Plat, ab.Build, ab.AID, ab.MID, ab.ResIDs, ab.Channel, ab.IP, ab.Buvid, ab.Network, ab.MobiApp, ab.Device, ab.OpenEvent, ab.AdExtra, ab.Version, ab.IsAd)
*res = *rs
return
}
// PasterAPP get paster for APP.
func (r *RPC) PasterAPP(c context.Context, arg *model.ArgPaster, res *model.Paster) (err error) {
var rs *model.Paster
if rs, err = r.s.PasterAPP(c, arg.Platform, arg.AdType, arg.Aid, arg.TypeId, arg.Buvid); err == nil {
*res = *rs
}
return
}
// IndexIcon get index icon.
func (r *RPC) IndexIcon(c context.Context, a *struct{}, res *map[string][]*model.IndexIcon) (err error) {
*res = r.s.IndexIcon(c)
return
}
// PlayerIcon get player icon config.
func (r *RPC) PlayerIcon(c context.Context, arg *struct{}, res *model.PlayerIcon) (err error) {
var rs *model.PlayerIcon
rs, err = r.s.PlayerIcon(c)
if err == nil {
*res = *rs
}
return
}
// Cmtbox get live box.
func (r *RPC) Cmtbox(c context.Context, cb *model.ArgCmtbox, res *model.Cmtbox) (err error) {
rs, err := r.s.Cmtbox(c, cb.ID)
if err == nil {
*res = *rs
}
return
}
// SideBars get sode bar.
func (r *RPC) SideBars(c context.Context, a *struct{}, res *model.SideBars) (err error) {
sbs := r.s.SideBars(c)
*res = *sbs
return
}
// AbTest get abtest.
func (r *RPC) AbTest(c context.Context, ab *model.ArgAbTest, res *map[string]*model.AbTest) (err error) {
*res = r.s.AbTest(c, ab.Groups, ab.IP)
return
}
// PasterCID get all Paster's cid.
func (r *RPC) PasterCID(c context.Context, a *struct{}, res *map[int64]int64) (err error) {
*res, err = r.s.PasterCID(c)
return
}

View File

@@ -0,0 +1,239 @@
package server
import (
"fmt"
"net/rpc"
"testing"
"time"
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/model"
"go-common/app/service/main/resource/service"
)
// rpc server const
const (
addr = "127.0.0.1:6429"
_resourceAll = "RPC.ResourceAll"
_assignmentAll = "RPC.AssignmentAll"
_defBanner = "RPC.DefBanner"
_resource = "RPC.Resource"
_resources = "RPC.Resources"
_assignment = "RPC.Assignment"
_banners = "RPC.Banners"
_pasterAPP = "RPC.PasterAPP"
_indexIcon = "RPC.IndexIcon"
_playerIcon = "RPC.playerIcon"
_cmtbox = "RPC.Cmtbox"
_sidebars = "RPC.SideBars"
_abtest = "RPC.AbTest"
_pasterCID = "RPC.PasterCID"
)
// TestResource test rpc server
func TestResource(t *testing.T) {
if err := conf.Init(); err != nil {
t.Errorf("conf.Init() error(%v)", err)
t.FailNow()
}
svr := service.New(conf.Conf)
New(conf.Conf, svr)
time.Sleep(time.Second * 3)
client, err := rpc.Dial("tcp", addr)
defer client.Close()
if err != nil {
t.Errorf("rpc.Dial(tcp, \"%s\") error(%v)", addr, err)
t.FailNow()
}
resourceAllRPC(client, t)
assignmentAllRPC(client, t)
defBannerRPC(client, t)
resourceRPC(client, t)
resourcesRPC(client, t)
assignmentRPC(client, t)
bannersRPC(client, t)
pasterAPPRpc(client, t)
indexIconRPC(client, t)
playerIconRPC(client, t)
cmtboxRPC(client, t)
sideBarsRPC(client, t)
abTestRPC(client, t)
pasterCIDRPC(client, t)
}
func resourceAllRPC(client *rpc.Client, t *testing.T) {
var res []*model.Resource
arg := &struct{}{}
if err := client.Call(_resourceAll, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("resourceAll", t, res)
}
}
func assignmentAllRPC(client *rpc.Client, t *testing.T) {
var res []*model.Assignment
arg := &struct{}{}
if err := client.Call(_assignmentAll, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("assignmentAll", t, res)
}
}
func defBannerRPC(client *rpc.Client, t *testing.T) {
var res model.Assignment
arg := &struct{}{}
if err := client.Call(_defBanner, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("defBanner", t, res)
}
}
func resourceRPC(client *rpc.Client, t *testing.T) {
var res model.Resource
arg := &model.ArgRes{
ResID: 1187,
}
if err := client.Call(_resource, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("resource", t, res)
}
}
func resourcesRPC(client *rpc.Client, t *testing.T) {
var res map[int]*model.Resource
arg := &model.ArgRess{
ResIDs: []int{1187, 1639},
}
if err := client.Call(_resources, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("resources", t, res)
}
}
func assignmentRPC(client *rpc.Client, t *testing.T) {
var res []*model.Assignment
arg := &model.ArgRes{
ResID: 1187,
}
if err := client.Call(_assignment, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("assignment", t, res)
}
}
func bannersRPC(client *rpc.Client, t *testing.T) {
var res *model.Banners
arg := &model.ArgBanner{
Plat: 1,
ResIDs: "454,467",
Build: 508000,
MID: 1493031,
Channel: "abc",
IP: "211.139.80.6",
Buvid: "123",
Network: "wifi",
MobiApp: "iphone",
Device: "test",
IsAd: true,
OpenEvent: "abc",
}
if err := client.Call(_banners, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("banners", t, res)
}
}
func pasterAPPRpc(client *rpc.Client, t *testing.T) {
var res model.Paster
arg := &model.ArgPaster{
Platform: int8(1),
AdType: int8(1),
Aid: "666666",
TypeId: "11",
Buvid: "666666",
}
if err := client.Call(_pasterAPP, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("pasterAPPRpc", t, res)
}
}
func indexIconRPC(client *rpc.Client, t *testing.T) {
var res map[string][]*model.IndexIcon
arg := &struct{}{}
if err := client.Call(_indexIcon, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("indexIconRpc", t, res)
}
}
func playerIconRPC(client *rpc.Client, t *testing.T) {
var res *model.PlayerIcon
arg := &struct{}{}
if err := client.Call(_playerIcon, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("playerIconRPC", t, res)
}
}
func cmtboxRPC(client *rpc.Client, t *testing.T) {
var res model.Cmtbox
arg := &model.ArgCmtbox{
ID: 1,
}
if err := client.Call(_cmtbox, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("resource", t, res)
}
}
func sideBarsRPC(client *rpc.Client, t *testing.T) {
var res []*model.SideBars
arg := &struct{}{}
if err := client.Call(_sidebars, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("sideBars", t, res)
}
}
func abTestRPC(client *rpc.Client, t *testing.T) {
var res map[string]*model.AbTest
arg := &model.ArgAbTest{
Groups: "不显示热门tab,显示热门tab",
IP: "127.0.0.1",
}
if err := client.Call(_abtest, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("abTest", t, res)
}
}
func pasterCIDRPC(client *rpc.Client, t *testing.T) {
var res map[int64]int64
arg := &struct{}{}
if err := client.Call(_pasterCID, arg, &res); err != nil {
t.Errorf("err: %v.", err)
} else {
result("pasterCID", t, res)
}
}
func result(name string, t *testing.T, res interface{}) {
fmt.Printf("res : %+v \n", res)
t.Log("[==========" + name + "单元测试结果==========]")
t.Log(res)
t.Log("[↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑]\r\n")
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/resource/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/resource/api/v1:go_default_library",
"//app/service/main/resource/service: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,19 @@
// Package server generate by warden_gen
package server
import (
pb "go-common/app/service/main/resource/api/v1"
"go-common/app/service/main/resource/service"
"go-common/library/net/rpc/warden"
)
// New Coin warden rpc server
func New(c *warden.ServerConfig, svr *service.Service) *warden.Server {
ws := warden.NewServer(c)
pb.RegisterResourceServer(ws.Server(), svr)
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}

View File

@@ -0,0 +1,84 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"ads_test.go",
"banner_test.go",
"relate_test.go",
"resource_test.go",
"service_test.go",
"special_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/resource/api/v1:go_default_library",
"//app/service/main/resource/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"abtest.go",
"ads.go",
"archive.go",
"banner.go",
"relate.go",
"resource.go",
"service.go",
"show.go",
"special.go",
],
importpath = "go-common/app/service/main/resource/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/rpc/client:go_default_library",
"//app/service/main/resource/api/v1:go_default_library",
"//app/service/main/resource/conf:go_default_library",
"//app/service/main/resource/dao/abtest:go_default_library",
"//app/service/main/resource/dao/ads:go_default_library",
"//app/service/main/resource/dao/alarm:go_default_library",
"//app/service/main/resource/dao/cpm:go_default_library",
"//app/service/main/resource/dao/manager:go_default_library",
"//app/service/main/resource/dao/resource:go_default_library",
"//app/service/main/resource/dao/show:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/dgryski/go-farm: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 @@
package service
import (
"context"
"strings"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
// AbTest get abtest by group name
func (s *Service) AbTest(c context.Context, names, ipaddr string) (res map[string]*model.AbTest) {
var (
now = time.Now().Unix()
mis []string
)
res = make(map[string]*model.AbTest)
ns := strings.Split(names, ",")
s.abTestLock.Lock()
for _, n := range ns {
if ab, ok := s.abTestCache[n]; ok && (now-ab.UTime <= 300) {
r := &model.AbTest{}
*r = *ab
res[n] = r
} else {
mis = append(mis, n)
}
}
s.abTestLock.Unlock()
if len(mis) > 0 {
nabs, err := s.abtest.AbTest(c, strings.Join(mis, ","), ipaddr)
if err != nil {
log.Error("AbTest(%v, %v) error(%v)", mis, ipaddr, err)
return
}
for _, nab := range nabs {
// add in res
r := &model.AbTest{}
*r = *nab
res[r.Name] = r
}
s.abTestLock.Lock()
s.UpdateAbTestCache(nabs)
s.abTestLock.Unlock()
}
return
}
// UpdateAbTestCache update abtest
func (s *Service) UpdateAbTestCache(nabs []*model.AbTest) {
var now = time.Now().Unix()
for _, nab := range nabs {
nab.UTime = now
s.abTestCache[nab.Name] = nab
}
}

View File

@@ -0,0 +1,250 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"go-common/app/service/main/archive/api"
arcmdl "go-common/app/service/main/archive/model/archive"
"go-common/app/service/main/resource/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// loadVideoAds load Video_ads to cache.
func (s *Service) loadVideoAds() (err error) {
var (
ok bool
vdoAds []*model.VideoAD
vdoAdsAPP = make(map[int8]map[int8]map[int8]map[string]*model.VideoAD)
tmpAIDm []map[int64]int64
tmpAIDs = make(map[int64]int64)
)
if vdoAds, err = s.ads.VideoAds(context.TODO()); err != nil {
log.Error("s.ads.VideoAds error(%v)", err)
return
}
for _, ad := range vdoAds {
var (
tmpAPP map[int8]map[int8]map[string]*model.VideoAD
tmpAPP2 map[int8]map[string]*model.VideoAD
tmpAPP3 map[string]*model.VideoAD
)
if tmpAPP, ok = vdoAdsAPP[ad.Platform]; !ok {
tmpAPP = make(map[int8]map[int8]map[string]*model.VideoAD)
vdoAdsAPP[ad.Platform] = tmpAPP
}
if tmpAPP2, ok = tmpAPP[ad.Type]; !ok {
tmpAPP2 = make(map[int8]map[string]*model.VideoAD)
tmpAPP[ad.Type] = tmpAPP2
}
if tmpAPP3, ok = tmpAPP2[ad.Target]; !ok {
tmpAPP3 = make(map[string]*model.VideoAD)
tmpAPP2[ad.Target] = tmpAPP3
}
switch ad.Target {
case model.VdoAdsTargetArchive:
if ad.Aids == "" {
continue
}
xids := strings.Split(ad.Aids, ",")
for _, xid := range xids {
tmpAPP3[xid] = ad
if ad.FrontAid > 0 {
tmpAIDs[ad.FrontAid] = ad.FrontAid
}
}
case model.VdoAdsTargetBangumi:
if ad.SeasonID <= 0 {
continue
}
sid := strconv.Itoa(ad.SeasonID)
tmpAPP3[sid] = ad
if ad.Platform == model.VdoAdsPC {
if ad.AdCid > 0 {
tmpAIDs[ad.AdCid] = ad.AdCid
}
} else {
if ad.FrontAid > 0 {
tmpAIDs[ad.FrontAid] = ad.FrontAid
}
}
case model.VdoAdsTargetType:
if ad.TypeID <= 0 {
continue
}
tid := strconv.Itoa(int(ad.TypeID))
tmpAPP3[tid] = ad
if ad.FrontAid > 0 {
tmpAIDs[ad.FrontAid] = ad.FrontAid
}
}
if len(tmpAIDs) == 50 {
tmpAIDm = append(tmpAIDm, tmpAIDs)
tmpAIDs = make(map[int64]int64)
}
}
if len(tmpAIDs) > 0 {
tmpAIDm = append(tmpAIDm, tmpAIDs)
}
s.videoAdsAPPCache = vdoAdsAPP
s.PasterAIDCache = tmpAIDm
return
}
// PasterAPP get paster for app nologin
func (s *Service) PasterAPP(c context.Context, plat, adType int8, aid, typeID, buvid string) (res *model.Paster, err error) {
var (
vdoApp map[int8]map[int8]map[string]*model.VideoAD
vdoApp2 map[int8]map[string]*model.VideoAD
vdoApp3 map[string]*model.VideoAD
vdoApp4 *model.VideoAD
ok bool
)
platform := model.PasterPlat(int8(plat))
res = new(model.Paster)
if vdoApp, ok = s.videoAdsAPPCache[platform]; !ok {
return
}
if vdoApp2, ok = vdoApp[adType]; !ok {
return
}
var (
pages []*api.Page
faid, playCount, confPlayCount int64
)
// aid first.
if vdoApp3, ok = vdoApp2[model.VdoAdsTargetArchive]; ok && vdoApp3[aid] != nil {
faid = vdoApp3[aid].FrontAid
confPlayCount = vdoApp3[aid].PlayCount
}
if faid <= 0 {
if vdoApp3, ok = vdoApp2[model.VdoAdsTargetType]; !ok {
return
}
if vdoApp4, ok = vdoApp3[typeID]; !ok && len(s.typeList) > 0 {
pid := s.typeList[typeID]
if pid != "" && pid != "0" {
vdoApp4 = vdoApp3[pid]
}
}
if vdoApp4 == nil {
return
}
if vdoApp4.FrontAid <= 0 {
return
}
faid = vdoApp4.FrontAid
confPlayCount = vdoApp4.PlayCount
}
// check buvid count.
if playCount, err = s.ads.BuvidCount(c, faid, buvid); err != nil || playCount == confPlayCount {
// skip ad when redis error or playCount reached
return
}
if pages, err = s.arcRPC.Page3(c, &arcmdl.ArgAid2{Aid: faid}); err != nil || len(pages) == 0 {
// skip ad when av error
log.Error("s.arcRPC.Page3(%d) error(%v)", faid, err)
return
}
res.AID = faid
res.CID = pages[0].Cid
res.Duration = pages[0].Duration
res.Type = adType
res.AllowJump = vdoApp4.Skipable
// update buvid count.
bcCache := map[string]map[int64]int64{
buvid: map[int64]int64{
faid: playCount + 1,
},
}
s.addCache(bcCache)
return
}
// PasterPGC get paster for pgc
func (s *Service) PasterPGC(c context.Context, plat, adType int8, sid string) (res *model.Paster, err error) {
var (
vdoApp map[int8]map[int8]map[string]*model.VideoAD
vdoApp2 map[int8]map[string]*model.VideoAD
vdoApp3 map[string]*model.VideoAD
ok bool
)
platform := model.PasterPlat(int8(plat))
res = new(model.Paster)
if vdoApp, ok = s.videoAdsAPPCache[platform]; !ok {
return
}
if vdoApp2, ok = vdoApp[adType]; !ok {
return
}
var (
pages []*api.Page
faid int64
)
// aid first.
if vdoApp3, ok = vdoApp2[model.VdoAdsTargetBangumi]; !ok || vdoApp3[sid] == nil {
return
}
if platform == model.VdoAdsPC {
faid = vdoApp3[sid].AdCid
} else {
faid = vdoApp3[sid].FrontAid
}
if pages, err = s.arcRPC.Page3(c, &arcmdl.ArgAid2{Aid: faid}); err != nil || len(pages) == 0 {
// skip ad when av error
log.Error("PasterPGC s.arcRPC.Page3(%d) error(%v)", faid, err)
return
}
res.AID = faid
res.CID = pages[0].Cid
res.Duration = pages[0].Duration
res.Type = adType
res.AllowJump = vdoApp3[sid].Skipable
if platform == model.VdoAdsPC {
url := vdoApp3[sid].AdURL
if url != "" {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = fmt.Sprintf("http://%v", url)
}
}
res.URL = url
}
return
}
// PasterCID get all Paster's cid.
func (s *Service) PasterCID(c context.Context) (res map[int64]int64, err error) {
var mutex = sync.Mutex{}
res = make(map[int64]int64)
g, ctx := errgroup.WithContext(c)
for _, aidm := range s.PasterAIDCache {
var aids []int64
for aid, _ := range aidm {
aids = append(aids, aid)
}
if len(aids) > 0 {
g.Go(func() (err error) {
arcs, err := s.arcRPC.Archives3(ctx, &arcmdl.ArgAids2{Aids: aids})
if err != nil {
log.Error("%v", err)
err = nil
return
}
for _, arc := range arcs {
mutex.Lock()
res[arc.FirstCid] = arc.Aid
mutex.Unlock()
}
return
})
}
}
if err = g.Wait(); err != nil {
log.Error("%+v", err)
}
return
}

View File

@@ -0,0 +1,36 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_LoadVideoAds(t *testing.T) {
Convey("load video ads", t, WithService(func(s *Service) {
err := s.loadVideoAds()
So(err, ShouldBeNil)
}))
}
func Test_PasterAPP(t *testing.T) {
Convey("get nologin paster", t, WithService(func(s *Service) {
_, err := s.PasterAPP(context.Background(), 0, 1, "15038932", "11", "22222")
So(err, ShouldBeNil)
}))
}
func Test_PasterPGC(t *testing.T) {
Convey("get bangumi paster", t, WithService(func(s *Service) {
_, err := s.PasterPGC(context.Background(), 2, 0, "43883")
So(err, ShouldBeNil)
}))
}
func Test_PasterCID(t *testing.T) {
Convey("get paster cids", t, WithService(func(s *Service) {
_, err := s.PasterCID(context.Background())
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,117 @@
package service
import (
"context"
"encoding/json"
"fmt"
"strconv"
"go-common/app/service/main/resource/model"
"go-common/library/database/sql"
"go-common/library/log"
)
func (s *Service) arcChan(action string, nwMsg []byte, oldMsg []byte) {
var err error
nw := &model.Archive{}
if err = json.Unmarshal(nwMsg, nw); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", nwMsg, err)
return
}
switch action {
case _updateAct:
old := &model.Archive{}
if err = json.Unmarshal(oldMsg, old); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", oldMsg, err)
return
}
if old.State != nw.State {
if nw.State == model.StateOrange || nw.State == model.StateForbidSubmit {
// only send msg
s.sendWechart(nw.State, nw.ID, "warn")
} else if nw.State == model.StateForbidRecycle || nw.State == model.StateForbidLock || nw.State == model.StateForbidUpDelete {
// send msg and off line
if err = s.offLine(nw.ID); err == nil {
s.sendWechart(nw.State, nw.ID, "offLine")
}
}
}
}
}
func (s *Service) sendWechart(ns int8, aid int64, titleType string) {
var sends = make(map[string][]*model.ResWarnInfo)
if ars, ok := s.resArchiveWarnCache[aid]; ok {
for _, ar := range ars {
sends[ar.UserName] = append(sends[ar.UserName], ar)
}
}
for useName, send := range sends {
log.Info("sendWechart(%v, %v, %d, %v) start send QYWX msg", aid, useName, ns, titleType)
s.alarmDao.SendWeChart(context.TODO(), ns, useName, send, titleType)
}
}
func (s *Service) offLine(aid int64) (err error) {
// begin tran
var tx *sql.Tx
if tx, err = s.res.BeginTran(context.TODO()); err != nil {
log.Error("offLine aid(%v) s.res.BeginTran() error(%v)", aid, err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("offLine aid(%v) off line recover error(%v)", aid, r)
}
}()
if ars, ok := s.resArchiveWarnCache[aid]; ok {
var (
applyGroupIDm = make(map[int]int)
applyGroupIDs []string
)
// update resource assignment etime by id
for _, ar := range ars {
log.Info("offLine aid(%v) ar(%+v) start off line resource", aid, ar)
if _, err = s.res.TxOffLine(tx, ar.AssignmentID); err != nil {
tx.Rollback()
log.Error("offLine aid(%v) s.res.TxOffLine(%v) error(%v)", aid, ar.AssignmentID, err)
return
}
etime := ar.ETime.Time().Format("2006-01-02 15:04:05")
// log for manager
if _, err = s.res.TxInResourceLogger(tx, "material", fmt.Sprintf("批量下线 原计划投放结束时间: %v备注: 稿件不可看,自动下线", etime), ar.MaterialID); err != nil {
tx.Rollback()
log.Error("offLine aid(%v) s.res.TxInResourceLogger(%v, %v, %v) error(%v)", aid, "material", fmt.Sprintf("批量下线 原计划投放结束时间: %v备注: 稿件不可看,自动下线", etime), ar.MaterialID, err)
return
}
// log for rollback db
if _, err = s.res.TxInResourceLogger(tx, "rejob", etime, ar.AssignmentID); err != nil {
tx.Rollback()
log.Error("offLine aid(%v) s.res.TxInResourceLogger(%v, %v, %v) error(%v)", aid, "rejob", etime, ar.AssignmentID, err)
return
}
applyGroupIDm[ar.ApplyGroupID] = ar.ApplyGroupID
}
for _, g := range applyGroupIDm {
applyGroupIDs = append(applyGroupIDs, strconv.Itoa(g))
// log for manager
if _, err = s.res.TxInResourceLogger(tx, "resource_apply", "投放被下线", g); err != nil {
tx.Rollback()
log.Error("offLine aid(%v) s.res.TxInResourceLogger(%v, %v, %v) error(%v)", aid, "resource_apply", "投放被下线", g, err)
return
}
}
// update resource apply audit status by group_id
log.Info("offLine aid(%v) apply_group_ids(%v) start free apply resource", aid, applyGroupIDs)
if _, err = s.res.TxFreeApply(tx, applyGroupIDs); err != nil {
tx.Rollback()
log.Error("offLine aid(%v) s.res.TxFreeApply(%v) error(%v)", aid, applyGroupIDs, err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("offLine aid(%v) tx.Commit() error(%v)", aid, err)
}
return
}

View File

@@ -0,0 +1,278 @@
package service
import (
"context"
"encoding/json"
"sort"
"strconv"
"strings"
"time"
locmdl "go-common/app/service/main/location/model"
"go-common/app/service/main/resource/model"
"go-common/library/log"
farm "github.com/dgryski/go-farm"
)
// loadBannerCahce load banner cache.
func (s *Service) loadBannerCahce() (err error) {
// get all banners
nbs, err := s.res.Banner(context.TODO())
if err != nil {
log.Error("s.res.Banner error(%v)", err)
return
}
s.bannerCache = nbs
log.Info("load bannerCache success")
var bannerHashTpm = make(map[int8]string, len(nbs))
for plat, bnnr := range nbs {
bannerHashTpm[plat] = hash(bnnr)
}
s.bannerHashCache = bannerHashTpm
log.Info("load BannerHashCache success")
cbs, err := s.res.Category(context.TODO())
if err != nil {
log.Error("s.res.Category error(%v)", err)
return
}
s.categoryBannerCache = cbs
log.Info("load categoryBannerCache success")
// banner limit
limit, err := s.res.Limit(context.TODO())
if err != nil {
log.Error("s.dao.Limit error(%v)", err)
return
}
s.bannerLimitCache = limit
log.Info("load BannerLimitCache success")
return
}
// hash get banner hash.
func hash(v map[int][]*model.Banner) (value string) {
bs, err := json.Marshal(v)
if err != nil {
log.Error("json.Marshal error(%v)", err)
return
}
value = strconv.FormatUint(farm.Hash64(bs), 10)
return
}
// Banners get banners by plat, build channel, ip for app-feed.
func (s *Service) Banners(c context.Context, plat int8, build int, aid, mid int64, resIdsStr, channel, ip, buvid, network, mobiApp, device, openEvent, adExtra, version string, isAd bool) (res *model.Banners) {
res = &model.Banners{}
if version != "" && (version == s.bannerHashCache[plat]) {
log.Warn("Banners() plat(%v) version(%v) same as hash cache, return nil", plat, version)
return
}
var (
cpmResBus map[int]map[int]*model.Banner
resIds []string
banner map[int][]*model.Banner
)
if isAd {
cpmResBus = s.cpmBanners(c, aid, mid, build, resIdsStr, mobiApp, device, buvid, network, ip, openEvent, adExtra)
}
resIds = strings.Split(resIdsStr, ",")
banner = map[int][]*model.Banner{}
for _, resIDStr := range resIds {
if resIDStr == "" {
continue
}
resID, err := strconv.Atoi(resIDStr)
if err != nil {
log.Warn("strconv.Atoi(%s) error(%v)", resIDStr, err)
err = nil
continue
}
var (
resBs, cbcs, resAll []*model.Banner
cbc = s.categoryBannerCache[plat] // operater category banner
bArea []string
ok bool
maxBannerIndex int
)
if len(cbc) > 0 {
if cbcs, ok = cbc[resID]; ok {
btime := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
for _, b := range cbcs {
if s.filterBs(c, plat, build, channel, b) {
continue
}
if b.Area != "" {
bArea = append(bArea, b.Area)
}
tmp := &model.Banner{}
*tmp = *b
tmp.ServerType = 0
tmp.RequestId = btime
if tmp.Rank > maxBannerIndex {
maxBannerIndex = tmp.Rank
}
resBs = append(resBs, tmp)
}
}
}
if len(resBs) > maxBannerIndex {
maxBannerIndex = len(resBs)
}
var (
cpmBus map[int]*model.Banner // cpm ad
allRank []int
tmpCmps []*model.Banner
)
// append cpm banner
if cpmBus, ok = cpmResBus[resID]; ok && len(cpmBus) > 0 {
var cpmMs = map[int]*model.Banner{}
for _, cpm := range cpmBus {
if cpm.IsAdReplace {
cpmMs[cpm.Rank] = cpm
allRank = append(allRank, cpm.Rank)
delete(cpmBus, cpm.Rank)
}
}
if len(allRank) > 0 {
sort.Ints(allRank)
for _, key := range allRank {
if cpmMs[key].Rank > maxBannerIndex {
maxBannerIndex = cpmMs[key].Rank
}
tmpCmps = append(tmpCmps, cpmMs[key])
}
}
}
if (len(resBs) + len(tmpCmps)) > maxBannerIndex {
maxBannerIndex = len(resBs) + len(tmpCmps)
}
var (
plm = s.bannerCache[plat] // operater normal banner
tmpBs, plbs []*model.Banner
)
// append normal banner
if len(plm) > 0 {
if plbs, ok = plm[resID]; ok {
btime := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
for _, b := range plbs {
if s.filterBs(c, plat, build, channel, b) {
continue
}
if b.Area != "" {
bArea = append(bArea, b.Area)
}
tmp := &model.Banner{}
*tmp = *b
tmp.ServerType = 0
tmp.RequestId = btime
if tmp.Rank > maxBannerIndex {
maxBannerIndex = tmp.Rank
}
tmpBs = append(tmpBs, tmp)
}
}
}
if (len(resBs) + len(tmpCmps) + len(tmpBs)) > maxBannerIndex {
maxBannerIndex = len(resBs) + len(tmpCmps) + len(tmpBs)
}
var tcIndex, tbIndex, cIndex int
for i := 1; i <= maxBannerIndex; i++ {
if tcIndex < len(tmpCmps) {
tc := tmpCmps[tcIndex]
if tc.Rank == i {
resAll = append(resAll, tc)
tcIndex++
continue
}
}
if tbIndex < len(tmpBs) {
tb := tmpBs[tbIndex]
if tb.Rank <= i {
resAll = append(resAll, tb)
tbIndex++
continue
}
}
if cIndex < len(resBs) {
cb := resBs[cIndex]
resAll = append(resAll, cb)
cIndex++
}
}
for i, b := range resAll {
if cpm, ok := cpmBus[i+1]; ok && !b.IsAdReplace { // NOTE: surplus cpm is ad loc
b.IsAdLoc = true
b.IsAd = cpm.IsAd
b.CmMark = cpm.CmMark
b.SrcId = cpm.SrcId
b.RequestId = cpm.RequestId
b.ClientIp = cpm.ClientIp
}
}
if max, ok := s.bannerLimitCache[resID]; ok && len(resAll) > max {
resAll = resAll[:max]
}
for i := 0; i < len(resAll); i++ {
resAll[i].Index = i + 1
resAll[i].ResourceID = resID
}
if len(resAll) > 0 {
var (
auths map[int64]*locmdl.Auth
resBs2 []*model.Banner
)
if len(bArea) > 0 {
if auths, err = s.locationRPC.AuthPIDs(c, &locmdl.ArgPids{Pids: strings.Join(bArea, ","), IP: ip}); err != nil {
log.Error("%v", err)
err = nil
}
}
for _, resB := range resAll {
if resB.Area != "" {
var pid int64
if pid, err = strconv.ParseInt(resB.Area, 10, 64); err != nil {
log.Warn("banner strconv.ParseInt(%v) error(%v)", resB.Area, err)
err = nil
} else {
if auth, ok := auths[pid]; ok && auth.Play == locmdl.Forbidden {
log.Warn("resID(%v) pid(%v) ip(%v) in zone limit", resID, resB.Area, ip)
continue
}
}
}
resBs2 = append(resBs2, resB)
}
banner[resID] = resBs2
}
}
res.Banner = banner
res.Version = s.bannerHashCache[plat]
return
}
// cpmBanners
func (s *Service) cpmBanners(c context.Context, aid, mid int64, build int, resource, mobiApp, device, buvid, network, ipaddr, openEvent, adExtra string) (banners map[int]map[int]*model.Banner) {
ipInfo, err := s.locationRPC.Info(c, &locmdl.ArgIP{IP: ipaddr})
if err != nil || ipInfo == nil {
log.Error("CpmsBanners s.locationRPC.Zone(%s) error(%v) or ipinfo is nil", ipaddr, err)
ipInfo = &locmdl.Info{Addr: ipaddr}
}
adr, err := s.cpm.CpmsAPP(c, aid, mid, build, resource, mobiApp, device, buvid, network, openEvent, adExtra, ipInfo)
if err != nil || adr == nil {
log.Error("s.ad.ADRequest error(%v)", err)
return
}
banners = adr.ConvertBanner(ipInfo.Addr, mobiApp, build)
return
}
// filterBs filter banner.
func (s *Service) filterBs(c context.Context, plat int8, build int, channel string, b *model.Banner) bool {
if model.InvalidBuild(build, b.Build, b.Condition) {
return true
}
if model.InvalidChannel(plat, channel, b.Channel) && b.Channel != "" {
return true
}
return false
}

View File

@@ -0,0 +1,29 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_LoadBannerCahce(t *testing.T) {
Convey("load banner cache", t, WithService(func(s *Service) {
err := s.loadBannerCahce()
So(err, ShouldBeNil)
}))
}
func Test_Banners(t *testing.T) {
Convey("get app banner", t, WithService(func(s *Service) {
res := s.Banners(context.Background(), 1, 6190, 0, 182504479, "457", "", "218.4.147.222", "222", "wifi", "iphone", "phone", "", "", "", true)
So(res, ShouldNotBeNil)
}))
}
func Test_CPMBanners(t *testing.T) {
Convey("get cpm by api", t, WithService(func(s *Service) {
res := s.cpmBanners(context.Background(), 0, 182504479, 6190, "457", "iphone", "phone", "222", "wifi", "218.4.147.222", "", "")
So(res, ShouldNotBeEmpty)
}))
}

View File

@@ -0,0 +1,36 @@
package service
import (
"context"
"time"
"go-common/app/service/main/resource/model"
"go-common/library/log"
"go-common/library/xstr"
)
//loadRelateCache load relate card cache
func (s *Service) loadRelateCache() {
relate, err := s.show.Relate(context.Background(), time.Now())
if err != nil {
log.Error("%+v", err)
return
}
pgcMapRelate := make(map[int64]int64)
relateCache := make(map[int64]*model.Relate)
for _, r := range relate {
var pgcIDs []int64
if pgcIDs, err = xstr.SplitInts(r.PgcIDs); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", r.PgcIDs, err)
return
}
if len(pgcIDs) > 0 {
for _, pgcID := range pgcIDs {
pgcMapRelate[pgcID] = r.ID
}
}
relateCache[r.ID] = r
}
s.relatePgcMapCache = pgcMapRelate
s.relateCache = relateCache
}

View File

@@ -0,0 +1,20 @@
package service
import (
"encoding/json"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Relate(t *testing.T) {
Convey("get app relate", t, WithService(func(s *Service) {
tmp := s.relateCache
byte, _ := json.Marshal(tmp)
fmt.Println(string(byte))
tmp2 := s.relatePgcMapCache
byte2, _ := json.Marshal(tmp2)
fmt.Println(string(byte2))
}))
}

View File

@@ -0,0 +1,264 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"go-common/app/service/main/resource/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_archiveURL = "https://www.bilibili.com/video/av"
_archiveURL2 = "http://www.bilibili.com/video/av"
)
// LoadRes load Res info to cache
func (s *Service) loadRes() (err error) {
// load default banner.
var posTmp map[int][]int
resTmp, err := s.res.Resources(context.TODO())
if err != nil {
log.Error("s.res.Resources error(%v)", err)
return
}
s.resCache = resTmp
resCacheMap := make(map[int]*model.Resource)
posTmp = make(map[int][]int)
for _, res := range resTmp {
resCacheMap[res.ID] = res
if res.Counter == 0 && res.Parent != 0 {
posTmp[res.Parent] = append(posTmp[res.Parent], res.ID)
}
}
s.posCache = posTmp
s.resCacheMap = resCacheMap
// load default banner.
asgTmp, err := s.res.Assignment(context.TODO())
if err != nil {
log.Error("s.res.Assignment error(%v)", err)
return
}
asgNewTmp, err := s.res.AssignmentNew(context.TODO())
if err != nil {
log.Error("s.res.AssignmentNew error(%v)", err)
return
}
asgNewTmp = append(asgNewTmp, asgTmp...)
categoryTmp, err := s.res.CategoryAssignment(context.TODO())
if err != nil {
log.Error("s.res.CategoryAssignment error(%v)", err)
return
}
asgNewTmp = append(asgNewTmp, categoryTmp...)
s.asgCache = asgNewTmp
resArchiveWarn, resURLWarn := s.formWarnInfo(asgNewTmp)
s.resArchiveWarnCache = resArchiveWarn
s.resURLWarnCache = resURLWarn
asgCacheMap := make(map[int][]*model.Assignment)
for _, asg := range asgNewTmp {
asgCacheMap[asg.ResID] = append(asgCacheMap[asg.ResID], asg)
}
s.asgCacheMap = asgCacheMap
// load default banner.
bannerTmp, err := s.res.DefaultBanner(context.TODO())
if err != nil {
log.Error("s.res.DefaultBanner error(%v)", err)
return
}
s.defBannerCache = bannerTmp
// index icon
tmpIndexIcon, err := s.res.IndexIcon(context.TODO())
if err != nil {
log.Error("s.res.IndexIcon() error(%v)", err)
return
}
s.indexIcon = tmpIndexIcon
return
}
func (s *Service) formWarnInfo(asgNewTmp []*model.Assignment) (resArchive map[int64][]*model.ResWarnInfo, resURL map[string][]*model.ResWarnInfo) {
resArchive = make(map[int64][]*model.ResWarnInfo)
resURL = make(map[string][]*model.ResWarnInfo)
for _, asg := range asgNewTmp {
var (
aid int64
url string
err error
rw *model.ResWarnInfo
)
if (asg.Atype == model.AsgTypeVideo) || (asg.Atype == model.AsgTypeAv) {
if aid, err = strconv.ParseInt(asg.URL, 10, 64); err != nil {
log.Error("formWarnInfo url(%v) error(%v)", asg.URL, err)
err = nil
continue
}
} else if (asg.Atype == model.AsgTypePic) || (asg.Atype == model.AsgTypeURL) {
if strings.HasPrefix(asg.URL, _archiveURL) {
urls := strings.Split(asg.URL, "?")
aidURL := strings.TrimPrefix(urls[0], _archiveURL)
aidURL = strings.TrimSuffix(aidURL, "/")
if aid, err = strconv.ParseInt(aidURL, 10, 64); err != nil {
log.Error("formWarnInfo url(%v) error(%v)", asg.URL, aidURL, err)
err = nil
continue
}
} else if strings.HasPrefix(asg.URL, _archiveURL2) {
urls := strings.Split(asg.URL, "?")
aidURL := strings.TrimPrefix(urls[0], _archiveURL2)
aidURL = strings.TrimSuffix(aidURL, "/")
if aid, err = strconv.ParseInt(aidURL, 10, 64); err != nil {
log.Error("formWarnInfo url(%v) error(%v)", asg.URL, err)
err = nil
continue
}
} else {
url = asg.URL
}
}
if aid == 0 && url == "" {
continue
}
rw = &model.ResWarnInfo{
AssignmentID: asg.AsgID,
AssignmentName: asg.Name,
STime: asg.STime,
ETime: asg.ETime,
UserName: asg.Username,
ApplyGroupID: asg.ApplyGroupID,
MaterialID: asg.ID,
}
if re, ok := s.resCacheMap[asg.ResID]; ok {
if re.Counter > 0 {
rw.ResourceID = re.ID
if rep, ok := s.resCacheMap[re.Parent]; ok {
rw.ResourceName = fmt.Sprintf("%v_%v", rep.Name, re.Name)
continue
}
rw.ResourceName = re.Name
} else {
rw.ResourceID = re.Parent
rw.ResourceName = re.Name
}
}
if aid != 0 {
rw.AID = aid
resArchive[aid] = append(resArchive[aid], rw)
} else {
rw.URL = url
resURL[url] = append(resURL[url], rw)
}
}
return
}
// ResourceAll get all resource
func (s *Service) ResourceAll(c context.Context) (res []*model.Resource) {
res = s.resCache
return
}
// AssignmentAll get all assignment
func (s *Service) AssignmentAll(c context.Context) (ass []*model.Assignment) {
// TODO delete
for _, asc := range s.asgCache {
as := &model.Assignment{}
*as = *asc
as.Weight = 0
ass = append(ass, as)
}
return
}
// Resource get resource by resource_id or positon_id
func (s *Service) Resource(c context.Context, resID int) (res *model.Resource) {
var (
ok bool
pos []int
)
if res, ok = s.resCacheMap[resID]; !ok {
return
}
// Safe first!! Prevent res nil panic.
if res.Counter == 0 {
if len(s.asgCacheMap[resID]) > 0 {
res.Assignments = s.asgCacheMap[resID]
return
}
res.Assignments = s.asgCacheMap[res.Parent]
} else {
if pos, ok = s.posCache[resID]; !ok {
return
}
var (
tmpNormalRes []*model.Assignment
tmpCategoryRes = s.asgCacheMap[resID]
)
for _, pid := range pos {
tmpNormalRes = append(tmpNormalRes, s.asgCacheMap[pid]...)
}
for _, nr := range tmpNormalRes {
if nr.Weight > len(tmpCategoryRes) {
tmpCategoryRes = append(tmpCategoryRes, nr)
} else {
tmpCategoryRes = append(tmpCategoryRes[:nr.Weight-1], append([]*model.Assignment{nr}, tmpCategoryRes[nr.Weight-1:]...)...)
}
}
if len(tmpCategoryRes) > res.Counter {
res.Assignments = tmpCategoryRes[:res.Counter]
} else {
res.Assignments = tmpCategoryRes
}
}
return
}
// Resources get resources by resource_ids or position_ids
func (s *Service) Resources(c context.Context, resIDs []int) (res map[int]*model.Resource) {
if len(resIDs) == 0 {
res = _emptyResources
return
}
res = make(map[int]*model.Resource)
for _, rid := range resIDs {
if resTmp := s.Resource(c, rid); resTmp != nil {
res[rid] = resTmp
}
}
return
}
// DefBanner get defbanner config
func (s *Service) DefBanner(c context.Context) (defbanner *model.Assignment) {
defbanner = s.defBannerCache
return
}
// IndexIcon get index icon
func (s *Service) IndexIcon(c context.Context) (icons map[string][]*model.IndexIcon) {
icons = map[string][]*model.IndexIcon{
model.IconTypes[model.IconTypeFix]: s.indexIcon[model.IconTypeFix],
model.IconTypes[model.IconTypeRandom]: s.indexIcon[model.IconTypeRandom],
}
return
}
// PlayerIcon get player icon
func (s *Service) PlayerIcon(c context.Context) (re *model.PlayerIcon, err error) {
if re = s.playIcon; re == nil {
err = ecode.NothingFound
}
return
}
// Cmtbox get live danmaku box
func (s *Service) Cmtbox(c context.Context, id int64) (re *model.Cmtbox, err error) {
var ok bool
if re, ok = s.cmtbox[id]; !ok {
err = ecode.NothingFound
}
return
}

View File

@@ -0,0 +1,57 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_LoadRes(t *testing.T) {
Convey("load resource", t, WithService(func(s *Service) {
err := s.loadRes()
So(err, ShouldBeNil)
}))
}
func Test_ResourceAll(t *testing.T) {
Convey("get all resources ", t, WithService(func(s *Service) {
res := s.ResourceAll(context.Background())
So(res, ShouldNotBeEmpty)
}))
}
func Test_AssignmentAll(t *testing.T) {
Convey("get all assignment", t, WithService(func(s *Service) {
res := s.AssignmentAll(context.Background())
So(res, ShouldNotBeEmpty)
}))
}
func Test_Resource(t *testing.T) {
Convey("get resource by id", t, WithService(func(s *Service) {
res := s.Resource(context.Background(), 2329)
So(res, ShouldNotBeEmpty)
}))
}
func Test_Resources(t *testing.T) {
Convey("get resource by ids", t, WithService(func(s *Service) {
res := s.Resources(context.Background(), []int{467, 2329})
So(res, ShouldNotBeEmpty)
}))
}
func Test_DefBanner(t *testing.T) {
Convey("get default banner", t, WithService(func(s *Service) {
res := s.DefBanner(context.Background())
So(res, ShouldNotBeNil)
}))
}
func Test_IndexIcon(t *testing.T) {
Convey("get index icon", t, WithService(func(s *Service) {
res := s.IndexIcon(context.Background())
So(res, ShouldNotBeEmpty)
}))
}

View File

@@ -0,0 +1,325 @@
package service
import (
"context"
"encoding/json"
"strconv"
"sync"
"time"
arcrpc "go-common/app/service/main/archive/api/gorpc"
arcmdl "go-common/app/service/main/archive/model/archive"
locrpc "go-common/app/service/main/location/rpc/client"
pb "go-common/app/service/main/resource/api/v1"
"go-common/app/service/main/resource/conf"
"go-common/app/service/main/resource/dao/abtest"
"go-common/app/service/main/resource/dao/ads"
"go-common/app/service/main/resource/dao/alarm"
"go-common/app/service/main/resource/dao/cpm"
"go-common/app/service/main/resource/dao/manager"
"go-common/app/service/main/resource/dao/resource"
"go-common/app/service/main/resource/dao/show"
"go-common/app/service/main/resource/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
const (
_updateAct = "update"
_archiveTable = "archive"
)
var (
_emptyResources = make(map[int]*model.Resource)
)
// Service define resource service
type Service struct {
c *conf.Config
cpm *cpm.Dao
abtest *abtest.Dao
res *resource.Dao
ads *ads.Dao
alarmDao *alarm.Dao
show *show.Dao
manager *manager.Dao
// location rpc
locationRPC *locrpc.Service
// web cache
resCache []*model.Resource // => resource
asgCache []*model.Assignment // => assignments
resCacheMap map[int]*model.Resource // resID => resource
asgCacheMap map[int][]*model.Assignment // resID => [ => assignments]
defBannerCache *model.Assignment
videoAdsAPPCache map[int8]map[int8]map[int8]map[string]*model.VideoAD // plat => [ => adsType] => [ => adsTarget] => aid(seasonId or typeId)
missch chan interface{}
typeList map[string]string
resArchiveWarnCache map[int64][]*model.ResWarnInfo
resURLWarnCache map[string][]*model.ResWarnInfo
posCache map[int][]int
// app cache
bannerCache map[int8]map[int][]*model.Banner
categoryBannerCache map[int8]map[int][]*model.Banner
bannerHashCache map[int8]string
bannerLimitCache map[int]int
indexIcon map[int][]*model.IndexIcon
playIcon *model.PlayerIcon
cardCache map[int8]*model.Head
sideBarCache []*model.SideBar
sideBarLimitCache map[int64][]*model.SideBarLimit
// live
cmtbox map[int64]*model.Cmtbox
// abtest
abTestCache map[string]*model.AbTest
// PasterAIDCache
PasterAIDCache []map[int64]int64
// rpc
arcRPC *arcrpc.Service2
// database
archiveSub *databus.Databus
closeSub bool
closeMonitorURL bool
// waiter
waiter sync.WaitGroup
// lock
abTestLock sync.Mutex
//pgc special cards
specialCache map[int64]*pb.SpecialReply
//pgc relate cards
relateCache map[int64]*model.Relate
//pgc id relate relate card id
relatePgcMapCache map[int64]int64
// audit
auditCache map[string][]int
}
// New return service object
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
cpm: cpm.New(c),
abtest: abtest.New(c),
res: resource.New(c),
ads: ads.New(c),
alarmDao: alarm.New(c),
show: show.New(c),
manager: manager.New(c),
locationRPC: locrpc.New(c.LocationRPC),
resCacheMap: make(map[int]*model.Resource),
asgCacheMap: make(map[int][]*model.Assignment),
videoAdsAPPCache: make(map[int8]map[int8]map[int8]map[string]*model.VideoAD),
missch: make(chan interface{}, 10240),
typeList: make(map[string]string),
resArchiveWarnCache: make(map[int64][]*model.ResWarnInfo),
resURLWarnCache: make(map[string][]*model.ResWarnInfo),
bannerHashCache: make(map[int8]string),
indexIcon: make(map[int][]*model.IndexIcon),
bannerCache: make(map[int8]map[int][]*model.Banner),
categoryBannerCache: make(map[int8]map[int][]*model.Banner),
posCache: make(map[int][]int),
cardCache: make(map[int8]*model.Head),
cmtbox: make(map[int64]*model.Cmtbox),
sideBarLimitCache: make(map[int64][]*model.SideBarLimit),
abTestCache: make(map[string]*model.AbTest),
arcRPC: arcrpc.New2(c.ArchiveRPC),
archiveSub: databus.New(c.ArchiveSub),
specialCache: make(map[int64]*pb.SpecialReply),
relateCache: make(map[int64]*model.Relate),
relatePgcMapCache: make(map[int64]int64),
auditCache: make(map[string][]int),
}
if err := s.loadRes(); err != nil {
panic(err)
}
if err := s.loadVideoAds(); err != nil {
panic(err)
}
if err := s.loadBannerCahce(); err != nil {
panic(err)
}
s.loadTypeList()
s.loadPlayIcon()
s.loadCmtbox()
s.loadSpecialCache()
s.loadRelateCache()
s.loadAudit()
go s.loadproc()
go s.loadCmtboxproc()
go s.loadCardCache()
go s.loadSideBarCache()
go s.cacheproc()
if s.c.MonitorArchive {
s.waiter.Add(1)
go s.arcConsume()
}
if s.c.MonitorURL {
go s.checkResURL()
}
return
}
// loadproc is a routine load ads to cache
func (s *Service) loadproc() {
for {
time.Sleep(time.Duration(conf.Conf.Reload.Ad))
s.loadRes()
s.loadVideoAds()
s.loadBannerCahce()
s.loadTypeList()
s.loadPlayIcon()
s.loadCardCache()
s.loadSideBarCache()
s.loadRelateCache()
s.loadSpecialCache()
s.loadAudit()
}
}
// loadCmtboxproc is a routine load cmtbox to cache
func (s *Service) loadCmtboxproc() {
for {
time.Sleep(time.Second * 10)
s.loadCmtbox()
}
}
func (s *Service) loadTypeList() (err error) {
var (
tmpTypeList map[int16]*arcmdl.ArcType
tmpTypeList2 = make(map[string]string)
)
if tmpTypeList, err = s.arcRPC.Types2(context.TODO()); err != nil || len(tmpTypeList) == 0 {
log.Error("s.arcRPC.Types2() error(%v) or typelist len is zero", err)
return
}
for tid, typeInfo := range tmpTypeList {
tidStr := strconv.Itoa(int(tid))
pidStr := strconv.Itoa(int(typeInfo.Pid))
tmpTypeList2[tidStr] = pidStr
}
s.typeList = tmpTypeList2
return
}
func (s *Service) loadPlayIcon() {
var (
pi *model.PlayerIcon
err error
)
if pi, err = s.res.PlayerIcon(context.TODO()); err != nil {
log.Error("s.res.PlayerIcon() error(%v)", err)
return
}
s.playIcon = pi
}
func (s *Service) loadCmtbox() {
var (
cmtbox map[int64]*model.Cmtbox
err error
)
if cmtbox, err = s.res.Cmtbox(context.TODO()); err != nil {
log.Error("s.res.Cmtbox() error(%v)", err)
return
}
s.cmtbox = cmtbox
}
func (s *Service) loadAudit() {
var (
at map[string][]int
err error
)
if at, err = s.show.Audit(context.TODO()); err != nil {
log.Error("s.show.Audit error(%v)", err)
return
}
s.auditCache = at
}
func (s *Service) checkResURL() {
for {
time.Sleep(time.Duration(conf.Conf.Reload.Ad))
if s.closeMonitorURL {
return
}
for url, resURL := range s.resURLWarnCache {
s.alarmDao.CheckURL(url, resURL)
time.Sleep(time.Duration(conf.Conf.SpLimit))
}
}
}
// arcConsume consumer archive
func (s *Service) arcConsume() {
defer s.waiter.Done()
var (
msgs = s.archiveSub.Messages()
err error
)
for {
msg, ok := <-msgs
if !ok {
log.Error("s.archiveSub.Message closed", err)
return
}
if s.closeSub {
return
}
msg.Commit()
m := &model.Message{}
if err = json.Unmarshal(msg.Value, m); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", msg.Value, err)
continue
}
if m.Table == _archiveTable {
s.arcChan(m.Action, m.New, m.Old)
}
}
}
// Ping ping service
func (s *Service) Ping(c context.Context) (err error) {
return s.res.Ping(c)
}
// Close close service
func (s *Service) Close() {
if s.c.MonitorArchive {
s.closeSub = true
time.Sleep(2 * time.Second)
s.archiveSub.Close()
s.waiter.Wait()
}
s.res.Close()
}
// Monitor for monitorURL
func (s *Service) Monitor(c context.Context) {
s.closeMonitorURL = true
}
func (s *Service) addCache(d interface{}) {
// asynchronous add rules to redis
select {
case s.missch <- d:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc is a routine for add rules into redis.
func (s *Service) cacheproc() {
for {
d := <-s.missch
switch d.(type) {
case map[string]map[int64]int64:
v := d.(map[string]map[int64]int64)
if err := s.ads.AddBuvidCount(context.TODO(), v); err != nil {
log.Error("s.ads.AddBuvidCount(%v) error(%+v)", v, err)
}
default:
log.Warn("cacheproc can't process the type")
}
}
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"flag"
"path/filepath"
"time"
"go-common/app/service/main/resource/conf"
"go-common/library/cache/redis"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func CleanCache() {
c := context.Background()
pool := redis.NewPool(conf.Conf.Redis.Ads.Config)
pool.Get(c).Do("FLUSHDB")
}
func init() {
dir, _ := filepath.Abs("../cmd/resource-service-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
Reset(func() { CleanCache() })
f(s)
}
}

View File

@@ -0,0 +1,184 @@
package service
import (
"context"
"strconv"
"time"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/app/service/main/resource/model"
"go-common/library/log"
)
// loadCardCache load all card cache
func (s *Service) loadCardCache() {
now := time.Now()
hdm, err := s.show.PosRecs(context.TODO(), now)
if err != nil {
log.Error("s.show.PosRecs error(%v)", err)
return
}
itm, aids, err := s.show.RecContents(context.TODO(), now)
if err != nil {
log.Error("s.show.RecContents error(%v)", err)
return
}
tmpItem := map[int]map[int64]*model.ShowItem{}
for recid, aid := range aids {
tmpItem[recid] = s.fromCardAids(context.TODO(), aid)
}
tmp := s.mergeCard(context.TODO(), hdm, itm, tmpItem, now)
s.cardCache = tmp
}
func (s *Service) loadSideBarCache() {
now := time.Now()
sidebar, limits, err := s.show.SideBar(context.TODO(), now)
if err != nil {
log.Error("s.show.SideBar error(%v)", err)
return
}
s.sideBarCache = sidebar
s.sideBarLimitCache = limits
}
// SideBars get side bars
func (s *Service) SideBars(c context.Context) (res *model.SideBars) {
res = &model.SideBars{
SideBar: s.sideBarCache,
Limit: s.sideBarLimitCache,
}
return res
}
// RegionCard get voice card.
func (s *Service) RegionCard(c context.Context, plat int8, build int) (res *model.Head, err error) {
res = &model.Head{}
sw := s.cardCache[plat]
if sw == nil {
return
}
if model.InvalidBuild(build, sw.Build, sw.Condition) {
return
}
*res = *sw
res.FillBuildURI(plat, build)
return
}
// fromCardAids get Aids.
func (s *Service) fromCardAids(c context.Context, aids []int64) (data map[int64]*model.ShowItem) {
var (
arc *api.Arc
ok bool
)
as, err := s.arcRPC.Archives3(c, &archive.ArgAids2{Aids: aids})
if err != nil {
log.Error("s.arcRPC.Archives3 error(%v)", err)
return
}
if len(as) == 0 {
log.Warn("s.arcRPC.Archives3(%v) length is 0", aids)
return
}
data = map[int64]*model.ShowItem{}
for _, aid := range aids {
if arc, ok = as[aid]; ok {
if !arc.IsNormal() {
continue
}
i := &model.ShowItem{}
i.FromArchivePB(arc)
data[aid] = i
}
}
return
}
// mergeCard merge Card
func (s *Service) mergeCard(c context.Context, hdm map[int8][]*model.Card, itm map[int][]*model.Content, tmpItems map[int]map[int64]*model.ShowItem, now time.Time) (res map[int8]*model.Head) {
res = map[int8]*model.Head{}
for plat, hds := range hdm {
for _, hd := range hds {
var (
sis []*model.ShowItem
)
its, ok := itm[hd.ID]
if !ok {
its = []*model.Content{}
}
tmpItem, ok := tmpItems[hd.ID]
if !ok {
tmpItem = map[int64]*model.ShowItem{}
}
switch hd.Type {
case 1:
for _, ci := range its {
si := s.fillCardItem(ci, tmpItem)
if si.Title != "" {
sis = append(sis, si)
}
}
default:
continue
}
if len(sis) == 0 {
continue
}
sw := &model.Head{
CardID: hd.ID,
Title: hd.Title,
Type: hd.TypeStr,
Build: hd.Build,
Condition: hd.Condition,
Plat: hd.Plat,
}
if hd.Cover != "" {
sw.Cover = hd.Cover
}
switch sw.Type {
case model.GotoDaily:
sw.Date = now.Unix()
sw.Param = hd.Rvalue
sw.URI = hd.URI
sw.Goto = hd.Goto
}
sw.Body = sis
res[plat] = sw
}
}
return
}
// fillCardItem fill card
func (s *Service) fillCardItem(csi *model.Content, tsi map[int64]*model.ShowItem) (si *model.ShowItem) {
si = &model.ShowItem{}
switch csi.Type {
case model.CardGotoAv:
si.Goto = model.GotoAv
si.Param = csi.Value
}
si.URI = model.FillURI(si.Goto, si.Param)
if si.Goto == model.GotoAv {
aid, err := strconv.ParseInt(si.Param, 10, 64)
if err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", si.Param, err)
} else {
if it, ok := tsi[aid]; ok {
si = it
if csi.Title != "" {
si.Title = csi.Title
}
} else {
si = &model.ShowItem{}
}
}
}
return
}
// Audit all audit config.
func (s *Service) Audit(c context.Context) map[string][]int {
return s.auditCache
}

Some files were not shown because too many files have changed in this diff Show More