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,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"bnj.go",
"service.go",
],
importpath = "go-common/app/interface/main/activity/service/bnj",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/bnj:go_default_library",
"//app/interface/main/activity/dao/like:go_default_library",
"//app/interface/main/activity/model/bnj:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup.v2: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,158 @@
package bnj
import (
"context"
"strings"
"sync/atomic"
"time"
"go-common/library/sync/errgroup.v2"
"go-common/app/interface/main/activity/model/bnj"
arcmdl "go-common/app/service/main/archive/api"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_rewardStepOne = 1
_rewardStepThree = 3
_lastCD = 300
)
// PreviewInfo preview info
func (s *Service) PreviewInfo(c context.Context, mid int64) *bnj.PreviewInfo {
data := &bnj.PreviewInfo{
ActID: s.c.Bnj2019.ActID,
SubID: s.c.Bnj2019.SubID,
}
// TODO del admin check
if err := s.bnjAdminCheck(mid); err != nil {
return data
}
for _, v := range s.c.Bnj2019.Reward {
data.RewardStep = append(data.RewardStep, v.Condition)
}
if s.timeFinish != 0 {
data.TimelinePic = s.c.Bnj2019.TimelinePic
data.H5TimelinePic = s.c.Bnj2019.H5TimelinePic
}
if s.c.Bnj2019.GameCancel != 0 {
data.GameCancel = 1
}
now := time.Now().Unix()
group := errgroup.WithCancel(c)
if mid > 0 && len(s.c.Bnj2019.Reward) > 0 {
for _, v := range s.c.Bnj2019.Reward {
if v.Step > 0 {
step := v.Step
group.Go(func(ctx context.Context) error {
if check, e := s.dao.HasReward(ctx, mid, s.c.Bnj2019.SubID, step); e != nil {
log.Error("Reward s.dao.HasReward(mid:%d,step:%d) error(%v) check(%v)", mid, step, e, check)
} else if check {
switch step {
case _rewardStepOne:
data.HasRewardFirst = 1
case _rewardStepThree:
data.HasRewardSecond = 1
}
}
return nil
})
}
}
}
if err := group.Wait(); err != nil {
log.Error("PreviewInfo group wait error(%v)", err)
}
arcs := s.previewArcs
for _, v := range s.c.Bnj2019.Info {
if v.Publish.Unix() < now {
if arc, ok := arcs[v.Aid]; ok && arc.IsNormal() {
tmp := &bnj.Info{Nav: v.Nav, Pic: v.Pic, H5Pic: v.H5Pic, Detail: v.Detail, H5Detail: v.H5Detail, Arc: &arcmdl.Arc{Aid: v.Aid}}
arc.Pic = strings.Replace(arc.Pic, "http://", "//", 1)
if v.Nickname != "" {
arc.Author.Name = arc.Author.Name + "&" + v.Nickname
}
tmp.Arc = arc
data.Info = append(data.Info, tmp)
}
}
}
if len(data.Info) == 0 {
data.Info = make([]*bnj.Info, 0)
}
return data
}
// Timeline only return timeline and game cancel.
func (s *Service) Timeline(c context.Context, mid int64) *bnj.Timeline {
data := new(bnj.Timeline)
// TODO delete admin check
if err := s.bnjAdminCheck(mid); err != nil {
return data
}
if s.timeFinish != 0 {
data.TimelinePic = s.c.Bnj2019.TimelinePic
data.H5TimelinePic = s.c.Bnj2019.H5TimelinePic
}
if s.c.Bnj2019.GameCancel != 0 {
data.GameCancel = 1
}
data.LikeCount = s.likeCount
return data
}
// TimeReset reset less time.
func (s *Service) TimeReset(c context.Context, mid int64) (ttl int64, err error) {
if time.Now().Unix() < s.c.Bnj2019.Start.Unix() {
err = ecode.ActivityNotStart
return
}
if s.timeFinish != 0 {
err = ecode.ActivityBnjTimeFinish
return
}
var value bool
if value, err = s.dao.CacheResetCD(c, mid, s.resetCD); err != nil {
log.Error("TimeReset s.dao.CacheResetCD(%d) error(%v) value(%v)", mid, err, value)
err = nil
return
}
if !value {
if ttl, err = s.dao.TTLResetCD(c, mid); err != nil {
log.Error("TimeReset s.dao.TTLResetCD(%d) error(%v) value(%v)", mid, err)
err = nil
}
return
}
if s.timeReset == 0 {
atomic.StoreInt64(&s.resetMid, mid)
atomic.StoreInt64(&s.timeReset, 1)
}
return
}
// DelTime .
func (s *Service) DelTime(c context.Context, key string) (err error) {
switch key {
case "time_finish":
if err = s.dao.DelCacheTimeFinish(c); err != nil {
log.Error("DelTime DelCacheTimeFinish error(%v)", err)
}
case "time_less":
if err = s.dao.DelCacheTimeLess(c); err != nil {
log.Error("DelTime DelCacheTimeLess error(%v)", err)
}
}
return
}
func (s *Service) bnjAdminCheck(mid int64) (err error) {
if s.c.Bnj2019.AdminCheck != 0 {
if _, ok := s.bnjAdmins[mid]; !ok {
err = ecode.AccessDenied
}
}
return
}

View File

@@ -0,0 +1,159 @@
package bnj
import (
"context"
"strconv"
"sync/atomic"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/dao/bnj"
"go-common/app/interface/main/activity/dao/like"
bnjmdl "go-common/app/interface/main/activity/model/bnj"
arcclient "go-common/app/service/main/archive/api"
"go-common/library/log"
"go-common/library/queue/databus"
)
// Service .
type Service struct {
c *conf.Config
arcClient arcclient.ArchiveClient
dao *bnj.Dao
likeDao *like.Dao
resetPub *databus.Databus
previewArcs map[int64]*arcclient.Arc
bnjAdmins map[int64]struct{}
likeCount int64
timeReset int64
resetMid int64
timeFinish int64
resetCD int32
}
// New init bnj service.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: bnj.New(c),
likeDao: like.New(c),
resetPub: databus.New(c.Databus.Bnj),
}
var err error
if s.arcClient, err = arcclient.NewClient(c.ArcClient); err != nil {
panic(err)
}
if s.c.Bnj2019.AdminCheck != 0 {
tmp := make(map[int64]struct{}, len(s.c.Bnj2019.Admins))
for _, mid := range s.c.Bnj2019.Admins {
tmp[mid] = struct{}{}
}
s.bnjAdmins = tmp
}
go s.bnjTimeproc()
return s
}
// Close .
func (s *Service) Close() {
s.dao.Close()
s.resetPub.Close()
}
func (s *Service) timeResetproc() {
for {
time.Sleep(time.Second)
if s.timeFinish != 0 {
log.Info("timeResetproc finish")
break
}
if s.timeReset == 1 {
// sub databus
msg := &bnjmdl.ResetMsg{Mid: s.resetMid, Ts: time.Now().Unix()}
if err := s.resetPub.Send(context.Background(), strconv.FormatInt(s.resetMid, 10), msg); err != nil {
log.Error("timeResetproc s.resetPub.Send(%+v) error(%v)", msg, err)
}
atomic.StoreInt64(&s.timeReset, 0)
atomic.StoreInt64(&s.resetMid, 0)
}
}
}
func (s *Service) timeFinishproc() {
for {
time.Sleep(time.Second)
if value, err := s.dao.CacheTimeFinish(context.Background()); err != nil {
log.Error("timeFinishproc s.dao.CacheTimeFinish error(%v)")
} else if value > 0 {
log.Info("timeFinishproc cache value finish")
atomic.StoreInt64(&s.timeFinish, value)
}
}
}
func (s *Service) bnjTimeproc() {
for {
time.Sleep(time.Second)
if time.Now().Unix() > s.c.Bnj2019.Start.Unix() {
go s.timeResetproc()
go s.timeFinishproc()
go s.bnjResetCDproc()
go s.bnjArcproc()
log.Info("bnjTimeproc start")
break
}
}
}
func (s *Service) bnjResetCDproc() {
for {
time.Sleep(time.Second)
lid := s.c.Bnj2019.SubID
scoreMap, err := s.likeDao.LikeActLidCounts(context.Background(), []int64{lid})
if err != nil || scoreMap == nil {
log.Error("bnjScoreproc s.likeDao.LikeActLidCounts(%d) error(%v)", lid, err)
continue
}
if score, ok := scoreMap[lid]; ok {
if score >= s.c.Bnj2019.Reward[len(s.c.Bnj2019.Reward)-1].Condition && s.resetCD != _lastCD {
atomic.StoreInt32(&s.resetCD, _lastCD)
log.Info("bnjResetCDproc finish")
}
if score > s.likeCount {
atomic.StoreInt64(&s.likeCount, score)
}
}
}
}
func (s *Service) bnjArcproc() {
for {
time.Sleep(time.Second)
now := time.Now().Unix()
var aids []int64
for _, v := range s.c.Bnj2019.Info {
if v.Publish.Unix() < now {
if v.Aid > 0 {
aids = append(aids, v.Aid)
}
}
}
if len(aids) > 0 {
if arcsReply, err := s.arcClient.Arcs(context.Background(), &arcclient.ArcsRequest{Aids: aids}); err != nil {
log.Error("bnjArcproc s.arcClient.Arcs(%v) error(%v)", aids, err)
} else if len(arcsReply.Arcs) > 0 {
tmp := make(map[int64]*arcclient.Arc, len(aids))
for _, aid := range aids {
if arc, ok := arcsReply.Arcs[aid]; ok && arc != nil {
tmp[aid] = arc
} else {
log.Error("bnjArcproc aid(%d) data(%v)", aid, arc)
continue
}
}
s.previewArcs = tmp
}
}
log.Error("bnjArcproc aids(%v) conf error", aids)
}
}

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 = [
"achievement.go",
"bws.go",
"check.go",
"lottery.go",
"point.go",
],
importpath = "go-common/app/interface/main/activity/service/bws",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/bws:go_default_library",
"//app/interface/main/activity/model/bws:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time: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 = ["bws_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/model/bws:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,189 @@
package bws
import (
"context"
"time"
bwsmdl "go-common/app/interface/main/activity/model/bws"
suitmdl "go-common/app/service/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
)
// Award achievement award
func (s *Service) Award(c context.Context, loginMid int64, p *bwsmdl.ParamAward) (err error) {
var (
userAchieves []*bwsmdl.UserAchieve
userAward int64 = -1
)
if _, ok := s.awardMids[loginMid]; !ok {
err = ecode.ActivityNotAwardAdmin
return
}
if p.Key == "" {
if p.Key, err = s.midToKey(c, p.Mid); err != nil {
return
}
}
if userAchieves, err = s.dao.UserAchieves(c, p.Bid, p.Key); err != nil {
err = ecode.ActivityAchieveFail
return
}
if len(userAchieves) == 0 {
err = ecode.ActivityNoAchieve
return
}
for _, v := range userAchieves {
if v.Aid == p.Aid {
userAward = v.Award
break
}
}
if userAward == -1 {
err = ecode.ActivityNoAchieve
return
} else if userAward == _noAward {
err = ecode.ActivityNoAward
return
} else if userAward == _awardAlready {
err = ecode.ActivityAwardAlready
return
}
if err = s.dao.Award(c, p.Key, p.Aid); err != nil {
log.Error("s.dao.Award key(%s) error(%v)", p.Key, err)
}
s.dao.DelCacheUserAchieves(c, p.Bid, p.Key)
return
}
// Achievements achievements list
func (s *Service) Achievements(c context.Context, p *bwsmdl.ParamID) (rs *bwsmdl.Achievements, err error) {
var mapCnt map[int64]int64
if rs, err = s.dao.Achievements(c, p.Bid); err != nil || rs == nil || len(rs.Achievements) == 0 {
log.Error("s.dao.Achievements error(%v)", err)
err = ecode.ActivityAchieveFail
return
}
if mapCnt, err = s.countAchieves(c, p.Bid, p.Day); err != nil || len(mapCnt) == 0 {
err = nil
return
}
for _, achieve := range rs.Achievements {
achieve.UserCount = mapCnt[achieve.ID]
}
return
}
func (s *Service) countAchieves(c context.Context, bid int64, day string) (rs map[int64]int64, err error) {
var countAchieves []*bwsmdl.CountAchieves
if day == "" {
day = today()
}
if countAchieves, err = s.dao.AchieveCounts(c, bid, day); err != nil {
log.Error("s.dao.RawCountAchieves error(%v)", err)
return
}
rs = make(map[int64]int64, len(countAchieves))
for _, countAchieve := range countAchieves {
rs[countAchieve.Aid] = countAchieve.Count
}
return
}
// Achievement Achievement
func (s *Service) Achievement(c context.Context, p *bwsmdl.ParamID) (rs *bwsmdl.Achievement, err error) {
var (
achieves *bwsmdl.Achievements
)
if achieves, err = s.dao.Achievements(c, p.Bid); err != nil || achieves == nil || len(achieves.Achievements) == 0 {
log.Error("s.dao.Achievements error(%v)", err)
err = ecode.ActivityAchieveFail
return
}
for _, Achievement := range achieves.Achievements {
if Achievement.ID == p.ID {
rs = Achievement
break
}
}
if rs == nil {
err = ecode.ActivityIDNotExists
}
return
}
func (s *Service) userAchieves(c context.Context, bid int64, key string) (res []*bwsmdl.UserAchieveDetail, err error) {
var (
usAchieves []*bwsmdl.UserAchieve
achieves *bwsmdl.Achievements
)
if usAchieves, err = s.dao.UserAchieves(c, bid, key); err != nil {
err = ecode.ActivityUserAchieveFail
return
}
if len(usAchieves) == 0 {
return
}
if achieves, err = s.dao.Achievements(c, bid); err != nil || achieves == nil || len(achieves.Achievements) == 0 {
err = ecode.ActivityAchieveFail
return
}
achievesMap := make(map[int64]*bwsmdl.Achievement, len(achieves.Achievements))
for _, v := range achieves.Achievements {
achievesMap[v.ID] = v
}
for _, v := range usAchieves {
detail := &bwsmdl.UserAchieveDetail{UserAchieve: v}
if achieve, ok := achievesMap[v.Aid]; ok {
detail.Name = achieve.Name
detail.Icon = achieve.Icon
detail.Dic = achieve.Dic
detail.LockType = achieve.LockType
detail.Unlock = achieve.Unlock
detail.Bid = achieve.Bid
detail.IconBig = achieve.IconBig
detail.IconActive = achieve.IconActive
detail.IconActiveBig = achieve.IconActiveBig
detail.SuitID = achieve.SuitID
}
res = append(res, detail)
}
return
}
func (s *Service) addAchieve(c context.Context, mid int64, achieve *bwsmdl.Achievement, key string) (err error) {
var uaID int64
if uaID, err = s.dao.AddUserAchieve(c, achieve.Bid, achieve.ID, achieve.Award, key); err != nil {
err = ecode.ActivityAddAchieveFail
return
}
if err = s.dao.AppendUserAchievesCache(c, achieve.Bid, key, &bwsmdl.UserAchieve{ID: uaID, Aid: achieve.ID, Award: achieve.Award, Ctime: xtime.Time(time.Now().Unix())}); err != nil {
return
}
s.cache.Do(c, func(c context.Context) {
s.dao.IncrCacheAchieveCounts(c, achieve.Bid, achieve.ID, today())
var (
keyID int64
e error
)
if mid == 0 {
if mid, keyID, e = s.keyToMid(c, key); e != nil || mid == 0 {
log.Warn("Lottery keyID(%d) key(%s) error(%v)", keyID, key, e)
}
}
if mid > 0 {
if achieve.SuitID > 0 {
arg := &suitmdl.ArgGrantByMids{Mids: []int64{mid}, Pid: achieve.SuitID, Expire: s.c.Rule.BwsSuitExpire}
if e := s.suitRPC.GrantByMids(c, arg); e != nil {
log.Error("addAchieve s.suit.GrantByMids(%d,%d) error(%v)", mid, achieve.SuitID, e)
}
log.Warn("Suit mid(%d) suitID(%d)", mid, achieve.SuitID)
}
if _, ok := s.lotteryAids[achieve.ID]; ok {
s.dao.AddLotteryMidCache(c, achieve.ID, mid)
}
}
})
return
}

View File

