Create & Init Project...

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

View File

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

View File

@@ -0,0 +1,56 @@
# v1.0.13
稿件时长限定fix
bvc
# v1.0.12
proto修改
bvc
# v1.0.11
uploading video增加home_url等信息
# v1.0.10
1. 视频删除接口fix
2. 获取转码中的视频接口
3. extension
4. http timeout
# v1.0.9
1. 视频删除接口
2. home img init
3. fix bug
4. fix bug
# v1.0.8
pre环境不开启主站稿件订阅databus
订阅主站稿件过滤宽度大于等于高度的视频
# v1.0.7
订阅主站稿件过滤转载状态
# v1.0.6
订阅主站稿件databus
# v1.0.5
为video表添加limits字段用于对视频的限制当前只有弹幕
同时ListVideoInfo接口中返回limits
# v1.0.4
添加接口ListVideoInfo后续将陆续往这个接口上迁移避免直接访问db
# v1.0.3
1. 视频播放量增加接口
# v1.0.2
发号器
# v1.0.1
1. userbase和user_statistics_hive表的插入或更新改为只更新
2. user_type默认为1
# v1.0.0
1. 视频es搜索一期
# v1.1.0
1.添加bvc转码回调服务
# v1.1.1
1.视频上传

View File

@@ -0,0 +1,8 @@
# Owner
yangyucheng
luxiaowei
jiangdongqi
# Author
# Reviewer
daiwei

View File

@@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- jiangdongqi
- luxiaowei
- yangyucheng
labels:
- bbq
- service
- service/bbq/video
options:
no_parent_owners: true
reviewers:
- daiwei

View File

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

View File

@@ -0,0 +1,66 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = [
"@com_google_protobuf//:empty_proto",
"@gogo_special_proto//github.com/gogo/protobuf/gogoproto",
],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/bbq/video/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
go_library(
name = "go_default_library",
srcs = ["video.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/bbq/video/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_gogo_protobuf//sortkeys:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
syntax = "proto3";
package bbq.service.video.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
message ImportVideoInfo{
int64 avid = 1 [(gogoproto.jsontag) = "avid",(gogoproto.moretags) = "form:\"avid\"",(gogoproto.customname)= "AVID"];
int64 cid = 2 [(gogoproto.jsontag) = "cid",(gogoproto.moretags) = "form:\"avid\"",(gogoproto.customname)= "CID"];
int64 mid = 3 [(gogoproto.jsontag) = "mid",(gogoproto.moretags) = "form:\"mid\"",(gogoproto.customname)= "MID"];
string title = 4 [(gogoproto.jsontag) = "title",(gogoproto.moretags) = "form:\"title\""];
string content = 5 [(gogoproto.jsontag) = "content",(gogoproto.moretags) = "form:\"content\""];
int64 original = 6 [(gogoproto.jsontag) = "original",(gogoproto.moretags) = "form:\"original\""];
int64 duration = 7 [(gogoproto.jsontag) = "duration",(gogoproto.moretags) = "form:\"duration\""];
int64 state = 8 [(gogoproto.jsontag) = "state",(gogoproto.moretags) = "form:\"state\""];
string tag = 9 [(gogoproto.jsontag) = "tag",(gogoproto.moretags) = "form:\"tag\""];
string pubtime = 10 [(gogoproto.jsontag) = "pubtime",(gogoproto.moretags) = "form:\"pubtime\""];
int64 tid = 11 [(gogoproto.jsontag) = "tid",(gogoproto.moretags) = "form:\"tid\"",(gogoproto.customname)= "TID"];
int64 sub_tid = 12 [(gogoproto.jsontag) = "sub_tid",(gogoproto.moretags) = "form:\"sub_tid\"",(gogoproto.customname)= "SubTID"];
int64 is_full_screen = 13 [(gogoproto.jsontag) = "is_full_screen",(gogoproto.moretags) = "form:\"is_full_screen\""];
string cover_url = 14 [(gogoproto.jsontag) = "cover_url",(gogoproto.moretags) = "form:\"cover_url\""];
int64 cover_width = 15 [(gogoproto.jsontag) = "cover_width",(gogoproto.moretags) = "form:\"cover_width\""];
int64 cover_height = 16 [(gogoproto.jsontag) = "cover_height",(gogoproto.moretags) = "form:\"cover_height\""];
int64 from = 17 [(gogoproto.jsontag) = "from",(gogoproto.moretags) = "form:\"from\""];
int64 svid = 18 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = "form:\"svid\""];
string home_img_url = 19 [(gogoproto.jsontag) = "home_img_url",(gogoproto.moretags) = "form:\"home_img_url\""];
int64 home_img_width = 20 [(gogoproto.jsontag) = "home_img_width",(gogoproto.moretags) = "form:\"home_img_width\""];
int64 home_img_height = 21 [(gogoproto.jsontag) = "home_img_height",(gogoproto.moretags) = "form:\"home_img_height\""];
}
message VideoBase{
int64 avid = 1 [(gogoproto.jsontag) = "avid",(gogoproto.moretags) = "form:\"avid\""];
int64 cid = 2 [(gogoproto.jsontag) = "cid",(gogoproto.moretags) = "form:\"avid\""];
int64 mid = 3 [(gogoproto.jsontag) = "mid",(gogoproto.moretags) = "form:\"mid\""];
string title = 4 [(gogoproto.jsontag) = "title",(gogoproto.moretags) = "form:\"title\""];
string content = 5 [(gogoproto.jsontag) = "content",(gogoproto.moretags) = "form:\"content\""];
int64 original = 6 [(gogoproto.jsontag) = "original",(gogoproto.moretags) = "form:\"original\""];
int64 duration = 7 [(gogoproto.jsontag) = "duration",(gogoproto.moretags) = "form:\"duration\""];
int64 state = 8 [(gogoproto.jsontag) = "state",(gogoproto.moretags) = "form:\"state\""];
string tag = 9 [(gogoproto.jsontag) = "tag",(gogoproto.moretags) = "form:\"tag\""];
int64 pubtime = 10 [(gogoproto.jsontag) = "pubtime", (gogoproto.moretags) = 'form:"tag"', (gogoproto.casttype) = "go-common/library/time.Time"];
int64 tid = 11 [(gogoproto.jsontag) = "tid",(gogoproto.moretags) = "form:\"tid\""];
int64 sub_tid = 12 [(gogoproto.jsontag) = "sub_tid",(gogoproto.moretags) = "form:\"sub_tid\""];
int64 is_full_screen = 13 [(gogoproto.jsontag) = "is_full_screen",(gogoproto.moretags) = "form:\"is_full_screen\""];
string cover_url = 14 [(gogoproto.jsontag) = "cover_url",(gogoproto.moretags) = "form:\"cover_url\""];
int64 cover_width = 15 [(gogoproto.jsontag) = "cover_width",(gogoproto.moretags) = "form:\"cover_width\""];
int64 cover_height = 16 [(gogoproto.jsontag) = "cover_height",(gogoproto.moretags) = "form:\"cover_height\""];
int64 from = 17 [(gogoproto.jsontag) = "from",(gogoproto.moretags) = "form:\"from\""];
int64 svid = 18 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = "form:\"svid\""];
uint64 limits = 19 [(gogoproto.jsontag) = "limits"];
}
message SyncVideoTagRequest{
repeated TagInfo tag_infos = 1 [(gogoproto.jsontag) = "tag_infos",(gogoproto.moretags) = "form:\"tag_infos\""];
}
message TagInfo{
int32 tag_type = 1 [(gogoproto.jsontag) = "tag_type",(gogoproto.moretags) = "form:\"tag_type\""];
string tag_name = 2 [(gogoproto.jsontag) = "tag_name",(gogoproto.moretags) = "form:\"tag_name\""];
}
message SvStatisticsInfoReq{
repeated int64 svid_list = 1 [(gogoproto.jsontag) = "svid_list",(gogoproto.moretags) = "form:\"svid_list\""];
}
message SvStatisticsInfoRes{
map<int64,SvStInfo> svst_info_map =1 [(gogoproto.jsontag) = "svst_info_map",(gogoproto.moretags) = "form:\"svst_info_map\""];
}
message SvStInfo{
int64 svid = 1 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = "form:\"svid\""];
int64 play =2 [(gogoproto.jsontag) = "play",(gogoproto.moretags) = "form:\"play\""];
int64 subtitles = 3 [(gogoproto.jsontag) = "subtitles",(gogoproto.moretags) = "form:\"subtitles\""];
int64 like = 4 [(gogoproto.jsontag) = "like",(gogoproto.moretags) = "form:\"like\""];
int64 share = 5 [(gogoproto.jsontag) = "share",(gogoproto.moretags) = "form:\"share\""];
int64 report = 6 [(gogoproto.jsontag) = "report",(gogoproto.moretags) = "form:\"report\""];
int64 reply = 7 [(gogoproto.jsontag) = "reply",(gogoproto.moretags) = "form:\"reply\""];
}
message SyncMidRequset{
int64 mid = 1 [(gogoproto.jsontag) = "mid",(gogoproto.moretags) = "form:\"mid\"",(gogoproto.customname)= "MID"];
}
message SyncUserBaseResponse{
int64 affc = 1 [(gogoproto.jsontag) = "affc",(gogoproto.moretags) = "form:\"affc\""];
}
message SyncMidsRequset{
repeated int64 mids = 1 [(gogoproto.jsontag) = "mids",(gogoproto.moretags) = "form:\"mids\"",(gogoproto.customname)= "MIDS"];
}
message BVideoTransRequset{
int64 svid = 1 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = "form:\"svid\" validate:\"min=0\"",(gogoproto.customname)= "SVID"];
int64 cid = 2 [(gogoproto.jsontag) = "cid",(gogoproto.moretags) = "form:\"cid\" validate:\"min=0\"",(gogoproto.customname)= "CID"];
}
message BVCTransBackRequset{
string flow_id = 1 [(gogoproto.jsontag) = "flow_id",(gogoproto.moretags) = "form:\"flow_id\" validate:\"min=0\"",(gogoproto.customname)= "FlowID"];
int64 flow_type = 2 [(gogoproto.jsontag) = "flow_type",(gogoproto.moretags) = "form:\"flow_type\" validate:\"min=0\"",(gogoproto.customname)= "FlowType",(gogoproto.casttype)="int8"];
int64 svid = 3 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = "form:\"svid\" validate:\"min=0\"",(gogoproto.customname)= "SVID"];
repeated BVCTransInfo trans_res= 4 [(gogoproto.jsontag) = "trans_res",(gogoproto.moretags) = "form:\"trans_res\""];
SvPic pic = 5 [(gogoproto.jsontag) = "pic",(gogoproto.moretags) = "form:\"pic\" validate:\"required\"",(gogoproto.customname)= "PIC"];
}
message SvPic{
string pic_url = 1 [(gogoproto.jsontag) = "pic_url",(gogoproto.moretags) = "form:\"pic_url\" validate:\"required\"",(gogoproto.customname)= "PicURL"];
int64 pic_width = 2 [(gogoproto.jsontag) = "pic_width",(gogoproto.moretags) = "form:\"pic_width\" validate:\"required\""];
int64 pic_height = 3 [(gogoproto.jsontag) = "pic_height",(gogoproto.moretags) = "form:\"pic_height\" validate:\"required\""];
}
message BVCTransInfo{
string path = 2 [(gogoproto.jsontag) = "path",(gogoproto.moretags) = "form:\"path\" validate:\"required\""];
string ppi = 3 [(gogoproto.jsontag) = "ppi",(gogoproto.moretags) = "form:\"ppi\" validate:\"required\"",(gogoproto.customname)= "PPI"];
string bps = 4 [(gogoproto.jsontag) = "bps",(gogoproto.moretags) = "form:\"bps\" validate:\"required\"",(gogoproto.customname)= "BPS"];
string video_code = 5 [(gogoproto.jsontag) = "video_code",(gogoproto.moretags) = "form:\"video_code\" validate:\"required\""];
int64 filesize = 6 [(gogoproto.jsontag) = "filesize",(gogoproto.moretags) = "form:\"filesize\" validate:\"required\""];
int64 duration = 8 [(gogoproto.jsontag) = "duration",(gogoproto.moretags) = "form:\"duration\" validate:\"required\""];
}
message CreateIDRequest {
int64 mid = 1 [(gogoproto.moretags) = 'form:"mid" validate:"required"'];
int64 time = 2 [(gogoproto.moretags) = 'form:"time"'];
}
message CreateIDResponse {
int64 new_id = 1;
}
message VideoInfo {
VideoBase video_base = 1[(gogoproto.jsontag) = 'vidoe_base'];
}
message ListVideoInfoRequest {
repeated int64 svIDs = 1 [(gogoproto.moretags) = 'form:"svids" validate:"required"'];
}
message ListVideoInfoResponse {
repeated VideoInfo list = 1[(gogoproto.jsontag) = 'list,omitempty'];
}
message ModifyLimitsRequest {
int64 svid = 1 [(gogoproto.moretags) = 'form:"svid" validate:"required"'];
uint64 limit_type = 2 [(gogoproto.moretags) = 'form:"limit_type" validate:"required"']; // 表示此次修改是针对哪种类型,如弹幕发布等
uint64 limit_op = 3 [(gogoproto.moretags) = 'form:"limit_op"']; // 操作0表示清零去除该类型的限制1表示开启限制
}
message ModifyLimitsResponse {
}
message PreUploadRequest{
string title = 1 [(gogoproto.jsontag) = 'title',(gogoproto.moretags) = 'form:"title" validate:"required"'];
int64 mid = 2 [(gogoproto.jsontag) = 'mid',(gogoproto.moretags) = 'form:"mid" validate:"required"'];
string topic = 3 [(gogoproto.jsontag) = 'topic',(gogoproto.moretags) = 'form:"topic"'];
int64 from = 4 [(gogoproto.jsontag) = 'from',(gogoproto.moretags) = 'form:"from" validate:"required"'];
string file_ext = 5 [(gogoproto.jsontag) = 'file_ext',(gogoproto.moretags) = 'form:"file_ext" validate:"required"'];
string entension = 6 [(gogoproto.jsontag) = 'entension',(gogoproto.moretags) = 'form:"entension"'];
}
message PreUploadResponse{
int64 svid = 1 [(gogoproto.jsontag) = 'biz_id',(gogoproto.moretags) = 'form:"biz_id"'];
string upos_uri = 2 [(gogoproto.jsontag) = 'upos_uri',(gogoproto.moretags) = 'form:"upos_uri"'];
string end_point = 3 [(gogoproto.jsontag) = 'endpoint',(gogoproto.moretags) = 'form:"endpoint"'];
repeated string end_points = 4 [(gogoproto.jsontag) = 'endpoints',(gogoproto.moretags) = 'form:"endpoints"'];
string auth = 5 [(gogoproto.jsontag) = 'auth',(gogoproto.moretags) = 'form:"auth"'];
}
message CallBackRequest{
int64 svid = 1 [(gogoproto.jsontag) = 'svid',(gogoproto.moretags) = 'form:"svid" validate:"required"'];
int64 mid = 2 [(gogoproto.jsontag) = 'mid',(gogoproto.moretags) = 'form:"mid" validate:"required"'];
}
message VideoUnshelfRequest {
int64 svid = 1 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = 'form:"svid" validate:"required"'];
}
message VideoDeleteRequest {
int64 svid = 1 [(gogoproto.jsontag) = "svid",(gogoproto.moretags) = 'form:"svid"'];
int64 up_mid = 2 [(gogoproto.jsontag) = "up_mid",(gogoproto.moretags) = 'form:"up_mid"'];
}
message UploadingVideo {
int64 svid = 1;
int64 mid = 2;
string title = 3[(gogoproto.jsontag) = 'title'];
int64 upload_status = 4[(gogoproto.jsontag) = 'upload_status'];
int64 retry_time = 5;
string home_img_url = 6[(gogoproto.jsontag) = 'home_img_url'];
int64 home_img_height = 7[(gogoproto.jsontag) = 'home_img_height'];
int64 home_img_width = 8[(gogoproto.jsontag) = 'home_img_width'];
}
message PrepareVideoRequest {
int64 mid = 1;
}
message PrepareVideoResponse {
repeated UploadingVideo list = 1;
}
message HomeImgCreateRequest {
int64 svid = 1 [(gogoproto.jsontag) = 'svid',(gogoproto.moretags) = 'form:"svid" validate:"required"'];
int64 mid = 2 [(gogoproto.jsontag) = 'mid',(gogoproto.moretags) = 'form:"mid" validate:"required"'];
int64 width = 3 [(gogoproto.jsontag) = 'width',(gogoproto.moretags) = 'form:"width" validate:"required"'];
string url = 4 [(gogoproto.jsontag) = 'url',(gogoproto.moretags) = 'form:"url" validate:"required"'];
int64 height = 5 [(gogoproto.jsontag) = 'height',(gogoproto.moretags) = 'form:"height" validate:"required"'];
}
message PlayInfoRequest{
repeated int64 svid = 1 [(gogoproto.jsontag) = 'svid',(gogoproto.moretags) = 'form:"svid" validate:"required"'];
}
message PlayInfoResponse{
map<int64,PlayInfo> list = 1[(gogoproto.jsontag) = 'list'];
}
message PlayInfo{
int64 svid = 1[(gogoproto.jsontag) = ''];
int64 expire_time = 2[(gogoproto.jsontag) = 'expire_time'];
int64 quality = 3[(gogoproto.jsontag) = 'quality'];
string url = 4[(gogoproto.jsontag) = 'url'];
int64 current_time = 5[(gogoproto.jsontag) = 'current_time'];
repeated FileInfo file_info = 6[(gogoproto.jsontag) = 'file_info'];
repeated int64 support_quality = 7[(gogoproto.jsontag) = 'support_quality'];
}
message FileInfo{
string ahead = 1[(gogoproto.jsontag) = 'ahead'];
int64 filesize = 2[(gogoproto.jsontag) = 'filesize'];
int64 timelength = 3[(gogoproto.jsontag) = 'timelength'];
string vhead = 4[(gogoproto.jsontag) = 'vhead'];
string path = 5[(gogoproto.jsontag) = 'path'];
string url = 6[(gogoproto.jsontag) = 'url'];
string url_bc = 7[(gogoproto.jsontag) = 'url_bc'];
}
service Video{
rpc ImportVideo(ImportVideoInfo) returns(.google.protobuf.Empty);
rpc SyncTag(SyncVideoTagRequest) returns(.google.protobuf.Empty);
rpc SvStatisticsInfo(SvStatisticsInfoReq)returns(SvStatisticsInfoRes);
rpc SyncUserBase(SyncMidRequset) returns(SyncUserBaseResponse);
rpc SyncUserSta(SyncMidRequset) returns(SyncUserBaseResponse);
rpc SyncUserBases(SyncMidsRequset) returns(SyncUserBaseResponse);
rpc SyncUserStas(SyncMidsRequset) returns(SyncUserBaseResponse);
rpc CreateID(CreateIDRequest) returns (CreateIDResponse);
rpc BVCTransCommit(BVideoTransRequset) returns(.google.protobuf.Empty);
rpc ListVideoInfo(ListVideoInfoRequest) returns (ListVideoInfoResponse);
rpc ModifyLimits (ModifyLimitsRequest) returns (ModifyLimitsResponse); // 修改视频的限制,比如弹幕发布权限等
rpc PreUpload(PreUploadRequest) returns (PreUploadResponse);
rpc CallBack(CallBackRequest) returns (.google.protobuf.Empty);
rpc VideoUnshelf(VideoUnshelfRequest) returns (.google.protobuf.Empty);
rpc VideoDelete(VideoDeleteRequest) returns (.google.protobuf.Empty);
rpc ListPrepareVideo(PrepareVideoRequest) returns (PrepareVideoResponse);
rpc HomeImgCreate(HomeImgCreateRequest) returns (.google.protobuf.Empty);
rpc PlayInfo(PlayInfoRequest) returns(PlayInfoResponse);
}

