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,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
}