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,87 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"crm.go",
"dao.cache.go",
"dao.go",
"data.go",
"mc.cache.go",
"memcahe.go",
"rank.go",
"recommend_pool.go",
"sign.go",
],
importpath = "go-common/app/interface/main/mcn/dao/mcndao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/mcn/model:go_default_library",
"//app/admin/main/up/util:go_default_library",
"//app/admin/main/up/util/mathutil:go_default_library",
"//app/interface/main/mcn/conf:go_default_library",
"//app/interface/main/mcn/dao/cache:go_default_library",
"//app/interface/main/mcn/dao/global:go_default_library",
"//app/interface/main/mcn/model:go_default_library",
"//app/interface/main/mcn/model/mcnmodel:go_default_library",
"//app/interface/main/mcn/tool/validate:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//vendor/github.com/bluele/gcache:go_default_library",
"//vendor/github.com/jinzhu/gorm: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 = [
"crm_test.go",
"dao.cache_test.go",
"dao_test.go",
"data_test.go",
"mc.cache_test.go",
"memcahe_test.go",
"rank_test.go",
"recommend_pool_test.go",
"sign_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/mcn/conf:go_default_library",
"//app/interface/main/mcn/dao/global:go_default_library",
"//app/interface/main/mcn/model:go_default_library",
"//app/interface/main/mcn/model/mcnmodel:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/bluele/gcache:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,38 @@
package mcndao
import (
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/log"
)
//GetActiveTid get tid from crm database
func (d *Dao) GetActiveTid(mids []int64) (res map[int64]int64, err error) {
var infoList []*mcnmodel.UpBaseInfo
err = d.mcndb.Select("mid, active_tid").Where("mid in (?) and business_type=1", mids).Find(&infoList).Error
if err != nil {
log.Error("fail to get active_tid from crm, err=%s", err)
return
}
res = make(map[int64]int64, len(infoList))
for _, v := range infoList {
res[v.Mid] = v.ActiveTid
}
return
}
//GetUpBaseInfo get up base info from crm database
func (d *Dao) GetUpBaseInfo(fields string, mids []int64) (res map[int64]*mcnmodel.UpBaseInfo, err error) {
var infoList []*mcnmodel.UpBaseInfo
err = d.mcndb.Select(fields).Where("mid in (?) and business_type=1", mids).Find(&infoList).Error
if err != nil {
log.Error("fail to get active_tid from crm, err=%s", err)
return
}
res = make(map[int64]*mcnmodel.UpBaseInfo, len(infoList))
for _, v := range infoList {
res[v.Mid] = v
}
return
}

View File

@@ -0,0 +1,22 @@
package mcndao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoGetActiveTid(t *testing.T) {
convey.Convey("GetActiveTid", t, func(ctx convey.C) {
var (
mids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetActiveTid(mids)
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)
})
})
})
}

View File

@@ -0,0 +1,133 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package mcndao is a generated cache proxy package.
It is generated from:
type _cache interface {
//cache: -nullcache=&mcnmodel.McnSign{ID:-1} -check_null_code=$!=nil&&$.ID==-1
McnSign(c context.Context, mcnmid int64) (up *mcnmodel.McnSign, err error)
//cache: -nullcache=&mcnmodel.McnGetDataSummaryReply{IsNull:true} -check_null_code=$!=nil&&$.IsNull
McnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error)
//cache: -nullcache=&mcnmodel.UpPermissionCache{IsNull:true} -check_null_code=$!=nil&&$.IsNull
UpPermission(c context.Context, signID int64, mid int64) (data *mcnmodel.UpPermissionCache, err error)
}
*/
package mcndao
import (
"context"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/stat/prom"
"time"
)
var _ _cache
// McnSign get data from cache if miss will call source method, then add to cache.
func (d *Dao) McnSign(c context.Context, id int64) (res *mcnmodel.McnSign, err error) {
addCache := true
res, err = d.CacheMcnSign(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.ID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("McnSign")
return
}
prom.CacheMiss.Incr("McnSign")
res, err = d.RawMcnSign(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &mcnmodel.McnSign{ID: -1}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheMcnSign(c, id, miss)
})
return
}
// McnDataSummary get data from cache if miss will call source method, then add to cache.
func (d *Dao) McnDataSummary(c context.Context, id int64, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error) {
addCache := true
res, err = d.CacheMcnDataSummary(c, id, generateDate)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.IsNull {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("McnDataSummary")
return
}
prom.CacheMiss.Incr("McnDataSummary")
res, err = d.RawMcnDataSummary(c, id, generateDate)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &mcnmodel.McnGetDataSummaryReply{IsNull: true}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheMcnDataSummary(c, id, miss, generateDate)
})
return
}
// UpPermission get data from cache if miss will call source method, then add to cache.
func (d *Dao) UpPermission(c context.Context, id int64, mid int64) (res *mcnmodel.UpPermissionCache, err error) {
addCache := true
res, err = d.CacheUpPermission(c, id, mid)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res != nil && res.IsNull {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("UpPermission")
return
}
prom.CacheMiss.Incr("UpPermission")
res, err = d.RawUpPermission(c, id, mid)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &mcnmodel.UpPermissionCache{IsNull: true}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheUpPermission(c, id, miss, mid)
})
return
}

View File