@@ -0,0 +1,331 @@
package bws
import (
"context"
"strconv"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/dao/bws"
bwsmdl "go-common/app/interface/main/activity/model/bws"
accapi "go-common/app/service/main/account/api"
suitmdl "go-common/app/service/main/usersuit/model"
suitrpc "go-common/app/service/main/usersuit/rpc/client"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/sync/pipeline/fanout"
)
const (
_accountBlocked = 1
_allType = 0
_dpType = 1
_gameType = 2
_clockinType = 3
_eggType = 4
_dp = "dp"
_game = "game"
_clockin = "clockin"
_egg = "egg"
_noAward = 0
_awardAlready = 2
_initLinkType = 5
)
var (
_emptPoints = make([]*bwsmdl.Point, 0)
_emptUserPoints = make([]*bwsmdl.UserPointDetail, 0)
_emptyUserAchieves = make([]*bwsmdl.UserAchieveDetail, 0)
)
// Service struct
type Service struct {
c *conf.Config
dao *bws.Dao
accClient accapi.AccountClient
suitRPC *suitrpc.Service2
// bws admin mids
allowMids map[int64]struct{}
awardMids map[int64]struct{}
lotteryMids map[int64]struct{}
lotteryAids map[int64]struct{}
cache *fanout.Fanout
}
// New Service
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: bws.New(c),
suitRPC: suitrpc.New(c.RPCClient2.Suit),
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
}
var err error
if s.accClient, err = accapi.NewClient(c.AccClient); err != nil {
panic(err)
}
s.initMids()
s.initLotteryAids()
return
}
func (s *Service) initMids() {
tmpMids := make(map[int64]struct{}, len(s.c.Rule.BwsMids))
tmpAward := make(map[int64]struct{}, len(s.c.Rule.BwsMids)+len(s.c.Rule.BwsAwardMids))
tmpLottery := make(map[int64]struct{}, len(s.c.Rule.BwsMids)+len(s.c.Rule.BwsLotteryMids))
for _, id := range s.c.Rule.BwsMids {
tmpMids[id] = struct{}{}
tmpAward[id] = struct{}{}
tmpLottery[id] = struct{}{}
}
for _, id := range s.c.Rule.BwsAwardMids {
tmpAward[id] = struct{}{}
}
for _, id := range s.c.Rule.BwsLotteryMids {
tmpLottery[id] = struct{}{}
}
s.allowMids = tmpMids
s.awardMids = tmpAward
s.lotteryMids = tmpLottery
}
func (s *Service) initLotteryAids() {
tmp := make(map[int64]struct{}, len(s.c.Rule.BwsLotteryAids))
for _, id := range s.c.Rule.BwsLotteryAids {
tmp[id] = struct{}{}
}
s.lotteryAids = tmp
}
// User user info.
func (s *Service) User(c context.Context, bid, mid int64, key string) (user *bwsmdl.User, err error) {
var (
hp, keyID int64
ac *accapi.CardReply
points, dps, games, clockins, eggs []*bwsmdl.UserPointDetail
achErr, pointErr error
)
if key == "" {
if key, err = s.midToKey(c, mid); err != nil {
return
}
} else {
if mid, keyID, err = s.keyToMid(c, key); err != nil {
return
}
}
user = new(bwsmdl.User)
if mid != 0 {
if ac, err = s.accCard(c, mid); err != nil {
log.Error("User s.accCard(%d) error(%v)", mid, err)
return
}
}
if ac != nil && ac.Card != nil {
user.User = &bwsmdl.UserInfo{
Mid: ac.Card.Mid,
Name: ac.Card.Name,
Face: ac.Card.Face,
Key: key,
}
} else {
user.User = &bwsmdl.UserInfo{
Name: strconv.FormatInt(keyID, 10),
Key: key,
}
}
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
if user.Achievements, achErr = s.userAchieves(errCtx, bid, key); achErr != nil {
log.Error("User s.userAchieves(%d,%s) error(%v)", bid, key, achErr)
}
return nil
})
group.Go(func() error {
if points, pointErr = s.userPoints(errCtx, bid, key); pointErr != nil {
log.Error("User s.userPoints(%d,%s) error(%v)", bid, key, pointErr)
}
return nil
})
group.Wait()
if len(user.Achievements) == 0 {
user.Achievements = _emptyUserAchieves
}
user.Items = make(map[string][]*bwsmdl.UserPointDetail, 4)
gidMap := make(map[int64]int64, len(points))
for _, v := range points {
switch v.LockType {
case _dpType:
dps = append(dps, v)
case _gameType:
if v.Points == v.Unlocked {
if _, ok := gidMap[v.Pid]; !ok {
games = append(games, v)
}
gidMap[v.Pid] = v.Pid
}
case _clockinType:
clockins = append(clockins, v)
case _eggType:
eggs = append(eggs, v)
}
hp += v.Points
}
user.User.Hp = hp
if len(dps) == 0 {
user.Items[_dp] = _emptUserPoints
} else {
user.Items[_dp] = dps
}
if len(games) == 0 {
user.Items[_game] = _emptUserPoints
} else {
user.Items[_game] = games
}
if len(clockins) == 0 {
user.Items[_clockin] = _emptUserPoints
} else {
user.Items[_clockin] = clockins
}
if len(eggs) == 0 {
user.Items[_egg] = _emptUserPoints
} else {
user.Items[_egg] = eggs
}
return
}
func (s *Service) accCard(c context.Context, mid int64) (ac *accapi.CardReply, err error) {
var (
arg = &accapi.MidReq{Mid: mid}
)
if ac, err = s.accClient.Card3(c, arg); err != nil || ac == nil {
log.Error("s.accRPC.Card3(%d) error(%v)", mid, err)
err = ecode.AnswerAccCallErr
} else if ac.Card.Silence == _accountBlocked {
err = ecode.UserDisabled
}
return
}
// Binding binding by mid
func (s *Service) Binding(c context.Context, loginMid int64, p *bwsmdl.ParamBinding) (err error) {
var (
achieves *bwsmdl.Achievements
users *bwsmdl.Users
checkMid int64
)
if _, err = s.accCard(c, loginMid); err != nil {
log.Error("s.accCard(%d) error(%v)", loginMid, err)
return
}
if checkMid, _, err = s.keyToMid(c, p.Key); err != nil {
return
}
if checkMid != 0 {
err = ecode.ActivityKeyBindAlready
return
}
if users, err = s.dao.UsersMid(c, loginMid); err != nil {
err = ecode.ActivityKeyFail
return
}
if users != nil && users.Key != "" {
err = ecode.ActivityMidBindAlready
return
}
if err = s.dao.Binding(c, loginMid, p); err != nil {
log.Error("s.dao.Binding mid(%d) key(%s) error(%v)", loginMid, p.Key, err)
return
}
if s.c.Rule.NeedInitAchieve {
if achieves, err = s.dao.Achievements(c, p.Bid); err != nil {
log.Error("s.dao.Achievements error(%v)", err)
err = ecode.ActivityAchieveFail
return
}
if achieves == nil || len(achieves.Achievements) == 0 {
err = ecode.ActivityNoAchieve
return
}
for _, achieve := range achieves.Achievements {
if achieve.LockType == _initLinkType {
s.addAchieve(c, loginMid, achieve, p.Key)
break
}
}
var userAchieves []*bwsmdl.UserAchieveDetail
if userAchieves, err = s.userAchieves(c, p.Bid, p.Key); err != nil {
log.Error("Binding add suit key(%s) mid(%d) %+v", p.Key, loginMid, err)
err = nil
} else {
for _, v := range userAchieves {
if v.LockType == _initLinkType {
continue
}
if suitID := v.SuitID; suitID != 0 {
log.Warn("Binding suit mid(%d) suitID(%d) expire(%d)", loginMid, suitID, s.c.Rule.BwsSuitExpire)
s.cache.Do(c, func(c context.Context) {
arg := &suitmdl.ArgGrantByMids{Mids: []int64{loginMid}, Pid: suitID, Expire: s.c.Rule.BwsSuitExpire}
if e := s.suitRPC.GrantByMids(c, arg); e != nil {
log.Error("Binding s.suit.GrantByMids(%d,%d) error(%v)", loginMid, suitID, e)
}
})
}
if _, ok := s.lotteryAids[v.Aid]; ok {
lotteryAid := v.Aid
log.Warn("Binding lottery mid(%d) achieve id(%d) expire(%d)", loginMid, lotteryAid, s.c.Rule.BwsSuitExpire)
s.cache.Do(c, func(c context.Context) {
s.dao.AddLotteryMidCache(c, lotteryAid, loginMid)
})
}
}
}
}
s.dao.DelCacheUsersKey(c, p.Key)
s.dao.DelCacheUsersMid(c, loginMid)
return
}
func (s *Service) isAdmin(mid int64) bool {
if _, ok := s.allowMids[mid]; ok {
return true
}
return false
}
func (s *Service) midToKey(c context.Context, mid int64) (key string, err error) {
var users *bwsmdl.Users
if users, err = s.dao.UsersMid(c, mid); err != nil {
err = ecode.ActivityKeyFail
return
}
if users == nil || users.Key == "" {
err = ecode.ActivityNotBind
return
}
key = users.Key
return
}
func (s *Service) keyToMid(c context.Context, key string) (mid, keyID int64, err error) {
var users *bwsmdl.Users
if users, err = s.dao.UsersKey(c, key); err != nil {
err = ecode.ActivityKeyFail
return
}
if users == nil || users.Key == "" {
err = ecode.ActivityKeyNotExists
return
}
if users.Mid > 0 {
mid = users.Mid
}
keyID = users.ID
return
}
func today() string {
return time.Now().Format("20060102")
}

View File

@@ -0,0 +1,42 @@
package bws
import (
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/activity/conf"
"context"
"go-common/app/interface/main/activity/model/bws"
. "github.com/smartystreets/goconvey/convey"
)
var svf *Service
func WithService(f func(s *Service)) func() {
return func() {
dir, _ := filepath.Abs("../../cmd/activity-test.toml")
flag.Set("conf", dir)
conf.Init()
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(2 * time.Second)
f(svf)
}
}
func TestService_Binding(t *testing.T) {
Convey("test binding", t, WithService(func(s *Service) {
logMid := int64(1)
p := &bws.ParamBinding{
Bid: 1,
Key: "",
}
err := s.Binding(context.Background(), logMid, p)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,210 @@
package bws
import (
"context"
"encoding/json"
bwsmdl "go-common/app/interface/main/activity/model/bws"
"go-common/library/ecode"
"go-common/library/log"
)
// RedisInfo .
func (s *Service) RedisInfo(c context.Context, loginMid, mid int64, key, day, typ string, del int) (data json.RawMessage, err error) {
if !s.isAdmin(loginMid) {
err = ecode.ActivityNotAdmin
return
}
if key == "" {
if key, err = s.midToKey(c, mid); err != nil {
return
}
}
var (
bid int64 = 1
bs []byte
)
switch typ {
case "point":
if del == 1 {
err = s.dao.DelCachePoints(c, bid)
return
}
var points *bwsmdl.Points
if points, err = s.dao.CachePoints(c, bid); err != nil || points == nil || len(points.Points) == 0 {
log.Error("RedisInfo point error (%v)", err)
return
}
if bs, err = json.Marshal(points.Points); err != nil {
log.Error("RedisInfo point json error (%v)", err)
return
}
data = json.RawMessage(bs)
case "achieve":
if del == 1 {
err = s.dao.DelCacheAchievements(c, bid)
return
}
var achieves *bwsmdl.Achievements
if achieves, err = s.dao.CacheAchievements(c, bid); err != nil || achieves == nil || len(achieves.Achievements) == 0 {
log.Error("RedisInfo achieve error (%v)", err)
return
}
if bs, err = json.Marshal(achieves.Achievements); err != nil {
log.Error("RedisInfo achieve json error (%v)", err)
return
}
data = json.RawMessage(bs)
case "user_point":
if del == 1 {
err = s.dao.DelCacheUserPoints(c, bid, key)
return
}
var res []*bwsmdl.UserPoint
if res, err = s.dao.CacheUserPoints(c, bid, key); err != nil {
log.Error("RedisInfo user point key(%s) error (%v)", key, err)
return
}
if bs, err = json.Marshal(res); err != nil {
log.Error("RedisInfo user point json error (%v)", err)
return
}
data = json.RawMessage(bs)
case "user_achieve":
if del == 1 {
err = s.dao.DelCacheUserAchieves(c, bid, key)
return
}
var res []*bwsmdl.UserAchieve
if res, err = s.dao.CacheUserAchieves(c, bid, key); err != nil {
log.Error("RedisInfo user achieve key(%s) error (%v)", key, err)
return
}
if bs, err = json.Marshal(res); err != nil {
log.Error("RedisInfo user achieve json error (%v)", err)
return
}
data = json.RawMessage(bs)
case "achieve_cnt":
if day == "" {
day = today()
}
if del == 1 {
err = s.dao.DelCacheAchieveCounts(c, bid, day)
return
}
var res []*bwsmdl.CountAchieves
if res, err = s.dao.CacheAchieveCounts(c, bid, day); err != nil {
log.Error("RedisInfo achieve_cnt day(%s) error (%v)", day, err)
return
}
if bs, err = json.Marshal(res); err != nil {
log.Error("RedisInfo achieve_cnt json error (%v)", err)
return
}
data = json.RawMessage(bs)
case "achieve_cnt_db":
if day == "" {
day = today()
}
var res []*bwsmdl.CountAchieves
if res, err = s.dao.RawAchieveCounts(c, bid, day); err != nil {
log.Error("RedisInfo achieve_cnt_db day(%s) error (%v)", day, err)
return
}
if bs, err = json.Marshal(res); err != nil {
log.Error("RedisInfo achieve_cnt_db json error (%v)", err)
return
}
data = json.RawMessage(bs)
default:
err = ecode.RequestErr
}
return
}
// KeyInfo .
func (s *Service) KeyInfo(c context.Context, loginMid, keyID, mid int64, key, typ string, del int) (data json.RawMessage, err error) {
if !s.isAdmin(loginMid) {
err = ecode.ActivityNotAdmin
return
}
var (
bs []byte
)
switch typ {
case "id":
if keyID == 0 {
err = ecode.RequestErr
return
}
var user *bwsmdl.Users
if user, err = s.dao.UserByID(c, keyID); err != nil {
return
}
if bs, err = json.Marshal(user); err != nil {
return
}
data = json.RawMessage(bs)
case "mid":
if mid == 0 {
err = ecode.RequestErr
return
}
if del == 1 {
err = s.dao.DelCacheUsersMid(c, mid)
return
}
var res *bwsmdl.Users
if res, err = s.dao.CacheUsersMid(c, mid); err != nil {
return
}
if bs, err = json.Marshal(res); err != nil {
return
}
data = json.RawMessage(bs)
case "key":
if key == "" {
err = ecode.RequestErr
return
}
if del == 1 {
err = s.dao.DelCacheUsersKey(c, key)
return
}
var res *bwsmdl.Users
if res, err = s.dao.CacheUsersKey(c, key); err != nil {
return
}
if bs, err = json.Marshal(res); err != nil {
return
}
data = json.RawMessage(bs)
default:
err = ecode.RequestErr
}
return
}
// AdminInfo get admin info.
func (s *Service) AdminInfo(c context.Context, bid, mid int64) (data *bwsmdl.AdminInfo, err error) {
data = new(bwsmdl.AdminInfo)
if s.isAdmin(mid) {
data.IsAdmin = true
}
var points *bwsmdl.Points
if points, err = s.dao.Points(c, bid); err != nil || points == nil || len(points.Points) == 0 {
log.Error("s.dao.Points error(%v)", err)
err = ecode.ActivityPointFail
return
}
for _, v := range points.Points {
if v.Ower == mid {
data.Point = v
}
}
if data.Point == nil {
data.Point = struct{}{}
}
return
}

View File

@@ -0,0 +1,53 @@
package bws
import (
"context"
bwsmdl "go-common/app/interface/main/activity/model/bws"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
)
// Lottery get lottery account.
func (s *Service) Lottery(c context.Context, bid, loginMid, aid int64, day string) (data *bwsmdl.LotteryUser, err error) {
var (
mid int64
accData *accapi.InfoReply
)
if _, ok := s.lotteryMids[loginMid]; !ok {
err = ecode.ActivityNotLotteryAdmin
return
}
if _, ok := s.lotteryAids[aid]; !ok {
err = ecode.ActivityNotLotteryAchieve
return
}
if _, err = s.Achievement(c, &bwsmdl.ParamID{Bid: bid, ID: aid}); err != nil {
return
}
if mid, err = s.dao.CacheLotteryMid(c, aid, day); err != nil || mid == 0 {
err = ecode.ActivityLotteryFail
return
}
log.Warn("Lottery bid(%d) loginMid(%d) aid(%d) lotteryMid(%d)", bid, loginMid, aid, mid)
data = &bwsmdl.LotteryUser{Mid: mid}
if accData, err = s.accClient.Info3(c, &accapi.MidReq{Mid: mid}); err != nil {
log.Error("Lottery s.accRPC.Info3(%d) error(%v)", mid, err)
err = nil
return
}
if accData != nil && accData.Info != nil {
data = &bwsmdl.LotteryUser{Mid: mid, Name: accData.Info.Name, Face: accData.Info.Face}
}
return
}
// LotteryCheck .
func (s *Service) LotteryCheck(c context.Context, mid, aid int64, day string) (data []int64, err error) {
if !s.isAdmin(mid) {
err = ecode.ActivityNotAdmin
return
}
return s.dao.CacheLotteryMids(c, aid, day)
}

View File

@@ -0,0 +1,253 @@
package bws
import (
"context"
"sort"
"time"
bwsmdl "go-common/app/interface/main/activity/model/bws"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
)
func (s *Service) points(c context.Context, bid int64) (rs map[string][]*bwsmdl.Point, err error) {
var (
points *bwsmdl.Points
dp, game, clockin, egg []*bwsmdl.Point
)
if points, err = s.dao.Points(c, bid); err != nil || points == nil || len(points.Points) == 0 {
log.Error("s.dao.Points error(%v)", err)
err = ecode.ActivityPointFail
return
}
for _, point := range points.Points {
switch point.LockType {
case _dpType:
dp = append(dp, point)
case _gameType:
game = append(game, point)
case _clockinType:
clockin = append(clockin, point)
case _eggType:
egg = append(egg, point)
}
}
rs = make(map[string][]*bwsmdl.Point, 4)
if len(dp) == 0 {
rs[_dp] = _emptPoints
} else {
rs[_dp] = dp
}
if len(game) == 0 {
rs[_game] = _emptPoints
} else {
rs[_game] = game
}
if len(clockin) == 0 {
rs[_clockin] = _emptPoints
} else {
rs[_clockin] = clockin
}
if len(egg) == 0 {
rs[_egg] = _emptPoints
} else {
rs[_egg] = egg
}
return
}
// Points points list
func (s *Service) Points(c context.Context, p *bwsmdl.ParamPoints) (rs map[string][]*bwsmdl.Point, err error) {
var points map[string][]*bwsmdl.Point
if points, err = s.points(c, p.Bid); err != nil {
return
}
rs = make(map[string][]*bwsmdl.Point)
switch p.Tp {
case _allType:
rs = points
case _dpType:
rs[_dp] = points[_dp]
case _gameType:
rs[_game] = points[_game]
case _clockinType:
rs[_clockin] = points[_clockin]
case _eggType:
rs[_egg] = points[_egg]
}
return
}
// Point point
func (s *Service) Point(c context.Context, p *bwsmdl.ParamID) (rs *bwsmdl.Point, err error) {
var (
points *bwsmdl.Points
)
if points, err = s.dao.Points(c, p.Bid); err != nil || points == nil || len(points.Points) == 0 {
log.Error("s.dao.Points error(%v)", err)
err = ecode.ActivityPointFail
return
}
for _, point := range points.Points {
if point.ID == p.ID {
rs = point
break
}
}
if rs == nil {
err = ecode.ActivityIDNotExists
}
return
}
// Unlock unlock point.
func (s *Service) Unlock(c context.Context, owner int64, arg *bwsmdl.ParamUnlock) (err error) {
var (
point *bwsmdl.Point
userPoints []*bwsmdl.UserPointDetail
userAchieves []*bwsmdl.UserAchieveDetail
achieves *bwsmdl.Achievements
unLockCnt, hp int64
addAchieve *bwsmdl.Achievement
lockAchieves []*bwsmdl.Achievement
)
if arg.Key == "" {
if arg.Key, err = s.midToKey(c, arg.Mid); err != nil {
return
}
}
if point, err = s.Point(c, &bwsmdl.ParamID{ID: arg.Pid, Bid: arg.Bid}); err != nil {
return
}
if point.Ower != owner && !s.isAdmin(owner) {
err = ecode.ActivityNotOwner
return
}
if point.LockType == _gameType {
if arg.GameResult != bwsmdl.GameResWin && arg.GameResult != bwsmdl.GameResFail {
err = ecode.ActivityGameResult
return
}
}
if userPoints, err = s.userPoints(c, arg.Bid, arg.Key); err != nil {
return
}
userPidMap := make(map[int64]int64, len(userPoints))
for _, v := range userPoints {
if point.LockType != _gameType && v.Pid == point.ID {
err = ecode.ActivityHasUnlock
return
}
if _, ok := userPidMap[v.Pid]; !ok && v.LockType == point.LockType {
if v.LockType == _gameType {
if v.Points == v.Unlocked {
unLockCnt++
userPidMap[v.Pid] = v.Pid
}
} else {
unLockCnt++
userPidMap[v.Pid] = v.Pid
}
}
hp += v.Points
}
lockPoint := point.Unlocked
if point.LockType == _gameType && arg.GameResult == bwsmdl.GameResFail {
lockPoint = point.LoseUnlocked
}
if hp+lockPoint < 0 {
err = ecode.ActivityLackHp
return
}
if userAchieves, err = s.userAchieves(c, arg.Bid, arg.Key); err != nil {
return
}
if err = s.addUserPoint(c, arg.Bid, arg.Pid, lockPoint, arg.Key); err != nil {
return
}
if achieves, err = s.dao.Achievements(c, arg.Bid); err != nil || len(achieves.Achievements) == 0 {
log.Error("s.dao.Achievements error(%v)", err)
err = ecode.ActivityAchieveFail
return
}
for _, v := range achieves.Achievements {
if point.LockType == v.LockType {
lockAchieves = append(lockAchieves, v)
}
}
if len(lockAchieves) > 0 {
sort.Slice(lockAchieves, func(i, j int) bool { return lockAchieves[i].Unlock > lockAchieves[j].Unlock })
if point.LockType == _gameType {
if arg.GameResult == bwsmdl.GameResWin {
unLockCnt++
}
} else {
unLockCnt++
}
for _, ach := range lockAchieves {
if unLockCnt >= ach.Unlock {
addAchieve = ach
break
}
}
}
if addAchieve != nil {
for _, v := range userAchieves {
if v.Aid == addAchieve.ID {
return
}
}
s.addAchieve(c, arg.Mid, addAchieve, arg.Key)
}
return
}
func (s *Service) userPoints(c context.Context, bid int64, key string) (res []*bwsmdl.UserPointDetail, err error) {
var (
usPoints []*bwsmdl.UserPoint
points *bwsmdl.Points
)
if usPoints, err = s.dao.UserPoints(c, bid, key); err != nil {
err = ecode.ActivityUserPointFail
return
}
if len(usPoints) == 0 {
return
}
if points, err = s.dao.Points(c, bid); err != nil || points == nil || len(points.Points) == 0 {
log.Error("s.dao.Points error(%v)", err)
err = ecode.ActivityPointFail
return
}
pointsMap := make(map[int64]*bwsmdl.Point, len(points.Points))
for _, v := range points.Points {
pointsMap[v.ID] = v
}
for _, v := range usPoints {
detail := &bwsmdl.UserPointDetail{UserPoint: v}
if point, ok := pointsMap[v.Pid]; ok {
detail.Name = point.Name
detail.Icon = point.Icon
detail.Fid = point.Fid
detail.Image = point.Image
detail.Unlocked = point.Unlocked
detail.LockType = point.LockType
detail.Dic = point.Dic
detail.Rule = point.Rule
detail.Bid = point.Bid
}
res = append(res, detail)
}
return
}
func (s *Service) addUserPoint(c context.Context, bid, pid, points int64, key string) (err error) {
var usPtID int64
if usPtID, err = s.dao.AddUserPoint(c, bid, pid, points, key); err != nil {
err = ecode.ActivityUnlockFail
return
}
err = s.dao.AppendUserPointsCache(c, bid, key, &bwsmdl.UserPoint{ID: usPtID, Pid: pid, Points: points, Ctime: xtime.Time(time.Now().Unix())})
return
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["kfc_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["kfc.go"],
importpath = "go-common/app/interface/main/activity/service/kfc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/kfc:go_default_library",
"//app/interface/main/activity/model/kfc:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/pipeline/fanout: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,144 @@
package kfc
import (
"context"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/dao/kfc"
kfcmdl "go-common/app/interface/main/activity/model/kfc"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/pipeline/fanout"
)
// Service struct
type Service struct {
c *conf.Config
dao *kfc.Dao
cache *fanout.Fanout
}
// Close service
func (s *Service) Close() {
s.dao.Close()
s.cache.Close()
}
// New Service
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: kfc.New(c),
cache: fanout.New("cache", fanout.Worker(5), fanout.Buffer(10240)),
}
return
}
// KfcInfo .
func (s *Service) KfcInfo(c context.Context, id, mid int64) (kfcInfo *kfcmdl.BnjKfcCoupon, err error) {
var (
res *kfcmdl.BnjKfcCoupon
)
if res, err = s.dao.KfcCoupon(c, id); err != nil {
log.Error("s.dao.KfcCoupon(%d) error(%+v)", id, err)
return
}
if res.ID == 0 {
err = ecode.NothingFound
return
}
if res.Mid == 0 {
var uid int64
if uid, err = s.kfcRecall(c, id); err == nil && uid > 0 {
if uid == mid {
res.Mid = uid
}
}
}
if res.Mid != 0 && res.Mid == mid {
kfcInfo = res
} else {
err = ecode.NothingFound
}
return
}
// kfcRecall .
func (s *Service) kfcRecall(c context.Context, id int64) (uid int64, err error) {
if uid, err = s.dao.KfcWinner(c, id); err != nil {
log.Error("s.dao.KfcWinner(%d) error(%+v)", id, err)
return
}
if uid > 0 {
s.DeliverKfc(c, id, uid)
}
return
}
// KfcUse .
func (s *Service) KfcUse(c context.Context, code string) (kfcID int64, err error) {
var (
kfcInfo *kfcmdl.BnjKfcCoupon
effectRows int64
)
if kfcID, err = s.dao.CacheKfcCode(c, code); err != nil {
log.Error("s.dao.CacheKfcCode(%s) error(%+v)", code, err)
return
}
if kfcID > 0 {
err = ecode.ActivityKfcHasUsed
return
}
if kfcInfo, err = s.dao.RawKfcCode(c, code); err != nil {
log.Error("s.dao.RawKfcCode(%s) error(%+v)", code, err)
return
}
if kfcInfo.ID == 0 {
err = ecode.ActivityKfcNotExist
return
}
if kfcInfo.Mid == 0 {
err = ecode.ActivityKfcNotGiveOut
return
}
if kfcInfo.State == int64(kfc.KfcCodeUsed) {
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheKfcCode(c, code, kfcInfo.ID)
})
err = ecode.ActivityKfcHasUsed
return
}
if effectRows, err = s.dao.KfcCodeGiveOut(c, kfcInfo.ID); err != nil {
log.Error("s.dao.KfcCodeGiveOut(%d) error(%+v)", kfcInfo.ID, err)
return
}
if effectRows == 0 {
err = ecode.ActivityKfcSqlError
}
kfcID = kfcInfo.ID
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheKfcCode(c, code, kfcInfo.ID)
s.dao.DelCacheKfcCoupon(c, kfcInfo.ID)
})
return
}
// DeliverKfc .
func (s *Service) DeliverKfc(c context.Context, id, mid int64) (err error) {
effectID, err := s.dao.KfcDeliver(c, id, mid)
if err != nil {
log.Error("s.dao.KfcDeliver(%d,%d) error(%+v)", id, mid, err)
return
}
if effectID > 0 {
s.cache.Do(c, func(c context.Context) {
if e := s.dao.DelCacheKfcCoupon(c, id); e == nil {
s.dao.KfcCoupon(c, id)
}
})
} else {
err = ecode.ActivityKfcSqlError
log.Error("DeliverKfc mysql effect o rows (%d,%d)", id, mid)
}
return
}

