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,83 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["user_like_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = ["//app/interface/bbq/app-bbq/conf:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"app.go",
"comment.go",
"danmu.go",
"dao.go",
"feed.go",
"filter.go",
"image.go",
"location.go",
"notice.go",
"push.go",
"redundance.go",
"report.go",
"search.go",
"share.go",
"sv.go",
"sv_stat.go",
"upload.go",
"user.go",
"user_like.go",
"user_relation.go",
"video.go",
],
importpath = "go-common/app/interface/bbq/app-bbq/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/bbq/app-bbq/api/http/v1:go_default_library",
"//app/interface/bbq/app-bbq/conf:go_default_library",
"//app/interface/bbq/app-bbq/model:go_default_library",
"//app/interface/bbq/app-bbq/model/grpc:go_default_library",
"//app/service/bbq/common:go_default_library",
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//app/service/bbq/recsys/api/grpc/v1:go_default_library",
"//app/service/bbq/user/api:go_default_library",
"//app/service/bbq/video-image/api/grpc/v1:go_default_library",
"//app/service/bbq/video/api/grpc/v1:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/filter/api/grpc/v1:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/json-iterator/go: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,58 @@
package dao
import (
"context"
"time"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/database/sql"
)
const (
_queryNewAppVersion = "select `id`, `platform`, `ver_name`, `ver_code`, `title`, `content`, `download`, `md5`, `size`, `force`, `status` from `app_package` where platform = ? and ver_code > ? and status = 1 order by ver_code desc;"
_queryAppPackage = "select `id`, `platform`, `ver_name`, `ver_code`, `title`, `content`, `download`, `md5`, `size`, `force`, `status`, `ctime` from `app_package` where status>0;"
_queryAppResource = "select `id`, `platform`, `name`, `version`, `md5`, `download`, `status`, `start_time`, `end_time` from `app_resource` where `platform` in (0, ?) and `version` = ? and `status` = ? and `end_time` > ?;"
)
// FetchNewAppVersion .
func (d *Dao) FetchNewAppVersion(c context.Context, platform int, vCode int) (result *model.AppVersion, err error) {
result = &model.AppVersion{}
err = d.db.QueryRow(c, _queryNewAppVersion, platform, vCode).Scan(&result.ID, &result.Platform, &result.Name, &result.Code, &result.Title, &result.Content, &result.Download, &result.MD5, &result.Size, &result.Force, &result.Status)
if err == sql.ErrNoRows {
err = nil
}
return
}
// FetchAppPackage .
func (d *Dao) FetchAppPackage(c context.Context) (result []*v1.AppPackage, err error) {
rows, err := d.db.Query(c, _queryAppPackage)
for rows.Next() {
tmp := &v1.AppPackage{}
err = rows.Scan(&tmp.ID, &tmp.Platform, &tmp.VersionName, &tmp.VersionCode, &tmp.Title, &tmp.Content, &tmp.Download, &tmp.MD5, &tmp.Size, &tmp.Force, &tmp.Status, &tmp.CTime)
if err != nil {
continue
}
result = append(result, tmp)
}
return
}
// FetchAppResource .
func (d *Dao) FetchAppResource(c context.Context, plat int, ver int) (result []*model.AppResource, err error) {
result = make([]*model.AppResource, 0)
rows, err := d.db.Query(c, _queryAppResource, plat, ver, 1, time.Now().Format("2006-01-02 15:04:05"))
if err != nil {
return
}
for rows.Next() {
tmp := new(model.AppResource)
err = rows.Scan(&tmp.ID, &tmp.Platform, &tmp.Name, &tmp.Code, &tmp.MD5, &tmp.Download, &tmp.Status, &tmp.StartTime, &tmp.EndTime)
if err != nil {
continue
}
result = append(result, tmp)
}
return
}

View File

