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,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"card_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/service/main/account/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"card.go",
"dao.go",
],
importpath = "go-common/app/interface/main/tv/dao/account",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,35 @@
package account
import (
"context"
accwar "go-common/app/service/main/account/api"
accmdl "go-common/app/service/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
)
// Card3 get card info by mid
func (d *Dao) Card3(c context.Context, mid int64) (res *accmdl.Card, err error) {
var (
arg = &accwar.MidReq{Mid: mid}
reply *accwar.CardReply
)
if reply, err = d.accClient.Card3(c, arg); err != nil || reply == nil || reply.Card == nil {
if err != nil {
log.Error("s.accDao.Info(%d) error(%v)", mid, err)
}
err = ecode.AccessDenied
return
}
res = reply.Card
return
}
// IsVip checks whether the member is vip
func IsVip(card *accmdl.Card) bool {
if card.Vip.Type == 0 || card.Vip.Status == 0 || card.Vip.Status == 2 || card.Vip.Status == 3 {
return false
}
return true
}

View File

@@ -0,0 +1,51 @@
package account
import (
"context"
"testing"
accmdl "go-common/app/service/main/account/model"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestAccountCard3(t *testing.T) {
var (
c = context.Background()
mid = int64(27515256)
)
convey.Convey("Card3", t, func(ctx convey.C) {
res, err := d.Card3(c, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
res, err = d.Card3(c, 777777777777)
ctx.So(err, convey.ShouldEqual, ecode.AccessDenied)
ctx.So(res, convey.ShouldBeNil)
})
}
func TestAccountIsVip(t *testing.T) {
var (
cardFalse = &accmdl.Card{}
// card.Vip.Type == 0 || card.Vip.Status == 0 || card.Vip.Status == 2 || card.Vip.Status == 3
cardTrue = &accmdl.Card{
Vip: accmdl.VipInfo{
Type: 1,
Status: 1,
},
}
)
convey.Convey("IsVip", t, func(ctx convey.C) {
p1 := IsVip(cardFalse)
ctx.Convey("Then p1 should be false.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldBeFalse)
})
p2 := IsVip(cardTrue)
ctx.Convey("Then p2 should be true.", func(ctx convey.C) {
ctx.So(p2, convey.ShouldBeTrue)
})
})
}

View File

@@ -0,0 +1,22 @@
package account
import (
"go-common/app/interface/main/tv/conf"
accwar "go-common/app/service/main/account/api"
)
// Dao is account dao.
type Dao struct {
// rpc
accClient accwar.AccountClient
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{}
var err error
if d.accClient, err = accwar.NewClient(c.AccClient); err != nil {
panic(err)
}
return
}

View File

@@ -0,0 +1,34 @@
package account
import (
"flag"
"os"
"testing"
"go-common/app/interface/main/tv/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,76 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"homepage_test.go",
"intervention_test.go",
"module_test.go",
"pgc_cards_test.go",
"recommend_test.go",
"redis_test.go",
"region_test.go",
"zone_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"homepage.go",
"intervention.go",
"module.go",
"pgc_cards.go",
"recommend.go",
"redis.go",
"region.go",
"zone.go",
],
importpath = "go-common/app/interface/main/tv/dao/app",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//app/interface/main/tv/model/search:go_default_library",
"//library/cache/memcache: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/stat/prom:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,50 @@
package dao
import (
"time"
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
// Dao .
type Dao struct {
db *sql.DB
conf *conf.Config
client *bm.Client
redis *redis.Pool
mc *memcache.Pool
dbeiExpire int64
}
// New .
func New(c *conf.Config) *Dao {
return &Dao{
db: sql.NewMySQL(c.Mysql),
conf: c,
client: bm.NewClient(c.HTTPClient),
redis: redis.NewPool(c.Redis.Config),
dbeiExpire: int64(time.Duration(c.Cfg.Dangbei.Expire) / time.Second),
mc: memcache.NewPool(c.Memcache.Config),
}
}
// Prom
var (
errorsCount = prom.BusinessErrCount
infosCount = prom.BusinessInfoCount
)
// PromError prom error
func PromError(name string) {
errorsCount.Incr(name)
}
// PromInfo add prom info
func PromInfo(name string) {
infosCount.Incr(name)
}

View File

@@ -0,0 +1,53 @@
package dao
import (
"context"
"flag"
"os"
"strings"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
ctx = context.TODO()
)
func init() {
// dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
// flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,74 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/tv/conf"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
// Zones represents the different zones to display on the homepage recommendation area
var Zones = []string{"jp", "cn", "tv", "movie", "documentary"}
// HeaderData gets the header data from PGC API
func (d *Dao) HeaderData(ctx context.Context, appInfo *conf.TVApp) (result map[string][]*model.Card, err error) {
var (
res = new(struct {
Code int `json:"code"`
Result map[string][]*model.Card `json:"result"`
})
bangumiURL = d.conf.Host.APIIndex
params = url.Values{}
)
params.Set("build", appInfo.Build)
params.Set("mobi_app", appInfo.MobiApp)
params.Set("platform", appInfo.Platform)
if err = d.client.Get(ctx, bangumiURL, "", params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), bangumiURL+"?"+params.Encode())
return
}
result = res.Result
// check result contain the 5 type data
for _, v := range Zones {
_, ok := result[v]
if !ok {
err = fmt.Errorf("Result Miss Data: %s", v)
return
}
}
return
}
// FollowData gets the follow data from PGC API
func (d *Dao) FollowData(ctx context.Context, appInfo *conf.TVApp, accessKey string) (result []*model.Follow, err error) {
var (
bangumiURL = d.conf.Host.APIFollow
params = url.Values{}
res = model.ResFollow{}
)
params.Set("access_key", accessKey)
params.Set("build", appInfo.Build)
params.Set("mobi_app", appInfo.MobiApp)
params.Set("platform", appInfo.Platform)
params.Set("pagesize", fmt.Sprintf("%d", d.conf.Homepage.FollowSize))
if err = d.client.Get(ctx, bangumiURL, "", params, &res); err != nil {
log.Error("FollowData ERROR:%v", err)
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), bangumiURL+"?"+params.Encode())
log.Error("FollowData ERROR:%v", err)
return
}
result = res.Result
return
}

View File