View File

@@ -0,0 +1,15 @@
package v1
// 表示video表中的limit字段每一位代表的含义
// limit中0表示通过1表示禁止
const (
VideoLimitBitAll uint64 = iota
VideoLimitBitBullet // 表示弹幕不显示,发布失败
VideoLimitBitMax
)
// IsLimitSet 根据输入的limits值返回相应limitType是否被设置
// example: 例如需要判断该视频是否可以发布弹幕的时候,如果(sql_limit_value & (1<<VideoLimitBitBullet)) > 0 则该视频被禁止发布弹幕
func IsLimitSet(limits uint64, limitType uint64) bool {
return limits&(1<<limitType) > 0
}

View File

@@ -0,0 +1,31 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"play.go",
],
importpath = "go-common/app/service/bbq/video/api/http/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,12 @@
package v1
// ViewsAddRequest .
type ViewsAddRequest struct {
Svid int64 `json:"svid" form:"svid" validate:"required"`
Views int `json:"views" form:"views"`
}
// ViewsAddResponse .
type ViewsAddResponse struct {
Affected int64 `json:"affected"`
}

View File

@@ -0,0 +1,28 @@
package v1
// VideoPlay playinfo
type VideoPlay struct {
SVID int64 `json:"svid"`
ExpireTime int64 `json:"expire_time"` //过期时间
FileInfo []*FileInfo `json:"file_info"` //分片信息
Quality int64 `json:"quality"` //清晰度
SupportQuality []int64 `json:"support_quality"` //支持清晰度
URL string `json:"url"` //基础url
CurrentTime int64 `json:"current_time"` //当前时间戳
}
// FileInfo bvc fileinfo
type FileInfo struct {
Ahead string `json:"ahead"`
FileSize int64 `json:"filesize"`
TimeLength int64 `json:"timelength"`
Vhead string `json:"vhead"`
Path string `json:"path"`
URL string `json:"url"`
URLBc string `json:"url_bc"`
}
//VideoPlayRequest ..
type VideoPlayRequest struct {
SIVD []int64 `json:"svid" form:"svid" validate:"required"`
}

View File

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

View File

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

View File

@@ -0,0 +1,18 @@
[archive]
state = 0
notAccess = 10000
tid = [11, 13, 23, 165, 177, 4, 5]
subTid = [130, 54, 71, 174, 153, 169, 170]
title = ["搬运", "抖音", "快手", "秒拍", "美拍", "微视", "西瓜视频", "火山视频", "火山小视频", "纳豆视频", "电流小视频"]
content = ["搬运", "抖音", "快手", "秒拍", "美拍", "微视", "西瓜视频", "火山视频", "火山小视频", "纳豆视频", "电流小视频", "转侵删", "来自网络", "韩国车展", "韩国车模", "付邮送", "退坑出", "出簪", "抽福袋", "评论抽"]
[up]
uname = ["搬运", "抖音", "快手"]
mid = [330061605, 38331436, 348608259, 39735082]
[dimension]
minX = 720
minYX = 1.75
maxYX = 1.80
maxDuration = 60
minDuration = 15

View File

@@ -0,0 +1,168 @@
[log]
# dir = "/tmp/log/bbq-service"
stdout=true
v = 5
[grpc]
timeout = "500ms"
addr = "0.0.0.0:9005"
[bm]
[bm.server]
addr = "0.0.0.0:8802"
timeout = "1s"
[bm.client]
key = "654af11b5df0c9d3"
secret = "a7512b8b243b82f4bdb72cf2824b3f8e"
dial = "500ms"
timeout = "30s"
keepAlive = "60s"
timer = 10
[bm.client.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[mysql]
#addr = "127.0.0.1:3306"
#dsn = "root:123456@tcp(127.0.0.1:3306)/bbq?allowNativePasswords=true&timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
#readDSN = ["root:123456@tcp(127.0.0.2:3306)/bbq?allowNativePasswords=true&timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
addr = "172.16.38.91:3306"
dsn = "root:123456@tcp(172.16.38.91:3306)/bbq?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["root:123456@tcp(172.16.38.91:3306)/bbq?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 50
idleTimeout ="4h"
queryTimeout = "1000ms"
execTimeout = "1000ms"
tranTimeout = "2000ms"
[cmsmysql]
addr = "172.16.38.91:3306"
dsn = "root:123456@tcp(172.16.38.91:3306)/bbq_cms?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["root:123456@tcp(172.16.38.91:3306)/bbq_cms?timeout=2000ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 50
idleTimeout ="4h"
queryTimeout = "1000ms"
execTimeout = "1000ms"
tranTimeout = "2000ms"
[redis]
name = "bbq-web"
proto = "tcp"
addr = "172.16.38.91:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[berserker]
[berserker.key]
[berserker.key.yyc]
appkey = "dcf555f4f314ccdfad7cb8a3288f1643"
secret = "4efd3443561e66832b3ba9128a1ad720"
[berserker.key.hsc]
appkey = "0bcf67ecf921576350a4f916c1edecbf"
secret = "1003e5a9babe66ef6834fe839ce8223f"
[berserker.key.lzq]
appkey = "e51d04f43e9c9bca8678dcb4586c76db"
secret = "7c53bf6d17c2d51253b927bc057abeae"
[berserker.api]
rankmonthly = "http://berserker.bilibili.co/avenger/api/92/query"
rankdaily = "http://berserker.bilibili.co/avenger/api/102/query"
userdmg = "http://berserker.bilibili.co/avenger/api/98/query"
operaonce = "http://berserker.bilibili.co/avenger/api/121/query"
[grpcClient]
[grpcClient.account]
addr = "discovery://default/account.service"
[grpcClient.account.wardenconf]
dial = "1s"
timeout = "2s"
[grpcClient.archive]
addr = "discovery://default/archive.service"
[grpcClient.archive.wardenconf]
dial = "100ms"
timeout = "500ms"
[grpcClient.bvcplay]
addr = "172.16.39.21:14500"
[grpcClient.bvcplay.wardenconf]
dial = "3000ms"
timeout = "5000ms"
[urls]
bvc_push="http://172.18.33.140:7703/api/v1/task/push/bbq"
[databus]
[databus.cms]
key = "36ff3e402f7c310a"
secret = "dbd11b140486dc0bc263cf7ec540186c"
group = "BBQCms-BbqBbq-P"
topic = "BBQCms-T"
action = "pub"
buffer = 1024
name = "history"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.cms.discovery]
domain = "uat-api.bilibili.co"
key = "c8c48e784e05acfb"
secret = "aa63ee0a10afa358d02a07e7abcec546"
region = "sh"
zone = "sh001"
env = "uat"
[databus.archive]
key = "36ff3e402f7c310a"
secret = "dbd11b140486dc0bc263cf7ec540186c"
group = "ArchiveNotify-BbqBbq-BbqBiliArchiveNotify-S"
topic = "ArchiveNotify-T"
action = "sub"
buffer = 1024
name = "history"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.archive.discovery]
domain = "api.bilibili.co"
key = "c8c48e784e05acfb"
secret = "aa63ee0a10afa358d02a07e7abcec546"
region = "sh"
zone = "sh001"
env = "uat"
[bpscode]
[bpscode.720p]
2m=130
1m=129
[bpscode.540p]
2m=128
1m=127
[upload]
[upload.file]
prefix= "0"
line = "ws"
[upload.endpoint]
main = "//upos-hz-uat.acgvideo.com"
backup = "//upos-hz-uat.acgvideo.com"
[upload.auth]
ak = "1494471752"
sk = "3c3989e9e0f4e64d9c817be4caf8a9c1"

View File

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

View File

@@ -0,0 +1,36 @@
package conf
// Rules 稿件导入规则
type Rules struct {
Archive *ArchiveRule
Up *UPRule
Dimension *PageRule
}
// ArchiveRule .
type ArchiveRule struct {
Titles []string
Contents []string
TID []int32
SubTID []int32
State int
NotAccess int
}
// UPRule .
type UPRule struct {
UName []string
MID []int64
}
// PageRule .
type PageRule struct {
MinX int64
MinY int64
MaxX int64
MaxY int64
MinYX float32
MaxYX float32
MaxDuration int64
MinDuration int64
}

View File

@@ -0,0 +1,158 @@
package conf
import (
"flag"
"go-common/library/cache/redis"
"go-common/library/conf/paladin"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"github.com/BurntSushi/toml"
)
var (
localConf string
confName string
// Conf config
Conf = &Config{}
// ArchiveRules 稿件导入规则
ArchiveRules = &Rules{}
)
// Config .
type Config struct {
Log *log.Config
BM *HTTPGeneral
Verify *verify.Config
Tracer *trace.Config
Redis *redis.Config
MySQL *sql.Config
CMSMySQL *sql.Config
Ecode *ecode.Config
Berserker *Berserker
GRPCClient map[string]*GRPCConf
URLs map[string]string
Databus map[string]*databus.Config
BPSCode map[string]map[string]int64
Upload *Upload
}
//Upload .
type Upload struct {
File *UploadFile
Endpoint *UploadEndPoint
Auth *UploadAuth
}
//UploadFile .
type UploadFile struct {
Prefix string
Line string
}
//UploadEndPoint .
type UploadEndPoint struct {
Main string
BackUp string
}
//UploadAuth .
type UploadAuth struct {
AK string
SK string
}
//GRPCConf .
type GRPCConf struct {
WardenConf *warden.ClientConfig
Addr string
}
//HTTPGeneral ...
type HTTPGeneral struct {
Server *bm.ServerConfig
Client *bm.ClientConfig
}
// Berserker conf
type Berserker struct {
Key *BerSerkerKeyList
API *BerserkerAPI
}
// BerserkerAPI conf
type BerserkerAPI struct {
Rankdaily string
Userdmg string
Operaonce string
}
// BerSerkerKeyList conf
type BerSerkerKeyList struct {
YYC *BerSerkerKey
HSC *BerSerkerKey
LZQ *BerSerkerKey
}
// BerSerkerKey conf
type BerSerkerKey struct {
Appkey string
Secret string
}
// Set .
func (c *Config) Set(text string) error {
if _, err := toml.Decode(text, c); err != nil {
panic(err)
}
return nil
}
// Set .
func (r *Rules) Set(text string) error {
if _, err := toml.Decode(text, r); err != nil {
panic(err)
}
return nil
}
func init() {
//线下使用
flag.StringVar(&localConf, "localconf", "", "default config path")
flag.StringVar(&confName, "conf_name", "video-service.toml", "default config filename")
}
// Init init conf
func Init() error {
if localConf != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(localConf, &Conf)
return
}
func remote() (err error) {
if err := paladin.Init(); err != nil {
panic(err)
}
// var setter
if err := paladin.Watch(confName, Conf); err != nil {
panic(err)
}
if err := paladin.Watch("rule.toml", ArchiveRules); err != nil {
panic(err)
}
return
}