@@ -0,0 +1,425 @@
package dao
import (
"bytes"
"context"
"fmt"
"strconv"
"strings"
"go-common/app/interface/bbq/app-bbq/model"
user "go-common/app/service/bbq/user/api"
"go-common/library/log"
"go-common/library/net/metadata"
"github.com/json-iterator/go"
)
// ReplySubCursor http请求子评论游标获取评论
func (d *Dao) ReplySubCursor(c context.Context, req map[string]interface{}) (res *model.SubCursorRes, err error) {
var r []byte
ip := metadata.String(c, metadata.RemoteIP)
res = new(model.SubCursorRes)
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_subcursor"], "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)
// err = json.Unmarshal(r, &res)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("json unmarlshal err data[%s]", string(r))))
return
}
//获取所有mid
var mid []int64
if res.Root != nil {
mid = append(mid, res.Root.Mid)
}
if res.Root.Replies != nil {
mid = append(mid, d.getMidInReplys(res.Root.Replies)...)
}
//批量获取userinfo
var userinfo map[int64]*user.UserBase
userinfo, err = d.JustGetUserBase(c, mid)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("d.UserBase err[%v]", err)))
return
}
if res.Root != nil {
d.replaceMemberInReply(res.Root, userinfo)
}
return
}
// ReplyCursor http请求游标获取评论
func (d *Dao) ReplyCursor(c context.Context, req map[string]interface{}) (res *model.CursorRes, err error) {
var r []byte
ip := metadata.String(c, metadata.RemoteIP)
res = new(model.CursorRes)
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_cursor"], "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
}
//获取所有mid
var mid []int64
if res.Replies != nil {
mid = append(mid, d.getMidInReplys(res.Replies)...)
}
if res.Hots != nil {
mid = append(mid, d.getMidInReplys(res.Hots)...)
}
if res.Top != nil {
if res.Top.Admin != nil {
mid = append(mid, res.Top.Admin.Mid)
}
if res.Top.Upper != nil {
mid = append(mid, res.Top.Upper.Mid)
}
}
//批量获取userinfo
var userinfo map[int64]*user.UserBase
userinfo, err = d.JustGetUserBase(c, mid)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("d.UserBase err[%v]", err)))
return
}
if res.Replies != nil {
d.replaceMemberInReplys(res.Replies, userinfo)
}
if res.Hots != nil {
d.replaceMemberInReplys(res.Hots, userinfo)
}
if res.Top != nil {
if res.Top.Admin != nil {
d.replaceMemberInReplys(res.Top.Admin.Replies, userinfo)
}
if res.Top.Upper != nil {
d.replaceMemberInReplys(res.Top.Upper.Replies, userinfo)
}
}
return
}
// getMidInReplys 批量获取评论列表中mid
func (d *Dao) getMidInReplys(r []*model.Reply) (l []int64) {
for _, v := range r {
l = append(l, v.Mid)
for _, c := range v.Content.Members {
cmid, err := strconv.ParseInt(c.Mid, 10, 64)
if err != nil {
log.Errorv(
context.Background(),
log.KV("log", fmt.Sprintf("strconv err [%v] data[%s]", err, c.Mid)),
)
continue
}
l = append(l, cmid)
}
if len(v.Replies) > 0 {
sl := d.getMidInReplys(v.Replies)
l = append(l, sl...)
}
}
return
}
// replaceMemberInReplys 批量替换评论列表中用户信息
func (d *Dao) replaceMemberInReplys(r []*model.Reply, umap map[int64]*user.UserBase) {
for _, v := range r {
if u, ok := umap[v.Mid]; ok {
v.Member.BInfo = u
} else {
v.Member.BInfo = new(user.UserBase)
v.Member.BInfo.Mid = v.Mid
v.Member.BInfo.Uname = v.Member.Name
v.Member.BInfo.Face = v.Member.Avatar
}
for _, c := range v.Content.Members {
cmid, err := strconv.ParseInt(c.Mid, 10, 64)
if err != nil {
log.Errorv(
context.Background(),
log.KV("log", fmt.Sprintf("strconv err [%v] data[%s]", err, c.Mid)),
)
continue
}
if u, ok := umap[cmid]; ok {
c.BInfo = u
} else {
c.BInfo = new(user.UserBase)
c.BInfo.Mid = cmid
c.BInfo.Uname = c.Name
c.BInfo.Face = c.Avatar
}
}
if len(v.Replies) > 0 {
d.replaceMemberInReplys(v.Replies, umap)
}
}
}
// replaceMemberInReply 替换评论中用户信息
func (d *Dao) replaceMemberInReply(r *model.Reply, umap map[int64]*user.UserBase) {
if u, ok := umap[r.Mid]; ok {
r.Member.BInfo = u
} else {
r.Member.BInfo = new(user.UserBase)
r.Member.BInfo.Mid = r.Mid
r.Member.BInfo.Uname = r.Member.Name
r.Member.BInfo.Face = r.Member.Avatar
}
for _, c := range r.Content.Members {
cmid, err := strconv.ParseInt(c.Mid, 10, 64)
if err != nil {
log.Errorv(
context.Background(),
log.KV("log", fmt.Sprintf("strconv err [%v] data[%s]", err, c.Mid)),
)
continue
}
if u, ok := umap[cmid]; ok {
c.BInfo = u
} else {
c.BInfo = new(user.UserBase)
c.BInfo.Mid = cmid
c.BInfo.Uname = c.Name
c.BInfo.Face = c.Avatar
}
}
if len(r.Replies) > 0 {
d.replaceMemberInReplys(r.Replies, umap)
}
}
// ReplyAdd http请求添加评论
func (d *Dao) ReplyAdd(c context.Context, req map[string]interface{}) (res *model.AddRes, err error) {
ip := metadata.String(c, metadata.RemoteIP)
res = new(model.AddRes)
var r []byte
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_add"], "POST", req, ip)
if err != nil {
log.Infov(c,
log.KV("log", fmt.Sprintf("replyHTTPCommon err [%v]", err)),
)
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Unmarshal(r, &res)
return
}
//ReplyLike http请求评论点赞
func (d *Dao) ReplyLike(c context.Context, req map[string]interface{}) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
_, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_like"], "POST", req, ip)
return
}
// ReplyList 评论列表
func (d *Dao) ReplyList(c context.Context, req map[string]interface{}) (res *model.ReplyList, err error) {
ip := metadata.String(c, metadata.RemoteIP)
res = new(model.ReplyList)
var r []byte
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_list"], "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
}
//获取所有mid
var mid []int64
if res.Replies != nil {
mid = append(mid, d.getMidInReplys(res.Replies)...)
}
if res.Hots != nil {
mid = append(mid, d.getMidInReplys(res.Hots)...)
}
if res.Top != nil {
mid = append(mid, res.Top.Mid)
}
//批量获取userinfo
var userinfo map[int64]*user.UserBase
userinfo, err = d.JustGetUserBase(c, mid)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("d.UserBase err[%v]", err)))
return
}
if res.Replies != nil {
d.replaceMemberInReplys(res.Replies, userinfo)
}
if res.Hots != nil {
d.replaceMemberInReplys(res.Hots, userinfo)
}
if res.Top != nil {
d.replaceMemberInReplys(res.Top.Replies, userinfo)
}
return
}
// ReplyReport 评论举报
func (d *Dao) ReplyReport(c context.Context, req map[string]interface{}) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
_, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_report"], "POST", req, ip)
return
}
// 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
}
// ReplyMinfo 批量请求评论
func (d *Dao) ReplyMinfo(c context.Context, svID int64, rpids []int64) (res map[int64]*model.Reply, err error) {
res = make(map[int64]*model.Reply)
if len(rpids) == 0 {
return
}
ip := metadata.String(c, metadata.RemoteIP)
var rpidStr string
for _, rpid := range rpids {
if len(rpidStr) != 0 {
rpidStr += fmt.Sprintf(",%d", rpid)
} else {
rpidStr += fmt.Sprintf("%d", rpid)
}
}
log.V(1).Infov(c, log.KV("log", "reply minfo: rpids="+rpidStr))
req := map[string]interface{}{
"type": model.DefaultCmType,
"oid": svID,
"rpid": rpidStr,
}
var r []byte
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_minfo"], "GET", req, ip)
if err != nil {
log.Errorv(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))))
}
log.V(1).Infov(c, log.KV("log", "get reply minfo"), log.KV("req_size", len(rpids)), log.KV("rsp_size", len(res)))
return
}
// ReplyHot 获取批量热评
func (d *Dao) ReplyHot(c context.Context, mid int64, oids []int64) (res map[int64][]*model.Reply, err error) {
res = make(map[int64][]*model.Reply)
if len(oids) == 0 {
return
}
ip := metadata.String(c, metadata.RemoteIP)
var oidStr string
for _, oid := range oids {
if len(oidStr) != 0 {
oidStr += fmt.Sprintf(",%d", oid)
} else {
oidStr += fmt.Sprintf("%d", oid)
}
}
log.V(1).Infov(c, log.KV("log", "reply minfo: oids="+oidStr))
req := map[string]interface{}{
"type": model.DefaultCmType,
"oids": oidStr,
"mid": mid,
}
var r []byte
r, err = replyHTTPCommon(c, d.httpClient, d.c.URLs["reply_hots"], "GET", req, ip)
if err != nil {
log.Errorv(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))))
}
log.V(1).Infov(c, log.KV("log", "get reply hots"), log.KV("req_size", len(oids)), log.KV("rsp_size", len(res)))
// 替换bbq的用户信息
var mIDs []int64
for _, replies := range res {
for _, reply := range replies {
mIDs = append(mIDs, reply.Mid)
}
}
var userBases map[int64]*user.UserBase
userBases, err = d.JustGetUserBase(c, mIDs)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("d.UserBase err[%v]", err)))
return
}
for _, replies := range res {
if len(replies) > 0 {
d.replaceMemberInReplys(replies, userBases)
}
}
return
}

View File

@@ -0,0 +1,21 @@
package dao
import (
"context"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/log"
)
const (
_queryDanmu = "select oid,mid,offset,content from bullet_content where id = ?"
)
//RawBullet ...
func (d *Dao) RawBullet(ctx context.Context, danmu int64) (v *model.Danmu, err error) {
v = new(model.Danmu)
if err = d.dbDM.QueryRow(ctx, _queryDanmu, danmu).Scan(&v.OID, &v.MID, &v.Offset, &v.Content); err != nil {
log.Errorw(ctx, "content", "query danmu", "err", err, "danmu id", danmu)
return
}
return
}

View File