View File

@@ -0,0 +1,73 @@
package kfc
import (
"testing"
"time"
"flag"
"go-common/app/interface/main/activity/conf"
"path/filepath"
"context"
"fmt"
. "github.com/smartystreets/goconvey/convey"
)
var svf *Service
func init() {
dir, _ := filepath.Abs("../../cmd/activity-test.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(err)
}
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svf)
}
}
func TestService_KfcInfo(t *testing.T) {
Convey("test fmt start and end", t, WithService(func(s *Service) {
id := int64(30)
mid := int64(16299551)
start, err := s.KfcInfo(context.Background(), id, mid)
So(err, ShouldBeNil)
Println(start)
}))
}
func TestService_KfcUse(t *testing.T) {
Convey("test fmt start and end", t, WithService(func(s *Service) {
code := "535487458740"
start, err := s.KfcUse(context.Background(), code)
So(err, ShouldBeNil)
Println(start)
}))
}
func TestService_DeliverKfc(t *testing.T) {
Convey("test fmt start and end", t, WithService(func(s *Service) {
id := int64(1)
mid := int64(2089810)
err := s.DeliverKfc(context.Background(), id, mid)
So(err, ShouldBeNil)
}))
}
func TestService_kfcRecall(t *testing.T) {
Convey("test fmt start and end", t, WithService(func(s *Service) {
id := int64(30)
uid, err := s.kfcRecall(context.Background(), id)
So(err, ShouldBeNil)
fmt.Print(uid)
}))
}

View File

@@ -0,0 +1,86 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"act_test.go",
"like_test.go",
"match_test.go",
"missiongroup_test.go",
"service_test.go",
"subject_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/model/like:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"act.go",
"bnj.go",
"like.go",
"match.go",
"missiongroup.go",
"service.go",
"subject.go",
],
importpath = "go-common/app/interface/main/activity/service/like",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/bnj:go_default_library",
"//app/interface/main/activity/dao/like:go_default_library",
"//app/interface/main/activity/model/bnj:go_default_library",
"//app/interface/main/activity/model/like:go_default_library",
"//app/interface/main/tag/model:go_default_library",
"//app/interface/main/tag/rpc/client:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/coin/api/gorpc:go_default_library",
"//app/service/main/coin/model:go_default_library",
"//app/service/main/spy/model:go_default_library",
"//app/service/main/spy/rpc/client:go_default_library",
"//app/service/main/thumbup/model:go_default_library",
"//app/service/main/thumbup/rpc/client:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//library/time: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,51 @@
package like
import (
"context"
"sync/atomic"
"time"
"go-common/app/interface/main/activity/model/like"
"go-common/library/log"
)
// RedDot get hot dot.
func (s *Service) RedDot(c context.Context, mid int64) (redDot *like.RedDot, err error) {
var lastTs int64
redDot = new(like.RedDot)
if mid <= 0 {
return
}
if lastTime, e := s.dao.CacheRedDotTs(c, mid); e != nil {
log.Error("s.dao.CacheRedDotTs mid(%d) error(%+v)", mid, e)
} else {
lastTs = lastTime
}
if s.newestSubTs > lastTs {
redDot.RedDot = true
}
return
}
// ClearRetDot clear red dot.
func (s *Service) ClearRetDot(c context.Context, mid int64) (err error) {
if err = s.dao.AddCacheRedDotTs(c, mid, time.Now().Unix()); err != nil {
log.Error("s.dao.AddCacheRedDotTs mid(%d) error(%+v)", mid, err)
}
return
}
func (s *Service) newestSubTsproc() {
for {
if like, err := s.dao.NewestSubject(context.Background(), like.VIDEOALL); err != nil || like == nil {
log.Error("actNewTsproc s.dao.NewestSubject error(%+v)", err)
time.Sleep(5 * time.Second)
} else {
newTs := like.Ctime.Time().Unix()
if newTs > s.newestSubTs {
atomic.StoreInt64(&s.newestSubTs, newTs)
}
}
time.Sleep(time.Duration(s.c.Interval.NewestSubTsInterval))
}
}

View File

@@ -0,0 +1,17 @@
package like
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_HotDot(t *testing.T) {
Convey("test hot dot", t, WithService(func(s *Service) {
mid := int64(908085)
data, err := s.RedDot(context.Background(), mid)
So(err, ShouldBeNil)
Println(data)
}))
}

View File

@@ -0,0 +1,71 @@
package like
import (
"context"
"strconv"
"go-common/app/interface/main/activity/model/bnj"
"go-common/app/interface/main/activity/model/like"
suitmdl "go-common/app/service/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
)
// Reward get bnj preview reward.
func (s *Service) Reward(c context.Context, mid int64, step int) (err error) {
reward, ok := s.reward[step]
if !ok {
err = ecode.RequestErr
return
}
var (
likeActs map[int64]int
likeScore map[int64]int64
check bool
)
actID := s.c.Bnj2019.ActID
subID := s.c.Bnj2019.SubID
if likeScore, err = s.dao.LikeActLidCounts(c, []int64{subID}); err != nil {
log.Error("Reward s.dao.LikeActLidCounts(subID:%d) error(%+v)", subID, err)
return
}
if score, ok := likeScore[subID]; !ok || score < reward.Condition {
err = ecode.ActivityBnjSubLow
return
}
if likeActs, err = s.dao.LikeActs(c, actID, mid, []int64{subID}); err != nil {
log.Error("Reward s.dao.LikeActs(subID:%d,actID:%d,mid:%d) error(%+v)", subID, actID, mid, err)
return
}
if isSub, ok := likeActs[subID]; !ok || isSub == 0 {
if _, err = s.LikeAct(c, &like.ParamAddLikeAct{Sid: actID, Lid: subID, Score: 1}, mid); err != nil {
return
}
}
// check has reward
if check, err = s.bnjDao.CacheHasReward(c, mid, subID, step); err != nil || !check {
log.Error("Reward s.dao.CacheHasReward(mid:%d,subID:%d,step:%d) error(%v) check(%v)", mid, subID, step, err, check)
err = ecode.ActivityBnjHasReward
return
}
switch reward.RewardType {
case bnj.RewardTypePendant:
rewardID, e := strconv.ParseInt(reward.RewardID, 10, 64)
if e != nil {
err = ecode.ActivityRewardConfErr
return
}
err = s.suit.GrantByMids(c, &suitmdl.ArgGrantByMids{Mids: []int64{mid}, Pid: rewardID, Expire: reward.Expire})
case bnj.RewardTypeCoupon:
err = s.bnjDao.GrantCoupon(c, mid, reward.RewardID)
// TODO check err code
}
if err != nil {
log.Error("Reward (%+v) error(%+v)", reward, err)
err = ecode.ActivityBnjRewardFail
if e := s.bnjDao.DelCacheHasReward(c, mid, subID, step); e != nil {
log.Error("s.dao.DelCacheHasReward(%+v) error(%v)", reward, e)
}
}
return
}

View File