@@ -0,0 +1,42 @@
package mcndao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoMcnSign(t *testing.T) {
convey.Convey("McnSign", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.McnSign(c, id)
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.ShouldBeNil)
})
})
})
}
func TestMcndaoMcnDataSummary(t *testing.T) {
convey.Convey("McnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.McnDataSummary(c, id, generateDate)
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.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,74 @@
package mcndao
import (
"context"
"fmt"
"runtime"
"time"
"go-common/app/interface/main/mcn/conf"
"go-common/app/interface/main/mcn/dao/global"
"go-common/library/cache/memcache"
"go-common/library/sync/pipeline/fanout"
"github.com/bluele/gcache"
"github.com/jinzhu/gorm"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
mcndb *gorm.DB
//cache tool
cache *fanout.Fanout
mcnSignExpire int32
mcnDataExpire int32
localcache gcache.Cache
}
// New init mysql db
func New(c *conf.Config, localcache gcache.Cache) (dao *Dao) {
dao = &Dao{
c: c,
mc: global.GetMc(),
// cache worker
cache: fanout.New("cache", fanout.Worker(runtime.NumCPU()), fanout.Buffer(1024)),
mcnSignExpire: int32(time.Duration(c.Memcache.McnSignCacheExpire) / time.Second),
mcnDataExpire: int32(time.Duration(c.Memcache.McnDataCacheExpire) / time.Second),
localcache: localcache,
}
if localcache == nil {
dao.localcache = gcache.New(c.RankCache.Size).Simple().Build()
}
if dao.mcnDataExpire == 0 {
dao.mcnDataExpire = 3600
}
if dao.mcnSignExpire == 0 {
dao.mcnSignExpire = 3600
}
var err error
dao.mcndb, err = gorm.Open("mysql", c.MCNorm.DSN)
if err != nil {
panic(fmt.Errorf("db connect fail, err=%s", err))
}
dao.mcndb.LogMode(c.Other.Debug)
return
}
// Close close the resource.
func (d *Dao) Close() {
d.cache.Close()
d.mc.Close()
d.mcndb.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}
//GetMcnDB get mcn db
func (d *Dao) GetMcnDB() *gorm.DB {
return d.mcndb
}

View File

@@ -0,0 +1,43 @@
package mcndao
import (
"flag"
"os"
"testing"
"go-common/app/interface/main/mcn/conf"
"github.com/bluele/gcache"
"go-common/app/interface/main/mcn/dao/global"
)
var (
d *Dao
localcache = gcache.New(1024).Simple().Build()
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.mcn-interface")
flag.Set("conf_token", "49e4671bafbf93059aeb602685052ca0")
flag.Set("tree_id", "58909")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/mcn-interface.toml")
}
if os.Getenv("UT_LOCAL_TEST") != "" {
flag.Set("conf", "../../cmd/mcn-interface.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
global.Init(conf.Conf)
d = New(conf.Conf, localcache)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,145 @@
package mcndao
import (
"time"
"go-common/app/interface/main/mcn/model"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
const (
dateFmt = "2006-01-02"
tidSummary = 65535 // 特殊的tid表示所有分区数据之和
)
//GetMcnDataSummary .
func (d *Dao) GetMcnDataSummary(selec string, query interface{}, args ...interface{}) (res *mcnmodel.McnDataSummary, err error) {
res = new(mcnmodel.McnDataSummary)
err = d.mcndb.Select(selec).Where(query, args...).Limit(1).Find(res).Error
if err != nil {
log.Error("query db fail, err=%s", err)
return
}
return
}
//GetMcnDataSummaryWithDiff get data with datacenter diff
func (d *Dao) GetMcnDataSummaryWithDiff(signID int64, dataTYpe mcnmodel.McnDataType, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error) {
dataDay0, err := d.GetMcnDataSummary("up_count, fans_count_accumulate, archive_count_accumulate, play_count_accumulate, generate_date", "sign_id=? and data_type=? and generate_date=? and active_tid=?", signID, dataTYpe, generateDate.Format(dateFmt), tidSummary)
if int64(dataDay0.GenerateDate) == 0 {
err = gorm.ErrRecordNotFound
}
if err != nil {
if err == gorm.ErrRecordNotFound {
err = nil
log.Warn("not found generate date=%s, sign id=%d", generateDate.Format(dateFmt), signID)
return
}
log.Error("fail to get data db, err=%s, sign id=%d", err, signID)
return
}
dataDay1, err := d.GetMcnDataSummary("up_count, fans_count_accumulate, archive_count_accumulate, play_count_accumulate, generate_date", "sign_id=? and data_type=? and generate_date=? and active_tid=?", signID, dataTYpe, generateDate.AddDate(0, 0, -1).Format(dateFmt), tidSummary)
if int64(dataDay1.GenerateDate) == 0 {
err = gorm.ErrRecordNotFound
}
if err != nil {
if err == gorm.ErrRecordNotFound {
err = nil
log.Warn("not found generate date=%s, sign id=%d", generateDate.Format(dateFmt), signID)
dataDay1 = new(mcnmodel.McnDataSummary)
} else {
log.Error("fail to get data db, err=%s, sign id=%d", err, signID)
return
}
}
res = new(mcnmodel.McnGetDataSummaryReply)
res.CopyFrom(dataDay0)
res.CalcDiff(dataDay1)
return
}
//GetDataUpLatestDate .
func (d *Dao) GetDataUpLatestDate(dataType mcnmodel.DataType, signID int64) (generateDate time.Time, err error) {
var model = mcnmodel.McnDataUp{}
err = d.mcndb.Select("generate_date").Where("data_type=? and sign_id=?", dataType, signID).Order("generate_date desc").Limit(1).Find(&model).Error
if err != nil {
log.Error("get latest date from mcn_data_up fail, err=%s", err)
return
}
generateDate = model.GenerateDate.Time()
return
}
//GetAllUpData .
func (d *Dao) GetAllUpData(signID int64, upmid int64, generateDate time.Time) (res []*mcnmodel.McnUpDataInfo, err error) {
var sqlstr = `select
u.begin_date,
u.end_date,
u.state,
u.up_mid,
u.publication_price,
u.permission,
d.fans_increase_accumulate,
d.archive_count,
d.play_count,
d.fans_increase_month,
d.fans_count,
d.fans_count_active,
generate_date
from
mcn_up as u left join mcn_data_up as d
on (d.sign_id = u.sign_id and d.up_mid = u.up_mid and d.data_type=1 and generate_date=? )
where u.sign_id=? and u.state not in (?)`
var values = []interface{}{generateDate, signID, []model.MCNUPState{model.MCNUPStateOnDelete}}
if upmid != 0 {
sqlstr += " and u.up_mid=?"
values = append(values, upmid)
}
err = d.mcndb.Raw(sqlstr, values...).Find(&res).Error
if err != nil {
log.Error("query db fail, err=%s", err)
return
}
return
}
//GetAllUpDataTemp .
func (d *Dao) GetAllUpDataTemp(signID int64, upmid int64, generateDate time.Time) (res []*mcnmodel.McnUpDataInfo, err error) {
/*
前台这边一期的数据
1.首页 - 绑定up主总数
2.up主列表 - 总粉数
3.up主列表 - 投稿数
4.up主列表 - up分区
5.up主列表 - 签约及到期时间
*/
var sqlstr = `select
u.begin_date,
u.end_date,
u.state,
u.up_mid,
d.article_count_accumulate as archive_count,
d.fans_count,
d.active_fans as fans_count_active
from
mcn_up as u left join up_base_info as d
on (d.mid = u.up_mid and d.business_type = 1)
where u.sign_id=? and u.state not in (?)`
var values = []interface{}{signID, []model.MCNUPState{model.MCNUPStateOnDelete, model.MCNUPStateOnExpire, model.MCNUPStateOnClear}}
if upmid != 0 {
sqlstr += " and u.up_mid=?"
values = append(values, upmid)
}
err = d.mcndb.Raw(sqlstr, values...).Find(&res).Error
if err != nil {
log.Error("query db fail, err=%s", err)
return
}
return
}

View File

@@ -0,0 +1,94 @@
package mcndao
import (
"testing"
"time"
"go-common/app/interface/main/mcn/model/mcnmodel"
"github.com/jinzhu/gorm"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoGetMcnDataSummary(t *testing.T) {
convey.Convey("GetMcnDataSummary", t, func(ctx convey.C) {
var (
selec = "*"
query = "1=?"
args = "1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetMcnDataSummary(selec, query, args)
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)
})
})
})
}
func TestMcndaoGetMcnDataSummaryWithDiff(t *testing.T) {
convey.Convey("GetMcnDataSummaryWithDiff", t, func(ctx convey.C) {
var (
signID = int64(0)
dataTYpe mcnmodel.McnDataType
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetMcnDataSummaryWithDiff(signID, dataTYpe, generateDate)
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.ShouldBeNil)
})
})
})
}
func TestMcndaoGetDataUpLatestDate(t *testing.T) {
convey.Convey("GetDataUpLatestDate", t, func(ctx convey.C) {
var (
dataType = mcnmodel.DataType(1)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
generateDate, err := d.GetDataUpLatestDate(dataType, 0)
ctx.Convey("Then err should be nil.generateDate should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, gorm.ErrRecordNotFound)
ctx.So(generateDate, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoGetAllUpData(t *testing.T) {
convey.Convey("GetAllUpData", t, func(ctx convey.C) {
var (
signID = int64(0)
upmid = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetAllUpData(signID, upmid, generateDate)
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)
})
})
})
}
func TestMcndaoGetAllUpDataTemp(t *testing.T) {
convey.Convey("GetAllUpDataTemp", t, func(ctx convey.C) {
var (
signID = int64(0)
upmid = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetAllUpDataTemp(signID, upmid, generateDate)
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)
})
})
})
}

View File