@@ -0,0 +1,218 @@
package dao
import (
"context"
"encoding/json"
"flag"
"fmt"
"go-common/library/sync/pipeline/fanout"
"net/url"
"reflect"
"strconv"
"go-common/app/interface/bbq/app-bbq/conf"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/app/interface/bbq/app-bbq/model/grpc"
notice "go-common/app/service/bbq/notice-service/api/v1"
recsys "go-common/app/service/bbq/recsys/api/grpc/v1"
user "go-common/app/service/bbq/user/api"
image "go-common/app/service/bbq/video-image/api/grpc/v1"
video "go-common/app/service/bbq/video/api/grpc/v1"
acc "go-common/app/service/main/account/api"
filter "go-common/app/service/main/filter/api/grpc/v1"
"go-common/library/cache/redis"
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"
jsoniter "github.com/json-iterator/go"
)
var (
videoPath string
)
// Dao dao
type Dao struct {
c *conf.Config
cache *fanout.Fanout
redis *redis.Pool
db *xsql.DB
dbDM *xsql.DB
httpClient *bm.Client
httpslowClient *bm.Client
accountClient acc.AccountClient
recsysClient recsys.RecsysClient
imageClient image.VideoImageClient
bvcPlayClient grpc.PlayurlServiceClient
redundanceVideos []*model.RVideo
noticeClient notice.NoticeClient
userClient user.UserClient
videoClient video.VideoClient
filterClient filter.FilterClient
}
func init() {
flag.StringVar(&videoPath, "video_json", "./video.json", "接口冗余降级video数据")
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
redis: redis.NewPool(c.Redis),
db: xsql.NewMySQL(c.MySQL),
dbDM: xsql.NewMySQL(c.DMMySQL),
httpClient: bm.NewClient(c.HTTPClient.Normal),
httpslowClient: bm.NewClient(c.HTTPClient.Slow),
accountClient: newAccountClient(c.GRPCClient["account"]),
recsysClient: newRecsysClient(c.GRPCClient["recsys"]),
imageClient: newVideoImageClient(c.GRPCClient["videoimage"]),
bvcPlayClient: newBVCPlayClient(c.GRPCClient["bvcplay"]),
redundanceVideos: model.RedundanceVideo(),
noticeClient: newNoticeClient(c.GRPCClient["notice"]),
userClient: newUserClient(c.GRPCClient["user"]),
videoClient: newVideoClient(c.GRPCClient["video"]),
filterClient: newFilterClient(c.GRPCClient["filter"]),
}
return
}
// newVideoClient .
func newVideoClient(cfg *conf.GRPCConf) video.VideoClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return video.NewVideoClient(cc)
}
// newUserClient .
func newUserClient(cfg *conf.GRPCConf) user.UserClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return user.NewUserClient(cc)
}
// newNoticeClient .
func newNoticeClient(cfg *conf.GRPCConf) notice.NoticeClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return notice.NewNoticeClient(cc)
}
// 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)
}
// newVideoImageClient .
func newVideoImageClient(cfg *conf.GRPCConf) image.VideoImageClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return image.NewVideoImageClient(cc)
}
//newAccountClient .
func newAccountClient(cfg *conf.GRPCConf) acc.AccountClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return acc.NewAccountClient(cc)
}
//newRecsysClient .
func newRecsysClient(cfg *conf.GRPCConf) recsys.RecsysClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return recsys.NewRecsysClient(cc)
}
// newUserClient .
func newFilterClient(cfg *conf.GRPCConf) filter.FilterClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return filter.NewFilterClient(cc)
}
// 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,102 @@
package dao
import (
"context"
"fmt"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/cache/redis"
"go-common/library/time"
"go-common/library/xstr"
"strconv"
"go-common/library/log"
)
// FetchAvailableOutboxList 根据提供的up主mids去获取比lastSvID还小的svid
// @param CursorID 函数并不判断SvID正确性由调用方保证
// @param cursorNext 表明fetch的方向同时会影响排序顺序
// true 则有如下条件sql"... and id < {{svid}} order by id desc..."
// false 则有如下条件sql"... and id > {{svid}} order by id asc..."
// @return svIDs 注意svid的返回有顺序
func (d *Dao) FetchAvailableOutboxList(c context.Context, fetchStates string, mids []int64, cursorNext bool, cursorSvID int64, cursorPubtime time.Time, size int) (svIDs []int64, err error) {
if len(mids) == 0 {
return
}
compareSymbol := string(">=")
orderDirection := "asc"
if cursorNext {
compareSymbol = "<="
orderDirection = "desc"
}
midStr := xstr.JoinInts(mids)
// 多个字段order by每个字段都要指定desc否则不带的字段为asc
querySQL := fmt.Sprintf("select svid, pubtime from video where mid in (%s) and state in (%s) and "+
"pubtime %s ? order by pubtime %s, svid %s limit %d",
midStr, fetchStates, compareSymbol, orderDirection, orderDirection, size)
log.V(1).Infov(c, log.KV("event", "mysql_select"), log.KV("table", "video"),
log.KV("sql", querySQL))
rows, err := d.db.Query(c, querySQL, cursorPubtime)
if err != nil {
log.Errorv(c, log.KV("event", "mysql_select"), log.KV("table", "video"),
log.KV("sql", querySQL))
return
}
defer rows.Close()
var svID int64
var pubTIme time.Time
conflict := bool(true)
for rows.Next() {
if err = rows.Scan(&svID, &pubTIme); err != nil {
log.Errorv(c, log.KV("event", "mysql_scan"), log.KV("table", "video"),
log.KV("sql", querySQL))
return
}
// 为了解决同一个pubtime的冲突问题
if pubTIme == cursorPubtime && conflict {
if svID == cursorSvID {
conflict = false
}
continue
}
svIDs = append(svIDs, svID)
}
log.Infov(c, log.KV("event", "mysql_select"), log.KV("table", "video"),
log.KV("desc", "fetch outbox"), log.KV("size", len(svIDs)))
return
}
// SetMIDLastPubtime redis设置
func (d *Dao) SetMIDLastPubtime(c context.Context, mid int64, pubtime int64) (err error) {
key := fmt.Sprintf(model.CacheKeyLastPubtime, mid)
conn := d.redis.Get(c)
defer conn.Close()
_, err = conn.Do("set", key, pubtime, "ex", model.CacheExpireLastPubtime)
if err != nil {
log.Errorv(c, log.KV("event", "redis_set"), log.KV("key", key), log.KV("value", pubtime))
}
return
}
// GetMIDLastPubtime 获取该用户feed中的最新浏览svid
func (d *Dao) GetMIDLastPubtime(c context.Context, mid int64) (pubtime int64, err error) {
pubtime = 0
key := fmt.Sprintf(model.CacheKeyLastPubtime, mid)
conn := d.redis.Get(c)
defer conn.Close()
var data []byte
if data, err = redis.Bytes(conn.Do("get", key)); err != nil {
if err == redis.ErrNil {
err = nil
log.V(1).Infov(c, log.KV("event", "redis_get"), log.KV("key", key), log.KV("result", "not_found"))
} else {
log.Errorv(c, log.KV("event", "redis_get"), log.KV("key", key))
}
return
}
pubtime, err = strconv.ParseInt(string(data), 10, 0)
if err != nil {
log.Errorv(c, log.KV("event", "redis_get"), log.KV("key", key), log.KV("value", data))
}
return
}

View File

@@ -0,0 +1,33 @@
package dao
import (
"context"
filter "go-common/app/service/main/filter/api/grpc/v1"
"go-common/library/log"
)
// 用于filter
const (
FilterAreaAccount = "BBQ_account"
FilterAreaVideo = "BBQ_video"
FilterAreaReply = "BBQ_reply"
FilterAreaSearch = "BBQ_search"
FilterAreaDanmu = "BBQ_danmu"
FilterLevel = 20
)
// Filter .
func (d *Dao) Filter(ctx context.Context, content string, area string) (level int32, err error) {
req := new(filter.FilterReq)
req.Message = content
req.Area = area
reply, err := d.filterClient.Filter(ctx, req)
if err != nil {
log.Errorv(ctx, log.KV("log", "filter fail : req="+req.String()))
return
}
level = reply.Level
log.V(1).Infov(ctx, log.KV("log", "get filter reply="+reply.String()))
return
}

View File

@@ -0,0 +1,25 @@
package dao
import (
"context"
image "go-common/app/service/bbq/video-image/api/grpc/v1"
"go-common/library/log"
)
//Upload .
func (d *Dao) Upload(c context.Context, fileName string, filePath string, file []byte) (location string, err error) {
imageReq := &image.ImgUploadRequest{
Filename: fileName,
Dir: filePath,
File: file,
}
imageRes, err := d.imageClient.ImgUpload(c, imageReq)
if err != nil {
log.Errorv(c, log.KV("event", "grpc/imageupload"), log.KV("err", err))
return
}
if imageRes != nil {
location = imageRes.Location
}
return
}

