go_dreamfactory/modules/buried/module.go
2023-05-30 21:25:29 +08:00

379 lines
11 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"
)
/*
模块名:用户埋点完成条件触发系统
模块描述:用户埋点数据中心管理模块
开发人员:李伟
*/
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 *pb.DBBuried
chanage bool
)
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
return
}
for _, v := range condiIds {
if conf, err = this.configure.getburiedcondidata(v); err != nil {
return
}
if bdata, ok := bdatas.Items[conf.Type]; ok {
if conf.Rtype == rtype2 {
ok = false
for _, v1 := range bdata.Condi {
if v1.Conid == v {
ok = true
v1.Value = 0
v1.Statistics = make([]string, 0)
v1.Timestamp = time.Now().Unix()
v1.State = pb.BuriedItemState_Activated
break
}
}
if !ok {
bdata.Condi = append(bdata.Condi, &pb.DBBuriedConItem{
Conid: v,
State: pb.BuriedItemState_Activated,
Value: 0,
Statistics: make([]string, 0),
Timestamp: time.Now().Unix(),
})
}
chanage = true
}
}
}
if chanage {
err = this.modelBuried.updateUserBurieds(uid, bdatas)
}
return
}
//激活数据采集点
func (this *Buried) CheckCondition(uid string, condiIds ...int32) (condIds []int32, err error) {
var (
bdatas *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.Items[conf.Type]; ok {
for _, v1 := range bdata.Condi {
if v1.Conid == v {
if v1.Value >= conf.Value {
condIds = append(condIds, v)
}
}
}
}
}
return
}
//校验同时激活
func (this *Buried) CheckAndActiveCondition(uid string, condiIds ...int32) (condIds []int32, err error) {
var (
bdatas *pb.DBBuried
conf *cfg.GameBuriedCondiData
chanage bool //变化埋点
)
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.Items[conf.Type]; ok {
ok = false
for _, v1 := range bdata.Condi {
if v1.Conid == v {
ok = true
if v1.Value >= conf.Value {
condIds = append(condIds, v)
}
if conf.Rtype == rtype2 {
chanage = true
v1.Value = 0
v1.Statistics = make([]string, 0)
v1.Timestamp = time.Now().Unix()
v1.State = pb.BuriedItemState_Activated
}
}
}
if conf.Rtype == rtype2 {
chanage = true
if !ok {
bdata.Condi = append(bdata.Condi, &pb.DBBuriedConItem{
Conid: v,
State: pb.BuriedItemState_Activated,
Value: 0,
Statistics: make([]string, 0),
Timestamp: time.Now().Unix(),
})
}
}
}
}
if chanage {
err = this.modelBuried.updateUserBurieds(uid, bdatas)
}
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{
Uid: uid,
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 *pb.DBBuried
bdata *pb.DBBuriedItem
ok bool
complete bool
change 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)
log.Debug("校验通过埋点条件!", log.Field{Key: "埋点id", Value: buried.TaskType}, log.Field{Key: "条件id", Value: cond.Id})
}
}
}
if len(pass) > 0 {
if bdatas, err = this.modelBuried.getUserBurieds(uid); err != nil {
return
}
}
completeConIds = make([]int32, 0)
//处理校验通过埋点数据
for buried, conds := range pass {
this.Debug("更新埋点数据", log.Field{Key: "埋点类型", Value: buried.TaskType})
if bconf, err = this.configure.getburiedtypedata(buried.TaskType); err != nil {
this.Error("未找到目标埋点类型配置", log.Field{Key: "type", Value: buried.TaskType})
continue
}
if bdata, ok = bdatas.Items[int32(buried.TaskType)]; !ok {
bdatas.Items[int32(buried.TaskType)] = &pb.DBBuriedItem{
Btype: int32(buried.TaskType),
Condi: make([]*pb.DBBuriedConItem, 0),
}
bdata = bdatas.Items[int32(buried.TaskType)]
}
for _, cond := range conds {
this.Debug("更新埋点数据", log.Field{Key: "埋点类型", Value: buried.TaskType}, log.Field{Key: "条件类型", Value: cond.Id})
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)
}
} else {
this.Error("未知的任务类型", log.Field{Key: "埋点类型", Value: buried.TaskType}, log.Field{Key: "条件Id", Value: cond.Id}, log.Field{Key: "条件类型", Value: cond.Rtype})
}
}
change = true
}
if change { //同步数据
if err = this.modelBuried.updateUserBurieds(uid, bdatas); 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.DBBuriedItem, collec *pb.BuriedParam, cond *cfg.GameBuriedCondiData, autoActivated bool) (complete bool, err error) {
var (
ok bool
bitem *pb.DBBuriedConItem
)
for _, v := range bdata.Condi {
if v.Conid == cond.Id {
bitem = v
ok = true
break
}
}
if !ok {
if autoActivated { //自动激活
bitem = &pb.DBBuriedConItem{
Conid: cond.Id,
State: pb.BuriedItemState_Activated,
Value: 0,
Statistics: make([]string, 0),
Timestamp: time.Now().Unix(),
}
bdata.Condi = append(bdata.Condi, bitem)
} else {
this.Debug("任务需激活才可写入!", log.Field{Key: "埋点Id", Value: bdata.Btype}, log.Field{Key: "条件Id", Value: cond.Id})
return
}
}
if bitem.State == pb.BuriedItemState_Inactivated || bitem.State == pb.BuriedItemState_Freeze { //未激活和冻结 不在处理
this.Debug("检测到任务状态不可写入!", log.Field{Key: "埋点Id", Value: bdata.Btype}, log.Field{Key: "条件Id", Value: bitem.Conid}, log.Field{Key: "State", Value: bitem.State})
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)
this.Error("未知的埋点数据处理类型!", log.Field{Key: "Insert", Value: bconf.Insert})
return
}
if bitem.Value >= cond.Value { //完成进度
complete = true
} else {
this.Debug("完成条件未达成!", log.Field{Key: "埋点Id", Value: bdata.Btype}, log.Field{Key: "条件Id", Value: bitem.Conid}, log.Field{Key: "当前进度", Value: bitem.Value}, log.Field{Key: "目标进度", Value: cond.Value})
}
return
}