View File

@@ -0,0 +1,64 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"archive_filter.go",
"bvc.go",
"check.go",
"comment.go",
"dao.cache.go",
"dao.go",
"databus.go",
"video.go",
"video_bvc.go",
"video_repository.go",
"video_upload_process.go",
],
importpath = "go-common/app/service/bbq/video/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/bbq/app-bbq/model:go_default_library",
"//app/service/bbq/common/db/bbq:go_default_library",
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/bbq/video/conf:go_default_library",
"//app/service/bbq/video/model:go_default_library",
"//app/service/bbq/video/model/grpc:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf/env:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,71 @@
package dao
import (
"context"
"errors"
"fmt"
"go-common/app/service/bbq/video/model"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/queue/databus"
"github.com/json-iterator/go"
)
const (
_queryCmsVideoRepository = "select id from `video_repository` where `cid` = ?;"
_insertCmsVideoRepository = "insert into `video_repository`(`avid`, `cid`, `mid`, `title`, `from`, `content`, `pubtime`, `duration`, `state`, `tid`, `sub_tid`, `svid`) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
)
// ArchiveSub .
func (d *Dao) ArchiveSub() (*model.Archive, error) {
if d.archiveSub == nil {
return nil, ecode.ArchiveDatabusNilErr
}
msg, ok := <-d.archiveSub.Messages()
if !ok {
return nil, errors.New("chan <- failed")
}
return d.archiveProcess(msg)
}
func (d *Dao) archiveProcess(msg *databus.Message) (a *model.Archive, err error) {
defer msg.Commit()
an := new(model.ArchiveNotify)
if err = jsoniter.Unmarshal(msg.Value, an); err != nil {
return
}
if an.Action == "update" && an.New.Videos <= an.Old.Videos {
return
}
if an.Table != "archive" || an.New == nil {
return
}
if d.archiveFilters.DoFilter(an.New) {
return
}
a = an.New
return
}
// ArchiveKickOff .
func (d *Dao) ArchiveKickOff(c context.Context, svid int64, a *model.Archive) (err error) {
row := d.cmsdb.QueryRow(c, _queryCmsVideoRepository, a.CID)
tmp := 0
if err = row.Scan(&tmp); err != nil && err != xsql.ErrNoRows {
return
}
if tmp != 0 {
err = fmt.Errorf("ArchiveKickOff cid existed [%d]", a.CID)
return
}
_, err = d.cmsdb.Exec(c, _insertCmsVideoRepository, a.AID, a.CID, a.MID, a.Title, 0, a.Content, a.PubTime, a.Duration, a.State, a.TID, a.SubTID, svid)
return
}

View File

@@ -0,0 +1,189 @@
package dao
import (
"context"
"fmt"
"strings"
"go-common/app/service/bbq/video/conf"
"go-common/app/service/bbq/video/model"
mainAccount "go-common/app/service/main/account/api"
mainArchive "go-common/app/service/main/archive/api"
"go-common/library/log"
)
// Filter .
type Filter interface {
doFilter(*model.Archive) bool
}
// ArchiveFilters .
type ArchiveFilters struct {
filter []Filter
}
// NewArchiveFilters .
func NewArchiveFilters(f ...Filter) *ArchiveFilters {
return &ArchiveFilters{
filter: f,
}
}
// DoFilter 过滤稿件
func (af *ArchiveFilters) DoFilter(a *model.Archive) (res bool) {
res = false
for _, v := range af.filter {
res = res || v.doFilter(a)
if res {
return
}
}
return
}
// ArchiveDetailFilter 稿件详情过滤
type ArchiveDetailFilter struct {
rule *conf.ArchiveRule
archiveType map[int32]*mainArchive.Tp
}
func (f *ArchiveDetailFilter) doFilter(a *model.Archive) bool {
c := context.Background()
// 过滤状态
if a.State != f.rule.State {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter state want[%d] actually[%d]", f.rule.State, a.State)))
return true
}
// 过滤转载
if a.Copyright != 1 {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter copyright want[1] actually[%d]", a.Copyright)))
return true
}
// 过滤access
if a.Access == f.rule.NotAccess {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter access not[%d] actually[%d]", f.rule.NotAccess, a.Access)))
return true
}
// 过滤TID
if subT, ok := f.archiveType[a.TypeID]; ok {
a.TID = subT.Pid
for _, t := range f.rule.TID {
if a.TID == t {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter TID not[%d] actually[%d]", t, a.TID)))
return true
}
}
}
// 过滤SubTID
a.SubTID = a.TypeID
for _, t := range f.rule.SubTID {
if a.TypeID == t {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter TID not[%d] actually[%d]", t, a.TypeID)))
return true
}
}
// 过滤Title
for _, v := range f.rule.Titles {
if strings.Contains(a.Title, v) {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter title[%s] contains[%s]", a.Title, v)))
return true
}
}
// 过滤Content
for _, v := range f.rule.Contents {
if strings.Contains(a.Content, v) {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter content[%s] contains[%s]", a.Content, v)))
return true
}
}
return false
}
// ArchiveUpFilter 稿件详情过滤
type ArchiveUpFilter struct {
rule *conf.UPRule
accountClient mainAccount.AccountClient
}
func (f *ArchiveUpFilter) doFilter(a *model.Archive) bool {
c := context.Background()
// 过滤UP主mid
for _, v := range f.rule.MID {
if a.MID == v {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter mid[%d] contains[%d]", a.MID, v)))
return true
}
}
response, err := f.accountClient.Card3(c, &mainAccount.MidReq{Mid: a.MID})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter err[%v]", err)))
return true
}
// 过滤UP主uname
for _, v := range f.rule.UName {
if strings.Contains(response.Card.Name, v) {
log.Infov(c, log.KV("log", fmt.Sprintf("ArchiveUpFilter doFilter uname[%s] contains[%s]", response.Card.Name, v)))
return true
}
}
return false
}
// ArchivePageFilter 稿件尺寸过滤
type ArchivePageFilter struct {
rule *conf.PageRule
archiveClient mainArchive.ArchiveClient
}
func (f *ArchivePageFilter) doFilter(a *model.Archive) bool {
c := context.Background()
response, err := f.archiveClient.View(c, &mainArchive.ViewRequest{
Aid: a.AID,
})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter err[%v]", err)))
return true
}
for _, page := range response.Pages {
// Rotate 不准,暂时不用
// if page.Dimension.Rotate != 1 {
// // 必须是竖屏
// continue
// }
if page.Dimension.Width >= page.Dimension.Height {
// 高度必须大于宽度
log.Infov(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter arc[%v] page[%v] filter width >= height", *(response.Arc), *page)))
continue
}
yx := float32(page.Dimension.Height) / float32(page.Dimension.Width)
if yx < f.rule.MinYX || yx > f.rule.MaxYX {
// 高宽比大于 1.75 小于 1.80
log.Infov(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter arc[%v] page[%v] filter want[%v, %v] actually[%v]", *(response.Arc), *page, f.rule.MinYX, f.rule.MaxYX, yx)))
continue
}
if page.Dimension.Width < f.rule.MinX {
// 不低于720p
log.Infov(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter arc[%v] page[%v] filter want[%v] actually[%v]", *(response.Arc), *page, f.rule.MinX, page.Dimension.Width)))
continue
}
if page.Duration <= f.rule.MinDuration || page.Duration > f.rule.MaxDuration {
// 过滤时长,大于15s 小于60s
log.Infov(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter arc[%v] page[%v] filter want(%v, %v) actually[%v]", *(response.Arc), *page, f.rule.MinDuration, f.rule.MaxDuration, page.Duration)))
continue
}
a.CID = page.Cid
}
log.Infov(c, log.KV("log", fmt.Sprintf("ArchivePageFilter doFilter arc[%v]", *(a))))
return a.CID == 0
}

View File

@@ -0,0 +1,23 @@
package dao
import (
"context"
"go-common/app/service/bbq/video/model"
"regexp"
)
const (
_insertRecord = "insert bvc_flow_record (`bvcid`,`svid`,`type`) values (?,?,?)"
_updateRecord = "update bvc_flow_record set `svid` = ?,`type` = ? where `bvcid` = ?"
)
// AddOrUpdateFlowRecord 添加bvc flow记录
func (d *Dao) AddOrUpdateFlowRecord(c context.Context, r *model.BVCRecord) error {
_, err := d.db.Exec(c, _insertRecord, r.FLowID, r.SVID, r.Type)
if err != nil {
if matched, _ := regexp.MatchString("Duplicate entry", err.Error()); matched {
_, err = d.db.Exec(c, _updateRecord, r.SVID, r.Type, r.FLowID)
}
}
return err
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"context"
"database/sql"
"fmt"
"go-common/library/log"
)
const (
_queryBvcResource = "select id from %s where svid = %d"
_queryCoverResource = "select cover_url,cover_width,cover_height from video_repository where svid = ?"
)
//CheckSVResource ...
func (d *Dao) CheckSVResource(c context.Context, svid int64) (err error) {
var (
ID int64
cURL string
cH int64
cW int64
)
tN := fmt.Sprintf("video_bvc_%02d", svid%100)
if err = d.db.QueryRow(c, fmt.Sprintf(_queryBvcResource, tN, svid)).Scan(&ID); err == sql.ErrNoRows {
log.Error("CheckSVResource bvc err,svid:%d,err:%v", svid, err)
return
}
//cover,err := d.cmsdb.QueryRow(c, query, ...)
if err = d.db.QueryRow(c, _queryCoverResource, svid).Scan(&cURL, &cW, &cH); err == sql.ErrNoRows {
log.Error("CheckSVResource cover err,svid:%d,err:%v", svid, err)
return
}
return
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"bytes"
"context"
"fmt"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/log"
"go-common/library/net/metadata"
"strings"
jsoniter "github.com/json-iterator/go"
)
const (
//DefaultCmType 默认评论类型
DefaultCmType = 23
)
// ReplyCounts 批量评论数
func (d *Dao) ReplyCounts(c context.Context, ids []int64, t int64) (res map[int64]*model.ReplyCount, err error) {
ip := metadata.String(c, metadata.RemoteIP)
oidStr := strings.Replace(strings.Trim(fmt.Sprint(ids), "[]"), " ", ",", -1)
req := map[string]interface{}{
"type": t,
"oid": oidStr,
}
res = make(map[int64]*model.ReplyCount)
var r []byte
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_counts"], "GET", req, ip)
if err != nil {
log.Infov(c,
log.KV("log", fmt.Sprintf("replyHTTPCommon err [%v]", err)),
)
return
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
decoder := json.NewDecoder(bytes.NewBuffer(r))
decoder.UseNumber()
err = decoder.Decode(&res)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("json unmarlshal err data[%s]", string(r))))
}
return
}

View File

@@ -0,0 +1,74 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package dao is a generated cache proxy package.
It is generated from:
type _cache interface {
// cache: -batch_err=break -nullcache=&v1.VideoBase{Svid:-1} -check_null_code=$==nil||$.Svid==-1
VideoBase(c context.Context, svid []int64) (map[int64]*v1.VideoBase, error)
}
*/
package dao
import (
"context"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/library/stat/prom"
)
var _ _cache
// VideoBase get data from cache if miss will call source method, then add to cache.
func (d *Dao) VideoBase(c context.Context, keys []int64) (res map[int64]*v1.VideoBase, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheVideoBase(c, keys); err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("VideoBase", int64(len(keys)-len(miss)))
for k, v := range res {
if v == nil || v.Svid == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
var missData map[int64]*v1.VideoBase
prom.CacheMiss.Add("VideoBase", int64(len(miss)))
missData, err = d.RawVideoBase(c, miss)
if res == nil {
res = make(map[int64]*v1.VideoBase, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &v1.VideoBase{Svid: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheVideoBase(c, missData)
})
return
}

View File

@@ -0,0 +1,189 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/conf"
"go-common/app/service/bbq/video/model/grpc"
account "go-common/app/service/main/account/api"
archive "go-common/app/service/main/archive/api"
"go-common/library/cache/redis"
"go-common/library/conf/env"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc/warden"
"go-common/library/queue/databus"
"go-common/library/sync/pipeline/fanout"
"net/url"
"reflect"
"strconv"
jsoniter "github.com/json-iterator/go"
)
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache: -batch_err=break -nullcache=&v1.VideoBase{Svid:-1} -check_null_code=$==nil||$.Svid==-1
VideoBase(c context.Context, svid []int64) (map[int64]*v1.VideoBase, error)
}
// Dao dao
type Dao struct {
c *conf.Config
redis *redis.Pool
cache *fanout.Fanout
db *xsql.DB
cmsdb *xsql.DB
httpClient *bm.Client
AccountClient account.AccountClient
cmsPub *databus.Databus
archiveSub *databus.Databus
archiveFilters *ArchiveFilters
ArchiveClient archive.ArchiveClient
bvcPlayClient grpc.PlayurlServiceClient
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
redis: redis.NewPool(c.Redis),
cache: fanout.New("cache"),
db: xsql.NewMySQL(c.MySQL),
cmsdb: xsql.NewMySQL(c.CMSMySQL),
httpClient: bm.NewClient(c.BM.Client),
cmsPub: databus.New(conf.Conf.Databus["cms"]),
archiveSub: newArchiveSub(c),
AccountClient: newAccountClient(c.GRPCClient["account"]),
ArchiveClient: newArchiveClient(c.GRPCClient["archive"]),
bvcPlayClient: newBVCPlayClient(c.GRPCClient["bvcplay"]),
}
dao.newArchiveFilters(conf.ArchiveRules)
return
}
// newBVCPlayClient .
func newBVCPlayClient(cfg *conf.GRPCConf) grpc.PlayurlServiceClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return grpc.NewPlayurlServiceClient(cc)
}
// newAccountClient .
func newAccountClient(cfg *conf.GRPCConf) account.AccountClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return account.NewAccountClient(cc)
}
// newArchiveClient .
func newArchiveClient(cfg *conf.GRPCConf) archive.ArchiveClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return archive.NewArchiveClient(cc)
}
// newArchiveFilters .
func (d *Dao) newArchiveFilters(c *conf.Rules) {
response, err := d.ArchiveClient.Types(context.Background(), &archive.NoArgRequest{})
if err != nil {
panic(err)
}
detailFilter := &ArchiveDetailFilter{
rule: c.Archive,
archiveType: response.Types,
}
upFilter := &ArchiveUpFilter{
rule: c.Up,
accountClient: d.AccountClient,
}
dimensionFilter := &ArchivePageFilter{
rule: c.Dimension,
archiveClient: d.ArchiveClient,
}
d.archiveFilters = NewArchiveFilters(detailFilter, upFilter, dimensionFilter)
}
func newArchiveSub(c *conf.Config) *databus.Databus {
if env.DeployEnv != env.DeployEnvProd {
return nil
}
if _, ok := c.Databus["archive"]; !ok {
return nil
}
return databus.New(c.Databus["archive"])
}
// Close close the resource.
func (d *Dao) Close() {
d.redis.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
// TODO: if you need use mc,redis, please add
return d.db.Ping(c)
}
// BeginTran begin mysql transaction
func (d *Dao) BeginTran(c context.Context) (*xsql.Tx, error) {
return d.db.Begin(c)
}
// ReplyHTTPCommon 评论公用请求
func replyHTTPCommon(c context.Context, httpClient *bm.Client, path string, method string, data map[string]interface{}, ip string) (r []byte, err error) {
params := url.Values{}
t := reflect.TypeOf(data).Kind()
if t == reflect.Map {
for k, v := range data {
// params.Set(k, v.(string))
switch reflect.TypeOf(v).Kind() {
case reflect.Int64:
params.Set(k, strconv.FormatInt(v.(int64), 10))
case reflect.Int16:
params.Set(k, strconv.FormatInt(int64(v.(int16)), 10))
case reflect.String:
params.Set(k, v.(string))
case reflect.Int:
params.Set(k, strconv.FormatInt(int64(v.(int)), 10))
}
}
}
log.V(5).Infov(c, log.KV("log", fmt.Sprintf("reply req url(%s)", path+"?"+params.Encode())))
req, err := httpClient.NewRequest(method, path, ip, params)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("reply url(%s) error(%v)", path+"?"+params.Encode(), err)))
return
}
var res struct {
Code int `json:"code"`
Msg string `json:"message"`
Data json.RawMessage `json:"data"`
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
if err = httpClient.Do(c, req, &res); err != nil {
str, _ := json.Marshal(res)
log.Errorv(c, log.KV("log", fmt.Sprintf("reply ret data(%s) err[%v]", str, err)))
return
}
str, _ := json.Marshal(res)
log.V(5).Infov(c, log.KV("log", fmt.Sprintf("reply ret data(%s)", str)))
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Warnv(c, log.KV("log", fmt.Sprintf("reply url(%s) error(%v)", path+"?"+params.Encode(), err)))
}
r = res.Data
return
}