View File

@@ -0,0 +1,57 @@
package dao
import (
"context"
"go-common/app/interface/bbq/app-bbq/model"
)
var (
locationQueryChild = "select `loc_id`, `pid`, `name` from `bbq_location` where `pid` = ?;"
locationQueryAll = "select `loc_id`, `pid`, `name` from `bbq_location`;"
)
// GetLocationAll .
func (d *Dao) GetLocationAll(c context.Context) (*map[int32][]*model.Location, error) {
rows, err := d.db.Query(c, locationQueryAll)
if err != nil {
return nil, err
}
defer rows.Close()
m := make(map[int32][]*model.Location)
var id, pid int32
var name string
for rows.Next() {
rows.Scan(&id, &pid, &name)
m[pid] = append(m[pid], &model.Location{
ID: id,
PID: pid,
Name: name,
})
}
return &m, err
}
// GetLocationChild .
func (d *Dao) GetLocationChild(c context.Context, locID int32) (*map[int32][]*model.Location, error) {
rows, err := d.db.Query(c, locationQueryChild, locID)
if err != nil {
return nil, err
}
defer rows.Close()
m := make(map[int32][]*model.Location)
var id, pid int32
var name string
for rows.Next() {
rows.Scan(&id, &pid, &name)
m[pid] = append(m[pid], &model.Location{
ID: id,
PID: pid,
Name: name,
})
}
return &m, err
}

View File

@@ -0,0 +1,49 @@
package dao
import (
"context"
notice "go-common/app/service/bbq/notice-service/api/v1"
"go-common/library/log"
)
// NoticeList 获取通知列表
func (d *Dao) NoticeList(ctx context.Context, noticeType int32, mid, cursorID int64) (list []*notice.NoticeBase, err error) {
req := &notice.ListNoticesReq{
Mid: mid,
NoticeType: noticeType,
CursorId: cursorID,
}
res, err := d.noticeClient.ListNotices(ctx, req)
if err != nil {
log.Errorv(ctx, log.KV("log", "notice-service:ListNotices fail"), log.KV("err", err))
return
}
list = res.List
return
}
// GetNoticeUnread 获取未读情况
func (d *Dao) GetNoticeUnread(ctx context.Context, mid int64) (list []*notice.UnreadItem, err error) {
req := &notice.GetUnreadInfoRequest{Mid: mid}
res, err := d.noticeClient.GetUnreadInfo(ctx, req)
if err != nil {
log.Errorv(ctx, log.KV("log", "call notice service get unread info fail: err="+err.Error()))
return
}
list = res.List
log.V(1).Infov(ctx, log.KV("log", "call notice service get unread info: res="+res.String()))
return
}
// CreateNotice 创建通知
func (d *Dao) CreateNotice(ctx context.Context, notice *notice.NoticeBase) (err error) {
_, err = d.noticeClient.CreateNotice(ctx, notice)
if err != nil {
log.Errorv(ctx, log.KV("log", "create notice fail: notice="+notice.String()))
return
}
log.V(1).Infov(ctx, log.KV("log", "create notice: notice="+notice.String()))
return
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"context"
"fmt"
notice "go-common/app/service/bbq/notice-service/api/v1"
"go-common/library/log"
)
// PushLogin .
func (d *Dao) PushLogin(c context.Context, req *notice.UserPushDev) (err error) {
_, err = d.noticeClient.PushLogin(c, req)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("push login fail: req=%s", req.String())))
}
return
}
// PushLogout .
func (d *Dao) PushLogout(c context.Context, req *notice.UserPushDev) (err error) {
_, err = d.noticeClient.PushLogout(c, req)
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("push logout fail: req=%s", req.String())))
}
return
}
// PushCallback .
func (d *Dao) PushCallback(c context.Context, tid string, nid string, mid int64, buvid string) (err error) {
_, err = d.noticeClient.PushCallback(c, &notice.PushCallbackRequest{
Tid: tid,
Nid: nid,
Mid: mid,
Buvid: buvid,
})
return
}

View File

@@ -0,0 +1,43 @@
package dao
import (
"math/rand"
"time"
"go-common/app/interface/bbq/app-bbq/model"
)
// GetRandVideoList .
func (d *Dao) GetRandVideoList(mid int64, limit int) []*model.SvInfo {
var result []*model.SvInfo
r := rand.New(rand.NewSource(time.Now().Unix()))
mask := len(d.redundanceVideos) - limit
cursor := r.Int() % mask
for _, v := range d.redundanceVideos[cursor : cursor+limit] {
result = append(result, &model.SvInfo{
SVID: v.Svid,
AVID: v.Avid,
CID: v.Cid,
MID: mid,
})
}
return result
}
// GetRandSvList .
func (d *Dao) GetRandSvList(limit int) []int64 {
result := make([]int64, limit)
r := rand.New(rand.NewSource(time.Now().Unix()))
mask := len(d.redundanceVideos) - limit
cursor := r.Int() % mask
for _, v := range d.redundanceVideos[cursor : cursor+limit] {
result = append(result, v.Svid)
}
return result
}

View File

@@ -0,0 +1,95 @@
package dao
import (
"context"
"errors"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/log"
xhttp "net/http"
"net/url"
"strconv"
)
//ReportUser rType=0 face;rType=1 name;
func (d *Dao) ReportUser(c context.Context, rType int, mid int64, rmid int64, reason string) (err error) {
var (
params url.Values
req *xhttp.Request
res model.HTTPRpcRes
)
params = url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("rmid", strconv.FormatInt(rmid, 10))
params.Set("type", strconv.Itoa(rType))
params.Set("reason", reason)
if req, err = d.httpClient.NewRequest("POST", d.c.URLs["cms_report"], "", params); err != nil {
log.Errorv(c, log.KV("event", "ReportUser d.httpClient.NewRequest failed"), log.KV("err", err))
return
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Errorv(c, log.KV("event", "cms ReportUser http req failed"), log.KV("err", err), log.KV("req", req))
return
}
if res.Code != 0 {
log.Errorv(c, log.KV("event", "cms ReportUser res.code err"), log.KV("err", err))
err = errors.New("cms ReportUser return err")
return
}
return
}
//ReportDanmu ..
func (d *Dao) ReportDanmu(c context.Context, danmu int64, mid int64, rmid int64, reason string) (err error) {
var (
params url.Values
req *xhttp.Request
res model.HTTPRpcRes
)
params = url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("rmid", strconv.FormatInt(rmid, 10))
params.Set("bullet_id", strconv.FormatInt(danmu, 10))
params.Set("reason", reason)
if req, err = d.httpClient.NewRequest("POST", d.c.URLs["cms_report_bullet"], "", params); err != nil {
log.Errorv(c, log.KV("event", "ReportDanmu d.httpClient.NewRequest failed"), log.KV("err", err))
return
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Errorv(c, log.KV("event", "cms ReportDanmu http req failed"), log.KV("err", err), log.KV("req", req))
return
}
if res.Code != 0 {
log.Errorv(c, log.KV("event", "cms ReportDanmu res.code err"), log.KV("err", err))
err = errors.New("cms ReportDanmu return err")
return
}
return
}
//ReportVideo ..
func (d *Dao) ReportVideo(c context.Context, svid int64, rmid int64, reason string) (err error) {
var (
params url.Values
req *xhttp.Request
res model.HTTPRpcRes
)
params = url.Values{}
params.Set("rmid", strconv.FormatInt(rmid, 10))
params.Set("svid", strconv.FormatInt(svid, 10))
params.Set("reason", reason)
if req, err = d.httpClient.NewRequest("POST", d.c.URLs["cms_report_video"], "", params); err != nil {
log.Errorv(c, log.KV("event", "ReportVideo d.httpClient.NewRequest failed"), log.KV("err", err))
return
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Errorv(c, log.KV("event", "cms ReportVideo http req failed"), log.KV("err", err), log.KV("req", req))
return
}
if res.Code != 0 {
log.Errorv(c, log.KV("event", "cms ReportVideo res.code err"), log.KV("err", err))
err = errors.New("cms ReportVideo return err")
return
}
return
}