@@ -0,0 +1,63 @@
package dao
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoHeaderData(t *testing.T) {
var (
ctx = context.Background()
appInfo = d.conf.TVApp
normalStr = `{"code":0,"message":"success","result":{"cn":[{"cover":"http://i0.hdslb.com/bfs/bangumi/1fb653e1e9a825ef1487216c834d3f72c647a8aa.jpg","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/4bbd70afe81fd1c483ca61a038a8a983358ef3ac.jpg","id":254310,"index":"34","index_show":"连载中"},"season_id":24438,"title":"小绿和小蓝"}],"documentary":[{"cover":"http://i0.hdslb.com/bfs/bangumi/30daefc74e09e9cb1a3e8771226002efe186aaf6.jpg","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/efe3a69efe4779662d4eff11f12e4b94cc3e52b6.jpg","id":253992,"index":"花絮12","index_show":"连载中"},"season_id":25810,"title":"历史那些事"}],"jp":[{"cover":"http://i0.hdslb.com/bfs/bangumi/a4c0e0ccc44fe3949a734f546cf5bb07da925bad.png","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/523e3b8faee592c683ea55cfdcdb26106651fdea.jpg","id":250465,"index":"6","index_show":"连载中"},"season_id":25739,"title":"关于我转生变成史莱姆这档事"}],"movie":[{"cover":"http://i0.hdslb.com/bfs/bangumi/75c7528cbf3254dd20a4512376ced74733ab98ef.jpg","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/8beff40b27076475353d25ca590d0932791f71d6.jpg","id":253907,"index":"中文","index_show":"全1话"},"season_id":25944,"title":"黑子的篮球 LAST GAME"}],"tv":[{"cover":"http://i0.hdslb.com/bfs/bangumi/f79e3d4bb24d73db6407d771a4293d737376a11a.jpg","new_ep":{"cover":"http://i1.hdslb.com/bfs/archive/e24e3c851a81d46d3706d7d5401d63e0f6d9453e.jpg","id":143246,"index ":"30 ","index_show ":"全30话 "},"season_id ":21448,"title ":"亮剑"}]}}`
httpErrStr = `{"code": -400}`
missingZoneStr = `{"code":0,"message":"success","result":{}}`
)
convey.Convey("HeaderData Normal Situation", t, func(c convey.C) {
c.Convey("Then err should be nil.result should not be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.APIIndex).Reply(200).JSON(normalStr)
result, err := d.HeaderData(ctx, appInfo)
cx.So(err, convey.ShouldBeNil)
cx.So(result, convey.ShouldNotBeNil)
})
c.Convey("Http err, Then err Should not be nil", func(cx convey.C) {
httpMock("GET", d.conf.Host.APIIndex).Reply(200).JSON(httpErrStr)
_, err := d.HeaderData(ctx, appInfo)
cx.So(err, convey.ShouldNotBeNil)
fmt.Println(err)
})
c.Convey("Then err should be about the zone", func(cx convey.C) {
httpMock("GET", d.conf.Host.APIIndex).Reply(200).JSON(missingZoneStr)
_, err := d.HeaderData(ctx, appInfo)
cx.So(err, convey.ShouldNotBeNil)
cx.So(err.Error(), convey.ShouldEqual, "Result Miss Data: jp")
fmt.Println(err)
})
})
}
func TestDaoFollowData(t *testing.T) {
var (
ctx = context.Background()
appInfo = d.conf.TVApp
accessKey = "9dfa21e5d98f0be3410974f6894b72af"
normalStr = `{"code":0,"count":"59","message":"success","pages":"6","result":[{"actor":[],"alias":"ラーメン大好き小泉さん","allow_bp":"1","allow_download":"0","area":"日本","bangumi_id":"3905","bangumi_title":"爱吃拉面的小泉同学","brief":"今天,她也在某处享用着拉面——\n冷淡而沉默不和他人亲近的神秘转学生小泉同学。她其实是每天追求着美...","copyright":"bilibili","cover":"http://i0.hdslb.com/bfs/bangumi/e4dcc80598a4133af6b1a880bb8006fa5346f31b.jpg","danmaku_count":"436189","ed_jump":5,"episodes":[],"evaluate":"","favorites":"975275","is_finish":"1","is_started":1,"last_time":"2018-03-22 19:00:00.0","limitGroupId":1193,"new_cover":"http://i0.hdslb.com/bfs/archive/a06bbc48bc0c5c95afe0d2875d12376fc764807a.jpg","new_ep":{"av_id":"21083439","cover":"http://i0.hdslb.com/bfs/archive/a06bbc48bc0c5c95afe0d2875d12376fc764807a.jpg","danmaku":"34591825","episode_id":"164993","episode_status":2,"from":"bangumi","index":"12","index_title":"名古屋 / 再会","page":"1","up":{},"update_time":"2018-03-22 19:00:00.0"},"newest_ep_id":"164993","newest_ep_index":"12","play_count":"14835307","progress":"全12话","pub_string":"","pub_time":"2018-01-04 19:00:00","related_seasons":[],"season_id":"21728","season_status":2,"season_title":"TV","seasons":[],"share_url":"http://bangumi.bilibili.com/anime/21728/","spid":"0","squareCover":"http://i0.hdslb.com/bfs/bangumi/a160be35d676316efeb53157001b8df257a48a77.jpg","staff":"","tag2s":[],"tags":[{"cover":"http://i0.hdslb.com/bfs/bangumi/29baa04d18505c775c131e0d0db0bf8704cc61bb.jpg","tag_id":"21","tag_name":"治愈"},{"cover":"http://i0.hdslb.com/bfs/bangumi/0a89e6fc2da1a8f714ef3872d3b58df7137eb195.jpg","tag_id":"106","tag_name":"美食"},{"cover":"http://i0.hdslb.com/bfs/bangumi/3121473d5dd03a9bcccb8490034207e724e731b3.jpg","tag_id":"135","tag_name":"漫画改"}],"title":"爱吃拉面的小泉同学","total_count":"12","trailerAid":"-1","update_pattern":"","user_season":{"attention":"0","bp":0,"last_ep_index":"","last_time":"0","report_ts":0},"watchingCount":"0","weekday":"4"}]}`
httpErrStr = `{code": -400}`
)
convey.Convey("FollowData", t, func(c convey.C) {
c.Convey("Then err should be nil.result should not be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.APIFollow).Reply(200).JSON(normalStr)
result, err := d.FollowData(ctx, appInfo, accessKey)
cx.So(err, convey.ShouldBeNil)
cx.So(result, convey.ShouldNotBeNil)
})
c.Convey("Then err should not be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.APIFollow).Reply(200).JSON(httpErrStr)
_, err := d.FollowData(ctx, appInfo, accessKey)
cx.So(err, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,160 @@
package dao
import (
"context"
"database/sql"
"fmt"
"go-common/app/interface/main/tv/model"
"go-common/app/interface/main/tv/model/search"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_intervs = "SELECT cont_id, cont_type FROM tv_rank WHERE is_deleted = 0"
_parseInterv = "SELECT cont_id, cont_type FROM tv_rank "
_modIntervs = "%s WHERE module_id = %d AND is_deleted = 0 ORDER BY position ASC LIMIT %d"
_rankList = "%s WHERE rank = %d AND category = %d AND is_deleted = 0 ORDER BY position ASC LIMIT %d"
_rmPGCInterv = "UPDATE tv_rank SET is_deleted = 1 WHERE cont_type != 2 AND is_deleted = 0 AND cont_id IN (%s)"
_rmUGCInterv = "UPDATE tv_rank SET is_deleted = 1 WHERE cont_type = 2 AND is_deleted = 0 AND cont_id IN (%s)"
_idxIntervs = "SELECT rank, category, cont_id FROM tv_rank WHERE category IN (?,?) AND rank > 0 AND is_deleted = 0 ORDER BY position ASC"
_pgcIdxInterv = 6
_ugcIdxInterv = 7
)
// ModIntervs get intervention data with a given mod ID
func (d *Dao) ModIntervs(c context.Context, modID int, capacity int) (resp *model.RespModInterv, err error) {
var sql = fmt.Sprintf(_modIntervs, _parseInterv, modID, capacity)
return d.rowsTreat(c, sql)
}
// ZoneIntervs get db data
func (d *Dao) ZoneIntervs(c context.Context, req *model.ReqZoneInterv) (resp *model.RespModInterv, err error) {
var sql = fmt.Sprintf(_rankList, _parseInterv, req.RankType, req.Category, req.Limit)
return d.rowsTreat(c, sql)
}
// IdxIntervs def.
func (d *Dao) IdxIntervs(c context.Context) (idxSave *search.IdxIntervSave, err error) {
var (
rows *xsql.Rows
)
idxSave = &search.IdxIntervSave{
Pgc: make(map[int][]int64),
Ugc: make(map[int][]int64),
}
if rows, err = d.db.Query(c, _idxIntervs, _pgcIdxInterv, _ugcIdxInterv); err != nil {
log.Error("IdxIntervs d.db.Query (%s) error(%v)", _idxIntervs, err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.Rank{}
if err = rows.Scan(&li.Rank, &li.Category, &li.ContID); err != nil {
return
}
if li.Category == _pgcIdxInterv {
idxSave.Pgc[li.Rank] = append(idxSave.Pgc[li.Rank], li.ContID)
} else {
idxSave.Ugc[li.Rank] = append(idxSave.Ugc[li.Rank], li.ContID)
}
}
err = rows.Err()
return
}
// AllIntervs picks all the active intervention data
func (d *Dao) AllIntervs(c context.Context) (sids []int64, aids []int64, err error) {
var (
pgcMap = make(map[int64]int)
ugcMap = make(map[int64]int)
)
rows, err := d.db.Query(c, _intervs)
if err != nil {
log.Error("AllIntervs d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.SimpleRank{}
if err = rows.Scan(&li.ContID, &li.ContType); err != nil {
log.Error("AllIntervs row.Scan error(%v)", err)
return
}
if li.IsUGC() {
ugcMap[li.ContID] = 1
} else {
pgcMap[li.ContID] = 1
}
}
for avid := range ugcMap {
aids = append(aids, avid)
}
for sid := range pgcMap {
sids = append(sids, sid)
}
log.Info("AllIntervs Distinct UGC Intervs %d, PGC Intervs %d", len(aids), len(sids))
return
}
func (d *Dao) rowsTreat(c context.Context, sql string) (resp *model.RespModInterv, err error) {
var ranks []*model.SimpleRank
resp = new(model.RespModInterv)
rows, err := d.db.Query(c, sql)
if err != nil {
log.Error("ZoneIntervs d.db.Query (%s) error(%v)", sql, err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.SimpleRank{}
if err = rows.Scan(&li.ContID, &li.ContType); err != nil {
log.Error("ZoneIntervs row.Scan error(%v)", err)
return
}
ranks = append(ranks, li)
}
resp = &model.RespModInterv{
Ranks: ranks,
}
for _, v := range ranks {
if v.IsUGC() {
resp.AIDs = append(resp.AIDs, v.ContID)
} else {
resp.SIDs = append(resp.SIDs, v.ContID)
}
}
return
}
// RmInterv removes invalids interventions
func (d *Dao) RmInterv(c context.Context, aids []int64, sids []int64) (err error) {
var (
resPGC, resUGC sql.Result
rowsPGC, rowsUGC int64
)
if len(sids) > 0 {
if resPGC, err = d.db.Exec(c, fmt.Sprintf(_rmPGCInterv, xstr.JoinInts(sids))); err != nil {
log.Error("RmInterv Sids %v, Err %v", sids, err)
return
}
if rowsPGC, err = resPGC.RowsAffected(); err != nil {
log.Error("RmInterv Sids %v, Err %v", sids, err)
return
}
}
if len(aids) > 0 {
if resUGC, err = d.db.Exec(c, fmt.Sprintf(_rmUGCInterv, xstr.JoinInts(aids))); err != nil {
log.Error("RmInterv Aids %v, Err %v", aids, err)
return
}
if rowsUGC, err = resUGC.RowsAffected(); err != nil {
log.Error("RmInterv Aids %v, Err %v", aids, err)
return
}
}
log.Warn("RmInterv Aids %v, Sids %v, UGCDel Rows %d, PGCDel Rows %d", aids, sids, rowsUGC, rowsPGC)
return
}

View File

@@ -0,0 +1,98 @@
package dao
import (
"encoding/json"
"fmt"
"testing"
"go-common/app/interface/main/tv/model"
"context"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_ModIntervs(t *testing.T) {
Convey("TestDao_ModIntervs", t, WithDao(func(d *Dao) {
var modID int
if err := d.db.QueryRow(ctx,
"SELECT module_id FROM tv_rank "+
"WHERE is_deleted = 0 AND module_id != 0 AND category = 5 AND type = 1"+
"LIMIT 1").Scan(&modID); err != nil || modID == 0 {
return
}
sids, err := d.ModIntervs(ctx, modID, 10)
fmt.Println(sids)
So(err, ShouldBeNil)
}))
}
func TestDao_ZoneIntervs(t *testing.T) {
Convey("TestDao_ZoneIntervs", t, WithDao(func(d *Dao) {
// home page
resp, err := d.ZoneIntervs(ctx, &model.ReqZoneInterv{
RankType: 0,
Category: 1,
Limit: 50,
})
for _, v := range resp.Ranks {
fmt.Println(v)
}
So(err, ShouldBeNil)
So(len(resp.Ranks), ShouldBeGreaterThan, 0)
}))
}
func TestDao_AllIntervs(t *testing.T) {
Convey("TestDao_AllIntervs", t, WithDao(func(d *Dao) {
var countUGC, countPGC int64
d.db.QueryRow(ctx, "SELECT COUNT(1) FROM tv_rank WHERE is_deleted =0 AND cont_type = 2 ").Scan(&countUGC)
d.db.QueryRow(ctx, "SELECT COUNT(1) FROM tv_rank WHERE is_deleted =0 AND cont_type != 2 ").Scan(&countPGC)
sids, aids, err := d.AllIntervs(ctx)
So(err, ShouldBeNil)
if countUGC > 0 {
So(len(aids), ShouldBeGreaterThan, 0)
fmt.Println(aids)
} else {
fmt.Println("empty ugc rank")
}
if countPGC > 0 {
So(len(sids), ShouldBeGreaterThan, 0)
fmt.Println(sids)
} else {
fmt.Println("empty pgc ranks")
}
}))
}
func TestDao_RmInterv(t *testing.T) {
Convey("TestDao_RmInterv", t, WithDao(func(d *Dao) {
var aid, sid int64
d.db.QueryRow(ctx, "SELECT cont_id FROM tv_rank WHERE is_deleted =0 AND cont_type = 2 LIMIT 1").Scan(&aid)
d.db.QueryRow(ctx, "SELECT cont_id FROM tv_rank WHERE is_deleted =0 AND cont_type != 2 LIMIT 1 ").Scan(&sid)
if aid > 0 {
err := d.RmInterv(context.Background(), []int64{aid}, []int64{})
So(err, ShouldBeNil)
d.db.Exec(ctx, "UPDATE tv_rank SET is_deleted = 0 WHERE cont_id = ?", aid)
} else {
fmt.Println("empty ugc rank")
}
if sid > 0 {
err := d.RmInterv(context.Background(), []int64{}, []int64{sid})
So(err, ShouldBeNil)
d.db.Exec(ctx, "UPDATE tv_rank SET is_deleted = 0 WHERE cont_id = ?", sid)
} else {
fmt.Println("empty pgc ranks")
}
}))
}
func TestDao_IdxIntervs(t *testing.T) {
Convey("TestDao_IdxIntervs", t, WithDao(func(d *Dao) {
res, err := d.IdxIntervs(ctx)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
qq, _ := json.Marshal(res)
fmt.Println(string(qq))
}))
}

View File

@@ -0,0 +1,55 @@
package dao
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_modPage = "SELECT id,page_id,type,title,icon,source,capacity,flexible, more, `order`,moretype,morepage,src_type FROM tv_modules WHERE page_id = ? AND deleted = 0 AND valid = 1 ORDER BY `order`"
_passedSn = "SELECT id FROM tv_ep_season WHERE is_deleted = 0 AND `check` = 1 AND valid = 1"
)
// ModPage gets all the modules in one page
func (d *Dao) ModPage(ctx context.Context, pid int) (modules []*model.Module, err error) {
var rows *sql.Rows
rows, err = d.db.Query(ctx, _modPage, pid)
if err != nil {
log.Error("ModPage.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
a := &model.Module{}
if err = rows.Scan(&a.ID, &a.PageID, &a.Type, &a.Title, &a.Icon, &a.Source, &a.Capacity, &a.Flexible, &a.More, &a.Order, &a.MoreType, &a.MorePage, &a.SrcType); err != nil {
log.Error("ModPage row.Scan error(%v)", err)
return
}
modules = append(modules, a)
}
return
}
// PassedSns gets all passed seasons, to prepare their index_show data
func (d *Dao) PassedSns(ctx context.Context) (ids []int64, err error) {
rows, err := d.db.Query(ctx, _passedSn)
if err != nil {
log.Error("PassedSns.Query error(%v)", err)
return nil, err
}
defer rows.Close()
for rows.Next() {
var sid int64
if err = rows.Scan(&sid); err != nil {
log.Error("PassedSns row.Scan error(%v)", err)
return nil, err
}
ids = append(ids, sid)
}
if err = rows.Err(); err != nil {
log.Error("PassedSns Rows Err %v,")
}
return
}

View File

@@ -0,0 +1,30 @@
package dao
import (
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_ModPage(t *testing.T) {
Convey("TestDao_ModPage", t, WithDao(func(d *Dao) {
// home page
homeMods, err := d.ModPage(ctx, 0)
So(err, ShouldBeNil)
So(len(homeMods), ShouldBeGreaterThan, 0)
// jp page
jpMods, err2 := d.ModPage(ctx, 1)
So(err2, ShouldBeNil)
So(len(jpMods), ShouldBeGreaterThan, 0)
}))
}
func TestDao_PassedSns(t *testing.T) {
Convey("TestDao_PassedSns", t, WithDao(func(d *Dao) {
ids, err := d.PassedSns(ctx)
So(err, ShouldBeNil)
So(len(ids), ShouldBeGreaterThan, 0)
fmt.Println(ids)
}))
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
// PgcCards get season new index from pgc
func (d *Dao) PgcCards(ctx context.Context, ids string) (result map[string]*model.SeasonCard, err error) {
var (
response = &model.PgcResponse{}
params = url.Values{}
pgcSeasonURL = d.conf.Host.APINewindex
)
params.Set("season_ids", ids)
if err = d.client.Get(ctx, pgcSeasonURL, "", params, response); err != nil {
log.Error("PgcCards New Ep ERROR:%v", err)
return
}
if response.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(response.Code), fmt.Sprintf("PgcCards API Error %v", response.Message))
log.Error("PgcCards ERROR:%v, URL: %s", err, pgcSeasonURL+"?"+params.Encode())
return
}
if response.Result == nil {
err = errors.Wrap(ecode.ServerErr, "PgcCards api returns empty")
log.Error("PgcCards ERROR:%v", err)
return
}
result = response.Result
return
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPgcCards(t *testing.T) {
var (
ctx = context.Background()
ids = "113,296"
mockStr = `{"code":0,"message":"success","result":{"113":{"badge":"","badge_type":0,"cover":"http://i0.hdslb.com/bfs/bangumi/1c3da58352df66fd409831f7d5e13594c804144e.jpg","is_finish":1,"is_play":1,"is_started":1,"media_id":113,"new_ep":{"cover":"http://i0.hdslb.com/bfs/bangumi/88c8d5f6f149880fa31f6d039ed96f58e7a150f1.jpg","id":113506,"index_show":"全13话"},"rating":{"count":1141,"score":9.5},"rights":{"allow_review":1},"season_id":113,"season_title":"TV","season_type":1,"season_type_name":"番剧","stat":{"danmaku":298320,"follow":277453,"view":6978766},"title":"我们大家的河合庄","total_count":13},"296":{"badge":"","badge_type":0,"cover":"http://i0.hdslb.com/bfs/bangumi/37e22d2feafdf9ea5ad2b39860bd0205fb5a2d1d.png","is_finish":1,"is_play":1,"is_started":1,"media_id":296,"new_ep":{"cover":"http://i0.hdslb.com/bfs/bangumi/ae475384c527366a6ef07b414e1e0364695c2aa8.jpg","id":27915,"index_show":"全13话"},"rating":{"count":643,"score":9.2},"rights":{"allow_review":1},"season_id":296,"season_title":"TV","season_type":1,"season_type_name":"番剧","stat":{"danmaku":342835,"follow":253085,"view":5879216},"title":"天体的秩序","total_count":13}}}`
httpErrStr = `{"code":-500}`
EmptyResStr = `{"code":0}`
)
convey.Convey("PgcCards", t, func(c convey.C) {
c.Convey("Normal Situation, Then err should be nil.result should not be nil.", func(c convey.C) {
httpMock("GET", d.conf.Host.APINewindex).Reply(200).JSON(mockStr)
result, err := d.PgcCards(ctx, ids)
c.So(err, convey.ShouldBeNil)
c.So(result, convey.ShouldNotBeNil)
})
c.Convey("Http code Err Situation, Err can't be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.APINewindex).Reply(200).JSON(httpErrStr)
_, err := d.PgcCards(ctx, ids)
cx.So(err, convey.ShouldNotBeNil)
fmt.Println(err)
})
c.Convey("Empty Res Situation, Then err Should not be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.APINewindex).Reply(200).JSON(EmptyResStr)
_, err := d.PgcCards(ctx, ids)
cx.So(err, convey.ShouldNotBeNil)
fmt.Println(err)
})
})
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"context"
"net/url"
"go-common/app/interface/main/tv/conf"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
"fmt"
"github.com/pkg/errors"
)
// RecomData gets the recom data from PGC API
func (d *Dao) RecomData(ctx context.Context, appInfo *conf.TVApp, sid string, stype string) (result []*model.Recom, err error) {
var (
bangumiURL = d.conf.Host.APIRecom
params = url.Values{}
response = &model.ResponseRecom{}
)
params.Set("season_id", sid)
params.Set("season_type", stype)
params.Set("build", appInfo.Build)
params.Set("mobi_app", appInfo.MobiApp)
params.Set("platform", appInfo.Platform)
log.Info("[RecomData Request] URL: %s, Params: %s", bangumiURL, params.Encode())
if err = d.client.Get(ctx, bangumiURL, "", params, response); err != nil {
log.Error("RecomData ERROR:%v", err)
return
}
if response.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(response.Code), fmt.Sprintf("Bangumi API Error %v", response.Message))
log.Error("RecomData ERROR:%v, URL: %s", err, bangumiURL+"?"+params.Encode())
return
}
if response.Result == nil {
err = errors.Wrap(ecode.ServerErr, "bangumi api returns empty")
log.Error("RecomData ERROR:%v", err)
return
}
result = response.Result.List
log.Info("[RecomData] For Sid: %s, Stype: %s, Get PGC data NB: %d", sid, stype, len(result))
return
}

View File

@@ -0,0 +1,41 @@
package dao
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoRecomData(t *testing.T) {
var (
ctx = context.Background()
appInfo = d.conf.TVApp
sid = "20001"
stype = "4"
normalStr = `{"code":0,"message":"success","result":{"from":1,"list":[{"badge":"","badge_type":0,"cover":"http://i0.hdslb.com/bfs/bangumi/3a315d3dd6223adbd69d3361db9474f2d865aafd.jpg","follow_count":1864,"index_show":"全52集","is_finish":1,"is_started":1,"newest_ep_cover":"http://i0.hdslb.com/bfs/archive/aa02da8dc49f1cdfc8562efc50d455a14194287a.jpg","newest_ep_index":"52","play_count":494484,"season_id":22112,"season_status":2,"season_type":5,"season_type_name":"电视剧","title":"猎场DVD版","total_count":52,"url":"http://www.bilibili.com/bangumi/play/ss22112"}],"season_id":20001,"title":""}}`
httpErrStr = `{"code":-400}`
emptyStr = `{"code":0}`
)
convey.Convey("RecomData", t, func(c convey.C) {
c.Convey("Then err should be nil.result should not be nil.", func(c convey.C) {
httpMock("GET", d.conf.Host.APIRecom).Reply(200).JSON(normalStr)
result, err := d.RecomData(ctx, appInfo, sid, stype)
c.So(err, convey.ShouldBeNil)
c.So(result, convey.ShouldNotBeNil)
})
c.Convey("Http Err", func(c convey.C) {
httpMock("GET", d.conf.Host.APIRecom).Reply(200).JSON(httpErrStr)
_, err := d.RecomData(ctx, appInfo, sid, stype)
c.So(err, convey.ShouldNotBeNil)
fmt.Println(err)
})
c.Convey("Empty Result Err", func(c convey.C) {
httpMock("GET", d.conf.Host.APIRecom).Reply(200).JSON(emptyStr)
_, err := d.RecomData(ctx, appInfo, sid, stype)
c.So(err, convey.ShouldNotBeNil)
fmt.Println(err)
})
})
}

View File

@@ -0,0 +1,41 @@
package dao
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
)
// keyZone gets the key of the zone in Redis
func keyZone(category int) string {
return fmt.Sprintf("zone_idx_%d", category)
}
// ZrevrangeList picks up the page of ids .
func (d *Dao) ZrevrangeList(c context.Context, category int, start, end int) (sids []int64, count int, err error) {
conn := d.redis.Get(c)
defer conn.Close()
key := keyZone(category)
if err = conn.Send("ZREVRANGE", key, start, end); err != nil {
log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
return
}
if err = conn.Send("ZCARD", key); err != nil {
log.Error("conn.Do(ZCARD) err(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() err(%v)", err)
return
}
if sids, err = redis.Int64s(conn.Receive()); err != nil {
log.Error("redis.Int64s()err(%v)", err)
return
}
if count, err = redis.Int(conn.Receive()); err != nil {
log.Error("redis.INT64 err(%v)", err)
}
return
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaokeyZone(t *testing.T) {
var category = int(0)
convey.Convey("keyZone", t, func(c convey.C) {
p1 := keyZone(category)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoZrevrangeList(t *testing.T) {
var (
c = context.Background()
category = int(1)
start = int(0)
end = int(10)
)
convey.Convey("ZrevrangeList", t, func(ctx convey.C) {
sids, count, err := d.ZrevrangeList(c, category, start, end)
ctx.Convey("Then err should be nil.sids,count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
ctx.So(sids, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,48 @@
package dao
import (
"context"
"time"
"go-common/app/interface/main/tv/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_selectSQL = "SELECT page_id,title,index_type,index_tid FROM tv_pages WHERE deleted=0 AND valid=1 ORDER BY rank ASC"
_findMaxmTime = "SELECT max(mtime) FROM tv_pages WHERE deleted=0 AND valid=1"
)
// Regions .
func (d *Dao) Regions(c context.Context) (res []*model.Region, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _selectSQL); err != nil {
log.Error("d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.Region)
if err = rows.Scan(&r.PageID, &r.Title, &r.IndexType, &r.IndexTid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// FindLastMtime .
func (d *Dao) FindLastMtime(c context.Context) (res int64, err error) {
var m time.Time
if err = d.db.QueryRow(c, _findMaxmTime).Scan(&m); err != nil {
log.Error("d.db.QueryRow error(%v)", err)
return
}
res = m.Unix()
return
}

View File

@@ -0,0 +1,34 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoRegions(t *testing.T) {
convey.Convey("Regions", t, func(ctx convey.C) {
var c = context.Background()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Regions(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
println(len(res))
})
})
})
}
func TestDaoFindLastMtime(t *testing.T) {
convey.Convey("Regions", t, func(ctx convey.C) {
var c = context.Background()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Regions(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
println(len(res))
})
})
})
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"fmt"
"net/url"
"strconv"
"go-common/app/interface/main/tv/conf"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
// ChannelData gets the header data from PGC API
func (d *Dao) ChannelData(c context.Context, seasonType int, appInfo *conf.TVApp) (result []*model.Card, err error) {
var res struct {
Code int `json:"code"`
Result []*model.Card `json:"result"`
}
bangumiURL := d.conf.Host.APIZone
params := url.Values{}
params.Set("build", appInfo.Build)
params.Set("mobi_app", appInfo.MobiApp)
params.Set("platform", appInfo.Platform)
params.Set("season_type", strconv.Itoa(int(seasonType)))
if err = d.client.Get(c, bangumiURL, "", params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), bangumiURL+"?"+params.Encode())
return
}
if len(res.Result) == 0 {
err = ecode.TvPGCRankEmpty
log.Error("[LoadPGCList] Zone %d, Err %v", seasonType, err)
return
}
for _, v := range res.Result {
if v.NewEP != nil {
v.BePGC()
result = append(result, v)
}
}
if len(result) == 0 {
err = ecode.TvPGCRankNewEPNil
log.Error("[LoadPGCList] Zone %d, Err %v", seasonType, err)
}
return
}
// UgcAIData gets the ugc types rank data from AI
func (d *Dao) UgcAIData(c context.Context, tid int16) (result []*model.AIData, err error) {
var (
res model.RespAI
AIURL = fmt.Sprintf(d.conf.Host.AIUgcType, tid)
params = url.Values{}
)
if err = d.client.Get(c, AIURL, "", params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), AIURL+"?"+params.Encode())
return
}
result = res.List
return
}

View File

@@ -0,0 +1,72 @@
package dao
import (
"context"
"fmt"
"testing"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoChannelData(t *testing.T) {
var (
ctx = context.Background()
seasonType = int(0)
appInfo = d.conf.TVApp
)
convey.Convey("ChannelData", t, func(c convey.C) {
c.Convey("Then err should be nil.result should not be nil.", func(c convey.C) {
httpMock("GET", d.conf.Host.APIZone).Reply(200).
JSON(`{"code":0,"message":"success","result":[{"cover":"http://i0.hdslb.com/bfs/bangumi/75c7528cbf3254dd20a4512376ced74733ab98ef.jpg","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/8beff40b27076475353d25ca590d0932791f71d6.jpg","id":253907,"index":"中文","index_show":"全1话"},"season_id":25944,"title":"黑子的篮球 LAST GAME"},{"cover":"http://i0.hdslb.com/bfs/bangumi/3622ff139d6875c7b196edd3f9db7d0a3883a158.jpg","new_ep":{"cover":"http://i0.hdslb.com/bfs/archive/86ec94eb1e00785d15612b700e95eb309710597a.jpg","id":151657,"index":"序列之争","index_show":"全1话"},"season_id":12364,"title":"刀剑神域:序列之争"}]}`)
result, err := d.ChannelData(ctx, seasonType, appInfo)
c.So(err, convey.ShouldBeNil)
c.So(result, convey.ShouldNotBeNil)
})
c.Convey("We mock http error, The error should not be nil", func(c convey.C) {
httpMock("GET", d.conf.Host.APIZone).Reply(200).
JSON(`{"code":-100,"message":"fail","result":[]}`)
result, err := d.ChannelData(ctx, seasonType, appInfo)
c.So(err, convey.ShouldNotBeNil)
c.So(len(result), convey.ShouldBeZeroValue)
})
c.Convey("result empty error", func(c convey.C) {
httpMock("GET", d.conf.Host.APIZone).Reply(200).
JSON(`{"code":0,"message":"succ","result":[]}`)
result, err := d.ChannelData(ctx, seasonType, appInfo)
c.So(err, convey.ShouldEqual, ecode.TvPGCRankEmpty)
c.So(len(result), convey.ShouldBeZeroValue)
})
c.Convey("result not empty but NewEP empty error", func(c convey.C) {
httpMock("GET", d.conf.Host.APIZone).Reply(200).
JSON(`{"code":0,"message":"succ","result":[{"cover":"ttt"}]}`)
result, err := d.ChannelData(ctx, seasonType, appInfo)
c.So(err, convey.ShouldEqual, ecode.TvPGCRankNewEPNil)
c.So(len(result), convey.ShouldBeZeroValue)
})
})
}
func TestDaoUgcAIData(t *testing.T) {
var (
ctx = context.Background()
tid = int16(3)
normalStr = `{"note":"统计所有投稿在 2018年11月02日 - 2018年11月09日 的数据综合得分,每日更新一次","source_date":"2018-11-09","code":0,"num":250,"list":[{"aid":35129595,"mid":423442,"pts":571043,"play":277133,"coins":22257,"video_review":2949},{"aid":34994701,"mid":284120,"pts":272817,"play":103881,"coins":7543,"video_review":446},{"aid":35395331,"mid":314791153,"pts":270235,"play":160364,"coins":13475,"video_review":2586}]}`
httpCodeErr = `{"code":-100}`
url = fmt.Sprintf(d.conf.Host.AIUgcType, tid)
)
convey.Convey("UgcAIData", t, func(c convey.C) {
c.Convey("Then err should be nil.result should not be nil.", func(c convey.C) {
httpMock("GET", url).Reply(200).JSON(normalStr)
result, err := d.UgcAIData(ctx, tid)
c.So(err, convey.ShouldBeNil)
c.So(result, convey.ShouldNotBeNil)
})
c.Convey("Http code error", func(c convey.C) {
httpMock("GET", url).Reply(200).JSON(httpCodeErr)
_, err := d.UgcAIData(ctx, tid)
c.So(err, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,74 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"arctypes_test.go",
"dao_test.go",
"memcache_test.go",
"valid_test.go",
"view_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/view:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"arctypes.go",
"dao.go",
"memcache.go",
"valid.go",
"view.go",
],
importpath = "go-common/app/interface/main/tv/dao/archive",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/history/model:go_default_library",
"//app/interface/main/history/rpc/client:go_default_library",
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//app/interface/main/tv/model/view:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//library/cache/memcache: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/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,41 @@
package archive
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_realteURL = "/recsys/related"
)
// RelateAids get relate by aid
func (d *Dao) RelateAids(c context.Context, aid int64, ip string) (aids []int64, err error) {
params := url.Values{}
params.Set("key", strconv.FormatInt(aid, 10))
var res struct {
Code int `json:"code"`
Data []*struct {
Value string `json:"value"`
} `json:"data"`
}
if err = d.client.Get(c, d.relateURL, ip, params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), d.relateURL+"?"+params.Encode())
return
}
if len(res.Data) != 0 {
if aids, err = xstr.SplitInts(res.Data[0].Value); err != nil {
err = errors.Wrap(err, res.Data[0].Value)
}
}
return
}

View File

@@ -0,0 +1,28 @@
package archive
import (
"context"
"fmt"
"testing"
"go-common/library/database/sql"
. "github.com/smartystreets/goconvey/convey"
)
func getPassAid(db *sql.DB) (aid int64, err error) {
if err = db.QueryRow(context.Background(), "select aid from ugc_archive where deleted = 0 and valid = 1 and result = 1 limit 1").Scan(&aid); err != nil {
fmt.Println(err)
}
return
}
func TestDao_RelateAids(t *testing.T) {
Convey("TestDao_RelateAids", t, WithDao(func(d *Dao) {
httpMock("GET", d.relateURL).Reply(200).JSON(`{"data":[{"key": "1234", "value": "23999,515522,55,10099960,10099978,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959"}]}`)
aids, err := d.RelateAids(context.Background(), 333444, "")
So(err, ShouldBeNil)
So(len(aids), ShouldBeGreaterThan, 0)
fmt.Println(aids)
}))
}

View File

@@ -0,0 +1,120 @@
package archive
import (
"context"
"go-common/app/interface/main/tv/model"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/ecode"
"go-common/library/log"
)
// call ArcRPC for types data
func (d *Dao) loadTypes(ctx context.Context) {
var (
res = make(map[int32]*arcwar.Tp)
resRel = make(map[int32][]*arcwar.Tp)
reply *arcwar.TypesReply
err error
)
if reply, err = d.arcClient.Types(ctx, &arcwar.NoArgRequest{}); err != nil {
log.Error("arcRPC loadType Error %v", err)
return
}
res = reply.Types
log.Info("Reload Types Data! Len: %d", len(res))
for _, v := range res {
if v.Pid != 0 {
if _, ok := resRel[v.Pid]; !ok {
resRel[v.Pid] = []*arcwar.Tp{}
}
resRel[v.Pid] = append(resRel[v.Pid], v)
}
}
if len(res) > 0 {
d.arcTypes = res
}
if len(resRel) > 0 {
d.arcTypesRel = resRel
}
}
// GetPTypeName get first level of types name
func (d *Dao) GetPTypeName(typeID int32) (firstName string, secondName string) {
var (
second, first *arcwar.Tp
ok bool
)
if second, ok = d.arcTypes[typeID]; !ok {
log.Error("can't find type for ID: %d ", typeID)
return
}
secondName = second.Name
if first, ok = d.arcTypes[second.Pid]; !ok {
log.Error("can't find type for ID: %d, second Info: %v", second, second.Pid)
return
}
firstName = first.Name
return
}
// TargetTypes get all the ugc ranks that AI prepared for us
func (d *Dao) TargetTypes() (tids []int32, err error) {
if len(d.arcTypesRel) == 0 {
err = ecode.ServiceUnavailable
return
}
for _, v := range d.conf.Cfg.ZonesInfo.TargetTypes {
if children, ok := d.arcTypesRel[v]; ok { // second level types
for _, child := range children {
tids = append(tids, child.ID)
}
}
tids = append(tids, v)
}
return
}
// FirstTypes returns only first level of types
func (d *Dao) FirstTypes() (typeMap map[int32]*model.ArcType, err error) {
if len(d.arcTypes) == 0 {
err = ecode.ServiceUnavailable
return
}
typeMap = make(map[int32]*model.ArcType)
for _, v := range d.arcTypes { // only pick first level of types
if v.Pid == 0 {
typeMap[v.ID] = &model.ArcType{
ID: v.ID,
Name: v.Name,
}
}
}
return
}
// TypeInfo returns the type info
func (d *Dao) TypeInfo(typeid int32) (*arcwar.Tp, error) {
if len(d.arcTypes) == 0 {
return nil, ecode.ServiceUnavailable
}
info, ok := d.arcTypes[typeid]
if !ok {
return nil, ecode.NothingFound
}
return info, nil
}
// TypeChildren returns a first level's type children
func (d *Dao) TypeChildren(typeid int32) (children []*arcwar.Tp, err error) {
if len(d.arcTypesRel) == 0 {
err = ecode.ServiceUnavailable
return
}
children, found := d.arcTypesRel[typeid]
if !found {
err = ecode.NothingFound
return
}
return
}

View File

@@ -0,0 +1,78 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveloadTypes(t *testing.T) {
var (
c = context.Background()
)
convey.Convey("loadTypes", t, func(ctx convey.C) {
d.loadTypes(c)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveGetPTypeName(t *testing.T) {
var (
typeID = int32(3)
)
convey.Convey("GetPTypeName", t, func(ctx convey.C) {
firstName, secondName := d.GetPTypeName(typeID)
ctx.Convey("Then firstName,secondName should not be nil.", func(ctx convey.C) {
ctx.So(secondName, convey.ShouldNotBeNil)
ctx.So(firstName, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTargetTypes(t *testing.T) {
convey.Convey("TargetTypes", t, func(ctx convey.C) {
tids, err := d.TargetTypes()
ctx.Convey("Then err should be nil.tids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tids, convey.ShouldNotBeNil)
})
})
}
func TestArchiveFirstTypes(t *testing.T) {
convey.Convey("FirstTypes", t, func(ctx convey.C) {
typeMap, err := d.FirstTypes()
ctx.Convey("Then err should be nil.typeMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(typeMap, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTypeInfo(t *testing.T) {
var (
typeid = int32(3)
)
convey.Convey("TypeInfo", t, func(ctx convey.C) {
p1, err := d.TypeInfo(typeid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTypeChildren(t *testing.T) {
var (
typeid = int32(3)
)
convey.Convey("TypeChildren", t, func(ctx convey.C) {
children, err := d.TypeChildren(typeid)
ctx.Convey("Then err should be nil.children should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(children, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,89 @@
package archive
import (
"context"
"runtime"
"time"
hisrpc "go-common/app/interface/main/history/rpc/client"
"go-common/app/interface/main/tv/conf"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// Dao is archive dao.
type Dao struct {
// cfg
db *sql.DB
conf *conf.Config
relateURL string
// memory
arcTypes map[int32]*arcwar.Tp // map for arc types
arcTypesRel map[int32][]*arcwar.Tp // map for relation between arc type
// http client
client *bm.Client
// rpc
arcClient arcwar.ArchiveClient
hisRPC *hisrpc.Service
// memcache
arcMc *memcache.Pool
expireRlt int32
expireArc int32
expireView int32
// chan
mCh chan func()
}
// New new a archive dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// http client
client: bm.NewClient(c.HTTPClient),
// rpc
hisRPC: hisrpc.New(c.HisRPC),
// cfg
relateURL: c.Host.Data + _realteURL,
conf: c,
db: sql.NewMySQL(c.Mysql),
// memorry
arcTypes: make(map[int32]*arcwar.Tp),
arcTypesRel: make(map[int32][]*arcwar.Tp),
// memcache
arcMc: memcache.NewPool(c.Memcache.Config),
expireRlt: int32(time.Duration(c.Memcache.RelateExpire) / time.Second),
expireView: int32(time.Duration(c.Memcache.ViewExpire) / time.Second),
expireArc: int32(time.Duration(c.Memcache.ArcExpire) / time.Second),
// mc proc
mCh: make(chan func(), 10240),
}
var err error
if d.arcClient, err = arcwar.NewClient(c.ArcClient); err != nil {
panic(err)
}
// video db
for i := 0; i < runtime.NumCPU()*2; i++ {
go d.cacheproc()
}
d.loadTypes(context.Background())
return
}
// addCache add archive to mc or redis
func (d *Dao) addCache(f func()) {
select {
case d.mCh <- f:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc write memcache and stat redis use goroutine
func (d *Dao) cacheproc() {
for {
f := <-d.mCh
f()
}
}

View File

@@ -0,0 +1,51 @@
package archive
import (
"flag"
"os"
"strings"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func init() {
//dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
//flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,146 @@
package archive
import (
"context"
"strconv"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_prefixRelate = "al_"
_prefixViewStatic = "avp_"
_prefixArchive = "a3p_"
)
func keyRl(aid int64) string {
return _prefixRelate + strconv.FormatInt(aid, 10)
}
func keyView(aid int64) string {
return _prefixViewStatic + strconv.FormatInt(aid, 10)
}
func keyArc(aid int64) string {
return _prefixArchive + strconv.FormatInt(aid, 10)
}
// AddArcCache add arc cache
func (d *Dao) AddArcCache(aid int64, arc *arcwar.Arc) {
d.addCache(func() {
d.addArcCache(context.TODO(), aid, arc)
})
}
// AddRelatesCache add relates
func (d *Dao) AddRelatesCache(aid int64, rls []*view.Relate) {
d.addCache(func() {
d.addRelatesCache(context.TODO(), aid, rls)
})
}
// AddViewCache add view relates
func (d *Dao) AddViewCache(aid int64, vp *arcwar.ViewReply) {
d.addCache(func() {
d.addViewCache(context.TODO(), aid, vp)
})
}
// addViewCache add relates cache.
func (d *Dao) addViewCache(c context.Context, aid int64, vp *arcwar.ViewReply) (err error) {
conn := d.arcMc.Get(c)
key := keyView(aid)
item := &memcache.Item{Key: key, Object: vp, Flags: memcache.FlagJSON, Expiration: d.expireView}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, vp, d.expireView)
}
conn.Close()
return
}
// RelatesCache get relates.
func (d *Dao) RelatesCache(c context.Context, aid int64) (rls []*view.Relate, err error) {
conn := d.arcMc.Get(c)
key := keyRl(aid)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
return
}
if err = conn.Scan(r, &rls); err != nil {
err = errors.Wrapf(err, "conn.Scan(%s)", r.Value)
}
return
}
// addRelatesCache add relates cache.
func (d *Dao) addRelatesCache(c context.Context, aid int64, rls []*view.Relate) (err error) {
conn := d.arcMc.Get(c)
key := keyRl(aid)
item := &memcache.Item{Key: key, Object: rls, Flags: memcache.FlagJSON, Expiration: d.expireRlt}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, rls, d.expireRlt)
}
conn.Close()
return
}
// addRelatesCache add relates cache.
func (d *Dao) addArcCache(c context.Context, aid int64, cached *arcwar.Arc) (err error) {
conn := d.arcMc.Get(c)
key := keyArc(aid)
item := &memcache.Item{Key: key, Object: cached, Flags: memcache.FlagJSON, Expiration: d.expireArc}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, cached, d.expireArc)
}
conn.Close()
return
}
// arcsCache get archives cache.
func (d *Dao) arcsCache(c context.Context, aids []int64) (cached map[int64]*arcwar.Arc, missed []int64, err error) {
cached = make(map[int64]*arcwar.Arc, len(aids))
conn := d.arcMc.Get(c)
defer conn.Close()
keys := make([]string, 0, len(aids))
aidmap := make(map[string]int64, len(aids))
for _, aid := range aids {
k := keyArc(aid)
if _, ok := aidmap[k]; !ok {
keys = append(keys, k)
aidmap[k] = aid
}
}
rs, err := conn.GetMulti(keys)
if err != nil {
err = errors.Wrapf(err, "conn.GetMulti(%v)", keys)
return
}
for k, r := range rs {
a := &arcwar.Arc{}
if err = conn.Scan(r, a); err != nil {
log.Error("conn.Scan(%s) error(%v)", r.Value, err)
err = nil
continue
}
cached[aidmap[k]] = a
// delete hit key
delete(aidmap, k)
}
// missed key
missed = make([]int64, 0, len(aidmap))
for _, aid := range aidmap {
missed = append(missed, aid)
}
return
}

View File

@@ -0,0 +1,171 @@
package archive
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivekeyRl(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyRl", t, func(ctx convey.C) {
p1 := keyRl(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivekeyView(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyView", t, func(ctx convey.C) {
p1 := keyView(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivekeyArc(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyArc", t, func(ctx convey.C) {
p1 := keyArc(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveAddArcCache(t *testing.T) {
var (
aid = int64(123)
arc = &arcwar.Arc{
Aid: aid,
}
)
convey.Convey("AddArcCache", t, func(ctx convey.C) {
d.AddArcCache(aid, arc)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveAddRelatesCache(t *testing.T) {
var (
aid = int64(123)
rls = []*view.Relate{
{
Aid: aid,
},
}
)
convey.Convey("AddRelatesCache", t, func(ctx convey.C) {
d.AddRelatesCache(aid, rls)
d.addRelatesCache(context.TODO(), aid, rls)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveAddViewCache(t *testing.T) {
convey.Convey("AddViewCache", t, func(c convey.C) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.view3(context.Background(), aid)
fmt.Println(vp, " ", aid)
convey.So(err, convey.ShouldBeNil)
convey.So(vp, convey.ShouldNotBeNil)
d.AddViewCache(aid, vp)
c.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveaddViewCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
vp = &arcwar.ViewReply{}
)
convey.Convey("addViewCache", t, func(ctx convey.C) {
err := d.addViewCache(c, aid, vp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveRelatesCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
)
convey.Convey("RelatesCache", t, func(ctx convey.C) {
rls, err := d.RelatesCache(c, aid)
ctx.Convey("Then err should be nil.rls should not be nil.", func(ctx convey.C) {
fmt.Println(rls)
ctx.So(err, convey.ShouldBeNil)
ctx.So(rls, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddRelatesCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
rls = []*view.Relate{
{Aid: aid},
}
)
convey.Convey("addRelatesCache", t, func(ctx convey.C) {
err := d.addRelatesCache(c, aid, rls)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveaddArcCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
cached = &arcwar.Arc{Aid: 123}
)
convey.Convey("addArcCache", t, func(ctx convey.C) {
err := d.addArcCache(c, aid, cached)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivearcsCache(t *testing.T) {
var (
c = context.Background()
aids = []int64{123}
)
convey.Convey("arcsCache", t, func(ctx convey.C) {
cached, missed, err := d.arcsCache(c, aids)
ctx.Convey("Then err should be nil.cached,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(missed)+len(cached), convey.ShouldEqual, len(aids))
fmt.Println(cached)
fmt.Println(missed)
})
})
}

View File

@@ -0,0 +1,28 @@
package archive
import (
arcwar "go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
)
// validView distinguishes whether an view is valid
func validView(vp *arcwar.ViewReply, checkAttr bool) (valid bool) {
if vp == nil {
return
}
if vp.Arc == nil {
return
}
if vp.Arc.Aid == 0 {
return
}
if len(vp.Pages) == 0 {
return
}
if checkAttr {
if vp.Arc.AttrVal(archive.AttrBitIsMovie) == archive.AttrYes {
return // regard it as none
}
}
return true
}

View File

@@ -0,0 +1,21 @@
package archive
import (
"testing"
arcwar "go-common/app/service/main/archive/api"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivevalidView(t *testing.T) {
var (
vp = &arcwar.ViewReply{}
)
convey.Convey("validView", t, func(ctx convey.C) {
valid := validView(vp, true)
ctx.Convey("Then valid should not be nil.", func(ctx convey.C) {
ctx.So(valid, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,221 @@
package archive
import (
"context"
history "go-common/app/interface/main/history/model"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
// Archive3 picks one archive data
func (d *Dao) Archive3(c context.Context, aid int64) (arc *arcwar.Arc, err error) {
var (
arcReply *arcwar.ArcReply
arg = &arcwar.ArcRequest{Aid: aid}
)
arcReply, err = d.arcClient.Arc(c, arg)
if err != nil {
log.Error("d.arcRPC.Archive(%v) error(%+v)", arg, err)
if ecode.Cause(err) == ecode.NothingFound {
err = nil
return
}
}
arc = arcReply.Arc
return
}
// LoadViews picks view meta information from Cache & RPC
func (d *Dao) LoadViews(ctx context.Context, aids []int64) (resMetas map[int64]*arcwar.ViewReply) {
var (
missedMetas = make(map[int64]*arcwar.ViewReply)
addCache = true
)
resMetas = make(map[int64]*arcwar.ViewReply, len(aids))
cachedMetas, missed, err := d.ViewsCache(ctx, aids)
if err != nil {
log.Error("LoadViews ViewsCache Sids:%v, Error:%v", aids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
for _, vv := range missed {
if vp, _ := d.view3(ctx, vv); vp != nil {
missedMetas[vv] = vp
resMetas[vv] = vp
}
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
log.Info("LoadViews Info Hit %d, Missed %d", len(cachedMetas), len(missed))
if addCache && len(missedMetas) > 0 { // async Reset the DB data in MC for next time
log.Info("Set MissedMetas %d Data in MC", missedMetas)
for aid, vp := range missedMetas {
d.AddViewCache(aid, vp)
}
}
return
}
// GetView gets the aid's View info from Cache or RPC
func (d *Dao) GetView(c context.Context, aid int64) (vp *arcwar.ViewReply, err error) {
var (
addCache = false
)
if vp, err = d.viewCache(c, aid); err != nil {
log.Error("ViewPage viewCache AID %d, Err %v", aid, err)
}
if !validView(vp, true) { // back source
if vp, err = d.view3(c, aid); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
addCache = true
}
if !validView(vp, false) {
err = ecode.NothingFound
return
}
if addCache {
d.AddViewCache(aid, vp)
return
}
return
}
// view3 view archive with pages pb.
func (d *Dao) view3(c context.Context, aid int64) (reply *arcwar.ViewReply, err error) {
var arg = &arcwar.ViewRequest{Aid: aid}
if reply, err = d.arcClient.View(c, arg); err != nil {
log.Error("d.arcRPC.view3(%v) error(%+v)", arg, err)
if ecode.Cause(err) == ecode.NothingFound {
err = nil
return
}
}
return
}
// viewCache get view cache from remote memecache .
func (d *Dao) viewCache(c context.Context, aid int64) (vs *arcwar.ViewReply, err error) {
conn := d.arcMc.Get(c)
key := keyView(aid)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
return
}
vs = &arcwar.ViewReply{Arc: &arcwar.Arc{}}
if err = conn.Scan(r, vs); err != nil {
vs = nil
err = errors.Wrapf(err, "conn.Scan(%s)", r.Value)
}
return
}
// Progress is archive plays progress .
func (d *Dao) Progress(c context.Context, aid, mid int64) (h *view.History, err error) {
ip := metadata.String(c, metadata.RemoteIP)
arg := &history.ArgPro{Mid: mid, Aids: []int64{aid}, RealIP: ip}
his, err := d.hisRPC.Progress(c, arg)
if err != nil {
log.Error("d.hisRPC.Progress(%v) error(%v)", arg, err)
return
}
if his[aid] != nil {
h = &view.History{Cid: his[aid].Cid, Progress: his[aid].Pro}
}
return
}
// ViewsCache pick view from cache
func (d *Dao) ViewsCache(c context.Context, aids []int64) (cached map[int64]*arcwar.ViewReply, missed []int64, err error) {
if len(aids) == 0 {
return
}
var allKeys []string
cached = make(map[int64]*arcwar.ViewReply, len(aids))
idmap := make(map[string]int64, len(aids))
for _, id := range aids {
k := keyView(id)
allKeys = append(allKeys, k)
idmap[k] = id
}
conn := d.arcMc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
vp := &arcwar.ViewReply{}
if err = conn.Scan(item, vp); err != nil {
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
if !validView(vp, true) {
continue
}
cached[idmap[key]] = vp
delete(idmap, key)
}
missed = make([]int64, 0, len(idmap))
for _, id := range idmap {
missed = append(missed, id)
}
return
}
// Archives multi get archives.
func (d *Dao) Archives(c context.Context, aids []int64) (as map[int64]*arcwar.Arc, err error) {
if len(aids) == 0 {
return
}
var (
missed []int64
tmp map[int64]*arcwar.Arc
reply *arcwar.ArcsReply
)
if as, missed, err = d.arcsCache(c, aids); err != nil {
as = make(map[int64]*arcwar.Arc, len(aids))
missed = aids
log.Error("%+v", err)
err = nil
}
if len(missed) == 0 {
return
}
arg := &arcwar.ArcsRequest{Aids: missed}
if reply, err = d.arcClient.Arcs(c, arg); err != nil {
log.Error("d.arcRPC.Archives3(%v) error(%v)", arg, err)
if reply, err = d.arcClient.Arcs(c, arg); err != nil {
err = errors.Wrapf(err, "%v", arg)
return
}
}
tmp = reply.Arcs
for aid, a := range tmp {
as[aid] = a
d.AddArcCache(aid, a) // re-fill the cache
}
return
}

View File

@@ -0,0 +1,95 @@
package archive
import (
"context"
"encoding/json"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_View3(t *testing.T) {
Convey("view3", t, func() {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.view3(context.Background(), aid)
fmt.Println(vp, " ", aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
})
}
func Test_ViewCache(t *testing.T) {
Convey("viewCache", t, func() {
reply, err := d.viewCache(context.TODO(), 123)
So(reply, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func TestDao_Progress(t *testing.T) {
Convey("TestDao_Progress", t, func() {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
h, err := d.Progress(context.TODO(), aid, 88895137)
So(err, ShouldBeNil)
fmt.Println(h)
})
}
func TestDao_LoadViews(t *testing.T) {
Convey("TestDao_LoadViews", t, func() {
resMetas := d.LoadViews(context.Background(), []int64{10110328, 10099960})
data, _ := json.Marshal(resMetas)
fmt.Println(string(data))
})
}
func TestDao_Archives(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
as, err := d.Archives(context.Background(), []int64{aid})
So(err, ShouldBeNil)
So(len(as), ShouldBeGreaterThan, 0)
fmt.Println(as)
}))
}
func TestDao_GetView(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.GetView(context.Background(), aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
fmt.Println(vp)
}))
}
func TestDao_Archive3(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.Archive3(context.Background(), aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
fmt.Println(vp)
}))
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"audit.go",
"dao.go",
"transcode.go",
],
importpath = "go-common/app/interface/main/tv/dao/audit",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"audit_test.go",
"dao_test.go",
"transcode_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,50 @@
package audit
import (
"context"
xtime "time"
"go-common/app/interface/main/tv/model"
xsql "go-common/library/database/sql"
"go-common/library/time"
)
const (
_updateCont = "UPDATE `tv_content` SET `state` = ?, `valid` = ?, `reason` = ?, `inject_time` = ? WHERE `epid` = ? AND `is_deleted` = 0"
_updateSea = "UPDATE `tv_ep_season` SET `check` = ?, `valid` = ?, `reason` = ?, `inject_time` = ? WHERE `id` = ? AND `is_deleted` = 0"
_updateVideo = "UPDATE `ugc_video` SET `result` = ?, `valid` = ?, `reason` = ? , `inject_time` = ? WHERE `cid` = ? AND `deleted` = 0"
_updateArc = "UPDATE `ugc_archive` SET `result` = ?, `valid` = ?, `reason` = ?, `inject_time` = ? WHERE `aid` = ? AND `deleted` = 0"
)
// BeginTran def.
func (d *Dao) BeginTran(c context.Context) (tx *xsql.Tx, err error) {
return d.db.Begin(c)
}
// UpdateVideo .
func (d *Dao) UpdateVideo(c context.Context, v *model.AuditOp, tx *xsql.Tx) (err error) {
now := time.Time(xtime.Now().Unix())
_, err = tx.Exec(_updateVideo, v.Result, v.Valid, v.AuditMsg, now, v.KID)
return
}
// UpdateArc .
func (d *Dao) UpdateArc(c context.Context, v *model.AuditOp, tx *xsql.Tx) (err error) {
now := time.Time(xtime.Now().Unix())
_, err = tx.Exec(_updateArc, v.Result, v.Valid, v.AuditMsg, now, v.KID)
return
}
// UpdateCont .
func (d *Dao) UpdateCont(c context.Context, val *model.AuditOp, tx *xsql.Tx) (err error) {
now := time.Time(xtime.Now().Unix())
_, err = tx.Exec(_updateCont, val.Result, val.Valid, val.AuditMsg, now, val.KID)
return
}
// UpdateSea .
func (d *Dao) UpdateSea(c context.Context, val *model.AuditOp, tx *xsql.Tx) (err error) {
now := time.Time(xtime.Now().Unix())
_, err = tx.Exec(_updateSea, val.Result, val.Valid, val.AuditMsg, now, val.KID)
return
}

View File

@@ -0,0 +1,83 @@
package audit
import (
"context"
"go-common/app/interface/main/tv/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestAuditBeginTrans(t *testing.T) {
var (
c = context.Background()
)
convey.Convey("BeginTran", t, func(ctx convey.C) {
tx, err := d.BeginTran(c)
ctx.Convey("Then err should be nil.tx should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tx, convey.ShouldNotBeNil)
})
tx.Commit()
})
}
func TestAuditUpdateVideo(t *testing.T) {
var (
c = context.Background()
v = &model.AuditOp{}
tx, _ = d.BeginTran(c)
)
convey.Convey("UpdateVideo", t, func(ctx convey.C) {
err := d.UpdateVideo(c, v, tx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
tx.Commit()
})
}
func TestAuditUpdateArc(t *testing.T) {
var (
c = context.Background()
v = &model.AuditOp{}
tx, _ = d.BeginTran(c)
)
convey.Convey("UpdateArc", t, func(ctx convey.C) {
err := d.UpdateArc(c, v, tx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
tx.Commit()
})
}
func TestAuditUpdateCont(t *testing.T) {
var (
c = context.Background()
val = &model.AuditOp{}
tx, _ = d.BeginTran(c)
)
convey.Convey("UpdateCont", t, func(ctx convey.C) {
err := d.UpdateCont(c, val, tx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
tx.Commit()
})
}
func TestAuditUpdateSea(t *testing.T) {
var (
c = context.Background()
val = &model.AuditOp{}
tx, _ = d.BeginTran(c)
)
convey.Convey("UpdateSea", t, func(ctx convey.C) {
err := d.UpdateSea(c, val, tx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
tx.Commit()
})
}

View File

@@ -0,0 +1,24 @@
package audit
import (
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
)
// Dao is account dao.
type Dao struct {
mc *memcache.Pool
conf *conf.Config
db *sql.DB
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
conf: c,
mc: memcache.NewPool(c.Memcache.Config),
db: sql.NewMySQL(c.Mysql),
}
return
}

View File

@@ -0,0 +1,44 @@
package audit
import (
"context"
"flag"
"os"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
ctx = context.Background()
)
func init() {
//dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
//flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}

View File

@@ -0,0 +1,76 @@
package audit
import (
"context"
"fmt"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/time"
"go-common/library/xstr"
)
const (
_PgcCID = "SELECT `id` FROM `tv_content` WHERE `cid` = ? AND `is_deleted` = 0"
_UgcCID = "SELECT `id` FROM `ugc_video` WHERE `cid` = ? AND `deleted` = 0"
_transcodePGC = "UPDATE `tv_content` SET `transcoded` = ?, mark_time = NOW() WHERE `id` IN (%s) "
_transcodeUGC = "UPDATE `ugc_video` SET `transcoded` = ? WHERE `id` IN (%s)"
_applyPGC = "UPDATE `tv_content` SET `apply_time` = ? WHERE `id` IN (%s)"
)
// checkCID picks one ugc or pgc video data with its cid
func (d *Dao) checkCID(c context.Context, cid int64, query string) (ids []int64, err error) {
rows, err := d.db.Query(c, query, cid)
if err != nil {
log.Error("checkCID d.db.Query (%s) cid %d, error(%v)", query, cid, err)
return
}
defer rows.Close()
for rows.Next() {
var li int64
if err = rows.Scan(&li); err != nil {
log.Error("checkCID Query (%s) row.Scan error(%v)", query, err)
return
}
ids = append(ids, li)
}
if err = rows.Err(); err != nil {
log.Error("checkCID Query (%s) rows Err cid %d, err %v", query, cid, err)
return
}
if len(ids) == 0 {
err = ecode.NothingFound
}
return
}
// UgcCID picks one ugc video data with its cid
func (d *Dao) UgcCID(c context.Context, cid int64) (ids []int64, err error) {
return d.checkCID(c, cid, _UgcCID)
}
// PgcCID picks one ugc video data with its cid
func (d *Dao) PgcCID(c context.Context, cid int64) (ids []int64, err error) {
return d.checkCID(c, cid, _PgcCID)
}
func (d *Dao) updateCIDs(c context.Context, query string, value interface{}) (err error) {
if _, err = d.db.Exec(c, query, value); err != nil {
log.Error("updateCIDs, Query %s, d.db.Exec.error(%v)", query, err)
}
return
}
// PgcTranscode updates the transcoded status of an ep data
func (d *Dao) PgcTranscode(c context.Context, ids []int64, action int64) (err error) {
return d.updateCIDs(c, fmt.Sprintf(_transcodePGC, xstr.JoinInts(ids)), action)
}
// UgcTranscode updates the transcoded status of an ep data
func (d *Dao) UgcTranscode(c context.Context, ids []int64, action int64) (err error) {
return d.updateCIDs(c, fmt.Sprintf(_transcodeUGC, xstr.JoinInts(ids)), action)
}
// ApplyPGC saves pgc apply_time; only PGC needs this
func (d *Dao) ApplyPGC(c context.Context, ids []int64, aTime int64) (err error) {
return d.updateCIDs(c, fmt.Sprintf(_applyPGC, xstr.JoinInts(ids)), time.Time(aTime))
}

View File

@@ -0,0 +1,128 @@
package audit
import (
"fmt"
"testing"
"time"
"go-common/library/database/sql"
. "github.com/smartystreets/goconvey/convey"
)
func getCID(db *sql.DB, isPGC bool, double bool) (cid int64, err error) {
var query string
if isPGC {
if double {
query = "SELECT cid FROM tv_content WHERE is_deleted = 0 GROUP BY cid HAVING COUNT(1) >1 LIMIT 1"
} else {
query = "SELECT cid FROM tv_content WHERE is_deleted = 0 LIMIT 1"
}
} else {
if double {
query = "SELECT cid FROM ugc_video WHERE deleted = 0 GROUP BY cid HAVING COUNT(1) > 1 LIMIT 1"
} else {
query = "SELECT cid FROM ugc_video WHERE deleted = 0 LIMIT 1"
}
}
if err = db.QueryRow(ctx, query).Scan(&cid); err != nil {
fmt.Println("No Ready Video : ", err)
return
}
fmt.Println("pick CID ", cid)
return
}
func tryDouble(isPGC bool) (cid int64, err error) {
var errDouble error
if cid, errDouble = getCID(d.db, isPGC, true); errDouble != nil {
fmt.Println("Double Err ", errDouble, " Will Use Single")
if cid, err = getCID(d.db, isPGC, false); err != nil {
fmt.Println("Single Err ", err, " Will Fail")
return
}
}
return
}
func TestDao_UgcCID(t *testing.T) {
Convey("TestDao_UgcCID", t, WithDao(func(d *Dao) {
cid, errTry := tryDouble(false)
if errTry != nil {
fmt.Println("No Cid Ready")
return
}
cont, err := d.UgcCID(ctx, cid)
So(err, ShouldBeNil)
So(len(cont), ShouldBeGreaterThan, 0)
fmt.Println(cont)
}))
}
func TestDao_PgcCID(t *testing.T) {
Convey("TestDao_PgcCID", t, WithDao(func(d *Dao) {
cid, errTry := tryDouble(true)
if errTry != nil {
fmt.Println("No Cid Ready")
return
}
cont, err := d.PgcCID(ctx, cid)
So(err, ShouldBeNil)
So(len(cont), ShouldBeGreaterThan, 0)
fmt.Println(cont)
}))
}
func TestDao_UgcTranscode(t *testing.T) {
Convey("TestDao_UgcTranscode", t, WithDao(func(d *Dao) {
cid, errTry := tryDouble(false)
if errTry != nil {
fmt.Println("No Cid Ready")
return
}
cont, _ := d.UgcCID(ctx, cid)
if len(cont) == 0 {
fmt.Println("UgcCid Error!")
return
}
fmt.Println("To Update ", cont)
err := d.UgcTranscode(ctx, cont, 1)
So(err, ShouldBeNil)
}))
}
func TestDao_PgcTranscode(t *testing.T) {
Convey("TestDao_PgcTranscode", t, WithDao(func(d *Dao) {
cid, errTry := tryDouble(true)
if errTry != nil {
fmt.Println("No Cid Ready")
return
}
cont, _ := d.PgcCID(ctx, cid)
if len(cont) == 0 {
fmt.Println("PgcCid Error!")
return
}
fmt.Println("To Update ", cont)
err := d.PgcTranscode(ctx, cont, 1)
So(err, ShouldBeNil)
}))
}
func TestDao_ApplyPGC(t *testing.T) {
Convey("TestDao_ApplyPGC", t, WithDao(func(d *Dao) {
cid, errTry := tryDouble(true)
if errTry != nil {
fmt.Println("No Cid Ready")
return
}
cont, _ := d.PgcCID(ctx, cid)
if len(cont) == 0 {
fmt.Println("PgcCid Error!")
return
}
fmt.Println("To Update ", cont)
err := d.ApplyPGC(ctx, cont, time.Now().Unix())
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,80 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"backsource_test.go",
"dao_test.go",
"db_operate_test.go",
"err_msg_test.go",
"mixed_test.go",
"pgc_auth_test.go",
"pgc_batch_test.go",
"pgc_load_test.go",
"pgc_single_test.go",
"ugc_batch_test.go",
"ugc_load_test.go",
"ugc_single_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"backsource.go",
"dao.go",
"db_operate.go",
"err_msg.go",
"mixed.go",
"pgc_auth.go",
"pgc_batch.go",
"pgc_load.go",
"pgc_single.go",
"ugc_batch.go",
"ugc_load.go",
"ugc_single.go",
],
importpath = "go-common/app/interface/main/tv/dao/cms",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr: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,287 @@
package cms
import (
"context"
"database/sql"
"fmt"
"go-common/app/interface/main/tv/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_seasonCols = "SELECT id, cover, title , upinfo, `desc`, category, area, play_time, role, staff, total_num, style,origin_name,alias,status FROM tv_ep_season "
_epCols = "SELECT epid, cover, title, subtitle, pay_status FROM tv_content "
_seasonMetas = _seasonCols + " WHERE id IN (%s)"
_arcMetas = "SELECT title, aid, content, cover, typeid, pubtime, videos, valid, deleted, result FROM ugc_archive WHERE aid IN (%s)"
_videoMeta = "SELECT cid, eptitle, aid, index_order, valid, deleted, result FROM ugc_video WHERE cid = ?"
_videoMetas = "SELECT cid, eptitle, aid, index_order, valid, deleted, result FROM ugc_video WHERE cid IN (%s)"
_epMetas = _epCols + " WHERE epid IN (%s) AND is_deleted = 0 "
_simpleEPC = "SELECT `id`, `epid`, `state`, `is_deleted`, `valid`, `season_id` , `mark` FROM `tv_content` WHERE `epid` = ? LIMIT 1"
_simpleEPCs = "SELECT `id`, `epid`, `state`, `is_deleted`, `valid`, `season_id` , `mark` FROM `tv_content` WHERE `epid` IN (%s)"
_simpleSea = "SELECT `id`, `is_deleted`, `check`, `valid` FROM `tv_ep_season` WHERE `id` = ? LIMIT 1"
_simpleSeas = "SELECT `id`, `is_deleted`, `check`, `valid` FROM `tv_ep_season` WHERE `id` IN (%s)"
_seasonCMS = _seasonCols + "WHERE id = ? AND is_deleted = 0"
_epCMS = _epCols + " WHERE epid = ? AND is_deleted = 0 "
_newestOrder = "SELECT a.epid,b.`order` FROM tv_content a LEFT JOIN tv_ep_content b ON a.epid=b.id " +
"WHERE a.season_id=? AND a.state= ? AND a.valid= ? AND a.is_deleted=0 ORDER by `order` DESC LIMIT 1"
epStatePass = 3
_CMSValid = 1
)
// VideoMetaDB picks video from DB
func (d *Dao) VideoMetaDB(c context.Context, cid int64) (meta *model.VideoCMS, err error) {
rows, err := d.db.Query(c, _videoMeta, cid)
if err != nil {
log.Error("VideoMetaDB d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.VideoCMS{}
if err = rows.Scan(&li.CID, &li.Title, &li.AID, &li.IndexOrder, &li.Valid, &li.Deleted, &li.Result); err != nil {
log.Error("VideoMetaDB row.Scan error(%v)", err)
return
}
meta = li
}
return
}
// ArcMetaDB picks arc from DB
func (d *Dao) ArcMetaDB(c context.Context, aid int64) (meta *model.ArcCMS, err error) {
rows, err := d.db.Query(c, fmt.Sprintf(_arcMetas, fmt.Sprintf("%d", aid)))
if err != nil {
log.Error("ArcMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.ArcCMS{}
if err = rows.Scan(&li.Title, &li.AID, &li.Content, &li.Cover, &li.TypeID, &li.Pubtime, &li.Videos, &li.Valid, &li.Deleted, &li.Result); err != nil {
log.Error("ArcMetas row.Scan error(%v)", err)
return
}
meta = li
}
return
}
// VideoMetas picks video from DB
func (d *Dao) VideoMetas(c context.Context, cids []int64) (meta map[int64]*model.VideoCMS, err error) {
meta = make(map[int64]*model.VideoCMS)
rows, err := d.db.Query(c, fmt.Sprintf(_videoMetas, xstr.JoinInts(cids)))
if err != nil {
log.Error("VideoMetaDB d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.VideoCMS{}
if err = rows.Scan(&li.CID, &li.Title, &li.AID, &li.IndexOrder, &li.Valid, &li.Deleted, &li.Result); err != nil {
log.Error("VideoMetaDB row.Scan error(%v)", err)
return
}
meta[int64(li.CID)] = li
}
return
}
// ArcMetas picks seasons from DB
func (d *Dao) ArcMetas(c context.Context, aids []int64) (metas map[int64]*model.ArcCMS, err error) {
metas = make(map[int64]*model.ArcCMS)
rows, err := d.db.Query(c, fmt.Sprintf(_arcMetas, xstr.JoinInts(aids)))
if err != nil {
log.Error("ArcMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.ArcCMS{}
if err = rows.Scan(&li.Title, &li.AID, &li.Content, &li.Cover, &li.TypeID, &li.Pubtime, &li.Videos, &li.Valid, &li.Deleted, &li.Result); err != nil {
log.Error("ArcMetas row.Scan error(%v)", err)
return
}
metas[li.AID] = li
}
return
}
// SeasonMetas picks seasons from DB
func (d *Dao) SeasonMetas(c context.Context, sids []int64) (metas map[int64]*model.SeasonCMS, err error) {
metas = make(map[int64]*model.SeasonCMS)
rows, err := d.db.Query(c, fmt.Sprintf(_seasonMetas, xstr.JoinInts(sids)))
if err != nil {
log.Error("SeasonMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.SeasonCMS{}
// SELECT id, cover, title , upinfo, `desc`, category, area, play_time, role, staff, total_num, style, origin_name, status
if err = rows.Scan(&li.SeasonID, &li.Cover, &li.Title, &li.UpInfo, &li.Desc, &li.Category, &li.Area,
&li.Playtime, &li.Role, &li.Staff, &li.TotalNum, &li.Style, &li.OriginName, &li.Alias, &li.PayStatus); err != nil {
log.Error("SeasonMetas row.Scan error(%v)", err)
return
}
metas[int64(li.SeasonID)] = li
}
for _, v := range metas {
v.NewestEPID, v.NewestOrder, _ = d.NewestOrder(c, v.SeasonID)
}
return
}
// NewestOrder picks one season's newest passed ep's order column value
func (d *Dao) NewestOrder(c context.Context, sid int64) (epid int64, newestOrder int, err error) {
if err = d.db.QueryRow(c, _newestOrder, sid, epStatePass, _CMSValid).Scan(&epid, &newestOrder); err != nil { // get the qualified aid to sync
log.Warn("d.NewestOrder(sid %d).Query error(%v)", sid, err)
}
return
}
// EpMetas picks ep info from DB
func (d *Dao) EpMetas(c context.Context, epids []int64) (metas map[int64]*model.EpCMS, err error) {
metas = make(map[int64]*model.EpCMS)
rows, err := d.db.Query(c, fmt.Sprintf(_epMetas, xstr.JoinInts(epids)))
if err != nil {
log.Error("EpMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
li := &model.EpCMS{}
if err = rows.Scan(&li.EPID, &li.Cover, &li.Title, &li.Subtitle, &li.PayStatus); err != nil {
log.Error("EpMetas row.Scan error(%v)", err)
return
}
metas[li.EPID] = li
}
return
}
// EpAuthDB pick ep data from DB for Cache missing case
func (d *Dao) EpAuthDB(c context.Context, cid int64) (ep *model.EpAuth, err error) {
var row *xsql.Row
if row = d.db.QueryRow(c, _simpleEPC, cid); err != nil {
log.Error("d.db.QueryRow(%d) error(%v)", cid, err)
return
}
ep = &model.EpAuth{}
if err = row.Scan(&ep.ID, &ep.EPID, &ep.State, &ep.IsDeleted, &ep.Valid, &ep.SeasonID, &ep.NoMark); err != nil {
if err == sql.ErrNoRows {
err = nil
ep = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// SnAuthDB .
func (d *Dao) SnAuthDB(c context.Context, cid int64) (s *model.SnAuth, err error) {
var row *xsql.Row
if row = d.db.QueryRow(c, _simpleSea, cid); err != nil {
log.Error("d.db.QueryRow(%d) error(%v)", cid, err)
return
}
s = &model.SnAuth{}
if err = row.Scan(&s.ID, &s.IsDeleted, &s.Check, &s.Valid); err != nil {
if err == sql.ErrNoRows {
err = nil
s = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// SnsAuthDB .
func (d *Dao) SnsAuthDB(c context.Context, sids []int64) (snsAuth map[int64]*model.SnAuth, err error) {
snsAuth = make(map[int64]*model.SnAuth)
rows, err := d.db.Query(c, fmt.Sprintf(_simpleSeas, xstr.JoinInts(sids)))
if err != nil {
log.Error("ArcMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
s := &model.SnAuth{}
if err = rows.Scan(&s.ID, &s.IsDeleted, &s.Check, &s.Valid); err != nil {
log.Error("SnsAuthDB row.Scan error(%v)", err)
return
}
snsAuth[s.ID] = s
}
return
}
// EpsAuthDB def.
func (d *Dao) EpsAuthDB(c context.Context, epids []int64) (epsAuth map[int64]*model.EpAuth, err error) {
epsAuth = make(map[int64]*model.EpAuth)
rows, err := d.db.Query(c, fmt.Sprintf(_simpleEPCs, xstr.JoinInts(epids)))
if err != nil {
log.Error("ArcMetas d.db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
ep := &model.EpAuth{}
if err = rows.Scan(&ep.ID, &ep.EPID, &ep.State, &ep.IsDeleted, &ep.Valid, &ep.SeasonID, &ep.NoMark); err != nil {
log.Error("SnsAuthDB row.Scan error(%v)", err)
return
}
epsAuth[ep.EPID] = ep
}
return
}
// SeasonCMS gets the fields that can be changed from tv-cms side to offer the TV APP
func (d *Dao) SeasonCMS(c context.Context, sid int64) (season *model.SeasonCMS, err error) {
var row *xsql.Row
if row = d.db.QueryRow(c, _seasonCMS, sid); err != nil {
log.Error("d.db.QueryRow(%d) error(%v)", sid, err)
return
}
season = &model.SeasonCMS{}
// select id, cover, `desc`, title , upinfo, category, area, play_time, role, staff, total_num, style, status
if err = row.Scan(&season.SeasonID, &season.Cover, &season.Desc, &season.Title, &season.UpInfo,
&season.Category, &season.Area, &season.Playtime, &season.Role, &season.Staff, &season.TotalNum,
&season.Style, &season.OriginName, &season.Alias, &season.PayStatus); err != nil {
if err == sql.ErrNoRows {
err = nil
season = nil
} else {
log.Error("row.Scan(sid %d) error(%v)", sid, err)
}
return
}
// add newest info
season.NewestEPID, season.NewestOrder, _ = d.NewestOrder(c, sid)
return
}
// EpCMS gets the fields that can be changed from tv-cms side to offer the TV APP
func (d *Dao) EpCMS(c context.Context, epid int64) (ep *model.EpCMS, err error) {
var row *xsql.Row
if row = d.db.QueryRow(c, _epCMS, epid); err != nil {
log.Error("d.db.QueryRow(%d) error(%v)", epid, err)
return
}
ep = &model.EpCMS{}
// select id, cover, `desc`, title , upinfo, category, area, play_time, role, staff, total_num, style
if err = row.Scan(&ep.EPID, &ep.Cover, &ep.Title, &ep.Subtitle, &ep.PayStatus); err != nil {
if err == sql.ErrNoRows {
err = nil
ep = nil
} else {
log.Error("row.Scan(sid %d) error(%v)", epid, err)
}
return
}
return
}

View File

@@ -0,0 +1,344 @@
package cms
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/tv/model"
"go-common/library/database/sql"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsVideoMetaDB(t *testing.T) {
var (
c = context.Background()
cid = int64(0)
)
convey.Convey("VideoMetaDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.meta should not be nil.", func(ctx convey.C) {
sids, err := pickIDs(d.db, _pickCids)
if err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
cid = sids[0]
meta, err := d.VideoMetaDB(c, cid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(meta, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.VideoMetaDB(c, cid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsArcMetaDB(t *testing.T) {
var (
c = context.Background()
aid = int64(0)
)
convey.Convey("ArcMetaDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.meta should not be nil.", func(ctx convey.C) {
sids, err := pickIDs(d.db, _pickAids)
if err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
aid = sids[0]
meta, err := d.ArcMetaDB(c, aid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(meta, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.ArcMetaDB(c, aid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsVideoMetas(t *testing.T) {
var (
c = context.Background()
cids = []int64{}
err error
)
convey.Convey("VideoMetas", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.meta should not be nil.", func(ctx convey.C) {
if cids, err = pickIDs(d.db, _pickCids); err != nil || len(cids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
meta, err := d.VideoMetas(c, cids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(meta, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.VideoMetas(c, cids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsArcMetas(t *testing.T) {
var (
c = context.Background()
aids = []int64{}
err error
)
convey.Convey("ArcMetas", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.metas should not be nil.", func(ctx convey.C) {
if aids, err = pickIDs(d.db, _pickAids); err != nil || len(aids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
metas, err := d.ArcMetas(c, aids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(metas, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.ArcMetas(c, aids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsSeasonMetas(t *testing.T) {
var (
c = context.Background()
sids = []int64{}
err error
)
convey.Convey("SeasonMetas", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.metas should not be nil.", func(ctx convey.C) {
if sids, err = pickIDs(d.db, _pickSids); err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
metas, err := d.SeasonMetas(c, sids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(metas, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.SeasonMetas(c, sids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsNewestOrder(t *testing.T) {
var (
c = context.Background()
sid = int64(0)
)
convey.Convey("NewestOrder", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.epid,newestOrder should not be nil.", func(ctx convey.C) {
epid, newestOrder, err := d.NewestOrder(c, sid)
if err != nil {
ctx.So(err, convey.ShouldEqual, sql.ErrNoRows)
} else {
ctx.So(err, convey.ShouldBeNil)
ctx.So(newestOrder, convey.ShouldNotBeNil)
ctx.So(epid, convey.ShouldNotBeNil)
}
})
})
}
func TestCmsEpMetas(t *testing.T) {
var (
c = context.Background()
epids = []int64{}
err error
)
convey.Convey("EpMetas", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.metas should not be nil.", func(ctx convey.C) {
if epids, err = pickIDs(d.db, _pickEpids); err != nil || len(epids) == 0 {
fmt.Println("Empty epids ", err)
return
}
metas, err := d.EpMetas(c, epids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(metas, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.EpMetas(c, epids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsEpAuthDB(t *testing.T) {
var (
c = context.Background()
epid = int64(0)
)
convey.Convey("EpAuthDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.ep should not be nil.", func(ctx convey.C) {
epids, err := pickIDs(d.db, _pickEpids)
if err != nil || len(epids) == 0 {
fmt.Println("Empty epids ", err)
return
}
epid = epids[0]
ep, err := d.EpAuthDB(c, epid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(ep, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.EpAuthDB(c, epid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsSnAuthDB(t *testing.T) {
var (
c = context.Background()
sids []int64
sid int64
err error
)
convey.Convey("SnAuthDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.s should not be nil.", func(ctx convey.C) {
if sids, err = pickIDs(d.db, _pickSids); err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
sid = sids[0]
s, err := d.SnAuthDB(c, sid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(s, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.SnAuthDB(c, sid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsSnsAuthDB(t *testing.T) {
var (
c = context.Background()
sids []int64
err error
snsAuth map[int64]*model.SnAuth
)
convey.Convey("SnsAuthDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.snsAuth should not be nil.", func(ctx convey.C) {
if sids, err = pickIDs(d.db, _pickSids); err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
snsAuth, err = d.SnsAuthDB(c, sids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(snsAuth, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err = d.SnsAuthDB(c, sids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsEpsAuthDB(t *testing.T) {
var (
c = context.Background()
epids []int64
err error
epsAuth map[int64]*model.EpAuth
)
convey.Convey("EpsAuthDB", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.epsAuth should not be nil.", func(ctx convey.C) {
epids, err = pickIDs(d.db, _pickEpids)
if err != nil || len(epids) == 0 {
fmt.Println("Empty epids ", err)
return
}
epsAuth, err = d.EpsAuthDB(c, epids)
ctx.So(err, convey.ShouldBeNil)
ctx.So(epsAuth, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err = d.EpsAuthDB(c, epids)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsSeasonCMS(t *testing.T) {
var (
c = context.Background()
sids []int64
sid = int64(0)
err error
season *model.SeasonCMS
)
convey.Convey("SeasonCMS", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.season should not be nil.", func(ctx convey.C) {
sids, err = pickIDs(d.db, _pickSids)
if err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
sid = sids[0]
season, err = d.SeasonCMS(c, sid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(season, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err = d.SeasonCMS(c, sid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}
func TestCmsEpCMS(t *testing.T) {
var (
c = context.Background()
epid = int64(0)
)
convey.Convey("EpCMS", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.ep should not be nil.", func(ctx convey.C) {
epids, err := pickIDs(d.db, _pickEpids)
if err != nil || len(epids) == 0 {
fmt.Println("Empty epids ", err)
return
}
epid = epids[0]
ep, err := d.EpCMS(c, epid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(ep, convey.ShouldNotBeNil)
})
ctx.Convey("Db Error", func(ctx convey.C) {
d.db.Close()
_, err := d.EpCMS(c, epid)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}

View File

@@ -0,0 +1,72 @@
package cms
import (
"runtime"
"time"
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/stat/prom"
)
// Dao is account dao.
type Dao struct {
mc *memcache.Pool
conf *conf.Config
db *sql.DB
mCh chan func()
expireCMS int32
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
conf: c,
mc: memcache.NewPool(c.Memcache.Config),
db: sql.NewMySQL(c.Mysql),
mCh: make(chan func(), 10240),
expireCMS: int32(time.Duration(c.Memcache.CmsExpire) / time.Second),
}
// video db
for i := 0; i < runtime.NumCPU()*2; i++ {
go d.cacheproc()
}
return
}
// Prom
var (
errorsCount = prom.BusinessErrCount
infosCount = prom.BusinessInfoCount
cachedCount = prom.CacheHit
missedCount = prom.CacheMiss
)
// PromError prom error
func PromError(name string) {
errorsCount.Incr(name)
}
// PromInfo add prom info
func PromInfo(name string) {
infosCount.Incr(name)
}
// addCache add archive to mc or redis
func (d *Dao) addCache(f func()) {
select {
case d.mCh <- f:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc write memcache and stat redis use goroutine
func (d *Dao) cacheproc() {
for {
f := <-d.mCh
f()
}
}

View File

@@ -0,0 +1,121 @@
package cms
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"testing"
"go-common/app/interface/main/tv/conf"
"go-common/library/database/sql"
. "github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
ctx = context.TODO()
)
const (
_pickSids = 1
_pickEpids = 2
_pickAids = 3
_pickCids = 4
)
func init() {
// dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
// flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func pickIDs(db *sql.DB, ttype int) (testSids []int64, err error) {
var (
querySQL string
rows *sql.Rows
)
switch ttype {
case _pickSids:
querySQL = "SELECT DISTINCT(id) FROM tv_ep_season WHERE is_deleted = 0 ORDER BY id DESC LIMIT 20"
case _pickEpids:
querySQL = "SELECT DISTINCT(epid) FROM tv_content WHERE is_deleted = 0 ORDER BY id DESC LIMIT 20"
case _pickAids:
querySQL = "SELECT DISTINCT(aid) FROM ugc_archive WHERE deleted = 0 ORDER BY id DESC LIMIT 20"
case _pickCids:
querySQL = "SELECT DISTINCT(cid) FROM ugc_video WHERE deleted = 0 ORDER BY id DESC LIMIT 20"
}
rows, err = db.Query(ctx, querySQL)
if err != nil {
fmt.Println("Query Err ", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
fmt.Printf("Scan Id %d, Err %v", id, err)
return
}
testSids = append(testSids, id)
}
return
}
func TestDao_MixedFilter(t *testing.T) {
Convey("TestDao_MixedFilter", t, WithDao(func(d *Dao) {
sids, errDB := pickIDs(d.db, _pickSids)
if errDB != nil {
fmt.Println("PickSids Err ", errDB)
return
}
aids, errDB2 := pickIDs(d.db, _pickAids)
if errDB != nil {
fmt.Println("PickAids Err ", errDB2)
return
}
okSids, okAids := d.MixedFilter(ctx, sids, aids)
fmt.Println(okSids)
fmt.Println(okAids)
So(len(okSids), ShouldBeLessThanOrEqualTo, len(sids))
So(len(okAids), ShouldBeLessThanOrEqualTo, len(aids))
}))
}
func TestDao_LoadVideosMeta(t *testing.T) {
Convey("TestDao_MixedFilter", t, WithDao(func(d *Dao) {
sids, errDB := pickIDs(d.db, _pickCids)
if errDB != nil {
fmt.Println("PickSids Err ", errDB)
return
}
res, err := d.LoadVideosMeta(ctx, sids)
So(err, ShouldBeNil)
data, _ := json.Marshal(res)
fmt.Println(string(data))
}))
}

View File

@@ -0,0 +1,18 @@
package cms
import (
"context"
"fmt"
"go-common/library/xstr"
)
const (
_unshelveArcs = "UPDATE ugc_archive SET valid = 0 WHERE aid IN (%s) AND valid = 1 AND deleted = 0"
)
// UnshelveArcs unshelves the arcs
func (d *Dao) UnshelveArcs(c context.Context, ids []int64) (err error) {
_, err = d.db.Exec(c, fmt.Sprintf(_unshelveArcs, xstr.JoinInts(ids)))
return
}

View File

@@ -0,0 +1,21 @@
package cms
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsUnshelveArcs(t *testing.T) {
var (
c = context.Background()
ids = []int64{123}
)
convey.Convey("UnshelveArcs", t, func(ctx convey.C) {
err := d.UnshelveArcs(c, ids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,77 @@
package cms
import "go-common/app/interface/main/tv/model"
const (
// auth failure cases
_pgcOffline = "pgc_offline"
_cmsInvalid = "cms_invalid"
_licenseReject = "license_reject"
// auth correct values in DB
_contentOnline = 0
_snPass = 1
_epPass = 3
_cmsValid = 1
)
// AuthMsg returns the error message in the config according to the error condition
func (d *Dao) authMsg(cond string) (msg string) {
msgCfg := d.conf.Cfg.AuthMsg
if cond == _licenseReject {
return msgCfg.LicenseReject
}
if cond == _cmsInvalid {
return msgCfg.CMSInvalid
}
if cond == _pgcOffline {
return msgCfg.PGCOffline
}
return "err msg config load error"
}
// SnErrMsg returns the season auth result and the error message in case of auth failure
func (d *Dao) SnErrMsg(season *model.SnAuth) (bool, string) {
if season.IsDeleted == _contentOnline && season.Check == _snPass && season.Valid == _cmsValid {
return true, ""
}
if season.Check != _snPass {
return false, d.authMsg(_licenseReject)
}
if season.IsDeleted != _contentOnline {
return false, d.authMsg(_pgcOffline)
}
return false, d.authMsg(_cmsInvalid) // must be cms valid logically
}
// UgcErrMsg returns the arc auth result and the error message in case of auth failure
func (d *Dao) UgcErrMsg(deleted int, result int, valid int) (bool, string) {
if deleted == _contentOnline && result == _snPass && valid == _cmsValid {
return true, ""
}
if result != _snPass {
return false, d.authMsg(_licenseReject)
}
if deleted != _contentOnline {
return false, d.authMsg(_pgcOffline)
}
return false, d.authMsg(_cmsInvalid) // must be cms valid logically
}
// AuditingMsg returns the msg for the archive whose all videos are being audited
func (d *Dao) AuditingMsg() (bool, string) {
return false, d.authMsg(_licenseReject) // must be cms valid logically
}
// EpErrMsg returns the ep auth result and the error message in case of auth failure
func (d *Dao) EpErrMsg(ep *model.EpAuth) (bool, string) {
if ep.IsDeleted == _contentOnline && ep.State == _epPass && ep.Valid == _cmsValid {
return true, ""
}
if ep.State != _epPass {
return false, d.authMsg(_licenseReject)
}
if ep.IsDeleted != _contentOnline {
return false, d.authMsg(_pgcOffline)
}
return false, d.authMsg(_cmsInvalid) // must be cms valid logically
}

View File

@@ -0,0 +1,71 @@
package cms
import (
"go-common/app/interface/main/tv/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsauthMsg(t *testing.T) {
var (
cond = ""
)
convey.Convey("authMsg", t, func(ctx convey.C) {
msg := d.authMsg(cond)
ctx.Convey("Then msg should not be nil.", func(ctx convey.C) {
ctx.So(msg, convey.ShouldNotBeNil)
})
})
}
func TestCmsSnErrMsg(t *testing.T) {
var (
season = &model.SnAuth{}
)
convey.Convey("SnErrMsg", t, func(ctx convey.C) {
p1, p2 := d.SnErrMsg(season)
ctx.Convey("Then p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsUgcErrMsg(t *testing.T) {
var (
deleted = int(0)
result = int(0)
valid = int(0)
)
convey.Convey("UgcErrMsg", t, func(ctx convey.C) {
p1, p2 := d.UgcErrMsg(deleted, result, valid)
ctx.Convey("Then p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsAuditingMsg(t *testing.T) {
convey.Convey("AuditingMsg", t, func(ctx convey.C) {
p1, p2 := d.AuditingMsg()
ctx.Convey("Then p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsEpErrMsg(t *testing.T) {
var (
ep = &model.EpAuth{}
)
convey.Convey("EpErrMsg", t, func(ctx convey.C) {
p1, p2 := d.EpErrMsg(ep)
ctx.Convey("Then p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,67 @@
package cms
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// MixedFilter filters ugc and pgc data to get the allowed data
func (d *Dao) MixedFilter(ctx context.Context, sids []int64, aids []int64) (okSids map[int64]int, okAids map[int64]int) {
g, _ := errgroup.WithContext(ctx)
g.Go(func() (err error) {
okAids = d.aidsFilter(context.Background(), aids)
return
})
g.Go(func() (err error) {
okSids = d.sidsFilter(context.Background(), sids)
return
})
g.Wait()
return
}
// filter canPlay Aids
func (d *Dao) aidsFilter(ctx context.Context, aids []int64) (okAids map[int64]int) {
var (
arcMetas map[int64]*model.ArcCMS
err error
)
okAids = make(map[int64]int)
if arcMetas, err = d.LoadArcsMediaMap(ctx, aids); err != nil {
log.Error("MixedFilter Aids %v, Err %v", aids, err)
return
}
if len(arcMetas) == 0 {
return
}
for aid, arcMeta := range arcMetas {
if arcMeta.CanPlay() {
okAids[aid] = 1
}
}
return
}
// filter canPlay Sids
func (d *Dao) sidsFilter(ctx context.Context, sids []int64) (okSids map[int64]int) {
var (
snsAuth map[int64]*model.SnAuth
err error
)
okSids = make(map[int64]int)
if snsAuth, err = d.LoadSnsAuthMap(ctx, sids); err != nil {
log.Error("MixedFilter Sids %v, Err %v", sids, err)
}
if len(snsAuth) == 0 {
return
}
for sid, snAuth := range snsAuth {
if snAuth.CanPlay() {
okSids[sid] = 1
}
}
return
}

View File

@@ -0,0 +1,49 @@
package cms
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsMixedFilter(t *testing.T) {
var (
ctx = context.Background()
sids = []int64{}
aids = []int64{}
)
convey.Convey("MixedFilter", t, func(c convey.C) {
okSids, okAids := d.MixedFilter(ctx, sids, aids)
c.Convey("Then okSids,okAids should not be nil.", func(c convey.C) {
c.So(okAids, convey.ShouldNotBeNil)
c.So(okSids, convey.ShouldNotBeNil)
})
})
}
func TestCmsaidsFilter(t *testing.T) {
var (
ctx = context.Background()
aids = []int64{}
)
convey.Convey("aidsFilter", t, func(c convey.C) {
okAids := d.aidsFilter(ctx, aids)
c.Convey("Then okAids should not be nil.", func(c convey.C) {
c.So(okAids, convey.ShouldNotBeNil)
})
})
}
func TestCmssidsFilter(t *testing.T) {
var (
ctx = context.Background()
sids = []int64{}
)
convey.Convey("sidsFilter", t, func(c convey.C) {
okSids := d.sidsFilter(ctx, sids)
c.Convey("Then okSids should not be nil.", func(c convey.C) {
c.So(okSids, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,198 @@
package cms
import (
"context"
"fmt"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_mcEPKey = "ep_%d"
_mcSeasonKey = "sn_%d"
)
// SeaCacheKey .
func (d *Dao) SeaCacheKey(sid int64) string {
return fmt.Sprintf(_mcSeasonKey, sid)
}
// EPCacheKey .
func (d *Dao) EPCacheKey(epid int64) string {
return fmt.Sprintf(_mcEPKey, epid)
}
// GetSeasonCache get SnAuth cache.
func (d *Dao) GetSeasonCache(c context.Context, sid int64) (s *model.SnAuth, err error) {
var (
key = d.SeaCacheKey(sid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
// GetEPCache get EpAuth cache.
func (d *Dao) GetEPCache(c context.Context, epid int64) (ep *model.EpAuth, err error) {
var (
key = d.EPCacheKey(epid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &ep); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
// AddSnAuthCache save model.SnAuth to memcache
func (d *Dao) AddSnAuthCache(c context.Context, s *model.SnAuth) (err error) {
var (
key = d.SeaCacheKey(s.ID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: s, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}
// AddEpAuthCache save model.EpAuth to memcache
func (d *Dao) AddEpAuthCache(c context.Context, ep *model.EpAuth) (err error) {
var (
key = d.EPCacheKey(ep.EPID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: ep, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}
// snAuthCache season auth cache
func (d *Dao) snAuthCache(c context.Context, ids []int64) (cached map[int64]*model.SnAuth, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.SnAuth, len(ids))
idmap, allKeys := keysTreat(ids, d.SeaCacheKey)
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取Season信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
return
}
for key, item := range replys {
art := &model.SnAuth{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取Season信息缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = missedTreat(idmap, len(cached))
return
}
// epAuthCache ep auth cache
func (d *Dao) epAuthCache(c context.Context, ids []int64) (cached map[int64]*model.EpAuth, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.EpAuth, len(ids))
idmap, allKeys := keysTreat(ids, d.EPCacheKey)
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取EP信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
return
}
for key, item := range replys {
art := &model.EpAuth{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取EP信息缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = missedTreat(idmap, len(cached))
return
}
// SnAuth get's season auth info from Cache & DB
func (d *Dao) SnAuth(c context.Context, sid int64) (sn *model.SnAuth, err error) {
if sn, err = d.GetSeasonCache(c, sid); err != nil { // mc Error
return
} else if sn == nil { // mc not found, go DB
if sn, err = d.SnAuthDB(c, int64(sid)); err != nil { // DB error
log.Error("SnAuthDB (%d) ERROR (%v)", sid, err)
return
}
if sn == nil { // DB not found, build a fake item in MC to avoid checking DB next time
log.Error("SnAuthDB (%d) not found(%v) in DB", sid)
sn = &model.SnAuth{ID: int64(sid), Check: 0, IsDeleted: 1}
}
if err = d.AddSnAuthCache(c, sn); err != nil { // set item in MC ( not found - fake, or true )
log.Error("AddSnAuthCache fail(%v)", err)
}
}
return
}
// EpAuth get's ep auth info from Cache & DB
func (d *Dao) EpAuth(c context.Context, epid int64) (ep *model.EpAuth, err error) {
if ep, err = d.GetEPCache(c, epid); err != nil { // MC error
log.Error("GetEPCache(%d) Error(%v)", epid, err)
return
} else if ep == nil { // MC not found, go DB
if ep, err = d.EpAuthDB(c, epid); err != nil { // DB error
log.Error("DBSimpleEP(%d) ERROR (%v)", epid, err)
return
}
if ep == nil { // DB not found, build a fake item in MC to avoid checking DB next time
log.Error("EPID(%d) not found", epid)
ep = &model.EpAuth{EPID: epid, State: 4, IsDeleted: 1}
}
if err = d.AddEpAuthCache(c, ep); err != nil {
log.Error("AddEpAuthCache fail(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,134 @@
package cms
import (
"context"
"fmt"
"go-common/app/interface/main/tv/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsSeaCacheKey(t *testing.T) {
var (
sid = int64(0)
)
convey.Convey("SeaCacheKey", t, func(c convey.C) {
p1 := d.SeaCacheKey(sid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsEPCacheKey(t *testing.T) {
var (
epid = int64(0)
)
convey.Convey("EPCacheKey", t, func(c convey.C) {
p1 := d.EPCacheKey(epid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsGetSeasonCache(t *testing.T) {
var (
ctx = context.Background()
sid = int64(0)
)
convey.Convey("GetSeasonCache", t, func(c convey.C) {
s, err := d.GetSeasonCache(ctx, sid)
c.Convey("Then err should be nil.s should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(s, convey.ShouldNotBeNil)
})
})
}
func TestCmsGetEPCache(t *testing.T) {
var (
ctx = context.Background()
epid = int64(0)
)
convey.Convey("GetEPCache", t, func(c convey.C) {
ep, err := d.GetEPCache(ctx, epid)
c.Convey("Then err should be nil.ep should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(ep, convey.ShouldNotBeNil)
})
})
}
func TestCmsAddSnAuthCache(t *testing.T) {
var (
ctx = context.Background()
s = &model.SnAuth{}
)
convey.Convey("AddSnAuthCache", t, func(c convey.C) {
err := d.AddSnAuthCache(ctx, s)
c.Convey("Then err should be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
})
})
}
func TestCmsAddEpAuthCache(t *testing.T) {
var (
ctx = context.Background()
ep = &model.EpAuth{}
)
convey.Convey("AddEpAuthCache", t, func(c convey.C) {
err := d.AddEpAuthCache(ctx, ep)
c.Convey("Then err should be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
})
})
}
func TestCmssnAuthCache(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("snAuthCache", t, func(c convey.C) {
sids, errPick := pickIDs(d.db, _pickSids)
if errPick != nil || len(sids) == 0 {
fmt.Println("Empty sids ", errPick)
return
}
cached, missed, err := d.snAuthCache(ctx, sids)
c.Convey("Then err should be nil.cached,missed should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(len(missed)+len(cached), convey.ShouldBeGreaterThan, 0)
})
})
}
func TestCmsSnAuth(t *testing.T) {
var (
ctx = context.Background()
sid = int64(0)
)
convey.Convey("SnAuth", t, func(c convey.C) {
sn, err := d.SnAuth(ctx, sid)
c.Convey("Then err should be nil.sn should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(sn, convey.ShouldNotBeNil)
})
})
}
func TestCmsEpAuth(t *testing.T) {
var (
ctx = context.Background()
epid = int64(0)
)
convey.Convey("EpAuth", t, func(c convey.C) {
ep, err := d.EpAuth(ctx, epid)
c.Convey("Then err should be nil.ep should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(ep, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,152 @@
package cms
import (
"context"
"fmt"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_mcSnCMSKey = "sn_cms_%d"
_mcEPCMSKey = "ep_cms_%d"
)
func snCMSCacheKey(sid int64) string {
return fmt.Sprintf(_mcSnCMSKey, sid)
}
func epCMSCacheKey(epid int64) string {
return fmt.Sprintf(_mcEPCMSKey, epid)
}
func keysTreat(ids []int64, keyFunc func(int64) string) (idmap map[string]int64, allKeys []string) {
idmap = make(map[string]int64, len(ids))
for _, id := range ids {
k := keyFunc(id)
allKeys = append(allKeys, k)
idmap[k] = id
}
return
}
func missedTreat(idmap map[string]int64, lenCached int) (missed []int64) {
missed = make([]int64, 0, len(idmap))
for _, id := range idmap {
missed = append(missed, id)
}
missedCount.Add("tv-meta", int64(len(missed)))
cachedCount.Add("tv-meta", int64(lenCached))
return
}
// SeasonsMetaCache season cms meta cache
func (d *Dao) SeasonsMetaCache(c context.Context, ids []int64) (cached map[int64]*model.SeasonCMS, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.SeasonCMS, len(ids))
idmap, allKeys := keysTreat(ids, snCMSCacheKey)
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取Season信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
art := &model.SeasonCMS{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取Season信息缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = missedTreat(idmap, len(cached))
return
}
// EpMetaCache season cms meta cache
func (d *Dao) EpMetaCache(c context.Context, ids []int64) (cached map[int64]*model.EpCMS, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.EpCMS, len(ids))
allKeys := make([]string, 0, len(ids))
idmap := make(map[string]int64, len(ids))
for _, id := range ids {
k := epCMSCacheKey(id)
allKeys = append(allKeys, k)
idmap[k] = id
}
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取EP信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
art := &model.EpCMS{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取EP信息缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = make([]int64, 0, len(idmap))
for _, id := range idmap {
missed = append(missed, int64(id))
}
missedCount.Add("tv-meta", int64(len(missed)))
cachedCount.Add("tv-meta", int64(len(cached)))
return
}
//AddSeasonMetaCache add season meta cache
func (d *Dao) AddSeasonMetaCache(c context.Context, vs ...*model.SeasonCMS) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
for _, v := range vs {
if v == nil {
continue
}
item := &memcache.Item{Key: snCMSCacheKey(v.SeasonID), Object: v, Flags: memcache.FlagJSON, Expiration: d.expireCMS}
if err = conn.Set(item); err != nil {
PromError("mc:增加Season信息缓存")
log.Error("conn.Store(%s) error(%v)", snCMSCacheKey(v.SeasonID), err)
return
}
}
return
}
//AddEpMetaCache add ep meta cache
func (d *Dao) AddEpMetaCache(c context.Context, vs ...*model.EpCMS) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
for _, v := range vs {
if v == nil {
continue
}
item := &memcache.Item{Key: epCMSCacheKey(v.EPID), Object: v, Flags: memcache.FlagJSON, Expiration: d.expireCMS}
if err = conn.Set(item); err != nil {
PromError("mc:增加EP信息缓存")
log.Error("conn.Store(%s) error(%v)", epCMSCacheKey(v.EPID), err)
return
}
}
return
}

View File

@@ -0,0 +1,111 @@
package cms
import (
"context"
"fmt"
"go-common/app/interface/main/tv/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmssnCMSCacheKey(t *testing.T) {
var (
sid = int64(0)
)
convey.Convey("snCMSCacheKey", t, func(c convey.C) {
p1 := snCMSCacheKey(sid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsepCMSCacheKey(t *testing.T) {
var (
epid = int64(0)
)
convey.Convey("epCMSCacheKey", t, func(c convey.C) {
p1 := epCMSCacheKey(epid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmskeysTreat(t *testing.T) {
var (
ids = []int64{1, 2, 3}
keyFunc = snCMSCacheKey
)
convey.Convey("keysTreat", t, func(c convey.C) {
idmap, allKeys := keysTreat(ids, keyFunc)
c.Convey("Then idmap,allKeys should not be nil.", func(c convey.C) {
c.So(allKeys, convey.ShouldNotBeNil)
c.So(idmap, convey.ShouldNotBeNil)
})
})
}
func TestCmsmissedTreat(t *testing.T) {
var (
idmap map[string]int64
lenCached = int(0)
)
convey.Convey("missedTreat", t, func(c convey.C) {
missed := missedTreat(idmap, lenCached)
c.Convey("Then missed should not be nil.", func(c convey.C) {
c.So(missed, convey.ShouldNotBeNil)
})
})
}
func TestCmsEpMetaCache(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("EpMetaCache", t, func(c convey.C) {
c.Convey("Empty Input", func(c convey.C) {
cached, missed, err := d.EpMetaCache(ctx, []int64{})
c.So(err, convey.ShouldBeNil)
c.So(len(missed), convey.ShouldBeZeroValue)
c.So(len(cached), convey.ShouldBeZeroValue)
})
c.Convey("Normal Situation", func(c convey.C) {
epids, err := pickIDs(d.db, _pickEpids)
if err != nil || len(epids) == 0 {
fmt.Println("empty epids")
return
}
cached, missed, err := d.EpMetaCache(ctx, epids)
c.So(err, convey.ShouldBeNil)
c.So(len(missed)+len(cached), convey.ShouldNotEqual, 0)
})
})
}
func TestCmsAddSeasonMetaCache(t *testing.T) {
var (
ctx = context.Background()
vs = &model.SeasonCMS{}
)
convey.Convey("AddSeasonMetaCache", t, func(c convey.C) {
err := d.AddSeasonMetaCache(ctx, vs)
c.Convey("Then err should be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
})
})
}
func TestCmsAddEpMetaCache(t *testing.T) {
var (
ctx = context.Background()
vs = &model.EpCMS{}
)
convey.Convey("AddEpMetaCache", t, func(c convey.C) {
err := d.AddEpMetaCache(ctx, vs)
c.Convey("Then err should be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,226 @@
package cms
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
)
// LoadSnsAuthMap loads a batch of arc meta
func (d *Dao) LoadSnsAuthMap(ctx context.Context, sids []int64) (resMetas map[int64]*model.SnAuth, err error) {
var (
cachedMetas map[int64]*model.SnAuth // cache hit seasons
missedMetas map[int64]*model.SnAuth // cache miss seasons, pick from DB
missed []int64 // cache miss seasons
addCache = true // whether we need to fill DB data in MC
)
resMetas = make(map[int64]*model.SnAuth) // merge info from MC and from DB
if cachedMetas, missed, err = d.snAuthCache(ctx, sids); err != nil {
log.Error("LoadSnsAuthMap snAuthCache Sids:%v, Error:%v", sids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.SnsAuthDB(ctx, missed); err != nil {
log.Error("LoadSnsAuthMap SnsAuthDB Sids:%v, Error:%v", missed, err)
return
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
if addCache && len(missedMetas) > 0 {
for _, snAuth := range missedMetas {
d.addCache(func() {
d.AddSnAuthCache(ctx, snAuth)
})
}
}
return
}
// LoadEpsAuthMap loads a batch of arc meta
func (d *Dao) LoadEpsAuthMap(ctx context.Context, epids []int64) (resMetas map[int64]*model.EpAuth, err error) {
var (
cachedMetas map[int64]*model.EpAuth // cache hit seasons
missedMetas map[int64]*model.EpAuth // cache miss seasons, pick from DB
missed []int64 // cache miss seasons
addCache = true // whether we need to fill DB data in MC
)
resMetas = make(map[int64]*model.EpAuth) // merge info from MC and from DB
if cachedMetas, missed, err = d.epAuthCache(ctx, epids); err != nil {
log.Error("LoadEpsAuthMap epAuthCache epids:%v, Error:%v", epids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.EpsAuthDB(ctx, missed); err != nil {
log.Error("LoadEpsAuthMap EpsAuthDB epids:%v, Error:%v", missed, err)
return
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
if addCache && len(missedMetas) > 0 {
for _, epAuth := range missedMetas {
d.addCache(func() {
d.AddEpAuthCache(ctx, epAuth)
})
}
}
return
}
// LoadSnsCMSMap loads season cms meta data from cache and db
func (d *Dao) LoadSnsCMSMap(ctx context.Context, sids []int64) (resMetas map[int64]*model.SeasonCMS, err error) {
var (
cachedMetas, missedMetas map[int64]*model.SeasonCMS // cache hit seasons
missed []int64 // cache miss seasons
addCache = true // whether we need to fill DB data in MC
)
resMetas = make(map[int64]*model.SeasonCMS)
// pick up the information for these season ids
if cachedMetas, missed, err = d.SeasonsMetaCache(ctx, sids); err != nil {
log.Error("LoadSnsCMS SeasonMetaCache Sids:%v, Error:%v", sids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.SeasonMetas(ctx, missed); err != nil {
log.Error("LoadSnsCMS SeasonMetas Sids:%v, Error:%v", sids, err)
return
}
}
log.Info("Set Sids [%d], HitMetas [%d], MissedMetas [%d][%d] Data in MC", len(sids), len(cachedMetas), len(missed), len(missedMetas))
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
// async Reset the DB data in MC for next time
if addCache && len(missedMetas) > 0 {
for _, art := range missedMetas {
d.addCache(func() {
d.AddSeasonMetaCache(ctx, art)
})
}
}
return
}
// LoadSnsCMS loads the seasons meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadSnsCMS(ctx context.Context, sids []int64) (seasons []*model.SeasonCMS, newestEpids []int64, err error) {
var (
resMetas map[int64]*model.SeasonCMS // merge info from MC and from DB
)
if resMetas, err = d.LoadSnsCMSMap(ctx, sids); err != nil {
log.Error("LoadSnsCMS Sids %v, Err %v", sids, err)
return
}
// re-arrange the info, according to the order got from Redis
for _, v := range sids {
if SnCMS, ok := resMetas[v]; !ok {
log.Error("LoadSnsCMS Miss Info for Sid: %d", v)
continue
} else {
seasons = append(seasons, SnCMS)
newestEpids = append(newestEpids, SnCMS.NewestEPID)
}
}
return
}
// LoadSnCMS loads the sn meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadSnCMS(ctx context.Context, sid int64) (sn *model.SeasonCMS, err error) {
if sn, err = d.GetSnCMSCache(ctx, sid); err != nil {
log.Error("LoadSnsCMS Get Season[%d] from CMS Error (%v)", sid, err) // cache set/get error
return
}
if sn != nil { // if cache hit, return
return
}
if sn, err = d.SeasonCMS(ctx, sid); err != nil {
log.Error("[LoadSnCMS] SeasonCMS SeasonID ERROR (%d) (%v)", sid, err)
return
} else if sn == nil {
err = ecode.NothingFound
return
}
d.addCache(func() {
d.AddSeasonMetaCache(ctx, sn)
})
return
}
// LoadEpCMS loads the sn meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadEpCMS(ctx context.Context, epid int64) (ep *model.EpCMS, err error) {
if ep, err = d.GetEpCMSCache(ctx, epid); err != nil {
log.Error("LoadEpCMS Get EP[%d] from CMS Error (%v)", epid, err) // cache set/get error
return
} else if ep == nil {
if ep, err = d.EpCMS(ctx, epid); err != nil {
log.Error("[LoadEpCMS] EpCMS Epid ERROR (%d) (%v)", epid, err)
return
} else if ep == nil {
err = ecode.NothingFound
return
}
}
d.addCache(func() {
d.SetEpCMSCache(ctx, ep)
})
return
}
// LoadEpsCMS picks ep meta information from Cache & DB
func (d *Dao) LoadEpsCMS(ctx context.Context, epids []int64) (resMetas map[int64]*model.EpCMS, err error) {
var (
cachedMetas, missedMetas map[int64]*model.EpCMS
missed []int64
addCache = true
)
resMetas = make(map[int64]*model.EpCMS)
// pick up the information for these season ids
if cachedMetas, missed, err = d.EpMetaCache(ctx, epids); err != nil {
log.Error("loadEpCMS EpMetaCache Sids:%v, Error:%v", epids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.EpMetas(ctx, missed); err != nil {
log.Error("loadEpCMS EpMetas Sids:%v, Error:%v", epids, err)
return
}
}
// merge info from DB and the info from MC
resMetas = make(map[int64]*model.EpCMS, len(epids))
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
log.Info("Combine Info for %d Epids, Origin Length %d", len(epids), len(resMetas))
if addCache && len(missedMetas) > 0 { // async Reset the DB data in MC for next time
log.Info("Set MissedMetas %d Data in MC", missedMetas)
for _, art := range missedMetas {
d.addCache(func() {
d.AddEpMetaCache(ctx, art)
})
}
}
return
}

View File

@@ -0,0 +1,113 @@
package cms
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsLoadSnsAuthMap(t *testing.T) {
var (
ctx = context.Background()
sids = []int64{}
)
convey.Convey("LoadSnsAuthMap", t, func(c convey.C) {
resMetas, err := d.LoadSnsAuthMap(ctx, sids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(resMetas, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadEpsAuthMap(t *testing.T) {
var (
ctx = context.Background()
epids = []int64{}
)
convey.Convey("LoadEpsAuthMap", t, func(c convey.C) {
resMetas, err := d.LoadEpsAuthMap(ctx, epids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(resMetas, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadSnsCMSMap(t *testing.T) {
var (
ctx = context.Background()
sids = []int64{}
)
convey.Convey("LoadSnsCMSMap", t, func(c convey.C) {
resMetas, err := d.LoadSnsCMSMap(ctx, sids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(resMetas, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadSnsCMS(t *testing.T) {
var (
ctx = context.Background()
sids = []int64{}
err error
)
convey.Convey("LoadSnsCMS", t, func(c convey.C) {
c.Convey("Then err should be nil.seasons,newestEpids should not be nil.", func(cx convey.C) {
if sids, err = pickIDs(d.db, _pickSids); err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
seasons, newestEpids, err := d.LoadSnsCMS(ctx, sids)
cx.So(err, convey.ShouldBeNil)
cx.So(newestEpids, convey.ShouldNotBeNil)
cx.So(seasons, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadSnCMS(t *testing.T) {
var (
ctx = context.Background()
sid = int64(0)
)
convey.Convey("LoadSnCMS", t, func(c convey.C) {
sn, err := d.LoadSnCMS(ctx, sid)
c.Convey("Then err should be nil.sn should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(sn, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadEpCMS(t *testing.T) {
var (
ctx = context.Background()
epid = int64(0)
)
convey.Convey("LoadEpCMS", t, func(c convey.C) {
ep, err := d.LoadEpCMS(ctx, epid)
c.Convey("Then err should be nil.ep should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(ep, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadEpsCMS(t *testing.T) {
var (
ctx = context.Background()
epids = []int64{}
)
convey.Convey("LoadEpsCMS", t, func(c convey.C) {
resMetas, err := d.LoadEpsCMS(ctx, epids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(resMetas, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,85 @@
package cms
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
// GetSnCMSCache get SeasonCMS cache.
func (d *Dao) GetSnCMSCache(c context.Context, sid int64) (s *model.SeasonCMS, err error) {
var (
key = snCMSCacheKey(sid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
missedCount.Add("tv-meta", 1)
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
cachedCount.Add("tv-meta", 1)
return
}
// SetSnCMSCache save model.SeasonCMS to memcache
func (d *Dao) SetSnCMSCache(c context.Context, s *model.SeasonCMS) (err error) {
var (
key = snCMSCacheKey(s.SeasonID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: s, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}
// GetEpCMSCache get EpCMS cache.
func (d *Dao) GetEpCMSCache(c context.Context, epid int64) (s *model.EpCMS, err error) {
var (
key = epCMSCacheKey(epid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
missedCount.Add("tv-meta", 1)
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
cachedCount.Add("tv-meta", 1)
return
}
// SetEpCMSCache save model.EpCMS to memcache
func (d *Dao) SetEpCMSCache(c context.Context, s *model.EpCMS) (err error) {
var (
key = epCMSCacheKey(s.EPID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: s, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,77 @@
package cms
import (
"fmt"
"testing"
"go-common/app/interface/main/tv/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_SetSnCMSCache(t *testing.T) {
Convey("TestDao_SetSnCMSCache Test", t, WithDao(func(d *Dao) {
err := d.SetSnCMSCache(ctx, &model.SeasonCMS{
SeasonID: 6462,
Cover: "Test_cover1",
Title: "Test_title1",
Desc: "Test_desc1",
})
So(err, ShouldBeNil)
}))
}
func TestDao_GetSnCMSCache(t *testing.T) {
Convey("TestDao_GetSnCMSCache Test", t, WithDao(func(d *Dao) {
sids, errPick := pickIDs(d.db, _pickSids)
if errPick != nil || len(sids) == 0 {
fmt.Println("Empty sids ", errPick)
return
}
sid := sids[0]
d.LoadSnCMS(ctx, sid)
season, err := d.GetSnCMSCache(ctx, sid)
So(err, ShouldBeNil)
So(season, ShouldNotBeNil)
fmt.Println(*season)
}))
}
func TestDao_GetEpCMSCache(t *testing.T) {
Convey("TestDao_GetEpCMSCache Test", t, WithDao(func(d *Dao) {
sids, errPick := pickIDs(d.db, _pickEpids)
if errPick != nil || len(sids) == 0 {
fmt.Println("Empty sids ", errPick)
return
}
epid := sids[1]
ep, err := d.GetEpCMSCache(ctx, epid)
So(err, ShouldBeNil)
So(ep, ShouldNotBeNil)
fmt.Println(*ep)
}))
}
func TestDao_SnCMSCacheKey(t *testing.T) {
Convey("TestDao_SnCMSCacheKey Test", t, WithDao(func(d *Dao) {
key := snCMSCacheKey(177)
So(key, ShouldNotBeBlank)
fmt.Println(key)
}))
}
func TestDao_EPCMSCacheKey(t *testing.T) {
Convey("TestDao_EPCMSCacheKey Test", t, WithDao(func(d *Dao) {
key := epCMSCacheKey(1)
So(key, ShouldNotBeBlank)
fmt.Println(key)
}))
}
func TestDao_ArcCMSCacheKey(t *testing.T) {
Convey("TestDao_ArcCMSCacheKey Test", t, WithDao(func(d *Dao) {
key := d.ArcCMSCacheKey(177)
So(key, ShouldNotBeBlank)
fmt.Println(key)
}))
}

View File

@@ -0,0 +1,91 @@
package cms
import (
"context"
"fmt"
"go-common/app/interface/main/tv/model"
"go-common/library/log"
)
const (
_arcCMSDeleted = 1
_mcArcCMSKey = "arc_cms_%d"
_mcVideoCMSKey = "video_cms_%d"
)
// ArcCMSCacheKey .
func (d *Dao) ArcCMSCacheKey(aid int64) string {
return fmt.Sprintf(_mcArcCMSKey, aid)
}
// VideoCMSCacheKey .
func (d *Dao) VideoCMSCacheKey(cid int64) string {
return fmt.Sprintf(_mcVideoCMSKey, cid)
}
// ArcsMetaCache pick archive cms meta cache
func (d *Dao) ArcsMetaCache(c context.Context, ids []int64) (cached map[int64]*model.ArcCMS, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.ArcCMS, len(ids))
idmap, allKeys := keysTreat(ids, d.ArcCMSCacheKey)
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取Archive信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
art := &model.ArcCMS{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取Archive信息缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = missedTreat(idmap, len(cached))
return
}
// VideosMetaCache pick video cms meta cache
func (d *Dao) VideosMetaCache(c context.Context, ids []int64) (cached map[int64]*model.VideoCMS, missed []int64, err error) {
if len(ids) == 0 {
return
}
cached = make(map[int64]*model.VideoCMS, len(ids))
idmap, allKeys := keysTreat(ids, d.VideoCMSCacheKey)
conn := d.mc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
PromError("mc:获取Video信息缓存")
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
art := &model.VideoCMS{}
if err = conn.Scan(item, art); err != nil {
PromError("mc:获取Video信息缓存缓存json解析")
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
if art.Deleted == _arcCMSDeleted { // if it's deleted, we ignore it
log.Info("ArcCMS deleted, %v, %v", item, art)
continue
}
cached[idmap[key]] = art
delete(idmap, key)
}
missed = missedTreat(idmap, len(cached))
return
}

View File

@@ -0,0 +1,69 @@
package cms
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsArcCMSCacheKey(t *testing.T) {
var (
aid = int64(0)
)
convey.Convey("ArcCMSCacheKey", t, func(c convey.C) {
p1 := d.ArcCMSCacheKey(aid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsVideoCMSCacheKey(t *testing.T) {
var (
cid = int64(0)
)
convey.Convey("VideoCMSCacheKey", t, func(c convey.C) {
p1 := d.VideoCMSCacheKey(cid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestCmsArcsMetaCache(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("ArcsMetaCache", t, func(c convey.C) {
sids, errPick := pickIDs(d.db, _pickAids)
if errPick != nil || len(sids) == 0 {
fmt.Println("Empty sids ", errPick)
return
}
cached, missed, err := d.ArcsMetaCache(ctx, sids)
c.Convey("Then err should be nil.cached,missed should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(len(missed)+len(cached), convey.ShouldEqual, len(sids))
})
})
}
func TestCmsVideosMetaCache(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("VideosMetaCache", t, func(c convey.C) {
sids, errPick := pickIDs(d.db, _pickCids)
if errPick != nil || len(sids) == 0 {
fmt.Println("Empty sids ", errPick)
return
}
cached, missed, err := d.VideosMetaCache(ctx, sids)
c.Convey("Then err should be nil.cached,missed should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(len(missed)+len(cached), convey.ShouldEqual, len(sids))
})
})
}

View File

@@ -0,0 +1,148 @@
package cms
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
)
// LoadArcsMediaMap loads a batch of arc meta
func (d *Dao) LoadArcsMediaMap(ctx context.Context, aids []int64) (resMetas map[int64]*model.ArcCMS, err error) {
var (
cachedMetas map[int64]*model.ArcCMS // cache hit seasons
missedMetas map[int64]*model.ArcCMS // cache miss seasons, pick from DB
missed []int64 // cache miss seasons
addCache = true // whether we need to fill DB data in MC
)
resMetas = make(map[int64]*model.ArcCMS) // merge info from MC and from DB
// pick up the information for these season ids
if cachedMetas, missed, err = d.ArcsMetaCache(ctx, aids); err != nil {
log.Error("LoadArcsMedia ArcsMetaCache Aids:%v, Error:%v", aids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.ArcMetas(ctx, missed); err != nil {
log.Error("LoadArcsMedia ArcMetas Sids:%v, Error:%v", missed, err)
return
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
// async Reset the DB data in MC for next time
log.Info("Set Sids [%d], MissedMetas [%d] Data in MC", len(aids), len(missedMetas))
if addCache && len(missedMetas) > 0 {
for _, art := range missedMetas {
d.AddArcMetaCache(art)
}
}
return
}
// LoadVideosMeta picks the videos meta info
func (d *Dao) LoadVideosMeta(ctx context.Context, cids []int64) (resMetas map[int64]*model.VideoCMS, err error) {
var (
cachedMetas map[int64]*model.VideoCMS // cache hit seasons
missedMetas map[int64]*model.VideoCMS // cache miss seasons, pick from DB
missed []int64 // cache miss seasons
addCache = true // whether we need to fill DB data in MC
)
resMetas = make(map[int64]*model.VideoCMS) // merge info from MC and from DB
// pick up the information for these season ids
if cachedMetas, missed, err = d.VideosMetaCache(ctx, cids); err != nil {
log.Error("LoadVideosMeta VideosMetaCache Aids:%v, Error:%v", cids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
if missedMetas, err = d.VideoMetas(ctx, missed); err != nil {
log.Error("LoadVideosMeta VideoMetas Sids:%v, Error:%v", missed, err)
return
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
for sid, v := range missedMetas {
resMetas[sid] = v
}
// async Reset the DB data in MC for next time
log.Info("Set Sids [%d], MissedMetas [%d] Data in MC", len(cids), len(missedMetas))
if addCache && len(missedMetas) > 0 {
for _, art := range missedMetas {
d.AddVideoMetaCache(art)
}
}
return
}
// LoadArcsMedia loads the arc meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadArcsMedia(ctx context.Context, aids []int64) (arcs []*model.ArcCMS, err error) {
var (
resMetas map[int64]*model.ArcCMS // merge info from MC and from DB
)
if resMetas, err = d.LoadArcsMediaMap(ctx, aids); err != nil {
log.Error("LoadArcsMedia LoadArcsMediaMap Aids: %v, Err: %v", aids, err)
return
}
// re-arrange the info, according to the order got from Redis
for _, v := range aids {
if arcCMS, ok := resMetas[v]; !ok {
log.Error("PickDBeiPage LoadArcsMedia Miss Info for Sid: %d", v)
continue
} else {
arcs = append(arcs, arcCMS)
}
}
return
}
// LoadArcMeta loads the arc meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadArcMeta(ctx context.Context, aid int64) (arcMeta *model.ArcCMS, err error) {
if arcMeta, err = d.ArcMetaCache(ctx, aid); err != nil { // mc error
log.Error("LoadArcMedia Get Aid [%d] from CMS Error (%v)", aid, err)
return
}
if arcMeta != nil { // mc found
return
}
if arcMeta, err = d.ArcMetaDB(ctx, aid); err != nil { // db error
log.Error("LoadArcMedia ArcMetaDB Aid ERROR (%d) (%v)", aid, err)
return
}
if arcMeta == nil { // db not found
err = ecode.NothingFound
return
}
d.AddArcMetaCache(arcMeta) // db found, re-fill the cache
return
}
// LoadVideoMeta loads the video meta cms data from cache, for missed ones, pick them from the DB
func (d *Dao) LoadVideoMeta(ctx context.Context, cid int64) (videoMeta *model.VideoCMS, err error) {
if videoMeta, err = d.VideoMetaCache(ctx, cid); err != nil { // mc error
log.Error("LoadVideoMeta Get Cid [%d] from CMS Error (%v)", cid, err)
return
}
if videoMeta != nil { // mc found
return
}
if videoMeta, err = d.VideoMetaDB(ctx, cid); err != nil { // db error
log.Error("LoadArcMedia ArcMetaDB Aid ERROR (%d) (%v)", cid, err)
return
}
if videoMeta == nil { // db not found
err = ecode.NothingFound
return
}
d.AddVideoMetaCache(videoMeta) // db found, re-fill the cache
return
}

View File

@@ -0,0 +1,97 @@
package cms
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsLoadArcsMediaMap(t *testing.T) {
var ctx = context.Background()
convey.Convey("LoadArcsMediaMap", t, func(c convey.C) {
aids, errPick := pickIDs(d.db, _pickAids)
if errPick != nil || len(aids) == 0 {
fmt.Println("Empty aids ", errPick)
return
}
resMetas, err := d.LoadArcsMediaMap(ctx, aids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(resMetas, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadVideosMeta(t *testing.T) {
var (
ctx = context.Background()
cids = []int64{}
)
convey.Convey("LoadVideosMeta", t, func(c convey.C) {
resMetas, err := d.LoadVideosMeta(ctx, cids)
c.Convey("Then err should be nil.resMetas should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(resMetas, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadArcsMedia(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("LoadArcsMedia", t, func(c convey.C) {
aids, errPick := pickIDs(d.db, _pickAids)
if errPick != nil || len(aids) == 0 {
fmt.Println("Empty aids ", errPick)
return
}
arcs, err := d.LoadArcsMedia(ctx, aids)
c.Convey("Then err should be nil.arcs should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(arcs, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadArcMeta(t *testing.T) {
var (
ctx = context.Background()
aid = int64(0)
)
convey.Convey("LoadArcMeta", t, func(c convey.C) {
aids, errPick := pickIDs(d.db, _pickAids)
if errPick != nil || len(aids) == 0 {
fmt.Println("Empty aids ", errPick)
return
}
aid = aids[0]
arcMeta, err := d.LoadArcMeta(ctx, aid)
c.Convey("Then err should be nil.arcMeta should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(arcMeta, convey.ShouldNotBeNil)
})
})
}
func TestCmsLoadVideoMeta(t *testing.T) {
var (
ctx = context.Background()
cid = int64(0)
)
convey.Convey("LoadVideoMeta", t, func(c convey.C) {
aids, errPick := pickIDs(d.db, _pickCids)
if errPick != nil || len(aids) == 0 {
fmt.Println("Empty aids ", errPick)
return
}
cid = aids[0]
videoMeta, err := d.LoadVideoMeta(ctx, cid)
c.Convey("Then err should be nil.videoMeta should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(videoMeta, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,99 @@
package cms
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
// ArcMetaCache get arc cms cache.
func (d *Dao) ArcMetaCache(c context.Context, aid int64) (s *model.ArcCMS, err error) {
var (
key = d.ArcCMSCacheKey(aid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
missedCount.Add("tv-meta", 1)
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
cachedCount.Add("tv-meta", 1)
return
}
// SetArcMetaCache save model.ArcCMS to memcache
func (d *Dao) SetArcMetaCache(c context.Context, s *model.ArcCMS) (err error) {
var (
key = d.ArcCMSCacheKey(s.AID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: s, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}
// AddArcMetaCache add view relates
func (d *Dao) AddArcMetaCache(arc *model.ArcCMS) {
d.addCache(func() {
d.SetArcMetaCache(context.TODO(), arc)
})
}
// VideoMetaCache get video cms cache.
func (d *Dao) VideoMetaCache(c context.Context, cid int64) (s *model.VideoCMS, err error) {
var (
key = d.VideoCMSCacheKey(cid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
missedCount.Add("tv-meta", 1)
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
cachedCount.Add("tv-meta", 1)
return
}
// SetVideoMetaCache save model.VideoCMS to memcache
func (d *Dao) SetVideoMetaCache(c context.Context, s *model.VideoCMS) (err error) {
var (
key = d.VideoCMSCacheKey(s.CID)
conn = d.mc.Get(c)
)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Object: s, Flags: memcache.FlagJSON, Expiration: d.expireCMS}); err != nil {
log.Error("conn.Set error(%v)", err)
return
}
return
}
// AddVideoMetaCache add view relates
func (d *Dao) AddVideoMetaCache(video *model.VideoCMS) {
d.addCache(func() {
d.SetVideoMetaCache(context.TODO(), video)
})
}

View File

@@ -0,0 +1,105 @@
package cms
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/tv/model"
"github.com/smartystreets/goconvey/convey"
)
func TestCmsArcMetaCache(t *testing.T) {
var (
c = context.Background()
aid = int64(0)
)
convey.Convey("ArcMetaCache", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.s should not be nil.", func(ctx convey.C) {
sids, err := pickIDs(d.db, _pickAids)
if err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
aid = sids[0]
d.LoadArcMeta(c, aid)
s, err := d.ArcMetaCache(c, aid)
ctx.So(err, convey.ShouldBeNil)
ctx.So(s, convey.ShouldNotBeNil)
})
ctx.Convey("mc not found Error", func(ctx convey.C) {
_, err := d.ArcMetaCache(c, 0)
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestCmsSetArcMetaCache(t *testing.T) {
var (
c = context.Background()
s = &model.ArcCMS{}
)
convey.Convey("SetArcMetaCache", t, func(ctx convey.C) {
err := d.SetArcMetaCache(c, s)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestCmsAddArcMetaCache(t *testing.T) {
var (
arc = &model.ArcCMS{}
)
convey.Convey("AddArcMetaCache", t, func(ctx convey.C) {
d.AddArcMetaCache(arc)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestCmsVideoMetaCache(t *testing.T) {
var (
c = context.Background()
cid = int64(0)
)
convey.Convey("VideoMetaCache", t, func(ctx convey.C) {
sids, err := pickIDs(d.db, _pickCids)
if err != nil || len(sids) == 0 {
fmt.Println("Empty Sids ", err)
return
}
cid = sids[0]
d.LoadVideoMeta(c, cid)
s, err := d.VideoMetaCache(c, cid)
ctx.Convey("Then err should be nil.s should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(s, convey.ShouldNotBeNil)
})
})
}
func TestCmsSetVideoMetaCache(t *testing.T) {
var (
c = context.Background()
s = &model.VideoCMS{}
)
convey.Convey("SetVideoMetaCache", t, func(ctx convey.C) {
err := d.SetVideoMetaCache(c, s)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestCmsAddVideoMetaCache(t *testing.T) {
var (
video = &model.VideoCMS{}
)
convey.Convey("AddVideoMetaCache", t, func(ctx convey.C) {
d.AddVideoMetaCache(video)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}

View File

@@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/tv/dao/favorite",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//app/service/main/favorite/api/gorpc:go_default_library",
"//app/service/main/favorite/model: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",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,103 @@
package favorite
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/tv/conf"
"go-common/app/interface/main/tv/model"
favrpc "go-common/app/service/main/favorite/api/gorpc"
favmdl "go-common/app/service/main/favorite/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
// Dao is account dao.
type Dao struct {
favRPC *favrpc.Service // rpc
conf *conf.Config
client *bm.Client
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
favRPC: favrpc.New2(c.FavoriteRPC),
conf: c,
client: bm.NewClient(c.HTTPClient),
}
return
}
const (
_FavBusiness = 2
_DefaultFav = 0
)
// FavoriteV3 picks favorite info from rpc
func (d *Dao) FavoriteV3(ctx context.Context, mid int64, pn int) (res *favmdl.Favorites, err error) {
var ip = metadata.String(ctx, metadata.RemoteIP)
arg := &favmdl.ArgFavs{
Type: _FavBusiness,
Mid: mid,
Fid: _DefaultFav,
Tv: 1,
Pn: pn,
Ps: d.conf.Cfg.FavPs,
RealIP: ip,
}
if res, err = d.favRPC.Favorites(ctx, arg); err != nil {
err = errors.Wrapf(err, "%v", arg)
}
return
}
// favAct adds/deletes favorite into/from the default folder
func (d *Dao) favAct(ctx context.Context, mid int64, aid int64, host string) (err error) {
var (
ip = metadata.String(ctx, metadata.RemoteIP)
params = url.Values{}
res = model.RespFavAct{}
)
params.Set("mid", fmt.Sprintf("%d", mid))
params.Set("aid", fmt.Sprintf("%d", aid))
if err = d.client.Post(ctx, host, ip, params, &res); err != nil {
log.Error("FavAdd Aid %d, Mid %d, Err %v", aid, mid, err)
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), fmt.Sprintf("Fav AID %d, Mid %d, API Error %s", aid, mid, res.Message))
log.Error("FavAdd ERROR:%v, URL: %s", err, host+"?"+params.Encode())
return
}
return
}
// FavAdd def.
func (d *Dao) FavAdd(ctx context.Context, mid, aid int64) (err error) {
host := d.conf.Host.FavAdd
return d.favAct(ctx, mid, aid, host)
}
// FavDel deletes favorite from the default folder
func (d *Dao) FavDel(ctx context.Context, mid int64, aid int64) (err error) {
host := d.conf.Host.FavDel
return d.favAct(ctx, mid, aid, host)
}
// InDefault returns whether the aid is in Default of Mid
func (d *Dao) InDefault(ctx context.Context, mid int64, aid int64) (bool, error) {
var ip = metadata.String(ctx, metadata.RemoteIP)
arg := &favmdl.ArgInDefaultFolder{
Type: _FavBusiness,
Mid: mid,
RealIP: ip,
Oid: aid,
}
return d.favRPC.InDefault(ctx, arg)
}

View File

@@ -0,0 +1,76 @@
package favorite
import (
"context"
"encoding/json"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/tv/conf"
"fmt"
. "github.com/smartystreets/goconvey/convey"
)
var d *Dao
func init() {
dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
flag.Set("conf", dir)
conf.Init()
d = New(conf.Conf)
time.Sleep(5 * time.Second)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func TestDao_FavoriteV3(t *testing.T) {
Convey("TestDao_FavoriteV3", t, func() {
res, err := d.FavoriteV3(context.Background(), 88894921, 1)
So(err, ShouldBeNil)
data, _ := json.Marshal(res)
Println(string(data))
})
}
func TestDao_FavAdd(t *testing.T) {
Convey("TestDao_FavAdd", t, func() {
err := d.FavAdd(context.Background(), 88894921, 10098813)
So(err, ShouldBeNil)
err = d.FavAdd(context.Background(), 88894921, 28417042)
So(err, ShouldBeNil)
})
}
func TestDao_FavDel(t *testing.T) {
Convey("TestDao_FavDel", t, func() {
err := d.FavDel(context.Background(), 88894921, 28417042)
So(err, ShouldBeNil)
})
}
func TestDao_InDefault(t *testing.T) {
Convey("TestDao_InDefault", t, WithDao(func(d *Dao) {
var mid = int64(27515418)
res, err := d.FavoriteV3(context.Background(), mid, 1)
So(err, ShouldBeNil)
if res == nil || len(res.List) == 0 {
fmt.Println("empty Fav")
return
}
exist, err2 := d.InDefault(context.Background(), mid, res.List[0].Oid)
So(err2, ShouldBeNil)
So(exist, ShouldBeTrue)
exist, err2 = d.InDefault(context.Background(), mid, 888888888888)
So(err2, ShouldBeNil)
So(exist, ShouldBeFalse)
}))
}

View File

@@ -0,0 +1,71 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"hotword.go",
"label.go",
"splash.go",
"ugc_playurl.go",
"upgrade.go",
],
importpath = "go-common/app/interface/main/tv/dao/goblin",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//app/interface/main/tv/model/goblin:go_default_library",
"//library/cache/memcache: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",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"hotword_test.go",
"label_test.go",
"splash_test.go",
"ugc_playurl_test.go",
"upgrade_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)

View File

@@ -0,0 +1,26 @@
package goblin
import (
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
)
// Dao .
type Dao struct {
conf *conf.Config
client *bm.Client
db *sql.DB
mc *memcache.Pool
}
// New .
func New(c *conf.Config) *Dao {
return &Dao{
conf: c,
client: bm.NewClient(c.PlayurlClient),
db: sql.NewMySQL(c.Mysql),
mc: memcache.NewPool(c.Memcache.Config),
}
}

View File

@@ -0,0 +1,49 @@
package goblin
import (
"flag"
"os"
"strings"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
var d *Dao
func init() {
//dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
//flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,23 @@
package goblin
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
)
const _hotwordKey = "_tv_search"
// Hotword get hotword cache.
func (d *Dao) Hotword(c context.Context) (s []*model.Hotword, err error) {
var (
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(_hotwordKey); err != nil {
return
}
err = conn.Scan(item, &s)
return
}

View File

@@ -0,0 +1,33 @@
package goblin
import (
"testing"
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_Hotword(t *testing.T) {
Convey("Hotword Test", t, WithDao(func(d *Dao) {
ctx := context.TODO()
conn := d.mc.Get(ctx)
s := []*model.Hotword{
{
Keyword: "Test1",
},
{
Keyword: "Test2",
},
}
defer conn.Close()
err := conn.Set(&memcache.Item{Key: _hotwordKey, Object: s, Flags: memcache.FlagJSON, Expiration: 1200})
So(err, ShouldBeNil)
hotwordList, err := d.Hotword(ctx)
So(err, ShouldBeNil)
So(len(hotwordList), ShouldBeGreaterThan, 0)
}))
}

View File

@@ -0,0 +1,30 @@
package goblin
import (
"context"
gbmdl "go-common/app/interface/main/tv/model/goblin"
)
const (
_labelSQL = "SELECT id,name,param, param_name,value FROM tv_label WHERE category = ? AND cat_type = ? AND valid = 1 AND deleted = 0" +
" ORDER BY position,id ASC "
)
// Label picks one category's label
func (d *Dao) Label(c context.Context, category, catType int) (res []*gbmdl.Label, err error) {
rows, err := d.db.Query(c, _labelSQL, category, catType)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
li := &gbmdl.Label{}
if err = rows.Scan(&li.ID, &li.Name, &li.Param, &li.ParamName, &li.Value); err != nil {
return
}
res = append(res, li)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,31 @@
package goblin
import (
"context"
"testing"
"go-common/library/database/sql"
"github.com/smartystreets/goconvey/convey"
)
func TestGoblinLabel(t *testing.T) {
var (
c = context.Background()
category = int(1)
catType = int(1)
)
convey.Convey("Label", t, func(ctx convey.C) {
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
res, err := d.Label(c, category, catType)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
ctx.Convey("db closed", func(ctx convey.C) {
d.db.Close()
_, err := d.Label(c, category, catType)
ctx.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}

View File

@@ -0,0 +1,28 @@
package goblin
import (
"context"
"go-common/app/interface/main/tv/model"
)
const (
_getChl = "SELECT id, title, `desc`, splash FROM tv_channel WHERE deleted = 0"
)
// ChlInfo .
func (d *Dao) ChlInfo(c context.Context) (chls []*model.Channel, err error) {
rows, err := d.db.Query(c, _getChl)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
li := &model.Channel{}
if err = rows.Scan(&li.ID, &li.Title, &li.Desc, &li.Splash); err != nil {
return
}
chls = append(chls, li)
}
return
}

View File

@@ -0,0 +1,29 @@
package goblin
import (
"context"
"testing"
"go-common/library/database/sql"
"github.com/smartystreets/goconvey/convey"
)
func TestGoblinChlInfo(t *testing.T) {
var (
ctx = context.Background()
)
convey.Convey("ChlInfo", t, func(c convey.C) {
c.Convey("Then err should be nil.chls should not be nil.", func(c convey.C) {
chls, err := d.ChlInfo(ctx)
c.So(err, convey.ShouldBeNil)
c.So(chls, convey.ShouldNotBeNil)
})
c.Convey("db closed", func(c convey.C) {
d.db.Close()
_, err := d.ChlInfo(ctx)
c.So(err, convey.ShouldNotBeNil)
d.db = sql.NewMySQL(d.conf.Mysql)
})
})
}

View File

@@ -0,0 +1,64 @@
package goblin
import (
"context"
"encoding/json"
xhttp "net/http"
"net/url"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
_httpHeaderRemoteIP = "x-backend-bili-real-ip"
)
// UgcPlayurl is use for get ugc play url
func (d *Dao) UgcPlayurl(ctx context.Context, p *model.PlayURLReq) (res map[string]interface{}, resp *model.PlayURLResp, err error) {
var (
params = url.Values{}
url = d.conf.Host.UgcPlayURL
bs []byte
req *xhttp.Request
ip = metadata.String(ctx, metadata.RemoteIP)
)
res = make(map[string]interface{})
params.Set("platform", p.Platform)
params.Set("device", p.Device)
params.Set("expire", p.Expire)
params.Set("build", p.Build)
params.Set("mid", p.Mid)
params.Set("qn", p.Qn)
params.Set("npcybs", p.Npcybs)
params.Set("buvid", p.Buvid)
params.Set("otype", "json")
params.Set("trackPath", p.TrackPath)
params.Set("cid", p.Cid)
params.Set("access_key", p.AccessKey)
params.Set("platform", "tvproj")
if req, err = d.client.NewRequest(xhttp.MethodGet, url, ip, params); err != nil {
return
}
if ip != "" { // add ip into header
req.Header.Set(_httpHeaderRemoteIP, ip)
}
log.Info("ugcPlayURL Cid %d, IP %s", p.Cid, ip)
if bs, err = d.client.Raw(ctx, req); err != nil {
log.Error("ugcPl URL %s, Cid %d, Client Raw Err %v", url, p.Cid, err)
return
}
if err = json.Unmarshal(bs, &resp); err != nil { // json unmarshal to struct, to detect error
log.Error("ugcPl URL %s, Cid %d, Json Unmarshal %s, Err %v", url, p.Cid, string(bs), err)
return
}
if resp.Code != ecode.OK.Code() {
log.Error("ugcPl URL %s, Cid %d, Resp Code %d, Msg %s", url, p.Cid, resp.Code, resp.Message)
err = ecode.TvVideoNotFound
return
}
err = json.Unmarshal(bs, &res)
return
}

View File

@@ -0,0 +1,51 @@
package goblin
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/tv/model"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
func TestGoblinUgcPlayurl(t *testing.T) {
var (
ctx = context.Background()
p = &model.PlayURLReq{
Cid: fmt.Sprintf("%d", 10131156),
}
)
convey.Convey("UgcPlayurl", t, func(c convey.C) {
defer gock.OffAll()
c.Convey("Normal Situation, Then err should be nil.res,resp should not be nil.", func(cx convey.C) {
httpMock("GET", d.conf.Host.UgcPlayURL).Reply(200).JSON(`{
"result": "succ",
"message": "succ",
"code": 0
}`)
res, resp, err := d.UgcPlayurl(ctx, p)
fmt.Println(resp)
cx.So(err, convey.ShouldBeNil)
cx.So(resp, convey.ShouldNotBeNil)
cx.So(res, convey.ShouldNotBeNil)
})
c.Convey("Request Error", func(cx convey.C) {
httpMock("GET", d.conf.Host.UgcPlayURL).Reply(404).JSON(``)
_, _, err := d.UgcPlayurl(ctx, p)
cx.So(err, convey.ShouldNotBeNil)
})
c.Convey("Code Error", func(cx convey.C) {
httpMock("GET", d.conf.Host.UgcPlayURL).Reply(200).JSON(`{"code":-400}`)
_, _, err := d.UgcPlayurl(ctx, p)
cx.So(err, convey.ShouldNotBeNil)
})
c.Convey("Json Error", func(cx convey.C) {
httpMock("GET", d.conf.Host.UgcPlayURL).Reply(200).JSON(`{"code":-400:}`)
_, _, err := d.UgcPlayurl(ctx, p)
cx.So(err, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,42 @@
package goblin
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/tv/model"
"go-common/library/ecode"
"github.com/pkg/errors"
)
// VerUpdate gets upgrade info.
func (d *Dao) VerUpdate(c context.Context, ver *model.VerUpdate) (result *model.HTTPData, errCode ecode.Codes, err error) {
var (
appURL = d.conf.Host.ReqURL
res struct {
Code int `json:"code"`
Data *model.HTTPData `json:"data"`
Message string `json:"message"`
}
)
params := url.Values{}
params.Set("mobi_app", ver.MobiApp)
params.Set("build", fmt.Sprintf("%d", ver.Build))
params.Set("channel", ver.Channel)
params.Set("seed", fmt.Sprintf("%d", ver.Seed))
params.Set("sdkint", fmt.Sprintf("%d", ver.Sdkint))
params.Set("model", ver.Model)
params.Set("old_id", ver.OldID)
if err = d.client.Get(c, appURL, "", params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), appURL+"?"+params.Encode())
errCode = ecode.Int(res.Code)
return
}
result = res.Data
return
}

View File

@@ -0,0 +1,39 @@
package goblin
import (
"context"
"go-common/app/interface/main/tv/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestGoblinVerUpdate(t *testing.T) {
var (
ctx = context.Background()
ver = &model.VerUpdate{}
)
convey.Convey("VerUpdate", t, func(c convey.C) {
c.Convey("Then err should be nil.result,errCode should not be nil.", func(c convey.C) {
result, errCode, err := d.VerUpdate(ctx, ver)
httpMock("GET", d.conf.Host.ReqURL).Reply(200).JSON(`{
"Data": {"ver":123},
"message": "succ",
"code": 0
}`)
c.So(err, convey.ShouldBeNil)
c.So(errCode, convey.ShouldBeNil)
c.So(result, convey.ShouldNotBeNil)
})
c.Convey("http error", func(c convey.C) {
_, _, err := d.VerUpdate(ctx, ver)
httpMock("GET", d.conf.Host.ReqURL).Reply(404).JSON(``)
c.So(err, convey.ShouldNotBeNil)
})
c.Convey("code error", func(c convey.C) {
_, _, err := d.VerUpdate(ctx, ver)
httpMock("GET", d.conf.Host.ReqURL).Reply(200).JSON(`{"code":400}`)
c.So(err, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,60 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"cursor_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/history/model:go_default_library",
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/history:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"cursor.go",
"dao.go",
],
importpath = "go-common/app/interface/main/tv/dao/history",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/history/model:go_default_library",
"//app/interface/main/history/rpc/client:go_default_library",
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/history:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,87 @@
package history
import (
"context"
"fmt"
hismodel "go-common/app/interface/main/history/model"
"go-common/app/interface/main/tv/model/history"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/net/metadata"
"time"
"github.com/pkg/errors"
)
func keyHis(mid int64) string {
return fmt.Sprintf("tv_his_%d", mid)
}
// Cursor get history rpc data
func (d *Dao) Cursor(c context.Context, mid, max int64, ps int, tp int8, businesses []string) (res []*hismodel.Resource, err error) {
ip := metadata.String(c, metadata.RemoteIP)
arg := &hismodel.ArgCursor{Mid: mid, Max: max, Ps: ps, RealIP: ip, TP: tp, ViewAt: max, Businesses: businesses}
if res, err = d.hisRPC.HistoryCursor(c, arg); err != nil {
err = errors.Wrapf(err, "d.historyRPC.HistoryCursor(%+v)", arg)
}
return
}
// HisCache get history cms cache.
func (d *Dao) HisCache(c context.Context, mid int64) (s *history.HisMC, err error) {
var (
key = keyHis(mid)
conn = d.mc.Get(c)
item *memcache.Item
)
defer conn.Close()
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
missedCount.Add("tv-his", 1)
} else {
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(item, &s); err != nil {
log.Error("conn.Get(%s) error(%v)", key, err)
}
cachedCount.Add("tv-his", 1)
return
}
// SaveHisCache save the member's history into cache
func (d *Dao) SaveHisCache(ctx context.Context, filtered []*history.HisRes) {
var hismc = &history.HisMC{}
if len(filtered) == 0 {
hismc.LastViewAt = time.Now().Unix()
} else {
firstItem := filtered[0]
hismc.LastViewAt = firstItem.Unix
hismc.MID = firstItem.Mid
}
hismc.Res = filtered
d.addHisCache(ctx, hismc)
}
// addHisCache adds the history into cache
func (d *Dao) addHisCache(ctx context.Context, his *history.HisMC) {
d.addCache(func() {
d.setHisCache(ctx, his)
})
}
// setHisCache add his cache
func (d *Dao) setHisCache(c context.Context, his *history.HisMC) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: keyHis(his.MID), Object: his, Flags: memcache.FlagJSON, Expiration: d.expireHis}
if err = conn.Set(item); err != nil {
log.Error("conn.Store(%s) error(%v)", keyHis(his.MID), err)
}
log.Info("set HisMC Mid %d", his.MID)
return
}

View File

@@ -0,0 +1,111 @@
package history
import (
"encoding/json"
"fmt"
"testing"
"time"
hmdl "go-common/app/interface/main/history/model"
"go-common/app/interface/main/tv/model/history"
"github.com/smartystreets/goconvey/convey"
)
var (
testMid = int64(320773689)
testAid = int64(10110670)
testHisMC = &history.HisMC{
MID: testMid,
Res: []*history.HisRes{
{
Mid: testMid,
Oid: testAid,
},
},
LastViewAt: time.Now().Unix(),
}
)
func TestDao_Cursor(t *testing.T) {
convey.Convey("TestDao_Cursor", t, WithDao(func(d *Dao) {
var (
mcDataHis = &hmdl.ArgHistory{
Mid: testMid,
Realtime: time.Now().Unix(),
History: &hmdl.History{
Mid: testMid,
Aid: testAid,
Business: "archive",
},
}
)
res, err := d.Cursor(ctx, testMid, 0, 100, 0, []string{"pgc", "archive"})
if len(res) == 0 {
if errAdd := d.hisRPC.Add(ctx, mcDataHis); errAdd != nil {
fmt.Println(errAdd)
return
}
res, err = d.Cursor(ctx, testMid, 0, 100, 0, []string{"pgc", "archive"})
}
convey.So(err, convey.ShouldBeNil)
convey.So(len(res), convey.ShouldBeGreaterThan, 0)
data, _ := json.Marshal(res)
fmt.Println(string(data))
}))
}
func TestHistorykeyHis(t *testing.T) {
var (
mid = int64(320773689)
)
convey.Convey("keyHis", t, func(c convey.C) {
p1 := keyHis(mid)
c.Convey("Then p1 should not be nil.", func(c convey.C) {
c.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestHistorySaveHisCache(t *testing.T) {
var (
filtered = []*history.HisRes{
{
Mid: testMid,
Oid: testAid,
},
}
)
convey.Convey("SaveHisCache", t, func(c convey.C) {
d.SaveHisCache(ctx, filtered)
c.Convey("No return values", func(c convey.C) {
})
})
}
func TestHistoryaddHisCache(t *testing.T) {
convey.Convey("addHisCache", t, func(c convey.C) {
d.addHisCache(ctx, testHisMC)
c.Convey("No return values", func(c convey.C) {
})
})
}
func TestHistorysetHisCache(t *testing.T) {
convey.Convey("setHisCache", t, func(c convey.C) {
err := d.setHisCache(ctx, testHisMC)
c.Convey("Then err should be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
})
})
}
func TestHistoryHisCache(t *testing.T) {
convey.Convey("HisCache", t, func(c convey.C) {
s, err := d.HisCache(ctx, testMid)
c.Convey("Then err should be nil.s should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(s, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,57 @@
package history
import (
"runtime"
"time"
hisrpc "go-common/app/interface/main/history/rpc/client"
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
// Dao is account dao.
type Dao struct {
// rpc
hisRPC *hisrpc.Service
mc *memcache.Pool
mCh chan func()
expireHis int32
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
hisRPC: hisrpc.New(c.HisRPC),
mc: memcache.NewPool(c.Memcache.Config),
mCh: make(chan func(), 10240),
expireHis: int32(time.Duration(c.Memcache.HisExpire) / time.Second),
}
for i := 0; i < runtime.NumCPU()*2; i++ {
go d.cacheproc()
}
return
}
var (
cachedCount = prom.CacheHit
missedCount = prom.CacheMiss
)
// addCache add archive to mc or redis
func (d *Dao) addCache(f func()) {
select {
case d.mCh <- f:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc write memcache and stat redis use goroutine
func (d *Dao) cacheproc() {
for {
f := <-d.mCh
f()
}
}

View File

@@ -0,0 +1,44 @@
package history
import (
"context"
"flag"
"os"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
ctx = context.TODO()
)
func init() {
//dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
//flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}

View File

@@ -0,0 +1,58 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"media_test.go",
"style_cache_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"media.go",
"style_cache.go",
],
importpath = "go-common/app/interface/main/tv/dao/pgc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,24 @@
package pgc
import (
"go-common/app/interface/main/tv/conf"
"go-common/library/cache/memcache"
bm "go-common/library/net/http/blademaster"
)
// Dao is account dao.
type Dao struct {
conf *conf.Config
client *bm.Client
mc *memcache.Pool
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
conf: c,
client: bm.NewClient(c.HTTPClient),
mc: memcache.NewPool(c.Memcache.Config),
}
return
}

View File

@@ -0,0 +1,45 @@
package pgc
import (
"context"
"flag"
"os"
"strings"
"go-common/app/interface/main/tv/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
ctx = context.Background()
)
func init() {
// dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
// flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,38 @@
package pgc
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/log"
)
// Media gets the media detail data from PGC API
func (d *Dao) Media(ctx context.Context, tvParam *model.MediaParam) (detail *model.SeasonDetail, err error) {
var result model.MediaResp
if err = d.client.Get(ctx, d.conf.Host.APIMedia, "", tvParam.GenerateUrl(), &result); err != nil {
log.Error("ClientGet Sid %d, error[%v]", tvParam.SeasonID, err)
return
}
if err = result.CodeErr(); err != nil {
log.Error("PGC API MediaResp: [CODE:(%d),MESSAGE:(%s)]", result.Code, result.Message)
return
}
detail = result.Result
return
}
// MediaV2 gets the media detail data from PGC API V2
func (d *Dao) MediaV2(ctx context.Context, tvParam *model.MediaParam) (detail *model.SnDetailV2, err error) {
var result model.MediaRespV2
if err = d.client.Get(ctx, d.conf.Host.APIMediaV2, "", tvParam.GenerateUrl(), &result); err != nil {
log.Error("ClientGet Sid %d, error[%v]", tvParam.SeasonID, err)
return
}
if err = result.CodeErr(); err != nil {
log.Error("PGC API MediaResp: [CODE:(%d),MESSAGE:(%s)]", result.Code, result.Message)
return
}
detail = result.Result
return
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,36 @@
package pgc
import (
"context"
"go-common/app/interface/main/tv/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_style = "style_label"
)
// GetLabelCache .
func (d *Dao) GetLabelCache(ctx context.Context) (res map[int64][]*model.ParamStyle, err error) {
var (
conn = d.mc.Get(ctx)
key = _style
rp *memcache.Item
)
res = make(map[int64][]*model.ParamStyle)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("mc.Get(%s) error(%v)", key, err)
}
return
}
if err = conn.Scan(rp, &res); err != nil {
log.Error("conn.Scan error(%v)", err)
}
return
}

View File

@@ -0,0 +1,19 @@
package pgc
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoGetLabelCache(t *testing.T) {
convey.Convey("GetLabelCache", t, func(cx convey.C) {
cx.Convey("When everything goes positive", func(cx convey.C) {
res, err := d.GetLabelCache(ctx)
cx.Convey("Then err should be nil.res should not be nil.", func(cx convey.C) {
cx.So(err, convey.ShouldBeNil)
cx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,67 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"elastic_test.go",
"result_test.go",
"search_sug_test.go",
"wild_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/search:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"elastic.go",
"result.go",
"search_sug.go",
"wild.go",
],
importpath = "go-common/app/interface/main/tv/dao/search",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/search:go_default_library",
"//library/database/elastic: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/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,40 @@
package search
import (
"go-common/app/interface/main/tv/conf"
"go-common/library/database/elastic"
bm "go-common/library/net/http/blademaster"
)
const (
_userSearch = "/main/search"
_card = "/pgc/internal/season/search/card"
)
// Dao is search dao.
type Dao struct {
conf *conf.Config
client *bm.Client
resultURL string
esClient *elastic.Elastic
userSearch string
card string
cfgWild *conf.WildSearch
}
// New account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
client: bm.NewClient(c.SearchClient),
resultURL: c.Search.ResultURL,
conf: c,
esClient: elastic.NewElastic(&elastic.Config{
Host: c.Host.ESHost,
HTTPClient: c.SearchClient,
}),
userSearch: c.Search.UserSearch + _userSearch,
card: c.Host.APICo + _card,
cfgWild: c.Wild.WildSearch,
}
return
}

View File

@@ -0,0 +1,33 @@
package search
import (
"flag"
"go-common/app/interface/main/tv/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

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