186 lines
5.7 KiB
Go
186 lines
5.7 KiB
Go
|
package service
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"fmt"
|
|||
|
"go-common/app/interface/live/push-live/model"
|
|||
|
"go-common/library/log"
|
|||
|
"go-common/library/queue/databus"
|
|||
|
"go-common/library/sync/errgroup"
|
|||
|
"sync"
|
|||
|
|
|||
|
"github.com/pkg/errors"
|
|||
|
)
|
|||
|
|
|||
|
// LiveStartMessage 直播开播提醒推送消息
|
|||
|
func (s *Service) LiveStartMessage(ctx context.Context, msg *databus.Message) (err error) {
|
|||
|
defer msg.Commit()
|
|||
|
var total int
|
|||
|
// message
|
|||
|
m := new(model.StartLiveMessage)
|
|||
|
if err = json.Unmarshal(msg.Value, &m); err != nil {
|
|||
|
log.Error("[service.start_live|LiveStartMessage] json Unmarshal error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
task := s.InitPushTask(m)
|
|||
|
midMap := s.GetMids(ctx, task)
|
|||
|
// do push
|
|||
|
total = s.Push(task, midMap)
|
|||
|
// create push task
|
|||
|
go s.CreatePushTask(task, total)
|
|||
|
log.Info("[service.push|LiveStartMessage] start live push done, total(%d), task(%v), model(%v), err(%v)",
|
|||
|
total, task, m, err)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// InitPushTask 初始化开播提醒推送task
|
|||
|
func (s *Service) InitPushTask(m *model.StartLiveMessage) (task *model.ApPushTask) {
|
|||
|
s.mutex.RLock()
|
|||
|
currentPushTypes := s.pushTypes
|
|||
|
s.mutex.RUnlock()
|
|||
|
// push task model
|
|||
|
task = &model.ApPushTask{
|
|||
|
Type: model.LivePushType,
|
|||
|
TargetID: m.TargetID,
|
|||
|
AlertTitle: m.Uname,
|
|||
|
AlertBody: m.RoomTitle,
|
|||
|
MidSource: s.getSourceByTypes(currentPushTypes),
|
|||
|
LinkType: s.c.Push.LinkType,
|
|||
|
LinkValue: m.LinkValue,
|
|||
|
ExpireTime: m.ExpireTime,
|
|||
|
}
|
|||
|
return task
|
|||
|
}
|
|||
|
|
|||
|
// GetMids 开播提醒,根据配置的策略从不同来源获取需要推送的用户id
|
|||
|
func (s *Service) GetMids(c context.Context, task *model.ApPushTask) map[int][]int64 {
|
|||
|
var (
|
|||
|
mutex sync.Mutex
|
|||
|
group = errgroup.Group{}
|
|||
|
fans = make(map[int64]bool)
|
|||
|
fansSP = make(map[int64]bool)
|
|||
|
midMap = make(map[int][]int64)
|
|||
|
midBlackList = make(map[int64]bool)
|
|||
|
)
|
|||
|
|
|||
|
// 获取黑名单
|
|||
|
mb, err := s.dao.GetBlackList(c, task)
|
|||
|
if err != nil {
|
|||
|
log.Error("[service.start_live|GetMids] get black list error(%v), task(%+v)", err, task)
|
|||
|
} else {
|
|||
|
midBlackList = mb
|
|||
|
log.Info("[service.start_live|GetMids] get black list len(%d), task(%+v)", len(midBlackList), task)
|
|||
|
}
|
|||
|
|
|||
|
// try get latest push options and expired time
|
|||
|
s.mutex.RLock()
|
|||
|
currentPushTypes := s.pushTypes
|
|||
|
s.mutex.RUnlock()
|
|||
|
// 开多个协程获取后求并集
|
|||
|
for _, t := range currentPushTypes {
|
|||
|
tp := string(t)
|
|||
|
group.Go(func() (e error) {
|
|||
|
var mFans, mSpe map[int64]bool
|
|||
|
switch tp {
|
|||
|
case model.StrategySwitch:
|
|||
|
// 直播开关
|
|||
|
mFans, mSpe, e = s.GetFansBySwitch(context.TODO(), task.TargetID)
|
|||
|
case model.StrategySpecial:
|
|||
|
// 只获取特别关注
|
|||
|
mFans, mSpe, e = s.dao.Fans(context.TODO(), task.TargetID, model.RelationSpecial)
|
|||
|
case model.StrategyFans:
|
|||
|
// 只获取普通关注
|
|||
|
mFans, mSpe, e = s.dao.Fans(context.TODO(), task.TargetID, model.RelationAttention)
|
|||
|
case model.StrategySwitchSpecial:
|
|||
|
// 只获取特别关注(直播开关中的特别关注)
|
|||
|
mFans, mSpe, e = s.GetFansBySwitchAndSpecial(context.TODO(), task.TargetID)
|
|||
|
default:
|
|||
|
log.Error("[service.mids|GetMids] strategy invalid, type(%s), task(%+v)", tp, task)
|
|||
|
e = fmt.Errorf("[service.mids|GetMids] strategy invalid, type(%s), task(%+v)", tp, task)
|
|||
|
return e
|
|||
|
}
|
|||
|
if e != nil {
|
|||
|
log.Error("[service.mids|GetMids] get mid error(%v), type(%s), task(%+v)", e, tp, task)
|
|||
|
return e
|
|||
|
}
|
|||
|
|
|||
|
// 来源之间求并集,并过滤重复出现的id
|
|||
|
// filter by black list
|
|||
|
mutex.Lock()
|
|||
|
for fansID := range mFans {
|
|||
|
if _, ok := midBlackList[fansID]; !ok {
|
|||
|
fans[fansID] = true
|
|||
|
}
|
|||
|
}
|
|||
|
for fansID := range mSpe {
|
|||
|
if _, ok := midBlackList[fansID]; !ok {
|
|||
|
fansSP[fansID] = true
|
|||
|
}
|
|||
|
}
|
|||
|
mutex.Unlock()
|
|||
|
log.Info("[service.mids|GetMids] get mids by type(%s), task(%+v), common(%d), special(%d)",
|
|||
|
tp, task, len(mFans), len(mSpe))
|
|||
|
return e
|
|||
|
})
|
|||
|
}
|
|||
|
group.Wait()
|
|||
|
|
|||
|
if len(fansSP) > 0 {
|
|||
|
midMap[model.RelationSpecial] = s.midFilter(fansSP, model.StartLiveBusiness, task)
|
|||
|
}
|
|||
|
if len(fans) > 0 {
|
|||
|
midMap[model.RelationAttention] = s.midFilter(fans, model.StartLiveBusiness, task)
|
|||
|
}
|
|||
|
return midMap
|
|||
|
}
|
|||
|
|
|||
|
// GetFansBySwitch 开播提醒,获取开关mids
|
|||
|
func (s *Service) GetFansBySwitch(c context.Context, targetID int64) (fans map[int64]bool, fansSP map[int64]bool, err error) {
|
|||
|
// 获取直播侧开关数据(可能包含普通关注与特别关注)
|
|||
|
m, err := s.dao.GetFansBySwitch(c, targetID)
|
|||
|
if err != nil {
|
|||
|
err = errors.WithStack(err)
|
|||
|
log.Error("[service.mids|GetMidsBySwitch] get switch mids error(%v), targetID(%v)", err, targetID)
|
|||
|
return
|
|||
|
}
|
|||
|
// 区分普通关注与特别关注
|
|||
|
fans, fansSP, err = s.dao.SeparateFans(c, targetID, m)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// GetFansBySwitchAndSpecial 开播提醒,获取开关用户与特别关注用户的交集
|
|||
|
func (s *Service) GetFansBySwitchAndSpecial(c context.Context, targetID int64) (fans map[int64]bool, fansSP map[int64]bool, err error) {
|
|||
|
// 获取直播侧开关数据(可能包含普通关注与特别关注)
|
|||
|
m, err := s.dao.GetFansBySwitch(c, targetID)
|
|||
|
if err != nil {
|
|||
|
err = errors.WithStack(err)
|
|||
|
log.Error("[service.mids|GetMidsBySwitch] get switch mids error(%v), targetID(%v)", err, targetID)
|
|||
|
return
|
|||
|
}
|
|||
|
// 从开关数据中获取到特别关注的部分
|
|||
|
_, fansSP, err = s.dao.SeparateFans(c, targetID, m)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// getSourceByTypes 根据不同的推送策略构造Task.MidSource字段
|
|||
|
func (s *Service) getSourceByTypes(types []string) int {
|
|||
|
var source, midSource int
|
|||
|
for _, t := range types {
|
|||
|
switch t {
|
|||
|
case model.StrategySwitch:
|
|||
|
source = model.TaskSourceSwitch
|
|||
|
case model.StrategySpecial:
|
|||
|
source = model.TaskSourceSpecial
|
|||
|
case model.StrategyFans:
|
|||
|
source = model.TaskSourceFans
|
|||
|
case model.StrategySwitchSpecial:
|
|||
|
source = model.TaskSourceSwitchSpe
|
|||
|
default:
|
|||
|
source = 0
|
|||
|
}
|
|||
|
midSource = midSource ^ source
|
|||
|
}
|
|||
|
return midSource
|
|||
|
}
|