319 lines
8.5 KiB
Go
319 lines
8.5 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
"go-common/app/interface/main/dm2/model"
|
||
"go-common/app/interface/main/dm2/model/oplog"
|
||
account "go-common/app/service/main/account/api"
|
||
assmdl "go-common/app/service/main/assist/model/assist"
|
||
"go-common/library/ecode"
|
||
"go-common/library/log"
|
||
)
|
||
|
||
const (
|
||
_assistUpperLimit = 100
|
||
)
|
||
|
||
// isAssist check if the user is assist of upper or not.
|
||
func (s *Service) isAssist(c context.Context, mid, uid int64) (err error) {
|
||
arg := assmdl.ArgAssist{
|
||
Mid: mid,
|
||
AssistMid: uid,
|
||
Type: assmdl.TypeDm,
|
||
RealIP: "",
|
||
}
|
||
res, err := s.assRPC.Assist(c, &arg)
|
||
if err != nil {
|
||
log.Error("s.assRPC.Assist(%v) error(%v)", arg, err)
|
||
return ecode.AccessDenied
|
||
}
|
||
if res.Assist == 1 && res.Allow == 1 {
|
||
return nil
|
||
}
|
||
if res.Assist == 1 && res.Count > _assistUpperLimit {
|
||
return ecode.DMAssistOpToMuch
|
||
}
|
||
return ecode.AccessDenied
|
||
}
|
||
|
||
// isUpper check if the user is upper.
|
||
func (s *Service) isUpper(mid, uid int64) bool {
|
||
return mid == uid
|
||
}
|
||
|
||
// EditDMState change dm state
|
||
// 0:正常、1:删除、10:用户删除、11:举报脚本删除
|
||
func (s *Service) EditDMState(c context.Context, tp int32, mid, oid int64, state int32, dmids []int64, source oplog.Source, operatorType oplog.OperatorType) (err error) {
|
||
var (
|
||
affect, action int64
|
||
)
|
||
if source <= 0 {
|
||
source = oplog.SourceUp
|
||
}
|
||
if operatorType <= 0 {
|
||
operatorType = oplog.OperatorUp
|
||
}
|
||
sub, err := s.subject(c, tp, oid)
|
||
if err != nil {
|
||
return
|
||
}
|
||
switch state {
|
||
case model.StateNormal, model.StateDelete:
|
||
var isAssist bool
|
||
if !s.isUpper(sub.Mid, mid) {
|
||
if err = s.isAssist(c, sub.Mid, mid); err != nil {
|
||
return
|
||
}
|
||
}
|
||
affect, err = s.dao.UpdateDMStat(c, tp, oid, state, dmids)
|
||
if err != nil {
|
||
log.Error("s.dao.UpdateDMStat(oid:%d state:%d dmids:%v) error(%v)", oid, state, dmids, err)
|
||
return
|
||
}
|
||
if affect > 0 {
|
||
if state == model.StateDelete && sub.IsMonitoring() {
|
||
s.oidLock.Lock()
|
||
s.moniOidMap[sub.Oid] = struct{}{}
|
||
s.oidLock.Unlock()
|
||
}
|
||
s.OpLog(c, oid, mid, time.Now().Unix(), int(tp), dmids, "status", "", strconv.FormatInt(int64(state), 10), "更新弹幕状态", source, operatorType)
|
||
if state == model.StateDelete {
|
||
action = assmdl.ActDelete
|
||
affect = -affect
|
||
}
|
||
if sub.Count+affect < 0 {
|
||
affect = -sub.Count
|
||
}
|
||
if _, err = s.dao.IncrSubjectCount(c, tp, oid, affect); err != nil {
|
||
return
|
||
}
|
||
if isAssist {
|
||
for _, dmid := range dmids {
|
||
s.addAssistLog(sub.Mid, mid, oid, action, dmid)
|
||
}
|
||
}
|
||
}
|
||
case model.StateUserDelete:
|
||
affect, err = s.dao.UpdateUserDMStat(c, tp, oid, mid, state, dmids)
|
||
if err != nil {
|
||
log.Error("s.dao.UpdateUserDMStat(mid:%d oid:%d state:%d dmids:%v) error(%v)", mid, oid, state, dmids, err)
|
||
return
|
||
}
|
||
if affect > 0 {
|
||
if sub.IsMonitoring() {
|
||
s.oidLock.Lock()
|
||
s.moniOidMap[sub.Oid] = struct{}{}
|
||
s.oidLock.Unlock()
|
||
}
|
||
s.OpLog(c, oid, mid, time.Now().Unix(), int(tp), dmids, "status", "", fmt.Sprint(state), "更新弹幕状态", source, operatorType)
|
||
affect = -affect
|
||
if sub.Count+affect < 0 {
|
||
affect = -sub.Count
|
||
}
|
||
if _, err = s.dao.IncrSubjectCount(c, tp, oid, affect); err != nil {
|
||
return
|
||
}
|
||
}
|
||
case model.StateScriptDelete:
|
||
affect, err = s.dao.UpdateDMStat(c, tp, oid, state, dmids)
|
||
if err != nil {
|
||
log.Error("s.dao.UpdateDMStat(oid:%d state:%d dmids:%v) error(%v)", oid, state, dmids, err)
|
||
return
|
||
}
|
||
if affect > 0 {
|
||
if sub.IsMonitoring() {
|
||
s.oidLock.Lock()
|
||
s.moniOidMap[sub.Oid] = struct{}{}
|
||
s.oidLock.Unlock()
|
||
}
|
||
s.OpLog(c, oid, mid, time.Now().Unix(), int(tp), dmids, "status", "", fmt.Sprint(state), "更新弹幕状态", source, operatorType)
|
||
affect = -affect
|
||
if sub.Count+affect < 0 {
|
||
affect = -sub.Count
|
||
}
|
||
if _, err = s.dao.IncrSubjectCount(c, tp, oid, affect); err != nil {
|
||
return
|
||
}
|
||
}
|
||
default:
|
||
err = ecode.RequestErr
|
||
}
|
||
return
|
||
}
|
||
|
||
// EditDMPool edit dm pool.
|
||
func (s *Service) EditDMPool(c context.Context, tp int32, mid, oid int64, pool int32, ids []int64, source oplog.Source, operatorType oplog.OperatorType) (err error) {
|
||
var (
|
||
isAssist bool
|
||
affect int64
|
||
)
|
||
if pool != model.PoolNormal && pool != model.PoolSubtitle {
|
||
err = ecode.RequestErr
|
||
return
|
||
}
|
||
// pool 2 dm can't move to other pool
|
||
dmids := make([]int64, 0, len(ids))
|
||
indexs, _, err := s.dao.IndexsByid(c, tp, oid, ids)
|
||
for dmid, index := range indexs {
|
||
if index.Pool != model.PoolSpecial {
|
||
dmids = append(dmids, dmid)
|
||
}
|
||
}
|
||
if len(dmids) <= 0 {
|
||
return
|
||
}
|
||
if source <= 0 {
|
||
source = oplog.SourceUp
|
||
}
|
||
if operatorType <= 0 {
|
||
operatorType = oplog.OperatorUp
|
||
}
|
||
sub, err := s.subject(c, tp, oid)
|
||
if err != nil {
|
||
return
|
||
}
|
||
// maximum batch move count to subtitle pool is 300 when the rank of
|
||
// user is equal or less than 15000
|
||
if pool == model.PoolSubtitle {
|
||
var (
|
||
reply *account.ProfileReply
|
||
)
|
||
if reply, err = s.accountRPC.Profile3(c, &account.MidReq{Mid: mid}); err != nil {
|
||
log.Error("accRPC.Profile3(%v) error(%v)", mid, err)
|
||
return
|
||
}
|
||
if reply.Profile.Rank <= 15000 && int(sub.MoveCnt)+len(dmids) > 300 {
|
||
err = ecode.DMPoolLimit
|
||
return
|
||
}
|
||
}
|
||
if !s.isUpper(sub.Mid, mid) {
|
||
if err = s.isAssist(c, sub.Mid, mid); err != nil {
|
||
return
|
||
}
|
||
}
|
||
if sub.Childpool < pool {
|
||
if _, err = s.dao.UpSubjectPool(c, tp, oid, pool); err != nil {
|
||
return
|
||
}
|
||
}
|
||
if affect, err = s.dao.UpdateDMPool(c, tp, oid, pool, dmids); err != nil {
|
||
log.Error("s.dao.UpdateDMPool(oid:%d pool:%d dmids:%v) error(%v)", oid, pool, dmids, err)
|
||
return
|
||
}
|
||
if affect > 0 {
|
||
if pool == model.PoolNormal {
|
||
s.dao.IncrSubMoveCount(c, sub.Type, sub.Oid, -affect) // NOTE update move_count,ignore error
|
||
} else {
|
||
s.dao.IncrSubMoveCount(c, sub.Type, sub.Oid, affect) // NOTE update move_count,ignore error
|
||
}
|
||
s.OpLog(c, oid, mid, time.Now().Unix(), int(tp), dmids, "pool", "", strconv.FormatInt(int64(pool), 10), "弹幕池变更", source, operatorType)
|
||
}
|
||
if isAssist {
|
||
for _, dmid := range dmids {
|
||
s.addAssistLog(sub.Mid, mid, oid, assmdl.ActProtect, dmid)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
// EditDMAttr update dm attribute.
|
||
func (s *Service) EditDMAttr(c context.Context, tp int32, mid, oid int64, bit uint, value int32, dmids []int64, source oplog.Source, operatorType oplog.OperatorType) (affectIds []int64, err error) {
|
||
var isAssist bool
|
||
affectIds = make([]int64, 0, len(dmids))
|
||
if value != model.AttrNo && value != model.AttrYes {
|
||
err = ecode.RequestErr
|
||
return
|
||
}
|
||
if source <= 0 {
|
||
source = oplog.SourceUp
|
||
}
|
||
if operatorType <= 0 {
|
||
operatorType = oplog.OperatorUp
|
||
}
|
||
sub, err := s.subject(c, tp, oid)
|
||
if err != nil {
|
||
return
|
||
}
|
||
if !s.isUpper(sub.Mid, mid) {
|
||
if err = s.isAssist(c, sub.Mid, mid); err != nil {
|
||
return
|
||
}
|
||
}
|
||
idxMap, _, err := s.dao.IndexsByid(c, tp, oid, dmids)
|
||
if err != nil {
|
||
return
|
||
}
|
||
for dmid, idx := range idxMap {
|
||
if !model.IsDMEditAble(idx.State) {
|
||
continue
|
||
}
|
||
idx.AttrSet(value, bit)
|
||
if _, err = s.dao.UpdateDMAttr(c, tp, oid, dmid, idx.Attr); err != nil {
|
||
continue
|
||
}
|
||
s.OpLog(c, oid, mid, time.Now().Unix(), int(tp), []int64{dmid}, "attribute", "", fmt.Sprintf("bit:%d,value:%d", bit, value), "弹幕保护状态变更", source, operatorType)
|
||
if isAssist {
|
||
s.addAssistLog(sub.Mid, mid, oid, assmdl.ActProtect, dmid)
|
||
}
|
||
affectIds = append(affectIds, dmid)
|
||
}
|
||
return
|
||
}
|
||
|
||
func (s *Service) addAssistLog(mid, assistMid, oid, action, dmid int64) {
|
||
ct, err := s.dao.Content(context.TODO(), oid, dmid)
|
||
if err != nil || ct == nil {
|
||
return
|
||
}
|
||
detail := ct.Msg
|
||
if len([]rune(ct.Msg)) > 50 {
|
||
detail = string([]rune(ct.Msg)[:50])
|
||
}
|
||
arg := &assmdl.ArgAssistLogAdd{
|
||
Mid: mid,
|
||
AssistMid: assistMid,
|
||
Type: assmdl.TypeDm,
|
||
Action: action,
|
||
SubjectID: oid,
|
||
ObjectID: fmt.Sprint(dmid),
|
||
Detail: detail,
|
||
}
|
||
select {
|
||
case s.assistLogChan <- arg:
|
||
default:
|
||
log.Error("assistLogChan is full")
|
||
}
|
||
}
|
||
|
||
func (s *Service) assistLogproc() {
|
||
for arg := range s.assistLogChan {
|
||
if err := s.assRPC.AssistLogAdd(context.TODO(), arg); err != nil {
|
||
log.Error("assRPC.AssistLogAdd(%v) error(%v)", arg, err)
|
||
} else {
|
||
log.Info("assRPC.AssistLogAdd(%v) success", arg)
|
||
}
|
||
}
|
||
}
|
||
|
||
// updateMonitorCnt update mcount of subject.
|
||
func (s *Service) updateMonitorCnt(c context.Context, sub *model.Subject) (err error) {
|
||
var state, mcount int64
|
||
if sub.AttrVal(model.AttrSubMonitorBefore) == model.AttrYes {
|
||
state = int64(model.StateMonitorBefore)
|
||
} else if sub.AttrVal(model.AttrSubMonitorAfter) == model.AttrYes {
|
||
state = int64(model.StateMonitorAfter)
|
||
} else {
|
||
return
|
||
}
|
||
if mcount, err = s.dao.DMCount(c, sub.Type, sub.Oid, []int64{state}); err != nil {
|
||
return
|
||
}
|
||
_, err = s.dao.UpSubjectMCount(c, sub.Type, sub.Oid, mcount)
|
||
return
|
||
}
|