View File

@@ -0,0 +1,19 @@
package dao
import (
"context"
"go-common/app/service/bbq/video/model"
"go-common/library/log"
)
const (
keyOnBoard = "OnboardVideo"
)
// CmsPub pub cms data into databus.
func (d *Dao) CmsPub(c context.Context, data *model.DataTopicCmsData) (err error) {
if err = d.cmsPub.Send(c, keyOnBoard, data); err != nil {
log.Error("d.databus.Send error(%v)", err)
}
return
}

View File

@@ -0,0 +1,736 @@
package dao
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"fmt"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/model"
acc "go-common/app/service/main/account/api"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/xstr"
xhttp "net/http"
"regexp"
"strconv"
"strings"
"time"
)
const (
_BVCSubTableSize = 100
_queryVideo = "SELECT svid FROM video WHERE svid = ?"
_addVideo = "INSERT INTO video(`cover_url`,`cover_width`,`cover_height`,`svid`,`title`,`mid`,`avid`,`cid`,`pubtime`,`from`,`tid`,`sub_tid`,`home_img_url`,`home_img_width`,`home_img_height`,`state`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
_queryTagByName = "SELECT `id` FROM tag WHERE name = ? and type = ?"
_insertTag = "INSERT INTO tag (`name`,`type`,`status`) VALUES %s "
_insOrUpUserBase = "INSERT IGNORE user_base (mid, uname, face, user_type) VALUES (?, ?, ?, ?) "
_insOrUpUserSta = "INSERT IGNORE user_statistics_hive (mid, uname) VALUES (?, ?)"
_queryStatisticsList = "select `svid`, `play`, `subtitles`, `like`, `share`, `report` from video_statistics where svid in (%s)"
_addBVCData = "insert into %s (`svid`,`path`,`resolution_retio`,`code_rate`,`video_code`,`duration`,`file_size`) values (?,?,?,?,?,?,?)"
_updateBVCData = "update %s set path=?, resolution_retio=?, video_code=?, duration=?, file_size=? where svid = ? and code_rate = ?"
_updateSvPIC = "update video_repository set cover_url=?,cover_width=?,cover_height=? ,sync_status = sync_status|? where svid = ?"
_addVideoViews = "update `video_statistics` set `play` = `play` + ? where `svid` = ?"
_existedStatistics = "select `id` from `video_statistics` where `svid` = ?;"
_insertStatistics = "insert into `video_statistics`(`svid`, `play`, `subtitles`, `like`, `share`, `report`) values(?,?,?,?,?,?);"
_queryVideoList = "select `avid`, `cid`, `svid`, `title`, `mid`, `content`, `pubtime`,`duration`,`tid`,`sub_tid`,`cover_url`,`cover_width`,`cover_height`,`limits`, `state` from video where svid in (%s)"
_updateVideoState = "update `video` set `state` = ? where `svid`= ?;"
)
const (
videoBaseCacheExpire = 600
videoBaseCacheKey = "video_base:%d"
)
func keyVideoBase(svid int64) string {
return fmt.Sprintf(videoBaseCacheKey, svid)
}
// ModifyLimits .
func (d *Dao) ModifyLimits(c context.Context, svid int64, limitType uint64, limitOp uint64) (num int64, err error) {
// 根据操作选择合适的limits update语句
limitOpCond := fmt.Sprintf("|%d", 1<<limitType)
if limitOp == 0 {
limitOpCond = fmt.Sprintf("&~%d", 1<<limitType)
}
querySQL := fmt.Sprintf("update video set limits = limits%s where svid = %d", limitOpCond, svid)
res, err := d.db.Exec(c, querySQL)
if err != nil {
log.Warnw(c, "log", "modify video limits fail", "sql", querySQL)
return
}
num, _ = res.RowsAffected()
log.V(1).Infow(c, "sql", querySQL, "affected_num", num)
d.DelCacheVideoBase(c, svid)
return
}
// RawVideoBase mysql获取video_base
func (d *Dao) RawVideoBase(c context.Context, svids []int64) (res map[int64]*v1.VideoBase, err error) {
res = make(map[int64]*v1.VideoBase)
if len(svids) == 0 {
return
}
querySQL := fmt.Sprintf(_queryVideoList, xstr.JoinInts(svids))
rows, err := d.db.Query(c, querySQL)
if err != nil {
log.Errorw(c, "log", "get video base from mysql fail", "sql", querySQL, "err", err)
return
}
defer rows.Close()
log.V(1).Infow(c, "log", "raw get video base from mysql", "sql", querySQL)
for rows.Next() {
sv := new(v1.VideoBase)
if err = rows.Scan(&sv.Avid, &sv.Cid, &sv.Svid, &sv.Title, &sv.Mid, &sv.Content, &sv.Pubtime, &sv.Duration, &sv.Tid, &sv.SubTid, &sv.CoverUrl, &sv.CoverWidth, &sv.CoverHeight, &sv.Limits, &sv.State); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
res[sv.Svid] = sv
}
if len(svids) > len(res) {
var rspID []int64
for k := range res {
rspID = append(rspID, k)
}
log.Warnw(c, "log", fmt.Sprintf("video req and rsp size not equal: req=%v, rsp=%v", svids, rspID))
}
log.V(1).Infow(c, "req_size", len(svids), "rsp_size", len(res))
return
}
// CacheVideoBase cache video base
func (d *Dao) CacheVideoBase(c context.Context, svids []int64) (res map[int64]*v1.VideoBase, err error) {
res = make(map[int64]*v1.VideoBase)
keys := make([]string, 0, len(svids))
keyMidMap := make(map[int64]bool, len(svids))
for _, svid := range svids {
key := keyVideoBase(svid)
if _, exist := keyMidMap[svid]; !exist {
// duplicate svid
keyMidMap[svid] = true
keys = append(keys, key)
}
}
conn := d.redis.Get(c)
defer conn.Close()
for _, key := range keys {
conn.Send("GET", key)
}
conn.Flush()
var data []byte
for i := 0; i < len(keys); i++ {
if data, err = redis.Bytes(conn.Receive()); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Errorv(c, log.KV("event", "redis_get"), log.KV("key", keys[i]))
}
continue
}
baseItem := new(v1.VideoBase)
json.Unmarshal(data, baseItem)
res[baseItem.Svid] = baseItem
}
log.Infov(c, log.KV("event", "redis_get"), log.KV("row_num", len(res)))
return
}
// AddCacheVideoBase 添加缓存
func (d *Dao) AddCacheVideoBase(c context.Context, videoBases map[int64]*v1.VideoBase) (err error) {
keyValueMap := make(map[string][]byte, len(videoBases))
for mid, videoBase := range videoBases {
key := keyVideoBase(mid)
if _, exist := keyValueMap[key]; !exist {
data, _ := json.Marshal(videoBase)
keyValueMap[key] = data
}
}
conn := d.redis.Get(c)
defer conn.Close()
for key, value := range keyValueMap {
conn.Send("SET", key, value, "EX", videoBaseCacheExpire)
}
conn.Flush()
for i := 0; i < len(keyValueMap); i++ {
conn.Receive()
}
log.Infov(c, log.KV("event", "redis_set"), log.KV("row_num", len(videoBases)))
return
}
// DelCacheVideoBase 删除缓存
func (d *Dao) DelCacheVideoBase(c context.Context, svid int64) {
var key = keyVideoBase(svid)
conn := d.redis.Get(c)
defer conn.Close()
conn.Do("DEL", key)
}
// AddOrUpdateVideo 添加或更新视频记录
func (d *Dao) AddOrUpdateVideo(c context.Context, vh *v1.ImportVideoInfo) (err error) {
var (
svid int64
)
tx, err := d.BeginTran(c)
if err != nil {
log.Error("begin transaction err :%v", err)
return
}
defer func() {
if err != nil {
if err = tx.Rollback(); err != nil {
log.Error("tx.Rollback() error(%v)", err)
}
} else {
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}
}()
p := &model.VideoInfo{
CoverURL: vh.CoverUrl,
CoverWidth: vh.CoverWidth,
CoverHeight: vh.CoverHeight,
SVID: vh.Svid,
Title: vh.Title,
MID: vh.MID,
AVID: vh.AVID,
CID: vh.CID,
Pubtime: vh.Pubtime,
From: int16(vh.From),
State: int16(vh.State),
TID: vh.TID,
SubTID: vh.SubTID,
HomeImgURL: vh.HomeImgUrl,
HomeImgWidth: vh.HomeImgWidth,
HomeImgHeight: vh.HomeImgHeight,
}
if err = tx.QueryRow(_queryVideo, vh.Svid).Scan(&svid); err == sql.ErrNoRows {
if err = d.txInsertVideo(c, tx, p); err != nil {
log.Warn("insert video err:%v,svid:%v", err, vh.Svid)
return
}
} else if err != nil {
log.Error("video queryrow scan err:[%v], svid[%v]", err, vh.Svid)
return
}
//sync video_upload_process status
if err = d.txUpdateVideoUploadProcessStatus(c, tx, vh.Svid, model.VideoUploadProcessStatusSuccessed); err != nil {
log.Errorw(c, "event", "d.UpdateVideoUploadProcessStatus err", "err", err)
}
return
}
//UpdateVideoUploadProcessStatus ...
func (d *Dao) txUpdateVideoUploadProcessStatus(ctx context.Context, tx *xsql.Tx, SVID int64, st int64) (err error) {
if _, err = tx.Exec("update video_upload_process set upload_status = ? where svid = ?", st, SVID); err != nil {
log.Errorw(ctx, "errmsg", "UpdateVideoUploadProcessStatus update failed", "err", err)
}
return
}
//txInsertVideo insert video
func (d *Dao) txInsertVideo(c context.Context, tx *xsql.Tx, vh *model.VideoInfo) (err error) {
if _, err = tx.Exec(_addVideo,
vh.CoverURL,
vh.CoverWidth,
vh.CoverHeight,
vh.SVID,
vh.Title,
vh.MID,
vh.AVID,
vh.CID,
vh.Pubtime,
vh.From,
vh.TID,
vh.SubTID,
vh.HomeImgURL,
vh.HomeImgWidth,
vh.HomeImgHeight,
vh.State,
); err != nil {
log.Errorw(c, "event", "insert video err", "err", err, "param", vh)
return
}
return
}
// AddOrUpdateTag 更新或添加标签
func (d *Dao) AddOrUpdateTag(c context.Context, tmap []*v1.TagInfo) (tids []int64, err error) {
// 检查已存在的tag
for _, v := range tmap {
row := d.db.QueryRow(c, _queryTagByName, v.TagName, v.TagType)
t := &model.Tag{
Type: v.TagType,
Name: v.TagName,
}
err = row.Scan(&t.ID)
if err == sql.ErrNoRows {
var q string
var id int64
var res sql.Result
n := strings.Replace(t.Name, "'", "\\'", -1)
q = "('" + n + "'," + strconv.FormatInt(int64(t.Type), 10) + ",1)"
res, _ = d.db.Exec(c, fmt.Sprintf(_insertTag, q))
if res != nil {
id, err = res.LastInsertId()
}
if id != 0 {
tids = append(tids, id)
}
} else if t.ID != 0 {
tids = append(tids, t.ID)
} else {
log.Error("d.db.QueryRow[%v],err:%v", v.TagName, err)
return
}
}
return
}
//根据mids批量查询用户基本信息
func (d *Dao) getUserInfos(c context.Context, mids []int64) (userBases []*model.UserBase, err error) {
midsReq := &acc.MidsReq{
Mids: mids,
RealIp: metadata.String(c, metadata.RemoteIP)}
infosReply, err := d.AccountClient.Infos3(c, midsReq)
if infosReply == nil {
log.Error("query infos3 failed, err (%v)", err)
return
}
userBases = make([]*model.UserBase, 0, 50)
for _, info := range infosReply.Infos {
if info.Mid != 0 {
if len(info.Face) > 255 {
info.Face = "http://i0.hdslb.com/bfs/bbq/video-image/userface/1558868601542006937.png"
log.Info("the value of Face is too long, replace it as http://i0.hdslb.com/bfs/bbq/video-image/userface/1558868601542006937.png, mid(%v)", info.Mid)
}
userBase := &model.UserBase{
Mid: info.Mid,
Name: info.Name,
Sex: info.Sex,
Face: info.Face,
Sign: info.Sign,
Rank: info.Rank,
}
userBases = append(userBases, userBase)
}
}
return
}
//根据mid查询用户基本信息
func (d *Dao) getUserInfo(c context.Context, mid int64) (userBase *model.UserBase, err error) {
midReq := &acc.MidReq{
Mid: mid,
RealIp: metadata.String(c, metadata.RemoteIP)}
info, err := d.AccountClient.Info3(c, midReq)
if err != nil {
log.Error("query info3 failed,mid(%v), err(%v)", mid, err)
return
}
if len(info.Info.Face) > 255 {
info.Info.Face = "http://i0.hdslb.com/bfs/bbq/video-image/userface/1558868601542006937.png"
log.Info("the value of Face is too long, replace it as http://i0.hdslb.com/bfs/bbq/video-image/userface/1558868601542006937.png,,mid(%v)", mid)
}
userBase = &model.UserBase{
Mid: info.Info.Mid,
Name: info.Info.Name,
Sex: info.Info.Sex,
Face: info.Info.Face,
Sign: info.Info.Sign,
Rank: info.Info.Rank,
}
log.Info("getUserInfo userbase (%v)", userBase)
return
}
//InOrUpUserBase 更新用户基本信息
func (d *Dao) InOrUpUserBase(c context.Context, mid int64) (response *v1.SyncUserBaseResponse, err error) {
var (
retry = 3
try int
tx *xsql.Tx
res sql.Result
)
userBase, _ := d.getUserInfo(c, mid)
response = &v1.SyncUserBaseResponse{Affc: -1}
for try = 0; try <= retry; try++ {
if tx, err = d.BeginTran(c); err != nil {
time.Sleep(time.Duration(try) * time.Second)
log.Warn("InOrUpUserBase try begin transaction failed ,err(%v)", err)
continue
}
if res, err = tx.Exec(
_insOrUpUserBase,
userBase.Mid,
userBase.Name,
userBase.Face,
); err != nil {
if err = tx.Rollback(); err != nil {
log.Warn("InOrUpUserBase try rollback failed ,error(%v)", err)
}
} else {
if err = tx.Commit(); err != nil {
log.Warn("InOrUpUserBase try commit failed , error(%v)", err)
} else {
//提交成功,退出
response.Affc, _ = res.RowsAffected()
log.Info("InOrUpUserBase success, affected %v rows", response.Affc)
break
}
}
}
if err != nil {
log.Error("InOrUpUserBase failed, mid(%v), err(%v)", mid, err)
}
return
}
//InOrUpUserBases 批量更新用户基本信息
func (d *Dao) InOrUpUserBases(c context.Context, mids []int64) (response *v1.SyncUserBaseResponse, err error) {
var (
retry = 3
try int
tx *xsql.Tx
res sql.Result
)
userBases, _ := d.getUserInfos(c, mids)
response = &v1.SyncUserBaseResponse{Affc: -1}
for try = 0; try <= retry; try++ {
if tx, err = d.BeginTran(c); err != nil {
time.Sleep(time.Duration(try) * time.Second)
log.Warn("InOrUpUserBases try begin transaction failed failed ,error(%v)", err)
continue
}
sql := "INSERT INTO user_base (mid, uname, face, user_type) VALUES "
for _, userBase := range userBases {
if userBase.Mid != 0 {
sql = sql + "(" + strconv.FormatInt(userBase.Mid, 10) + ",'" + userBase.Name + "','" + userBase.Face + "', 1),"
}
}
if sql == "INSERT INTO user_base (mid, uname, face) VALUES " {
response.Affc = 0
log.Info("InOrUpUserBases param mids are not exist")
return
}
sql = sql[0:len(sql)-1] + " ON DUPLICATE KEY UPDATE uname=values(uname), face=values(face);"
if res, err = tx.Exec(sql); err != nil {
log.Info("InOrUpUserBases sql = (%s)", sql)
if err = tx.Rollback(); err != nil {
log.Warn("InOrUpUserBases try rollback failed ,error(%v)", err)
}
} else {
log.Info("InOrUpUserBases sql = (%s)", sql)
if err = tx.Commit(); err != nil {
log.Warn("InOrUpUserBases try commit failed , error(%v)", err)
} else {
//提交成功,退出
response.Affc, _ = res.RowsAffected()
log.Info("InOrUpUserBases commit success, affected %v rows", response.Affc)
break
}
}
}
if err != nil {
log.Error("InOrUpUserBases failed, err(%v)", err)
}
return
}
//InOrUpUserSta 更新用户up主主站画像
func (d *Dao) InOrUpUserSta(c context.Context, mid int64) (response *v1.SyncUserBaseResponse, err error) {
var (
retry = 3
try int
tx *xsql.Tx
res sql.Result
)
log.Info("InOrUpUserSta start")
response = &v1.SyncUserBaseResponse{Affc: -1}
userBase, _ := d.getUserInfo(c, mid)
for try = 0; try <= retry; try++ {
if tx, err = d.BeginTran(c); err != nil {
time.Sleep(time.Duration(try) * time.Second)
log.Info("InOrUpUserSta on mid(%v) try begin transaction failed failed ,error(%v)", userBase.Mid, err)
continue
}
if res, err = tx.Exec(
_insOrUpUserSta,
userBase.Mid,
userBase.Name,
); err != nil {
fmt.Printf("sql exec error,err(%v)", err)
if err = tx.Rollback(); err != nil {
log.Info("InOrUpUserSta on mid(%v) rollback failed ,error(%v)", userBase.Mid, err)
} else {
fmt.Println("rollbacked")
}
} else {
if err = tx.Commit(); err != nil {
log.Info("InOrUpUserSta on mid(%v) commit failed , error(%v)", userBase.Mid, err)
} else {
//提交成功,退出
response.Affc, _ = res.RowsAffected()
break
}
}
}
if err != nil {
log.Error("InOrUpUserSta mid(%v) failed, err(%v)", mid, err)
}
return
}
//InOrUpUserStas 批量更新用户状态
func (d *Dao) InOrUpUserStas(c context.Context, mids []int64) (response *v1.SyncUserBaseResponse, err error) {
var (
retry = 3
try int
tx *xsql.Tx
res sql.Result
)
log.Info("InOrUpUserStas start")
response = &v1.SyncUserBaseResponse{Affc: -1}
userBases, _ := d.getUserInfos(c, mids)
for try = 0; try <= retry; try++ {
if tx, err = d.BeginTran(c); err != nil {
time.Sleep(time.Duration(try) * time.Second)
log.Warn("InOrUpUserStas try begin transaction failed failed ,error(%v)", err)
continue
}
sql := "INSERT INTO user_statistics_hive (mid, uname) VALUES"
for _, userBase := range userBases {
sql = sql + "(" + strconv.FormatInt(userBase.Mid, 10) + ",'" + userBase.Name + "'),"
}
sql = sql[0:len(sql)-1] + "ON DUPLICATE KEY UPDATE uname=values(uname)"
if res, err = tx.Exec(sql); err != nil {
if err = tx.Rollback(); err != nil {
log.Warn("InOrUpUserStas try rollback failed ,error(%v)", err)
} else {
log.Warn("InOrUpUserStas rollbacked")
}
} else {
if err = tx.Commit(); err != nil {
log.Warn("InOrUpUserStas try commit failed , error(%v)", err)
} else {
//提交成功,退出
response.Affc, _ = res.RowsAffected()
log.Info("InOrUpUserStas on commit success, affected %v rows", response.Affc)
break
}
}
}
if err != nil {
log.Error("InOrUpUserSta run failed, err(%v)", err)
}
return
}
// GetVideoBvcTable 获取bvc分表名
func (d *Dao) getVideoBvcTable(svid int64) string {
return fmt.Sprintf("video_bvc_%02d", svid%_BVCSubTableSize)
}
//RawVideoStatistic get video statistics
func (d *Dao) RawVideoStatistic(c context.Context, svids []int64) (res map[int64]*model.SvStInfo, err error) {
const maxIDNum = 20
var (
idStr string
)
res = make(map[int64]*model.SvStInfo)
if len(svids) > maxIDNum {
svids = svids[:maxIDNum]
}
l := len(svids)
for k, svid := range svids {
if k < l-1 {
idStr += strconv.FormatInt(svid, 10) + ","
} else {
idStr += strconv.FormatInt(svid, 10)
}
res[svid] = &model.SvStInfo{}
}
rows, err := d.db.Query(c, fmt.Sprintf(_queryStatisticsList, idStr))
if err != nil {
log.Error("query error(%s)", err.Error())
return
}
defer rows.Close()
for rows.Next() {
ssv := new(model.SvStInfo)
if err = rows.Scan(&ssv.SVID, &ssv.Play, &ssv.Subtitles, &ssv.Like, &ssv.Share, &ssv.Report); err != nil {
log.Error("RawVideoStatistic rows.Scan() error(%v)", err)
return
}
res[ssv.SVID] = ssv
}
cmtCount, _ := d.ReplyCounts(c, svids, DefaultCmType)
for id, cmt := range cmtCount {
if _, ok := res[id]; ok {
res[id].Reply = cmt.Count
}
}
return
}
// CommitTrans 提交转码
func (d *Dao) CommitTrans(c context.Context, arg *v1.BVideoTransRequset) error {
path, ok := d.c.URLs["bvc_push"]
if !ok {
log.Warnv(c, log.KV("log", "bvc_push url not set"))
return ecode.ReqParamErr
}
data, _ := json.Marshal(arg)
b := string(data)
req, err := xhttp.NewRequest("POST", path, bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
if err != nil {
log.Error("bvc_push url(%s) req(%+v) body(%s) error(%v)", path, req, b, err)
return err
}
var res struct {
Code int `json:"code"`
Msg string `json:"message"`
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("bvc_push url(%s) req(%+v) body(%s) ret (%+v) err[%v]", path, req, b, res, err)))
return err
}
log.V(5).Infov(c, log.KV("log", fmt.Sprintf("bvc_push req(%+v) body(%s) ret (%+v)", req, b, res)))
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Errorv(c, log.KV("log", fmt.Sprintf("bvc_push url(%s) req(%+v) body(%s) ret(%+v) error(%v)", path, req, b, res, err)))
return err
}
return nil
}
//AddOrUpdateBVCInfo 添加或更新BVC转码信息
func (d *Dao) AddOrUpdateBVCInfo(c context.Context, arg *model.VideoBVC) (err error) {
err = d.AddBVCInfo(c, arg)
if err != nil {
if matched, _ := regexp.MatchString("Duplicate entry", err.Error()); matched {
err = d.UpdataBVCInfo(c, arg)
return
}
log.Errorv(c,
log.KV("log", fmt.Sprintf("dao.db.Exec(AddOrUpdateBVCInfo[%+v]) err(%v)", arg, err)),
)
}
return
}
//TxAddOrUpdateBVCInfo 事务添加或更新BVC转码信息
func (d *Dao) TxAddOrUpdateBVCInfo(c context.Context, tx *xsql.Tx, arg *model.VideoBVC) (err error) {
err = d.TxAddBVCInfo(tx, arg)
if err != nil {
if matched, _ := regexp.MatchString("Duplicate entry", err.Error()); matched {
err = d.TxUpdataBVCInfo(tx, arg)
return
}
log.Errorv(c,
log.KV("log", fmt.Sprintf("dao.db.Exec(AddOrUpdateBVCInfo[%+v]) err(%v)", arg, err)),
)
}
return
}
// AddBVCInfo 添加BVC转码信息
func (d *Dao) AddBVCInfo(c context.Context, arg *model.VideoBVC) (err error) {
t := d.getVideoBvcTable(arg.SVID)
sql := fmt.Sprintf(_addBVCData, t)
_, err = d.db.Exec(c, sql, arg.SVID, arg.Path, arg.ResolutionRetio, arg.CodeRate, arg.VideoCode, arg.Duration, arg.FileSize)
return
}
// TxAddBVCInfo 事务添加BVC转码信息
func (d *Dao) TxAddBVCInfo(tx *xsql.Tx, arg *model.VideoBVC) (err error) {
t := d.getVideoBvcTable(arg.SVID)
sql := fmt.Sprintf(_addBVCData, t)
_, err = tx.Exec(sql, arg.SVID, arg.Path, arg.ResolutionRetio, arg.CodeRate, arg.VideoCode, arg.Duration, arg.FileSize)
return
}
// TxUpdataBVCInfo 事务更新BVC转码信息
func (d *Dao) TxUpdataBVCInfo(tx *xsql.Tx, arg *model.VideoBVC) (err error) {
t := d.getVideoBvcTable(arg.SVID)
sql := fmt.Sprintf(_updateBVCData, t)
_, err = tx.Exec(sql, arg.Path, arg.ResolutionRetio, arg.VideoCode, arg.Duration, arg.FileSize, arg.SVID, arg.CodeRate)
return
}
// UpdataBVCInfo 更新BVC转码信息
func (d *Dao) UpdataBVCInfo(c context.Context, arg *model.VideoBVC) (err error) {
t := d.getVideoBvcTable(arg.SVID)
sql := fmt.Sprintf(_updateBVCData, t)
_, err = d.db.Exec(c, sql, arg.Path, arg.ResolutionRetio, arg.VideoCode, arg.Duration, arg.FileSize, arg.SVID, arg.CodeRate)
return
}
// UpdateCmsSvPIC 更新封面图
func (d *Dao) UpdateCmsSvPIC(c context.Context, svid int64, pic *v1.SvPic, st int64) error {
_, err := d.cmsdb.Exec(c, _updateSvPIC, pic.PicURL, pic.PicWidth, pic.PicHeight, st, svid)
return err
}
// HostnameRegister .
func (d *Dao) HostnameRegister(hostnameIndex int64) (succ bool) {
conn := d.redis.Get(context.Background())
defer conn.Close()
redisKey := fmt.Sprintf("hostname:index:%d", hostnameIndex)
exists, err := redis.Int(conn.Do("EXISTS", redisKey))
if err != nil {
log.Errorv(context.Background(), log.KV("event", "fatal"), log.KV("log", fmt.Sprintf("get hostname index from redis fail: key=%s", redisKey)))
// 即使redis失败了也给返回成功
return true
}
if exists == 1 {
return false
}
// 不去管返回结果,永远返回成功
if _, err = conn.Do("SETEX", redisKey, 1000, 1); err != nil {
log.Errorv(context.Background(), log.KV("event", "fatal"), log.KV("log", fmt.Sprintf("get hostname index from redis fail: key=%s", redisKey)))
}
return true
}
// AddVideoViews .
func (d *Dao) AddVideoViews(c context.Context, svid int64, views int) (affected int64, err error) {
row := d.db.QueryRow(c, _existedStatistics, svid)
tmp := 0
if err = row.Scan(&tmp); err != nil || tmp == 0 {
_, err = d.db.Exec(c, _insertStatistics, svid, 0, 0, 0, 0, 0)
if err != nil {
return
}
}
result, err := d.db.Exec(c, _addVideoViews, views, svid)
if err != nil {
return
}
return result.RowsAffected()
}
// VideoStateUpdate .
func (d *Dao) VideoStateUpdate(c context.Context, svid int64, newState int) (aff int64, err error) {
result, err := d.db.Exec(c, _updateVideoState, newState, svid)
if err != nil {
return
}
aff, err = result.RowsAffected()
return
}