@@ -0,0 +1,287 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
/*
Package mcndao is a generated mc cache package.
It is generated from:
type _mc interface {
//mc: -key=mcnSignCacheKey -expire=d.mcnSignExpire -encode=json
AddCacheMcnSign(c context.Context, mcnmid int64, up *mcnmodel.McnSign) (err error)
//mc: -key=mcnSignCacheKey
CacheMcnSign(c context.Context, mcnmid int64) (up *mcnmodel.McnSign, err error)
//mc: -key=mcnSignCacheKey
DelCacheMcnSign(c context.Context, mcnmid int64) (err error)
//mc: -key=mcnDataCacheKey -expire=d.mcnDataExpire -encode=json
AddCacheMcnDataSummary(c context.Context, mcnmid int64, data *mcnmodel.McnGetDataSummaryReply, generateDate time.Time) (err error)
//mc: -key=mcnDataCacheKey
CacheMcnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (data *mcnmodel.McnGetDataSummaryReply, err error)
//mc: -key=mcnDataCacheKey
DelMcnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (err error)
//mc: -key=mcnPublicationPriceKey -expire=0 -encode=json
AddCachePublicationPrice(c context.Context, signID int64, data *mcnmodel.PublicationPriceCache, mid int64) (err error)
//mc: -key=mcnPublicationPriceKey
CachePublicationPrice(c context.Context, signID int64, mid int64) (data *mcnmodel.PublicationPriceCache, err error)
//mc: -key=mcnPublicationPriceKey
DelPublicationPrice(c context.Context, signID int64, mid int64) (err error)
//mc: -key=mcnUpPermissionKey -expire=d.mcnSignExpire -encode=json
AddCacheUpPermission(c context.Context, signID int64, data *mcnmodel.UpPermissionCache, mid int64) (err error)
//mc: -key=mcnUpPermissionKey
CacheUpPermission(c context.Context, signID int64, mid int64) (data *mcnmodel.UpPermissionCache, err error)
//mc: -key=mcnUpPermissionKey
DelUpPermission(c context.Context, signID int64, mid int64) (err error)
}
*/
package mcndao
import (
"context"
"fmt"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
"time"
)
var _ _mc
// AddCacheMcnSign Set data to mc
func (d *Dao) AddCacheMcnSign(c context.Context, id int64, val *mcnmodel.McnSign) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := mcnSignCacheKey(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.mcnSignExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheMcnSign")
log.Errorv(c, log.KV("AddCacheMcnSign", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheMcnSign get data from mc
func (d *Dao) CacheMcnSign(c context.Context, id int64) (res *mcnmodel.McnSign, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnSignCacheKey(id)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheMcnSign")
log.Errorv(c, log.KV("CacheMcnSign", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &mcnmodel.McnSign{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheMcnSign")
log.Errorv(c, log.KV("CacheMcnSign", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheMcnSign delete data from mc
func (d *Dao) DelCacheMcnSign(c context.Context, id int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnSignCacheKey(id)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheMcnSign")
log.Errorv(c, log.KV("DelCacheMcnSign", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheMcnDataSummary Set data to mc
func (d *Dao) AddCacheMcnDataSummary(c context.Context, id int64, val *mcnmodel.McnGetDataSummaryReply, generateDate time.Time) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := mcnDataCacheKey(id, generateDate)
item := &memcache.Item{Key: key, Object: val, Expiration: d.mcnDataExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheMcnDataSummary")
log.Errorv(c, log.KV("AddCacheMcnDataSummary", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheMcnDataSummary get data from mc
func (d *Dao) CacheMcnDataSummary(c context.Context, id int64, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnDataCacheKey(id, generateDate)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheMcnDataSummary")
log.Errorv(c, log.KV("CacheMcnDataSummary", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &mcnmodel.McnGetDataSummaryReply{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheMcnDataSummary")
log.Errorv(c, log.KV("CacheMcnDataSummary", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelMcnDataSummary delete data from mc
func (d *Dao) DelMcnDataSummary(c context.Context, id int64, generateDate time.Time) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnDataCacheKey(id, generateDate)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelMcnDataSummary")
log.Errorv(c, log.KV("DelMcnDataSummary", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCachePublicationPrice Set data to mc
func (d *Dao) AddCachePublicationPrice(c context.Context, id int64, val *mcnmodel.PublicationPriceCache, mid int64) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := mcnPublicationPriceKey(id, mid)
item := &memcache.Item{Key: key, Object: val, Expiration: 0, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCachePublicationPrice")
log.Errorv(c, log.KV("AddCachePublicationPrice", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CachePublicationPrice get data from mc
func (d *Dao) CachePublicationPrice(c context.Context, id int64, mid int64) (res *mcnmodel.PublicationPriceCache, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnPublicationPriceKey(id, mid)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CachePublicationPrice")
log.Errorv(c, log.KV("CachePublicationPrice", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &mcnmodel.PublicationPriceCache{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CachePublicationPrice")
log.Errorv(c, log.KV("CachePublicationPrice", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelPublicationPrice delete data from mc
func (d *Dao) DelPublicationPrice(c context.Context, id int64, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnPublicationPriceKey(id, mid)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelPublicationPrice")
log.Errorv(c, log.KV("DelPublicationPrice", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheUpPermission Set data to mc
func (d *Dao) AddCacheUpPermission(c context.Context, id int64, val *mcnmodel.UpPermissionCache, mid int64) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := mcnUpPermissionKey(id, mid)
item := &memcache.Item{Key: key, Object: val, Expiration: d.mcnSignExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheUpPermission")
log.Errorv(c, log.KV("AddCacheUpPermission", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheUpPermission get data from mc
func (d *Dao) CacheUpPermission(c context.Context, id int64, mid int64) (res *mcnmodel.UpPermissionCache, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnUpPermissionKey(id, mid)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheUpPermission")
log.Errorv(c, log.KV("CacheUpPermission", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &mcnmodel.UpPermissionCache{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheUpPermission")
log.Errorv(c, log.KV("CacheUpPermission", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelUpPermission delete data from mc
func (d *Dao) DelUpPermission(c context.Context, id int64, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcnUpPermissionKey(id, mid)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelUpPermission")
log.Errorv(c, log.KV("DelUpPermission", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}

View File

@@ -0,0 +1,108 @@
package mcndao
import (
"context"
"testing"
"time"
"go-common/app/interface/main/mcn/model/mcnmodel"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoAddCacheMcnSign(t *testing.T) {
convey.Convey("AddCacheMcnSign", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
val = &mcnmodel.McnSign{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddCacheMcnSign(c, id, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoCacheMcnSign(t *testing.T) {
convey.Convey("CacheMcnSign", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.CacheMcnSign(c, id)
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)
})
})
})
}
func TestMcndaoDelCacheMcnSign(t *testing.T) {
convey.Convey("DelCacheMcnSign", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelCacheMcnSign(c, id)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoAddCacheMcnDataSummary(t *testing.T) {
convey.Convey("AddCacheMcnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
val = &mcnmodel.McnGetDataSummaryReply{}
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddCacheMcnDataSummary(c, id, val, generateDate)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoCacheMcnDataSummary(t *testing.T) {
convey.Convey("CacheMcnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.CacheMcnDataSummary(c, id, generateDate)
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)
})
})
})
}
func TestMcndaoDelMcnDataSummary(t *testing.T) {
convey.Convey("DelMcnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelMcnDataSummary(c, id, generateDate)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,116 @@
package mcndao
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
//cache: -nullcache=&mcnmodel.McnSign{ID:-1} -check_null_code=$!=nil&&$.ID==-1
McnSign(c context.Context, mcnmid int64) (up *mcnmodel.McnSign, err error)
//cache: -nullcache=&mcnmodel.McnGetDataSummaryReply{IsNull:true} -check_null_code=$!=nil&&$.IsNull
McnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error)
//cache: -nullcache=&mcnmodel.UpPermissionCache{IsNull:true} -check_null_code=$!=nil&&$.IsNull
UpPermission(c context.Context, signID int64, mid int64) (data *mcnmodel.UpPermissionCache, err error)
}
//go:generate $GOPATH/src/go-common/app/tool/cache/mc
type _mc interface {
//mc: -key=mcnSignCacheKey -expire=d.mcnSignExpire -encode=json
AddCacheMcnSign(c context.Context, mcnmid int64, up *mcnmodel.McnSign) (err error)
//mc: -key=mcnSignCacheKey
CacheMcnSign(c context.Context, mcnmid int64) (up *mcnmodel.McnSign, err error)
//mc: -key=mcnSignCacheKey
DelCacheMcnSign(c context.Context, mcnmid int64) (err error)
//mc: -key=mcnDataCacheKey -expire=d.mcnDataExpire -encode=json
AddCacheMcnDataSummary(c context.Context, mcnmid int64, data *mcnmodel.McnGetDataSummaryReply, generateDate time.Time) (err error)
//mc: -key=mcnDataCacheKey
CacheMcnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (data *mcnmodel.McnGetDataSummaryReply, err error)
//mc: -key=mcnDataCacheKey
DelMcnDataSummary(c context.Context, mcnmid int64, generateDate time.Time) (err error)
//mc: -key=mcnPublicationPriceKey -expire=0 -encode=json
AddCachePublicationPrice(c context.Context, signID int64, data *mcnmodel.PublicationPriceCache, mid int64) (err error)
//mc: -key=mcnPublicationPriceKey
CachePublicationPrice(c context.Context, signID int64, mid int64) (data *mcnmodel.PublicationPriceCache, err error)
//mc: -key=mcnPublicationPriceKey
DelPublicationPrice(c context.Context, signID int64, mid int64) (err error)
//mc: -key=mcnUpPermissionKey -expire=d.mcnSignExpire -encode=json
AddCacheUpPermission(c context.Context, signID int64, data *mcnmodel.UpPermissionCache, mid int64) (err error)
//mc: -key=mcnUpPermissionKey
CacheUpPermission(c context.Context, signID int64, mid int64) (data *mcnmodel.UpPermissionCache, err error)
//mc: -key=mcnUpPermissionKey
DelUpPermission(c context.Context, signID int64, mid int64) (err error)
}
func mcnSignCacheKey(mcnmid int64) string {
return fmt.Sprintf("mcn_s_%d", mcnmid)
}
//RawMcnSign raw db .
func (d *Dao) RawMcnSign(c context.Context, mcnmid int64) (up *mcnmodel.McnSign, err error) {
up, _, err = d.GetMcnSignState("*", mcnmid)
if err != nil {
if err == gorm.ErrRecordNotFound {
err = nil
return
}
log.Error("error get state, err=%s", err)
return
}
return
}
//AsyncDelCacheMcnSign delete in async way
func (d *Dao) AsyncDelCacheMcnSign(id int64) (err error) {
return d.cache.Do(context.Background(), func(c context.Context) {
d.DelCacheMcnSign(c, id)
})
}
func mcnDataCacheKey(signID int64, generateDate time.Time) string {
var key = fmt.Sprintf("mcn_data_%d_%s", signID, generateDate.Format(dateFmt))
return key
}
//RawMcnDataSummary raw get
func (d *Dao) RawMcnDataSummary(c context.Context, signID int64, generateDate time.Time) (res *mcnmodel.McnGetDataSummaryReply, err error) {
return d.GetMcnDataSummaryWithDiff(signID, mcnmodel.McnDataTypeDay, generateDate)
}
func mcnPublicationPriceKey(signID int64, mid int64) string {
return fmt.Sprintf("mcn_pubprice_%d_%d", signID, mid)
}
func mcnUpPermissionKey(signID int64, mid int64) string {
var s = fmt.Sprintf("mcn_upperm_%d_%d", signID, mid)
log.Info("key=%s", s)
return s
}
//RawUpPermission get permissino from db
func (d *Dao) RawUpPermission(c context.Context, signID int64, mid int64) (res *mcnmodel.UpPermissionCache, err error) {
upList, err := d.GetUpBind("up_mid=? and sign_id=? and state in (?)", mid, signID, UpSignedStates)
if err != nil {
log.Error("get up from db fail, err=%v, signid=%d, mid=%d", err, signID, mid)
return
}
if len(upList) == 0 {
log.Warn("up not found, sign_id=%d, mid=%d", signID, mid)
return
}
res = new(mcnmodel.UpPermissionCache)
res.Permission = upList[0].Permission
return
}

View File

@@ -0,0 +1,85 @@
package mcndao
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaomcnSignCacheKey(t *testing.T) {
convey.Convey("mcnSignCacheKey", t, func(ctx convey.C) {
var (
mcnmid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := mcnSignCacheKey(mcnmid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRawMcnSign(t *testing.T) {
convey.Convey("RawMcnSign", t, func(ctx convey.C) {
var (
c = context.Background()
mcnmid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
up, err := d.RawMcnSign(c, mcnmid)
ctx.Convey("Then err should be nil.up should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(up, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoAsyncDelCacheMcnSign(t *testing.T) {
convey.Convey("AsyncDelCacheMcnSign", t, func(ctx convey.C) {
var (
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AsyncDelCacheMcnSign(id)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaomcnDataCacheKey(t *testing.T) {
convey.Convey("mcnDataCacheKey", t, func(ctx convey.C) {
var (
signID = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := mcnDataCacheKey(signID, generateDate)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRawMcnDataSummary(t *testing.T) {
convey.Convey("RawMcnDataSummary", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(0)
generateDate = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.RawMcnDataSummary(c, id, generateDate)
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.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,426 @@
package mcndao
import (
"context"
"fmt"
"sort"
"time"
"go-common/app/admin/main/up/util"
"go-common/app/admin/main/up/util/mathutil"
"go-common/app/interface/main/mcn/conf"
"go-common/app/interface/main/mcn/dao/cache"
"go-common/app/interface/main/mcn/dao/global"
"go-common/app/interface/main/mcn/model/mcnmodel"
arcgrpc "go-common/app/service/main/archive/api"
"go-common/library/log"
"github.com/bluele/gcache"
)
// RankByTid .
// 存储rank的缓存
// 对每种排行榜的分类进行缓存
// 对排序进行实时计算
// 先去localcache中取取不到的话去db中取
type RankByTid struct {
// [tid][datatype] rank list
TidMap map[int16]map[mcnmodel.DataType][]mcnmodel.RankDataInterface
TidTypeListMap map[mcnmodel.DataType][]*mcnmodel.TidnameInfo
}
//RankFunc rank func
type RankFunc func(signId int64) (result *RankByTid, err error)
type tidnameUnique struct {
tidInfoMap map[mcnmodel.DataType]map[int16]*mcnmodel.TidnameInfo
}
func newTidNameUnique() *tidnameUnique {
return &tidnameUnique{tidInfoMap: make(map[mcnmodel.DataType]map[int16]*mcnmodel.TidnameInfo)}
}
func (t *tidnameUnique) addTid(tid int16, name string, datatype mcnmodel.DataType) {
var dmap map[int16]*mcnmodel.TidnameInfo
var ok bool
if dmap, ok = t.tidInfoMap[datatype]; !ok {
dmap = make(map[int16]*mcnmodel.TidnameInfo)
t.tidInfoMap[datatype] = dmap
}
dmap[tid] = &mcnmodel.TidnameInfo{Tid: tid, Name: name}
}
func (t *tidnameUnique) getList(datatype mcnmodel.DataType) (typeList []*mcnmodel.TidnameInfo) {
for _, v := range t.tidInfoMap[datatype] {
typeList = append(typeList, v)
}
return
}
func (t *tidnameUnique) export(dmap map[mcnmodel.DataType][]*mcnmodel.TidnameInfo) {
for dataType, tidMap := range t.tidInfoMap {
var typeList []*mcnmodel.TidnameInfo
for k, v := range tidMap {
if k == 0 {
continue
}
typeList = append(typeList, v)
}
dmap[dataType] = typeList
}
}
// // 排序根据increase数量做倒序
// type rankByFansIncreaseDesc []*mcnmodel.RankUpFansInfo
// func (s rankByFansIncreaseDesc) Len() int {
// return len(s)
// }
// func (s rankByFansIncreaseDesc) Swap(i, j int) {
// s[i], s[j] = s[j], s[i]
// }
// func (s rankByFansIncreaseDesc) Less(i, j int) bool {
// return s[i].FansIncrease > s[j].FansIncrease
// }
type sortRankFunc func(p1, p2 mcnmodel.RankDataInterface) bool
type rankDataSorter struct {
datas []mcnmodel.RankDataInterface
by sortRankFunc // Closure used in the Less method.
}
// Len is part of sort.Interface.
func (s *rankDataSorter) Len() int {
return len(s.datas)
}
// Swap is part of sort.Interface.
func (s *rankDataSorter) Swap(i, j int) {
s.datas[i], s.datas[j] = s.datas[j], s.datas[i]
}
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *rankDataSorter) Less(i, j int) bool {
return s.by(s.datas[i], s.datas[j])
}
func byValueDesc(p1, p2 mcnmodel.RankDataInterface) bool {
return p1.GetValue() > p2.GetValue()
}
//GetList get list
func (s *RankByTid) GetList(tid int16, dataType mcnmodel.DataType) (res []mcnmodel.RankDataInterface) {
if s.TidMap == nil {
return
}
tMap, ok := s.TidMap[tid]
if !ok || tMap == nil {
return
}
if res, ok = tMap[dataType]; !ok {
res = nil
}
return
}
var nulltidlist = make([]*mcnmodel.TidnameInfo, 0)
//GetTypeList get type's list
func (s *RankByTid) GetTypeList(dataType mcnmodel.DataType) (res []*mcnmodel.TidnameInfo) {
res = s.TidTypeListMap[dataType]
if res == nil {
res = nulltidlist
}
return
}
func (s *RankByTid) addRank(v mcnmodel.RankDataInterface) {
var dmap, allMap map[mcnmodel.DataType][]mcnmodel.RankDataInterface
if s.TidMap == nil {
s.TidMap = make(map[int16]map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
}
var ok bool
if v.GetTid() != 0 {
if dmap, ok = s.TidMap[v.GetTid()]; !ok {
dmap = make(map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
s.TidMap[v.GetTid()] = dmap
}
dmap[v.GetDataType()] = append(dmap[v.GetDataType()], v)
}
if allMap, ok = s.TidMap[0]; !ok {
allMap = make(map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
s.TidMap[0] = allMap
}
allMap[v.GetDataType()] = append(allMap[v.GetDataType()], v)
}
func (s *RankByTid) addTidMap(v *tidnameUnique) {
if s.TidTypeListMap == nil {
s.TidTypeListMap = make(map[mcnmodel.DataType][]*mcnmodel.TidnameInfo)
}
v.export(s.TidTypeListMap)
}
//Truncate truncate all the sorted list by max item number
func (s *RankByTid) Truncate(max int) {
for _, v := range s.TidMap {
for k2, v2 := range v {
var length = len(v2)
if length == 0 {
continue
}
var m = mathutil.Min(max, length)
v[k2] = v2[0:m]
}
}
}
// Sort sort by sorting function
func (s *RankByTid) Sort(sortFunc sortRankFunc) {
for _, v := range s.TidMap {
for k2, v2 := range v {
var sorter = &rankDataSorter{
datas: v2,
by: sortFunc,
}
sort.Sort(sorter)
v[k2] = v2
}
}
}
type keyFunc func(int64) string
type loadRankFunc func(signID int64, date time.Time) (result *RankByTid, err error)
// GetRankUpFans get fans
func (d *Dao) GetRankUpFans(signID int64) (result *RankByTid, err error) {
return d.getRankCache(signID, cacheKeyRankFans, d.loadRankUpFansCache)
}
// GetRankArchiveLikes get fans
func (d *Dao) GetRankArchiveLikes(signID int64) (result *RankByTid, err error) {
return d.getRankCache(signID, cacheKeyRankArchiveLikes, d.loadRankArchiveLikesCache)
}
func (d *Dao) getRankCache(signID int64, keyCalc keyFunc, load loadRankFunc) (result *RankByTid, err error) {
var key = keyCalc(signID)
v, err := d.localcache.Get(key)
if err != nil {
if err == gcache.KeyNotFoundError {
// load cache
v, err = load(signID, time.Now())
if err != nil {
log.Error("load cache error, signID=%d, err=%s", signID, err)
return
}
d.localcache.SetWithExpire(key, v, time.Duration(conf.Conf.RankCache.ExpireTime))
} else {
log.Error("get from gcache err, signID=%d, err=%s", signID, err)
return
}
}
if v == nil {
return
}
result, _ = v.(*RankByTid)
return
}
func cacheKeyRankFans(signID int64) string {
return fmt.Sprintf("rank_fans_%d", signID)
}
func cacheKeyRankArchiveLikes(signID int64) string {
return fmt.Sprintf("rank_likes_%d", signID)
}
var dataTypes = []mcnmodel.DataType{
mcnmodel.DataTypeAccumulate,
mcnmodel.DataTypeDay,
mcnmodel.DataTypeWeek,
mcnmodel.DataTypeMonth,
mcnmodel.DataTypeActiveFans,
}
// --------------------------------------- load rank up fans -------------------------------
func (d *Dao) loadRankUpFansCache(signID int64, date time.Time) (result *RankByTid, err error) {
rawRanks, err := d.RawRankUpFans(signID, date)
if err != nil {
log.Error("fail to get raw rank up fans, signid=%d, err=%s", signID, err)
return
}
result = new(RankByTid)
if len(rawRanks) == 0 {
log.Info("up fans rank data is empty, sign id=%d", signID)
return
}
var midMap = make(map[int64]struct{})
//var accumulateMap = make(map[int64]*mcnmodel.McnRankUpFan)
// 获取mid列表
for _, v := range rawRanks {
midMap[v.UpMid] = struct{}{}
//if v.DataType == mcnmodel.DataTypeAccumulate {
// accumulateMap[v.UpMid] = v
//}
}
var mids []int64
for k := range midMap {
mids = append(mids, k)
}
// 获取账号信息,头像
accInfos, err := global.GetInfos(context.Background(), mids)
if err != nil || accInfos == nil {
log.Warn("get infos fail, err=%s", err)
}
var tidUnique = newTidNameUnique()
// 组装信息
for _, v := range rawRanks {
var info mcnmodel.RankUpFansInfo
info.Copy(v)
if account, ok := accInfos[v.UpMid]; ok {
info.Name = account.Name
info.UpFaceLink = account.Face
info.TidName = cache.GetTidName(int64(info.Tid))
if info.TidName == "" {
info.TidName = "其他"
}
tidUnique.addTid(info.Tid, info.TidName, info.DataType)
}
//if accumulateData, ok := accumulateMap[v.UpMid]; ok {
// info.FansAccumulate = accumulateData.Value1
//}
result.addRank(&info)
}
result.addTidMap(tidUnique)
// 排序
result.Sort(byValueDesc)
// 截断到10个截断需要在排序之后
result.Truncate(10)
return
}
//RawRankUpFans get from db
func (d *Dao) RawRankUpFans(signID int64, date time.Time) (result []*mcnmodel.McnRankUpFan, err error) {
// 有X种类型
// 昨日、上周、上月、累计
// 每种类型取最近日期的数据
for _, typ := range dataTypes {
var tmpResult []*mcnmodel.McnRankUpFan
e := d.mcndb.Raw(`select * from mcn_rank_up_fans where data_type=? and sign_id=?
and generate_date=(select generate_date from mcn_rank_up_fans where data_type=? and sign_id=? and generate_date <= ? order by generate_date desc limit 1)`,
typ, signID, typ, signID, date).
Find(&tmpResult).Error
if e != nil {
log.Error("fail to get rank, type=%d, sign id=%d, err=%s", typ, signID, e)
continue
}
result = append(result, tmpResult...)
}
log.Info("get rank from db, sign id=%d, len=%d, date=%s", signID, len(result), date.Format(dateFmt))
return
}
//ReloadRank reload rank from db
func (d *Dao) ReloadRank(signID int64) (err error) {
// load cache
v, err := d.loadRankUpFansCache(signID, time.Now())
if err != nil {
log.Error("load cache error, signID=%d, err=%s", signID, err)
return
}
var key = cacheKeyRankFans(signID)
d.localcache.SetWithExpire(key, v, time.Hour)
log.Info("reload rank cache, sign id=%d", signID)
return
}
// ----------------------------------------- load rank archive likes ------------------------------------
func (d *Dao) loadRankArchiveLikesCache(signID int64, date time.Time) (result *RankByTid, err error) {
rawArchiveLike, err := d.RawRankArchiveLikes(signID, date)
if err != nil {
log.Error("fail to get raw rank up fans, signid=%d, err=%s", signID, err)
return
}
result = new(RankByTid)
if len(rawArchiveLike) == 0 {
log.Info("archive likes rank data is empty, sign id=%d", signID)
return
}
// 获取 aid列表
var aids []int64
//var accumulateMap = make(map[int64]*mcnmodel.McnRankArchiveLike)
for _, v := range rawArchiveLike {
aids = append(aids, v.ArchiveID)
//if v.DataType == mcnmodel.DataTypeAccumulate {
// accumulateMap[v.ArchiveID] = v
//}
}
aids = util.Unique(aids)
// 获取archive信息
arcsReply, err := global.GetArcGRPC().Arcs(context.Background(), &arcgrpc.ArcsRequest{Aids: aids})
if err != nil {
log.Error("fail to get archive info, sign_id=%d err=%s", signID, err)
return
}
archiveDataMap := arcsReply.Arcs
var tidUnique = newTidNameUnique()
// 组装archive信息
for _, v := range rawArchiveLike {
var info = mcnmodel.RankArchiveLikeInfo{}
info.CopyFromDB(v)
var archive, ok = archiveDataMap[v.ArchiveID]
if !ok {
continue
}
info.CopyFromArchive(archive)
tidUnique.addTid(info.Tid, info.TidName, info.DataType)
//if accumulateData, ok := accumulateMap[v.ArchiveID]; ok {
// info.LikesAccumulate = accumulateData.LikeCount
//}
result.addRank(&info)
}
result.addTidMap(tidUnique)
// 排序
result.Sort(byValueDesc)
result.Truncate(10)
return
}
//RawRankArchiveLikes get from db
func (d *Dao) RawRankArchiveLikes(signID int64, date time.Time) (result []*mcnmodel.McnRankArchiveLike, err error) {
// 有X种类型
// 昨日、上周、上月、累计
// 每种类型取最近日期的数据
for _, typ := range dataTypes {
var tmpResult []*mcnmodel.McnRankArchiveLike
e := d.mcndb.Raw(`select * from mcn_rank_archive_likes where data_type=? and sign_id=?
and generate_date=(select generate_date from mcn_rank_archive_likes where data_type=? and sign_id=? and generate_date <= ? order by generate_date desc limit 1)`,
typ, signID, typ, signID, date).
Find(&tmpResult).Error
if e != nil {
log.Error("fail to get rank, type=%d, sign id=%d, err=%s", typ, signID, e)
continue
}
result = append(result, tmpResult...)
}
log.Info("get rank from db, sign id=%d, len=%d, date=%s", signID, len(result), date.Format(dateFmt))
return
}

View File

@@ -0,0 +1,193 @@
package mcndao
import (
"testing"
"time"
"go-common/app/interface/main/mcn/model/mcnmodel"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaobyValueDesc(t *testing.T) {
convey.Convey("byValueDesc", t, func(ctx convey.C) {
var (
p1 = &mcnmodel.RankUpFansInfo{Mid: 1}
p2 = &mcnmodel.RankUpFansInfo{Mid: 2}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := byValueDesc(p1, p2)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoGetRankUpFans(t *testing.T) {
convey.Convey("GetRankUpFans", t, func(ctx convey.C) {
var (
signID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.GetRankUpFans(signID)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoGetRankArchiveLikes(t *testing.T) {
convey.Convey("GetRankArchiveLikes", t, func(ctx convey.C) {
var (
signID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.GetRankArchiveLikes(signID)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaogetRankCache(t *testing.T) {
convey.Convey("getRankCache", t, func(ctx convey.C) {
var (
signID = int64(1)
keyCalc keyFunc
load loadRankFunc
)
keyCalc = cacheKeyRankFans
load = d.loadRankUpFansCache
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.getRankCache(signID, keyCalc, load)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
if result == nil {
ctx.So(result, convey.ShouldBeNil)
} else {
ctx.So(result, convey.ShouldNotBeNil)
}
})
})
})
}
func TestMcndaocacheKeyRankFans(t *testing.T) {
convey.Convey("cacheKeyRankFans", t, func(ctx convey.C) {
var (
signID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := cacheKeyRankFans(signID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaocacheKeyRankArchiveLikes(t *testing.T) {
convey.Convey("cacheKeyRankArchiveLikes", t, func(ctx convey.C) {
var (
signID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := cacheKeyRankArchiveLikes(signID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoloadRankUpFansCache(t *testing.T) {
convey.Convey("loadRankUpFansCache", t, func(ctx convey.C) {
var (
signID = int64(0)
date = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.loadRankUpFansCache(signID, date)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRawRankUpFans(t *testing.T) {
convey.Convey("RawRankUpFans", t, func(ctx convey.C) {
var (
signID = int64(1)
date = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.RawRankUpFans(signID, date)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
if len(result) == 0 {
ctx.So(result, convey.ShouldBeNil)
} else {
ctx.So(result, convey.ShouldNotBeNil)
}
})
})
})
}
func TestMcndaoReloadRank(t *testing.T) {
convey.Convey("ReloadRank", t, func(ctx convey.C) {
var (
signID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.ReloadRank(signID)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoloadRankArchiveLikesCache(t *testing.T) {
convey.Convey("loadRankArchiveLikesCache", t, func(ctx convey.C) {
var (
signID = int64(0)
date = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.loadRankArchiveLikesCache(signID, date)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRawRankArchiveLikes(t *testing.T) {
convey.Convey("RawRankArchiveLikes", t, func(ctx convey.C) {
var (
signID = int64(1)
date = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, err := d.RawRankArchiveLikes(signID, date)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
if len(result) == 0 {
ctx.So(result, convey.ShouldBeEmpty)
} else {
ctx.So(result, convey.ShouldNotBeNil)
}
})
})
})
}

View File

@@ -0,0 +1,183 @@
package mcndao
import (
"context"
"sort"
"time"
"go-common/app/interface/main/mcn/conf"
"go-common/app/interface/main/mcn/dao/cache"
"go-common/app/interface/main/mcn/dao/global"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/log"
"github.com/bluele/gcache"
)
// RecommendPoolCache .
type RecommendPoolCache struct {
// map[tid] list
UpTidMap map[int16][]*mcnmodel.McnGetRecommendPoolInfo
TidTypeList []*mcnmodel.TidnameInfo
}
func (r *RecommendPoolCache) add(v *mcnmodel.McnGetRecommendPoolInfo) {
if v == nil {
return
}
if r.UpTidMap == nil {
r.UpTidMap = make(map[int16][]*mcnmodel.McnGetRecommendPoolInfo)
}
r.UpTidMap[v.ActiveTid] = append(r.UpTidMap[v.ActiveTid], v)
if v.ActiveTid != 0 {
// 加入到全部分类中
r.UpTidMap[0] = append(r.UpTidMap[0], v)
}
}
//RecommendSortFunc sort func
type RecommendSortFunc func(p1, p2 *mcnmodel.McnGetRecommendPoolInfo) bool
//RecommendDataSorter data sorter
type RecommendDataSorter struct {
Datas []*mcnmodel.McnGetRecommendPoolInfo
By RecommendSortFunc // Closure used in the Less method.
}
// Len is part of sort.Interface.
func (s *RecommendDataSorter) Len() int {
return len(s.Datas)
}
// Swap is part of sort.Interface.
func (s *RecommendDataSorter) Swap(i, j int) {
s.Datas[i], s.Datas[j] = s.Datas[j], s.Datas[i]
}
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *RecommendDataSorter) Less(i, j int) bool {
return s.By(s.Datas[i], s.Datas[j])
}
// RecommendSortByFansDesc .
func RecommendSortByFansDesc(p1, p2 *mcnmodel.McnGetRecommendPoolInfo) bool {
return p1.FansCount > p2.FansCount
}
// RecommendSortByFansAsc .
func RecommendSortByFansAsc(p1, p2 *mcnmodel.McnGetRecommendPoolInfo) bool {
return p1.FansCount < p2.FansCount
}
// RecommendSortByMonthFansDesc .
func RecommendSortByMonthFansDesc(p1, p2 *mcnmodel.McnGetRecommendPoolInfo) bool {
return p1.FansCountIncreaseMonth > p2.FansCountIncreaseMonth
}
// RecommendSortByArchiveCountDesc .
func RecommendSortByArchiveCountDesc(p1, p2 *mcnmodel.McnGetRecommendPoolInfo) bool {
return p1.ArchiveCount > p2.ArchiveCount
}
type loadRecommandFunc func() (res *RecommendPoolCache, err error)
func cacheKeyRecommend(int64) string {
return "recommend"
}
//rawGetRecommendPool get recommend pool
func (d *Dao) rawGetRecommendPool() (res []*mcnmodel.McnGetRecommendPoolInfo, err error) {
var dbresult []*mcnmodel.McnUpRecommendPool
err = d.mcndb.Where("state=?", mcnmodel.MCNUPRecommendStateOn).Find(&dbresult).Error
if err != nil {
log.Error("fail to get recommend pool, err=%s", err)
return
}
for _, v := range dbresult {
var info = &mcnmodel.McnGetRecommendPoolInfo{}
info.Copy(v)
res = append(res, info)
}
return
}
func (d *Dao) loadRecommendPool() (res *RecommendPoolCache, err error) {
recommendInfos, err := d.rawGetRecommendPool()
if err != nil {
log.Error("get recommend fail, err=%s", err)
return
}
var midMap = make(map[int64]struct{})
// 获取mid列表
for _, v := range recommendInfos {
midMap[v.UpMid] = struct{}{}
}
var mids []int64
for k := range midMap {
mids = append(mids, k)
}
// 获取账号信息,头像
accInfos, err := global.GetInfos(context.Background(), mids)
if err != nil || accInfos == nil {
log.Warn("get infos fail, err=%s", err)
}
var tidUnique = newTidNameUnique()
res = new(RecommendPoolCache)
for _, v := range recommendInfos {
if account, ok := accInfos[v.UpMid]; ok {
v.UpName = account.Name
}
v.TidName = cache.GetTidName(int64(v.ActiveTid))
// 这里DataTypeAccumulate只是用来记录一下
tidUnique.addTid(v.ActiveTid, v.TidName, mcnmodel.DataTypeAccumulate)
res.add(v)
}
res.TidTypeList = tidUnique.getList(mcnmodel.DataTypeAccumulate)
// 进行默认排序,按照粉丝数,降序
for k := range res.UpTidMap {
sort.Sort(&RecommendDataSorter{Datas: res.UpTidMap[k], By: RecommendSortByFansDesc})
}
return
}
func (d *Dao) getRecommendCache(keyCalc keyFunc, load loadRecommandFunc) (result *RecommendPoolCache, err error) {
var key = keyCalc(0)
v, err := d.localcache.Get(key)
if err != nil {
if err == gcache.KeyNotFoundError {
// load cache
v, err = load()
if err != nil {
log.Error("load cache error, key=%s. err=%s", key, err)
return
}
d.localcache.SetWithExpire(key, v, time.Duration(conf.Conf.RankCache.RecommendPoolExpireTime))
} else {
log.Error("get from gcache err, key=%s, err=%s", key, err)
return
}
}
if v == nil {
return
}
result, _ = v.(*RecommendPoolCache)
return
}
//GetRecommendPool get recommend pool
func (d *Dao) GetRecommendPool() (res *RecommendPoolCache, err error) {
res, err = d.getRecommendCache(cacheKeyRecommend, d.loadRecommendPool)
if err != nil {
log.Error("fail to get recommend pool, err=%s", err)
return
}
return
}

View File

@@ -0,0 +1,162 @@
package mcndao
import (
"go-common/app/interface/main/mcn/model/mcnmodel"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoadd(t *testing.T) {
convey.Convey("add", t, func(ctx convey.C) {
var (
v = &mcnmodel.McnGetRecommendPoolInfo{}
s = &RecommendPoolCache{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
s.add(v)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestMcndaoLen(t *testing.T) {
var (
s = &RecommendDataSorter{}
)
convey.Convey("Len", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := s.Len()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRecommendSortByFansDesc(t *testing.T) {
convey.Convey("RecommendSortByFansDesc", t, func(ctx convey.C) {
var (
p1 = &mcnmodel.McnGetRecommendPoolInfo{}
p2 = &mcnmodel.McnGetRecommendPoolInfo{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := RecommendSortByFansDesc(p1, p2)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRecommendSortByFansAsc(t *testing.T) {
convey.Convey("RecommendSortByFansAsc", t, func(ctx convey.C) {
var (
p1 = &mcnmodel.McnGetRecommendPoolInfo{}
p2 = &mcnmodel.McnGetRecommendPoolInfo{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := RecommendSortByFansAsc(p1, p2)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRecommendSortByMonthFansDesc(t *testing.T) {
convey.Convey("RecommendSortByMonthFansDesc", t, func(ctx convey.C) {
var (
p1 = &mcnmodel.McnGetRecommendPoolInfo{}
p2 = &mcnmodel.McnGetRecommendPoolInfo{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := RecommendSortByMonthFansDesc(p1, p2)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoRecommendSortByArchiveCountDesc(t *testing.T) {
convey.Convey("RecommendSortByArchiveCountDesc", t, func(ctx convey.C) {
var (
p1 = &mcnmodel.McnGetRecommendPoolInfo{}
p2 = &mcnmodel.McnGetRecommendPoolInfo{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := RecommendSortByArchiveCountDesc(p1, p2)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaocacheKeyRecommend(t *testing.T) {
convey.Convey("cacheKeyRecommend", t, func(ctx convey.C) {
var (
a1 = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := cacheKeyRecommend(a1)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaorawGetRecommendPool(t *testing.T) {
convey.Convey("rawGetRecommendPool", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.rawGetRecommendPool()
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(res), convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
})
}
func TestMcndaoloadRecommendPool(t *testing.T) {
convey.Convey("loadRecommendPool", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.loadRecommendPool()
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)
})
})
})
}
func TestMcndaogetRecommendCache(t *testing.T) {
convey.Convey("getRecommendCache", t, func(ctx convey.C) {
var (
keyCalc = cacheKeyRecommend
load = d.loadRecommendPool
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
result, err := d.getRecommendCache(keyCalc, load)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoGetRecommendPool(t *testing.T) {
convey.Convey("GetRecommendPool", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.GetRecommendPool()
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)
})
})
})
}

View File

@@ -0,0 +1,255 @@
package mcndao
import (
"time"
adminmodel "go-common/app/admin/main/mcn/model"
"go-common/app/interface/main/mcn/model"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/app/interface/main/mcn/tool/validate"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
)
var (
signNotInStates = []model.MCNSignState{model.MCNSignStateOnDelete, model.MCNSignStateOnPreOpen, model.MCNSignStateOnExpire, model.MCNSignStateOnClear}
// 从高到低,先找到的返回
// 状态优先级:
// 0 封禁
// 1 签约
// 2
statePriority = []model.MCNSignState{
model.MCNSignStateOnBlock,
model.MCNSignStateOnSign,
model.MCNSignStateOnReject,
model.MCNSignStateOnReview,
model.MCNSignStateNoApply,
}
// mcnSign = mcnmodel.McnSign{}
// mcnUp = mcnmodel.McnUp{}
// UpPermissionApplyCannotApplyStates 在这此状态下不能再申请改变Up主
UpPermissionApplyCannotApplyStates = []adminmodel.MCNUPPermissionState{
adminmodel.MCNUPPermissionStateNoAuthorize, // 待Up主同意
adminmodel.MCNUPPermissionStateReview, // 待审核
}
// UpSignedStates up signed state
UpSignedStates = []model.MCNUPState{
model.MCNUPStateOnSign,
model.MCNUPStateOnPreOpen,
}
)
// GetMcnSignState .
// mcnList, it's all mcn sign found with the state
// state, the mcn's state of qualified, if multiple state found, will be return in priority
func (d *Dao) GetMcnSignState(fields string, mcnMid int64) (mcn *mcnmodel.McnSign, state model.MCNSignState, err error) {
var mcnList []*mcnmodel.McnSign
if err = d.mcndb.Select(fields).Where("mcn_mid=? and state not in(?)", mcnMid, signNotInStates).Find(&mcnList).Error; err != nil {
err = errors.WithStack(err)
return
}
if len(mcnList) == 0 {
log.Warn("mcn not exist, mcn id=%d", mcnMid)
err = ecode.NothingFound
return
}
var stateMap = make(map[model.MCNSignState]*mcnmodel.McnSign)
for _, v := range mcnList {
stateMap[model.MCNSignState(v.State)] = v
}
for _, v := range statePriority {
if mcnValue, ok := stateMap[v]; ok {
state = v
mcn = mcnValue
break
}
}
return
}
// GetUpBind .
func (d *Dao) GetUpBind(query interface{}, args ...interface{}) (upList []*mcnmodel.McnUp, err error) {
if err = d.mcndb.Select("*").Where(query, args...).Find(&upList).Error; err != nil {
if err == gorm.ErrRecordNotFound {
err = nil
} else {
log.Error("fail to get bind up from db, err=%s", err)
return
}
}
return
}
// BindUp .
func (d *Dao) BindUp(up *mcnmodel.McnUp, sign *mcnmodel.McnSign, arg *mcnmodel.McnBindUpApplyReq) (result *mcnmodel.McnUp, affectedRow int64, err error) {
if arg == nil || sign == nil {
return nil, 0, ecode.ServerErr
}
var db *gorm.DB
if up == nil {
up = &mcnmodel.McnUp{
SignID: sign.ID,
}
}
arg.CopyTo(up)
// 如果绑定自己,那么直接接受
if sign.McnMid == arg.UpMid {
up.State = model.MCNUPStateOnSign
// 签约周期为MCN的签约周期
if up.BeginDate == 0 {
up.BeginDate = sign.BeginDate
}
if up.EndDate == 0 {
up.EndDate = sign.EndDate
}
var (
now = time.Now()
date = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
)
if up.BeginDate.Time().After(date) {
up.State = model.MCNUPStateOnPreOpen
}
} else {
// 清除状态为未授权
up.State = model.MCNUPStateNoAuthorize
if !validate.RegHTTPCheck.MatchString(arg.ContractLink) || !validate.RegHTTPCheck.MatchString(arg.UpAuthLink) {
log.Error("contract link or up auth link is not http, arg=%v", arg)
err = ecode.RequestErr
return
}
}
// 判断开始时间与结束时间
if up.BeginDate == 0 || up.EndDate < up.BeginDate {
log.Error("begin date is after end date, arg=%v", arg)
err = ecode.MCNUpBindUpDateError
return
}
db = d.mcndb.Save(up)
affectedRow, err = db.RowsAffected, db.Error
if err != nil {
log.Error("save bind up info fail, err=%s, sign=%v", err, sign)
err = ecode.ServerErr
}
result = up
return
}
// UpdateBindUp .
func (d *Dao) UpdateBindUp(values map[string]interface{}, query interface{}, args ...interface{}) (affectedRow int64, err error) {
var db = d.mcndb.Table(mcnmodel.TableNameMcnUp).Where(query, args...).Updates(values)
affectedRow, err = db.RowsAffected, db.Error
if err != nil {
log.Error("fail to update bind up, err=%s", err)
}
return
}
//UpConfirm up confrim
func (d *Dao) UpConfirm(arg *mcnmodel.McnUpConfirmReq, state model.MCNUPState) (err error) {
var tx = d.mcndb.Begin()
defer func() {
if r := recover(); r != nil || err != nil {
tx.Rollback()
}
}()
var changeMap = map[string]interface{}{
"state": state,
"state_change_time": time.Now(),
}
if arg.Choice {
changeMap["confirm_time"] = time.Now()
}
err = tx.Table(mcnmodel.TableNameMcnUp).
Where("id=? and up_mid=? and state=?", arg.BindID, arg.UpMid, model.MCNUPStateNoAuthorize).
Updates(changeMap).Error
if err != nil {
log.Error("fail to update db, err=%s", err)
return
}
// 表示同意
if arg.Choice {
// 驳回其他的绑定请求
err = tx.Table(mcnmodel.TableNameMcnUp).
Where("id !=? and up_mid=? and state=?", arg.BindID, arg.UpMid, model.MCNUPStateNoAuthorize).
Updates(map[string]interface{}{
"state": model.MCNUPStateOnRefuse,
"state_change_time": time.Now(),
}).Error
if err != nil {
log.Error("fail to update db, err=%s", err)
return
}
}
return tx.Commit().Error
}
// GetBindInfo .
func (d *Dao) GetBindInfo(arg *mcnmodel.McnUpGetBindReq) (res *mcnmodel.McnGetBindReply, err error) {
var result mcnmodel.McnGetBindReply
err = d.mcndb.Raw(`select s.company_name, s.mcn_mid, u.up_auth_link, u.id as bind_id, u.permission as new_permission
from mcn_up as u inner join mcn_sign as s
on s.id = u.sign_id
where u.id = ? and u.up_mid=? and u.state = 0;`, arg.BindID, arg.UpMid).Find(&result).Error
res = &result
return
}
//GetMcnOldInfo 获取冷却中的信息
func (d *Dao) GetMcnOldInfo(mcnMid int64) (res *mcnmodel.McnSign, err error) {
res = new(mcnmodel.McnSign)
err = d.mcndb.Where("mcn_mid=? and state=?", mcnMid, model.MCNSignStateOnCooling).Order("id desc").Limit(1).Find(res).Error
if err != nil && err != gorm.ErrRecordNotFound {
log.Error("fail to get db, err=%s", err)
return
}
return
}
//GetUpPermissionApply 从permission apply表中读取数据
func (d *Dao) GetUpPermissionApply(fields string, query interface{}, args ...interface{}) (res []*mcnmodel.McnUpPermissionApply, err error) {
err = d.mcndb.Select(fields).Where(query, args...).Find(&res).Error
if err != nil {
log.Error("fail to get db, err=%v", err)
return
}
return
}
// GetUpPermissionBindInfo .
func (d *Dao) GetUpPermissionBindInfo(arg *mcnmodel.McnUpGetBindReq) (res *mcnmodel.McnGetBindReply, err error) {
var result mcnmodel.McnGetBindReply
err = d.mcndb.Raw(`select s.company_name, u.mcn_mid, u.up_auth_link, u.id as bind_id, u.old_permission, u.new_permission
from mcn_up_permission_apply as u inner join mcn_sign as s
on s.id = u.sign_id
where u.id = ? and u.up_mid=? and u.state = 0;`, arg.BindID, arg.UpMid).Find(&result).Error
res = &result
return
}
//UpPermissionConfirm up confrim
func (d *Dao) UpPermissionConfirm(arg *mcnmodel.McnUpConfirmReq, state adminmodel.MCNUPPermissionState) (err error) {
var db = d.mcndb
var changeMap = map[string]interface{}{
"state": state,
}
err = db.Table(mcnmodel.TableMcnUpPermissionApply).
Where("id=? and up_mid=? and state=?", arg.BindID, arg.UpMid, adminmodel.MCNUPPermissionStateNoAuthorize).
Updates(changeMap).Error
if err != nil {
log.Error("fail to update db, err=%s", err)
return
}
return
}

View File

@@ -0,0 +1,134 @@
package mcndao
import (
"testing"
"go-common/app/interface/main/mcn/model"
"go-common/app/interface/main/mcn/model/mcnmodel"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestMcndaoGetMcnSignState(t *testing.T) {
convey.Convey("GetMcnSignState", t, func(ctx convey.C) {
var (
fields = "*"
mcnMid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mcn, state, err := d.GetMcnSignState(fields, mcnMid)
ctx.Convey("Then err should be nil.mcn,state should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, -404)
ctx.So(state, convey.ShouldNotBeNil)
ctx.So(mcn, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoGetUpBind(t *testing.T) {
convey.Convey("GetUpBind", t, func(ctx convey.C) {
var (
query = "1=?"
args = "0"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
upList, err := d.GetUpBind(query, args)
ctx.Convey("Then err should be nil.upList should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(upList, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoBindUp(t *testing.T) {
convey.Convey("BindUp", t, func(ctx convey.C) {
var (
up = &mcnmodel.McnUp{}
sign = &mcnmodel.McnSign{}
arg = &mcnmodel.McnBindUpApplyReq{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
result, affectedRow, err := d.BindUp(up, sign, arg)
ctx.Convey("Then err should be nil.result,affectedRow should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, 82010)
ctx.So(affectedRow, convey.ShouldEqual, 0)
ctx.So(result, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoUpdateBindUp(t *testing.T) {
convey.Convey("UpdateBindUp", t, func(ctx convey.C) {
var (
values map[string]interface{}
query = interface{}(0)
args = interface{}(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
affectedRow, err := d.UpdateBindUp(values, query, args)
ctx.Convey("Then err should be nil.affectedRow should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affectedRow, convey.ShouldNotBeNil)
})
})
})
}
func TestMcndaoUpConfirm(t *testing.T) {
convey.Convey("UpConfirm", t, func(ctx convey.C) {
var (
arg = &mcnmodel.McnUpConfirmReq{}
state model.MCNUPState
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.UpConfirm(arg, state)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcndaoGetBindInfo(t *testing.T) {
convey.Convey("GetBindInfo", t, func(ctx convey.C) {
var (
arg = &mcnmodel.McnUpGetBindReq{}
)
arg.BindID = 10
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetBindInfo(arg)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
if err == ecode.NothingFound {
ctx.So(err, convey.ShouldNotBeNil)
} else {
ctx.So(err, convey.ShouldBeNil)
}
if res != nil {
ctx.So(res, convey.ShouldNotBeNil)
} else {
ctx.So(res, convey.ShouldBeNil)
}
})
})
})
}
func TestMcndaoGetMcnOldInfo(t *testing.T) {
convey.Convey("GetMcnOldInfo", t, func(ctx convey.C) {
var (
mcnMid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.GetMcnOldInfo(mcnMid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, -404)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}