355 lines
9.8 KiB
Go
355 lines
9.8 KiB
Go
package buried
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"go_dreamfactory/comm"
|
|
"go_dreamfactory/lego/base"
|
|
"go_dreamfactory/lego/core"
|
|
"go_dreamfactory/lego/sys/event"
|
|
"go_dreamfactory/lego/sys/log"
|
|
"go_dreamfactory/modules"
|
|
"go_dreamfactory/pb"
|
|
cfg "go_dreamfactory/sys/configure/structs"
|
|
"go_dreamfactory/sys/db"
|
|
"time"
|
|
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
/*
|
|
模块名:用户埋点完成条件触发系统
|
|
模块描述:用户埋点数据中心管理模块
|
|
开发人员:李伟
|
|
*/
|
|
|
|
const moduleName = "埋点统计中心"
|
|
|
|
type Buried struct {
|
|
modules.ModuleBase
|
|
service base.IRPCXService
|
|
configure *configureComp
|
|
modelBuried *modelBuried
|
|
}
|
|
|
|
func NewModule() core.IModule {
|
|
return &Buried{}
|
|
}
|
|
|
|
func (this *Buried) GetType() core.M_Modules {
|
|
return comm.ModuleBuried
|
|
}
|
|
|
|
func (this *Buried) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) {
|
|
err = this.ModuleBase.Init(service, module, options)
|
|
this.service = service.(base.IRPCXService)
|
|
return
|
|
}
|
|
|
|
func (this *Buried) Start() (err error) {
|
|
err = this.ModuleBase.Start()
|
|
this.service.RegisterFunctionName(string(comm.Rpc_ModuleBuriedTrigger), this.Rpc_ModuleBuriedTrigger)
|
|
return
|
|
}
|
|
|
|
//装备组件
|
|
func (this *Buried) OnInstallComp() {
|
|
this.ModuleBase.OnInstallComp()
|
|
|
|
this.configure = this.RegisterComp(new(configureComp)).(*configureComp)
|
|
this.modelBuried = this.RegisterComp(new(modelBuried)).(*modelBuried)
|
|
}
|
|
|
|
// 跨服埋点触发
|
|
func (this *Buried) Rpc_ModuleBuriedTrigger(ctx context.Context, args *pb.Rpc_ModuleBuriedTriggerReq, reply *pb.Rpc_ModuleBuriedTriggerResp) (err error) {
|
|
this.Debug("跨服埋点触发!", log.Field{Key: "uid", Value: args.Uid}, log.Field{Key: "burieds", Value: args.Burieds})
|
|
this.trigger(args.Uid, args.Burieds...)
|
|
return
|
|
}
|
|
|
|
//激活数据采集点
|
|
func (this *Buried) ActiveCondition(uid string, condiIds ...int32) (err error) {
|
|
var (
|
|
conf *cfg.GameBuriedCondiData
|
|
bdatas map[int32]*pb.DBBuried
|
|
chanage []*pb.DBBuried //变化埋点
|
|
)
|
|
|
|
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
|
|
return
|
|
}
|
|
chanage = make([]*pb.DBBuried, 0)
|
|
for _, v := range condiIds {
|
|
if conf, err = this.configure.getburiedcondidata(v); err != nil {
|
|
return
|
|
}
|
|
if bdata, ok := bdatas[conf.Type]; ok {
|
|
if conf.Rtype == rtype2 {
|
|
if item, ok := bdata.Items[v]; !ok {
|
|
bdata.Items[v] = &pb.DBBuriedItem{
|
|
Conid: v,
|
|
State: pb.BuriedItemState_Activated,
|
|
Value: 0,
|
|
Statistics: make([]string, 0),
|
|
Timestamp: time.Now().Unix(),
|
|
}
|
|
chanage = append(chanage, bdata)
|
|
} else {
|
|
item.Value = 0
|
|
item.Statistics = make([]string, 0)
|
|
item.Timestamp = time.Now().Unix()
|
|
item.State = pb.BuriedItemState_Activated
|
|
chanage = append(chanage, bdata)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(chanage) > 0 {
|
|
err = this.modelBuried.updateUserBurieds(uid, chanage)
|
|
}
|
|
return
|
|
}
|
|
|
|
//激活数据采集点
|
|
func (this *Buried) CheckCondition(uid string, condiIds ...int32) (condIds []int32, err error) {
|
|
var (
|
|
bdatas map[int32]*pb.DBBuried
|
|
conf *cfg.GameBuriedCondiData
|
|
)
|
|
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
|
|
return
|
|
}
|
|
condIds = make([]int32, 0)
|
|
for _, v := range condiIds {
|
|
if conf, err = this.configure.getburiedcondidata(v); err != nil {
|
|
return
|
|
}
|
|
if bdata, ok := bdatas[conf.Type]; ok {
|
|
if data, ok := bdata.Items[v]; ok {
|
|
if data.Value >= conf.Value {
|
|
condIds = append(condIds, v)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
//校验同时激活
|
|
func (this *Buried) CheckAndActiveCondition(uid string, condiIds ...int32) (condIds []int32, err error) {
|
|
var (
|
|
bdatas map[int32]*pb.DBBuried
|
|
conf *cfg.GameBuriedCondiData
|
|
chanage []*pb.DBBuried //变化埋点
|
|
)
|
|
|
|
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
|
|
return
|
|
}
|
|
condIds = make([]int32, 0)
|
|
chanage = make([]*pb.DBBuried, 0)
|
|
for _, v := range condiIds {
|
|
if conf, err = this.configure.getburiedcondidata(v); err != nil {
|
|
return
|
|
}
|
|
if bdata, ok := bdatas[conf.Type]; ok {
|
|
if data, ok := bdata.Items[v]; ok {
|
|
if data.Value >= conf.Value {
|
|
condIds = append(condIds, v)
|
|
}
|
|
}
|
|
if conf.Rtype == rtype2 {
|
|
if item, ok := bdata.Items[v]; !ok {
|
|
bdata.Items[v] = &pb.DBBuriedItem{
|
|
Conid: v,
|
|
State: pb.BuriedItemState_Activated,
|
|
Value: 0,
|
|
Statistics: make([]string, 0),
|
|
Timestamp: time.Now().Unix(),
|
|
}
|
|
chanage = append(chanage, bdata)
|
|
} else {
|
|
item.Value = 0
|
|
item.Statistics = make([]string, 0)
|
|
item.Timestamp = time.Now().Unix()
|
|
item.State = pb.BuriedItemState_Activated
|
|
chanage = append(chanage, bdata)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(chanage) > 0 {
|
|
err = this.modelBuried.updateUserBurieds(uid, chanage)
|
|
}
|
|
return
|
|
}
|
|
|
|
//触发埋点
|
|
func (this *Buried) TriggerBuried(uid string, burieds ...*pb.BuriedParam) {
|
|
|
|
if db.IsCross() {
|
|
var (
|
|
stag string
|
|
err error
|
|
)
|
|
if stag, err = comm.UidToSTag(uid); err != nil {
|
|
this.Error("远程触发埋点错误!", log.Field{Key: "uid", Value: uid}, log.Field{Key: "err", Value: err.Error()})
|
|
return
|
|
}
|
|
if _, err = this.service.AcrossClusterRpcGo(
|
|
context.Background(),
|
|
stag,
|
|
comm.Service_Worker,
|
|
string(comm.Rpc_ModuleBuriedTrigger),
|
|
pb.Rpc_ModuleBuriedTriggerReq{
|
|
Burieds: burieds,
|
|
},
|
|
nil); err != nil {
|
|
this.Error("远程触发埋点错误!", log.Field{Key: "burieds", Value: burieds}, log.Field{Key: "err", Value: err.Error()})
|
|
return
|
|
}
|
|
} else {
|
|
this.trigger(uid, burieds...)
|
|
}
|
|
}
|
|
|
|
func (this *Buried) trigger(uid string, burieds ...*pb.BuriedParam) {
|
|
var (
|
|
pass map[*pb.BuriedParam][]*cfg.GameBuriedCondiData = make(map[*pb.BuriedParam][]*cfg.GameBuriedCondiData)
|
|
bconf *cfg.GameBuriedTypeData
|
|
bdatas map[int32]*pb.DBBuried
|
|
change []*pb.DBBuried
|
|
bdata *pb.DBBuried
|
|
ok bool
|
|
complete bool
|
|
completeConIds []int32 //完成id列表
|
|
err error
|
|
)
|
|
this.Debug("触发埋点!", log.Field{Key: "burieds", Value: burieds})
|
|
|
|
lock, _ := this.modelBuried.userlock(uid)
|
|
err = lock.Lock()
|
|
if err != nil {
|
|
this.Error("埋点分布式锁失效 err!", log.Field{Key: "uid", Value: uid}, log.Field{Key: "err", Value: err.Error()})
|
|
return
|
|
}
|
|
defer lock.Unlock()
|
|
|
|
for _, buried := range burieds {
|
|
conds := this.configure.getCondiDatas(buried.TaskType)
|
|
if bconf, err = this.configure.getburiedtypedata(buried.TaskType); err != nil {
|
|
this.Error("未找到目标埋点类型配置", log.Field{Key: "type", Value: buried.TaskType})
|
|
continue
|
|
}
|
|
for _, cond := range conds {
|
|
if checkburied(buried, bconf, cond) { //判断此埋点数据是否有效
|
|
if _, ok := pass[buried]; !ok {
|
|
pass[buried] = make([]*cfg.GameBuriedCondiData, 0)
|
|
}
|
|
pass[buried] = append(pass[buried], cond)
|
|
}
|
|
}
|
|
}
|
|
if len(pass) > 0 {
|
|
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
|
|
return
|
|
}
|
|
}
|
|
completeConIds = make([]int32, 0)
|
|
change = make([]*pb.DBBuried, 0)
|
|
//处理校验通过埋点数据
|
|
for buried, conds := range pass {
|
|
if bconf, err = this.configure.getburiedtypedata(buried.TaskType); err != nil {
|
|
this.Error("未找到目标埋点类型配置", log.Field{Key: "type", Value: buried.TaskType})
|
|
continue
|
|
}
|
|
if bdata, ok = bdatas[int32(buried.TaskType)]; !ok {
|
|
bdatas[int32(buried.TaskType)] = &pb.DBBuried{
|
|
Id: primitive.NewObjectID().Hex(),
|
|
Uid: uid,
|
|
Btype: int32(buried.TaskType),
|
|
Items: make(map[int32]*pb.DBBuriedItem),
|
|
}
|
|
bdata = bdatas[int32(buried.TaskType)]
|
|
}
|
|
for _, cond := range conds {
|
|
if cond.Rtype == rtype1 { //创号后入录
|
|
if complete, err = this.updateAndCheckBuried(bconf, bdata, buried, cond, true); complete {
|
|
completeConIds = append(completeConIds, cond.Id)
|
|
}
|
|
} else if cond.Rtype == rtype2 { //任务接取后才会录入 判断用户埋点数据是否存在 不存在等待任务系统调用接口 ActivationBuried 激活
|
|
if complete, err = this.updateAndCheckBuried(bconf, bdata, buried, cond, false); complete {
|
|
completeConIds = append(completeConIds, cond.Id)
|
|
}
|
|
}
|
|
}
|
|
change = append(change, bdatas[bdata.Btype])
|
|
}
|
|
|
|
if len(change) > 0 { //同步数据
|
|
if err = this.modelBuried.updateUserBurieds(uid, change); err != nil {
|
|
this.Error("更新用户埋点数据错误!", log.Field{Key: "err", Value: err.Error()})
|
|
return
|
|
}
|
|
}
|
|
|
|
//通知事件
|
|
if len(completeConIds) > 0 {
|
|
this.Debug("条件达成通知", log.Field{Key: "ConIds", Value: completeConIds})
|
|
event.TriggerEvent(comm.EventBuriedComplete, uid, completeConIds)
|
|
}
|
|
}
|
|
|
|
//更新并校验完成
|
|
func (this *Buried) updateAndCheckBuried(bconf *cfg.GameBuriedTypeData, bdata *pb.DBBuried, collec *pb.BuriedParam, cond *cfg.GameBuriedCondiData, autoActivated bool) (complete bool, err error) {
|
|
var (
|
|
ok bool
|
|
bitem *pb.DBBuriedItem
|
|
)
|
|
|
|
if bitem, ok = bdata.Items[int32(cond.Id)]; !ok {
|
|
if autoActivated { //自动激活
|
|
bdata.Items[int32(cond.Id)] = &pb.DBBuriedItem{
|
|
Conid: cond.Id,
|
|
State: pb.BuriedItemState_Activated,
|
|
Value: 0,
|
|
Statistics: make([]string, 0),
|
|
Timestamp: time.Now().Unix(),
|
|
}
|
|
bitem = bdata.Items[int32(cond.Id)]
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
|
|
if bitem.State == pb.BuriedItemState_Inactivated || bitem.State == pb.BuriedItemState_Freeze { //未激活和冻结 不在处理
|
|
return
|
|
}
|
|
|
|
switch bconf.Insert { //数据接入方式
|
|
case overlay: //累加数据
|
|
bitem.Value += collec.Value
|
|
case cover:
|
|
bitem.Value = collec.Value
|
|
case statistics:
|
|
ok = true
|
|
for _, v := range bitem.Statistics {
|
|
if v == collec.Statistics { //已统计过
|
|
ok = false
|
|
}
|
|
}
|
|
if ok {
|
|
bitem.Statistics = append(bitem.Statistics, "")
|
|
bitem.Value = int32(len(bitem.Statistics))
|
|
}
|
|
default:
|
|
err = fmt.Errorf("未知的埋点数据处理类型:%d", bconf.Insert)
|
|
return
|
|
}
|
|
|
|
if bitem.Value >= cond.Value { //完成进度
|
|
complete = true
|
|
}
|
|
return
|
|
}
|