View File

@@ -0,0 +1,78 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/service/bbq/common/db/bbq"
"go-common/app/service/bbq/video/model/grpc"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/net/metadata"
"strconv"
"strings"
)
const (
_querySvPlay = "select `svid`,`path`,`resolution_retio`,`code_rate`,`video_code`,`file_size`,`duration` from %s where svid in (%s) and is_deleted = 0 order by code_rate desc"
)
const (
_defaultPlatform = "html5"
_playBcNum = 1
)
//RawSVBvcKey 批量获取playurl相对地址
func (d *Dao) RawSVBvcKey(c context.Context, svids []int64) (res map[int64][]*bbq.VideoBvc, err error) {
var (
tb map[string][]string
rows *sql.Rows
)
res = make(map[int64][]*bbq.VideoBvc)
tb = make(map[string][]string)
tName := "video_bvc_%02d"
for _, v := range svids {
if v <= 0 {
continue
}
tbName := fmt.Sprintf(tName, v%100)
tb[tbName] = append(tb[tbName], strconv.FormatInt(v, 10))
}
for k, v := range tb {
query := fmt.Sprintf(_querySvPlay, k, strings.Join(v, ","))
if rows, err = d.db.Query(c, query); err != nil {
log.Errorv(c, log.KV("log", "RawSVBvcKey query sql"), log.KV("err", err))
continue
}
for rows.Next() {
tmp := bbq.VideoBvc{}
if err = rows.Scan(&tmp.SVID, &tmp.Path, &tmp.ResolutionRetio, &tmp.CodeRate, &tmp.VideoCode, &tmp.FileSize, &tmp.Duration); err != nil {
log.Errorv(c, log.KV("log", "RawSVBvcKey scan"), log.KV("err", err))
continue
}
res[tmp.SVID] = append(res[tmp.SVID], &tmp)
}
}
return
}
// RelPlayURLs 相对地址批量获取playurl
func (d *Dao) RelPlayURLs(c context.Context, addrs []string) (res map[string]*grpc.VideoKeyItem, err error) {
res = make(map[string]*grpc.VideoKeyItem)
req := &grpc.RequestMsg{
Keys: addrs,
Backup: uint32(_playBcNum),
Platform: _defaultPlatform,
UIP: metadata.String(c, metadata.RemoteIP),
}
_str, _ := json.Marshal(req)
log.V(5).Infov(c, log.KV("log", fmt.Sprintf("bvc play req (%s)", string(_str))))
r, err := d.bvcPlayClient.ProtobufPlayurl(c, req)
_str, _ = json.Marshal(r)
if err != nil {
log.Error("bvc play err[%v] ret[%s]", err, string(_str))
return
}
log.V(5).Infov(c, log.KV("log", fmt.Sprintf("bvc play ret (%s)", string(_str))))
res = r.Data
return
}