@@ -0,0 +1,780 @@
package like
import (
"bytes"
"context"
"strconv"
"sync"
dao "go-common/app/interface/main/activity/dao/like"
likemdl "go-common/app/interface/main/activity/model/like"
tagmdl "go-common/app/interface/main/tag/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
thpmdl "go-common/app/service/main/thumbup/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
)
const (
_aidBulkSize = 100
_tagBlkSize = 50
_tagArcType = 3
_tagLikePoint = 100
_orderTypeCtime = "ctime"
_orderTypeRandom = "random"
_specialLikeRate = 1000
_businessLike = "archive"
)
var (
_emptyLikeList = make([]*likemdl.Like, 0)
_emptyArcs = make([]*api.Arc, 0)
)
// UpdateActSourceList update act arc list.
func (s *Service) updateActSourceList(c context.Context, sid int64, typ string) (err error) {
var (
likes []*likemdl.Item
)
if likes, err = s.dao.LikeList(c, sid); err != nil {
log.Error("UpdateActSourceList s.dao.LikeList(%d) error(%v)", sid, err)
return
}
s.cache.Do(c, func(c context.Context) {
if typ == _typeAll {
s.updateActCacheList(c, sid, likes)
}
if typ == _typeRegion {
s.updateActRegionList(c, sid, likes)
}
})
return
}
func (s *Service) updateActCacheList(c context.Context, sid int64, likes []*likemdl.Item) (err error) {
var (
aids []int64
tags map[int64][]*tagmdl.Tag
arcs map[int64]*api.Arc
)
likeMap := make(map[int64]*likemdl.Item, len(likes))
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
likeMap[v.Wid] = v
}
}
if len(aids) == 0 {
return
}
if tags, err = s.arcTags(c, aids); err != nil {
return
}
if arcs, err = s.archives(c, aids); err != nil {
return
}
arcTagMap := make(map[int64][]*likemdl.Item, len(s.dialectTags))
tagLikePtTmp := make(map[int64]int32, len(s.dialectTags))
for aid, arcTag := range tags {
for _, tag := range arcTag {
if _, ok := s.dialectTags[tag.ID]; ok {
arcTagMap[tag.ID] = append(arcTagMap[tag.ID], likeMap[aid])
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
tagLikePtTmp[tag.ID] += arc.Stat.Like
}
}
}
}
tagPtMap := make(map[int64]int32, len(s.dialectTags))
for tagID, v := range arcTagMap {
s.dao.SetLikeTagCache(c, sid, tagID, v)
if like, ok := tagLikePtTmp[tagID]; ok {
tagPt := int32(len(v)*_tagLikePoint) + like
tagPtMap[tagID] = tagPt
}
}
s.dao.SetTagLikeCountsCache(c, sid, tagPtMap)
regionMap := make(map[int16][]*likemdl.Item, len(s.dialectRegions))
for _, arc := range arcs {
if region, ok := s.arcType[int16(arc.TypeID)]; ok {
if _, ok := s.dialectRegions[region.Pid]; ok {
regionMap[region.Pid] = append(regionMap[region.Pid], likeMap[arc.Aid])
}
}
}
for rid, v := range regionMap {
s.dao.SetLikeRegionCache(c, sid, rid, v)
}
return
}
func (s *Service) updateActRegionList(c context.Context, sid int64, likes []*likemdl.Item) (err error) {
var (
aids []int64
arcs map[int64]*api.Arc
)
likeMap := make(map[int64]*likemdl.Item, len(likes))
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
likeMap[v.Wid] = v
}
}
if len(aids) == 0 {
return
}
if arcs, err = s.archives(c, aids); err != nil {
return
}
regionMap := make(map[int16][]*likemdl.Item)
for _, arc := range arcs {
if region, ok := s.arcType[int16(arc.TypeID)]; ok {
regionMap[region.Pid] = append(regionMap[region.Pid], likeMap[arc.Aid])
}
}
for rid, v := range regionMap {
s.dao.SetLikeRegionCache(c, sid, rid, v)
}
return
}
func (s *Service) archives(c context.Context, aids []int64) (archives map[int64]*api.Arc, err error) {
var (
mutex = sync.Mutex{}
aidsLen = len(aids)
group, errCtx = errgroup.WithContext(c)
)
archives = make(map[int64]*api.Arc, aidsLen)
for i := 0; i < aidsLen; i += _aidBulkSize {
var partAids []int64
if i+_aidBulkSize > aidsLen {
partAids = aids[i:]
} else {
partAids = aids[i : i+_aidBulkSize]
}
group.Go(func() (err error) {
var arcs map[int64]*api.Arc
arg := &archive.ArgAids2{Aids: partAids}
if arcs, err = s.arcRPC.Archives3(errCtx, arg); err != nil {
log.Error("s.arcRPC.Archives(%v) error(%v)", partAids, err)
return
}
mutex.Lock()
for _, v := range arcs {
archives[v.Aid] = v
}
mutex.Unlock()
return
})
}
err = group.Wait()
return
}
func (s *Service) arcTags(c context.Context, aids []int64) (tags map[int64][]*tagmdl.Tag, err error) {
var (
tagErr error
mutex = sync.Mutex{}
)
group, errCtx := errgroup.WithContext(c)
aidsLen := len(aids)
tags = make(map[int64][]*tagmdl.Tag, aidsLen)
for i := 0; i < aidsLen; i += _tagBlkSize {
var partAids []int64
if i+_tagBlkSize > aidsLen {
partAids = aids[i:]
} else {
partAids = aids[i : i+_tagBlkSize]
}
group.Go(func() (err error) {
var tmpRes map[int64][]*tagmdl.Tag
arg := &tagmdl.ArgResTags{Oids: partAids, Type: _tagArcType}
if tmpRes, tagErr = s.tagRPC.ResTags(errCtx, arg); tagErr != nil {
dao.PromError("ResTags接口错误", "s.tag.ResTag(%+v) error(%v)", arg, tagErr)
return
}
mutex.Lock()
for aid, tmpTags := range tmpRes {
tags[aid] = tmpTags
}
mutex.Unlock()
return nil
})
}
group.Wait()
return
}
// TagArcList tag arc list.
func (s *Service) TagArcList(c context.Context, sid, tagID int64, pn, ps int, typ, ip string) (list []*likemdl.Like, cnt int, err error) {
var (
likes []*likemdl.Item
start, end int
aids []int64
archives map[int64]*api.Arc
)
if sid != s.c.Rule.DialectSid {
err = ecode.RequestErr
return
}
if _, ok := s.dialectTags[tagID]; !ok {
err = ecode.RequestErr
return
}
if cnt, err = s.dao.LikeTagCnt(c, sid, tagID); err != nil {
log.Error("TagArcList s.dao.LikeTagCnt sid(%d) tagID(%d) error(%v)", sid, tagID, err)
return
}
if start, end, err = s.fmtStartEnd(pn, ps, cnt, typ); err != nil {
err = nil
list = _emptyLikeList
return
}
if likes, err = s.dao.LikeTagCache(c, sid, tagID, start, end); err != nil {
log.Error("TagArcList s.dao.LikeTagCache sid(%d) tagID(%d) start(%d) end(%d) error(%+v)", sid, tagID, start, end, err)
return
}
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
}
}
if len(aids) == 0 {
list = _emptyLikeList
return
}
if archives, err = s.arcRPC.Archives3(c, &archive.ArgAids2{Aids: aids, RealIP: ip}); err != nil {
log.Error("TagArcList s.arcRPC.Archives3 aids(%v) error(%+v)", aids, err)
return
}
for _, v := range likes {
if arc, ok := archives[v.Wid]; ok && arc.IsNormal() {
list = append(list, &likemdl.Like{Item: v, Archive: arc})
}
}
l := len(list)
if l == 0 {
list = _emptyLikeList
return
}
if typ == _orderTypeRandom {
s.shuffle(l, func(i, j int) {
list[i], list[j] = list[j], list[i]
})
}
return
}
// RegionArcList region arc list.
func (s *Service) RegionArcList(c context.Context, sid int64, rid int16, pn, ps int, typ, ip string) (list []*likemdl.Like, cnt int, err error) {
var (
likes []*likemdl.Item
start, end int
aids []int64
archives map[int64]*api.Arc
)
if sid != s.c.Rule.DialectSid {
err = ecode.RequestErr
return
}
if _, ok := s.dialectRegions[rid]; !ok {
err = ecode.RequestErr
return
}
if cnt, err = s.dao.LikeRegionCnt(c, sid, rid); err != nil {
log.Error("RegionArcList s.dao.LikeRegionCnt sid(%d) rid(%d) error(%v)", sid, rid, err)
return
}
if start, end, err = s.fmtStartEnd(pn, ps, cnt, typ); err != nil {
err = nil
list = _emptyLikeList
return
}
if likes, err = s.dao.LikeRegionCache(c, sid, rid, start, end); err != nil {
log.Error("RegionArcList s.dao.LikeRegionCache sid(%d) rid(%d) start(%d) end(%d) error(%+v)", sid, rid, start, end, err)
return
}
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
}
}
if len(aids) == 0 {
list = _emptyLikeList
return
}
if archives, err = s.arcRPC.Archives3(c, &archive.ArgAids2{Aids: aids, RealIP: ip}); err != nil {
log.Error("RegionArcList s.arcRPC.Archives3 aids(%v) error(%+v)", aids, err)
return
}
for _, v := range likes {
if arc, ok := archives[v.Wid]; ok && arc.IsNormal() {
list = append(list, &likemdl.Like{Item: v, Archive: arc})
}
}
l := len(list)
if l == 0 {
list = _emptyLikeList
return
}
if typ == _orderTypeRandom {
s.shuffle(l, func(i, j int) {
list[i], list[j] = list[j], list[i]
})
}
return
}
// TagLikeCounts .
func (s *Service) TagLikeCounts(c context.Context, sid int64) (data map[int64]int32, err error) {
if sid != s.c.Rule.DialectSid {
err = ecode.RequestErr
return
}
return s.dao.TagLikeCountsCache(c, sid, s.c.Rule.DialectTags)
}
func (s *Service) fmtStartEnd(pn, ps, cnt int, typ string) (start, end int, err error) {
if typ == _orderTypeCtime {
start = (pn - 1) * ps
end = start + ps - 1
if start > cnt {
err = ecode.NothingFound
return
}
if end > cnt {
end = cnt
}
} else {
if ps >= cnt-1 {
start = 0
} else {
start = s.r.Intn(cnt - ps - 1)
}
end = start + ps - 1
}
return
}
func (s *Service) shuffle(l int, swap func(i, j int)) {
for i := l - 1; i > 0; i-- {
j := s.r.Intn(i + 1)
swap(i, j)
}
}
// LikeInitialize initialize like cache data .
func (s *Service) LikeInitialize(c context.Context, lid int64) (err error) {
if lid < 0 {
lid = 0
}
var likesItem []*likemdl.Item
for {
if likesItem, err = s.dao.LikeListMoreLid(c, lid); err != nil {
log.Error("dao.LikeInitialize(%d) error(%+v)", lid, err)
break
}
if len(likesItem) == 0 {
log.Info("LikeInitialize end success")
break
}
for _, val := range likesItem {
item := val
if lid < item.ID {
lid = item.ID
}
id := item.ID
//the likes offline is stored with empty data
if item.State != 1 {
item = &likemdl.Item{}
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheLike(c, id, item)
})
}
}
s.cache.Do(c, func(c context.Context) {
s.LikeMaxIDInitialize(c)
})
return
}
// LikeMaxIDInitialize likes max id initialize
func (s *Service) LikeMaxIDInitialize(c context.Context) (err error) {
var likeItem *likemdl.Item
if likeItem, err = s.dao.LikeMaxID(c); err != nil {
log.Error("s.dao.LikeMaxID() error(%+v)", err)
return
}
if likeItem.ID >= 0 {
if err = s.dao.AddCacheLikeMaxID(c, likeItem.ID); err != nil {
log.Error("s.dao.AddCacheLikeMaxID(%d),error(%v)", likeItem.ID, err)
}
}
return
}
// LikeUp update likes cache and like maxID cache
func (s *Service) LikeUp(c context.Context, lid int64) (err error) {
var (
likeItem *likemdl.Item
likeMaxID int64
)
group, ctx := errgroup.WithContext(c)
group.Go(func() (e error) {
if likeItem, e = s.dao.RawLike(ctx, lid); e != nil {
log.Error("LikeUp:s.dao.RawLike(%d) error(%+v)", lid, e)
}
return
})
group.Go(func() (e error) {
if likeMaxID, e = s.dao.CacheLikeMaxID(ctx); e != nil {
log.Error("LikeUp:s.dao.CacheLikeMaxID() error(%v)", e)
}
return
})
if err = group.Wait(); err != nil {
log.Error("LikeUp: group.Wait() error(%v)", err)
return
}
if likeMaxID < lid {
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheLikeMaxID(c, lid)
})
}
if likeItem.ID == 0 {
likeItem = &likemdl.Item{}
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheLike(c, lid, likeItem)
})
return
}
// AddLikeCtimeCache add cache .
func (s *Service) AddLikeCtimeCache(c context.Context, lid int64) (err error) {
var (
likeItem *likemdl.Item
cItems = make([]*likemdl.Item, 0, 1)
)
if likeItem, err = s.dao.RawLike(c, lid); err != nil {
log.Error("LikeUp:s.dao.RawLike(%d) error(%+v)", lid, err)
return
}
if likeItem.ID > 0 {
eg, errCtx := errgroup.WithContext(c)
cItems = append(cItems, likeItem)
eg.Go(func() (e error) {
e = s.dao.LikeListCtime(errCtx, likeItem.Sid, cItems)
return
})
eg.Go(func() (e error) {
// 初始化排行榜数据
e = s.dao.SetRedisCache(c, likeItem.Sid, lid, 0, likeItem.Type)
return
})
if err = eg.Wait(); err != nil {
log.Error("AddLikeCtimeCache eg.Wait() error(%+v)", err)
}
}
return
}
// DelLikeCtimeCache delete ctime cache.
func (s *Service) DelLikeCtimeCache(c context.Context, lid, sid int64, likeType int) (err error) {
var (
cItems = make([]*likemdl.Item, 0, 1)
)
likeItem := &likemdl.Item{
ID: lid,
Sid: sid,
Type: likeType,
}
cItems = append(cItems, likeItem)
if err = s.dao.DelLikeListCtime(c, likeItem.Sid, cItems); err != nil {
log.Error("s.dao.DelLikeListCtime(%v) error (%v)", likeItem, err)
}
return
}
// SubjectStat get subject stat .
func (s *Service) SubjectStat(c context.Context, sid int64) (score *likemdl.SubjectScore, err error) {
if sid == s.c.Rule.S8Sid {
var arcScore, artScore int64
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
var (
stat *likemdl.SubjectStat
arcErr error
)
if stat, arcErr = s.dao.CacheSubjectStat(errCtx, s.c.Rule.S8ArcSid); arcErr != nil {
log.Error("s.dao.CacheSubjectStat sid(%d) error(%v)", sid, arcErr)
}
if stat == nil {
stat = new(likemdl.SubjectStat)
}
arcScore = stat.Count*_specialLikeRate + stat.Like
return nil
})
group.Go(func() error {
var (
stat *likemdl.SubjectStat
artErr error
)
if stat, artErr = s.dao.CacheSubjectStat(errCtx, s.c.Rule.S8ArtSid); artErr != nil {
log.Error("s.dao.CacheSubjectStat sid(%d) error(%v)", sid, artErr)
}
if stat == nil {
stat = new(likemdl.SubjectStat)
}
artScore = stat.Count*_specialLikeRate + stat.Like
return nil
})
group.Wait()
score = &likemdl.SubjectScore{Score: arcScore + artScore}
} else {
var stat *likemdl.SubjectStat
if stat, err = s.dao.CacheSubjectStat(c, sid); err != nil {
log.Error("s.dao.CacheSubjectStat sid(%d) error(%v)", sid, err)
err = nil
}
if stat == nil {
stat = new(likemdl.SubjectStat)
}
if sid == s.c.Rule.KingStorySid {
score = &likemdl.SubjectScore{Score: stat.View + stat.Fav + stat.Coin + stat.Like}
} else {
score = &likemdl.SubjectScore{Score: stat.Count*_specialLikeRate + stat.Like}
}
}
return
}
// SetSubjectStat set subject stat .
func (s *Service) SetSubjectStat(c context.Context, stat *likemdl.SubjectStat) (err error) {
return s.dao.AddCacheSubjectStat(c, stat.Sid, stat)
}
// ViewRank get view rank arcs.
func (s *Service) ViewRank(c context.Context, sid int64, pn, ps int) (list []*api.Arc, count int, err error) {
var (
aidsCache string
aids, pieceAids []int64
arcs map[int64]*api.Arc
)
if aidsCache, err = s.dao.CacheViewRank(c, sid); err != nil {
log.Error("ViewRank s.dao.CacheViewRank(%d) error(%v)", sid, err)
return
}
if aids, err = xstr.SplitInts(aidsCache); err != nil {
log.Error("ViewRank xstr.SplitInts(%d,%s) error(%v)", sid, aidsCache, err)
return
}
count = len(aids)
start := (pn - 1) * ps
end := start + ps - 1
if count < start {
list = _emptyArcs
return
}
if count > end {
pieceAids = aids[start : end+1]
} else {
pieceAids = aids[start:]
}
if arcs, err = s.arcRPC.Archives3(c, &archive.ArgAids2{Aids: pieceAids}); err != nil {
log.Error("ViewRank s.arcRPC.Archives3(%v) error(%v)", aids, err)
return
}
for _, aid := range pieceAids {
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
list = append(list, arc)
}
}
if len(list) == 0 {
list = _emptyArcs
}
return
}
// SetViewRank set view rank arcs.
func (s *Service) SetViewRank(c context.Context, sid int64, aids []int64) (err error) {
aidsStr := xstr.JoinInts(aids)
if err = s.dao.AddCacheViewRank(c, sid, aidsStr); err != nil {
log.Error("SetViewRank s.dao.AddCacheViewRank(%d,%s) error(%v)", sid, aidsStr, err)
}
return
}
// ObjectGroup group like data.
func (s *Service) ObjectGroup(c context.Context, sid int64, ck string) (data map[int64][]*likemdl.GroupItem, err error) {
var sids []int64
if sids, err = s.dao.SourceItemData(c, sid); err != nil {
log.Error("ObjectGroup SourceItemData(%d) error(%+v)", sid, err)
return
}
if len(sids) == 0 {
log.Warn("ObjectGroup sid(%d) len(sids) == 0", sid)
err = ecode.NothingFound
return
}
data = make(map[int64][]*likemdl.GroupItem, len(sids))
group, errCtx := errgroup.WithContext(c)
mutex := sync.Mutex{}
for _, v := range sids {
groupSid := v
group.Go(func() error {
item, e := s.dao.GroupItemData(errCtx, groupSid, ck)
if e != nil {
log.Error("ObjectGroup s.dao.GroupItemData(%d) error(%+v)", groupSid, e)
} else {
mutex.Lock()
data[groupSid] = item
mutex.Unlock()
}
return nil
})
}
group.Wait()
return
}
// SetLikeContent .
func (s *Service) SetLikeContent(c context.Context, lid int64) (err error) {
var (
conts map[int64]*likemdl.LikeContent
)
if conts, err = s.dao.RawLikeContent(c, []int64{lid}); err != nil {
log.Error("s.dao.RawLikeContent(%d) error(%+v)", lid, err)
return
}
if _, ok := conts[lid]; !ok {
conts = make(map[int64]*likemdl.LikeContent, 1)
conts[lid] = &likemdl.LikeContent{}
}
if err = s.dao.AddCacheLikeContent(c, conts); err != nil {
log.Error("s.dao.AddCacheLikeContent(%d) error(%+v)", lid, err)
}
return
}
// AddLikeActCache .
func (s *Service) AddLikeActCache(c context.Context, sid, lid, score int64) (err error) {
var (
likeItem *likemdl.Item
)
if likeItem, err = s.dao.Like(c, lid); err != nil {
log.Error("AddLikeActCache:s.dao.Like(%d) error(%+v)", lid, err)
return
}
if likeItem.ID == 0 {
return
}
if err = s.dao.SetRedisCache(c, sid, lid, score, likeItem.Type); err != nil {
log.Error("AddLikeActCache:s.dao.SetRedisCache(%d,%d,%d) error(%+v)", sid, lid, score, err)
}
return
}
// LikeActCache .
func (s *Service) LikeActCache(c context.Context, sid, lid int64) (res int64, err error) {
return s.dao.LikeActZscore(c, sid, lid)
}
// BatchInsertLikeExtend batch insert like_extend table.
func (s *Service) BatchInsertLikeExtend(c context.Context, extends []*likemdl.Extend) (res int64, err error) {
var (
buf bytes.Buffer
cnt int
rows int64
)
for _, v := range extends {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(v.Lid, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.Like, 10))
buf.WriteString("),")
cnt++
if cnt%500 == 0 {
buf.Truncate(buf.Len() - 1)
if rows, err = s.dao.AddExtend(c, buf.String()); err != nil {
log.Error("dao.dealAddExtend() error(%+v)", err)
return
}
res += rows
buf.Reset()
}
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
if rows, err = s.dao.AddExtend(c, buf.String()); err != nil {
log.Error("dao.dealAddExtend() error(%+v)", err)
return
}
res += rows
}
return
}
// arcTag get archive and tags.
func (s *Service) arcTag(c context.Context, list []*likemdl.List, order string, mid int64) (err error) {
var (
arcsReply *api.ArcsReply
lt = len(list)
wids = make([]int64, 0, lt)
tagRes map[int64][]string
hasLikeList map[int64]int8
)
for _, v := range list {
if v.Wid > 0 {
wids = append(wids, v.Wid)
}
}
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() (e error) {
arcsReply, e = s.arcClient.Arcs(errCtx, &api.ArcsRequest{Aids: wids})
return
})
eg.Go(func() (e error) {
tagRes, e = s.dao.MultiTags(errCtx, wids)
return
})
if mid != 0 && (order == dao.EsOrderLikes || order == dao.ActOrderCtime) {
eg.Go(func() (e error) {
hasLikeList, e = s.thumbup.HasLike(errCtx, &thpmdl.ArgHasLike{Business: _businessLike, MessageIDs: wids, Mid: mid})
return
})
}
if err = eg.Wait(); err != nil {
log.Error("arcTag:eg.Wait() error(%+v)", err)
return
}
for _, v := range list {
if v.Wid == 0 {
continue
}
obj := new(likemdl.ArgTag)
if _, ok := arcsReply.Arcs[v.Wid]; ok {
obj.Archive = arcsReply.Arcs[v.Wid]
}
if _, ok := tagRes[v.Wid]; ok {
obj.Tags = tagRes[v.Wid]
}
v.Object = obj
if _, ok := hasLikeList[v.Wid]; ok {
v.HasLikes = hasLikeList[v.Wid]
}
}
return
}
// LikeOidsInfo .
func (s *Service) LikeOidsInfo(c context.Context, sType int, oids []int64) (res map[int64]*likemdl.Item, err error) {
if res, err = s.dao.OidInfoFromES(c, oids, sType); err != nil {
log.Error("s.dao.OidInfoFromES(%v,%d) error(%v)", oids, sType, err)
}
return
}