View File

@@ -0,0 +1,164 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
"net/url"
"strconv"
"strings"
"time"
jsoniter "github.com/json-iterator/go"
)
const (
httpProto = "http://"
searchBaseURI = "/bbq/search"
sugBaseURI = "/main/suggest"
getSVIDbyRelID = "select id,svid from video where id in (%s)"
)
// SearchBBQ 搜索视频
func (d *Dao) SearchBBQ(c context.Context, sreq *model.SearchBaseReq) (ret *model.RawSearchRes, err error) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
ret = new(model.RawSearchRes)
path := httpProto + d.c.Search.Host + searchBaseURI
params := url.Values{}
d.preSetSearchParam(c, &params)
params.Set("keyword", sreq.KeyWord)
params.Set("page", strconv.FormatInt(sreq.Page, 10))
params.Set("pagesize", strconv.FormatInt(sreq.PageSize, 10))
params.Set("highlight", strconv.FormatInt(sreq.Highlight, 10))
params.Set("search_type", sreq.Type)
log.Infov(c, log.KV("log", fmt.Sprintf("search url(%s)", path+"?"+params.Encode())))
req, err := d.httpClient.NewRequest("GET", path, params.Get("ip"), params)
if err != nil {
log.Error("search url(%s) error(%v)", path+"?"+params.Encode(), err)
return
}
if err = d.httpClient.Do(c, req, &ret); err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("search url(%s) error(%v)", path+"?"+params.Encode(), err)))
return
}
if ret.Code != 0 {
err = ecode.Int(ret.Code)
log.Errorv(c, log.KV("log", fmt.Sprintf("search url(%s) error(%v)", path+"?"+params.Encode(), err)))
return
}
_str, _ := json.Marshal(ret)
log.Infov(c,
log.KV("log", fmt.Sprintf("Search req[%s] ret[%s]", path+"?"+params.Encode(), _str)))
return
}
// SugBBQ 搜索视频
func (d *Dao) SugBBQ(c context.Context, sreq *model.SugBaseReq) (ret json.RawMessage, err error) {
path := httpProto + d.c.Search.Host + sugBaseURI
params := url.Values{}
d.preSetSearchParam(c, &params)
params.Set("term", sreq.Term)
params.Set("suggest_type", sreq.SuggestType)
params.Set("highlight", strconv.FormatInt(sreq.Highlight, 10))
params.Set("main_ver", sreq.MainVer)
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
log.Infov(c, log.KV("log", fmt.Sprintf("sug url(%s)", path+"?"+params.Encode())))
req, err := d.httpClient.NewRequest("GET", path, params.Get("ip"), params)
if err != nil {
log.Error("sug url(%s) error(%v)", path+"?"+params.Encode(), err)
return
}
var res struct {
Code int `json:"code"`
Stoken string `json:"stoken"`
Res struct {
Tag json.RawMessage `json:"tag"`
} `json:"result"`
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("sug url(%s) error(%v)", path+"?"+params.Encode(), err)))
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Errorv(c, log.KV("log", fmt.Sprintf("sug url(%s) error(%v)", path+"?"+params.Encode(), err)))
return
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
_str, _ := json.Marshal(ret)
log.Infov(c, log.KV("log", fmt.Sprintf("Sug req[%s] ret[%s]", path+"?"+params.Encode(), _str)))
ret = res.Res.Tag
return
}
func (d *Dao) preSetSearchParam(c context.Context, params *url.Values) {
device := c.Value("device")
if device != nil {
dev := device.(*bm.Device)
if dev.RawPlatform != "" {
params.Set("platform", dev.RawPlatform)
}
if dev.RawMobiApp != "" {
params.Set("mobi_app", dev.RawMobiApp)
}
if dev.Device != "" {
params.Set("device", dev.Device)
}
if dev.Build > 0 {
params.Set("device", strconv.FormatInt(dev.Build, 10))
}
}
ip := metadata.String(c, metadata.RemoteIP)
if ip != "" {
params.Set("clientip", ip)
}
}
// ConvID2SVID 转换搜索相对id到svid
func (d *Dao) ConvID2SVID(c context.Context, ids []int64) (res map[int64]int64, err error) {
var idList []string
res = make(map[int64]int64)
if len(ids) == 0 {
return
}
for _, id := range ids {
idList = append(idList, strconv.FormatInt(id, 10))
}
if len(idList) == 0 {
log.Warn("empty query list relID [%v]", ids)
return
}
idStr := strings.Join(idList, ",")
sql := fmt.Sprintf(getSVIDbyRelID, idStr)
rows, err := d.db.Query(c, sql)
if err != nil {
log.Warn("Query Err [%v]", err)
return
}
defer rows.Close()
for rows.Next() {
var svid int64
var id int64
err = rows.Scan(&id, &svid)
if err != nil {
log.Warn("Scan Err [%v]", err)
return
}
res[id] = svid
}
return
}
// ParseRel2ID 转换搜索相对id到自增id
func (d *Dao) ParseRel2ID(relID []int32) (idList []int64) {
for _, id := range relID {
idList = append(idList, int64(id/100))
}
return
}

View File

@@ -0,0 +1,54 @@
package dao
import (
"context"
"fmt"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/cache/redis"
"go-common/library/log"
)
var (
_selectUserShareToken = "select token from user_share_token where mid = ?;"
_insertUserShareToken = "insert into user_share_token (mid, token) values (?, ?);"
)
// GetUserShareToken .
func (d *Dao) GetUserShareToken(ctx context.Context, mid int64) string {
conn := d.redis.Get(ctx)
defer conn.Close()
raw, err := redis.Bytes(conn.Do("GET", fmt.Sprintf(model.CacheKeyUserShareToken, mid)))
if err == redis.ErrNil || raw == nil {
rows, err := d.db.Query(ctx, _selectUserShareToken, mid)
if err != nil {
log.Errorv(ctx, log.KV("GetUserShareToken", err))
return ""
}
var token string
for rows.Next() {
rows.Scan(&token)
}
return token
}
return string(raw)
}
// SetUserShareToken .
func (d *Dao) SetUserShareToken(ctx context.Context, mid int64, token string) (int64, error) {
result, err := d.db.Exec(ctx, _insertUserShareToken, mid, token)
fmt.Println(result, err)
if err != nil {
return 0, err
}
if n, _ := result.RowsAffected(); n > 0 {
conn := d.redis.Get(ctx)
defer conn.Close()
conn.Do("SET", fmt.Sprintf(model.CacheKeyUserShareToken, mid), token)
}
return result.LastInsertId()
}

View File