View File

@@ -0,0 +1,73 @@
package dao
import (
"context"
"go-common/app/service/bbq/video/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
insertVR = "insert into video_repository (`cid`,`svid`,`mid`,`title`,`from`,`sync_status`) values (?,?,?,?,?,?)"
updateVRSyncStatus = "update video_repository set sync_status = ?"
queryVRBySvid = "select `title`,`mid`,`home_img_url`,`home_img_width`,`home_img_height` from video_repository where svid = ?"
)
//InsertVR ..
func (d *Dao) InsertVR(c context.Context, vr *model.VideoRepository) (err error) {
if vr == nil {
err = ecode.BBQSystemErr
log.Errorw(c, "event", "InsertVR req nil")
return
}
if _, err = d.cmsdb.Exec(c, insertVR, vr.SVID, vr.SVID, vr.MID, vr.Title, vr.From,
vr.SyncStatus); err != nil {
log.Errorw(c, "event", "InsertVR err", "err", err, "param", vr)
return
}
return
}
//UpdateVR ..
func (d *Dao) UpdateVR(c context.Context, vr *model.VideoRepository) (err error) {
if vr == nil {
err = ecode.BBQSystemErr
log.Errorw(c, "event", "InsertVR req nil")
return
}
if _, err = d.cmsdb.Exec(c, updateVRSyncStatus, vr.SyncStatus); err != nil {
log.Errorw(c, "event", "UpdateVR err", "err", err, "param", vr)
return
}
return
}
//QueryVR ..
func (d *Dao) QueryVR(c context.Context, vr *model.VideoRepository) (res *model.VideoRepository, err error) {
if vr == nil {
err = ecode.BBQSystemErr
log.Errorw(c, "event", "InsertVR req nil")
return
}
res = new(model.VideoRepository)
if err = d.cmsdb.QueryRow(c, queryVRBySvid, vr.SVID).Scan(&res.Title, &res.MID, &res.HomeImgURL, &res.HomeImgWidth, &res.HomeImgHeight); err != nil {
log.Errorw(c, "event", "queryVR scan err", "err", err, "param", vr)
return
}
return
}
//HomeImgCreate ..
func (d *Dao) HomeImgCreate(c context.Context, vr *model.VideoRepository) (err error) {
if vr == nil {
err = ecode.BBQSystemErr
log.Errorw(c, "event", "HomeImgCreate req nil")
return
}
if _, err = d.cmsdb.Exec(c, "update video_repository set home_img_url = ?,home_img_width = ? ,home_img_height = ? where svid = ? and mid = ?",
vr.HomeImgURL, vr.HomeImgWidth, vr.HomeImgHeight, vr.SVID, vr.MID); err != nil {
log.Errorw(c, "update home_img err", "err", err, "param", vr)
return
}
return
}

View File

@@ -0,0 +1,51 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
insertOrUpdateVUP = "insert into video_upload_process (`svid`,`title`,`mid`,`upload_status`,`retry_times`,`home_img_url`,`home_img_width`,`home_img_height`) values(?,?,?,?,?,?,?,?) on duplicate key update `title` = values(`title`),`mid` = values(`mid`),`upload_status` = values(`upload_status`),`retry_times`= values(`retry_times`)"
selectPrepareVUP = "select `svid`,`title`,`upload_status`,`home_img_url`,`home_img_height`,`home_img_width` from video_upload_process where mid=%d and is_deleted=0 and upload_status != 1 order by ctime desc limit 20"
)
//InsertOrUpdateVUP ..
func (d *Dao) InsertOrUpdateVUP(c context.Context, vup *model.VideoUploadProcess) (err error) {
if vup == nil {
err = ecode.BBQSystemErr
log.Errorw(c, "event", "InsertVUP req nil")
return
}
if _, err = d.db.Exec(c, insertOrUpdateVUP, vup.SVID, vup.Title, vup.Mid, vup.UploadStatus, vup.RetryTimes, vup.HomeImgURL, vup.HomeImgWidth, vup.HomeImgHeight); err != nil {
log.Errorw(c, "event", "InsertVR err", "err", err, "param", vup)
return
}
return
}
// GetPrepareVUP 获取数据
func (d *Dao) GetPrepareVUP(c context.Context, mid int64) (vups []*v1.UploadingVideo, err error) {
querySQL := fmt.Sprintf(selectPrepareVUP, mid)
rows, err := d.db.Query(c, querySQL)
if err != nil {
log.Errorw(c, "log", "get prepare vup fail", "mid", mid)
return
}
defer rows.Close()
for rows.Next() {
vup := new(v1.UploadingVideo)
if err = rows.Scan(&vup.Svid, &vup.Title, &vup.UploadStatus, &vup.HomeImgUrl, &vup.HomeImgHeight, &vup.HomeImgWidth); err != nil {
log.Errorw(c, "log", "scan vup fail")
return
}
vups = append(vups, vup)
}
return
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"bvc.go",
"databus.go",
"model.go",
"util.go",
],
importpath = "go-common/app/service/bbq/video/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/time:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/video/model/grpc:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,51 @@
package model
// ArchiveNotify .
type ArchiveNotify struct {
Action string `json:"action"`
Table string `json:"table"`
New *Archive `json:"new"`
Old *Archive `json:"old"`
}
// Archive .
type Archive struct {
ID int `json:"id"`
AID int64 `json:"aid"`
CID int64 `json:"cid"`
MID int64 `json:"mid"`
TypeID int32 `json:"typeid"`
Videos int `json:"videos"`
Title string `json:"title"`
Cover string `json:"cover"`
Content string `json:"content"`
Duration int `json:"duration"`
Attribute int `json:"attribute"`
Copyright int `json:"copyright"`
Access int `json:"access"`
PubTime string `json:"pubtime"`
CTime string `json:"ctime"`
MTime string `json:"mtime"`
State int `json:"state"`
MissionID int `json:"mission_id"`
OrderID int `json:"order_id"`
RedirectURL string `json:"redirect_url"`
Forward int `json:"forward"`
TID int32 `json:"tid"`
SubTID int32 `json:"sub_tid"`
}
// ArchiveTypeResponse .
type ArchiveTypeResponse struct {
Code int `json:"code"`
Data map[string]*ArchiveType `json:"data"`
Message string `json:"message"`
TTL int `json:"ttl"`
}
// ArchiveType .
type ArchiveType struct {
ID int `json:"id"`
PID int `json:"pid"`
Name string `json:"name"`
}

View File

@@ -0,0 +1,8 @@
package model
// BVCRecord .
type BVCRecord struct {
SVID int64
FLowID string
Type int8
}

View File

@@ -0,0 +1,6 @@
package model
//DataTopicCmsData Cms消息结构
type DataTopicCmsData struct {
SVID int64 `json:"svid"`
}

View File