View File

@@ -0,0 +1,74 @@
package like
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_fmtStartEnd(t *testing.T) {
Convey("test fmt start and end", t, WithService(func(s *Service) {
pn := 1
ps := 10
cnt := 11
typ := "random" //ctime random
start, end, err := s.fmtStartEnd(pn, ps, cnt, typ)
So(err, ShouldBeNil)
Println(start, end)
}))
}
func TestService_LikeInitialize(t *testing.T) {
Convey("test LikeInitialize", t, WithService(func(s *Service) {
lid := int64(13537)
err := s.LikeInitialize(context.Background(), lid)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_LikeMaxIDInitialize(t *testing.T) {
Convey("test LikeInitialize", t, WithService(func(s *Service) {
err := s.LikeMaxIDInitialize(context.Background())
So(err, ShouldBeNil)
}))
}
func TestService_LikeUp(t *testing.T) {
Convey("test LikeUp", t, WithService(func(s *Service) {
lid := int64(13538)
err := s.LikeUp(context.Background(), lid)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_AddLikeCtimeCache(t *testing.T) {
Convey("test LikeUp", t, WithService(func(s *Service) {
lid := int64(13540)
err := s.AddLikeCtimeCache(context.Background(), lid)
So(err, ShouldBeNil)
}))
}
func TestService_DelLikeCtimeCache(t *testing.T) {
Convey("test LikeUp", t, WithService(func(s *Service) {
err := s.DelLikeCtimeCache(context.Background(), 13537, 10296, 5)
So(err, ShouldBeNil)
}))
}
func TestService_SetLikeContent(t *testing.T) {
Convey("test LikeUp", t, WithService(func(s *Service) {
err := s.SetLikeContent(context.Background(), 13511)
So(err, ShouldBeNil)
}))
}
func TestService_AddLikeActCache(t *testing.T) {
Convey("test LikeUp", t, WithService(func(s *Service) {
err := s.AddLikeActCache(context.Background(), 10296, 13528, 7)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,302 @@
package like
import (
"context"
"encoding/json"
"time"
"go-common/app/interface/main/activity/conf"
dao "go-common/app/interface/main/activity/dao/like"
match "go-common/app/interface/main/activity/model/like"
coinmdl "go-common/app/service/main/coin/model"
suitmdl "go-common/app/service/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_matchTable = "act_matchs"
_objectTable = "act_matchs_object"
_userLogTable = "act_match_user_log"
_reason = "参与竞猜"
)
var (
_emptyMatch = make([]*match.Match, 0)
_emptyObjects = make([]*match.Object, 0)
_emptyUserLog = make([]*match.UserLog, 0)
_emptyFollow = make([]string, 0)
)
// Match get match.
func (s *Service) Match(c context.Context, sid int64) (rs []*match.Match, err error) {
// get from cache.
if rs, err = s.dao.ActMatchCache(c, sid); err != nil || len(rs) == 0 {
if rs, err = s.dao.ActMatch(c, sid); err != nil {
log.Error("s.dao.Match sid(%d) error(%v)", sid, err)
return
}
if len(rs) == 0 {
rs = _emptyMatch
return
}
s.cache.Do(c, func(c context.Context) {
s.dao.SetActMatchCache(c, sid, rs)
})
}
return
}
// AddGuess add match guess.
func (s *Service) AddGuess(c context.Context, mid int64, p *match.ParamAddGuess) (rs int64, err error) {
var (
object *match.Object
userGuess []*match.UserLog
group *errgroup.Group
coinErr, suitErr error
count float64
ip = metadata.String(c, metadata.RemoteIP)
)
if p.Stake > conf.Conf.Rule.MaxGuessCoin {
err = ecode.ActivityOverCoin
return
}
//check mid coin count
if count, err = s.coin.UserCoins(c, &coinmdl.ArgCoinInfo{Mid: mid, RealIP: ip}); err != nil {
dao.PromError("UserCoins接口错误", "s.coin.UserCoins(%d,%s) error(%v)", mid, ip, err)
return
}
if count < float64(p.Stake) {
err = ecode.ActivityNotEnoughCoin
return
}
// get from cache.
if object, err = s.dao.ObjectCache(c, p.ObjID); err != nil || object == nil {
if object, err = s.dao.Object(c, p.ObjID); err != nil {
log.Error("s.dao.Match id(%d) error(%v)", p.ObjID, err)
return
}
if object == nil || object.ID == 0 {
err = ecode.ActivityNotExist
return
}
s.cache.Do(c, func(c context.Context) {
s.dao.SetObjectCache(c, p.ObjID, object)
})
}
if time.Now().Unix() < object.Stime.Time().Unix() {
err = ecode.ActivityNotStart
return
} else if object.Result > 0 || time.Now().Unix() > object.Etime.Time().Unix() {
err = ecode.ActivityOverEnd
return
}
sid := object.Sid
if userGuess, err = s.ListGuess(c, sid, mid); err != nil {
log.Error("s.ListGuess(%d,%d) error(%v)", sid, mid, err)
return
}
for _, userLog := range userGuess {
if userLog.MOId == p.ObjID {
err = ecode.ActivityHaveGuess
return
}
}
if rs, err = s.dao.AddGuess(c, mid, object.MatchId, p.ObjID, sid, p.Result, p.Stake); err != nil || rs == 0 {
log.Error("s.dao.AddGuess matchID(%d) objectID(%d) sid(%d) error(%v)", object.MatchId, p.ObjID, sid, err)
return
}
s.dao.DelUserLogCache(context.Background(), sid, mid)
group, errCtx := errgroup.WithContext(c)
if len(s.c.Rule.SuitPids) > 0 && len(userGuess)+1 == s.c.Rule.GuessCount {
for _, v := range s.c.Rule.SuitPids {
pid := v
group.Go(func() error {
mids := []int64{mid}
if suitErr = s.suit.GrantByMids(errCtx, &suitmdl.ArgGrantByMids{Mids: mids, Pid: pid, Expire: s.c.Rule.SuitExpire}); suitErr != nil {
dao.PromError("GrantByMids接口错误", "s.suit.GrantByMids(%d,%d,%s) error(%v)", mid, p.Stake, ip, suitErr)
}
return nil
})
}
}
group.Go(func() error {
loseCoin := float64(-p.Stake)
if _, coinErr = s.coin.ModifyCoin(errCtx, &coinmdl.ArgModifyCoin{Mid: mid, Count: loseCoin, Reason: _reason, IP: ip}); coinErr != nil {
dao.PromError("ModifyCoin接口错误", "s.coin.ModifyCoin(%d,%d,%s) error(%v)", mid, p.Stake, ip, coinErr)
}
return nil
})
if s.c.Rule.MatchLotteryID > 0 {
group.Go(func() error {
if lotteryErr := s.dao.AddLotteryTimes(errCtx, s.c.Rule.MatchLotteryID, mid); lotteryErr != nil {
log.Error("s.dao.AddLotteryTimes(%d,%d) error(%+v)", s.c.Rule.MatchLotteryID, mid, lotteryErr)
}
return nil
})
}
group.Wait()
return
}
// ListGuess get match guess list.
func (s *Service) ListGuess(c context.Context, sid, mid int64) (rs []*match.UserLog, err error) {
// get from cache.
if rs, err = s.dao.UserLogCache(c, sid, mid); err != nil || len(rs) == 0 {
if rs, err = s.dao.ListGuess(c, sid, mid); err != nil {
log.Error("s.dao.ListGuess sid(%d) mid(%d) error(%v)", sid, mid, err)
return
}
if len(rs) == 0 {
rs = _emptyUserLog
return
}
}
var (
moIDs []int64
objects map[int64]*match.Object
)
for _, v := range rs {
moIDs = append(moIDs, v.MOId)
}
if len(moIDs) == 0 {
return
}
if objects, err = s.dao.MatchSubjects(c, moIDs); err == nil {
for _, v := range rs {
if obj, ok := objects[v.MOId]; ok {
v.HomeName = obj.HomeName
v.AwayName = obj.AwayName
v.ObjResult = obj.Result
v.GameStime = obj.GameStime
}
}
}
s.cache.Do(c, func(c context.Context) {
s.dao.SetUserLogCache(c, sid, mid, rs)
})
return
}
// Guess user guess
func (s *Service) Guess(c context.Context, mid int64, p *match.ParamSid) (rs *match.UserGuess, err error) {
var (
userGuess []*match.UserLog
totalCont, winCount int64
)
if userGuess, err = s.ListGuess(c, p.Sid, mid); err != nil {
log.Error("s.ListGuess(%d,%d) error(%v)", p.Sid, mid, err)
return
}
for _, guess := range userGuess {
if guess.ObjResult > 0 {
if guess.Result == guess.ObjResult {
winCount++
}
totalCont++
}
}
rs = new(match.UserGuess)
rs.Total = totalCont
rs.Win = winCount
return
}
// ClearCache del match and object cache
func (s *Service) ClearCache(c context.Context, msg string) (err error) {
var m struct {
Table string `json:"table"`
New struct {
ID int64 `json:"id"`
Sid int64 `json:"sid"`
MatID int64 `json:"match_id"`
Mid int64 `json:"mid"`
MOId int64 `json:"m_o_id"`
} `json:"new,omitempty"`
}
if err = json.Unmarshal([]byte(msg), &m); err != nil {
log.Error("ClearCache json.Unmarshal msg(%s) error(%v)", msg, err)
return
}
log.Info("ClearCache json.Unmarshal msg(%s)", msg)
if m.Table == _matchTable {
if err = s.dao.DelActMatchCache(c, m.New.Sid, m.New.ID); err != nil {
log.Error("s.dao.DelActMatchCache sid(%d) matchID(%d) error(%v)", m.New.Sid, m.New.ID, err)
}
} else if m.Table == _objectTable {
if err = s.dao.DelObjectCache(c, m.New.ID, m.New.Sid); err != nil {
log.Error("s.dao.DelObjectCache objID(%d) Sid(%d) error(%v)", m.New.ID, m.New.Sid, err)
}
} else if m.Table == _userLogTable {
if err = s.dao.DelUserLogCache(c, m.New.Sid, m.New.Mid); err != nil {
log.Error("s.dao.DelUserLogCache mid(%d) error(%v)", m.New.Mid, err)
}
}
return
}
// AddFollow add match follow
func (s *Service) AddFollow(c context.Context, mid int64, teams []string) (err error) {
if err = s.dao.AddFollow(c, mid, teams); err != nil {
log.Error("s.dao.AddFollow mid(%d) teams(%v) error(%v)", mid, teams, err)
}
return
}
// Follow get match follow
func (s *Service) Follow(c context.Context, mid int64) (res []string, err error) {
if res, err = s.dao.Follow(c, mid); err != nil {
log.Error("s.dao.Follow mid(%d) error(%v)", mid, err)
}
if len(res) == 0 {
res = _emptyFollow
}
return
}
// ObjectsUnStart get unstart object list.
func (s *Service) ObjectsUnStart(c context.Context, mid int64, p *match.ParamObject) (rs []*match.Object, count int, err error) {
var (
userGuess []*match.UserLog
objects []*match.Object
start = (p.Pn - 1) * p.Ps
end = start + p.Ps - 1
)
// get from cache.
if rs, count, err = s.dao.ObjectsCache(c, p.Sid, start, end); err != nil || len(rs) == 0 {
if objects, err = s.dao.ObjectsUnStart(c, p.Sid); err != nil {
log.Error("s.dao.ObjectsUnStart id(%d) error(%v)", p.Sid, err)
return
}
count = len(objects)
if count == 0 || count < start {
rs = _emptyObjects
return
}
s.cache.Do(c, func(c context.Context) {
s.dao.SetObjectsCache(c, p.Sid, objects, count)
})
if count > end+1 {
rs = objects[start : end+1]
} else {
rs = objects[start:]
}
}
if mid > 0 {
if userGuess, err = s.ListGuess(c, p.Sid, mid); err != nil {
log.Error("s.ListGuess(%d,%d) error(%v)", p.Sid, mid, err)
err = nil
}
for _, rsObj := range rs {
for _, guess := range userGuess {
if rsObj.ID == guess.MOId {
rsObj.UserResult = guess.Result
break
}
}
}
}
return
}

View File

@@ -0,0 +1,88 @@
package like
import (
"context"
"testing"
"go-common/app/interface/main/activity/model/like"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Match(t *testing.T) {
Convey("test service Match", t, WithService(func(s *Service) {
sid := int64(1)
res, err := s.Match(context.Background(), sid)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
}))
}
func TestService_AddGuess(t *testing.T) {
Convey("test service AddGuess", t, WithService(func(s *Service) {
mid := int64(111)
objID := int64(1)
result := int64(2)
stake := int64(3)
lastID, err := s.AddGuess(context.Background(), mid, &like.ParamAddGuess{ObjID: objID, Result: result, Stake: stake})
So(err, ShouldBeNil)
So(lastID, ShouldBeGreaterThan, 0)
}))
}
func TestService_ListGuess(t *testing.T) {
Convey("test service match ListGuess", t, WithService(func(s *Service) {
sid := int64(111)
mid := int64(111)
guess, err := s.ListGuess(context.Background(), sid, mid)
So(err, ShouldBeNil)
So(len(guess), ShouldBeGreaterThan, 0)
}))
}
func TestService_Guess(t *testing.T) {
Convey("test service match Guess", t, WithService(func(s *Service) {
mid := int64(111)
sid := int64(1)
guess, err := s.Guess(context.Background(), mid, &like.ParamSid{Sid: sid})
So(err, ShouldBeNil)
So(guess, ShouldNotBeNil)
}))
}
func TestService_ClearCache(t *testing.T) {
Convey("test service ClearCache", t, WithService(func(s *Service) {
msg := `{"action":"update","table":"act_matchs_object","old":{"name":0},"new":{"id":2,"sid":12,"match_id":2}}`
err := s.ClearCache(context.Background(), msg)
So(err, ShouldBeNil)
}))
}
func TestService_AddFollow(t *testing.T) {
Convey("test service AddFollow", t, WithService(func(s *Service) {
mid := int64(111)
team := []string{"11", "22", "33"}
err := s.AddFollow(context.Background(), mid, team)
So(err, ShouldBeNil)
}))
}
func TestService_Follow(t *testing.T) {
Convey("test service Follow", t, WithService(func(s *Service) {
mid := int64(111)
teams, err := s.Follow(context.Background(), mid)
So(err, ShouldBeNil)
So(len(teams), ShouldBeGreaterThan, 0)
}))
}
func TestService_ObjectsUnStart(t *testing.T) {
Convey("test service ObjectsUnStart", t, WithService(func(s *Service) {
mid := int64(111)
sid := int64(1)
objs, total, err := s.ObjectsUnStart(context.Background(), mid, &like.ParamObject{Sid: sid, Pn: 1, Ps: 4})
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(objs), ShouldBeGreaterThan, 0)
}))
}

View File

@@ -0,0 +1,467 @@
package like
import (
"context"
"net"
"time"
ldao "go-common/app/interface/main/activity/dao/like"
l "go-common/app/interface/main/activity/model/like"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
// MissionLike launch buff activity .
func (s *Service) MissionLike(c context.Context, sid, mid int64) (lid int64, err error) {
var (
subject *l.SubjectItem
now = time.Now().Unix()
missionGroup int64
group *l.MissionGroup
)
if subject, err = s.dao.ActSubject(c, sid); err != nil {
log.Error("s.dao.ActSubject(%d) error(%+v)", sid, err)
return
}
if subject.ID == 0 || subject.Type != l.MISSIONGROUP {
err = ecode.ActivityNotExist
return
}
if subject.Stime.Time().Unix() > now {
err = ecode.ActivityNotStart
return
}
if subject.Etime.Time().Unix() < now {
err = ecode.ActivityOverEnd
return
}
if missionGroup, err = s.dao.LikeMissionBuff(c, sid, mid); err != nil {
log.Error("s.dao.LikeMissionBuff(%d,%d) error(%+v)", sid, mid, err)
return
}
if missionGroup > 0 {
err = ecode.ActivityHasMissionGroup
return
}
group = &l.MissionGroup{
Sid: sid,
Mid: mid,
State: ldao.MissionStateInit,
}
if lid, err = s.dao.MissionGroupAdd(c, group); err != nil {
log.Error("s.dao.MissionGroupAdd(%d,%d) error(%+v)", sid, mid, err)
return
}
s.dao.AddCacheLikeMissionBuff(c, sid, lid, mid)
return
}
// MissionInfo .
func (s *Service) MissionInfo(c context.Context, sid, lid, mid int64) (res *l.MissionInfo, err error) {
var hasBufErr, hasHelpErr error
res = &l.MissionInfo{}
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() error {
res.HasBuff, hasBufErr = s.dao.LikeMissionBuff(errCtx, sid, mid)
if hasBufErr != nil {
log.Error("s.dao.LikeMissionBuff(%d,%d) error(%+v)", sid, mid, hasBufErr)
}
return nil
})
eg.Go(func() error {
res.HasHelp, hasHelpErr = s.dao.ActMission(errCtx, sid, lid, mid)
if hasHelpErr != nil {
log.Error("s.dao.ActMission(%d,%d,%d) error(%+v)", sid, lid, mid, hasHelpErr)
}
return nil
})
eg.Wait()
return
}
// MissionUser .
func (s *Service) MissionUser(c context.Context, sid, lid int64) (res *l.MissionFriends, err error) {
var (
groups map[int64]*l.MissionGroup
group *l.MissionGroup
member *accapi.InfoReply
)
if groups, err = s.dao.MissionGroupItems(c, []int64{lid}); err != nil {
log.Error("s.dao.MissionGroupItems(%v) error(%v)", lid, err)
return
}
if _, ok := groups[lid]; !ok {
err = ecode.ActivityNotExist
return
}
group = groups[lid]
if group.ID == 0 || group.Sid != sid {
err = ecode.ActivityNotExist
return
}
if member, err = s.accClient.Info3(c, &accapi.MidReq{Mid: group.Mid}); err != nil {
log.Error(" s.acc.Info3(c,&accmdl.ArgMids{Mid:%d}) error(%v)", group.Mid, err)
return
}
res = &l.MissionFriends{
Name: member.Info.Name,
Face: member.Info.Face,
Mid: member.Info.Mid,
}
return
}
// MissionLikeAct help to mission group .
func (s *Service) MissionLikeAct(c context.Context, p *l.ParamMissionLikeAct, mid int64) (data *l.MissionLikeAct, err error) {
var (
subject *l.SubjectItem
groups map[int64]*l.MissionGroup
group *l.MissionGroup
memberRly *accapi.ProfileReply
now = time.Now().Unix()
ActMissionID, likeLimit, missionActCount, mLid int64
score = int64(1)
missionActList *l.ActMissionGroup
lottery *l.Lottery
subErr, groupErr, missionErr, caculErr, incrErr error
)
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() error {
subject, subErr = s.dao.ActSubject(errCtx, p.Sid)
return subErr
})
eg.Go(func() error {
groups, groupErr = s.dao.MissionGroupItems(errCtx, []int64{p.Lid})
return groupErr
})
if err = eg.Wait(); err != nil {
log.Error("MissionLikeAct:eg.Wait error(%v)", err)
return
}
if _, ok := groups[p.Lid]; ok {
group = groups[p.Lid]
} else {
err = ecode.ActivityNotExist
return
}
if subject.ID == 0 || subject.Type != l.MISSIONGROUP || group.ID == 0 || group.Sid != p.Sid {
err = ecode.ActivityNotExist
return
}
if group.Mid == mid {
err = ecode.ActivityMGNotYourself
return
}
if memberRly, err = s.accClient.Profile3(c, &accapi.MidReq{Mid: mid}); err != nil {
log.Error(" s.acc.Profile3(c,&accmdl.ArgMid{Mid:%d}) error(%v)", mid, err)
return
}
if err = s.judgeUser(c, subject, memberRly.Profile); err != nil {
return
}
if subject.Lstime.Time().Unix() >= now {
err = ecode.ActivityMissionNotStart
return
}
if subject.Letime.Time().Unix() <= now {
err = ecode.ActivityMissionHasEnd
return
}
if ActMissionID, err = s.dao.ActMission(c, p.Sid, p.Lid, mid); err != nil {
log.Error("s.dao.ActMission(%v) error(%+v)", p, err)
return
}
if ActMissionID > 0 {
err = ecode.ActivityHasMission
return
}
if subject.LikeLimit > 0 {
if likeLimit, err = s.dao.MissionLikeLimit(c, p.Sid, mid); err != nil {
log.Error("s.dao.ActMission(%v) error(%+v)", p, err)
return
}
if likeLimit >= subject.LikeLimit {
err = ecode.ActivityOverMissionLimit
return
}
}
if missionActCount, err = s.dao.SetMissionTop(c, p.Sid, p.Lid, score, now); err != nil {
log.Error("s.dao.SetMissionTop(%v) error(%+v)", p, err)
return
}
missionActList = &l.ActMissionGroup{
Lid: p.Lid,
Sid: p.Sid,
Mid: mid,
Action: score,
IPv6: make([]byte, 0),
}
if IPv6 := net.ParseIP(metadata.String(c, metadata.RemoteIP)); IPv6 != nil {
missionActList.IPv6 = IPv6
}
if mLid, err = s.dao.AddActMission(c, missionActList); err != nil {
log.Error("s.dao.AddActMission(%v) error(%+v)", p, err)
return
}
egT, errCtxT := errgroup.WithContext(c)
egT.Go(func() error {
missionErr = s.dao.AddCacheActMission(errCtxT, p.Sid, mLid, p.Lid, mid)
return missionErr
})
egT.Go(func() error {
caculErr = s.CalculateAchievement(errCtxT, p.Sid, group.Mid, missionActCount)
return caculErr
})
egT.Go(func() error {
_, incrErr = s.dao.InrcMissionLikeLimit(errCtxT, p.Sid, mid, score)
return incrErr
})
if err = egT.Wait(); err != nil {
log.Error("MissionLikeAct:eg.Wait add cache error(%v)", err)
return
}
if lottery, err = s.dao.LotteryIndex(c, s.c.Rule.LotteryActID, int64(0), int64(0), mid); err != nil {
log.Error("s.dao.LotteryIndex(%d) mid(%d) error(%+v)", s.c.Rule.LotteryActID, mid, err)
return
}
data = &l.MissionLikeAct{
Mlid: mLid,
Lottery: lottery,
}
return
}
// CalculateAchievement .
func (s *Service) CalculateAchievement(c context.Context, sid, mid int64, missionCount int64) (err error) {
var (
achieves *l.Achievements
avState int64
)
if achieves, err = s.dao.ActLikeAchieves(c, sid); err != nil {
log.Error("s.dao.ActLikeAchieves(%d,%d) error(%v)", sid, mid, err)
return
}
if len(achieves.Achievements) > 0 {
for _, v := range achieves.Achievements {
if v.Unlock == missionCount {
if v.Award == ldao.HaveAward {
avState = ldao.AwardNotChange
} else {
avState = ldao.AwardNoGet
}
if _, err = s.dao.AddUserAchievment(c, &l.ActLikeUserAchievement{Aid: v.ID, Sid: sid, Mid: mid, Award: avState}); err != nil {
log.Error("s.dao.AddUserAchievment(%d,%d,%v) error(%+v)", sid, mid, v, err)
return
}
break
}
}
}
return
}
// MissionRank get user rank .
func (s *Service) MissionRank(c context.Context, sid, mid int64) (data *l.MissionRank, err error) {
data = &l.MissionRank{Rank: -1}
if data.Lid, err = s.dao.LikeMissionBuff(c, sid, mid); err != nil {
log.Error("s.dao.LikeMissionBuff(%d,%d) error(%+v)", sid, mid, err)
return
}
if data.Lid > 0 {
if data.Score, err = s.dao.MissionLidScore(c, sid, data.Lid); err != nil {
log.Error("s.dao.MissionLidScore(%d,%d) error(%+v)", sid, data.Lid, err)
return
}
if data.Rank, err = s.dao.MissionLidRank(c, sid, data.Lid); err != nil {
log.Error("s.dao.MissionLidRank(%d,%d) error(%+v)", sid, data.Lid, err)
return
}
if data.Rank >= 0 {
data.Rank = data.Rank + 1
}
}
return
}
// MissionTops get the top list .
func (s *Service) MissionTops(c context.Context, sid int64, num int) (data []*l.MissionFriends, err error) {
var (
lids []int64
lidsList map[int64]*l.MissionGroup
mids []int64
membersRly *accapi.InfosReply
)
if lids, err = s.dao.MissionScoreList(c, sid, 0, num-1); err != nil {
log.Error("s.dao.MissionScoreList(%d) error(%+v)", sid, err)
return
}
if len(lids) > 0 {
if lidsList, err = s.dao.MissionGroupItems(c, lids); err != nil {
log.Error("s.dao.MissionGroupItems(%v) error(%v)", lids, err)
return
}
mids = make([]int64, 0, len(lidsList))
for _, v := range lidsList {
if v.ID > 0 {
mids = append(mids, v.Mid)
}
}
if len(mids) > 0 {
if membersRly, err = s.accClient.Infos3(c, &accapi.MidsReq{Mids: mids}); err != nil {
log.Error("s.acc.Infos3(%v) error(%v)", mids, err)
return
}
}
data = make([]*l.MissionFriends, 0, len(lids))
for _, v := range lids {
if _, ok := lidsList[v]; ok {
n := &l.MissionFriends{Mid: lidsList[v].Mid}
if membersRly != nil {
if val, y := membersRly.Infos[lidsList[v].Mid]; y {
n.Name = val.Name
n.Face = val.Face
}
}
data = append(data, n)
}
}
}
return
}
// MissionFriendsList .
func (s *Service) MissionFriendsList(c context.Context, p *l.ParamMissionFriends, mid int64) (data []*l.MissionFriends, err error) {
var (
groups map[int64]*l.MissionGroup
ActList []*l.ActMissionGroup
ActMissions *l.ActMissionGroups
mids []int64
membersRly *accapi.InfosReply
score int64
actLen int
)
if groups, err = s.dao.MissionGroupItems(c, []int64{p.Lid}); err != nil {
log.Error("s.dao.MissionGroupItems(%d) error(%v)", p.Lid, err)
return
}
if _, ok := groups[p.Lid]; !ok {
err = ecode.ActivityNotExist
return
}
if groups[p.Lid].ID == 0 || groups[p.Lid].Mid != mid || groups[p.Lid].Sid != p.Sid {
err = ecode.ActivityNotExist
return
}
if ActMissions, err = s.dao.ActMissionFriends(c, p.Sid, p.Lid); err != nil {
log.Error("s.dao.ActMissionFriends(%v) error(%+v)", p, err)
return
}
ActList = ActMissions.ActMissionGroups
actLen = len(ActList)
score, _ = s.dao.MissionLidScore(c, p.Sid, p.Lid)
if int64(actLen) < score && actLen < p.Size {
// need to update cache
s.dao.DelCacheActMissionFriends(c, p.Sid, p.Lid)
if ActMissions, err = s.dao.ActMissionFriends(c, p.Sid, p.Lid); err != nil {
log.Error("s.dao.ActMissionFriends(%v) error(%+v)", p, err)
return
}
ActList = ActMissions.ActMissionGroups
actLen = len(ActList)
}
if actLen > p.Size {
ActList = ActList[:p.Size]
actLen = p.Size
}
mids = make([]int64, 0, actLen)
for _, v := range ActList {
mids = append(mids, v.Mid)
}
if len(mids) > 0 {
if membersRly, err = s.accClient.Infos3(c, &accapi.MidsReq{Mids: mids}); err != nil {
log.Error("s.acc.Infos3(%v) error(%v)", mids, err)
return
}
}
data = make([]*l.MissionFriends, 0, len(ActList))
for _, v := range ActList {
n := &l.MissionFriends{Mid: v.Mid}
if membersRly != nil {
if val, y := membersRly.Infos[v.Mid]; y {
n.Name = val.Name
n.Face = val.Face
}
}
data = append(data, n)
}
return
}
// MissionAward .
func (s *Service) MissionAward(c context.Context, sid, mid int64) (data []*l.MissionAward, err error) {
var (
achieves *l.Achievements
userAchieves []*l.ActLikeUserAchievement
userAchMap map[int64]*l.ActLikeUserAchievement
achErr error
userErr error
)
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() error {
achieves, achErr = s.dao.ActLikeAchieves(errCtx, sid)
return achErr
})
eg.Go(func() error {
userAchieves, userErr = s.dao.UserAchievement(c, sid, mid)
return userErr
})
if err = eg.Wait(); err != nil {
log.Error("MissionAward:eg.Wait() error(%+v)", err)
return
}
userAchMap = make(map[int64]*l.ActLikeUserAchievement, len(userAchieves))
for _, v := range userAchieves {
userAchMap[v.Aid] = v
}
for _, val := range achieves.Achievements {
n := &l.MissionAward{Name: val.Name, Image: val.Image}
if v, ok := userAchMap[val.ID]; ok {
n.ID = v.ID
n.Award = v.Award
}
data = append(data, n)
}
return
}
// MissionAchieve .
func (s *Service) MissionAchieve(c context.Context, sid, id, mid int64) (res int64, err error) {
var (
useActAchieve *l.ActLikeUserAchievement
award int64
)
if useActAchieve, err = s.dao.ActUserAchieve(c, id); err != nil {
log.Error("s.dao.ActUserAchieve(%d) error(%+v)", id, err)
return
}
if useActAchieve.ID == 0 || useActAchieve.Mid != mid || useActAchieve.Sid != sid {
err = ecode.ActivityNotAward
return
}
if award, err = s.dao.CacheActUserAward(c, id); err != nil {
log.Info("s.dao.CacheActUserAward(%d) error(%v)", id, err)
}
if award > 0 {
err = ecode.ActivityHasAward
return
}
if res, err = s.dao.ActUserAchieveChange(c, id, ldao.AwardHasChange); err != nil {
log.Error("s.dao.ActUserAchieveChange(%d) error(%+v)", id, err)
return
}
s.dao.AddCacheActUserAward(c, id, id)
return
}

View File

@@ -0,0 +1,99 @@
package like
import (
"context"
"fmt"
"testing"
l "go-common/app/interface/main/activity/model/like"
"encoding/json"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_MissionLike(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
lid, err := svf.MissionLike(context.Background(), 10293, 15555180)
So(err, ShouldBeNil)
fmt.Printf("%d", lid)
}))
}
func TestService_MissionInfo(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.MissionInfo(context.Background(), 10292, 2, 442549)
So(err, ShouldBeNil)
fmt.Printf("%+v", res)
}))
}
func TestService_MissionLikeAct(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.MissionLikeAct(context.Background(), &l.ParamMissionLikeAct{Sid: 10292, Lid: 17}, 216761)
So(err, ShouldBeNil)
bs, _ := json.Marshal(res)
Printf("%+v", string(bs))
}))
}
func TestService__MissionTops(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
acts, err := svf.MissionTops(context.Background(), 10292, 50)
So(err, ShouldBeNil)
for _, v := range acts {
fmt.Printf("%+v", v)
}
}))
}
func TestService_CalculateAchievement(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
err := svf.CalculateAchievement(context.Background(), 10292, 15555180, 10)
So(err, ShouldBeNil)
}))
}
func TestService_MissionRank(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
res, err := svf.MissionRank(context.Background(), 10292, 14137123)
So(err, ShouldBeNil)
fmt.Printf("%+v", res)
}))
}
func TestService_MissionFriendsList(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
res, err := svf.MissionFriendsList(context.Background(), &l.ParamMissionFriends{Sid: 10292, Lid: 11, Size: 5}, 216761)
So(err, ShouldBeNil)
for _, v := range res {
fmt.Printf("%+v", v)
}
}))
}
func TestService_MissionAward(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
res, err := svf.MissionAward(context.Background(), 10292, 2089809)
So(err, ShouldBeNil)
for _, v := range res {
fmt.Printf("%+v", v)
}
}))
}
func TestService_MissionAchieve(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
res, err := svf.MissionAchieve(context.Background(), 10292, 4, 2089809)
So(err, ShouldBeNil)
Printf("%d", res)
}))
}
func TestService_MissionUser(t *testing.T) {
Convey("test set like act", t, WithService(func(svf *Service) {
res, err := svf.MissionUser(context.Background(), 10292, 12)
So(err, ShouldBeNil)
Printf("%+v", res)
}))
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
package like
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/model/like"
"fmt"
. "github.com/smartystreets/goconvey/convey"
)
var svf *Service
func init() {
dir, _ := filepath.Abs("../../cmd/activity-test.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(err)
}
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svf)
}
}
func TestService_Subject(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.Subject(context.Background(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestService_LikeAct(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.LikeAct(context.Background(), &like.ParamAddLikeAct{Sid: 10296, Lid: 13513, Score: 1}, 27515615)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestService_LikeActList(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.LikeActList(context.Background(), 10296, 2089809, []int64{13510, 13511, 13514, 13513})
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
fmt.Printf("res %v", res)
}))
}
func TestService_StoryKingAct(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.StoryKingAct(context.Background(), &like.ParamStoryKingAct{Sid: 10365, Lid: 2357, Score: 1}, 27515615)
So(err, ShouldBeNil)
fmt.Printf("%v", res)
}))
}
func TestService_StoryKingLeftTime(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.StoryKingLeftTime(context.Background(), 10296, 55555)
So(err, ShouldBeNil)
fmt.Printf("%d", res)
}))
}
func TestService_storyEachUsed(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.storyEachUsed(context.Background(), 10296, 216761, 13538)
So(err, ShouldBeNil)
fmt.Printf("%d", res)
}))
}
func TestService_StoryKingList(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.StoryKingList(context.Background(), &like.ParamList{Sid: 1, Pn: 1, Ps: 100, Type: "random"}, 27515257)
So(err, ShouldBeNil)
fmt.Printf("%v", res)
}))
}
func TestService_UpList(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
res, err := svf.UpList(context.Background(), &like.ParamList{Sid: 10259, Pn: 1, Ps: 100, Type: "random"}, 27515257)
So(err, ShouldBeNil)
if res != nil {
if len(res.List) > 0 {
for _, v := range res.List {
fmt.Printf("%v %v", v.Item, v.Object)
}
}
}
}))
}