@@ -0,0 +1,386 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/url"
"sort"
"strconv"
"strings"
"time"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/app/interface/bbq/app-bbq/model/grpc"
rec "go-common/app/service/bbq/recsys/api/grpc/v1"
video "go-common/app/service/bbq/video/api/grpc/v1"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
xgrpc "google.golang.org/grpc"
)
const (
_defaultPlatform = "html5"
_playBcNum = 1
_queryList = "select `avid`, `cid`, `svid`, `title`, `mid`, `content`, `pubtime`,`duration`,`tid`,`sub_tid`,`ctime`,`cover_url`,`cover_width`,`cover_height`,`state` from video where svid in (%s)"
_queryRand = "select `svid` from video where state in (4,5) order by mtime desc limit 400;"
_queryStatisticsList = "select `svid`, `play`, `subtitles`, `like`, `share`, `report` from video_statistics where svid in (%s)"
_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"
)
// GetList 获取列表按照db排序按page返回用于推荐的降级
func (d *Dao) GetList(c context.Context, pageSize int64) (result []int64, err error) {
rows, err := d.db.Query(c, _queryRand)
if err != nil {
log.Error("Query(%s) error(%v)", _queryRand, err)
return
}
defer rows.Close()
var list []int64
for rows.Next() {
sv := new(model.SvInfo)
if err = rows.Scan(&sv.SVID); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
if tag, ok := d.c.Tmap[strconv.FormatInt(sv.TID, 10)]; ok {
sv.Tag = tag
}
list = append(list, sv.SVID)
}
size := len(list)
if size > int(pageSize) {
size = int(pageSize)
}
rand.Seed(time.Now().Unix())
sort.Slice(list, func(i, j int) bool {
return rand.Float32() > 0.5
})
result = list[:size]
return
}
// AttentionRecList 关注页为空时的推荐
func (d *Dao) AttentionRecList(ctx context.Context, size int64, mid int64, buvid string) (svIDs []int64, err error) {
svIDs, err = d.abstractRawRecList(ctx, d.recsysClient.UpsRecService, size, mid, buvid)
log.V(1).Infow(ctx, "log", "get ups rec service", "method", "UpsRecService")
return
}
// RawRecList 获取推荐列表
func (d *Dao) RawRecList(ctx context.Context, size int64, mid int64, buvid string) (svIDs []int64, err error) {
svIDs, err = d.abstractRawRecList(ctx, d.recsysClient.RecService, size, mid, buvid)
log.V(1).Infow(ctx, "log", "get ups rec service", "method", "RecService")
return
}
type recsysFunc func(ctx context.Context, in *rec.RecsysRequest, opts ...xgrpc.CallOption) (*rec.RecsysResponse, error)
// abstractRawRecList 由于访问recsys的方法都是同样的请求&回包,同时过程也一样,因此
func (d *Dao) abstractRawRecList(ctx context.Context, f recsysFunc, size int64, mid int64, buvid string) (svIDs []int64, err error) {
var (
res *rec.RecsysResponse
)
req := &rec.RecsysRequest{
MID: mid,
BUVID: buvid,
Limit: int32(size),
}
if tmp, ok := ctx.(*bm.Context).Get("BBQBase"); ok && tmp != nil {
switch tmp.(type) {
case *v1.Base:
base := tmp.(*v1.Base)
req.App = base.App
req.AppVersion = base.Version
}
}
if tmp, ok := ctx.(*bm.Context).Get("QueryID"); ok && tmp != nil {
switch tmp.(type) {
case string:
req.QueryID = tmp.(string)
}
}
log.Info("Rec请求 params: [%v]", req)
//res, err = d.recsysClient.RecService(ctx, req)
res, err = f(ctx, req)
debug := ctx.(*bm.Context).Request.Header.Get("debug")
if err != nil {
log.Errorv(ctx,
log.KV("log", fmt.Sprintf("d.recsysClient.RecService err [%v]", err)),
)
// 降级(推荐服务已挂)
svIDs = d.GetRandSvList(int(size))
return
} else if len(res.List) == 0 || debug == "1" {
log.Warnv(ctx,
log.KV("log", fmt.Sprintf("d.recsysClient.RecService return empty [%v]", res.List)),
)
// 降级(推荐接口返回空)
svIDs = d.GetRandSvList(int(size))
return
} else {
num := len(res.List)
if int64(num) != size {
log.Warnv(ctx,
log.KV("log", fmt.Sprintf("d.recsysClient.RecService return num[%d] not match size[%d]", num, size)),
)
}
for n, sv := range res.List {
if int64(n) > size {
break
}
svIDs = append(svIDs, sv.Svid)
}
}
return
}
// GetVideoDetail 从数据库video中获取svid相应的信息
func (d *Dao) GetVideoDetail(ctx context.Context, svIDs []int64) (list []*model.SvInfo, retIDs []int64, err error) {
list = make([]*model.SvInfo, 0)
num := len(svIDs)
if num == 0 {
return
}
var IDsStr string
for i, id := range svIDs {
if i < num-1 {
IDsStr += strconv.FormatInt(id, 10) + ","
} else {
IDsStr += strconv.FormatInt(id, 10)
}
}
query := fmt.Sprintf(_queryList, IDsStr)
rows, err := d.db.Query(ctx, query)
if err != nil {
log.Error("Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
sv := new(model.SvInfo)
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.Ctime, &sv.CoverURL, &sv.CoverWidth, &sv.CoverHeight, &sv.State); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
if tag, ok := d.c.Tmap[strconv.FormatInt(sv.TID, 10)]; ok {
sv.Tag = tag
}
retIDs = append(retIDs, sv.SVID)
list = append(list, sv)
}
return
}
// RawVideos 从数据库批量获取视频信息
func (d *Dao) RawVideos(ctx context.Context, svIDs []int64) (res map[int64]*model.SvInfo, err error) {
res = make(map[int64]*model.SvInfo)
num := len(svIDs)
if num == 0 {
return
}
var IDsStr string
for i, id := range svIDs {
if i < num-1 {
IDsStr += strconv.FormatInt(id, 10) + ","
} else {
IDsStr += strconv.FormatInt(id, 10)
}
}
query := fmt.Sprintf(_queryList, IDsStr)
rows, err := d.db.Query(ctx, query)
if err != nil {
log.Error("Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
sv := new(model.SvInfo)
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.Ctime, &sv.CoverURL, &sv.CoverWidth, &sv.CoverHeight, &sv.State); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
res[sv.SVID] = sv
}
return
}
// 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, model.DefaultCmType)
for id, cmt := range cmtCount {
if _, ok := res[id]; ok {
res[id].Reply = cmt.Count
}
}
return
}
// RawPlayURLs 批量获取cid playurl
func (d *Dao) RawPlayURLs(c context.Context, cids []int64, qn int64, plat string) (res map[int64]*v1.CVideo, err error) {
res = make(map[int64]*v1.CVideo)
var cs string
// transfer cid array to string
l := len(cids)
for i := 0; i < l; i++ {
if i != l-1 {
cs += strconv.FormatInt(cids[i], 10) + ","
} else {
cs += strconv.FormatInt(cids[i], 10)
}
}
ip := metadata.String(c, metadata.RemoteIP)
params := url.Values{}
params.Set("cid", cs)
params.Set("qn", strconv.FormatInt(qn, 10))
params.Set("platform", plat)
var ret struct {
Code int `json:"code"`
Data map[string]map[string]*v1.CVideo `json:"data"`
}
err = d.httpClient.Get(c, d.c.URLs["bvc_batch"], ip, params, &ret)
if err != nil || ret.Data["cids"] == nil {
log.Error("http Get err %v", err)
return
}
for id, v := range ret.Data["cids"] {
var cid int64
cid, err = strconv.ParseInt(id, 10, 64)
if err != nil {
log.Error("strconv.ParseInt err %v", err)
}
if _, ok := res[cid]; !ok {
res[cid] = new(v1.CVideo)
}
res[cid] = v
}
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
}
//RawSVBvcKey 批量获取playurl相对地址
func (d *Dao) RawSVBvcKey(c context.Context, svids []int64) (res map[int64][]*model.SVBvcKey, err error) {
var (
tb map[string][]string
rows *sql.Rows
)
res = make(map[int64][]*model.SVBvcKey)
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 := model.SVBvcKey{}
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
}
// RelRecList 相关推荐列表
func (d *Dao) RelRecList(ctx context.Context, req *rec.RecsysRequest) (svIDs []int64, err error) {
log.V(1).Infov(ctx, log.KV("log", fmt.Sprintf("RelatedRecService req [%+v]", req)))
res, err := d.recsysClient.RelatedRecService(ctx, req)
if err != nil {
log.Errorv(ctx,
log.KV("log", fmt.Sprintf("RelatedRecService err [%v]", err)),
)
return
}
num := len(res.List)
if int32(num) != req.Limit {
log.Errorv(ctx,
log.KV("log", fmt.Sprintf("RelatedRecService ret num[%d] not match req size[%d]", num, req.Limit)),
)
}
for n, sv := range res.List {
if int32(n) > req.Limit {
break
}
svIDs = append(svIDs, sv.Svid)
}
log.V(1).Infov(ctx, log.KV("log", fmt.Sprintf("RelatedRecService svid [%+v]", svIDs)))
return
}
// SvDel 视频删除
func (d *Dao) SvDel(c context.Context, in *video.VideoDeleteRequest) (interface{}, error) {
return d.videoClient.VideoDelete(c, in)
}

