diff --git a/cmd/v2/ui/tool_term.go b/cmd/v2/ui/tool_term.go index b5338b922..546bfcc2f 100644 --- a/cmd/v2/ui/tool_term.go +++ b/cmd/v2/ui/tool_term.go @@ -114,6 +114,7 @@ func (this *appTerm) LazyInit(obs observer.Observer) error { //excute excuteBtn := &widget.Button{Text: "执行", Icon: theme.ConfirmIcon()} + excuteBtn.TypedKey(&fyne.KeyEvent{Name: fyne.KeyEnter}) excuteBtn.OnTapped = func() { output.Text = "" excuteBtn.Disable() @@ -136,7 +137,7 @@ func (this *appTerm) LazyInit(obs observer.Observer) error { split := container.NewVSplit(container.NewGridWithColumns(2, cmdLast, container.NewBorder(configForm, btns, widget.NewSeparator(), nil)), output) - split.Offset = 0.3 + split.Offset = 0.25 content.Objects = append(content.Objects, split) this.tabItem.Content = content diff --git a/modules/comp_model.go b/modules/comp_model.go index 674150a4c..5b7193ea9 100644 --- a/modules/comp_model.go +++ b/modules/comp_model.go @@ -115,6 +115,11 @@ func (this *MCompModel) GetListObj(uid string, id string, data interface{}) (err return this.DBModel.GetListObj(uid, id, data) } +//批量读取列表中多个数据 +func (this *MCompModel) GetListObjs(uid string, ids []string, data interface{}) (err error) { + return this.DBModel.GetListObjs(uid, ids, data) +} + //删除用户数据 func (this *MCompModel) Del(uid string, opt ...db.DBOption) (err error) { return this.DBModel.Del(uid, opt...) diff --git a/modules/equipment/api_lock.go b/modules/equipment/api_lock.go new file mode 100644 index 000000000..58b1d2768 --- /dev/null +++ b/modules/equipment/api_lock.go @@ -0,0 +1,35 @@ +package equipment + +import ( + "go_dreamfactory/comm" + "go_dreamfactory/pb" + + "google.golang.org/protobuf/proto" +) + +//参数校验 +func (this *apiComp) LockCheck(session comm.IUserSession, req *pb.EquipmentLockReq) (code pb.ErrorCode) { + if req.EquipmentId == "" { + code = pb.ErrorCode_ReqParameterError + } + return +} + +///获取用户装备列表 +func (this *apiComp) Lock(session comm.IUserSession, req *pb.EquipmentLockReq) (code pb.ErrorCode, data proto.Message) { + var ( + err error + equipment *pb.DB_Equipment + ) + if code = this.LockCheck(session, req); code != pb.ErrorCode_Success { + return + } + if equipment, err = this.module.modelEquipment.QueryUserEquipmentsById(session.GetUserId(), req.EquipmentId); err != nil { + this.module.Errorf("Equip_Check err:%v", err) + code = pb.ErrorCode_EquipmentOnFoundEquipment + return + } + equipment.Lock = req.IsLock + session.SendMsg(string(this.module.GetType()), "getlist", &pb.EquipmentLockResp{IsSucc: true, EquipmentId: req.EquipmentId, IsLock: req.IsLock}) + return +} diff --git a/modules/equipment/api_sellI.go b/modules/equipment/api_sellI.go new file mode 100644 index 000000000..7d90d7887 --- /dev/null +++ b/modules/equipment/api_sellI.go @@ -0,0 +1,62 @@ +package equipment + +import ( + "go_dreamfactory/comm" + "go_dreamfactory/pb" + cfg "go_dreamfactory/sys/configure/structs" + + "google.golang.org/protobuf/proto" +) + +//参数校验 +func (this *apiComp) SellCheck(session comm.IUserSession, req *pb.EquipmentSellReq) (code pb.ErrorCode) { + if req.EquipIds == nil || len(req.EquipIds) == 0 { + code = pb.ErrorCode_ReqParameterError + } + return +} + +//出售 +func (this *apiComp) Sell(session comm.IUserSession, req *pb.EquipmentSellReq) (code pb.ErrorCode, data proto.Message) { + var ( + err error + equipments []*pb.DB_Equipment + confs []*cfg.GameEquipData + sale []*cfg.Gameatn + ) + if code = this.SellCheck(session, req); code != pb.ErrorCode_Success { + return + } + if equipments, err = this.module.modelEquipment.QueryUserEquipmentsByIds(session.GetUserId(), req.EquipIds); err != nil { + code = pb.ErrorCode_ReqParameterError + return + } + confs = make([]*cfg.GameEquipData, len(equipments)) + for i, v := range equipments { + if v.HeroId != "" || v.Lock { + code = pb.ErrorCode_EquipmentNoCanSell + this.module.Errorf("NoCanSell %v", v) + return + } + if confs[i], err = this.module.configure.GetEquipmentConfigureById(v.CId); err != nil { + this.module.Errorln(err) + code = pb.ErrorCode_EquipmentOnFoundEquipment + return + } + } + + sale = make([]*cfg.Gameatn, 0) + for _, v := range confs { + for _, s := range v.Sale { + sale = append(sale, s) + } + } + if code = this.module.DispenseRes(session, sale, true); code != pb.ErrorCode_Success { + return + } + if code = this.module.DelEquipments(session, req.EquipIds, true); code != pb.ErrorCode_Success { + return + } + session.SendMsg(string(this.module.GetType()), "sell", &pb.ItemsUseItemResp{Issucc: true}) + return +} diff --git a/modules/equipment/configure.go b/modules/equipment/configure.go index 1a80671d7..907882b3f 100644 --- a/modules/equipment/configure.go +++ b/modules/equipment/configure.go @@ -70,6 +70,30 @@ func (this *configureComp) GetEquipmentConfigureById(equipmentId string) (config return } +//获取装备配置数据 +func (this *configureComp) GetEquipmentConfigureByIds(equipmentId []string) (configure []*cfg.GameEquipData, err error) { + var ( + t interface{} + c *cfg.GameEquipData + ok bool + ) + if t, err = this.GetConfigure(game_equip); err != nil { + this.module.Errorf("err:%v", err) + return + } else { + + configure = make([]*cfg.GameEquipData, len(equipmentId)) + + for i, v := range equipmentId { + if c, ok = t.(*cfg.GameEquip).GetDataMap()[v]; ok { + configure[i] = c + return + } + } + } + return +} + //获取装备属性表 func (this *configureComp) GetEquipmentAttrlibraryConfigure() (configure *cfg.GameEquipAttrlibrary, err error) { var ( diff --git a/modules/equipment/modelEquipment.go b/modules/equipment/modelEquipment.go index 7cfa99372..35430e9c5 100644 --- a/modules/equipment/modelEquipment.go +++ b/modules/equipment/modelEquipment.go @@ -40,6 +40,13 @@ func (this *modelEquipmentComp) QueryUserEquipmentsById(uId, id string) (equipme return } +//查询用户装备数据 +func (this *modelEquipmentComp) QueryUserEquipmentsByIds(uId string, ids []string) (equipments []*pb.DB_Equipment, err error) { + equipments = []*pb.DB_Equipment{} + err = this.GetListObjs(uId, ids, &equipments) + return +} + ///查询用户的武器背包 func (this *modelEquipmentComp) QueryUserEquipments(uId string) (equipments []*pb.DB_Equipment, err error) { equipments = make([]*pb.DB_Equipment, 0) @@ -123,6 +130,23 @@ func (this *modelEquipmentComp) AddEquipments(uId string, cIds map[string]uint32 return } +//删除装备 +func (this *modelEquipmentComp) DelEquipments(uId string, eIds []string) (change []*pb.DB_Equipment, err error) { + change = make([]*pb.DB_Equipment, 0) + if err = this.DelListlds(uId, eIds...); err != nil { + this.module.Errorln(err) + return + } + for _, v := range eIds { + change = append(change, &pb.DB_Equipment{ + Id: v, + UId: uId, + OverlayNum: 0, + }) + } + return +} + //更新武器挂载信息 func (this *modelEquipmentComp) UpdateByHeroId(uid string, equipments ...*pb.DB_Equipment) (err error) { for _, v := range equipments { diff --git a/modules/equipment/module.go b/modules/equipment/module.go index c2c2901e9..fb4c4a11c 100644 --- a/modules/equipment/module.go +++ b/modules/equipment/module.go @@ -104,11 +104,26 @@ func (this *Equipment) AddNewEquipments(source *comm.ModuleCallSource, session c return } +//删除武器 +func (this *Equipment) DelEquipments(session comm.IUserSession, equipIds []string, bPush bool) (code pb.ErrorCode) { + var ( + err error + change []*pb.DB_Equipment + ) + if change, err = this.modelEquipment.DelEquipments(session.GetUserId(), equipIds); err != nil { + this.Errorf("err%v", err) + code = pb.ErrorCode_SystemError + return + } + if len(change) > 0 && bPush { + this.equipmentsChangePush(session, change) + } + return +} + //Evens-------------------------------------------------------------------------------------------------------------------------------- //推送道具变化消息 func (this *Equipment) equipmentsChangePush(session comm.IUserSession, items []*pb.DB_Equipment) (err error) { - session.SendMsg(string(this.GetType()), "change", &pb.EquipmentChangePush{Equipments: items}) - return } diff --git a/modules/martialhall/modelMartialhall.go b/modules/martialhall/modelMartialhall.go index c170ff503..6ce8c06c3 100644 --- a/modules/martialhall/modelMartialhall.go +++ b/modules/martialhall/modelMartialhall.go @@ -41,7 +41,7 @@ func (this *modelMartialhall) queryUserMartialhall(uid string) (result *pb.DBMar Id: primitive.NewObjectID().Hex(), Uid: uid, Lv: 1, - Pillar1: &pb.DBPillar{Index: 1}, + Pillar1: &pb.DBPillar{Index: 1, Isunlock: true}, Pillar2: &pb.DBPillar{Index: 2}, Pillar3: &pb.DBPillar{Index: 3}, Pillar4: &pb.DBPillar{Index: 4}, diff --git a/modules/task/module.go b/modules/task/module.go index bf1bf6c4d..51850db0b 100644 --- a/modules/task/module.go +++ b/modules/task/module.go @@ -52,8 +52,10 @@ func (this *ModuleTask) Start() (err error) { } //初始化日常、周常、成就 -func (this *ModuleTask) InitTask(uid string, taskTag comm.TaskTag) { - this.modelTask.initTask(uid, taskTag) +func (this *ModuleTask) InitTaskAll(uid string) { + this.modelTask.initTask(uid, comm.TASK_DAILY) + this.modelTask.initTask(uid, comm.TASK_WEEKLY) + this.modelTask.initTask(uid, comm.TASK_ACHIEVE) this.modelTaskActive.initActiveReward(uid) } @@ -96,7 +98,7 @@ func (this *ModuleTask) ResetTask(uid string, taskTag comm.TaskTag) { this.resetActive(uid, taskTag) this.modelTask.clearTask(uid, taskTag) this.modelTaskActive.clearTask(uid, taskTag) - this.InitTask(uid, taskTag) + this.InitTaskAll(uid) } //任务处理 diff --git a/pb/equipment_db.pb.go b/pb/equipment_db.pb.go index d6de33c94..e2840761e 100644 --- a/pb/equipment_db.pb.go +++ b/pb/equipment_db.pb.go @@ -116,6 +116,7 @@ type DB_Equipment struct { AdverbEntry []*EquipmentAttributeEntry `protobuf:"bytes,9,rep,name=adverbEntry,proto3" json:"adverbEntry" bson:"adverbEntry"` //装备副词条 OverlayNum uint32 `protobuf:"varint,10,opt,name=overlayNum,proto3" json:"overlayNum" bson:"overlayNum"` //叠加数量 IsInitialState bool `protobuf:"varint,11,opt,name=isInitialState,proto3" json:"isInitialState" bson:"isInitialState"` //是否初始状态 + Lock bool `protobuf:"varint,12,opt,name=lock,proto3" json:"lock" bson:"lock"` //是否锁 } func (x *DB_Equipment) Reset() { @@ -220,6 +221,13 @@ func (x *DB_Equipment) GetIsInitialState() bool { return false } +func (x *DB_Equipment) GetLock() bool { + if x != nil { + return x.Lock + } + return false +} + var File_equipment_equipment_db_proto protoreflect.FileDescriptor var file_equipment_equipment_db_proto_rawDesc = []byte{ @@ -233,7 +241,7 @@ var file_equipment_equipment_db_proto_rawDesc = []byte{ 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x41, 0x74, 0x74, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x4c, 0x76, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x4c, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc8, 0x02, 0x0a, 0x0c, 0x44, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xdc, 0x02, 0x0a, 0x0c, 0x44, 0x42, 0x5f, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x49, 0x64, 0x12, 0x10, 0x0a, @@ -254,8 +262,9 @@ var file_equipment_equipment_db_proto_rawDesc = []byte{ 0x0d, 0x52, 0x0a, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x4e, 0x75, 0x6d, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x04, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pb/equipment_msg.pb.go b/pb/equipment_msg.pb.go index 30d2aea37..a1eae50ea 100644 --- a/pb/equipment_msg.pb.go +++ b/pb/equipment_msg.pb.go @@ -307,14 +307,15 @@ func (x *EquipmentUpgradeReq) GetEquipmentId() string { return "" } -//装备升级 回应 +//装备升级 回应 由于装备可以叠加 升级后会创建一个新的装备出来 +//所以可能影响两个装备 type EquipmentUpgradeResp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields IsSucc bool `protobuf:"varint,1,opt,name=IsSucc,proto3" json:"IsSucc"` - Equipment []*DB_Equipment `protobuf:"bytes,2,rep,name=Equipment,proto3" json:"Equipment"` //由于装备可以叠加 升级后会创建一个新的装备出来 所以可能影响两个装备 + Equipment []*DB_Equipment `protobuf:"bytes,2,rep,name=Equipment,proto3" json:"Equipment"` } func (x *EquipmentUpgradeResp) Reset() { @@ -363,6 +364,222 @@ func (x *EquipmentUpgradeResp) GetEquipment() []*DB_Equipment { return nil } +//出售道具请求sailitem +type EquipmentLockReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EquipmentId string `protobuf:"bytes,1,opt,name=EquipmentId,proto3" json:"EquipmentId"` //装备的唯一id + IsLock bool `protobuf:"varint,2,opt,name=IsLock,proto3" json:"IsLock"` //是否锁 +} + +func (x *EquipmentLockReq) Reset() { + *x = EquipmentLockReq{} + if protoimpl.UnsafeEnabled { + mi := &file_equipment_equipment_msg_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EquipmentLockReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EquipmentLockReq) ProtoMessage() {} + +func (x *EquipmentLockReq) ProtoReflect() protoreflect.Message { + mi := &file_equipment_equipment_msg_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EquipmentLockReq.ProtoReflect.Descriptor instead. +func (*EquipmentLockReq) Descriptor() ([]byte, []int) { + return file_equipment_equipment_msg_proto_rawDescGZIP(), []int{7} +} + +func (x *EquipmentLockReq) GetEquipmentId() string { + if x != nil { + return x.EquipmentId + } + return "" +} + +func (x *EquipmentLockReq) GetIsLock() bool { + if x != nil { + return x.IsLock + } + return false +} + +//出售道具请求 回应 +type EquipmentLockResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IsSucc bool `protobuf:"varint,1,opt,name=IsSucc,proto3" json:"IsSucc"` + EquipmentId string `protobuf:"bytes,2,opt,name=EquipmentId,proto3" json:"EquipmentId"` + IsLock bool `protobuf:"varint,3,opt,name=IsLock,proto3" json:"IsLock"` +} + +func (x *EquipmentLockResp) Reset() { + *x = EquipmentLockResp{} + if protoimpl.UnsafeEnabled { + mi := &file_equipment_equipment_msg_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EquipmentLockResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EquipmentLockResp) ProtoMessage() {} + +func (x *EquipmentLockResp) ProtoReflect() protoreflect.Message { + mi := &file_equipment_equipment_msg_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EquipmentLockResp.ProtoReflect.Descriptor instead. +func (*EquipmentLockResp) Descriptor() ([]byte, []int) { + return file_equipment_equipment_msg_proto_rawDescGZIP(), []int{8} +} + +func (x *EquipmentLockResp) GetIsSucc() bool { + if x != nil { + return x.IsSucc + } + return false +} + +func (x *EquipmentLockResp) GetEquipmentId() string { + if x != nil { + return x.EquipmentId + } + return "" +} + +func (x *EquipmentLockResp) GetIsLock() bool { + if x != nil { + return x.IsLock + } + return false +} + +//出售道具请求sailitem +type EquipmentSellReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EquipIds []string `protobuf:"bytes,1,rep,name=EquipIds,proto3" json:"EquipIds"` +} + +func (x *EquipmentSellReq) Reset() { + *x = EquipmentSellReq{} + if protoimpl.UnsafeEnabled { + mi := &file_equipment_equipment_msg_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EquipmentSellReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EquipmentSellReq) ProtoMessage() {} + +func (x *EquipmentSellReq) ProtoReflect() protoreflect.Message { + mi := &file_equipment_equipment_msg_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EquipmentSellReq.ProtoReflect.Descriptor instead. +func (*EquipmentSellReq) Descriptor() ([]byte, []int) { + return file_equipment_equipment_msg_proto_rawDescGZIP(), []int{9} +} + +func (x *EquipmentSellReq) GetEquipIds() []string { + if x != nil { + return x.EquipIds + } + return nil +} + +//出售道具请求 回应 +type EquipmentSellResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IsSucc bool `protobuf:"varint,1,opt,name=IsSucc,proto3" json:"IsSucc"` +} + +func (x *EquipmentSellResp) Reset() { + *x = EquipmentSellResp{} + if protoimpl.UnsafeEnabled { + mi := &file_equipment_equipment_msg_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EquipmentSellResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EquipmentSellResp) ProtoMessage() {} + +func (x *EquipmentSellResp) ProtoReflect() protoreflect.Message { + mi := &file_equipment_equipment_msg_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EquipmentSellResp.ProtoReflect.Descriptor instead. +func (*EquipmentSellResp) Descriptor() ([]byte, []int) { + return file_equipment_equipment_msg_proto_rawDescGZIP(), []int{10} +} + +func (x *EquipmentSellResp) GetIsSucc() bool { + if x != nil { + return x.IsSucc + } + return false +} + var File_equipment_equipment_msg_proto protoreflect.FileDescriptor var file_equipment_equipment_msg_proto_rawDesc = []byte{ @@ -399,8 +616,25 @@ var file_equipment_equipment_msg_proto_rawDesc = []byte{ 0x49, 0x73, 0x53, 0x75, 0x63, 0x63, 0x12, 0x2b, 0x0a, 0x09, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x44, 0x42, 0x5f, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, - 0x65, 0x6e, 0x74, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x65, 0x6e, 0x74, 0x22, 0x4c, 0x0a, 0x10, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, + 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x45, 0x71, 0x75, 0x69, 0x70, + 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x45, 0x71, + 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x4c, + 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x73, 0x4c, 0x6f, 0x63, + 0x6b, 0x22, 0x65, 0x0a, 0x11, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x53, 0x75, 0x63, 0x63, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x73, 0x53, 0x75, 0x63, 0x63, 0x12, 0x20, + 0x0a, 0x0b, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x45, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x4c, 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x49, 0x73, 0x4c, 0x6f, 0x63, 0x6b, 0x22, 0x2e, 0x0a, 0x10, 0x45, 0x71, 0x75, 0x69, + 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, + 0x45, 0x71, 0x75, 0x69, 0x70, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x45, 0x71, 0x75, 0x69, 0x70, 0x49, 0x64, 0x73, 0x22, 0x2b, 0x0a, 0x11, 0x45, 0x71, 0x75, 0x69, + 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, + 0x06, 0x49, 0x73, 0x53, 0x75, 0x63, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, + 0x73, 0x53, 0x75, 0x63, 0x63, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -415,7 +649,7 @@ func file_equipment_equipment_msg_proto_rawDescGZIP() []byte { return file_equipment_equipment_msg_proto_rawDescData } -var file_equipment_equipment_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_equipment_equipment_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_equipment_equipment_msg_proto_goTypes = []interface{}{ (*EquipmentGetListReq)(nil), // 0: EquipmentGetListReq (*EquipmentGetListResp)(nil), // 1: EquipmentGetListResp @@ -424,18 +658,22 @@ var file_equipment_equipment_msg_proto_goTypes = []interface{}{ (*EquipmentEquipResp)(nil), // 4: EquipmentEquipResp (*EquipmentUpgradeReq)(nil), // 5: EquipmentUpgradeReq (*EquipmentUpgradeResp)(nil), // 6: EquipmentUpgradeResp - (*DB_Equipment)(nil), // 7: DB_Equipment + (*EquipmentLockReq)(nil), // 7: EquipmentLockReq + (*EquipmentLockResp)(nil), // 8: EquipmentLockResp + (*EquipmentSellReq)(nil), // 9: EquipmentSellReq + (*EquipmentSellResp)(nil), // 10: EquipmentSellResp + (*DB_Equipment)(nil), // 11: DB_Equipment } var file_equipment_equipment_msg_proto_depIdxs = []int32{ - 7, // 0: EquipmentGetListResp.Equipments:type_name -> DB_Equipment - 7, // 1: EquipmentChangePush.Equipments:type_name -> DB_Equipment - 7, // 2: EquipmentEquipResp.Equipments:type_name -> DB_Equipment - 7, // 3: EquipmentUpgradeResp.Equipment:type_name -> DB_Equipment - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 11, // 0: EquipmentGetListResp.Equipments:type_name -> DB_Equipment + 11, // 1: EquipmentChangePush.Equipments:type_name -> DB_Equipment + 11, // 2: EquipmentEquipResp.Equipments:type_name -> DB_Equipment + 11, // 3: EquipmentUpgradeResp.Equipment:type_name -> DB_Equipment + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_equipment_equipment_msg_proto_init() } @@ -529,6 +767,54 @@ func file_equipment_equipment_msg_proto_init() { return nil } } + file_equipment_equipment_msg_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EquipmentLockReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_equipment_equipment_msg_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EquipmentLockResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_equipment_equipment_msg_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EquipmentSellReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_equipment_equipment_msg_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EquipmentSellResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -536,7 +822,7 @@ func file_equipment_equipment_msg_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_equipment_equipment_msg_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/sys/db/dbconn.go b/sys/db/dbconn.go index 035cd8418..7542d1481 100644 --- a/sys/db/dbconn.go +++ b/sys/db/dbconn.go @@ -8,6 +8,7 @@ import ( "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" lgredis "go_dreamfactory/lego/sys/redis" + "go_dreamfactory/lego/sys/redis/pipe" "go_dreamfactory/lego/utils/codec" "go_dreamfactory/lego/utils/codec/codecore" "go_dreamfactory/lego/utils/codec/json" @@ -631,6 +632,118 @@ func (this *DBModel) GetListObj(uid string, id string, data interface{}) (err er return } +//读取列表数据中单个数据 +func (this *DBModel) GetListObjs(uid string, ids []string, data interface{}) (err error) { + var ( + dtype reflect2.Type + dkind reflect.Kind + sType reflect2.Type + sliceType *reflect2.UnsafeSliceType + sliceelemType reflect2.Type + decoder codecore.IDecoderMapJson + encoder codecore.IEncoderMapJson + dptr unsafe.Pointer + elemPtr unsafe.Pointer + n int + ok bool + keys map[string]string = make(map[string]string) + tempdata map[string]string + onfound []string = make([]string, 0, len(ids)) + pipe *pipe.RedisPipe = this.Redis.RedisPipe(context.TODO()) + result []*redis.StringStringMapCmd = make([]*redis.StringStringMapCmd, len(ids)) + c *mongo.Cursor + ) + dptr = reflect2.PtrOf(data) + dtype = reflect2.TypeOf(data) + dkind = dtype.Kind() + if dkind != reflect.Ptr { + err = fmt.Errorf("MCompModel: GetList(non-pointer %T)", data) + return + } + sType = dtype.(*reflect2.UnsafePtrType).Elem() + if sType.Kind() != reflect.Slice { + err = fmt.Errorf("MCompModel: GetList(data no slice %T)", data) + return + } + sliceType = sType.(*reflect2.UnsafeSliceType) + sliceelemType = sliceType.Elem() + if sliceelemType.Kind() != reflect.Ptr { + err = fmt.Errorf("MCompModel: GetList(sliceelemType non-pointer %T)", data) + return + } + if decoder, ok = codec.DecoderOf(sliceelemType, defconf).(codecore.IDecoderMapJson); !ok { + err = fmt.Errorf("MCompModel: GetList(data not support MarshalMapJson %T)", data) + return + } + sliceelemType = sliceelemType.(*reflect2.UnsafePtrType).Elem() + for i, v := range ids { + result[i] = pipe.HGetAllToMapString(this.ukeylist(uid, v)) + } + if _, err = pipe.Exec(); err == nil { + for i, v := range result { + if tempdata, err = v.Result(); err == nil { + sliceType.UnsafeGrow(dptr, n+1) + elemPtr = sliceType.UnsafeGetIndex(dptr, n) + if *((*unsafe.Pointer)(elemPtr)) == nil { + newPtr := sliceelemType.UnsafeNew() + if err = decoder.DecodeForMapJson(newPtr, json.GetReader([]byte{}), tempdata); err != nil { + log.Errorf("err:%v", err) + return + } + *((*unsafe.Pointer)(elemPtr)) = newPtr + } else { + decoder.DecodeForMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetReader([]byte{}), tempdata) + } + n++ + } else { + onfound = append(onfound, ids[i]) + } + } + } else { + onfound = ids + } + + if err == lgredis.RedisNil { + if c, err = this.DB.Find(core.SqlTable(this.TableName), bson.M{"uid": uid}); err != nil { + return err + } else { + pipe := this.Redis.RedisPipe(context.TODO()) + for c.Next(context.Background()) { + _id := c.Current.Lookup("_id").StringValue() + sliceType.UnsafeGrow(dptr, n+1) + elemPtr = sliceType.UnsafeGetIndex(dptr, n) + if *((*unsafe.Pointer)(elemPtr)) == nil { + newPtr := sliceelemType.UnsafeNew() + *((*unsafe.Pointer)(elemPtr)) = newPtr + } + elem := sliceType.GetIndex(data, n) + if err = c.Decode(elem); err != nil { + return + } + if tempdata, err = encoder.EncodeToMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetWriter()); err != nil { + return + } + key := this.ukeylist(uid, _id) + pipe.HMSetForMap(key, tempdata) + keys[_id] = key + n++ + } + if len(keys) > 0 { + pipe.HMSetForMap(this.ukey(uid), keys) + _, err = pipe.Exec() + } + } + } + if this.Expired > 0 { + childs := make(map[string]struct{}, len(keys)) + for _, v := range keys { + childs[v] = struct{}{} + } + UpDateModelExpired(this.ukey(uid), childs, this.Expired) + } + return +} + //删除用户数据 func (this *DBModel) Del(uid string, opt ...DBOption) (err error) { err = this.Redis.Delete(this.ukey(uid)) diff --git a/sys/wordfilter/core.go b/sys/wordfilter/core.go new file mode 100644 index 000000000..bb66d5d11 --- /dev/null +++ b/sys/wordfilter/core.go @@ -0,0 +1,119 @@ +package wordfilter + +import "io" + +/* +系统:单词守卫 +描述:DFA 算法实践敏感词过滤 敏感词 过滤 验证 替换 +*/ + +type ( + ISys interface { + //加载文件 + LoadWordDict(path string) error + //加载网络数据 + LoadNetWordDict(url string) error + ///加载 + Load(rd io.Reader) error + ///添加敏感词 + AddWord(words ...string) + ///删除敏感词 + DelWord(words ...string) + ///过滤敏感词 + Filter(text string) string + ///和谐敏感词 + Replace(text string, repl rune) string + ///检测敏感词 + FindIn(text string) (bool, string) + ///找到所有匹配词 + FindAll(text string) []string + ///检测字符串是否合法 + Validate(text string) (bool, string) + ///去除空格等噪音 + RemoveNoise(text string) string + ///更新去噪模式 + UpdateNoisePattern(pattern string) + } +) + +var ( + defsys ISys +) + +func OnInit(config map[string]interface{}, opt ...Option) (err error) { + var option *Options + if option, err = newOptions(config, opt...); err != nil { + return + } + defsys, err = newSys(option) + return +} + +func NewSys(opt ...Option) (sys ISys, err error) { + var option *Options + if option, err = newOptionsByOption(opt...); err != nil { + return + } + sys, err = newSys(option) + return +} + +//加载文件 +func LoadWordDict(path string) error { + return defsys.LoadWordDict(path) +} + +//加载网络数据 +func LoadNetWordDict(url string) error { + return defsys.LoadNetWordDict(url) +} + +///加载 +func Load(rd io.Reader) error { + return defsys.Load(rd) +} + +///添加敏感词 +func AddWord(words ...string) { + defsys.AddWord(words...) +} + +///删除敏感词 +func DelWord(words ...string) { + defsys.DelWord(words...) +} + +///过滤敏感词 +func Filter(text string) string { + return defsys.Filter(text) +} + +///和谐敏感词 +func Replace(text string, repl rune) string { + return defsys.Replace(text, repl) +} + +///检测敏感词 +func FindIn(text string) (bool, string) { + return defsys.FindIn(text) +} + +///找到所有匹配词 +func FindAll(text string) []string { + return defsys.FindAll(text) +} + +///检测字符串是否合法 +func Validate(text string) (bool, string) { + return defsys.Validate(text) +} + +///去除空格等噪音 +func RemoveNoise(text string) string { + return defsys.RemoveNoise(text) +} + +///更新去噪模式 +func UpdateNoisePattern(pattern string) { + defsys.UpdateNoisePattern(pattern) +} diff --git a/sys/wordfilter/options.go b/sys/wordfilter/options.go new file mode 100644 index 000000000..e31639823 --- /dev/null +++ b/sys/wordfilter/options.go @@ -0,0 +1,53 @@ +package wordfilter + +import ( + "errors" + + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/lego/utils/mapstructure" +) + +type Option func(*Options) +type Options struct { + Debug bool //日志是否开启 + Log log.Ilogf +} + +func SetDebug(v bool) Option { + return func(o *Options) { + o.Debug = v + } +} + +func SetLog(v log.Ilogf) Option { + return func(o *Options) { + o.Log = v + } +} + +func newOptions(config map[string]interface{}, opts ...Option) (options *Options, err error) { + options = &Options{} + if config != nil { + mapstructure.Decode(config, &options) + } + for _, o := range opts { + o(options) + } + + if options.Log = log.NewTurnlog(options.Debug, log.Clone("sys.Blockcache", 2)); options.Log == nil { + err = errors.New("log is nil") + } + + return +} + +func newOptionsByOption(opts ...Option) (options *Options, err error) { + options = &Options{} + for _, o := range opts { + o(options) + } + if options.Log = log.NewTurnlog(options.Debug, log.Clone("sys.Blockcache", 2)); options.Log == nil { + err = errors.New("log is nil") + } + return +} diff --git a/sys/wordfilter/sys.go b/sys/wordfilter/sys.go new file mode 100644 index 000000000..c83a87925 --- /dev/null +++ b/sys/wordfilter/sys.go @@ -0,0 +1,113 @@ +package wordfilter + +import ( + "bufio" + "io" + "net/http" + "os" + "regexp" + "time" +) + +func newSys(options *Options) (sys *Sys, err error) { + sys = &Sys{ + options: options, + trie: NewTrie(), + noise: regexp.MustCompile(`[\|\s&%$@*]+`), + } + return +} + +type Sys struct { + options *Options + trie *Trie + noise *regexp.Regexp +} + +// UpdateNoisePattern 更新去噪模式 +func (Sys *Sys) UpdateNoisePattern(pattern string) { + Sys.noise = regexp.MustCompile(pattern) +} + +// LoadWordDict 加载敏感词字典 +func (Sys *Sys) LoadWordDict(path string) error { + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + return Sys.Load(f) +} + +// LoadNetWordDict 加载网络敏感词字典 +func (Sys *Sys) LoadNetWordDict(url string) error { + c := http.Client{ + Timeout: 5 * time.Second, + } + rsp, err := c.Get(url) + if err != nil { + return err + } + defer rsp.Body.Close() + + return Sys.Load(rsp.Body) +} + +// Load common method to add words +func (Sys *Sys) Load(rd io.Reader) error { + buf := bufio.NewReader(rd) + for { + line, _, err := buf.ReadLine() + if err != nil { + if err != io.EOF { + return err + } + break + } + Sys.trie.Add(string(line)) + } + return nil +} + +// AddWord 添加敏感词 +func (Sys *Sys) AddWord(words ...string) { + Sys.trie.Add(words...) +} + +// DelWord 删除敏感词 +func (Sys *Sys) DelWord(words ...string) { + Sys.trie.Del(words...) +} + +// Sys 过滤敏感词 +func (Sys *Sys) Filter(text string) string { + return Sys.trie.Filter(text) +} + +// Replace 和谐敏感词 +func (Sys *Sys) Replace(text string, repl rune) string { + return Sys.trie.Replace(text, repl) +} + +// FindIn 检测敏感词 +func (Sys *Sys) FindIn(text string) (bool, string) { + text = Sys.RemoveNoise(text) + return Sys.trie.FindIn(text) +} + +// FindAll 找到所有匹配词 +func (Sys *Sys) FindAll(text string) []string { + return Sys.trie.FindAll(text) +} + +// Validate 检测字符串是否合法 +func (Sys *Sys) Validate(text string) (bool, string) { + text = Sys.RemoveNoise(text) + return Sys.trie.Validate(text) +} + +// RemoveNoise 去除空格等噪音 +func (Sys *Sys) RemoveNoise(text string) string { + return Sys.noise.ReplaceAllString(text, "") +} diff --git a/sys/wordfilter/trie.go b/sys/wordfilter/trie.go new file mode 100644 index 000000000..fb3e61c49 --- /dev/null +++ b/sys/wordfilter/trie.go @@ -0,0 +1,272 @@ +package wordfilter + +// Node Trie树上的一个节点. +type Node struct { + isRootNode bool + isPathEnd bool + Character rune + Children map[rune]*Node +} + +// Trie 短语组成的Trie树. +type Trie struct { + Root *Node +} + +// NewTrie 新建一棵Trie +func NewTrie() *Trie { + return &Trie{ + Root: NewRootNode(0), + } +} + +// Add 添加若干个词 +func (tree *Trie) Add(words ...string) { + for _, word := range words { + tree.add(word) + } +} + +func (tree *Trie) add(word string) { + var current = tree.Root + var runes = []rune(word) + for position := 0; position < len(runes); position++ { + r := runes[position] + if next, ok := current.Children[r]; ok { + current = next + } else { + newNode := NewNode(r) + current.Children[r] = newNode + current = newNode + } + if position == len(runes)-1 { + current.isPathEnd = true + } + } +} + +func (tree *Trie) Del(words ...string) { + for _, word := range words { + tree.del(word) + } +} + +func (tree *Trie) del(word string) { + var current = tree.Root + var runes = []rune(word) + for position := 0; position < len(runes); position++ { + r := runes[position] + if next, ok := current.Children[r]; !ok { + return + } else { + current = next + } + + if position == len(runes)-1 { + current.SoftDel() + } + } +} + +// Replace 词语替换 +func (tree *Trie) Replace(text string, character rune) string { + var ( + parent = tree.Root + current *Node + runes = []rune(text) + length = len(runes) + left = 0 + found bool + ) + + for position := 0; position < len(runes); position++ { + current, found = parent.Children[runes[position]] + + if !found || (!current.IsPathEnd() && position == length-1) { + parent = tree.Root + position = left + left++ + continue + } + + // println(string(current.Character), current.IsPathEnd(), left) + if current.IsPathEnd() && left <= position { + for i := left; i <= position; i++ { + runes[i] = character + } + } + + parent = current + } + + return string(runes) +} + +// Filter 直接过滤掉字符串中的敏感词 +func (tree *Trie) Filter(text string) string { + var ( + parent = tree.Root + current *Node + left = 0 + found bool + runes = []rune(text) + length = len(runes) + resultRunes = make([]rune, 0, length) + ) + + for position := 0; position < length; position++ { + current, found = parent.Children[runes[position]] + + if !found || (!current.IsPathEnd() && position == length-1) { + resultRunes = append(resultRunes, runes[left]) + parent = tree.Root + position = left + left++ + continue + } + + if current.IsPathEnd() { + left = position + 1 + parent = tree.Root + } else { + parent = current + } + + } + + resultRunes = append(resultRunes, runes[left:]...) + return string(resultRunes) +} + +// Validate 验证字符串是否合法,如不合法则返回false和检测到 +// 的第一个敏感词 +func (tree *Trie) Validate(text string) (bool, string) { + const ( + Empty = "" + ) + var ( + parent = tree.Root + current *Node + runes = []rune(text) + length = len(runes) + left = 0 + found bool + ) + + for position := 0; position < len(runes); position++ { + current, found = parent.Children[runes[position]] + + if !found || (!current.IsPathEnd() && position == length-1) { + parent = tree.Root + position = left + left++ + continue + } + + if current.IsPathEnd() && left <= position { + return false, string(runes[left : position+1]) + } + + parent = current + } + + return true, Empty +} + +// FindIn 判断text中是否含有词库中的词 +func (tree *Trie) FindIn(text string) (bool, string) { + validated, first := tree.Validate(text) + return !validated, first +} + +// FindAll 找有所有包含在词库中的词 +func (tree *Trie) FindAll(text string) []string { + var matches []string + var ( + parent = tree.Root + current *Node + runes = []rune(text) + length = len(runes) + left = 0 + found bool + ) + + for position := 0; position < length; position++ { + current, found = parent.Children[runes[position]] + + if !found { + parent = tree.Root + position = left + left++ + continue + } + + if current.IsPathEnd() && left <= position { + matches = append(matches, string(runes[left:position+1])) + } + + if position == length-1 { + parent = tree.Root + position = left + left++ + continue + } + + parent = current + } + + var i = 0 + if count := len(matches); count > 0 { + set := make(map[string]struct{}) + for i < count { + _, ok := set[matches[i]] + if !ok { + set[matches[i]] = struct{}{} + i++ + continue + } + count-- + copy(matches[i:], matches[i+1:]) + } + return matches[:count] + } + + return nil +} + +// NewNode 新建子节点 +func NewNode(character rune) *Node { + return &Node{ + Character: character, + Children: make(map[rune]*Node, 0), + } +} + +// NewRootNode 新建根节点 +func NewRootNode(character rune) *Node { + return &Node{ + isRootNode: true, + Character: character, + Children: make(map[rune]*Node, 0), + } +} + +// IsLeafNode 判断是否叶子节点 +func (node *Node) IsLeafNode() bool { + return len(node.Children) == 0 +} + +// IsRootNode 判断是否为根节点 +func (node *Node) IsRootNode() bool { + return node.isRootNode +} + +// IsPathEnd 判断是否为某个路径的结束 +func (node *Node) IsPathEnd() bool { + return node.isPathEnd +} + +// SoftDel 置软删除状态 +func (node *Node) SoftDel() { + node.isPathEnd = false +}