View File

@@ -0,0 +1,248 @@
package like
import (
"context"
"time"
ldao "go-common/app/interface/main/activity/dao/like"
"go-common/app/interface/main/activity/model/like"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// SubjectInitialize act_subject data initialize .
func (s *Service) SubjectInitialize(c context.Context, minSid int64) (err error) {
if minSid < 0 {
minSid = 0
}
var actSub []*like.SubjectItem
for {
if actSub, err = s.dao.SubjectListMoreSid(c, minSid); err != nil {
log.Error("dao.subjectListMoreSid(%d) error(%+v)", minSid, err)
break
}
// empty slice or nil
if len(actSub) == 0 {
log.Info("SubjectInitialize end success")
break
}
for _, sub := range actSub {
item := sub
if minSid < item.ID {
minSid = item.ID
}
id := item.ID
//the activity offline is stored with empty data
if item.State != ldao.SubjectValidState {
item = &like.SubjectItem{}
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheActSubject(c, id, item)
})
}
}
s.cache.Do(c, func(c context.Context) {
s.SubjectMaxIDInitialize(c)
})
return
}
// SubjectMaxIDInitialize Initialize act_subject max id data .
func (s *Service) SubjectMaxIDInitialize(c context.Context) (err error) {
var actSub *like.SubjectItem
if actSub, err = s.dao.SubjectMaxID(c); err != nil {
log.Error(" s.dao.SubjectMaxID() error(%+v)", err)
return
}
if actSub.ID >= 0 {
if err = s.dao.AddCacheActSubjectMaxID(c, actSub.ID); err != nil {
log.Error("s.dao.AddCacheActSubjectMaxID(%d) error(%v)", actSub.ID, err)
}
}
return
}
// SubjectUp up act_subject cahce info .
func (s *Service) SubjectUp(c context.Context, sid int64) (err error) {
var (
actSub *like.SubjectItem
maxSubID int64
)
group, ctx := errgroup.WithContext(c)
group.Go(func() (e error) {
if actSub, e = s.dao.RawActSubject(ctx, sid); e != nil {
log.Error("dao.RawActSubject(%d) error(%+v)", sid, e)
}
return
})
group.Go(func() (e error) {
if maxSubID, e = s.dao.CacheActSubjectMaxID(ctx); e != nil {
log.Error("dao.RawActSubject(%d) error(%v)", sid, e)
}
return
})
if err = group.Wait(); err != nil {
log.Error("SubjectUp error(%v)", err)
return
}
if actSub.ID == 0 || actSub.State != ldao.SubjectValidState {
actSub = &like.SubjectItem{}
}
if maxSubID < sid {
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheActSubjectMaxID(context.Background(), sid)
})
}
s.cache.Do(c, func(c context.Context) {
s.dao.AddCacheActSubject(context.Background(), sid, actSub)
})
return
}
// SubjectLikeListInitialize Initialize likes list .
func (s *Service) SubjectLikeListInitialize(c context.Context, sid int64) (err error) {
var (
actSub *like.SubjectItem
items []*like.Item
lid = int64(0)
)
if actSub, err = s.dao.RawActSubject(c, sid); err != nil {
log.Error("dao.RawActSubject(%d) error(%+v)", sid, err)
return
}
if actSub.ID == 0 {
log.Info("SubjectSLikeListInitialize end success")
return
}
for {
if items, err = s.dao.LikesBySid(c, lid, sid); err != nil {
log.Error("dao.LikesBySid(%d,%d) error(%+v)", lid, sid, err)
break
}
// empty slice or nil
if len(items) == 0 {
log.Info("SubjectSLikeListInitialize end success")
break
}
//Initialize likes ctime cache
cItems := items
s.cache.Do(c, func(c context.Context) {
s.dao.LikeListCtime(c, sid, cItems)
})
for _, val := range items {
if lid < val.ID {
lid = val.ID
}
}
}
return
}
// LikeActCountInitialize Initialize like_action cache data .
func (s *Service) LikeActCountInitialize(c context.Context, sid int64) (err error) {
var (
actSub *like.SubjectItem
items []*like.Item
lid = int64(0)
types = make(map[int64]int)
likeSumItem []*like.LidLikeSum
)
if actSub, err = s.dao.RawActSubject(c, sid); err != nil {
log.Error("dao.RawActSubject(%d) error(%+v)", sid, err)
return
}
if actSub.ID == 0 {
log.Info("SubjectSLikeListInitialize end success")
return
}
for {
if items, err = s.dao.LikesBySid(c, lid, sid); err != nil {
log.Error("dao.LikesBySid(%d,%d) error(%+v)", lid, sid, err)
break
}
if len(items) == 0 {
log.Info("SubjectSLikeListInitialize end success")
break
}
lidList := make([]int64, 0, len(items))
for _, val := range items {
if lid < val.ID {
lid = val.ID
}
lidList = append(lidList, val.ID)
types[val.ID] = val.Type
}
if likeSumItem, err = s.dao.LikeActSums(c, sid, lidList); err != nil {
log.Error(" s.dao.LikeActSums(%d,%v) error(%+v)", sid, lidList, err)
return
}
if len(likeSumItem) == 0 {
continue
}
lidLike := make(map[int64]int64, len(likeSumItem))
for _, v := range likeSumItem {
lidLike[v.Lid] = v.Likes
}
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() (e error) {
e = s.dao.SetInitializeLikeCache(errCtx, sid, lidLike, types)
return
})
eg.Go(func() (e error) {
e = s.SetLikeActSum(errCtx, lidLike)
return
})
if err = eg.Wait(); err != nil {
log.Error("LikeActCountInitialize:eg.Wait() error(%+v)", err)
return
}
}
return
}
// SetLikeActSum set like_extend sum data
func (s *Service) SetLikeActSum(c context.Context, lidLikes map[int64]int64) (err error) {
var (
AddLids []*like.Extend
)
if len(lidLikes) == 0 {
return
}
for k, v := range lidLikes {
AddLids = append(AddLids, &like.Extend{Like: v, Lid: k})
}
_, err = s.BatchInsertLikeExtend(c, AddLids)
return
}
// ActSubject .
func (s *Service) ActSubject(c context.Context, sid int64) (res *like.SubjectItem, err error) {
if res, err = s.dao.ActSubject(c, sid); err != nil {
return
}
if res == nil {
err = ecode.NothingFound
}
return
}
// ActProtocol .
func (s *Service) ActProtocol(c context.Context, a *like.ArgActProtocol) (res *like.SubProtocol, err error) {
res = new(like.SubProtocol)
if res.SubjectItem, err = s.dao.ActSubject(c, a.Sid); err != nil {
log.Error("s.dao.ActSubject() error(%+v)", err)
return
}
if res.SubjectItem.ID == 0 {
err = ecode.NothingFound
return
}
now := time.Now().Unix()
if int64(res.SubjectItem.Stime) <= now && int64(res.SubjectItem.Etime) >= now {
if res.ActSubjectProtocol, err = s.dao.ActSubjectProtocol(c, a.Sid); err != nil {
log.Error("s.dao.ActSubjectProtocol(%d) error(%+v)", a.Sid, err)
}
}
return
}