View File

@@ -0,0 +1,75 @@
package dao
import (
"context"
xsql "database/sql"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_insertVideoStatistics = "insert into video_statistics (`svid`,`play`,`subtitles`,`like`,`share`,`report`) values (?,?,?,?,?,?)"
_incrVideoStatisticsLike = "update video_statistics set `like` = `like` + 1 where `svid` = ?"
_decrVideoStatisticsLike = "update video_statistics set `like` = `like` - 1 where `svid` = ? and `like` > 0"
_insertVideoStatisticsShare = "INSERT INTO video_statistics (`svid`,`share`) VALUES (?,1) ON DUPLICATE KEY UPDATE `share` = `share` + 1;"
_incrVideoStatisticsShare = "UPDATE `video_statistics` SET `share` = `share` + 1 WHERE `svid` = ?;"
_selectVideoStatisticsLike = "select `svid`,`play`,`subtitles`,`like`,`share`,`report` from video_statistics where `svid` = ?"
_videoStatisticsShare = "select `share`+1 from video_statistics where `svid`= ?"
)
//TxIncrVideoStatisticsLike .
func (d *Dao) TxIncrVideoStatisticsLike(tx *sql.Tx, svid int64) (num int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_incrVideoStatisticsLike, svid); err != nil {
log.Error("update video_statistics like err(%v)", err)
return
}
return res.RowsAffected()
}
//TxDecrVideoStatisticsLike .
func (d *Dao) TxDecrVideoStatisticsLike(tx *sql.Tx, svid int64) (num int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_decrVideoStatisticsLike, svid); err != nil {
log.Error("update video_statistics like err(%v)", err)
return
}
return res.RowsAffected()
}
//IncrVideoStatisticsShare .
func (d *Dao) IncrVideoStatisticsShare(ctx context.Context, svid int64) (num int32, err error) {
row := d.db.QueryRow(ctx, _videoStatisticsShare, svid)
err = row.Scan(&num)
if err != nil || num == 0 {
if _, err = d.db.Exec(ctx, _insertVideoStatisticsShare, svid); err != nil {
log.Error("insert video_statistics share error: [%+v] svid: [%d]", err, svid)
}
num = 1
} else if _, err = d.db.Exec(ctx, _incrVideoStatisticsShare, svid); err != nil {
log.Error("update video_statistics share error: [%+v] svid: [%d]", err, svid)
}
return
}
//TxAddVideoStatistics .
func (d *Dao) TxAddVideoStatistics(tx *sql.Tx, videoStatistics *model.VideoStatistics) (num int64, err error) {
var res xsql.Result
if res, err = tx.Exec(_insertVideoStatistics, videoStatistics.SVID, videoStatistics.Play, videoStatistics.Subtitles, videoStatistics.Like, videoStatistics.Share, videoStatistics.Report); err != nil {
log.Error("insert video_statistics err(%v)", err)
return
}
return res.LastInsertId()
}
//RawVideoStatistics .
func (d *Dao) RawVideoStatistics(c context.Context, svid int64) (res *model.VideoStatistics, err error) {
res = new(model.VideoStatistics)
row := d.db.QueryRow(c, _selectVideoStatisticsLike, svid)
err = row.Scan(&res.SVID, &res.Play, &res.Subtitles, &res.Like, &res.Share, &res.Report)
if err == sql.ErrNoRows {
err = nil
}
return
}

View File

@@ -0,0 +1,38 @@
package dao
import (
"context"
"go-common/library/ecode"
"go-common/library/log"
xhttp "net/http"
"net/url"
"strconv"
)
//MergeUploadReq ..
func (d *Dao) MergeUploadReq(c context.Context, rurl string, uploadID string, profile string, svid int64, auth string) (err error) {
var (
req *xhttp.Request
)
rurl = d.c.Upload.HTTPSchema + rurl
param := make(url.Values)
param.Set("uploadId", uploadID)
param.Set("profile", profile)
param.Set("biz_id", strconv.FormatInt(svid, 10))
rurl = rurl + "?" + param.Encode()
req, err = d.httpslowClient.NewRequest(xhttp.MethodPost, rurl, "", param)
if err != nil {
log.Errorw(c, "event", "MergeUploadReq d.httpClient.NewRequest err", "err", err)
err = ecode.UploadFailed
return
}
req.Header.Add("X-Upos-Auth", auth)
if err = d.httpClient.Do(c, req, nil); err != nil {
log.Errorw(c, "event", "MergeUploadReq d.httpClient.Do err", "err", err)
err = ecode.UploadFailed
return
}
return
}

View File

@@ -0,0 +1,99 @@
package dao
import (
"context"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
"go-common/app/interface/bbq/app-bbq/model"
user "go-common/app/service/bbq/user/api"
accountv1 "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
)
//GetUserBProfile 获取用户全量b站信息
func (d *Dao) GetUserBProfile(c context.Context, mid int64) (res *accountv1.ProfileReply, err error) {
req := &accountv1.MidReq{
Mid: mid,
RealIp: "",
}
res, err = d.accountClient.Profile3(c, req)
return
}
// Login .
func (d *Dao) Login(c context.Context, userBase *user.UserBase) (res *user.UserBase, err error) {
res, err = d.userClient.Login(c, userBase)
if err != nil {
log.Errorv(c, log.KV("log", "login fail"))
}
return
}
// BatchUserInfo 提供批量获取UserInfo的方法
// 由于user service返回的结构和video的回包不同因此这里进行映射返回video-c的结构避免外部使用方多次映射
func (d *Dao) BatchUserInfo(c context.Context, visitorMID int64, MIDs []int64, needDesc, needStat, needFollowState bool) (res map[int64]*v1.UserInfo, err error) {
res = make(map[int64]*v1.UserInfo)
if len(MIDs) == 0 {
return
}
if len(MIDs) > model.BatchUserLen {
err = ecode.BatchUserTooLong
return
}
userReq := &user.ListUserInfoReq{Mid: visitorMID, UpMid: MIDs, NeedDesc: needDesc, NeedStat: needStat, NeedFollowState: needFollowState}
reply, err := d.userClient.ListUserInfo(c, userReq)
if err != nil {
log.Errorv(c, log.KV("log", "get user info fail: req=%s"+userReq.String()))
return
}
for _, userInfo := range reply.List {
newUserInfo := &v1.UserInfo{UserBase: *userInfo.UserBase}
if userInfo.UserStat != nil {
newUserInfo.UserStat = *userInfo.UserStat
}
newUserInfo.FollowState = userInfo.FollowState
res[userInfo.UserBase.Mid] = newUserInfo
}
return
}
//JustGetUserBase 只取UserBase不要其他
func (d *Dao) JustGetUserBase(c context.Context, mids []int64) (res map[int64]*user.UserBase, err error) {
res = make(map[int64]*user.UserBase)
userInfos, err := d.BatchUserInfo(c, 0, mids, false, false, false)
if err != nil {
log.Warnv(c, log.KV("log", "get user info fail"))
return
}
for mid, userInfo := range userInfos {
res[mid] = &userInfo.UserBase
}
return
}
// EditUserBase .
func (d *Dao) EditUserBase(c context.Context, userBase *user.UserBase) (err error) {
_, err = d.userClient.UserEdit(c, userBase)
if err != nil {
log.Warnw(c, "log", "edit user base fail: req="+userBase.String(), "err", err.Error())
return
}
return
}
// PhoneCheck .
func (d *Dao) PhoneCheck(c context.Context, mid int64) (telStatus int32, err error) {
req := &user.PhoneCheckReq{Mid: mid}
res, err := d.userClient.PhoneCheck(c, req)
if err != nil {
log.Errorw(c, "log", "call phone check fail", "err", err, "mid", mid)
return
}
telStatus = res.TelStatus
return
}