@@ -0,0 +1,57 @@
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 = "grpc_proto",
srcs = ["bvc.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "grpc_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/bbq/video/model/grpc",
proto = ":grpc_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [],
embed = [":grpc_go_proto"],
importpath = "go-common/app/service/bbq/video/model/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_gogo_protobuf//sortkeys: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,34 @@
syntax="proto3";
package video.vod.playurlbbq;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "grpc";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
message RequestMsg {
repeated string keys = 1;
string platform = 2;
string uip = 3[(gogoproto.customname)= "UIP"];
uint32 uiplong = 4;
uint32 backup = 5;
string uuid = 6[(gogoproto.customname)= "UUID"];
}
message VideoKeyItem {
uint32 etime = 1;
repeated string url = 2[(gogoproto.customname)= "URL"];
}
message ResponseMsg {
uint32 code = 1;
map<string, VideoKeyItem> data = 2;
}
//// Following defines rpc services.
service PlayurlService {
rpc ProtobufPlayurl(RequestMsg) returns (ResponseMsg);
};

View File

@@ -0,0 +1,223 @@
package model
import "go-common/library/time"
const (
//FromBILI from bilibili
FromBILI = 0
//FromBBQ from bbq
FromBBQ = 1
//FromCMS from cms
FromCMS = 2
//SourceRequest video_repository.sync_status source request
SourceRequest = 1
//SourceXcodeCover video_repository.sync_status xcode/cover
SourceXcodeCover = 2
//SourceAI video_repository.sync_status ai source
SourceAI = 4
//SourceOnshelf video_repository.sync_status video on shelf
SourceOnshelf = 8
//UploadStatusFailed video_upload_process.upload_status
UploadStatusFailed = -1
//UploadStatusSuccessed video_upload_process.upload_status
UploadStatusSuccessed = 1
//UploadStatusWaiting video_upload_process.upload_status
UploadStatusWaiting = 0
//VideoUploadProcessStatusFailed .
VideoUploadProcessStatusFailed = -1
//VideoUploadProcessStatusPending .
VideoUploadProcessStatusPending = 0
//VideoUploadProcessStatusSuccessed .
VideoUploadProcessStatusSuccessed = 1
)
//视频状态集合
const (
//VideoStRecommend 推荐
VideoStRecommend = 5
//VideoStHighGrade 优质
VideoStHighGrade = 4
//VideoStCanPlay 可放出
VideoStCanPlay = 3
//VideoStCheckBack 视频状态回查
VideoStCheckBack = 2
//VideoStPassReview 审核通过
VideoStPassReview = 1
//VideoStPendingPassReview 原始稿件状态,等待安全审核
VideoStPendingPassReview = 0
//VideoStPassReviewReject 回查不通过,仅自见
VideoStPassReviewReject = -1
//VideoStCheckBackPatialPlay 回查不放出在APP部分放出
VideoStCheckBackPatialPlay = -2
//VideoUnshelf 下架
VideoUnshelf = -3
//VideoDelete 删除
VideoDelete = -4
)
//Tag .
type Tag struct {
ID int64 `json:"id"`
Name string `json:"name"`
Type int32 `json:"type"`
}
// VideoInfo 一般视频信息
type VideoInfo struct {
SVID int64 `json:"svid"`
TID int64 `json:"tid"`
SubTID int64 `json:"sub_tid"`
Title string `json:"title"`
Content string `json:"content"`
MID int64 `json:"mid"`
Report int64 `json:"report"`
Duration int64 `json:"duration"`
Pubtime string `json:"pubtime"`
Ctime time.Time `json:"ctime"`
AVID int64 `json:"avid"`
CID int64 `json:"cid"`
State int16 `json:"state"`
Original int64 `json:"original"`
From int16 `json:"from"`
IsFullScreen int16 `json:"is_full_screen"`
CoverURL string `json:"cover_url"`
CoverWidth int64 `json:"cover_width"`
CoverHeight int64 `json:"cover_height"`
HomeImgURL string `json:"home_img_url" form:"home_img_url"`
HomeImgWidth int64 `json:"home_img_width" form:"home_img_width"`
HomeImgHeight int64 `json:"home_img_height" form:"home_img_height"`
}
//VideoUploadProcess .
type VideoUploadProcess struct {
SVID int64 `json:"svid"`
Title string `json:"Title"`
Mid int64 `json:"mid"`
UploadStatus int64 `json:"upload_status"`
RetryTimes int64 `json:"retry_times"`
HomeImgURL string `json:"home_img_url"`
HomeImgWidth int64 `json:"home_img_width"`
HomeImgHeight int64 `json:"home_img_height"`
}
//VideoRepository ...
type VideoRepository struct {
AVID int64 `json:"avid"`
CID int64 `json:"cid"`
MID int64 `json:"mid"`
SVID int64 `json:"svid"`
From int64 `json:"from"`
Title string `json:"title"`
Content string `json:"content"`
Original int64 `json:"original"`
Duration int64 `json:"duration"`
Pubtime string `json:"pubtime"`
TID int64 `json:"tid"`
SubTID int64 `json:"sub_tid"`
IsFullScreen int64 `json:"is_full_screen"`
CoverURL string `json:"cover_url"`
CoverWidth string `json:"cover_width"`
CoverHeight string `json:"cover_height"`
HomeImgURL string `json:"home_img_url"`
HomeImgWidth int64 `json:"home_img_width"`
HomeImgHeight int64 `json:"home_img_height"`
SyncStatus int64 `json:"sync_status"`
}
// VideoStHive 视频hive统计数据
type VideoStHive struct {
SVID int64 `json:"svid"`
Play int64 `json:"play"`
Report int64 `json:"report"`
DurationAll int64 `json:"duration_all"`
Access int64 `json:"access"`
Reply int64 `json:"reply"`
Fav int64 `json:"fav"`
Likes int64 `json:"likes"`
Coin int64 `json:"coin"`
Share int64 `json:"share"`
Subtitles int64 `json:"subtitles"`
ElecPay int64 `json:"elec_pay"`
ElecNum int64 `json:"elec_num"`
ElecUser int64 `json:"elec_user"`
DurationDaily int64 `json:"duration_daily"`
ShareDaily int64 `json:"share_daily"`
PlayDaily int64 `json:"play_daily"`
FavDaily int64 `json:"fav_daily"`
ReplyDaily int64 `json:"reply_daily"`
SubtitlesDaily int64 `json:"subtitles_daily"`
LikesDaily int64 `json:"likes_daily"`
}
//VideoHiveInfo struct
type VideoHiveInfo struct {
AVID int64 `json:"avid"`
CID int64 `json:"cid"`
MID int64 `json:"mid"`
Title string `json:"title"`
Content string `json:"content"`
Original int16 `json:"original"`
Report int64 `json:"report"`
DurationAll int64 `json:"duration_all"`
Play int64 `json:"play"`
PlayGuest int64 `json:"play_guest"`
PlayFans int64 `json:"play_fans"`
Access int64 `json:"access"`
Reply int64 `json:"reply"`
Fav int64 `json:"fav"`
Likes int64 `json:"likes"`
Coin int64 `json:"coin"`
Share int64 `json:"share"`
Danmu int64 `json:"danmu"`
ElecPay int64 `json:"elec_pay"`
ElecNum int64 `json:"elec_num"`
ElecUser int64 `json:"elec_user"`
Duration int64 `json:"duration"`
State int64 `json:"state"`
Tag string `json:"tag"`
ShareDaily int64 `json:"share_daily"`
PlayDaily int64 `json:"play_daily"`
FavDaily int64 `json:"fav_daily"`
ReplyDaily int64 `json:"reply_daily"`
DanmuDaily int64 `json:"danmu_daily"`
LikesDaily int64 `json:"likes_daily"`
DurationDaily int64 `json:"duration_daily"`
Pubtime string `json:"pubtime"`
LogDate string `json:"log_date"`
TID int64 `json:"tid"`
SubTID int64 `json:"sub_tid"`
Ctime string `json:"ctime"`
}
//UserBase .
type UserBase struct {
Mid int64 `json:"mid"`
Name string `json:"uname"`
Sex string `json:"sex"`
Face string `json:"face"`
Sign string `json:"sign"`
Rank int32 `json:"rank"`
}
// VideoBVC 视频转码信息
type VideoBVC struct {
SVID int64 `json:"svid"`
Path string `json:"path"`
ResolutionRetio string `json:"resolution_retio"`
CodeRate int64 `json:"code_rate"`
VideoCode string `json:"video_code"`
Duration int64 `json:"duration"`
FileSize int64 `json:"file_size"`
}
// SvStInfo 视频统计
type SvStInfo struct {
SVID int64 `json:"svid"`
Play int64 `json:"view"` //和上层的play重复因此改成view
Subtitles int64 `json:"subtitles"`
Like int64 `json:"like"`
Share int64 `json:"share"`
Reply int64 `json:"reply"`
Report int64 `json:"report"`
}

View File

@@ -0,0 +1,34 @@
package model
import (
"fmt"
"reflect"
"strings"
)
// Implode function like php
func Implode(list interface{}, seq string) string {
listValue := reflect.Indirect(reflect.ValueOf(list))
if listValue.Kind() != reflect.Slice {
return ""
}
count := listValue.Len()
listStr := make([]string, 0, count)
for i := 0; i < count; i++ {
v := listValue.Index(i)
if str, err := getValue(v); err == nil {
listStr = append(listStr, str)
}
}
return strings.Join(listStr, seq)
}
func getValue(value reflect.Value) (res string, err error) {
switch value.Kind() {
case reflect.Ptr:
res, err = getValue(value.Elem())
default:
res = fmt.Sprint(value.Interface())
}
return
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/bbq/video/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/bbq/video/service:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@org_golang_google_grpc//:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,30 @@
package grpc
import (
"context"
v1 "go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/service"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
//New 生成rpc服务
func New(srv *service.Service) *warden.Server {
s := warden.NewServer(nil)
s.Use(middleware())
v1.RegisterVideoServer(s.Server(), srv)
_, err := s.Start()
if err != nil {
panic("run server failed!" + err.Error())
}
return s
}
func middleware() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
//call chain
resp, err = handler(ctx, req)
return
}
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"video.go",
],
importpath = "go-common/app/service/bbq/video/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/bbq/video/api/http/v1:go_default_library",
"//app/service/bbq/video/conf:go_default_library",
"//app/service/bbq/video/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,67 @@
package http
import (
"encoding/json"
"net/http"
"go-common/app/service/bbq/video/conf"
"go-common/app/service/bbq/video/service"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init
func Init(c *conf.Config, s *service.Service) {
srv = s
engine := bm.DefaultServer(c.BM.Server)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/bbq/internal")
{
g.POST("/sv/trans/back", bvcTransBack)
g.GET("/sv/trans/commit", bvcTransCommit)
g.POST("/sv/stat", videoStat)
g.GET("/create/id", createID)
g.GET("/sv/create/id", createID)
// 增加视频播放量数据
g.POST("/sv/views/add", videoViewsAdd)
g.POST("/sv/limits/modify", limitsModify)
g.POST("/sv/play", svPlays)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// bindJson 解析application/json请求body
func bindJSON(c *bm.Context, obj interface{}) error {
decoder := json.NewDecoder(c.Request.Body)
err := decoder.Decode(obj)
if err != nil {
log.Warn("参数解析失败 %v", err)
err = ecode.ReqParamErr
return err
}
return nil
}

View File

@@ -0,0 +1,77 @@
package http
import (
"go-common/app/service/bbq/video/api/grpc/v1"
grpc "go-common/app/service/bbq/video/api/grpc/v1"
httpV1 "go-common/app/service/bbq/video/api/http/v1"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// example for http request handler
func bvcTransBack(c *bm.Context) {
arg := new(v1.BVCTransBackRequset)
err := bindJSON(c, arg)
if err == nil {
err = srv.BVCTransRes(c, arg)
}
c.JSON(nil, err)
}
func bvcTransCommit(c *bm.Context) {
arg := new(v1.BVideoTransRequset)
err := c.Bind(arg)
if err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(srv.BVCTransCommit(c, arg))
}
func createID(c *bm.Context) {
arg := new(v1.CreateIDRequest)
err := c.Bind(arg)
if err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(srv.CreateID(c, arg))
}
func videoViewsAdd(c *bm.Context) {
arg := new(httpV1.ViewsAddRequest)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(srv.VideoViewsAdd(c, arg))
}
func videoStat(c *bm.Context) {
arg := new(grpc.SvStatisticsInfoReq)
if err := bindJSON(c, arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(srv.SvStatisticsInfo(c, arg))
}
func limitsModify(c *bm.Context) {
arg := new(grpc.ModifyLimitsRequest)
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
c.JSON(srv.ModifyLimits(c, arg))
}
func svPlays(c *bm.Context) {
arg := new(grpc.PlayInfoRequest)
if err := bindJSON(c, arg); err != nil {
log.Error("param err:%v", err)
return
}
c.JSON(srv.PlayInfo(c, arg))
}

View File

@@ -0,0 +1,62 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"play.go",
"service.go",
"upload.go",
"video.go",
],
importpath = "go-common/app/service/bbq/video/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/common/db/bbq:go_default_library",
"//app/service/bbq/topic/api:go_default_library",
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/bbq/video/api/http/v1:go_default_library",
"//app/service/bbq/video/conf:go_default_library",
"//app/service/bbq/video/dao:go_default_library",
"//app/service/bbq/video/model:go_default_library",
"//app/service/bbq/video/model/grpc:go_default_library",
"//library/conf/env:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/errgroup:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["service_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/bbq/video/conf:go_default_library",
],
)

View File

@@ -0,0 +1,63 @@
package service
import (
"context"
v1 "go-common/app/service/bbq/video/api/grpc/v1"
"go-common/library/ecode"
"go-common/library/log"
"sync"
"time"
)
var (
_wait sync.WaitGroup
_archiveSubKeepAlive = true
)
// archiveSub 订阅B站稿件过滤后传给生产流程
func (s *Service) archiveSub(c context.Context) {
_wait.Add(1)
defer _wait.Done()
for _archiveSubKeepAlive {
// 订阅稿件
archive, err := s.dao.ArchiveSub()
if err == ecode.ArchiveDatabusNilErr {
log.Error("ArchiveSub failed archive[%v] err[%v]", archive, err)
return
}
if err != nil {
log.Error("ArchiveSub failed archive[%v] err[%v]", archive, err)
continue
}
if archive == nil {
continue
}
// 生产SVID
pubtime, err := time.Parse("2006-01-02 15:04:05", archive.PubTime)
if err != nil {
log.Error("ArchiveSub pubtime parse failed archive[%v] err[%v]", archive, err)
continue
}
res, err := s.CreateID(c, &v1.CreateIDRequest{
Mid: int64(archive.MID),
Time: pubtime.Unix(),
})
if err != nil || res == nil {
log.Error("ArchiveSub CreateID failed archive[%v] err[%v]", archive, err)
continue
}
// 传递生产
if err = s.dao.ArchiveKickOff(c, res.NewId, archive); err != nil {
log.Error("ArchiveSub ArchiveKickOff failed archive[%v] SVID[%d] err[%v]", archive, res.NewId, err)
continue
}
}
}
func (s *Service) archiveSubClose() {
_archiveSubKeepAlive = false
_wait.Wait()
}

View File

@@ -0,0 +1,78 @@
package service
import (
"context"
"go-common/app/service/bbq/common/db/bbq"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/model/grpc"
"go-common/library/log"
"time"
)
// PlayInfo 批量获取playurl(相对地址方法)
func (s *Service) PlayInfo(c context.Context, args *v1.PlayInfoRequest) (res *v1.PlayInfoResponse, err error) {
var (
relAddr []string
bvcUrls map[string]*grpc.VideoKeyItem
bvcKeys map[int64][]*bbq.VideoBvc
svids = args.Svid
)
res = new(v1.PlayInfoResponse)
bvcKeys, err = s.dao.RawSVBvcKey(c, svids)
if err != nil {
log.Error("s.dao.RawSVBvcKey err[%v]", err)
}
res.List = make(map[int64]*v1.PlayInfo)
for id, keys := range bvcKeys {
res.List[id] = &v1.PlayInfo{
Svid: id,
}
for k, v := range keys {
if k == 0 {
res.List[id].Quality = int64(v.CodeRate)
}
fi := &v1.FileInfo{
Timelength: v.Duration,
Filesize: v.FileSize,
Path: v.Path,
}
res.List[id].FileInfo = append(res.List[id].FileInfo, fi)
res.List[id].SupportQuality = append(res.List[id].SupportQuality, int64(v.CodeRate))
relAddr = append(relAddr, v.Path)
}
}
bvcUrls, err = s.dao.RelPlayURLs(c, relAddr)
if err != nil {
log.Error("s.dao.RelPlayURLs err[%v]", err)
return
}
//拼装playurl
for _, svid := range svids {
if play, ok := res.List[svid]; ok {
for fk, f := range play.FileInfo {
if urls, ok := bvcUrls[f.Path]; ok {
res.List[svid].ExpireTime = int64(urls.Etime)
res.List[svid].CurrentTime = time.Now().Unix()
for _, u := range urls.URL {
if res.List[svid].FileInfo[fk].Url == "" {
res.List[svid].FileInfo[fk].Url = u
if res.List[svid].Url == "" {
res.List[svid].Url = u
}
continue
}
if res.List[svid].FileInfo[fk].UrlBc == "" {
res.List[svid].FileInfo[fk].UrlBc = u
break
}
}
} else {
delete(res.List, svid)
break
}
}
res.List[svid] = play
}
}
return
}

View File

@@ -0,0 +1,77 @@
package service
import (
"context"
"crypto/md5"
"fmt"
topic "go-common/app/service/bbq/topic/api"
"go-common/app/service/bbq/video/conf"
"go-common/app/service/bbq/video/dao"
"go-common/library/conf/env"
"go-common/library/log"
"os"
"strconv"
"github.com/pkg/errors"
)
var (
hostHashIndex int64
autoIncreaseID int64
)
// Service struct
type Service struct {
c *conf.Config
BPSCode map[string]int
dao *dao.Dao
topicClient topic.TopicClient
}
func init() {
hostName, err := os.Hostname()
if err != nil {
errors.Wrap(err, "获取hostname失败")
panic(err)
}
data := []byte(hostName)
hash := fmt.Sprintf("%x", md5.Sum(data))
log.Infov(context.Background(), log.KV("log", "md5="+hash))
truncateHash := hash[0:8]
index, err := strconv.ParseInt(truncateHash, 16, 0)
if err != nil {
errors.Wrap(err, "解析MD5->int64失败")
panic(err)
}
hostHashIndex = index % 1000
log.Infov(context.Background(), log.KV("log", fmt.Sprintf("hostname hash index=%03d", hostHashIndex)))
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
}
s.dao.HostnameRegister(hostHashIndex)
if env.DeployEnv == env.DeployEnvProd {
go s.archiveSub(context.Background())
}
var err error
if s.topicClient, err = topic.NewClient(nil); err != nil {
log.Errorw(context.Background(), "log", "get topic client fail")
panic(err)
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
s.archiveSubClose()
}

View File

@@ -0,0 +1,46 @@
package service
import (
"context"
"flag"
"go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/conf"
"os"
"testing"
)
var (
s *Service
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/")
flag.Set("conf_name", "test.toml")
flag.Set("deploy.env", "uat")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
conf.Conf.Log.Stdout = false
s = New(conf.Conf)
os.Exit(m.Run())
}
func BenchmarkService_CreateID(b *testing.B) {
req := &v1.CreateIDRequest{Mid: 3}
for i := 0; i < b.N; i++ {
s.CreateID(context.Background(), req)
}
}

View File

@@ -0,0 +1,161 @@
package service
import (
"context"
"crypto/md5"
"fmt"
topic_v1 "go-common/app/service/bbq/topic/api"
video_v1 "go-common/app/service/bbq/video/api/grpc/v1"
"go-common/app/service/bbq/video/model"
"go-common/library/ecode"
"go-common/library/log"
"io"
"net/url"
"strconv"
"time"
"github.com/golang/protobuf/ptypes/empty"
)
//PreUpload ...
func (s *Service) PreUpload(c context.Context, req *video_v1.PreUploadRequest) (rep *video_v1.PreUploadResponse, err error) {
var (
p *video_v1.CreateIDResponse
m *model.VideoRepository
)
r := &video_v1.CreateIDRequest{
Mid: req.Mid,
}
if p, err = s.CreateID(c, r); err != nil {
log.Errorw(c, "event", "CreateID err:", "err", err)
return
}
//new topic
tp := &topic_v1.VideoExtension{
Svid: p.NewId,
Extension: req.Entension,
}
if _, err = s.topicClient.Register(c, tp); err != nil {
log.Errorw(c, "event", "s.topicClient.Register err", "err", err)
return
}
m = &model.VideoRepository{
SVID: p.NewId,
From: req.From,
Title: req.Title,
MID: req.Mid,
SyncStatus: model.SourceRequest,
}
if err = s.dao.InsertVR(c, m); err != nil {
log.Warnw(c, "event", "s.dao.InsertVR err", "err", err)
return
}
fn := s.getFileName(p.NewId)
rep = &video_v1.PreUploadResponse{
Svid: p.NewId,
UposUri: "upos://bbq/" + fn + "." + req.FileExt,
EndPoint: s.c.Upload.Endpoint.Main,
EndPoints: []string{s.c.Upload.Endpoint.Main, s.c.Upload.Endpoint.BackUp},
Auth: s.getAuth(fn, req.FileExt),
}
return
}
func (s *Service) getAuth(fileName string, fileExt string) (auth string) {
var (
url = url.Values{}
h = md5.New()
md5key string
t string
sign string
)
t = strconv.FormatInt(time.Now().Unix(), 10)
md5key = s.c.Upload.Auth.AK + t + "/bbq/" + fileName + "." + fileExt + s.c.Upload.Auth.SK
io.WriteString(h, md5key)
sign = fmt.Sprintf("%x", h.Sum(nil))
url.Add("ak", s.c.Upload.Auth.AK)
url.Add("timestamp", t)
url.Add("sign", sign)
return url.Encode()
}
func (s *Service) getFileName(svid int64) (fn string) {
fn = fmt.Sprintf("%s%6s%2s%23s",
s.c.Upload.File.Prefix,
time.Now().Format("060102"),
s.c.Upload.File.Line,
"svid"+strconv.FormatInt(svid, 10),
)
return
}
//CallBack upload call back function
func (s *Service) CallBack(c context.Context, req *video_v1.CallBackRequest) (res *empty.Empty, err error) {
res = new(empty.Empty)
var (
pvr *model.VideoRepository
pvup *model.VideoUploadProcess
rvr *model.VideoRepository
)
pvr = &model.VideoRepository{
SVID: req.Svid,
SyncStatus: model.SourceRequest,
}
if rvr, err = s.dao.QueryVR(c, pvr); err != nil {
log.Warnw(c, "event", "s.dao.QueryVR err", "err", err)
return
}
//callback legality verification
if req.Mid != rvr.MID {
err = ecode.UploadFailed
return
}
pvup = &model.VideoUploadProcess{
SVID: req.Svid,
Title: rvr.Title,
Mid: rvr.MID,
UploadStatus: model.UploadStatusWaiting,
RetryTimes: 0,
HomeImgURL: rvr.HomeImgURL,
HomeImgWidth: rvr.HomeImgWidth,
HomeImgHeight: rvr.HomeImgHeight,
}
if err = s.dao.InsertOrUpdateVUP(c, pvup); err != nil {
log.Warnw(c, "event", "s.dao.InsertOrUpdateVUP", "err", err)
return
}
//ignore update result
s.dao.UpdateVR(c, pvr)
return
}
// ListPrepareVideo 获取prepare视频
func (s *Service) ListPrepareVideo(c context.Context, req *video_v1.PrepareVideoRequest) (res *video_v1.PrepareVideoResponse, err error) {
res = new(video_v1.PrepareVideoResponse)
list, err := s.dao.GetPrepareVUP(c, req.Mid)
if err != nil {
log.Warnw(c, "log", "get prepare vup fail", "mid", req.Mid)
return
}
res.List = list
return
}
//HomeImgCreate ..
func (s *Service) HomeImgCreate(c context.Context, req *video_v1.HomeImgCreateRequest) (res *empty.Empty, err error) {
res = new(empty.Empty)
p := &model.VideoRepository{
SVID: req.Svid,
MID: req.Mid,
HomeImgHeight: req.Height,
HomeImgURL: req.Url,
HomeImgWidth: req.Width,
}
if err = s.dao.HomeImgCreate(c, p); err != nil {
return
}
return
}

View File

@@ -0,0 +1,276 @@
package service
import (
"context"
"fmt"
v1 "go-common/app/service/bbq/video/api/grpc/v1"
httpV1 "go-common/app/service/bbq/video/api/http/v1"
"go-common/app/service/bbq/video/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"sync/atomic"
"time"
"github.com/golang/protobuf/ptypes/empty"
)
// ModifyLimits .
func (s *Service) ModifyLimits(c context.Context, args *v1.ModifyLimitsRequest) (response *v1.ModifyLimitsResponse, err error) {
response = new(v1.ModifyLimitsResponse)
_, err = s.dao.ModifyLimits(c, args.Svid, args.LimitType, args.LimitOp)
if err != nil {
log.Warnw(c, "log", "modify limits fail", "args", args.String())
return
}
return
}
// ListVideoInfo 视频信息列表.
func (s *Service) ListVideoInfo(ctx context.Context, v *v1.ListVideoInfoRequest) (res *v1.ListVideoInfoResponse, err error) {
res = new(v1.ListVideoInfoResponse)
videoBases, err := s.dao.VideoBase(ctx, v.SvIDs)
if err != nil {
log.Errorw(ctx, "log", "batch get video base fail")
return
}
for _, videoBase := range videoBases {
res.List = append(res.List, &v1.VideoInfo{VideoBase: videoBase})
}
return
}
// ImportVideo 导入视频服务.
func (s *Service) ImportVideo(ctx context.Context, v *v1.ImportVideoInfo) (res *empty.Empty, err error) {
res = &empty.Empty{}
err = s.dao.AddOrUpdateVideo(ctx, v)
return
}
// SyncTag 同步标签.
func (s *Service) SyncTag(ctx context.Context, v *v1.SyncVideoTagRequest) (res *empty.Empty, err error) {
res = &empty.Empty{}
_, err = s.dao.AddOrUpdateTag(ctx, v.TagInfos)
return
}
//SvStatisticsInfo ...
func (s *Service) SvStatisticsInfo(ctx context.Context, v *v1.SvStatisticsInfoReq) (res *v1.SvStatisticsInfoRes, err error) {
res = new(v1.SvStatisticsInfoRes)
res.SvstInfoMap = make(map[int64]*v1.SvStInfo)
if v.SvidList == nil || len(v.SvidList) <= 0 {
return
}
var data map[int64]*model.SvStInfo
data, err = s.dao.RawVideoStatistic(ctx, v.SvidList)
for svid, st := range data {
res.SvstInfoMap[svid] = &v1.SvStInfo{
Like: st.Like,
Play: st.Play,
Report: st.Report,
Share: st.Share,
Subtitles: st.Subtitles,
Reply: st.Reply,
Svid: svid,
}
}
return
}
//SyncUserBase 更新userbase
func (s *Service) SyncUserBase(ctx context.Context, req *v1.SyncMidRequset) (res *v1.SyncUserBaseResponse, err error) {
res, err = s.dao.InOrUpUserBase(ctx, req.MID)
return
}
//SyncUserSta 更新user_statistics_hive
func (s *Service) SyncUserSta(ctx context.Context, req *v1.SyncMidRequset) (res *v1.SyncUserBaseResponse, err error) {
res, err = s.dao.InOrUpUserSta(ctx, req.MID)
return
}
//SyncUserBases 批量更新userbase
func (s *Service) SyncUserBases(ctx context.Context, req *v1.SyncMidsRequset) (res *v1.SyncUserBaseResponse, err error) {
res, err = s.dao.InOrUpUserBases(ctx, req.MIDS)
return
}
//SyncUserStas 批量更新user_statistics_hive
func (s *Service) SyncUserStas(ctx context.Context, req *v1.SyncMidsRequset) (res *v1.SyncUserBaseResponse, err error) {
res, err = s.dao.InOrUpUserStas(ctx, req.MIDS)
return
}
// BVCTransRes 处理BVC回调服务
func (s *Service) BVCTransRes(ctx context.Context, req *v1.BVCTransBackRequset) (err error) {
//记录回调日志
err = s.dao.AddOrUpdateFlowRecord(ctx, &model.BVCRecord{
FLowID: req.FlowID,
SVID: req.SVID,
Type: req.FlowType,
})
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("AddFlowRecord err[%v]", err)))
err = ecode.SyncBVCFail
return
}
//失败回调直接返回
if req.FlowType < 0 {
log.Warn("BVCTrans fail [%+v]", req)
return nil
}
tx, err := s.dao.BeginTran(ctx)
if err != nil {
return
}
if req.PIC.PicURL == "" || req.PIC.PicHeight == 0 || req.PIC.PicWidth == 0 {
log.Warn("图片参数缺失 pic[%+v]", req.PIC)
err = ecode.ReqParamErr
return
}
err = s.dao.UpdateCmsSvPIC(ctx, req.SVID, req.PIC, model.SourceXcodeCover)
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("UpdateSvPIC err[%v]", err)))
return
}
stratAt := time.Now()
wg := &errgroup.Group{}
for i := range req.TransRes {
wg.Go(func(i int) func() error {
return func() error {
d := req.TransRes[i]
var bcode int64
if _, ok := s.c.BPSCode[d.PPI]; ok {
if codeRate, ok := s.c.BPSCode[d.PPI][d.BPS]; ok {
bcode = int64(codeRate)
}
}
if bcode == 0 {
return ecode.UnKnownBPS
}
data := &model.VideoBVC{
SVID: req.SVID,
Path: d.Path,
CodeRate: bcode,
ResolutionRetio: d.PPI,
VideoCode: d.VideoCode,
Duration: d.Duration,
FileSize: d.Filesize,
}
err = s.dao.TxAddOrUpdateBVCInfo(ctx, tx, data)
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("TxAddOrUpdateBVCInfo err[%v]", err)))
}
return err
}
}(i))
}
//统一回滚
if err = wg.Wait(); err != nil {
tx.Rollback()
log.Errorv(ctx, log.KV("log", fmt.Sprintf("ErrorGroup err[%v]", err)))
return
}
//统一提交事务
if err = tx.Commit(); err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("Tx err[%v]", err)))
err = ecode.SyncBVCFail
return
}
elapsed := time.Since(stratAt)
log.Infov(ctx,
log.KV("log", fmt.Sprintf("BVCTransRes Sync Complete, cost[%s]", elapsed)))
err = s.dao.CmsPub(ctx, &model.DataTopicCmsData{SVID: req.SVID})
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("CmsPub Fail:[%v]", err)))
}
return
}
// BVCTransCommit 提交转码
func (s *Service) BVCTransCommit(ctx context.Context, req *v1.BVideoTransRequset) (*empty.Empty, error) {
err := s.dao.CommitTrans(ctx, req)
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("CommitTrans err[%v] data[%+v]", err, req)))
}
return &empty.Empty{}, err
}
//CheckVideoUploadSt upload video to client
func (s *Service) CheckVideoUploadSt(c context.Context, SVID int64) (err error) {
err = s.dao.CheckSVResource(c, SVID)
return
}
// CreateID 创建新ID
// 按十进制计算
// 63个1=9223372036854775807共19位
// 时间戳取32个1=4294967295共10位且最高位4小于9
// mid%1000共3位
// 机器标志3位
// 自增2位
// 保留1位
func (s *Service) CreateID(ctx context.Context, req *v1.CreateIDRequest) (res *v1.CreateIDResponse, err error) {
res = new(v1.CreateIDResponse)
mid := req.Mid
if mid == 0 {
err = ecode.ReqParamErr
return
}
timestamp := time.Now().Unix()
if req.Time > 0xFFFFFFFF {
err = ecode.ReqParamErr
return
}
if req.Time != 0 {
timestamp = req.Time
}
// 十进制19位的分配情况
// 10 |1 |3 |2 |3
// ts |reserved|host|index|mid
increaseID := atomic.AddInt64(&autoIncreaseID, 1)
newIndex := increaseID % 100
midInfo := mid % 1000
res.NewId = (timestamp * 1000000000) + (hostHashIndex * 100000) + (newIndex * 1000) + midInfo
log.Infov(ctx, log.KV("log",
fmt.Sprintf("create one new id: new_id=%d, timestamp=%d, increase_id=%d, mid=%d",
res.NewId, timestamp, increaseID, mid)))
return
}
// VideoViewsAdd .
func (s *Service) VideoViewsAdd(c context.Context, args *httpV1.ViewsAddRequest) (response *httpV1.ViewsAddResponse, err error) {
response = new(httpV1.ViewsAddResponse)
affected, err := s.dao.AddVideoViews(c, args.Svid, args.Views)
response.Affected = affected
return
}
// VideoUnshelf .
func (s *Service) VideoUnshelf(ctx context.Context, in *v1.VideoUnshelfRequest) (*empty.Empty, error) {
newState := model.VideoUnshelf
if _, err := s.dao.VideoStateUpdate(ctx, in.Svid, newState); err != nil {
return nil, err
}
return new(empty.Empty), nil
}
// VideoDelete .
func (s *Service) VideoDelete(ctx context.Context, in *v1.VideoDeleteRequest) (*empty.Empty, error) {
videoBase, err := s.dao.RawVideoBase(ctx, []int64{in.Svid})
if err != nil {
return nil, err
}
if v, ok := videoBase[in.Svid]; !ok || v.Mid != in.UpMid {
return nil, ecode.VideoDelFail
}
newState := model.VideoDelete
if _, err := s.dao.VideoStateUpdate(ctx, in.Svid, newState); err != nil {
return nil, err
}
return new(empty.Empty), nil
}