View File

@@ -0,0 +1,67 @@
package like
import (
"context"
"testing"
"time"
"go-common/app/interface/main/activity/model/like"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_SubjectInitialize(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
err := svf.SubjectInitialize(context.Background(), 10292)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_SubjectMaxIDInitialize(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
err := svf.SubjectMaxIDInitialize(context.Background())
So(err, ShouldBeNil)
}))
}
func TestService_SubjectLikeListInitialize(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
err := svf.SubjectLikeListInitialize(context.Background(), 10256)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_LikeActCountInitialize(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
err := svf.LikeActCountInitialize(context.Background(), 10256)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_SubjectUp(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
err := svf.SubjectUp(context.Background(), 10256)
time.Sleep(time.Second)
So(err, ShouldBeNil)
}))
}
func TestService_ActSubject(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
data, err := svf.ActSubject(context.Background(), 10340)
time.Sleep(time.Second)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}
func TestService_ActProtocol(t *testing.T) {
Convey("should return without err", t, WithService(func(svf *Service) {
data, _ := svf.ActProtocol(context.Background(), &like.ArgActProtocol{Sid: 10274})
time.Sleep(time.Second)
Printf("%+v %+v", data, data.Protocol)
}))
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["sports.go"],
importpath = "go-common/app/interface/main/activity/service/sports",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/sports:go_default_library",
"//app/interface/main/activity/model/sports: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"],
)
go_test(
name = "go_default_test",
srcs = ["sports_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/model/sports:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,158 @@
package sports
import (
"context"
"encoding/json"
"net/url"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/dao/sports"
mdlsp "go-common/app/interface/main/activity/model/sports"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_qqNews = 1
_qqMatch = 2
_qqMatchTid = "14"
_qqTeamRank = 3
_qqRankTid = "34"
_qqPlayerRank = 4
_qqRoute = "matchUnion/fetchData"
_newsRoute = "getQQNewsIndexAndItemsVerify"
)
// Service struct
type Service struct {
dao *sports.Dao
}
// New Service
func New(c *conf.Config) (s *Service) {
s = &Service{
dao: sports.New(c),
}
go s.qqNews()
go s.qqMatch()
go s.qqTeamRank()
go s.qqPlayerRank()
return
}
func (s *Service) qqNews() {
var (
params = url.Values{}
rs *mdlsp.QqRes
err error
c = context.Background()
)
for {
for t := 0; t < conf.Conf.Rule.QqTryCount; t++ {
if rs, err = s.dao.QqNews(c, params, _newsRoute); err != nil || rs == nil {
continue
}
s.dao.SetQqCache(c, &rs.IDlist, _qqNews)
break
}
time.Sleep(time.Duration(conf.Conf.Rule.TickQq))
}
}
func (s *Service) qqMatch() {
var (
rs *json.RawMessage
err error
c = context.Background()
params = url.Values{}
)
params.Set("tid", _qqMatchTid)
params.Set("indexName", "col_4")
params.Set("startTime", conf.Conf.Rule.QqStartTime)
params.Set("endTime", conf.Conf.Rule.QqEndTime)
for {
for t := 0; t < conf.Conf.Rule.QqTryCount; t++ {
if rs, err = s.dao.Qq(c, params, _qqRoute); err != nil || rs == nil || len(*rs) == 0 {
continue
}
s.dao.SetQqCache(c, rs, _qqMatch)
break
}
time.Sleep(time.Duration(conf.Conf.Rule.TickQq))
}
}
func (s *Service) qqTeamRank() {
var (
rs *json.RawMessage
err error
c = context.Background()
params = url.Values{}
)
params.Set("tid", _qqRankTid)
params.Set("competitionId", "4")
params.Set("seasonId", conf.Conf.Rule.QqYear)
params.Set("valueType", "teamRank")
params.Set("valueId", "teamRank")
for {
for t := 0; t < conf.Conf.Rule.QqTryCount; t++ {
if rs, err = s.dao.Qq(c, params, _qqRoute); err != nil || rs == nil || len(*rs) == 0 {
continue
}
s.dao.SetQqCache(c, rs, _qqTeamRank)
break
}
time.Sleep(time.Duration(conf.Conf.Rule.TickQq))
}
}
func (s *Service) qqPlayerRank() {
var (
rs *json.RawMessage
err error
c = context.Background()
params = url.Values{}
)
params.Set("tid", _qqRankTid)
params.Set("competitionId", "4")
params.Set("seasonId", conf.Conf.Rule.PlayerYear)
params.Set("valueType", "playerGoalRank")
params.Set("valueId", "playerGoalRank")
for {
for t := 0; t < conf.Conf.Rule.QqTryCount; t++ {
if rs, err = s.dao.Qq(c, params, _qqRoute); err != nil || rs == nil || len(*rs) == 0 {
continue
}
s.dao.SetQqCache(c, rs, _qqPlayerRank)
break
}
time.Sleep(time.Duration(conf.Conf.Rule.TickQq))
}
}
// Qq get qq.
func (s *Service) Qq(c context.Context, params url.Values, p *mdlsp.ParamQq) (rs *json.RawMessage, err error) {
if p.Tp > 0 {
if rs, err = s.dao.QqCache(c, p.Tp); err != nil {
log.Error("s.dao.QqCache tp(%d) error(%v) ", p.Tp, err)
}
} else if rs, err = s.dao.Qq(c, params, p.Route); err != nil {
sports.PromError("QQ接口错误", "s.dao.Qq route(%s) error(%v)", p.Route, err)
}
if rs == nil {
err = ecode.ActivityServerTimeout
}
return
}
// News get qq news.
func (s *Service) News(c context.Context, params url.Values, p *mdlsp.ParamNews) (rs *mdlsp.QqRes, err error) {
if rs, err = s.dao.QqNews(c, params, p.Route); err != nil {
sports.PromError("QQ接口错误", "s.dao.Qq error(%v)", err)
}
if rs == nil {
err = ecode.ActivityServerTimeout
}
return
}

View File

@@ -0,0 +1,57 @@
package sports
import (
"context"
"flag"
"net/url"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/model/sports"
. "github.com/smartystreets/goconvey/convey"
)
var svf *Service
func init() {
dir, _ := filepath.Abs("../../cmd/activity-test.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(err)
}
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svf)
}
}
func TestService_Qq(t *testing.T) {
Convey("test service qq", t, WithService(func(svf *Service) {
var (
params url.Values
)
res, err := svf.Qq(context.Background(), params, &sports.ParamQq{Tp: 1})
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}
func TestService_News(t *testing.T) {
Convey("test service qq news", t, WithService(func(svf *Service) {
var (
params url.Values
)
res, err := svf.News(context.Background(), params, &sports.ParamNews{Route: "getQQNewsIndexAndItemsVerify"})
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
}))
}

View File

@@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"service.go",
"timemachine.go",
],
importpath = "go-common/app/interface/main/activity/service/timemachine",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/activity/conf:go_default_library",
"//app/interface/main/activity/dao/like:go_default_library",
"//app/interface/main/activity/dao/timemachine:go_default_library",
"//app/interface/main/activity/model/timemachine:go_default_library",
"//app/interface/main/tag/api:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/interface/openplatform/article/rpc/client:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup.v2: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,157 @@
package timemachine
import (
"context"
"encoding/json"
"time"
"go-common/app/interface/main/activity/conf"
"go-common/app/interface/main/activity/dao/like"
"go-common/app/interface/main/activity/dao/timemachine"
model "go-common/app/interface/main/activity/model/timemachine"
tagclient "go-common/app/interface/main/tag/api"
artrpc "go-common/app/interface/openplatform/article/rpc/client"
accclient "go-common/app/service/main/account/api"
arcclient "go-common/app/service/main/archive/api"
"go-common/library/log"
)
const (
_typeArticle = 1
_typeArchive = 2
_totalViewLen = 3
)
// Service time machine service.
type Service struct {
c *conf.Config
likeDao *like.Dao
dao *timemachine.Dao
article *artrpc.Service
tagClient tagclient.TagRPCClient
arcClient arcclient.ArchiveClient
accClient accclient.AccountClient
tmMidMap map[int64]struct{}
tagDescMap map[int64]*model.TagDesc
tagRegionDescMap map[int64]*model.TagRegionDesc
regionDescMap map[int64]*model.RegionDesc
}
// New init.
func New(c *conf.Config) *Service {
s := &Service{
c: c,
dao: timemachine.New(c),
likeDao: like.New(c),
article: artrpc.New(c.RPCClient2.Article),
}
var err error
if s.tagClient, err = tagclient.NewClient(c.TagClient); err != nil {
panic(err)
}
if s.arcClient, err = arcclient.NewClient(c.ArcClient); err != nil {
panic(err)
}
if s.accClient, err = accclient.NewClient(c.AccClient); err != nil {
panic(err)
}
go s.loadAdminMids()
go s.tmDescproc()
return s
}
func (s *Service) loadAdminMids() {
for {
time.Sleep(time.Duration(s.c.Interval.TmInternal))
tmp := make(map[int64]struct{}, len(s.c.Rule.TmMids))
for _, mid := range s.c.Rule.TmMids {
tmp[mid] = struct{}{}
}
s.tmMidMap = tmp
}
}
func (s *Service) tmDescproc() {
go func() {
for {
time.Sleep(time.Duration(s.c.Interval.TmInternal))
if s.c.Timemachine.TagDescID == 0 {
continue
}
if data, err := s.likeDao.SourceItem(context.Background(), s.c.Timemachine.TagDescID); err != nil {
log.Error("tmDescproc s.likeDao.SourceItem(%d) error(%v)", s.c.Timemachine.TagDescID, err)
continue
} else {
var descs struct {
List []*struct {
Data *model.TagDesc `json:"data"`
} `json:"list"`
}
if err := json.Unmarshal(data, &descs); err != nil {
log.Error("tmDescproc tag s.likeDao.SourceItem(%s) json error(%v)", string(data), err)
continue
}
tmp := make(map[int64]*model.TagDesc, len(descs.List))
for _, v := range descs.List {
tmp[v.Data.TagID] = v.Data
}
s.tagDescMap = tmp
}
}
}()
go func() {
for {
time.Sleep(time.Duration(s.c.Interval.TmInternal))
if s.c.Timemachine.TagRegionDescID == 0 {
continue
}
if data, err := s.likeDao.SourceItem(context.Background(), s.c.Timemachine.TagRegionDescID); err != nil {
log.Error("tmDescproc tagRegion s.likeDao.SourceItem(%d) error(%v)", s.c.Timemachine.TagRegionDescID, err)
continue
} else {
var descs struct {
List []*struct {
Data *model.TagRegionDesc `json:"data"`
} `json:"list"`
}
if err := json.Unmarshal(data, &descs); err != nil {
log.Error("tmDescproc tagRegion s.likeDao.SourceItem(%s) json error(%v)", string(data), err)
continue
}
tmp := make(map[int64]*model.TagRegionDesc, len(descs.List))
for _, v := range descs.List {
tmp[v.Data.RID] = v.Data
}
s.tagRegionDescMap = tmp
}
}
}()
go func() {
for {
time.Sleep(time.Duration(s.c.Interval.TmInternal))
if s.c.Timemachine.RegionDescID == 0 {
continue
}
if data, err := s.likeDao.SourceItem(context.Background(), s.c.Timemachine.RegionDescID); err != nil {
log.Error("tmDescproc region s.likeDao.SourceItem(%d) error(%v)", s.c.Timemachine.RegionDescID, err)
continue
} else {
var descs struct {
List []*struct {
Data *model.RegionDesc `json:"data"`
} `json:"list"`
}
if err := json.Unmarshal(data, &descs); err != nil {
log.Error("tmDescproc region s.likeDao.SourceItem(%s) json error(%v)", string(data), err)
continue
}
tmp := make(map[int64]*model.RegionDesc, len(descs.List))
for _, v := range descs.List {
tmp[v.Data.RID] = v.Data
}
s.regionDescMap = tmp
}
}
}()
}

View File

@@ -0,0 +1,475 @@
package timemachine
import (
"context"
"sort"
"strconv"
"strings"
"time"
model "go-common/app/interface/main/activity/model/timemachine"
tagmdl "go-common/app/interface/main/tag/api"
artmdl "go-common/app/interface/openplatform/article/model"
accmdl "go-common/app/service/main/account/api"
arcmdl "go-common/app/service/main/archive/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup.v2"
)
// StartTmproc start tm proc.
//func (s *Service) StartTmproc(c context.Context) (err error) {
// s.dao.StartTmProc(context.Background())
// return
//}
// StopTmproc start tm proc.
//func (s *Service) StopTmproc(c context.Context) (err error) {
// s.dao.StopTmproc(c)
// return
//}
// Timemachine2018Raw .
func (s *Service) Timemachine2018Raw(c context.Context, loginMid, mid int64) (data *model.Item, err error) {
if _, ok := s.tmMidMap[loginMid]; !ok {
err = ecode.AccessDenied
return
}
if mid == 0 {
mid = loginMid
}
if data, err = s.dao.RawTimemachine(c, mid); err != nil {
log.Error("Timemachine2018 s.dao.RawTimemachine(%d) error(%v)", mid, err)
}
return
}
// Timemachine2018Cache .
func (s *Service) Timemachine2018Cache(c context.Context, loginMid, mid int64) (data *model.Item, err error) {
if _, ok := s.tmMidMap[loginMid]; !ok {
err = ecode.AccessDenied
return
}
if mid == 0 {
mid = loginMid
}
if data, err = s.dao.CacheTimemachine(c, mid); err != nil {
log.Error("Timemachine2018Cache s.dao.CacheTimemachine(%d) error(%v)", mid, err)
}
return
}
// Timemachine2018 .
func (s *Service) Timemachine2018(c context.Context, loginMid, mid int64) (data *model.Timemachine, err error) {
if _, ok := s.tmMidMap[loginMid]; !ok {
mid = loginMid
} else {
if mid == 0 {
mid = loginMid
}
}
var item *model.Item
if item, err = s.dao.CacheTimemachine(c, mid); err != nil {
log.Error("Timemachine2018 s.dao.Timemachine(%d) error(%v)", mid, err)
err = nil
}
if item == nil || item.DurationHour == 0 || (item.LikeUpAvDuration == 0 && item.LikeUpLiveDuration == 0) {
item = &model.Item{Mid: mid}
}
data = s.groupTmData(c, item)
return
}
func (s *Service) groupTmData(c context.Context, item *model.Item) (data *model.Timemachine) {
var (
aids, viewAids, upAids, artIDs, mids []int64
totalView, ugcView, pgcView []*model.AidView
upBestLiveFanMid, liveMinute, upBestFanMid, favVv, subTidBest int64
)
data = &model.Timemachine{
Mid: item.Mid,
IsUp: item.IsUp,
DurationHour: item.DurationHour,
ArchiveVv: item.ArchiveVv,
BrainwashCirVv: item.BrainwashCirVv,
FirstSubmitType: item.FirstSubmitType,
LikeSubtidVv: item.LikeSubtidVv,
LikeUpAvDuration: item.LikeUpAvDuration,
LikeUpLiveDuration: item.LikeUpLiveDuration,
LikeUpDuration: item.LikeUpAvDuration + item.LikeUpLiveDuration,
LikeLiveUpSubTname: item.LikeLiveUpSubTname,
BestAvidType: item.BestAvidType,
AllVv: item.AllVv,
BestAvidOldType: item.BestAvidOldType,
OldAvVv: item.OldAvVv,
UpLiveDuration: item.UpLiveDuration,
IsLiveUp: item.IsLiveUp,
ValidLiveDays: item.ValidLiveDays,
AddAttentions: item.Attentions,
WinRatio: item.WinRatio,
SubmitAvsRds: item.SubmitAvsRds,
}
// win ratio fix
if data.WinRatio == "100%" {
data.WinRatio = "99%"
}
if data.ValidLiveDays > 365 {
data.ValidLiveDays = 365
}
if item.Like2SubTids != "" {
subTidBest = s.groupTagDesc(item, data)
}
if tagDesc, ok := s.tagDescMap[item.LikeTagID]; ok && tagDesc != nil {
data.LikeTagDescFirst = tagDesc.Desc1
data.LikeTagDescSecond = tagDesc.Desc2Line1
data.LikeTagDescSecond2 = tagDesc.Desc2Line2
} else if subTidBest > 0 {
if tagRegDesc, ok := s.tagRegionDescMap[subTidBest]; ok && tagRegDesc != nil {
data.LikeTagDescFirst = tagRegDesc.Desc1
data.LikeTagDescSecond = tagRegDesc.Desc2Line1
data.LikeTagDescSecond2 = tagRegDesc.Desc2Line2
}
}
if braTime, e := time.Parse("20060102", item.BrainwashCirTime); e != nil {
log.Warn("groupTmData BrainwashCirTime time.Parse(%s) warn(%v)", item.BrainwashCirTime, e)
} else {
data.BrainwashCirTime = braTime.Format("2006.01.02")
}
// LikeUpDuration data fix
if data.LikeUpDuration > item.DurationHour*60 {
if data.LikeUpDuration < (item.AvDurationHour*60 + item.LikeUpLiveDuration) {
if (item.AvDurationHour*60 + item.LikeUpLiveDuration) > 0 {
data.LikeUpDuration = int64(float64(item.DurationHour*60) * (float64(data.LikeUpDuration) / float64(item.AvDurationHour*60+item.LikeUpLiveDuration)))
}
} else {
if (item.PlayDurationHourRep*60 + item.LikeUpLiveDuration) > 0 {
data.LikeUpDuration = int64(float64(item.DurationHour*60) * (float64(item.LikeUpAvDurationRep+item.LikeUpLiveDuration) / float64(item.PlayDurationHourRep*60+item.LikeUpLiveDuration)))
}
}
}
realIP := metadata.String(c, metadata.RemoteIP)
group := errgroup.WithCancel(c)
// tag data
if item.LikeTagID > 0 {
group.Go(func(ctx context.Context) error {
if tag, e := s.tagClient.Tag(ctx, &tagmdl.TagReq{Tid: item.LikeTagID}); e != nil || tag == nil {
log.Error("s.tagClient.Tag tid(%d) error(%v)", item.LikeTagID, e)
} else {
data.LikeTagID = item.LikeTagID
data.LikeTagName = tag.Tag.Name
}
return nil
})
}
// group aids
if item.BestAvid > 0 {
aids = append(aids, item.BestAvid)
}
if item.LikesUgc3Avids != "" {
list := strings.Split(item.LikesUgc3Avids, ",")
for _, v := range list {
items := strings.Split(v, ":")
if len(items) == 2 {
aid, e := strconv.ParseInt(items[0], 10, 64)
if e != nil {
continue
}
vv, e := strconv.ParseInt(items[1], 10, 64)
if e != nil {
continue
}
ugcView = append(ugcView, &model.AidView{Aid: aid, View: vv})
}
}
}
if item.LikePgc3Avids != "" {
list := strings.Split(item.LikePgc3Avids, ",")
for _, v := range list {
items := strings.Split(v, "@")
if len(items) == 2 {
aid, e := strconv.ParseInt(items[0], 10, 64)
if e != nil {
continue
}
vv, e := strconv.ParseInt(items[1], 10, 64)
if e != nil {
continue
}
pgcView = append(pgcView, &model.AidView{Aid: aid, View: vv})
}
}
}
ugcViewLen := len(ugcView)
if ugcViewLen > 3 {
ugcView = ugcView[:_totalViewLen]
}
sort.Slice(ugcView, func(i, j int) bool {
return ugcView[i].View > ugcView[j].View
})
pgcViewLen := len(pgcView)
if pgcViewLen > 3 {
pgcView = pgcView[:_totalViewLen]
}
sort.Slice(pgcView, func(i, j int) bool {
return pgcView[i].View > pgcView[j].View
})
totalView = append(totalView, ugcView...)
switch {
case ugcViewLen == 0:
totalView = append(totalView, pgcView...)
case ugcViewLen == 1:
switch {
case pgcViewLen == 1:
totalView = append(totalView, pgcView[0])
case pgcViewLen > 1:
totalView = append(totalView, pgcView[:2]...)
}
case ugcViewLen >= 2:
if pgcViewLen > 0 {
totalView = append(totalView, pgcView[0])
}
}
sort.Slice(totalView, func(i, j int) bool {
return totalView[i].View > totalView[j].View
})
if len(totalView) > _totalViewLen {
totalView = totalView[:_totalViewLen]
}
for _, v := range totalView {
viewAids = append(viewAids, v.Aid)
}
aids = append(aids, viewAids...)
if item.LikeUp3Avs != "" {
aidsStr := strings.Split(item.LikeUp3Avs, ",")
for _, aidStr := range aidsStr {
if aid, e := strconv.ParseInt(aidStr, 10, 64); e != nil {
continue
} else {
upAids = append(upAids, aid)
}
}
}
aids = append(aids, upAids...)
if item.BrainwashCirAvid > 0 {
aids = append(aids, item.BrainwashCirAvid)
}
if item.BestAvid > 0 {
switch item.BestAvidType {
case _typeArticle:
artIDs = append(artIDs, item.BestAvid)
case _typeArchive:
aids = append(aids, item.BestAvid)
}
}
if item.BestAvidOld > 0 {
switch item.BestAvidOldType {
case _typeArticle:
artIDs = append(artIDs, item.BestAvidOld)
case _typeArchive:
aids = append(aids, item.BestAvidOld)
}
}
if item.FirstSubmitAvid > 0 {
switch item.FirstSubmitType {
case _typeArticle:
artIDs = append(artIDs, item.FirstSubmitAvid)
case _typeArchive:
aids = append(aids, item.FirstSubmitAvid)
}
}
if len(aids) > 0 {
group.Go(func(ctx context.Context) error {
s.groupArcData(ctx, aids, upAids, totalView, item, data)
return nil
})
}
// article
if len(artIDs) > 0 {
group.Go(func(ctx context.Context) error {
s.groupArtData(ctx, artIDs, item, data)
return nil
})
}
group.Go(func(ctx context.Context) error {
if acc, e := s.accClient.ProfileWithStat3(ctx, &accmdl.MidReq{Mid: item.Mid}); e != nil {
log.Error("groupTmData s.arcClient.ProfileWithStat3(%v) error(%v)", item.Mid, e)
} else {
data.Uname = acc.Profile.Name
data.Face = acc.Profile.Face
data.Fans = acc.Follower
data.RegTime = time.Unix(int64(acc.Profile.JoinTime), 0).Format("2006.01.02")
data.RegDay = (time.Now().Unix() - int64(acc.Profile.JoinTime)) / 86400
}
return nil
})
// group mids
if item.LikeBestUpID > 0 {
mids = append(mids, item.LikeBestUpID)
}
if item.IsUp == 1 {
if firstSubTime, e := time.Parse("2006-01-02 15:04:05", item.FirstSubmitTime); e != nil {
log.Warn("groupTmData FirstSubmitTime time.Parse(%s) warn(%v)", item.FirstSubmitTime, e)
} else {
data.FirstSubmitTime = firstSubTime.Format("2006.01.02")
}
if item.UpBestFanVv != "" {
list := strings.Split(item.UpBestFanVv, "@")
if len(list) == 2 {
if mid, e := strconv.ParseInt(list[0], 10, 64); e != nil {
log.Error("UpBestFanVv parse(%s) error(%v)", list[0], e)
} else {
upBestFanMid = mid
mids = append(mids, mid)
}
if vv, e := strconv.ParseInt(list[1], 10, 64); e != nil {
log.Error("UpBestFanLiveMinute parse(%s) error(%v)", list[1], e)
} else {
favVv = vv
}
}
}
}
if item.IsLiveUp == 1 {
if maxCdnTime, e := time.Parse("20060102", item.MaxCdnNumDate); e != nil {
log.Warn("groupTmData MaxCdnNumDate time.Parse(%s) warn(%v)", item.MaxCdnNumDate, e)
} else {
data.MaxCdnNumDate = maxCdnTime.Format("2006.01.02")
}
data.MaxCdnNum = item.MaxCdnNum
if item.UpBestFanLiveMinute != "" {
list := strings.Split(item.UpBestFanLiveMinute, "@")
if len(list) == 2 {
if mid, e := strconv.ParseInt(list[0], 10, 64); e != nil {
log.Error("UpBestFanLiveMinute parse(%s) error(%v)", list[0], e)
} else {
upBestLiveFanMid = mid
mids = append(mids, mid)
}
if minute, e := strconv.ParseInt(list[1], 10, 64); e != nil {
log.Error("UpBestFanLiveMinute parse(%s) error(%v)", list[1], e)
} else {
liveMinute = minute
}
}
}
}
if len(mids) > 0 {
group.Go(func(ctx context.Context) error {
if accs, e := s.accClient.Infos3(ctx, &accmdl.MidsReq{Mids: mids, RealIp: realIP}); e != nil || accs.Infos == nil {
log.Error("groupTmData s.accClient.Cards3(%v) error(%v)", mids, e)
} else {
if item.LikeBestUpID > 0 {
if info, ok := accs.Infos[item.LikeBestUpID]; ok {
data.LikeBestUpID = item.LikeBestUpID
data.LikeBestUpName = info.Name
data.LikeBestUpFace = info.Face
}
}
if item.IsUp == 1 && upBestFanMid > 0 {
if info, ok := accs.Infos[upBestFanMid]; ok {
data.UpBestFanVv = &model.FavVv{Mid: upBestFanMid, Name: info.Name, Face: info.Face, Vv: favVv}
}
}
if item.IsLiveUp == 1 && upBestLiveFanMid > 0 {
if info, ok := accs.Infos[upBestLiveFanMid]; ok {
data.UpBestFanLiveMinute = &model.FanMinute{Mid: upBestLiveFanMid, Name: info.Name, Face: info.Face, Minute: liveMinute}
}
}
}
return nil
})
}
if e := group.Wait(); e != nil {
log.Error("groupTmData group.Wait error(%v)", e)
}
if len(data.LikeUp3Arcs) == 0 {
data.LikeUp3Arcs = make([]*model.TmArc, 0)
}
return
}
func (s *Service) groupArcData(c context.Context, aids, upAids []int64, totalView []*model.AidView, item *model.Item, data *model.Timemachine) {
if arcs, e := s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); e != nil {
log.Error("groupTmData s.arcClient.Arcs(%v) error(%v)", aids, e)
} else if arcs != nil {
if item.BrainwashCirAvid > 0 {
if arc, ok := arcs.Arcs[item.BrainwashCirAvid]; ok && arc.IsNormal() {
data.BrainwashCirArc = &model.TmArc{Aid: item.BrainwashCirAvid, Title: arc.Title, Cover: arc.Pic, Author: arc.Author}
}
}
if item.BestAvid > 0 && item.BestAvidType == _typeArchive {
if arc, ok := arcs.Arcs[item.BestAvid]; ok && arc.IsNormal() {
data.BestArc = &model.TmArc{Aid: item.BestAvid, Title: arc.Title, Cover: arc.Pic, Author: arc.Author}
}
}
if item.BestAvidOld > 0 && item.BestAvidOldType == _typeArchive {
if arc, ok := arcs.Arcs[item.BestAvidOld]; ok && arc.IsNormal() {
data.BestArcOld = &model.TmArc{Aid: item.BestAvidOld, Title: arc.Title, Cover: arc.Pic, Author: arc.Author}
}
}
if item.FirstSubmitAvid > 0 && item.FirstSubmitType == _typeArchive {
if arc, ok := arcs.Arcs[item.FirstSubmitAvid]; ok && arc.IsNormal() {
data.FirstSubmitArc = &model.TmArc{Aid: item.FirstSubmitAvid, Title: arc.Title, Cover: arc.Pic, Author: arc.Author}
}
}
for _, aid := range upAids {
if arc, ok := arcs.Arcs[aid]; ok && arc.IsNormal() {
data.LikeUp3Arcs = append(data.LikeUp3Arcs, &model.TmArc{Aid: aid, Title: arc.Title, Cover: arc.Pic, Author: arc.Author})
}
}
for _, item := range totalView {
if arc, ok := arcs.Arcs[item.Aid]; ok && arc.IsNormal() {
data.Likes3Arcs = append(data.Likes3Arcs, &model.TmArc{Aid: item.Aid, Title: arc.Title, Cover: arc.Pic, Author: arc.Author})
}
}
}
}
func (s *Service) groupArtData(c context.Context, artIDs []int64, item *model.Item, data *model.Timemachine) {
if arts, e := s.article.ArticleMetas(c, &artmdl.ArgAids{Aids: artIDs}); e != nil {
log.Error("groupTmData s.article.ArticleMetas(%v) error(%v)", artIDs, e)
} else {
if item.BestAvid > 0 && item.BestAvidType == _typeArticle {
if art, ok := arts[item.BestAvid]; ok {
data.BestArc = &model.TmArc{Aid: item.BestAvid, Title: art.Title}
}
}
if item.BestAvidOld > 0 && item.BestAvidOldType == _typeArticle {
if art, ok := arts[item.BestAvidOld]; ok {
data.BestArcOld = &model.TmArc{Aid: item.BestAvidOld, Title: art.Title}
}
}
if item.FirstSubmitAvid > 0 && item.FirstSubmitType == _typeArticle {
if art, ok := arts[item.FirstSubmitAvid]; ok {
data.FirstSubmitArc = &model.TmArc{Aid: item.FirstSubmitAvid, Title: art.Title}
}
}
}
}
func (s *Service) groupTagDesc(item *model.Item, data *model.Timemachine) (subTidBest int64) {
var subTid int64
subList := strings.Split(item.Like2SubTids, ",")
if len(subList) == 2 {
if subID, e := strconv.ParseInt(subList[0], 10, 64); e != nil {
log.Warn("groupTmData Like2SubTids time.Parse(%s) warn(%v)", subList[0], e)
} else if subID > 0 {
subTidBest = subID
}
if subID, e := strconv.ParseInt(subList[1], 10, 64); e != nil {
log.Warn("groupTmData Like2SubTids strconv.ParseInt(%s) warn(%v)", subList[1], e)
} else if subID > 0 {
subTid = subID
}
if regionDesc, ok := s.regionDescMap[subTidBest]; ok && regionDesc != nil {
data.LikeSubDesc2 = regionDesc.Desc2
data.LikeSubDesc3 = regionDesc.Desc3
}
if regionDesc, ok := s.regionDescMap[subTid]; ok && regionDesc != nil {
data.LikeSubDesc1 = regionDesc.Desc1
}
}
return
}