View File

@@ -0,0 +1,55 @@
package dao
import (
"context"
"fmt"
user "go-common/app/service/bbq/user/api"
"go-common/library/log"
)
// AddLike .
func (d *Dao) AddLike(c context.Context, mid, upMid, svid int64) (affectedNum int64, err error) {
reply, err := d.userClient.AddLike(c, &user.LikeReq{Mid: mid, UpMid: upMid, Opid: svid})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("add like fail: mid=%d, up_mid=%d, svid=%d", mid, upMid, svid)))
return
}
affectedNum = reply.AffectedNum
return
}
// CancelLike .
func (d *Dao) CancelLike(c context.Context, mid, upMid, svid int64) (affectedNum int64, err error) {
reply, err := d.userClient.CancelLike(c, &user.LikeReq{Mid: mid, UpMid: upMid, Opid: svid})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("cancel like fail: mid=%d, up_mid=%d, svid=%d", mid, upMid, svid)))
return
}
affectedNum = reply.AffectedNum
return
}
// CheckUserLike 检测用户是否点赞
func (d *Dao) CheckUserLike(c context.Context, mid int64, svids []int64) (res map[int64]bool, err error) {
res = make(map[int64]bool)
reply, err := d.userClient.IsLike(c, &user.IsLikeReq{Mid: mid, Svids: svids})
if err != nil {
log.Errorv(c, log.KV("log", "get is like info fail"))
return
}
for _, svid := range reply.List {
res[svid] = true
}
return
}
// UserLikeList .
func (d *Dao) UserLikeList(c context.Context, upMid int64, cursorPrev, cursorNext string) (res *user.ListUserLikeReply, err error) {
res, err = d.userClient.ListUserLike(c, &user.ListUserLikeReq{UpMid: upMid, CursorPrev: cursorPrev, CursorNext: cursorNext})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("get user like list fail: up_mid=%d, cursor_prev=%s, next=%s", upMid, cursorPrev, cursorNext)))
return
}
return
}

View File

@@ -0,0 +1,33 @@
package dao
import (
"context"
"flag"
"fmt"
"go-common/app/interface/bbq/app-bbq/conf"
"testing"
)
var (
d *Dao
)
func init() {
flag.Set("conf", "../cmd/")
flag.Set("conf_name", "test.toml")
flag.Set("app_setting_name", "app_setting.toml")
flag.Set("deploy.env", "uat")
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func TestUserLike(t *testing.T) {
res, err := d.CheckUserLike(context.Background(), 88895104, []int64{74850, 2222})
fmt.Printf("res: %v", res)
if err != nil && len(res) == 0 {
t.Errorf("user like fail: err(%v)", err)
}
}

View File

@@ -0,0 +1,57 @@
package dao
import (
"context"
"fmt"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
user "go-common/app/service/bbq/user/api"
"go-common/library/log"
)
// ModifyRelation .
func (d *Dao) ModifyRelation(c context.Context, mid, upMid int64, action int32) (res *user.ModifyRelationReply, err error) {
res, err = d.userClient.ModifyRelation(c, &user.ModifyRelationReq{Mid: mid, UpMid: upMid, Action: action})
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("modify relation fail: mid=%d, up_mid=%d, action=%d", mid, upMid, action)))
}
return
}
// UserRelationList .
func (d *Dao) UserRelationList(c context.Context, userReq *user.ListRelationUserInfoReq, relationType int32) (res *v1.UserRelationListResponse, err error) {
res = new(v1.UserRelationListResponse)
var reply *user.ListUserInfoReply
switch relationType {
case user.Follow:
reply, err = d.userClient.ListFollowUserInfo(c, userReq)
case user.Fan:
reply, err = d.userClient.ListFanUserInfo(c, userReq)
case user.Black:
reply, err = d.userClient.ListBlackUserInfo(c, userReq)
}
if err != nil {
log.Errorv(c, log.KV("log", fmt.Sprintf("user relation list fail: req=%s", userReq.String())))
return
}
res.HasMore = reply.HasMore
for _, v := range reply.List {
userInfo := &v1.UserInfo{UserBase: *v.UserBase, FollowState: v.FollowState, CursorValue: v.CursorValue}
res.List = append(res.List, userInfo)
}
return
}
// FetchFollowList 获取mid的所有关注up主
func (d *Dao) FetchFollowList(c context.Context, mid int64) (upMid []int64, err error) {
res, err := d.userClient.ListFollow(c, &user.ListRelationReq{Mid: mid})
if err != nil {
log.Errorv(c, log.KV("log", "fetch follow list fail"))
return
}
upMid = res.List
return
}

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"go-common/app/service/bbq/common"
video "go-common/app/service/bbq/video/api/grpc/v1"
"go-common/library/ecode"
"go-common/library/log"
)
// BatchVideoInfo .
func (d *Dao) BatchVideoInfo(c context.Context, svids []int64) (res map[int64]*video.VideoInfo, err error) {
res = make(map[int64]*video.VideoInfo)
videoReq := &video.ListVideoInfoRequest{SvIDs: svids}
reply, err := d.videoClient.ListVideoInfo(c, videoReq)
if err != nil {
log.Errorw(c, "log", "call video service list vidoe info fail", "req", videoReq.String())
return
}
for _, videoInfo := range reply.List {
res[videoInfo.VideoBase.Svid] = videoInfo
}
log.V(10).Infow(c, "log", "batch video base", "video_info", res)
return
}
// VideoBase 获取单个svid的VideoBase不存在则会返回error
func (d *Dao) VideoBase(c context.Context, mid, svid int64) (res *video.VideoBase, err error) {
videoInfos, err := d.BatchVideoInfo(c, []int64{svid})
if err != nil {
log.Warnw(c, "log", "batch fetch video info fail", "mid", mid, "svid", svid)
return
}
if len(videoInfos) == 0 {
err = ecode.VideoUnExists
log.Warnw(c, "log", "get empty video base", "mid", mid, "svid", svid)
return
}
videoInfo, exists := videoInfos[svid]
if !exists {
err = ecode.VideoUnExists
log.Infow(c, "log", "get empty video base", "mid", mid, "svid", svid)
return
}
res = videoInfo.VideoBase
if res.State == common.VideoStPassReviewReject {
log.Infow(c, "log", "video state in audit", "mid", mid, "svid", svid, "video_base", res)
err = ecode.VideoInAudit
return
}
if !common.IsSvStateAvailable(res.State) {
err = ecode.VideoUnReachable
log.Infow(c, "log", "video state not available", "mid", mid, "svid", svid, "video_base", res)
return
}
if res.State == common.VideoStPassReviewReject && mid != res.Mid {
err = ecode.VideoUnReachable
log.Infow(c, "log", "video state only owner available", "mid", mid, "svid", svid, "video_base", res)
return
}
return
}