diff --git a/cmd/robot/robot.go b/cmd/robot/robot.go index 8f5554ba7..13b6671f9 100644 --- a/cmd/robot/robot.go +++ b/cmd/robot/robot.go @@ -203,6 +203,9 @@ func (r *Robot) onUserLoaded() { //task r.RunTask() + + // story + r.RunStory() } //注册账号 diff --git a/cmd/robot/story.go b/cmd/robot/story.go new file mode 100644 index 000000000..e56c5afa9 --- /dev/null +++ b/cmd/robot/story.go @@ -0,0 +1,45 @@ +package robot + +import ( + "fmt" + "go_dreamfactory/comm" + "go_dreamfactory/modules/story" + "go_dreamfactory/pb" + + "google.golang.org/protobuf/proto" +) + +var ( + storyBuilders = []*TestCase{ + { + desc: "主线数据", + mainType: string(comm.ModuleStory), + subType: story.StoryGetListResp, + req: &pb.StoryGetListReq{}, + rsp: &pb.StoryGetListResp{}, + print: func(rsp proto.Message) { + out := rsp.(*pb.StoryGetListResp) + for i, v := range out.Data { + fmt.Printf("%d- %v\n", (i + 1), v) + } + }, + //enabled: true, + }, { + desc: "主线详情", + mainType: string(comm.ModuleStory), + subType: story.StoryChallengeResp, + req: &pb.StoryChallengeReq{ + ChapterId: 1, + StoryId: 1, + }, + rsp: &pb.StoryChallengeResp{}, + enabled: true, + }, + } +) + +//声明加入到构建器并发起请求 +func (r *Robot) RunStory() { + r.addBuilders(storyBuilders) + r.batchHandleReq() +} diff --git a/comm/const.go b/comm/const.go index ca296aefd..be9e6784b 100644 --- a/comm/const.go +++ b/comm/const.go @@ -29,12 +29,12 @@ const ( //模块名定义处 const ( ModuleGate core.M_Modules = "gateway" //gate模块 网关服务模块 - ModuleWeb core.M_Modules = "web" //web模块 + ModuleGM core.M_Modules = "gm" //gm模块 ModuleUser core.M_Modules = "user" //用户模块 ModulePack core.M_Modules = "pack" //背包模块 ModuleMail core.M_Modules = "mail" //邮件模块 ModuleFriend core.M_Modules = "friend" //好友模块 - ModuleLogModel core.M_Modules = "model" //日志模块 + ModuleMgoLog core.M_Modules = "mgolog" //日志模块 ModuleEquipment core.M_Modules = "equipment" //装备模块 ModuleHero core.M_Modules = "hero" //英雄模块 ModuleForum core.M_Modules = "forum" //论坛模块 @@ -42,6 +42,7 @@ const ( ModuleShop core.M_Modules = "shop" //商店模块 ModuleTask core.M_Modules = "task" //任务模块 ModuleStory core.M_Modules = "story" //主线模块 + ModuleNotify core.M_Modules = "notify" //公告模块 ) //RPC服务接口定义处 diff --git a/comm/usersession.go b/comm/usersession.go index 75087048b..d325bb00c 100644 --- a/comm/usersession.go +++ b/comm/usersession.go @@ -118,7 +118,7 @@ func (this *UserSession) UnBind() (err error) { //向用户发送消息 func (this *UserSession) SendMsg(mainType, subType string, msg proto.Message) (err error) { - log.Debugf("SendMsg to UserId:[%s] Data: %v", this.UserId, msg) + // log.Debugf("SendMsg to UserId:[%s] Data: %v", this.UserId, msg) data, _ := anypb.New(msg) this.msgqueue = append(this.msgqueue, &pb.UserMessage{ MainType: mainType, diff --git a/lego/base/rpcx/service.go b/lego/base/rpcx/service.go index f541eda5e..63677ed99 100644 --- a/lego/base/rpcx/service.go +++ b/lego/base/rpcx/service.go @@ -8,6 +8,7 @@ import ( "go_dreamfactory/lego/base" "go_dreamfactory/lego/core" "go_dreamfactory/lego/core/cbase" + "go_dreamfactory/lego/sys/codec" "go_dreamfactory/lego/sys/event" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/rpcx" @@ -83,6 +84,12 @@ func (this *RPCXService) InitSys() { } else { log.Infof("Sys event Init success !") } + //初始化编码Codec + if err := codec.OnInit(this.opts.Setting.Sys["codec"]); err != nil { + log.Panicf(fmt.Sprintf("Sys codec Init err:%v", err)) + } else { + log.Infof("Sys codec Init success !") + } //初始化rpcx系统 if err := rpcx.OnInit(this.opts.Setting.Sys["rpcx"], rpcx.SetServiceTag(this.GetTag()), rpcx.SetServiceId(this.GetId()), rpcx.SetServiceType(this.GetType()), rpcx.SetServiceVersion(this.GetVersion()), rpcx.SetServiceAddr(fmt.Sprintf("%s:%d", this.GetIp(), this.GetPort()))); err != nil { log.Panicf(fmt.Sprintf("Sys rpcx Init err:%v", err)) diff --git a/lego/core/cbase/servicebase.go b/lego/core/cbase/servicebase.go index da2c3b38f..86f6cac58 100644 --- a/lego/core/cbase/servicebase.go +++ b/lego/core/cbase/servicebase.go @@ -105,8 +105,8 @@ func (this *ServiceBase) Run(mod ...core.IModule) { mi: v, closeSig: make(chan bool, 1), } - log.Warnf("注册模块【%s】 没有对应的配置信息", v.GetType()) } + log.Infof("注册模块【%s】", v.GetType()) } for _, v := range this.modules { //序列化每一个模块的参数对象 完成模块的初始化 过程 options := v.mi.NewOptions() diff --git a/lego/sys/codec/codec.go b/lego/sys/codec/codec.go new file mode 100644 index 000000000..3fa30b128 --- /dev/null +++ b/lego/sys/codec/codec.go @@ -0,0 +1,273 @@ +package codec + +import ( + "errors" + "fmt" + "reflect" + "sync" + + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/factory" + "go_dreamfactory/lego/sys/codec/render" + + "github.com/modern-go/reflect2" +) + +func newSys(options core.Options) (sys *Codec, err error) { + sys = &Codec{ + options: &options, + decoderCache: new(sync.Map), + encoderCache: new(sync.Map), + streamPool: &sync.Pool{ + New: func() interface{} { + return render.NewStream(sys, 512) + }, + }, + extraPool: &sync.Pool{ + New: func() interface{} { + return render.NewExtractor(sys) + }, + }, + } + return +} + +type Codec struct { + options *core.Options + decoderCache *sync.Map + encoderCache *sync.Map + streamPool *sync.Pool + extraPool *sync.Pool +} + +func (this *Codec) Options() *core.Options { + return this.options +} + +func (this *Codec) addDecoderToCache(cacheKey uintptr, decoder core.IDecoder) { + this.decoderCache.Store(cacheKey, decoder) +} +func (this *Codec) addEncoderToCache(cacheKey uintptr, encoder core.IEncoder) { + this.encoderCache.Store(cacheKey, encoder) +} + +func (this *Codec) GetEncoderFromCache(cacheKey uintptr) core.IEncoder { + encoder, found := this.encoderCache.Load(cacheKey) + if found { + return encoder.(core.IEncoder) + } + return nil +} + +func (this *Codec) GetDecoderFromCache(cacheKey uintptr) core.IDecoder { + decoder, found := this.decoderCache.Load(cacheKey) + if found { + return decoder.(core.IDecoder) + } + return nil +} + +func (this *Codec) EncoderOf(typ reflect2.Type) core.IEncoder { + cacheKey := typ.RType() + encoder := this.GetEncoderFromCache(cacheKey) + if encoder != nil { + return encoder + } + ctx := &core.Ctx{ + ICodec: this, + Prefix: "", + Decoders: map[reflect2.Type]core.IDecoder{}, + Encoders: map[reflect2.Type]core.IEncoder{}, + } + encoder = factory.EncoderOfType(ctx, typ) + if typ.LikePtr() { + encoder = factory.NewonePtrEncoder(encoder) + } + this.addEncoderToCache(cacheKey, encoder) + return encoder +} + +func (this *Codec) DecoderOf(typ reflect2.Type) core.IDecoder { + cacheKey := typ.RType() + decoder := this.GetDecoderFromCache(cacheKey) + if decoder != nil { + return decoder + } + ctx := &core.Ctx{ + ICodec: this, + Prefix: "", + Decoders: map[reflect2.Type]core.IDecoder{}, + Encoders: map[reflect2.Type]core.IEncoder{}, + } + ptrType := typ.(*reflect2.UnsafePtrType) + decoder = factory.DecoderOfType(ctx, ptrType.Elem()) + this.addDecoderToCache(cacheKey, decoder) + return decoder +} + +func (this *Codec) BorrowStream() core.IStream { + stream := this.streamPool.Get().(core.IStream) + return stream +} + +func (this *Codec) ReturnStream(stream core.IStream) { + this.streamPool.Put(stream) +} + +func (this *Codec) BorrowExtractor(buf []byte) core.IExtractor { + extra := this.extraPool.Get().(core.IExtractor) + extra.ResetBytes(buf) + return extra +} + +func (this *Codec) ReturnExtractor(extra core.IExtractor) { + this.extraPool.Put(extra) +} + +//编码对象到json +func (this *Codec) MarshalJson(val interface{}, option ...core.ExecuteOption) (buf []byte, err error) { + stream := this.BorrowStream() + defer this.ReturnStream(stream) + stream.WriteVal(val) + if stream.Error() != nil { + return nil, stream.Error() + } + result := stream.Buffer() + copied := make([]byte, len(result)) + copy(copied, result) + return copied, nil +} + +//解码json到对象 +func (this *Codec) UnmarshalJson(data []byte, v interface{}, option ...core.ExecuteOption) error { + extra := this.BorrowExtractor(data) + defer this.ReturnExtractor(extra) + extra.ReadVal(v) + return extra.Error() +} + +//编码对象到mapjson +func (this *Codec) MarshalMapJson(val interface{}, option ...core.ExecuteOption) (ret map[string]string, err error) { + if nil == val { + err = errors.New("val is null") + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := this.GetEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = this.EncoderOf(typ) + } + if encoderMapJson, ok := encoder.(core.IEncoderMapJson); !ok { + err = fmt.Errorf("val type:%T not support MarshalMapJson", val) + } else { + ret, err = encoderMapJson.EncodeToMapJson(reflect2.PtrOf(val)) + } + return +} + +//解码mapjson到对象 +func (this *Codec) UnmarshalMapJson(data map[string]string, val interface{}, option ...core.ExecuteOption) (err error) { + cacheKey := reflect2.RTypeOf(val) + decoder := this.GetDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(val) + if typ == nil || typ.Kind() != reflect.Ptr { + err = errors.New("can only unmarshal into pointer") + return + } + decoder = this.DecoderOf(typ) + } + ptr := reflect2.PtrOf(val) + if ptr == nil { + err = errors.New("can not read into nil pointer") + return + } + if decoderMapJson, ok := decoder.(core.IDecoderMapJson); !ok { + err = fmt.Errorf("val type:%T not support MarshalMapJson", val) + } else { + err = decoderMapJson.DecodeForMapJson(ptr, data) + } + return +} + +//编码对象到sliceJson +func (this *Codec) MarshalSliceJson(val interface{}, option ...core.ExecuteOption) (ret []string, err error) { + if nil == val { + err = errors.New("val is null") + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := this.GetEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = this.EncoderOf(typ) + } + if encoderMapJson, ok := encoder.(core.IEncoderSliceJson); !ok { + err = fmt.Errorf("val type:%T not support MarshalMapJson", val) + } else { + ret, err = encoderMapJson.EncodeToSliceJson(reflect2.PtrOf(val)) + } + return +} + +//解码sliceJson到对象 +func (this *Codec) UnmarshalSliceJson(data []string, val interface{}, option ...core.ExecuteOption) (err error) { + cacheKey := reflect2.RTypeOf(val) + decoder := this.GetDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(val) + if typ == nil || typ.Kind() != reflect.Ptr { + err = errors.New("can only unmarshal into pointer") + return + } + decoder = this.DecoderOf(typ) + } + ptr := reflect2.PtrOf(val) + if ptr == nil { + err = errors.New("can not read into nil pointer") + return + } + if decoderMapJson, ok := decoder.(core.IDecoderSliceJson); !ok { + err = fmt.Errorf("val type:%T not support UnmarshalSliceJson", val) + } else { + err = decoderMapJson.DecodeForSliceJson(ptr, data) + } + return +} + +///日志*********************************************************************** +func (this *Codec) Debug() bool { + return this.options.Debug +} + +func (this *Codec) Debugf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Debugf("[SYS Codec] "+format, a...) + } +} +func (this *Codec) Infof(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Infof("[SYS Codec] "+format, a...) + } +} +func (this *Codec) Warnf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Warnf("[SYS Codec] "+format, a...) + } +} +func (this *Codec) Errorf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Errorf("[SYS Codec] "+format, a...) + } +} +func (this *Codec) Panicf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Panicf("[SYS Codec] "+format, a...) + } +} +func (this *Codec) Fatalf(format string, a ...interface{}) { + if this.options.Debug { + this.options.Log.Fatalf("[SYS Codec] "+format, a...) + } +} diff --git a/lego/sys/codec/core.go b/lego/sys/codec/core.go new file mode 100644 index 000000000..b83970fa9 --- /dev/null +++ b/lego/sys/codec/core.go @@ -0,0 +1,56 @@ +package codec + +import ( + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type ( + ISys interface { + DecoderOf(typ reflect2.Type) core.IDecoder + EncoderOf(typ reflect2.Type) core.IEncoder + MarshalJson(v interface{}, option ...core.ExecuteOption) ([]byte, error) + UnmarshalJson(data []byte, v interface{}, option ...core.ExecuteOption) error + MarshalMapJson(val interface{}, option ...core.ExecuteOption) (ret map[string]string, err error) + UnmarshalMapJson(data map[string]string, val interface{}, option ...core.ExecuteOption) (err error) + MarshalSliceJson(val interface{}, option ...core.ExecuteOption) (ret []string, err error) + UnmarshalSliceJson(data []string, val interface{}, option ...core.ExecuteOption) (err error) + } +) + +var defsys ISys + +func OnInit(config map[string]interface{}, option ...core.Option) (err error) { + defsys, err = newSys(newOptions(config, option...)) + return +} + +func NewSys(option ...core.Option) (sys ISys, err error) { + sys, err = newSys(newOptionsByOption(option...)) + return +} +func DecoderOf(typ reflect2.Type) core.IDecoder { + return defsys.DecoderOf(typ) +} +func EncoderOf(typ reflect2.Type) core.IEncoder { + return defsys.EncoderOf(typ) +} +func MarshalJson(v interface{}, option ...core.ExecuteOption) ([]byte, error) { + return defsys.MarshalJson(v, option...) +} +func UnmarshalJson(data []byte, v interface{}, option ...core.ExecuteOption) error { + return defsys.UnmarshalJson(data, v, option...) +} +func MarshalMapJson(val interface{}, option ...core.ExecuteOption) (ret map[string]string, err error) { + return defsys.MarshalMapJson(val, option...) +} +func UnmarshalMapJson(data map[string]string, val interface{}, option ...core.ExecuteOption) (err error) { + return defsys.UnmarshalMapJson(data, val, option...) +} +func MarshalSliceJson(val interface{}, option ...core.ExecuteOption) (ret []string, err error) { + return defsys.MarshalSliceJson(val, option...) +} +func UnmarshalSliceJson(data []string, val interface{}, option ...core.ExecuteOption) (err error) { + return defsys.UnmarshalSliceJson(data, val) +} diff --git a/lego/sys/codec/core/core.go b/lego/sys/codec/core/core.go new file mode 100644 index 000000000..191765a3a --- /dev/null +++ b/lego/sys/codec/core/core.go @@ -0,0 +1,167 @@ +package core + +import ( + "reflect" + "unsafe" + + "github.com/modern-go/reflect2" +) + +//数据类型 +type CodecType int8 + +const ( + Json CodecType = iota //json 格式数据 + Bytes //byte 字节流数据 + Proto //proto google protobuff 数据 +) + +//结构值类型 +type ValueType int + +const ( + // InvalidValue invalid JSON element + InvalidValue ValueType = iota + // StringValue JSON element "string" + StringValue + // NumberValue JSON element 100 or 0.10 + NumberValue + // NilValue JSON element null + NilValue + // BoolValue JSON element true or false + BoolValue + // ArrayValue JSON element [] + ArrayValue + // ObjectValue JSON element {} + ObjectValue +) + +type ( + ICodec interface { + Options() *Options + GetEncoderFromCache(cacheKey uintptr) IEncoder + GetDecoderFromCache(cacheKey uintptr) IDecoder + EncoderOf(typ reflect2.Type) IEncoder + DecoderOf(typ reflect2.Type) IDecoder + BorrowExtractor(buf []byte) IExtractor //借 提取器 + ReturnExtractor(extra IExtractor) //还 提取器 + BorrowStream() IStream //借 输出对象 + ReturnStream(stream IStream) //换 输出对象 + } + IExtractor interface { + ReadVal(obj interface{}) //读取指定类型对象 + WhatIsNext() ValueType + Read() interface{} + ReadNil() (ret bool) //读取空 null + ReadArrayStart() (ret bool) //读数组开始 [ + CheckNextIsArrayEnd() (ret bool) //下一个是否是数组结束符 不影响数据游标位置 + ReadArrayEnd() (ret bool) //读数组结束 ] + ReadObjectStart() (ret bool) //读对象或Map开始 { + CheckNextIsObjectEnd() (ret bool) //下一个是否是数对象结束符 不影响数据游标位置 + ReadObjectEnd() (ret bool) //读对象或Map结束 } + ReadMemberSplit() (ret bool) //读成员分割符 , + ReadKVSplit() (ret bool) //读取key value 分割符 : + ReadKeyStart() (ret bool) //读取字段名 开始 + ReadKeyEnd() (ret bool) //读取字段名 结束 + Skip() //跳过一个数据单元 容错处理 + ReadBool() (ret bool) + ReadInt8() (ret int8) + ReadInt16() (ret int16) + ReadInt32() (ret int32) + ReadInt64() (ret int64) + ReadUint8() (ret uint8) + ReadUint16() (ret uint16) + ReadUint32() (ret uint32) + ReadUint64() (ret uint64) + ReadFloat32() (ret float32) + ReadFloat64() (ret float64) + ReadString() (ret string) + ResetBytes(d []byte) + Error() error + SetErr(err error) + } + IStream interface { + WriteVal(val interface{}) //写入一个对象 + WriteNil() //写空 null + WriteEmptyArray() //写空数组 [] + WriteArrayStart() //写数组开始 [ + WriteArrayEnd() //写数组结束 ] + WriteEmptyObject() //写空对象 {} + WriteObjectStart() //写对象或Map开始 { + WriteObjectEnd() //写对象或Map结束 } + WriteMemberSplit() //写成员分割符 , + WriteKVSplit() //写key value 分割符 : + WriteKeyStart() //写入字段名 开始 + WriteKeyEnd() //写入字段名 结束 + WriteObjectFieldName(val string) //写入对象字段名 + WriteBool(val bool) + WriteInt8(val int8) + WriteInt16(val int16) + WriteInt32(val int32) + WriteInt64(val int64) + WriteUint8(val uint8) + WriteUint16(val uint16) + WriteUint32(val uint32) + WriteUint64(val uint64) + WriteFloat32(val float32) + WriteFloat64(val float64) + WriteString(val string) + WriteBytes(val []byte) + Reset(bufSize int) + Buffer() []byte //返回缓存区数据 + Error() error + SetErr(err error) + } + //Json 编码器 + IEncoder interface { + GetType() reflect.Kind + IsEmpty(ptr unsafe.Pointer) bool + Encode(ptr unsafe.Pointer, stream IStream) + } + //MapJson 编码器 + IEncoderMapJson interface { + EncodeToMapJson(ptr unsafe.Pointer) (ret map[string]string, err error) + } + //SliceJson 编码器 + IEncoderSliceJson interface { + EncodeToSliceJson(ptr unsafe.Pointer) (ret []string, err error) + } + + //Json 解码器 + IDecoder interface { + GetType() reflect.Kind + Decode(ptr unsafe.Pointer, extra IExtractor) + } + //MapJson 解码器 + IDecoderMapJson interface { + DecodeForMapJson(ptr unsafe.Pointer, extra map[string]string) (err error) + } + //MapJson 解码器 + IDecoderSliceJson interface { + DecodeForSliceJson(ptr unsafe.Pointer, extra []string) (err error) + } + //空校验 + CheckIsEmpty interface { + IsEmpty(ptr unsafe.Pointer) bool + } + //内嵌指针是否是空 + IsEmbeddedPtrNil interface { + IsEmbeddedPtrNil(ptr unsafe.Pointer) bool + } +) + +type Ctx struct { + ICodec + Prefix string + Encoders map[reflect2.Type]IEncoder + Decoders map[reflect2.Type]IDecoder +} + +func (this *Ctx) Append(prefix string) *Ctx { + return &Ctx{ + ICodec: this.ICodec, + Prefix: this.Prefix + " " + prefix, + Encoders: this.Encoders, + Decoders: this.Decoders, + } +} diff --git a/lego/sys/codec/core/options.go b/lego/sys/codec/core/options.go new file mode 100644 index 000000000..1524d0ddb --- /dev/null +++ b/lego/sys/codec/core/options.go @@ -0,0 +1,30 @@ +package core + +import ( + "go_dreamfactory/lego/sys/log" +) + +type Option func(*Options) +type Options struct { + IndentionStep int //缩进步骤 + ObjectFieldMustBeSimpleString bool //对象字段必须是简单字符串 + OnlyTaggedField bool //仅仅处理标签字段 + DisallowUnknownFields bool //禁止未知字段 + CaseSensitive bool //是否区分大小写 + TagKey string //标签 + Debug bool //日志是否开启 + Log log.ILog +} + +//执行选项 +type ExecuteOption func(*ExecuteOptions) +type ExecuteOptions struct { +} + +func NewExecuteOptions(opts ...ExecuteOption) ExecuteOptions { + options := ExecuteOptions{} + for _, o := range opts { + o(&options) + } + return options +} diff --git a/lego/sys/codec/factory/factory.go b/lego/sys/codec/factory/factory.go new file mode 100644 index 000000000..ca6cf2039 --- /dev/null +++ b/lego/sys/codec/factory/factory.go @@ -0,0 +1,219 @@ +package factory + +import ( + "fmt" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type sortableBindings []*Binding + +func (this sortableBindings) Len() int { + return len(this) +} + +func (this sortableBindings) Less(i, j int) bool { + left := this[i].levels + right := this[j].levels + k := 0 + for { + if left[k] < right[k] { + return true + } else if left[k] > right[k] { + return false + } + k++ + } +} + +func (this sortableBindings) Swap(i, j int) { + this[i], this[j] = this[j], this[i] +} + +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- +func EncoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + encoder := ctx.Encoders[typ] + if encoder != nil { + return encoder + } + root := &rootEncoder{} + ctx.Encoders[typ] = root + encoder = _createEncoderOfType(ctx, typ) + root.encoder = encoder + return encoder +} + +func _createEncoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + var encoder core.IEncoder + encoder = createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return encoderOfStruct(ctx, typ) + case reflect.Array: + return encoderOfArray(ctx, typ) + case reflect.Slice: + return encoderOfSlice(ctx, typ) + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return encoderOfOptional(ctx, typ) + default: + return &lazyErrorEncoder{err: fmt.Errorf("%s %s is unsupported type", ctx.Prefix, typ.String())} + } +} + +func DecoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + decoder := ctx.Decoders[typ] + if decoder != nil { + return decoder + } + root := &rootDecoder{} + ctx.Decoders[typ] = root + decoder = _createDecoderOfType(ctx, typ) + root.decoder = decoder + return decoder +} + +func _createDecoderOfType(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + var decoder core.IDecoder + + decoder = createDecoderOfNative(ctx, typ) + if decoder != nil { + return decoder + } + switch typ.Kind() { + case reflect.Interface: + ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) + if isIFace { + return &ifaceDecoder{valType: ifaceType} + } + return &efaceDecoder{} + case reflect.Struct: + return decoderOfStruct(ctx, typ) + case reflect.Array: + return decoderOfArray(ctx, typ) + case reflect.Slice: + return decoderOfSlice(ctx, typ) + case reflect.Map: + return decoderOfMap(ctx, typ) + case reflect.Ptr: + return decoderOfOptional(ctx, typ) + default: + return &lazyErrorDecoder{err: fmt.Errorf("%s %s is unsupported type", ctx.Prefix, typ.String())} + } +} + +// string +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func StringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} + +//根节点 ------------------------------------------------------------------- +type rootDecoder struct { + decoder core.IDecoder +} + +func (this *rootDecoder) GetType() reflect.Kind { + return reflect.Ptr +} +func (this *rootDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + this.decoder.Decode(ptr, extra) +} + +type rootEncoder struct { + encoder core.IEncoder +} + +func (this *rootEncoder) GetType() reflect.Kind { + return reflect.Ptr +} +func (this *rootEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + this.encoder.Encode(ptr, stream) +} + +func (this *rootEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return this.encoder.IsEmpty(ptr) +} + +//onePtrEncoder--------------------------------------------------------------- +func NewonePtrEncoder(encoder core.IEncoder) core.IEncoder { + return &onePtrEncoder{encoder} +} + +type onePtrEncoder struct { + encoder core.IEncoder +} + +func (this *onePtrEncoder) GetType() reflect.Kind { + return reflect.Ptr +} + +func (this *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return this.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +func (this *onePtrEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + this.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func (this *onePtrEncoder) EncodeToMapJson(ptr unsafe.Pointer) (ret map[string]string, err error) { + if encoderMapJson, ok := this.encoder.(core.IEncoderMapJson); !ok { + err = fmt.Errorf("encoder %T not support EncodeToMapJson", this.encoder) + return + } else { + return encoderMapJson.EncodeToMapJson(unsafe.Pointer(&ptr)) + } +} + +//错误节点 ------------------------------------------------------------------ +type lazyErrorDecoder struct { + err error +} + +func (this *lazyErrorDecoder) GetType() reflect.Kind { + return reflect.Ptr +} +func (this *lazyErrorDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.Error() == nil { + extra.SetErr(this.err) + } +} + +type lazyErrorEncoder struct { + err error +} + +func (this *lazyErrorEncoder) GetType() reflect.Kind { + return reflect.Ptr +} + +func (this *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if ptr == nil { + stream.WriteNil() + } else if stream.Error() == nil { + stream.SetErr(this.err) + } +} + +func (this *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} diff --git a/lego/sys/codec/factory/factory_array.go b/lego/sys/codec/factory/factory_array.go new file mode 100644 index 000000000..7f50618ec --- /dev/null +++ b/lego/sys/codec/factory/factory_array.go @@ -0,0 +1,145 @@ +package factory + +import ( + "errors" + "fmt" + "io" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfArray(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + decoder := DecoderOfType(ctx.Append("[arrayElem]"), arrayType.Elem()) + return &arrayDecoder{ctx.ICodec, arrayType, decoder} +} + +func encoderOfArray(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + if arrayType.Len() == 0 { + return &emptyArrayEncoder{} + } + encoder := EncoderOfType(ctx.Append("[arrayElem]"), arrayType.Elem()) + return &arrayEncoder{ctx.ICodec, arrayType, encoder} +} + +//array------------------------------------------------------------------------------------------------------------------------------- +type arrayEncoder struct { + codec core.ICodec + arrayType *reflect2.UnsafeArrayType + elemEncoder core.IEncoder +} + +func (codec *arrayEncoder) GetType() reflect.Kind { + return reflect.Array +} +func (this *arrayEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(ptr) + this.elemEncoder.Encode(elemPtr, stream) + for i := 1; i < this.arrayType.Len(); i++ { + stream.WriteMemberSplit() + elemPtr = this.arrayType.UnsafeGetIndex(ptr, i) + this.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v: %s", this.arrayType, stream.Error().Error())) + } +} + +func (this *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +//编码对象到json数组 +func (this *arrayEncoder) EncodeToSliceJson(ptr unsafe.Pointer) (ret []string, err error) { + ret = make([]string, this.arrayType.Len()) + stream := this.codec.BorrowStream() + for i := 1; i < this.arrayType.Len(); i++ { + elemPtr := this.arrayType.UnsafeGetIndex(ptr, i) + this.elemEncoder.Encode(elemPtr, stream) + if stream.Error() != nil && stream.Error() != io.EOF { + err = stream.Error() + return + } + ret[i] = BytesToString(stream.Buffer()) + stream.Reset(512) + } + return +} + +type arrayDecoder struct { + codec core.ICodec + arrayType *reflect2.UnsafeArrayType + elemDecoder core.IDecoder +} + +func (codec *arrayDecoder) GetType() reflect.Kind { + return reflect.Array +} +func (this *arrayDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + arrayType := this.arrayType + if extra.ReadNil() { + return + } + if extra.ReadArrayStart() { + return + } + if extra.CheckNextIsArrayEnd() { + return + } + elemPtr := arrayType.UnsafeGetIndex(ptr, 0) + this.elemDecoder.Decode(elemPtr, extra) + length := 1 + for extra.ReadMemberSplit() { + idx := length + length += 1 + elemPtr = arrayType.UnsafeGetIndex(ptr, idx) + this.elemDecoder.Decode(elemPtr, extra) + } + if extra.ReadArrayEnd() { + return + } + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%v: %s", this.arrayType, extra.Error().Error())) + } +} + +func (this *arrayDecoder) DecodeForSliceJson(ptr unsafe.Pointer, data []string) (err error) { + arrayType := this.arrayType + if data == nil { + err = errors.New("extra is nil") + return + } + extra := this.codec.BorrowExtractor([]byte{}) + arrayType.UnsafeGetIndex(ptr, len(data)) + for i, v := range data { + elemPtr := arrayType.UnsafeGetIndex(ptr, i) + extra.ResetBytes(StringToBytes(v)) + this.elemDecoder.Decode(elemPtr, extra) + if extra.Error() != nil && extra.Error() != io.EOF { + err = extra.Error() + return + } + } + return +} + +type emptyArrayEncoder struct{} + +func (this *emptyArrayEncoder) GetType() reflect.Kind { + return reflect.Array +} + +func (this *emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteEmptyArray() +} + +func (this *emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return true +} diff --git a/lego/sys/codec/factory/factory_interface.go b/lego/sys/codec/factory/factory_interface.go new file mode 100644 index 000000000..d9e446285 --- /dev/null +++ b/lego/sys/codec/factory/factory_interface.go @@ -0,0 +1,83 @@ +package factory + +import ( + "errors" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type dynamicEncoder struct { + valType reflect2.Type +} + +func (codec *dynamicEncoder) GetType() reflect.Kind { + return reflect.Interface +} +func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + obj := encoder.valType.UnsafeIndirect(ptr) + stream.WriteVal(obj) +} + +func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.valType.UnsafeIndirect(ptr) == nil +} + +type efaceDecoder struct { +} + +func (codec *efaceDecoder) GetType() reflect.Kind { + return reflect.Interface +} +func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + pObj := (*interface{})(ptr) + obj := *pObj + if obj == nil { + *pObj = extra.Read() + return + } + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + *pObj = extra.Read() + return + } + ptrType := typ.(*reflect2.UnsafePtrType) + ptrElemType := ptrType.Elem() + if extra.WhatIsNext() == core.NilValue { + if ptrElemType.Kind() != reflect.Ptr { + extra.ReadNil() + *pObj = nil + return + } + } + if reflect2.IsNil(obj) { + obj := ptrElemType.New() + extra.ReadVal(obj) + *pObj = obj + return + } + extra.ReadVal(obj) +} + +type ifaceDecoder struct { + valType *reflect2.UnsafeIFaceType +} + +func (codec *ifaceDecoder) GetType() reflect.Kind { + return reflect.Interface +} +func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadNil() { + decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) + return + } + obj := decoder.valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + extra.SetErr(errors.New("decode non empty interface can not unmarshal into nil")) + return + } + extra.ReadVal(obj) +} diff --git a/lego/sys/codec/factory/factory_map.go b/lego/sys/codec/factory/factory_map.go new file mode 100644 index 000000000..8562b28d1 --- /dev/null +++ b/lego/sys/codec/factory/factory_map.go @@ -0,0 +1,273 @@ +package factory + +import ( + "fmt" + "io" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfMap(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + mapType := typ.(*reflect2.UnsafeMapType) + keyDecoder := decoderOfMapKey(ctx.Append("[mapKey]"), mapType.Key()) + elemDecoder := DecoderOfType(ctx.Append("[mapElem]"), mapType.Elem()) + return &mapDecoder{ + codec: ctx.ICodec, + mapType: mapType, + keyType: mapType.Key(), + elemType: mapType.Elem(), + keyDecoder: keyDecoder, + elemDecoder: elemDecoder, + } +} + +func encoderOfMap(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + mapType := typ.(*reflect2.UnsafeMapType) + return &mapEncoder{ + codec: ctx.ICodec, + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.Append("[mapKey]"), mapType.Key()), + elemEncoder: EncoderOfType(ctx.Append("[mapElem]"), mapType.Elem()), + } +} + +func decoderOfMapKey(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + switch typ.Kind() { + case reflect.String: + return DecoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyDecoder{DecoderOfType(ctx, typ)} + default: + return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +func encoderOfMapKey(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + switch typ.Kind() { + case reflect.String: + return EncoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyEncoder{EncoderOfType(ctx, typ)} + default: + if typ.Kind() == reflect.Interface { + return &dynamicMapKeyEncoder{ctx, typ} + } + return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +//Map-------------------------------------------------------------------------------------------------------------------------------------- +type mapEncoder struct { + codec core.ICodec + mapType *reflect2.UnsafeMapType + keyEncoder core.IEncoder + elemEncoder core.IEncoder +} + +func (this *mapEncoder) GetType() reflect.Kind { + return reflect.Map +} +func (this *mapEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *(*unsafe.Pointer)(ptr) == nil { + stream.WriteNil() + return + } + stream.WriteObjectStart() + iter := this.mapType.UnsafeIterate(ptr) + for i := 0; iter.HasNext(); i++ { + if i != 0 { + stream.WriteMemberSplit() + } + key, elem := iter.UnsafeNext() + this.keyEncoder.Encode(key, stream) + stream.WriteKVSplit() + this.elemEncoder.Encode(elem, stream) + } + stream.WriteObjectEnd() +} + +func (this *mapEncoder) EncodeToMapJson(ptr unsafe.Pointer) (ret map[string]string, err error) { + ret = make(map[string]string) + keystream := this.codec.BorrowStream() + elemstream := this.codec.BorrowStream() + iter := this.mapType.UnsafeIterate(ptr) + for i := 0; iter.HasNext(); i++ { + key, elem := iter.UnsafeNext() + this.keyEncoder.Encode(key, keystream) + if keystream.Error() != nil && keystream.Error() != io.EOF { + err = keystream.Error() + return + } + this.elemEncoder.Encode(elem, elemstream) + if elemstream.Error() != nil && elemstream.Error() != io.EOF { + err = elemstream.Error() + return + } + ret[BytesToString(keystream.Buffer())] = BytesToString(elemstream.Buffer()) + keystream.Reset(512) + elemstream.Reset(512) + } + return +} + +func (this *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := this.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type mapDecoder struct { + codec core.ICodec + mapType *reflect2.UnsafeMapType + keyType reflect2.Type + elemType reflect2.Type + keyDecoder core.IDecoder + elemDecoder core.IDecoder +} + +func (codec *mapDecoder) GetType() reflect.Kind { + return reflect.Map +} +func (this *mapDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + mapType := this.mapType + if extra.ReadNil() { + *(*unsafe.Pointer)(ptr) = nil + mapType.UnsafeSet(ptr, mapType.UnsafeNew()) + return + } + if mapType.UnsafeIsNil(ptr) { + mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) + } + if !extra.ReadObjectStart() { + return + } + if extra.CheckNextIsObjectEnd() { + extra.ReadObjectEnd() + return + } + key := this.keyType.UnsafeNew() + this.keyDecoder.Decode(key, extra) + if !extra.ReadKVSplit() { + return + } + elem := this.elemType.UnsafeNew() + this.elemDecoder.Decode(elem, extra) + this.mapType.UnsafeSetIndex(ptr, key, elem) + for extra.ReadMemberSplit() { + key := this.keyType.UnsafeNew() + this.keyDecoder.Decode(key, extra) + if !extra.ReadKVSplit() { + return + } + elem := this.elemType.UnsafeNew() + this.elemDecoder.Decode(elem, extra) + this.mapType.UnsafeSetIndex(ptr, key, elem) + } + extra.ReadObjectEnd() +} + +//解码对象从MapJson 中 +func (this *mapDecoder) DecodeForMapJson(ptr unsafe.Pointer, extra map[string]string) (err error) { + keyext := this.codec.BorrowExtractor([]byte{}) + elemext := this.codec.BorrowExtractor([]byte{}) + for k, v := range extra { + key := this.keyType.UnsafeNew() + if this.keyDecoder.GetType() != reflect.String { + keyext.ResetBytes(StringToBytes(k)) + this.keyDecoder.Decode(key, keyext) + if keyext.Error() != nil && keyext.Error() != io.EOF { + err = keyext.Error() + return + } + } else { + *((*string)(key)) = k + } + elem := this.elemType.UnsafeNew() + if this.elemDecoder.GetType() != reflect.String { + elemext.ResetBytes(StringToBytes(v)) + this.elemDecoder.Decode(elem, elemext) + this.mapType.UnsafeSetIndex(ptr, key, elem) + if elemext.Error() != nil && elemext.Error() != io.EOF { + err = elemext.Error() + return + } + } else { + *((*string)(elem)) = v + } + } + return +} + +//NumericMap------------------------------------------------------------------------------------------------------------------------------- +type numericMapKeyDecoder struct { + decoder core.IDecoder +} + +func (this *numericMapKeyDecoder) GetType() reflect.Kind { + return this.decoder.GetType() +} +func (this *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadKeyStart() { + return + } + this.decoder.Decode(ptr, extra) + if extra.ReadKeyEnd() { + return + } +} + +type numericMapKeyEncoder struct { + encoder core.IEncoder +} + +func (this *numericMapKeyEncoder) GetType() reflect.Kind { + return this.encoder.GetType() +} +func (this *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteKeyStart() + this.encoder.Encode(ptr, stream) + stream.WriteKeyEnd() +} + +func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +//------------------------------------------------------------------------------------------------------------------ +type dynamicMapKeyEncoder struct { + ctx *core.Ctx + valType reflect2.Type +} + +func (this *dynamicMapKeyEncoder) GetType() reflect.Kind { + return reflect.Interface +} + +func (this *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + obj := this.valType.UnsafeIndirect(ptr) + encoderOfMapKey(this.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) +} + +func (this *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + obj := this.valType.UnsafeIndirect(ptr) + return encoderOfMapKey(this.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) +} diff --git a/lego/sys/codec/factory/factory_native.go b/lego/sys/codec/factory/factory_native.go new file mode 100644 index 000000000..c8cfdb0f1 --- /dev/null +++ b/lego/sys/codec/factory/factory_native.go @@ -0,0 +1,434 @@ +package factory + +import ( + "reflect" + "strconv" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +const ptrSize = 32 << uintptr(^uintptr(0)>>63) //计算int的大小 是32 还是64 + +func createDecoderOfNative(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + typeName := typ.String() + switch typ.Kind() { + case reflect.String: + if typeName != "string" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return DecoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +func createEncoderOfNative(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + typeName := typ.String() + kind := typ.Kind() + switch kind { + case reflect.String: + if typeName != "string" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return EncoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +type stringCodec struct { +} + +func (codec *stringCodec) GetType() reflect.Kind { + return reflect.String +} +func (codec *stringCodec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + *((*string)(ptr)) = extra.ReadString() +} + +func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream core.IStream) { + str := *((*string)(ptr)) + stream.WriteString(str) +} + +func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +type int8Codec struct { +} + +func (codec *int8Codec) GetType() reflect.Kind { + return reflect.Int8 +} + +func (codec *int8Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int8)(ptr)) = extra.ReadInt8() + } +} + +func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt8(*((*int8)(ptr))) +} + +func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int8)(ptr)) == 0 +} + +type int16Codec struct { +} + +func (codec *int16Codec) GetType() reflect.Kind { + return reflect.Int16 +} +func (codec *int16Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int16)(ptr)) = extra.ReadInt16() + } +} + +func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt16(*((*int16)(ptr))) +} + +func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int16)(ptr)) == 0 +} + +type int32Codec struct { +} + +func (codec *int32Codec) GetType() reflect.Kind { + return reflect.Int32 +} +func (codec *int32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int32)(ptr)) = extra.ReadInt32() + } +} + +func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt32(*((*int32)(ptr))) +} +func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int32)(ptr)) == 0 +} + +type int64Codec struct { +} + +func (codec *int64Codec) GetType() reflect.Kind { + return reflect.Int64 +} +func (codec *int64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*int64)(ptr)) = extra.ReadInt64() + } +} + +func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteInt64(*((*int64)(ptr))) +} + +func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int64)(ptr)) == 0 +} + +type uint8Codec struct { +} + +func (codec *uint8Codec) GetType() reflect.Kind { + return reflect.Uint8 +} +func (codec *uint8Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint8)(ptr)) = extra.ReadUint8() + } +} + +func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint8(*((*uint8)(ptr))) +} + +func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint8)(ptr)) == 0 +} + +type uint16Codec struct { +} + +func (codec *uint16Codec) GetType() reflect.Kind { + return reflect.Uint16 +} +func (codec *uint16Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint16)(ptr)) = extra.ReadUint16() + } +} + +func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint16(*((*uint16)(ptr))) +} + +func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint16)(ptr)) == 0 +} + +type uint32Codec struct { +} + +func (codec *uint32Codec) GetType() reflect.Kind { + return reflect.Uint32 +} +func (codec *uint32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint32)(ptr)) = extra.ReadUint32() + } +} + +func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint32(*((*uint32)(ptr))) +} +func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint32)(ptr)) == 0 +} + +type uint64Codec struct { +} + +func (codec *uint64Codec) GetType() reflect.Kind { + return reflect.Uint64 +} +func (codec *uint64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*uint64)(ptr)) = extra.ReadUint64() + } +} + +func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteUint64(*((*uint64)(ptr))) +} + +func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint64)(ptr)) == 0 +} + +type float32Codec struct { +} + +func (codec *float32Codec) GetType() reflect.Kind { + return reflect.Float32 +} +func (codec *float32Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*float32)(ptr)) = extra.ReadFloat32() + } +} + +func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteFloat32(*((*float32)(ptr))) +} + +func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type float64Codec struct { +} + +func (codec *float64Codec) GetType() reflect.Kind { + return reflect.Float64 +} +func (codec *float64Codec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*float64)(ptr)) = extra.ReadFloat64() + } +} + +func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteFloat64(*((*float64)(ptr))) +} + +func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +type boolCodec struct { +} + +func (codec *boolCodec) GetType() reflect.Kind { + return reflect.Bool +} +func (codec *boolCodec) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadNil() { + *((*bool)(ptr)) = extra.ReadBool() + } +} + +func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteBool(*((*bool)(ptr))) +} + +func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { + return !(*((*bool)(ptr))) +} diff --git a/lego/sys/codec/factory/factory_optional.go b/lego/sys/codec/factory/factory_optional.go new file mode 100644 index 000000000..558f7d500 --- /dev/null +++ b/lego/sys/codec/factory/factory_optional.go @@ -0,0 +1,167 @@ +package factory + +import ( + "fmt" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfOptional(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + decoder := DecoderOfType(ctx, elemType) + return &OptionalDecoder{elemType, decoder} +} + +func encoderOfOptional(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elemEncoder := EncoderOfType(ctx, elemType) + encoder := &OptionalEncoder{elemEncoder} + return encoder +} + +//Optional-------------------------------------------------------------------------------------------------------------------- +type OptionalDecoder struct { + ValueType reflect2.Type + ValueDecoder core.IDecoder +} + +func (this *OptionalDecoder) GetType() reflect.Kind { + return this.ValueDecoder.GetType() +} +func (this *OptionalDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if extra.ReadNil() { + *((*unsafe.Pointer)(ptr)) = nil + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + newPtr := this.ValueType.UnsafeNew() + this.ValueDecoder.Decode(newPtr, extra) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + this.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), extra) + } + } +} + +func (this *OptionalDecoder) DecodeForMapJson(ptr unsafe.Pointer, extra map[string]string) (err error) { + if decoderMapJson, ok := this.ValueDecoder.(core.IDecoderMapJson); !ok { + err = fmt.Errorf("encoder %T not support EncodeToMapJson", this.ValueDecoder) + return + } else { + return decoderMapJson.DecodeForMapJson(ptr, extra) + } +} + +type OptionalEncoder struct { + ValueEncoder core.IEncoder +} + +func (this *OptionalEncoder) GetType() reflect.Kind { + return this.ValueEncoder.GetType() +} +func (this *OptionalEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + this.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (this *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*unsafe.Pointer)(ptr)) == nil +} + +func (this *OptionalEncoder) EncodeToMapJson(ptr unsafe.Pointer) (ret map[string]string, err error) { + if encoderMapJson, ok := this.ValueEncoder.(core.IEncoderMapJson); !ok { + err = fmt.Errorf("encoder %T not support EncodeToMapJson", this.ValueEncoder) + return + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + err = fmt.Errorf("encoder ptr is nil") + return + } else { + return encoderMapJson.EncodeToMapJson(*((*unsafe.Pointer)(ptr))) + } + } +} + +//reference-------------------------------------------------------------------------------------------------------------------- +type referenceEncoder struct { + encoder core.IEncoder +} + +func (this *referenceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + this.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func (this *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return this.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +type referenceDecoder struct { + decoder core.IDecoder +} + +func (this *referenceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + this.decoder.Decode(unsafe.Pointer(&ptr), extra) +} + +//dereference-------------------------------------------------------------------------------------------------------------------- +type dereferenceDecoder struct { + valueType reflect2.Type + valueDecoder core.IDecoder +} + +func (this *dereferenceDecoder) GetType() reflect.Kind { + return this.valueDecoder.GetType() +} +func (this *dereferenceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if *((*unsafe.Pointer)(ptr)) == nil { + newPtr := this.valueType.UnsafeNew() + this.valueDecoder.Decode(newPtr, extra) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + this.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), extra) + } +} + +type dereferenceEncoder struct { + ValueEncoder core.IEncoder +} + +func (this *dereferenceEncoder) GetType() reflect.Kind { + return this.ValueEncoder.GetType() +} +func (this *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + this.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (this *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + dePtr := *((*unsafe.Pointer)(ptr)) + if dePtr == nil { + return true + } + return this.ValueEncoder.IsEmpty(dePtr) +} + +func (this *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + deReferenced := *((*unsafe.Pointer)(ptr)) + if deReferenced == nil { + return true + } + isEmbeddedPtrNil, converted := this.ValueEncoder.(core.IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := unsafe.Pointer(deReferenced) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} diff --git a/lego/sys/codec/factory/factory_slice.go b/lego/sys/codec/factory/factory_slice.go new file mode 100644 index 000000000..291c59e78 --- /dev/null +++ b/lego/sys/codec/factory/factory_slice.go @@ -0,0 +1,146 @@ +package factory + +import ( + "errors" + "fmt" + "io" + "reflect" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +func decoderOfSlice(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + decoder := DecoderOfType(ctx.Append("[sliceElem]"), sliceType.Elem()) + return &sliceDecoder{ctx.ICodec, sliceType, decoder} +} +func encoderOfSlice(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + encoder := EncoderOfType(ctx.Append("[sliceElem]"), sliceType.Elem()) + return &sliceEncoder{ctx.ICodec, sliceType, encoder} +} + +type sliceEncoder struct { + codec core.ICodec + sliceType *reflect2.UnsafeSliceType + elemEncoder core.IEncoder +} + +func (codec *sliceEncoder) GetType() reflect.Kind { + return reflect.Slice +} +func (this *sliceEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + if this.sliceType.UnsafeIsNil(ptr) { + stream.WriteNil() + return + } + length := this.sliceType.UnsafeLengthOf(ptr) + if length == 0 { + stream.WriteEmptyArray() + return + } + stream.WriteArrayStart() + this.elemEncoder.Encode(this.sliceType.UnsafeGetIndex(ptr, 0), stream) + for i := 1; i < length; i++ { + stream.WriteMemberSplit() + elemPtr := this.sliceType.UnsafeGetIndex(ptr, i) + this.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v: %s", this.sliceType, stream.Error().Error())) + } +} + +func (this *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return this.sliceType.UnsafeLengthOf(ptr) == 0 +} + +//编码对象到json数组 +func (this *sliceEncoder) EncodeToSliceJson(ptr unsafe.Pointer) (ret []string, err error) { + if this.sliceType.UnsafeIsNil(ptr) { + err = errors.New("val is nil") + return + } + length := this.sliceType.UnsafeLengthOf(ptr) + ret = make([]string, length) + if length == 0 { + return + } + stream := this.codec.BorrowStream() + for i := 1; i < length; i++ { + elemPtr := this.sliceType.UnsafeGetIndex(ptr, i) + this.elemEncoder.Encode(elemPtr, stream) + if stream.Error() != nil && stream.Error() != io.EOF { + err = stream.Error() + return + } + ret[i] = BytesToString(stream.Buffer()) + stream.Reset(512) + } + return +} + +type sliceDecoder struct { + codec core.ICodec + sliceType *reflect2.UnsafeSliceType + elemDecoder core.IDecoder +} + +func (codec *sliceDecoder) GetType() reflect.Kind { + return reflect.Slice +} +func (this *sliceDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + sliceType := this.sliceType + if extra.ReadNil() { + sliceType.UnsafeSetNil(ptr) + return + } + if !extra.ReadArrayStart() { + return + } + if extra.CheckNextIsArrayEnd() { + sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) + return + } + sliceType.UnsafeGrow(ptr, 1) + elemPtr := sliceType.UnsafeGetIndex(ptr, 0) + this.elemDecoder.Decode(elemPtr, extra) + length := 1 + for extra.ReadMemberSplit() { + idx := length + length += 1 + sliceType.UnsafeGrow(ptr, length) + elemPtr = sliceType.UnsafeGetIndex(ptr, idx) + this.elemDecoder.Decode(elemPtr, extra) + } + if extra.ReadArrayEnd() { + return + } + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%v: %s", this.sliceType, extra.Error().Error())) + } +} + +func (this *sliceDecoder) DecodeForSliceJson(ptr unsafe.Pointer, data []string) (err error) { + sliceType := this.sliceType + if data == nil { + err = errors.New("extra is nil") + return + } + extra := this.codec.BorrowExtractor([]byte{}) + sliceType.UnsafeGrow(ptr, len(data)) + for i, v := range data { + elemPtr := sliceType.UnsafeGetIndex(ptr, i) + extra.ResetBytes(StringToBytes(v)) + this.elemDecoder.Decode(elemPtr, extra) + if extra.Error() != nil && extra.Error() != io.EOF { + err = extra.Error() + return + } + } + return +} diff --git a/lego/sys/codec/factory/factory_struct.go b/lego/sys/codec/factory/factory_struct.go new file mode 100644 index 000000000..a07ae27ce --- /dev/null +++ b/lego/sys/codec/factory/factory_struct.go @@ -0,0 +1,447 @@ +package factory + +import ( + "errors" + "fmt" + "io" + "reflect" + "sort" + "strings" + "unicode" + "unsafe" + + "go_dreamfactory/lego/sys/codec/core" + + "github.com/modern-go/reflect2" +) + +type StructDescriptor struct { + Type reflect2.Type + Fields []*Binding +} + +type Binding struct { + levels []int + Field reflect2.StructField + FromNames []string + ToNames []string + Encoder core.IEncoder + Decoder core.IDecoder +} + +func encoderOfStruct(ctx *core.Ctx, typ reflect2.Type) core.IEncoder { + type bindingTo struct { + binding *Binding + toName string + ignored bool + } + orderedBindings := []*bindingTo{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, toName := range binding.ToNames { + new := &bindingTo{ + binding: binding, + toName: toName, + } + for _, old := range orderedBindings { + if old.toName != toName { + continue + } + old.ignored, new.ignored = resolveConflictBinding(ctx.Options(), old.binding, new.binding) + } + orderedBindings = append(orderedBindings, new) + } + } + if len(orderedBindings) == 0 { + return &emptyStructEncoder{} + } + finalOrderedFields := []structFieldTo{} + for _, bindingTo := range orderedBindings { + if !bindingTo.ignored { + finalOrderedFields = append(finalOrderedFields, structFieldTo{ + encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + toName: bindingTo.toName, + }) + } + } + return &structEncoder{ctx.ICodec, typ, finalOrderedFields} +} + +func decoderOfStruct(ctx *core.Ctx, typ reflect2.Type) core.IDecoder { + bindings := map[string]*Binding{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, fromName := range binding.FromNames { + old := bindings[fromName] + if old == nil { + bindings[fromName] = binding + continue + } + ignoreOld, ignoreNew := resolveConflictBinding(ctx.Options(), old, binding) + if ignoreOld { + delete(bindings, fromName) + } + if !ignoreNew { + bindings[fromName] = binding + } + } + } + fields := map[string]*structFieldDecoder{} + for k, binding := range bindings { + fields[k] = binding.Decoder.(*structFieldDecoder) + } + + if !ctx.Options().CaseSensitive { + for k, binding := range bindings { + if _, found := fields[strings.ToLower(k)]; !found { + fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) + } + } + } + return createStructDecoder(ctx.ICodec, typ, fields) +} + +//结构第编辑码构建 +func describeStruct(ctx *core.Ctx, typ reflect2.Type) *StructDescriptor { + structType := typ.(*reflect2.UnsafeStructType) + embeddedBindings := []*Binding{} + bindings := []*Binding{} + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + tag, hastag := field.Tag().Lookup(ctx.Options().TagKey) + if ctx.Options().OnlyTaggedField && !hastag && !field.Anonymous() { + continue + } + if tag == "-" || field.Name() == "_" { + continue + } + tagParts := strings.Split(tag, ",") + if field.Anonymous() && (tag == "" || tagParts[0] == "") { + if field.Type().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, field.Type()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } else if field.Type().Kind() == reflect.Ptr { + ptrType := field.Type().(*reflect2.UnsafePtrType) + if ptrType.Elem().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, ptrType.Elem()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &dereferenceEncoder{binding.Encoder} + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } + } + } + fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) + decoder := DecoderOfType(ctx.Append(field.Name()), field.Type()) + encoder := EncoderOfType(ctx.Append(field.Name()), field.Type()) + binding := &Binding{ + Field: field, + FromNames: fieldNames, + ToNames: fieldNames, + Decoder: decoder, + Encoder: encoder, + } + binding.levels = []int{i} + bindings = append(bindings, binding) + } + return createStructDescriptor(ctx, typ, bindings, embeddedBindings) +} + +func createStructDescriptor(ctx *core.Ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + structDescriptor := &StructDescriptor{ + Type: typ, + Fields: bindings, + } + processTags(structDescriptor, ctx.ICodec) + allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + sort.Sort(allBindings) + structDescriptor.Fields = allBindings + return structDescriptor +} + +func processTags(structDescriptor *StructDescriptor, codec core.ICodec) { + for _, binding := range structDescriptor.Fields { + shouldOmitEmpty := false + tagParts := strings.Split(binding.Field.Tag().Get(codec.Options().TagKey), ",") + for _, tagPart := range tagParts[1:] { + if tagPart == "omitempty" { + shouldOmitEmpty = true + } + } + binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + } +} + +func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { + // ignore? + if wholeTag == "-" { + return []string{} + } + // rename? + var fieldNames []string + if tagProvidedFieldName == "" { + fieldNames = []string{originalFieldName} + } else { + fieldNames = []string{tagProvidedFieldName} + } + // private? + isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_' + if isNotExported { + fieldNames = []string{} + } + return fieldNames +} + +func createStructDecoder(codec core.ICodec, typ reflect2.Type, fields map[string]*structFieldDecoder) core.IDecoder { + if codec.Options().DisallowUnknownFields { + return &structDecoder{typ: typ, fields: fields, disallowUnknownFields: true} + } else { + return &structDecoder{codec, typ, fields, false} + } +} + +func resolveConflictBinding(opt *core.Options, old, new *Binding) (ignoreOld, ignoreNew bool) { + newTagged := new.Field.Tag().Get(opt.TagKey) != "" + oldTagged := old.Field.Tag().Get(opt.TagKey) != "" + if newTagged { + if oldTagged { + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } else { + return true, false + } + } else { + if oldTagged { + return true, false + } + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } +} + +//结构对象 编解码----------------------------------------------------------------------------------------------------------------------- +type structEncoder struct { + codec core.ICodec + typ reflect2.Type + fields []structFieldTo +} + +func (codec *structEncoder) GetType() reflect.Kind { + return reflect.Struct +} +func (this *structEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteObjectStart() + isNotFirst := false + for _, field := range this.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if field.encoder.IsEmbeddedPtrNil(ptr) { + continue + } + if isNotFirst { + stream.WriteMemberSplit() + } + stream.WriteObjectFieldName(field.toName) + field.encoder.Encode(ptr, stream) + isNotFirst = true + } + stream.WriteObjectEnd() + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%v.%s", this.typ, stream.Error().Error())) + } +} + +func (this *structEncoder) EncodeToMapJson(ptr unsafe.Pointer) (ret map[string]string, err error) { + ret = make(map[string]string) + stream := this.codec.BorrowStream() + for _, field := range this.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if field.encoder.IsEmbeddedPtrNil(ptr) { + continue + } + stream.Reset(512) + field.encoder.Encode(ptr, stream) + if stream.Error() != nil && stream.Error() != io.EOF { + err = stream.Error() + return + } + ret[field.toName] = BytesToString(stream.Buffer()) + } + return +} + +func (this *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type structDecoder struct { + codec core.ICodec + typ reflect2.Type + fields map[string]*structFieldDecoder + disallowUnknownFields bool +} + +func (codec *structDecoder) GetType() reflect.Kind { + return reflect.Struct +} +func (this *structDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + if !extra.ReadObjectStart() { + return + } + this.decodeField(ptr, extra) + for extra.ReadMemberSplit() { + this.decodeField(ptr, extra) + } + if extra.Error() != nil && extra.Error() != io.EOF && len(this.typ.Type1().Name()) != 0 { + extra.SetErr(fmt.Errorf("%v.%s", this.typ, extra.Error().Error())) + } + extra.ReadObjectEnd() +} + +func (this *structDecoder) decodeField(ptr unsafe.Pointer, extra core.IExtractor) { + var field string + var fieldDecoder *structFieldDecoder + + field = extra.ReadString() + fieldDecoder = this.fields[field] + if fieldDecoder == nil && !this.codec.Options().CaseSensitive { + fieldDecoder = this.fields[strings.ToLower(field)] + } + + if fieldDecoder == nil { + if this.disallowUnknownFields { + msg := "found unknown field: " + field + extra.SetErr(fmt.Errorf("decodeField %s", msg)) + return + } + if !extra.ReadKVSplit() { + return + } + extra.Skip() //跳过一个数据单元 + return + } + if !extra.ReadKVSplit() { + return + } + fieldDecoder.Decode(ptr, extra) +} + +//解码对象从MapJson 中 +func (this *structDecoder) DecodeForMapJson(ptr unsafe.Pointer, extra map[string]string) (err error) { + var fieldDecoder *structFieldDecoder + ext := this.codec.BorrowExtractor([]byte{}) + for k, v := range extra { + fieldDecoder = this.fields[k] + if fieldDecoder == nil && !this.codec.Options().CaseSensitive { + fieldDecoder = this.fields[strings.ToLower(k)] + } + if fieldDecoder == nil { + if this.disallowUnknownFields { + err = errors.New("found unknown field: " + k) + return + } + continue + } + ext.ResetBytes(StringToBytes(v)) + fieldDecoder.Decode(ptr, ext) + if ext.Error() != nil && ext.Error() != io.EOF { + err = ext.Error() + return + } + } + return +} + +//结构对象字段 编解码----------------------------------------------------------------------------------------------------------------------- +type structFieldTo struct { + encoder *structFieldEncoder + toName string +} +type structFieldEncoder struct { + field reflect2.StructField + fieldEncoder core.IEncoder + omitempty bool +} + +func (this *structFieldEncoder) GetType() reflect.Kind { + return this.fieldEncoder.GetType() +} +func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + fieldPtr := encoder.field.UnsafeGet(ptr) + encoder.fieldEncoder.Encode(fieldPtr, stream) + if stream.Error() != nil && stream.Error() != io.EOF { + stream.SetErr(fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error().Error())) + } +} + +func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := encoder.field.UnsafeGet(ptr) + return encoder.fieldEncoder.IsEmpty(fieldPtr) +} + +func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + isEmbeddedPtrNil, converted := encoder.fieldEncoder.(core.IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := encoder.field.UnsafeGet(ptr) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type structFieldDecoder struct { + field reflect2.StructField + fieldDecoder core.IDecoder +} + +func (this *structFieldDecoder) GetType() reflect.Kind { + return this.fieldDecoder.GetType() +} +func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { + fieldPtr := decoder.field.UnsafeGet(ptr) + decoder.fieldDecoder.Decode(fieldPtr, extra) + if extra.Error() != nil && extra.Error() != io.EOF { + extra.SetErr(fmt.Errorf("%s: %s", decoder.field.Name(), extra.Error().Error())) + } +} + +//Empty----------------------------------------------------------------------------------------------------------------------- +type emptyStructEncoder struct { +} + +func (codec *emptyStructEncoder) GetType() reflect.Kind { + return reflect.Struct +} +func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream core.IStream) { + stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} diff --git a/lego/sys/codec/options.go b/lego/sys/codec/options.go new file mode 100644 index 000000000..28b5cd723 --- /dev/null +++ b/lego/sys/codec/options.go @@ -0,0 +1,36 @@ +package codec + +import ( + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/lego/utils/mapstructure" +) + +func newOptions(config map[string]interface{}, opts ...core.Option) core.Options { + options := core.Options{ + IndentionStep: 2, + } + if config != nil { + mapstructure.Decode(config, &options) + } + for _, o := range opts { + o(&options) + } + if options.Debug && options.Log == nil { + options.Log = log.Clone() + } + return options +} + +func newOptionsByOption(opts ...core.Option) core.Options { + options := core.Options{ + IndentionStep: 2, + } + for _, o := range opts { + o(&options) + } + if options.Debug && options.Log == nil { + options.Log = log.Clone() + } + return options +} diff --git a/lego/sys/codec/render/core.go b/lego/sys/codec/render/core.go new file mode 100644 index 000000000..a62153d14 --- /dev/null +++ b/lego/sys/codec/render/core.go @@ -0,0 +1,45 @@ +package render + +import "go_dreamfactory/lego/sys/codec/core" + +const maxDepth = 10000 + +var hexDigits []byte +var valueTypes []core.ValueType + +func init() { + hexDigits = make([]byte, 256) + for i := 0; i < len(hexDigits); i++ { + hexDigits[i] = 255 + } + for i := '0'; i <= '9'; i++ { + hexDigits[i] = byte(i - '0') + } + for i := 'a'; i <= 'f'; i++ { + hexDigits[i] = byte((i - 'a') + 10) + } + for i := 'A'; i <= 'F'; i++ { + hexDigits[i] = byte((i - 'A') + 10) + } + valueTypes = make([]core.ValueType, 256) + for i := 0; i < len(valueTypes); i++ { + valueTypes[i] = core.InvalidValue + } + valueTypes['"'] = core.StringValue + valueTypes['-'] = core.NumberValue + valueTypes['0'] = core.NumberValue + valueTypes['1'] = core.NumberValue + valueTypes['2'] = core.NumberValue + valueTypes['3'] = core.NumberValue + valueTypes['4'] = core.NumberValue + valueTypes['5'] = core.NumberValue + valueTypes['6'] = core.NumberValue + valueTypes['7'] = core.NumberValue + valueTypes['8'] = core.NumberValue + valueTypes['9'] = core.NumberValue + valueTypes['t'] = core.BoolValue + valueTypes['f'] = core.BoolValue + valueTypes['n'] = core.NilValue + valueTypes['['] = core.ArrayValue + valueTypes['{'] = core.ObjectValue +} diff --git a/lego/sys/codec/render/json_extractor.go b/lego/sys/codec/render/json_extractor.go new file mode 100644 index 000000000..f12bc59a2 --- /dev/null +++ b/lego/sys/codec/render/json_extractor.go @@ -0,0 +1,823 @@ +package render + +import ( + "fmt" + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/utils" + "io" + "math/big" + "reflect" + "unicode/utf16" + + "github.com/modern-go/reflect2" +) + +func NewExtractor(codec core.ICodec) *JsonExtractor { + return &JsonExtractor{ + codec: codec, + buf: nil, + head: 0, + tail: 0, + depth: 0, + err: nil, + } +} + +type JsonExtractor struct { + codec core.ICodec + buf []byte + head int + tail int + depth int + err error +} + +func (this *JsonExtractor) ReadVal(obj interface{}) { + depth := this.depth + cacheKey := reflect2.RTypeOf(obj) + decoder := this.codec.GetDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(obj) + if typ == nil || typ.Kind() != reflect.Ptr { + this.reportError("ReadVal", "can only unmarshal into pointer") + return + } + decoder = this.codec.DecoderOf(typ) + } + ptr := reflect2.PtrOf(obj) + if ptr == nil { + this.reportError("ReadVal", "can not read into nil pointer") + return + } + decoder.Decode(ptr, this) + if this.depth != depth { + this.reportError("ReadVal", "unexpected mismatched nesting") + return + } +} +func (this *JsonExtractor) WhatIsNext() core.ValueType { + valueType := valueTypes[this.nextToken()] + this.unreadByte() + return valueType +} +func (this *JsonExtractor) Read() interface{} { + valueType := this.WhatIsNext() + switch valueType { + case core.StringValue: + return this.ReadString() + case core.NumberValue: + return this.ReadFloat64() + case core.NilValue: + this.skipFourBytes('n', 'u', 'l', 'l') + return nil + case core.BoolValue: + return this.ReadBool() + case core.ArrayValue: + arr := []interface{}{} + this.ReadArrayCB(func(extra core.IExtractor) bool { + var elem interface{} + extra.ReadVal(&elem) + arr = append(arr, elem) + return true + }) + return arr + case core.ObjectValue: + obj := map[string]interface{}{} + this.ReadMapCB(func(extra core.IExtractor, field string) bool { + var elem interface{} + this.ReadVal(&elem) + obj[field] = elem + return true + }) + return obj + default: + this.reportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) + return nil + } +} +func (this *JsonExtractor) ReadNil() (ret bool) { + c := this.nextToken() + if c == 'n' { + this.skipThreeBytes('u', 'l', 'l') // null + return true + } + this.unreadByte() + return false +} +func (this *JsonExtractor) ReadArrayStart() (ret bool) { + c := this.nextToken() + if c == '[' { + return true + } + this.reportError("ReadArrayStart", `expect [ but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) CheckNextIsArrayEnd() (ret bool) { + c := this.nextToken() + this.unreadByte() + if c == ']' { + return true + } + return +} +func (this *JsonExtractor) ReadArrayEnd() (ret bool) { + c := this.nextToken() + if c == ']' { + return true + } + this.reportError("ReadArrayEnd", `expect ] but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadObjectStart() (ret bool) { + c := this.nextToken() + if c == '{' { + return this.incrementDepth() + } + this.reportError("ReadObjectStart", `expect { but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) CheckNextIsObjectEnd() (ret bool) { + c := this.nextToken() + this.unreadByte() + if c == '}' { + return true + } + return +} +func (this *JsonExtractor) ReadObjectEnd() (ret bool) { + c := this.nextToken() + if c == '}' { + return this.decrementDepth() + } + this.reportError("ReadObjectEnd", `expect } but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadMemberSplit() (ret bool) { + c := this.nextToken() + if c == ',' { + return true + } + this.unreadByte() + return +} +func (this *JsonExtractor) ReadKVSplit() (ret bool) { + c := this.nextToken() + if c == ':' { + return true + } + this.reportError("ReadKVSplit", `expect : but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadKeyStart() (ret bool) { + c := this.nextToken() + if c == '"' { + return true + } + this.reportError("ReadKeyStart", `expect " but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadKeyEnd() (ret bool) { + c := this.nextToken() + if c == '"' { + return true + } + this.reportError("ReadKeyEnd", `expect " but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) Skip() { + c := this.nextToken() + switch c { + case '"': + this.skipString() + case 'n': + this.skipThreeBytes('u', 'l', 'l') // null + case 't': + this.skipThreeBytes('r', 'u', 'e') // true + case 'f': + this.skipFourBytes('a', 'l', 's', 'e') // false + case '0': + this.unreadByte() + this.ReadFloat32() + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + this.skipNumber() + case '[': + this.skipArray() + case '{': + this.skipObject() + default: + this.reportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) + return + } +} +func (this *JsonExtractor) ReadBool() (ret bool) { + c := this.nextToken() + if c == 't' { + this.skipThreeBytes('r', 'u', 'e') + return true + } + if c == 'f' { + this.skipFourBytes('a', 'l', 's', 'e') + return false + } + this.reportError("ReadBool", "expect t or f, but found "+string([]byte{c})) + return +} +func (this *JsonExtractor) ReadInt8() (ret int8) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt8ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt8", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt16() (ret int16) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt16ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt32() (ret int32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadInt64() (ret int64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadInt64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadInt64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint8() (ret uint8) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint8ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint8", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint16() (ret uint16) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint16ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint16", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint32() (ret uint32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadUint64() (ret uint64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadUint64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadUint64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadFloat32() (ret float32) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadFloat32ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadFloat32", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadFloat64() (ret float64) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadFloat64ForString(this.buf[this.head:]); err != nil { + this.reportError("ReadFloat64", err.Error()) + return + } + this.head += n + return +} +func (this *JsonExtractor) ReadString() (ret string) { + c := this.nextToken() + if c == '"' { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + if c == '"' { + ret = string(this.buf[this.head:i]) + this.head = i + 1 + return ret + } else if c == '\\' { + break + } else if c < ' ' { + this.reportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return + } + } + return this.readStringSlowPath() + } else if c == 'n' { + this.skipThreeBytes('u', 'l', 'l') + return "" + } + this.reportError("ReadString", `expects " or n, but found `+string([]byte{c})) + return +} +func (this *JsonExtractor) ResetBytes(d []byte) { + this.buf = d + this.head = 0 + this.tail = len(d) +} +func (this *JsonExtractor) Error() error { + return this.err +} +func (this *JsonExtractor) SetErr(err error) { + this.err = err +} + +//----------------------------------------------------------------------------------------------------------------------------------- +func (this *JsonExtractor) readByte() (ret byte) { + if this.head == this.tail { + return 0 + } + ret = this.buf[this.head] + this.head++ + return ret +} +func (this *JsonExtractor) readStringSlowPath() (ret string) { + var str []byte + var c byte + for this.err == nil { + c = this.readByte() + if c == '"' { + return string(str) + } + if c == '\\' { + c = this.readByte() + str = this.readEscapedChar(c, str) + } else { + str = append(str, c) + } + } + this.reportError("readStringSlowPath", "unexpected end of input") + return +} +func (this *JsonExtractor) readEscapedChar(c byte, str []byte) []byte { + switch c { + case 'u': + r := this.readU4() + if utf16.IsSurrogate(r) { + c = this.readByte() + if this.err != nil { + return nil + } + if c != '\\' { + this.unreadByte() + str = utils.AppendRune(str, r) + return str + } + c = this.readByte() + if this.err != nil { + return nil + } + if c != 'u' { + str = utils.AppendRune(str, r) + return this.readEscapedChar(c, str) + } + r2 := this.readU4() + if this.err != nil { + return nil + } + combined := utf16.DecodeRune(r, r2) + if combined == '\uFFFD' { + str = utils.AppendRune(str, r) + str = utils.AppendRune(str, r2) + } else { + str = utils.AppendRune(str, combined) + } + } else { + str = utils.AppendRune(str, r) + } + case '"': + str = append(str, '"') + case '\\': + str = append(str, '\\') + case '/': + str = append(str, '/') + case 'b': + str = append(str, '\b') + case 'f': + str = append(str, '\f') + case 'n': + str = append(str, '\n') + case 'r': + str = append(str, '\r') + case 't': + str = append(str, '\t') + default: + this.reportError("readEscapedChar", + `invalid escape char after \`) + return nil + } + return str +} +func (this *JsonExtractor) readU4() (ret rune) { + for i := 0; i < 4; i++ { + c := this.readByte() + if this.err != nil { + return + } + if c >= '0' && c <= '9' { + ret = ret*16 + rune(c-'0') + } else if c >= 'a' && c <= 'f' { + ret = ret*16 + rune(c-'a'+10) + } else if c >= 'A' && c <= 'F' { + ret = ret*16 + rune(c-'A'+10) + } else { + this.reportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) + return + } + } + return ret +} +func (this *JsonExtractor) nextToken() byte { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + this.head = i + 1 + return c + } + return 0 +} +func (this *JsonExtractor) unreadByte() { + if this.err != nil { + return + } + this.head-- + return +} +func (this *JsonExtractor) skipNumber() { + if !this.trySkipNumber() { + this.unreadByte() + if this.err != nil && this.err != io.EOF { + return + } + this.ReadFloat64() + if this.err != nil && this.err != io.EOF { + this.err = nil + this.ReadBigFloat() + } + } +} +func (this *JsonExtractor) ReadBigFloat() (ret *big.Float) { + var ( + n int + err error + ) + if ret, n, err = utils.ReadBigFloatForString(this.buf[this.head:]); err != nil { + this.reportError("ReadBigFloat", err.Error()) + return + } + this.head += n + return +} +func (iter *JsonExtractor) trySkipNumber() bool { + dotFound := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + case '.': + if dotFound { + iter.reportError("validateNumber", `more than one dot found in number`) + return true // already failed + } + if i+1 == iter.tail { + return false + } + c = iter.buf[i+1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + iter.reportError("validateNumber", `missing digit after dot`) + return true // already failed + } + dotFound = true + default: + switch c { + case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } + iter.head = i + return true // must be valid + } + return false // may be invalid + } + } + return false +} +func (this *JsonExtractor) skipString() { + if !this.trySkipString() { + this.unreadByte() + this.ReadString() + } +} +func (this *JsonExtractor) trySkipString() bool { + for i := this.head; i < this.tail; i++ { + c := this.buf[i] + if c == '"' { + this.head = i + 1 + return true // valid + } else if c == '\\' { + return false + } else if c < ' ' { + this.reportError("trySkipString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return true // already failed + } + } + return false +} +func (this *JsonExtractor) skipObject() { + this.unreadByte() + this.ReadObjectCB(func(extra core.IExtractor, field string) bool { + extra.Skip() + return true + }) +} +func (this *JsonExtractor) skipArray() { + this.unreadByte() + this.ReadArrayCB(func(extra core.IExtractor) bool { + extra.Skip() + return true + }) +} +func (this *JsonExtractor) skipThreeBytes(b1, b2, b3 byte) { + if this.readByte() != b1 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if this.readByte() != b2 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if this.readByte() != b3 { + this.reportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } +} +func (this *JsonExtractor) skipFourBytes(b1, b2, b3, b4 byte) { + if this.readByte() != b1 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b2 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b3 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if this.readByte() != b4 { + this.reportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } +} +func (this *JsonExtractor) reportError(operation string, msg string) { + if this.err != nil { + if this.err != io.EOF { + return + } + } + peekStart := this.head - 10 + if peekStart < 0 { + peekStart = 0 + } + peekEnd := this.head + 10 + if peekEnd > this.tail { + peekEnd = this.tail + } + parsing := string(this.buf[peekStart:peekEnd]) + contextStart := this.head - 50 + if contextStart < 0 { + contextStart = 0 + } + contextEnd := this.head + 50 + if contextEnd > this.tail { + contextEnd = this.tail + } + context := string(this.buf[contextStart:contextEnd]) + this.err = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", + operation, msg, this.head-peekStart, parsing, context) +} +func (this *JsonExtractor) incrementDepth() (success bool) { + this.depth++ + if this.depth <= maxDepth { + return true + } + this.reportError("incrementDepth", "exceeded max depth") + return false +} +func (this *JsonExtractor) decrementDepth() (success bool) { + this.depth-- + if this.depth >= 0 { + return true + } + this.reportError("decrementDepth", "unexpected negative nesting") + return false +} +func (iter *JsonExtractor) ReadObjectCB(callback func(core.IExtractor, string) bool) bool { + c := iter.nextToken() + var field string + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.reportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.reportError("ReadObjectCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.reportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *JsonExtractor) ReadMapCB(callback func(core.IExtractor, string) bool) bool { + c := iter.nextToken() + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + if iter.nextToken() != ':' { + iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + if iter.nextToken() != ':' { + iter.reportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.reportError("ReadMapCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.reportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *JsonExtractor) ReadArrayCB(callback func(core.IExtractor) bool) (ret bool) { + c := iter.nextToken() + if c == '[' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != ']' { + iter.reportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + return iter.decrementDepth() + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.reportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) + return false +} diff --git a/lego/sys/codec/render/json_stream.go b/lego/sys/codec/render/json_stream.go new file mode 100644 index 000000000..4fa115f40 --- /dev/null +++ b/lego/sys/codec/render/json_stream.go @@ -0,0 +1,206 @@ +package render + +import ( + "go_dreamfactory/lego/sys/codec/core" + "go_dreamfactory/lego/sys/codec/utils" + + "github.com/modern-go/reflect2" +) + +func NewStream(codec core.ICodec, bufSize int) *JsonStream { + return &JsonStream{ + codec: codec, + buf: make([]byte, 0, bufSize), + err: nil, + indention: 0, + } +} + +type JsonStream struct { + codec core.ICodec + err error + buf []byte + indention int +} + +//写入对象 +func (this *JsonStream) WriteVal(val interface{}) { + if nil == val { + this.WriteNil() + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := this.codec.GetEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = this.codec.EncoderOf(typ) + } + encoder.Encode(reflect2.PtrOf(val), this) +} + +func (this *JsonStream) WriteNil() { + this.writeFourBytes('n', 'u', 'l', 'l') +} +func (this *JsonStream) WriteEmptyArray() { + this.writeTwoBytes('[', ']') +} +func (this *JsonStream) WriteArrayStart() { + this.indention += this.codec.Options().IndentionStep + this.writeByte('[') + this.writeIndention(0) +} +func (this *JsonStream) WriteArrayEnd() { + this.writeIndention(this.codec.Options().IndentionStep) + this.indention -= this.codec.Options().IndentionStep + this.writeByte(']') +} +func (this *JsonStream) WriteEmptyObject() { + this.writeTwoBytes('{', '}') +} +func (this *JsonStream) WriteObjectStart() { + this.indention += this.codec.Options().IndentionStep + this.writeByte('{') + this.writeIndention(0) +} +func (this *JsonStream) WriteObjectEnd() { + this.writeIndention(this.codec.Options().IndentionStep) + this.indention -= this.codec.Options().IndentionStep + this.writeByte('}') +} +func (this *JsonStream) WriteMemberSplit() { + this.writeByte(',') + this.writeIndention(0) +} +func (this *JsonStream) WriteKVSplit() { + this.writeByte(':') +} +func (this *JsonStream) WriteKeyStart() { + this.writeByte('"') +} +func (this *JsonStream) WriteKeyEnd() { + this.writeByte('"') +} +func (this *JsonStream) WriteObjectFieldName(val string) { + this.WriteString(val) + if this.indention > 0 { + this.writeTwoBytes(':', ' ') + } else { + this.writeByte(':') + } +} +func (this *JsonStream) WriteBool(val bool) { + if val { + this.writeTrue() + } else { + this.writeFalse() + } +} +func (this *JsonStream) WriteInt8(val int8) { + utils.WriteInt8ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt16(val int16) { + utils.WriteInt16ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt32(val int32) { + utils.WriteInt32ToString(&this.buf, val) +} +func (this *JsonStream) WriteInt64(val int64) { + utils.WriteInt64ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint8(val uint8) { + utils.WriteUint8ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint16(val uint16) { + utils.WriteUint16ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint32(val uint32) { + utils.WriteUint32ToString(&this.buf, val) +} +func (this *JsonStream) WriteUint64(val uint64) { + utils.WriteUint64ToString(&this.buf, val) +} +func (this *JsonStream) WriteFloat32(val float32) { + utils.WriteFloat32ToString(&this.buf, val) +} +func (this *JsonStream) WriteFloat64(val float64) { + utils.WriteFloat64ToString(&this.buf, val) +} +func (this *JsonStream) WriteString(val string) { + valLen := len(val) + this.buf = append(this.buf, '"') + i := 0 + for ; i < valLen; i++ { + c := val[i] + if c > 31 && c != '"' && c != '\\' { + this.buf = append(this.buf, c) + } else { + break + } + } + if i == valLen { + this.buf = append(this.buf, '"') + return + } + utils.WriteStringSlowPath(&this.buf, i, val, valLen) +} +func (this *JsonStream) WriteBytes(val []byte) { + this.buf = append(this.buf, val...) +} +func (this *JsonStream) Reset(bufSize int) { + this.buf = make([]byte, 0, bufSize) + this.err = nil + this.indention = 0 + return +} +func (this *JsonStream) Buffer() []byte { + return this.buf +} +func (this *JsonStream) Error() error { + return this.err +} +func (this *JsonStream) SetErr(err error) { + this.err = err +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +// WriteTrue write true to stream +func (stream *JsonStream) writeTrue() { + stream.writeFourBytes('t', 'r', 'u', 'e') +} + +// WriteFalse write false to stream +func (stream *JsonStream) writeFalse() { + stream.writeFiveBytes('f', 'a', 'l', 's', 'e') +} + +func (this *JsonStream) writeByte(c byte) { + this.buf = append(this.buf, c) +} + +func (this *JsonStream) writeTwoBytes(c1 byte, c2 byte) { + this.buf = append(this.buf, c1, c2) +} + +func (this *JsonStream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { + this.buf = append(this.buf, c1, c2, c3) +} + +func (this *JsonStream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { + this.buf = append(this.buf, c1, c2, c3, c4) +} + +func (this *JsonStream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { + this.buf = append(this.buf, c1, c2, c3, c4, c5) +} + +func (stream *JsonStream) writeIndention(delta int) { + if stream.indention == 0 { + return + } + stream.writeByte('\n') + toWrite := stream.indention - delta + for i := 0; i < toWrite; i++ { + stream.buf = append(stream.buf, ' ') + } +} diff --git a/lego/sys/codec/sys_test.go b/lego/sys/codec/sys_test.go new file mode 100644 index 000000000..321e593e4 --- /dev/null +++ b/lego/sys/codec/sys_test.go @@ -0,0 +1,106 @@ +package codec_test + +import ( + "fmt" + "reflect" + "testing" + + "go_dreamfactory/lego/sys/codec" + "go_dreamfactory/lego/sys/log" + + "github.com/modern-go/reflect2" +) + +type TestData struct { + Name string + Value int + Array []interface{} + Data map[string]interface{} +} +type Test1Data struct { + Name string + Value int +} + +func Test_sys_slice(t *testing.T) { + if err := log.OnInit(nil); err != nil { + fmt.Printf("log init err:%v", err) + return + } + if sys, err := codec.NewSys(); err != nil { + fmt.Printf("gin init err:%v", err) + } else { + data := []*Test1Data{{"liwe", 1}, {"liwe2", 2}} + d, err := sys.MarshalJson(data) + fmt.Printf("codec Marshal d:%s err:%v", d, err) + data = []*Test1Data{} + err = sys.UnmarshalJson(d, &data) + fmt.Printf("codec UnmarshalJson data:%v err:%v", data, err) + } +} +func Test_sys_json(t *testing.T) { + if err := log.OnInit(nil); err != nil { + fmt.Printf("log init err:%v", err) + return + } + if sys, err := codec.NewSys(); err != nil { + fmt.Printf("gin init err:%v", err) + } else { + d, err := sys.MarshalJson(&TestData{Name: "http://liwei1dao.com?asd=1&dd=1", Value: 10, Array: []interface{}{1, "dajiahao", &Test1Data{Name: "liwe1dao", Value: 123}}, Data: map[string]interface{}{"hah": 1, "asd": 999}}) + fmt.Printf("codec Marshal d:%s err:%v", d, err) + data := &TestData{} + err = sys.UnmarshalJson(d, data) + fmt.Printf("codec UnmarshalJson data:%v err:%v", data, err) + } +} + +func Test_sys_mapjson(t *testing.T) { + if err := log.OnInit(nil); err != nil { + fmt.Printf("log init err:%v", err) + return + } + if sys, err := codec.NewSys(); err != nil { + fmt.Printf("gin init err:%v", err) + } else { + m := map[string]interface{}{"liwe": 123, "aasd": "123"} + fmt.Printf("codec Marshal m:%s err:%v", m, err) + d, err := sys.MarshalMapJson(&TestData{Name: "http://liwei1dao.com?asd=1&dd=1", Value: 10, Array: []interface{}{1, "dajiahao", &Test1Data{Name: "liwe1dao", Value: 123}}, Data: map[string]interface{}{"hah": 1, "asd": 999}}) + fmt.Printf("codec Marshal d:%s err:%v", d, err) + data := &TestData{} + err = sys.UnmarshalMapJson(d, data) + fmt.Printf("codec UnmarshalJson data:%v err:%v", data, err) + } +} + +func Test_sys_reflect2(t *testing.T) { + data := []*Test1Data{} + ptr := reflect2.TypeOf(&data) + kind := ptr.Kind() + switch kind { + case reflect.Interface: + return + case reflect.Struct: + return + case reflect.Array: + return + case reflect.Slice: + return + case reflect.Map: + return + case reflect.Ptr: + ptrType := ptr.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + kind = elemType.Kind() + if kind == reflect.Slice { + sliceelem := elemType.(*reflect2.UnsafeSliceType).Elem() + sliceelemkind := sliceelem.Kind() + if sliceelemkind == reflect.Ptr { + return + } + return + } + return + default: + return + } +} diff --git a/lego/sys/codec/utils/float.go b/lego/sys/codec/utils/float.go new file mode 100644 index 000000000..58c1a2b8d --- /dev/null +++ b/lego/sys/codec/utils/float.go @@ -0,0 +1,416 @@ +package utils + +import ( + "errors" + "fmt" + "math" + "math/big" + "strconv" + "strings" + "unsafe" +) + +var pow10 []uint64 +var floatDigits []int8 + +const invalidCharForNumber = int8(-1) +const endOfNumber = int8(-2) +const dotInNumber = int8(-3) + +func init() { + pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} + floatDigits = make([]int8, 256) + for i := 0; i < len(floatDigits); i++ { + floatDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + floatDigits[i] = i - int8('0') + } + floatDigits[','] = endOfNumber + floatDigits[']'] = endOfNumber + floatDigits['}'] = endOfNumber + floatDigits[' '] = endOfNumber + floatDigits['\t'] = endOfNumber + floatDigits['\n'] = endOfNumber + floatDigits['.'] = dotInNumber +} + +//Read Float For String------------------------------------------------------------------------------------------------------------------------------------------------------------- +//从字符串中读取float 对象 +func ReadBigFloatForString(buf []byte) (ret *big.Float, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err == nil { + return + } + prec := 64 + if len(str) > prec { + prec = len(str) + } + ret, _, err = big.ParseFloat(str, 10, uint(prec), big.ToZero) + return +} +func ReadFloat32ForString(buf []byte) (ret float32, n int, err error) { + if buf[0] == '-' { + ret, n, err = readPositiveFloat32(buf[1:]) + ret = -ret + return + } + return readPositiveFloat32(buf) +} +func ReadFloat64ForString(buf []byte) (ret float64, n int, err error) { + if buf[0] == '-' { + ret, n, err = readPositiveFloat64(buf[1:]) + ret = -ret + return + } + return readPositiveFloat64(buf) +} + +//读取float32 +func readPositiveFloat32(buf []byte) (ret float32, n int, err error) { + i := 0 + // first char + if len(buf) == 0 { + return readFloat32SlowPath(buf) + } + c := buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat32SlowPath(buf) + case endOfNumber: + err = errors.New("readFloat32 empty number") + return + case dotInNumber: + err = errors.New("readFloat32 leading dot is invalid") + return + case 0: + if i == len(buf) { + return readFloat32SlowPath(buf) + } + c = buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + err = errors.New("readFloat32 leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat32SlowPath(buf) + case endOfNumber: + n = i + ret = float32(value) + return + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return readFloat32SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == len(buf) { + return readFloat32SlowPath(buf) + } + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + n = i + ret = float32(float64(value) / float64(pow10[decimalPlaces])) + return + } + // too many decimal places + return readFloat32SlowPath(buf) + case invalidCharForNumber, dotInNumber: + return readFloat32SlowPath(buf) + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return readFloat32SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return readFloat32SlowPath(buf) +} +func readFloat32SlowPath(buf []byte) (ret float32, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err != nil { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + err = errors.New(errMsg) + return + } + var val float64 + if val, err = strconv.ParseFloat(str, 32); err != nil { + return + } + ret = float32(val) + return +} + +//读取float64 +func readPositiveFloat64(buf []byte) (ret float64, n int, err error) { + i := 0 + // first char + if i == len(buf) { + return readFloat64SlowPath(buf) + } + c := buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat64SlowPath(buf) + case endOfNumber: + err = errors.New("readFloat64 empty number") + return + case dotInNumber: + err = errors.New("readFloat64 leading dot is invalid") + return + case 0: + if i == len(buf) { + return readFloat64SlowPath(buf) + } + c = buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + err = errors.New("readFloat64 leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return readFloat64SlowPath(buf) + case endOfNumber: + n = i + ret = float64(value) + return + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return readFloat64SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == len(buf) { + return readFloat64SlowPath(buf) + } + for ; i < len(buf); i++ { + c = buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + n = i + ret = float64(value) / float64(pow10[decimalPlaces]) + return + } + // too many decimal places + return readFloat64SlowPath(buf) + case invalidCharForNumber, dotInNumber: + return readFloat64SlowPath(buf) + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return readFloat64SlowPath(buf) + } + value = (value << 3) + (value << 1) + uint64(ind) + if value > maxFloat64 { + return readFloat64SlowPath(buf) + } + } + } + return readFloat64SlowPath(buf) +} + +func readFloat64SlowPath(buf []byte) (ret float64, n int, err error) { + var str string + if str, n, err = readNumberAsString(buf); err != nil { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + err = fmt.Errorf("readFloat64SlowPath:%v", errMsg) + return + } + ret, err = strconv.ParseFloat(str, 64) + return +} + +//读取字符串数字 +func readNumberAsString(buf []byte) (ret string, n int, err error) { + strBuf := [16]byte{} + str := strBuf[0:0] +load_loop: + for i := 0; i < len(buf); i++ { + c := buf[i] + switch c { + case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + str = append(str, c) + continue + default: + n = i + break load_loop + } + } + if len(str) == 0 { + err = errors.New("readNumberAsString invalid number") + } + ret = *(*string)(unsafe.Pointer(&str)) + return +} + +//字符串float 错误检验 +func validateFloat(str string) string { + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} + +//Write Float To String------------------------------------------------------------------------------------------------------------------------------------------------------------- +func WriteFloat32ToString(buff *[]byte, val float32) (err error) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(float64(val)) + fmt := byte('f') + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + *buff = strconv.AppendFloat(*buff, float64(val), fmt, -1, 32) + return +} + +//float32 写入只有 6 位精度的流,但速度要快得多 +func WriteFloat32LossyToString(buf *[]byte, val float32) (err error) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + WriteChar(buf, '-') + val = -val + } + if val > 0x4ffffff { + WriteFloat32ToString(buf, val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val)*float64(exp) + 0.5) + WriteUint64ToString(buf, lval/exp) + fval := lval % exp + if fval == 0 { + return + } + WriteChar(buf, '.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + WriteChar(buf, '0') + } + WriteUint64ToString(buf, fval) + temp := *buf + for temp[len(temp)-1] == '0' { + temp = temp[:len(temp)-1] + } + buf = &temp + return +} + +func WriteFloat64ToString(buf *[]byte, val float64) (err error) { + if math.IsInf(val, 0) || math.IsNaN(val) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + *buf = strconv.AppendFloat(*buf, float64(val), fmt, -1, 64) + return +} + +//将 float64 写入只有 6 位精度的流,但速度要快得多 +func WriteFloat64LossyToString(buf *[]byte, val float64) (err error) { + if math.IsInf(val, 0) || math.IsNaN(val) { + err = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + WriteChar(buf, '-') + val = -val + } + if val > 0x4ffffff { + WriteFloat64ToString(buf, val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(val*float64(exp) + 0.5) + WriteUint64ToString(buf, lval/exp) + fval := lval % exp + if fval == 0 { + return + } + WriteChar(buf, '.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + WriteChar(buf, '0') + } + WriteUint64ToString(buf, fval) + temp := *buf + for temp[len(temp)-1] == '0' { + temp = temp[:len(temp)-1] + } + buf = &temp + return +} diff --git a/lego/sys/codec/utils/int.go b/lego/sys/codec/utils/int.go new file mode 100644 index 000000000..ba3c9b483 --- /dev/null +++ b/lego/sys/codec/utils/int.go @@ -0,0 +1,543 @@ +package utils + +import ( + "errors" + "math" + "strconv" +) + +var digits []uint32 +var intDigits []int8 + +const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 +const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 +const maxFloat64 = 1<<53 - 1 + +func init() { + digits = make([]uint32, 1000) + for i := uint32(0); i < 1000; i++ { + digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' + if i < 10 { + digits[i] += 2 << 24 + } else if i < 100 { + digits[i] += 1 << 24 + } + } + + intDigits = make([]int8, 256) + for i := 0; i < len(intDigits); i++ { + intDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + intDigits[i] = i - int8('0') + } +} + +//Read Int For String-------------------------------------------------------------------------------------------------------------------------------- +func ReadInt8ForString(buf []byte) (ret int8, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt8+1 { + err = errors.New("ReadInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int8(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt8 { + err = errors.New("ReadInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int8(val) + return +} + +func ReadInt16ForString(buf []byte) (ret int16, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt16+1 { + err = errors.New("ReadInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int16(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt16 { + err = errors.New("ReadInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int16(val) + return +} + +func ReadInt32ForString(buf []byte) (ret int32, n int, err error) { + var ( + val uint32 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint32ForString(buf[1:]) + if val > math.MaxInt32+1 { + err = errors.New("ReadInt32ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int32(val) + return + } + val, n, err = ReadUint32ForString(buf) + if val > math.MaxInt32 { + err = errors.New("ReadInt32ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int32(val) + return +} + +func ReadInt64ForString(buf []byte) (ret int64, n int, err error) { + var ( + val uint64 + ) + c := buf[0] + if c == '-' { + val, n, err = ReadUint64ForString(buf[1:]) + if val > math.MaxInt64+1 { + err = errors.New("ReadInt64ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = -int64(val) + return + } + val, n, err = ReadUint64ForString(buf) + if val > math.MaxInt64 { + err = errors.New("ReadInt64ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = int64(val) + return +} + +func ReadUint8ForString(buf []byte) (ret uint8, n int, err error) { + var ( + val uint32 + ) + val, n, err = ReadUint32ForString(buf) + if val > math.MaxUint8 { + err = errors.New("ReadUInt8ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = uint8(val) + return +} + +func ReadUint16ForString(buf []byte) (ret uint16, n int, err error) { + var ( + val uint32 + ) + val, n, err = ReadUint32ForString(buf) + if val > math.MaxUint16 { + err = errors.New("ReadUInt16ForString overflow: " + strconv.FormatInt(int64(val), 10)) + return + } + ret = uint16(val) + return +} + +func ReadUint32ForString(buf []byte) (ret uint32, n int, err error) { + ind := intDigits[buf[0]] + if ind == 0 { + err = assertInteger(buf[1:]) + return + } + if ind == invalidCharForNumber { + err = errors.New("ReadUint32ForString unexpected character: " + string([]byte{byte(ind)})) + return + } + ret = uint32(ind) + if len(buf) > 10 { + i := 0 + ind2 := intDigits[buf[i]] + if ind2 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + i++ + ind3 := intDigits[buf[i]] + if ind3 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10 + uint32(ind2) + return + } + i++ + ind4 := intDigits[buf[i]] + if ind4 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100 + uint32(ind2)*10 + uint32(ind3) + return + } + i++ + ind5 := intDigits[buf[i]] + if ind5 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) + return + } + i++ + ind6 := intDigits[buf[i]] + if ind6 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) + return + } + i++ + ind7 := intDigits[buf[i]] + if ind7 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) + return + } + i++ + ind8 := intDigits[buf[i]] + if ind8 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) + return + } + i++ + ind9 := intDigits[buf[i]] + ret = ret*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) + n = i + if ind9 == invalidCharForNumber { + err = assertInteger(buf[i:]) + return + } + } + for i := 1; i < len(buf); i++ { + ind = intDigits[buf[i]] + if ind == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + if ret > uint32SafeToMultiply10 { + value2 := (ret << 3) + (ret << 1) + uint32(ind) + if value2 < ret { + err = errors.New("ReadUint32ForString overflow") + return + } + ret = value2 + continue + } + ret = (ret << 3) + (ret << 1) + uint32(ind) + } + return +} + +func ReadUint64ForString(buf []byte) (ret uint64, n int, err error) { + ind := intDigits[buf[0]] + if ind == 0 { + err = assertInteger(buf[1:]) + return + } + if ind == invalidCharForNumber { + err = errors.New("ReadUint64ForString unexpected character: " + string([]byte{byte(ind)})) + return + } + ret = uint64(ind) + if len(buf) > 10 { + i := 0 + ind2 := intDigits[buf[i]] + if ind2 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + i++ + ind3 := intDigits[buf[i]] + if ind3 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10 + uint64(ind2) + return + } + i++ + ind4 := intDigits[buf[i]] + if ind4 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100 + uint64(ind2)*10 + uint64(ind3) + return + } + i++ + ind5 := intDigits[buf[i]] + if ind5 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) + return + } + i++ + ind6 := intDigits[buf[i]] + if ind6 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) + return + } + i++ + ind7 := intDigits[buf[i]] + if ind7 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) + return + } + i++ + ind8 := intDigits[buf[i]] + if ind8 == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + ret = ret*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) + return + } + i++ + ind9 := intDigits[buf[i]] + ret = ret*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) + n = i + if ind9 == invalidCharForNumber { + err = assertInteger(buf[i:]) + return + } + } + for i := 1; i < len(buf); i++ { + ind = intDigits[buf[i]] + if ind == invalidCharForNumber { + n = i + err = assertInteger(buf[i:]) + return + } + if ret > uint64SafeToMultiple10 { + value2 := (ret << 3) + (ret << 1) + uint64(ind) + if value2 < ret { + err = errors.New("ReadUint64ForString overflow") + return + } + ret = value2 + continue + } + ret = (ret << 3) + (ret << 1) + uint64(ind) + } + return +} + +func assertInteger(buf []byte) (err error) { + if len(buf) > 0 && buf[0] == '.' { + err = errors.New("assertInteger can not decode float as int") + } + return +} + +//Write Int To String-------------------------------------------------------------------------------------------------------------------------------- +func WriteChar(buff *[]byte, c byte) { + *buff = append(*buff, c) +} + +// WriteUint8 write uint8 to stream +func WriteUint8ToString(buf *[]byte, val uint8) { + *buf = writeFirstBuf(*buf, digits[val]) + return +} + +// WriteInt8 write int8 to stream +func WriteInt8ToString(buf *[]byte, nval int8) { + var val uint8 + if nval < 0 { + val = uint8(-nval) + *buf = append(*buf, '-') + } else { + val = uint8(nval) + } + *buf = writeFirstBuf(*buf, digits[val]) + return +} + +// WriteUint16 write uint16 to stream +func WriteUint16ToString(buf *[]byte, val uint16) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt16 write int16 to stream +func WriteInt16ToString(buf *[]byte, nval int16) { + var val uint16 + if nval < 0 { + val = uint16(-nval) + *buf = append(*buf, '-') + } else { + val = uint16(nval) + } + WriteUint16ToString(buf, val) + return +} + +// WriteUint32 write uint32 to stream +func WriteUint32ToString(buf *[]byte, val uint32) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + *buf = writeFirstBuf(*buf, digits[q2]) + } else { + r3 := q2 - q3*1000 + *buf = append(*buf, byte(q3+'0')) + *buf = writeBuf(*buf, digits[r3]) + } + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt32 write int32 to stream +func WriteInt32ToString(buf *[]byte, nval int32) { + var val uint32 + if nval < 0 { + val = uint32(-nval) + *buf = append(*buf, '-') + } else { + val = uint32(nval) + } + WriteUint32ToString(buf, val) + return +} + +// WriteUint64 write uint64 to stream +func WriteUint64ToString(buf *[]byte, val uint64) { + q1 := val / 1000 + if q1 == 0 { + *buf = writeFirstBuf(*buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + *buf = writeFirstBuf(*buf, digits[q1]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + *buf = writeFirstBuf(*buf, digits[q2]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + *buf = writeFirstBuf(*buf, digits[q3]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + *buf = writeFirstBuf(*buf, digits[q4]) + *buf = writeBuf(*buf, digits[r4]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + *buf = writeFirstBuf(*buf, digits[q5]) + } else { + *buf = writeFirstBuf(*buf, digits[q6]) + r6 := q5 - q6*1000 + *buf = writeBuf(*buf, digits[r6]) + } + *buf = writeBuf(*buf, digits[r5]) + *buf = writeBuf(*buf, digits[r4]) + *buf = writeBuf(*buf, digits[r3]) + *buf = writeBuf(*buf, digits[r2]) + *buf = writeBuf(*buf, digits[r1]) + return +} + +// WriteInt64 write int64 to stream +func WriteInt64ToString(buf *[]byte, nval int64) { + var val uint64 + if nval < 0 { + val = uint64(-nval) + *buf = append(*buf, '-') + } else { + val = uint64(nval) + } + WriteUint64ToString(buf, val) + return +} + +// WriteInt write int to stream +func WriteIntToString(buf *[]byte, val int) { + WriteInt64ToString(buf, int64(val)) + return +} + +// WriteUint write uint to stream +func WriteUint(buf *[]byte, val uint) { + WriteUint64ToString(buf, uint64(val)) + return +} + +func writeFirstBuf(space []byte, v uint32) []byte { + start := v >> 24 + if start == 0 { + space = append(space, byte(v>>16), byte(v>>8)) + } else if start == 1 { + space = append(space, byte(v>>8)) + } + space = append(space, byte(v)) + return space +} + +func writeBuf(buf []byte, v uint32) []byte { + return append(buf, byte(v>>16), byte(v>>8), byte(v)) +} diff --git a/lego/sys/codec/utils/string.go b/lego/sys/codec/utils/string.go new file mode 100644 index 000000000..fb92add1b --- /dev/null +++ b/lego/sys/codec/utils/string.go @@ -0,0 +1,349 @@ +package utils + +import "unicode/utf8" + +var htmlSafeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': false, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': false, + '=': true, + '>': false, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var safeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': true, + '=': true, + '>': true, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var hex = "0123456789abcdef" + +func WriteStringSlowPathWithHTMLEscaped(buf *[]byte, i int, s string, valLen int) { + start := i + // for the remaining parts, we process them char by char + for i < valLen { + if b := s[i]; b < utf8.RuneSelf { + if htmlSafeSet[b] { + i++ + continue + } + if start < i { + *buf = append(*buf, s[start:i]...) + } + switch b { + case '\\', '"': + *buf = append(*buf, '\\', b) + case '\n': + *buf = append(*buf, '\\', 'n') + case '\r': + *buf = append(*buf, '\\', 'r') + case '\t': + *buf = append(*buf, '\\', 't') + default: + *buf = append(*buf, `\u00`...) + *buf = append(*buf, hex[b>>4], hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + *buf = append(*buf, s[start:i]...) + } + *buf = append(*buf, `\ufffd`...) + i++ + start = i + continue + } + + if c == '\u2028' || c == '\u2029' { + if start < i { + *buf = append(*buf, s[start:i]...) + } + *buf = append(*buf, `\u202`...) + *buf = append(*buf, hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(s) { + *buf = append(*buf, s[start:]...) + } + *buf = append(*buf, '"') +} + +func WriteStringSlowPath(buf *[]byte, i int, s string, valLen int) { + start := i + for i < valLen { + if b := s[i]; b < utf8.RuneSelf { + if safeSet[b] { + i++ + continue + } + if start < i { + *buf = append(*buf, s[start:i]...) + } + switch b { + case '\\', '"': + *buf = append(*buf, '\\', b) + case '\n': + *buf = append(*buf, '\\', 'n') + case '\r': + *buf = append(*buf, '\\', 'r') + case '\t': + *buf = append(*buf, '\\', 't') + default: + *buf = append(*buf, `\u00`...) + *buf = append(*buf, hex[b>>4], hex[b&0xF]) + } + i++ + start = i + continue + } + i++ + continue + } + if start < len(s) { + *buf = append(*buf, s[start:]...) + } + *buf = append(*buf, '"') +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + + surrogateMin = 0xD800 + surrogateMax = 0xDFFF + + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. + runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" +) + +func AppendRune(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p = append(p, byte(r)) + return p + case i <= rune2Max: + p = append(p, t2|byte(r>>6)) + p = append(p, tx|byte(r)&maskx) + return p + case i > maxRune, surrogateMin <= i && i <= surrogateMax: + r = runeError + fallthrough + case i <= rune3Max: + p = append(p, t3|byte(r>>12)) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + default: + p = append(p, t4|byte(r>>18)) + p = append(p, tx|byte(r>>12)&maskx) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + } +} diff --git a/lego/sys/gin/core.go b/lego/sys/gin/core.go index bd388b0ad..c35264623 100644 --- a/lego/sys/gin/core.go +++ b/lego/sys/gin/core.go @@ -1,9 +1,14 @@ package gin import ( + "fmt" "net/http" + "reflect" + "sort" + "strings" "go_dreamfactory/lego/sys/gin/engine" + "go_dreamfactory/lego/utils/crypto/md5" ) type ISys interface { @@ -71,3 +76,41 @@ func Static(relativePath string, root string) engine.IRoutes { func StaticFS(relativePath string, fs http.FileSystem) engine.IRoutes { return defsys.StaticFS(relativePath, fs) } + +//签名接口 +func ParamSign(key string, param map[string]interface{}) (sign string) { + var keys []string + for k, _ := range param { + keys = append(keys, k) + } + sort.Strings(keys) + builder := strings.Builder{} + for _, v := range keys { + builder.WriteString(v) + builder.WriteString("=") + switch reflect.TypeOf(param[v]).Kind() { + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64, + reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr, + reflect.Float32, + reflect.Float64: + builder.WriteString(fmt.Sprintf("%d", param[v])) + break + default: + builder.WriteString(fmt.Sprintf("%s", param[v])) + break + } + builder.WriteString("&") + } + builder.WriteString("key=" + key) + sign = md5.MD5EncToLower(builder.String()) + return +} diff --git a/lego/sys/log/core.go b/lego/sys/log/core.go index 63f23324d..a9024acfe 100644 --- a/lego/sys/log/core.go +++ b/lego/sys/log/core.go @@ -50,7 +50,10 @@ func NewSys(option ...Option) (sys ILog, err error) { } func Clone(option ...Option) ILog { - return defsys.Clone(option...) + if defsys != nil { + return defsys.Clone(option...) + } + return nil } func Debug(msg string, fields ...Field) { defsys.Debug(msg, fields...) } diff --git a/lego/sys/mgo/mgo.go b/lego/sys/mgo/mgo.go index f35e2fa7d..47bd1b5b6 100644 --- a/lego/sys/mgo/mgo.go +++ b/lego/sys/mgo/mgo.go @@ -9,7 +9,6 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/mongo/readconcern" "go.mongodb.org/mongo-driver/mongo/readpref" ) @@ -31,12 +30,12 @@ func (this *Mongodb) init() (err error) { // return fmt.Errorf("数据库设置辅助节点 err=%s", err.Error()) // } // wc := writeconcern.New(writeconcern.W(1)) - readconcern.Majority() + // readconcern.Majority() //链接mongo服务 opt := options.Client().ApplyURI(this.options.MongodbUrl) // opt.SetLocalThreshold(3 * time.Second) //只使用与mongo操作耗时小于3秒的 // opt.SetMaxConnIdleTime(5 * time.Second) //指定连接可以保持空闲的最大毫秒数 - opt.SetMaxPoolSize(this.options.MaxPoolSize) //使用最大的连接数 + // opt.SetMaxPoolSize(this.options.MaxPoolSize) //使用最大的连接数 // opt.SetReadPreference(want) //表示只使用辅助节点 // opt.SetReadConcern(readconcern.Majority()) //指定查询应返回实例的最新数据确认为,已写入副本集中的大多数成员 // opt.SetWriteConcern(wc) //请求确认写操作传播到大多数mongod实例 @@ -48,7 +47,6 @@ func (this *Mongodb) init() (err error) { return fmt.Errorf("数据库不可用 err=%s", err.Error()) } this.Database = client.Database(this.options.MongodbDatabase) - } return } diff --git a/lego/sys/redis/cluster/core.go b/lego/sys/redis/cluster/core.go index 3c5148b85..bfc85f786 100644 --- a/lego/sys/redis/cluster/core.go +++ b/lego/sys/redis/cluster/core.go @@ -2,15 +2,14 @@ package cluster import ( "context" - "go_dreamfactory/lego/utils/codec" + "go_dreamfactory/lego/sys/redis/core" "time" "github.com/go-redis/redis/v8" ) func NewSys(RedisUrl []string, RedisPassword string, timeOut time.Duration, - encode codec.IEncoder, - decode codec.IDecoder, + codec core.ICodec, ) (sys *Redis, err error) { var ( client *redis.ClusterClient @@ -22,8 +21,7 @@ func NewSys(RedisUrl []string, RedisPassword string, timeOut time.Duration, sys = &Redis{ client: client, timeOut: timeOut, - encode: encode, - decode: decode, + codec: codec, } _, err = sys.Ping() return @@ -32,8 +30,7 @@ func NewSys(RedisUrl []string, RedisPassword string, timeOut time.Duration, type Redis struct { client *redis.ClusterClient timeOut time.Duration - encode codec.IEncoder - decode codec.IDecoder + codec core.ICodec } func (this *Redis) getContext() (ctx context.Context) { diff --git a/lego/sys/redis/cluster/hash.go b/lego/sys/redis/cluster/hash.go index 55bed3662..7c36be40c 100644 --- a/lego/sys/redis/cluster/hash.go +++ b/lego/sys/redis/cluster/hash.go @@ -36,7 +36,7 @@ func (this *Redis) HMSet(key string, v interface{}) (err error) { agrs = append(agrs, "HMSET") agrs = append(agrs, key) var data map[string]string - if data, err = this.encode.EncoderToMapString(v); err != nil { + if data, err = this.codec.MarshalMap(v); err != nil { return } for k, v := range data { @@ -46,19 +46,30 @@ func (this *Redis) HMSet(key string, v interface{}) (err error) { return } +func (this *Redis) HMSetForMap(key string, v map[string]string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "HMSET") + agrs = append(agrs, key) + for k, v := range v { + agrs = append(agrs, k, v) + } + err = this.client.Do(this.getContext(), agrs...).Err() + return +} + /* Redis Hget 命令用于返回哈希表中指定字段的值 */ func (this *Redis) HGet(key string, field string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "HGET", key, field) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { + var _result []byte + if _result, err = cmd.Bytes(); err == nil { if len(_result) == 0 { err = redis.Nil return } - err = this.decode.DecoderString(_result, v) + err = this.codec.Unmarshal(_result, v) } return } @@ -76,7 +87,22 @@ func (this *Redis) HGetAll(key string, v interface{}) (err error) { err = redis.Nil return } - err = this.decode.DecoderMapString(_result, v) + err = this.codec.UnmarshalMap(_result, v) + } + return +} + +/* + 读取全部hash集合数据到map中 +*/ +func (this *Redis) HGetAllToMapString(key string) (result map[string]string, err error) { + cmd := redis.NewStringStringMapCmd(this.getContext(), "HGETALL", key) + this.client.Process(this.getContext(), cmd) + if result, err = cmd.Result(); err == nil { + if len(result) == 0 { + err = redis.Nil + return + } } return } @@ -140,7 +166,7 @@ func (this *Redis) HMGet(key string, v interface{}, fields ...string) (err error err = redis.Nil return } - err = this.decode.DecoderMapString(_result, v) + err = this.codec.UnmarshalMap(_result, v) } return } @@ -152,7 +178,7 @@ Redis Hset 命令用于为哈希表中的字段赋值 */ func (this *Redis) HSet(key string, field string, value interface{}) (err error) { var resultvalue []byte - if resultvalue, err = this.encode.Encoder(value); err == nil { + if resultvalue, err = this.codec.Marshal(value); err == nil { err = this.client.Do(this.getContext(), "HSET", key, field, resultvalue).Err() } return @@ -166,7 +192,7 @@ Redis Hsetnx 命令用于为哈希表中不存在的的字段赋值 */ func (this *Redis) HSetNX(key string, field string, value interface{}) (err error) { var resultvalue []byte - if resultvalue, err = this.encode.Encoder(value); err == nil { + if resultvalue, err = this.codec.Marshal(value); err == nil { err = this.client.Do(this.getContext(), "HSETNX", key, field, resultvalue).Err() } return diff --git a/lego/sys/redis/cluster/list.go b/lego/sys/redis/cluster/list.go index b141c485b..537960f39 100644 --- a/lego/sys/redis/cluster/list.go +++ b/lego/sys/redis/cluster/list.go @@ -10,13 +10,13 @@ Redis Lindex 命令用于通过索引获取列表中的元素。你也可以使 func (this *Redis) Lindex(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "LINDEX", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { + var _result []byte + if _result, err = cmd.Bytes(); err == nil { if len(_result) == 0 { err = redis.Nil return } - err = this.decode.DecoderString(_result, v) + err = this.codec.Unmarshal(_result, v) } return } @@ -28,13 +28,13 @@ Redis Linsert 命令用于在列表的元素前或者后插入元素。当指定 */ func (this *Redis) Linsert(key string, isbefore bool, tager interface{}, value interface{}) (err error) { var ( - tagervalue string - resultvalue string + tagervalue []byte + resultvalue []byte ) - if tagervalue, err = this.encode.EncoderString(tager); err != nil { + if tagervalue, err = this.codec.Marshal(tager); err != nil { return } - if resultvalue, err = this.encode.EncoderString(value); err != nil { + if resultvalue, err = this.codec.Marshal(value); err != nil { return } if isbefore { @@ -59,9 +59,9 @@ Redis Lpop 命令用于移除并返回列表的第一个元素 func (this *Redis) LPop(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "LPOP", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -73,7 +73,7 @@ func (this *Redis) LPush(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "LPUSH") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -87,7 +87,7 @@ func (this *Redis) LPushX(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "LPUSHX") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -103,7 +103,7 @@ func (this *Redis) LRange(key string, start, end int, v interface{}) (err error) cmd := redis.NewStringSliceCmd(this.getContext(), "LRANGE", key, start, end) this.client.Process(this.getContext(), cmd) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -116,8 +116,8 @@ count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素, count = 0 : 移除表中所有与 VALUE 相等的值 */ func (this *Redis) LRem(key string, count int, target interface{}) (err error) { - var resultvalue string - if resultvalue, err = this.encode.EncoderString(target); err != nil { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(target); err != nil { return } err = this.client.Do(this.getContext(), "LREM", key, count, resultvalue).Err() @@ -129,8 +129,8 @@ Redis Lset 通过索引来设置元素的值。 当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误 */ func (this *Redis) LSet(key string, index int, value interface{}) (err error) { - var resultvalue string - if resultvalue, err = this.encode.EncoderString(value); err == nil { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(value); err == nil { return } err = this.client.Do(this.getContext(), "LSET", key, index, resultvalue).Err() @@ -153,9 +153,9 @@ Redis Rpop 命令用于移除列表的最后一个元素,返回值为移除的 func (this *Redis) Rpop(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "RPOP", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -166,9 +166,9 @@ Redis Rpoplpush 命令用于移除列表的最后一个元素,并将该元素 func (this *Redis) RPopLPush(oldkey string, newkey string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "RPOPLPUSH", oldkey, newkey) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -182,7 +182,7 @@ func (this *Redis) RPush(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "RPUSH") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -196,7 +196,7 @@ func (this *Redis) RPushX(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "RPUSHX") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() diff --git a/lego/sys/redis/cluster/set.go b/lego/sys/redis/cluster/set.go index 70d20fc6a..9571b72d0 100644 --- a/lego/sys/redis/cluster/set.go +++ b/lego/sys/redis/cluster/set.go @@ -10,7 +10,7 @@ func (this *Redis) SAdd(key string, values ...interface{}) (err error) { agrs = append(agrs, "SADD") agrs = append(agrs, key) for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -34,7 +34,7 @@ func (this *Redis) SDiff(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SDiff(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -54,7 +54,7 @@ func (this *Redis) SInter(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SInter(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -82,7 +82,7 @@ func (this *Redis) SMembers(v interface{}, key string) (err error) { var _result []string cmd := this.client.SMembers(this.getContext(), key) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -137,7 +137,7 @@ func (this *Redis) SUnion(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SUnion(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } diff --git a/lego/sys/redis/cluster/string.go b/lego/sys/redis/cluster/string.go index ecc6e1798..53ddd76cb 100644 --- a/lego/sys/redis/cluster/string.go +++ b/lego/sys/redis/cluster/string.go @@ -11,8 +11,8 @@ import ( 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。 */ func (this *Redis) Set(key string, value interface{}, expiration time.Duration) (err error) { - var result string - if result, err = this.encode.EncoderString(value); err != nil { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { return } err = this.client.Set(this.getContext(), key, result, expiration).Err() @@ -37,7 +37,7 @@ func (this *Redis) MSet(v map[string]interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "MSET") for k, v := range v { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, k, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -51,7 +51,7 @@ func (this *Redis) MSetNX(v map[string]interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "MSETNX") for k, v := range v { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, k, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -117,8 +117,8 @@ Redis Append 命令用于为指定的 key 追加值。 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。 */ func (this *Redis) Append(key string, value interface{}) (err error) { - var result string - if result, err = this.encode.EncoderString(value); err != nil { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { return } err = this.client.Do(this.getContext(), "APPEND", key, result).Err() @@ -129,9 +129,9 @@ func (this *Redis) Append(key string, value interface{}) (err error) { 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型 */ func (this *Redis) Get(key string, value interface{}) (err error) { - var result string - if result, err = this.client.Get(this.getContext(), key).Result(); err == nil { - err = this.decode.DecoderString(result, value) + var result []byte + if result, err = this.client.Get(this.getContext(), key).Bytes(); err == nil { + err = this.codec.Unmarshal(result, value) } return } @@ -141,14 +141,14 @@ func (this *Redis) Get(key string, value interface{}) (err error) { */ func (this *Redis) GetSet(key string, value interface{}, result interface{}) (err error) { var ( - _value string + _value []byte ) - if _value, err = this.encode.EncoderString(value); err == nil { + if _value, err = this.codec.Marshal(value); err == nil { cmd := redis.NewStringCmd(this.getContext(), "GETSET", key, _value) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, result) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, result) } } return @@ -169,7 +169,7 @@ func (this *Redis) MGet(v interface{}, keys ...string) (err error) { if result, err = cmd.Result(); err != nil { return } - err = this.decode.DecoderSliceString(result, v) + err = this.codec.UnmarshalSlice(result, v) return } diff --git a/lego/sys/redis/cluster/zset.go b/lego/sys/redis/cluster/zset.go index a69bc7270..ca82e6140 100644 --- a/lego/sys/redis/cluster/zset.go +++ b/lego/sys/redis/cluster/zset.go @@ -59,7 +59,7 @@ func (this *Redis) ZRange(key string, start int64, stop int64, v interface{}) (e var _result []string cmd := this.client.ZRange(this.getContext(), key, start, stop) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -71,7 +71,7 @@ func (this *Redis) ZRangeByLex(key string, opt *redis.ZRangeBy, v interface{}) ( var _result []string cmd := this.client.ZRangeByLex(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -83,7 +83,7 @@ func (this *Redis) ZRangeByScore(key string, opt *redis.ZRangeBy, v interface{}) var _result []string cmd := this.client.ZRangeByScore(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -135,7 +135,7 @@ func (this *Redis) ZRevRange(key string, start int64, stop int64, v interface{}) var _result []string cmd := this.client.ZRevRange(this.getContext(), key, start, stop) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -147,7 +147,7 @@ func (this *Redis) ZRevRangeByScore(key string, opt *redis.ZRangeBy, v interface var _result []string cmd := this.client.ZRevRangeByScore(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } diff --git a/lego/sys/redis/core.go b/lego/sys/redis/core.go index fc7545619..d07f5ab1c 100644 --- a/lego/sys/redis/core.go +++ b/lego/sys/redis/core.go @@ -65,12 +65,14 @@ type ( HExists(key string, field string) (result bool, err error) HGet(key string, field string, value interface{}) (err error) HGetAll(key string, v interface{}) (err error) + HGetAllToMapString(key string) (result map[string]string, err error) HIncrBy(key string, field string, value int) (err error) HIncrByFloat(key string, field string, value float32) (err error) Hkeys(key string) (result []string, err error) Hlen(key string) (result int, err error) HMGet(key string, v interface{}, fields ...string) (err error) HMSet(key string, v interface{}) (err error) + HMSetForMap(key string, v map[string]string) (err error) HSet(key string, field string, value interface{}) (err error) HSetNX(key string, field string, value interface{}) (err error) /*Set*/ @@ -325,6 +327,9 @@ func HMGet(key string, v interface{}, fields ...string) (err error) { func HMSet(key string, v interface{}) (err error) { return defsys.HMSet(key, v) } +func HMSetForMap(key string, v map[string]string) (err error) { + return defsys.HMSetForMap(key, v) +} func HSet(key string, field string, value interface{}) (err error) { return defsys.HSet(key, field, value) } diff --git a/lego/sys/redis/core/core.go b/lego/sys/redis/core/core.go new file mode 100644 index 000000000..d99eb3f1c --- /dev/null +++ b/lego/sys/redis/core/core.go @@ -0,0 +1,12 @@ +package core + +type ( + ICodec interface { + Marshal(v interface{}) ([]byte, error) + Unmarshal(data []byte, v interface{}) error + MarshalMap(val interface{}) (ret map[string]string, err error) + UnmarshalMap(data map[string]string, val interface{}) (err error) + MarshalSlice(val interface{}) (ret []string, err error) + UnmarshalSlice(data []string, val interface{}) (err error) + } +) diff --git a/lego/sys/redis/options.go b/lego/sys/redis/options.go index 427ec10ac..3e097668c 100644 --- a/lego/sys/redis/options.go +++ b/lego/sys/redis/options.go @@ -3,6 +3,7 @@ package redis import ( "time" + "go_dreamfactory/lego/sys/redis/core" "go_dreamfactory/lego/utils/mapstructure" ) @@ -13,14 +14,6 @@ const ( Redis_Cluster ) -///redis 存储数据格式化类型 -type RedisStorageTyoe int8 - -const ( - JsonData RedisStorageTyoe = iota - ProtoData -) - type Option func(*Options) type Options struct { RedisType RedisType @@ -30,8 +23,8 @@ type Options struct { Redis_Single_PoolSize int Redis_Cluster_Addr []string Redis_Cluster_Password string - RedisStorageType RedisStorageTyoe TimeOut time.Duration + Codec core.ICodec } func SetRedisType(v RedisType) Option { @@ -74,11 +67,6 @@ func SetRedis_Cluster_Password(v string) Option { o.Redis_Cluster_Password = v } } -func SetRedisStorageType(v RedisStorageTyoe) Option { - return func(o *Options) { - o.RedisStorageType = v - } -} func SetTimeOut(v time.Duration) Option { return func(o *Options) { @@ -86,6 +74,12 @@ func SetTimeOut(v time.Duration) Option { } } +func SetCodec(v core.ICodec) Option { + return func(o *Options) { + o.Codec = v + } +} + func newOptions(config map[string]interface{}, opts ...Option) Options { options := Options{ Redis_Single_Addr: "127.0.0.1:6379", diff --git a/lego/sys/redis/redis.go b/lego/sys/redis/redis.go index ab119af6b..5ac350bbb 100644 --- a/lego/sys/redis/redis.go +++ b/lego/sys/redis/redis.go @@ -5,25 +5,15 @@ import ( "fmt" "time" - jsoniter "github.com/json-iterator/go" - + "go_dreamfactory/lego/sys/codec" "go_dreamfactory/lego/sys/redis/cluster" "go_dreamfactory/lego/sys/redis/single" - "go_dreamfactory/lego/utils/codec" "github.com/go-redis/redis/v8" - "google.golang.org/protobuf/proto" ) func newSys(options Options) (sys *Redis, err error) { sys = &Redis{options: options} - if options.RedisStorageType == JsonData { - sys.decoder = &codec.Decoder{DefDecoder: jsoniter.Unmarshal} - sys.encoder = &codec.Encoder{DefEncoder: jsoniter.Marshal} - } else { - sys.decoder = &codec.Decoder{DefDecoder: func(buf []byte, v interface{}) error { return proto.Unmarshal(buf, v.(proto.Message)) }} - sys.encoder = &codec.Encoder{DefEncoder: func(v interface{}) (data []byte, err error) { return proto.Marshal(v.(proto.Message)) }} - } err = sys.init() return } @@ -31,8 +21,6 @@ func newSys(options Options) (sys *Redis, err error) { type Redis struct { options Options client IRedis - decoder codec.IDecoder - encoder codec.IEncoder } func (this *Redis) init() (err error) { @@ -43,16 +31,14 @@ func (this *Redis) init() (err error) { this.options.Redis_Single_DB, this.options.Redis_Single_PoolSize, this.options.TimeOut, - this.encoder, - this.decoder, + this, ) } else if this.options.RedisType == Redis_Cluster { this.client, err = cluster.NewSys( this.options.Redis_Cluster_Addr, this.options.Redis_Cluster_Password, this.options.TimeOut, - this.encoder, - this.decoder, + this, ) } else { err = fmt.Errorf("init Redis err:RedisType - %d", this.options.RedisType) @@ -227,6 +213,9 @@ func (this *Redis) HGet(key string, field string, value interface{}) (err error) func (this *Redis) HGetAll(key string, v interface{}) (err error) { return this.client.HGetAll(key, v) } +func (this *Redis) HGetAllToMapString(key string) (result map[string]string, err error) { + return this.client.HGetAllToMapString(key) +} func (this *Redis) HIncrBy(key string, field string, value int) (err error) { return this.client.HIncrBy(key, field, value) } @@ -245,6 +234,11 @@ func (this *Redis) HMGet(key string, v interface{}, fields ...string) (err error func (this *Redis) HMSet(key string, v interface{}) (err error) { return this.client.HMSet(key, v) } + +func (this *Redis) HMSetForMap(key string, v map[string]string) (err error) { + return this.client.HMSetForMap(key, v) +} + func (this *Redis) HSet(key string, field string, value interface{}) (err error) { return this.client.HSet(key, field, value) } @@ -360,3 +354,47 @@ func (this *Redis) ZUnionStore(dest string, store *redis.ZStore) (result int64, func (this *Redis) ZScan(key string, _cursor uint64, match string, count int64) (keys []string, cursor uint64, err error) { return this.client.ZScan(key, _cursor, match, count) } + +//Codec--------------------------------------------------------------------------------------------------------------------------------------- +func (this *Redis) Marshal(v interface{}) ([]byte, error) { + if this.options.Codec != nil { + return this.options.Codec.Marshal(v) + } else { + return codec.MarshalJson(v) + } +} +func (this *Redis) Unmarshal(data []byte, v interface{}) error { + if this.options.Codec != nil { + return this.options.Codec.Unmarshal(data, v) + } else { + return codec.UnmarshalJson(data, v) + } +} +func (this *Redis) MarshalMap(val interface{}) (ret map[string]string, err error) { + if this.options.Codec != nil { + return this.options.Codec.MarshalMap(val) + } else { + return codec.MarshalMapJson(val) + } +} +func (this *Redis) UnmarshalMap(data map[string]string, val interface{}) (err error) { + if this.options.Codec != nil { + return this.options.Codec.UnmarshalMap(data, val) + } else { + return codec.UnmarshalMapJson(data, val) + } +} +func (this *Redis) MarshalSlice(val interface{}) (ret []string, err error) { + if this.options.Codec != nil { + return this.options.Codec.MarshalSlice(val) + } else { + return codec.MarshalSliceJson(val) + } +} +func (this *Redis) UnmarshalSlice(data []string, val interface{}) (err error) { + if this.options.Codec != nil { + return this.options.Codec.UnmarshalSlice(data, val) + } else { + return codec.UnmarshalSliceJson(data, val) + } +} diff --git a/lego/sys/redis/single/core.go b/lego/sys/redis/single/core.go index 74899c5c1..58dd8c807 100644 --- a/lego/sys/redis/single/core.go +++ b/lego/sys/redis/single/core.go @@ -2,15 +2,14 @@ package single import ( "context" - "go_dreamfactory/lego/utils/codec" + "go_dreamfactory/lego/sys/redis/core" "time" "github.com/go-redis/redis/v8" ) func NewSys(RedisUrl, RedisPassword string, RedisDB, PoolSize int, timeOut time.Duration, - encode codec.IEncoder, - decode codec.IDecoder, + codec core.ICodec, ) (sys *Redis, err error) { var ( client *redis.Client @@ -24,8 +23,7 @@ func NewSys(RedisUrl, RedisPassword string, RedisDB, PoolSize int, timeOut time. sys = &Redis{ client: client, timeOut: timeOut, - encode: encode, - decode: decode, + codec: codec, } _, err = sys.Ping() return @@ -34,8 +32,7 @@ func NewSys(RedisUrl, RedisPassword string, RedisDB, PoolSize int, timeOut time. type Redis struct { client *redis.Client timeOut time.Duration - encode codec.IEncoder - decode codec.IDecoder + codec core.ICodec } func (this *Redis) getContext() (ctx context.Context) { diff --git a/lego/sys/redis/single/hash.go b/lego/sys/redis/single/hash.go index d37c24f05..863abf46e 100644 --- a/lego/sys/redis/single/hash.go +++ b/lego/sys/redis/single/hash.go @@ -36,7 +36,7 @@ func (this *Redis) HMSet(key string, v interface{}) (err error) { agrs = append(agrs, "HMSET") agrs = append(agrs, key) var data map[string]string - if data, err = this.encode.EncoderToMapString(v); err != nil { + if data, err = this.codec.MarshalMap(v); err != nil { return } for k, v := range data { @@ -45,6 +45,16 @@ func (this *Redis) HMSet(key string, v interface{}) (err error) { err = this.client.Do(this.getContext(), agrs...).Err() return } +func (this *Redis) HMSetForMap(key string, v map[string]string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "HMSET") + agrs = append(agrs, key) + for k, v := range v { + agrs = append(agrs, k, v) + } + err = this.client.Do(this.getContext(), agrs...).Err() + return +} /* Redis Hget 命令用于返回哈希表中指定字段的值 @@ -52,9 +62,9 @@ Redis Hget 命令用于返回哈希表中指定字段的值 func (this *Redis) HGet(key string, field string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "HGET", key, field) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -71,7 +81,22 @@ func (this *Redis) HGetAll(key string, v interface{}) (err error) { if len(_result) == 0 { return redis.Nil } - err = this.decode.DecoderMapString(_result, v) + err = this.codec.UnmarshalMap(_result, v) + } + return +} + +/* + 读取全部hash集合数据到map中 +*/ +func (this *Redis) HGetAllToMapString(key string) (result map[string]string, err error) { + cmd := redis.NewStringStringMapCmd(this.getContext(), "HGETALL", key) + this.client.Process(this.getContext(), cmd) + if result, err = cmd.Result(); err == nil { + if len(result) == 0 { + err = redis.Nil + return + } } return } @@ -131,7 +156,7 @@ func (this *Redis) HMGet(key string, v interface{}, fields ...string) (err error this.client.Process(this.getContext(), cmd) var _result map[string]string if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderMapString(_result, v) + err = this.codec.UnmarshalMap(_result, v) } return } @@ -143,7 +168,7 @@ Redis Hset 命令用于为哈希表中的字段赋值 */ func (this *Redis) HSet(key string, field string, value interface{}) (err error) { var resultvalue []byte - if resultvalue, err = this.encode.Encoder(value); err == nil { + if resultvalue, err = this.codec.Marshal(value); err == nil { err = this.client.Do(this.getContext(), "HSET", key, field, resultvalue).Err() } return @@ -157,7 +182,7 @@ Redis Hsetnx 命令用于为哈希表中不存在的的字段赋值 */ func (this *Redis) HSetNX(key string, field string, value interface{}) (err error) { var resultvalue []byte - if resultvalue, err = this.encode.Encoder(value); err == nil { + if resultvalue, err = this.codec.Marshal(value); err == nil { err = this.client.Do(this.getContext(), "HSETNX", key, field, resultvalue).Err() } return diff --git a/lego/sys/redis/single/list.go b/lego/sys/redis/single/list.go index 0123cc821..7cdc71f82 100644 --- a/lego/sys/redis/single/list.go +++ b/lego/sys/redis/single/list.go @@ -10,9 +10,9 @@ Redis Lindex 命令用于通过索引获取列表中的元素。你也可以使 func (this *Redis) Lindex(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "LINDEX", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -24,13 +24,13 @@ Redis Linsert 命令用于在列表的元素前或者后插入元素。当指定 */ func (this *Redis) Linsert(key string, isbefore bool, tager interface{}, value interface{}) (err error) { var ( - tagervalue string - resultvalue string + tagervalue []byte + resultvalue []byte ) - if tagervalue, err = this.encode.EncoderString(tager); err != nil { + if tagervalue, err = this.codec.Marshal(tager); err != nil { return } - if resultvalue, err = this.encode.EncoderString(value); err != nil { + if resultvalue, err = this.codec.Marshal(value); err != nil { return } if isbefore { @@ -55,9 +55,9 @@ Redis Lpop 命令用于移除并返回列表的第一个元素 func (this *Redis) LPop(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "LPOP", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -69,7 +69,7 @@ func (this *Redis) LPush(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "LPUSH") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -83,7 +83,7 @@ func (this *Redis) LPushX(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "LPUSHX") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -99,7 +99,7 @@ func (this *Redis) LRange(key string, start, end int, v interface{}) (err error) cmd := redis.NewStringSliceCmd(this.getContext(), "LRANGE", key, start, end) this.client.Process(this.getContext(), cmd) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -112,8 +112,8 @@ count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素, count = 0 : 移除表中所有与 VALUE 相等的值 */ func (this *Redis) LRem(key string, count int, target interface{}) (err error) { - var resultvalue string - if resultvalue, err = this.encode.EncoderString(target); err != nil { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(target); err != nil { return } err = this.client.Do(this.getContext(), "LREM", key, count, resultvalue).Err() @@ -125,8 +125,8 @@ Redis Lset 通过索引来设置元素的值。 当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误 */ func (this *Redis) LSet(key string, index int, value interface{}) (err error) { - var resultvalue string - if resultvalue, err = this.encode.EncoderString(value); err == nil { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(value); err == nil { return } err = this.client.Do(this.getContext(), "LSET", key, index, resultvalue).Err() @@ -149,9 +149,9 @@ Redis Rpop 命令用于移除列表的最后一个元素,返回值为移除的 func (this *Redis) Rpop(key string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "RPOP", key) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -162,9 +162,9 @@ Redis Rpoplpush 命令用于移除列表的最后一个元素,并将该元素 func (this *Redis) RPopLPush(oldkey string, newkey string, v interface{}) (err error) { cmd := redis.NewStringCmd(this.getContext(), "RPOPLPUSH", oldkey, newkey) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, v) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) } return } @@ -178,7 +178,7 @@ func (this *Redis) RPush(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "RPUSH") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -192,7 +192,7 @@ func (this *Redis) RPushX(key string, values ...interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "RPUSHX") for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() diff --git a/lego/sys/redis/single/set.go b/lego/sys/redis/single/set.go index 14a345666..5f5678d4f 100644 --- a/lego/sys/redis/single/set.go +++ b/lego/sys/redis/single/set.go @@ -10,7 +10,7 @@ func (this *Redis) SAdd(key string, values ...interface{}) (err error) { agrs = append(agrs, "SADD") agrs = append(agrs, key) for _, v := range values { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -34,7 +34,7 @@ func (this *Redis) SDiff(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SDiff(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -54,7 +54,7 @@ func (this *Redis) SInter(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SInter(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -82,7 +82,7 @@ func (this *Redis) SMembers(v interface{}, key string) (err error) { var _result []string cmd := this.client.SMembers(this.getContext(), key) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -137,7 +137,7 @@ func (this *Redis) SUnion(v interface{}, keys ...string) (err error) { var _result []string cmd := this.client.SUnion(this.getContext(), keys...) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } diff --git a/lego/sys/redis/single/string.go b/lego/sys/redis/single/string.go index ec63e2d6f..e894a84d3 100644 --- a/lego/sys/redis/single/string.go +++ b/lego/sys/redis/single/string.go @@ -11,8 +11,8 @@ import ( 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。 */ func (this *Redis) Set(key string, value interface{}, expiration time.Duration) (err error) { - var result string - if result, err = this.encode.EncoderString(value); err != nil { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { return } err = this.client.Set(this.getContext(), key, result, expiration).Err() @@ -37,7 +37,7 @@ func (this *Redis) MSet(v map[string]interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "MSET") for k, v := range v { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, k, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -51,7 +51,7 @@ func (this *Redis) MSetNX(v map[string]interface{}) (err error) { agrs := make([]interface{}, 0) agrs = append(agrs, "MSETNX") for k, v := range v { - result, _ := this.encode.EncoderString(v) + result, _ := this.codec.Marshal(v) agrs = append(agrs, k, result) } err = this.client.Do(this.getContext(), agrs...).Err() @@ -117,8 +117,8 @@ Redis Append 命令用于为指定的 key 追加值。 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。 */ func (this *Redis) Append(key string, value interface{}) (err error) { - var result string - if result, err = this.encode.EncoderString(value); err != nil { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { return } err = this.client.Do(this.getContext(), "APPEND", key, result).Err() @@ -129,9 +129,9 @@ func (this *Redis) Append(key string, value interface{}) (err error) { 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型 */ func (this *Redis) Get(key string, value interface{}) (err error) { - var result string - if result, err = this.client.Get(this.getContext(), key).Result(); err == nil { - err = this.decode.DecoderString(result, value) + var result []byte + if result, err = this.client.Get(this.getContext(), key).Bytes(); err == nil { + err = this.codec.Unmarshal(result, value) } return } @@ -141,14 +141,14 @@ func (this *Redis) Get(key string, value interface{}) (err error) { */ func (this *Redis) GetSet(key string, value interface{}, result interface{}) (err error) { var ( - _value string + _value []byte ) - if _value, err = this.encode.EncoderString(value); err == nil { + if _value, err = this.codec.Marshal(value); err == nil { cmd := redis.NewStringCmd(this.getContext(), "GETSET", key, _value) this.client.Process(this.getContext(), cmd) - var _result string - if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderString(_result, result) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, result) } } return @@ -169,7 +169,7 @@ func (this *Redis) MGet(v interface{}, keys ...string) (err error) { if result, err = cmd.Result(); err != nil { return } - err = this.decode.DecoderSliceString(result, v) + err = this.codec.UnmarshalSlice(result, v) return } diff --git a/lego/sys/redis/single/zset.go b/lego/sys/redis/single/zset.go index cf447b19c..e4c264e13 100644 --- a/lego/sys/redis/single/zset.go +++ b/lego/sys/redis/single/zset.go @@ -59,7 +59,7 @@ func (this *Redis) ZRange(key string, start int64, stop int64, v interface{}) (e var _result []string cmd := this.client.ZRange(this.getContext(), key, start, stop) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -71,7 +71,7 @@ func (this *Redis) ZRangeByLex(key string, opt *redis.ZRangeBy, v interface{}) ( var _result []string cmd := this.client.ZRangeByLex(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -83,7 +83,7 @@ func (this *Redis) ZRangeByScore(key string, opt *redis.ZRangeBy, v interface{}) var _result []string cmd := this.client.ZRangeByScore(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -135,7 +135,7 @@ func (this *Redis) ZRevRange(key string, start int64, stop int64, v interface{}) var _result []string cmd := this.client.ZRevRange(this.getContext(), key, start, stop) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } @@ -147,7 +147,7 @@ func (this *Redis) ZRevRangeByScore(key string, opt *redis.ZRangeBy, v interface var _result []string cmd := this.client.ZRevRangeByScore(this.getContext(), key, opt) if _result, err = cmd.Result(); err == nil { - err = this.decode.DecoderSliceString(_result, v) + err = this.codec.UnmarshalSlice(_result, v) } return } diff --git a/lego/sys/redis/sys_test.go b/lego/sys/redis/sys_test.go index 3d690774c..522ca0f87 100644 --- a/lego/sys/redis/sys_test.go +++ b/lego/sys/redis/sys_test.go @@ -16,7 +16,6 @@ func TestMain(m *testing.M) { redis.SetRedisType(redis.Redis_Cluster), redis.SetRedis_Cluster_Addr([]string{"10.0.0.9:9001", "10.0.0.9:9002", "10.0.0.9:9003", "10.0.1.45:9004", "10.0.1.45:9005", "10.0.1.45:9006"}), redis.SetRedis_Cluster_Password(""), - redis.SetRedisStorageType(redis.JsonData), ); err != nil { fmt.Println("err:", err) return diff --git a/lego/utils/crypto/base64/base64.go b/lego/utils/crypto/base64/base64.go new file mode 100644 index 000000000..5bb52dc95 --- /dev/null +++ b/lego/utils/crypto/base64/base64.go @@ -0,0 +1,13 @@ +package base64 + +import "encoding/base64" + +///编码 +func EncodeToString(src []byte) string { + return base64.StdEncoding.EncodeToString(src) +} + +///解码 +func DecodeString(s string) ([]byte, error) { + return base64.StdEncoding.DecodeString(s) +} diff --git a/lego/utils/crypto/md5/md5.go b/lego/utils/crypto/md5/md5.go new file mode 100644 index 000000000..5d9650ced --- /dev/null +++ b/lego/utils/crypto/md5/md5.go @@ -0,0 +1,47 @@ +package md5 + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "sort" + "strings" +) + +/* +MD5加密 +*/ + +//MD5加密 大写 +func MD5EncToUpper(str string) string { + h := md5.New() + h.Write([]byte(str)) + return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) +} + +//MD5加密 小写 +func MD5EncToLower(str string) string { + h := md5.New() + h.Write([]byte(str)) + return strings.ToLower(hex.EncodeToString(h.Sum(nil))) +} + +//参数签名 +func ParamSign(param map[string]interface{}, key string) (orsign, sign string) { + a := sort.StringSlice{} + for k, _ := range param { + a = append(a, k) + } + sort.Sort(a) + orsign = "" + for _, k := range a { + switch param[k].(type) { //只签名基础数据 + case bool, byte, int8, int16, uint16, int32, uint32, int, int64, uint64, float64, float32, string: + orsign = orsign + fmt.Sprintf("%s=%v&", k, param[k]) + break + } + } + orsign = orsign + fmt.Sprintf("key=%s", key) + sign = MD5EncToLower(orsign) + return +} diff --git a/modules/comp_model.go b/modules/comp_model.go index 06ae6eb63..5f3999aea 100644 --- a/modules/comp_model.go +++ b/modules/comp_model.go @@ -6,14 +6,19 @@ import ( "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/core/cbase" + "go_dreamfactory/lego/sys/codec" + ccore "go_dreamfactory/lego/sys/codec/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/lego/sys/redis" + "go_dreamfactory/pb" "go_dreamfactory/sys/cache" "go_dreamfactory/sys/db" "reflect" "time" + "unsafe" + "github.com/modern-go/reflect2" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -70,6 +75,7 @@ func (this *MCompModel) InsertModelLogs(table string, uID string, target interfa return err } + func (this *MCompModel) DeleteModelLogs(table string, uID string, where interface{}) (err error) { data := &comm.Autogenerated{ @@ -88,6 +94,7 @@ func (this *MCompModel) DeleteModelLogs(table string, uID string, where interfac return err } + func (this *MCompModel) UpdateModelLogs(table string, uID string, where bson.M, target interface{}) (err error) { data := &comm.Autogenerated{ @@ -221,8 +228,8 @@ func (this *MCompModel) Get(uid string, data interface{}) (err error) { return } -//获取列表数据 注意 data 必须啊转 切片的指针 *[]type -func (this *MCompModel) GetList(uid string, data interface{}) (err error) { +//获取列表数据 注意 data 必须是 切片的指针 *[]type 暂时废弃 +func (this *MCompModel) mGetList(uid string, data interface{}) (err error) { var keys map[string]string = make(map[string]string) var c *mongo.Cursor t := reflect.TypeOf(data) @@ -312,6 +319,110 @@ func (this *MCompModel) GetList(uid string, data interface{}) (err error) { return err } +//获取列表数据 注意 data 必须是 切片的指针 *[]type +func (this *MCompModel) GetList(uid string, data interface{}) (err error) { + var ( + dtype reflect2.Type + dkind reflect.Kind + sType reflect2.Type + sliceType *reflect2.UnsafeSliceType + sliceelemType reflect2.Type + decoder ccore.IDecoderMapJson + encoder ccore.IEncoderMapJson + dptr unsafe.Pointer + elemPtr unsafe.Pointer + n int + ok bool + keys map[string]string + cdata map[string]string + c *mongo.Cursor + ) + keys = make(map[string]string) + 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).(ccore.IDecoderMapJson); !ok { + err = fmt.Errorf("MCompModel: GetList(data not support MarshalMapJson %T)", data) + return + } + sliceelemType = sliceelemType.(*reflect2.UnsafePtrType).Elem() + keys, err = this.Redis.HGetAllToMapString(this.ukey(uid)) + if err == nil { + n = 0 + for _, v := range keys { + if cdata, err = this.Redis.HGetAllToMapString(v); err != nil { + return + } + sliceType.UnsafeGrow(dptr, n+1) + elemPtr = sliceType.UnsafeGetIndex(dptr, n) + if *((*unsafe.Pointer)(elemPtr)) == nil { + newPtr := sliceelemType.UnsafeNew() + decoder.DecodeForMapJson(newPtr, cdata) + *((*unsafe.Pointer)(elemPtr)) = newPtr + } else { + decoder.DecodeForMapJson(*((*unsafe.Pointer)(elemPtr)), cdata) + } + n++ + } + } + if err == redis.RedisNil { + //query from mgo + if c, err = this.DB.Find(core.SqlTable(this.TableName), bson.M{"uid": uid}); err != nil { + return err + } else { + if encoder, ok = codec.EncoderOf(sliceelemType).(ccore.IEncoderMapJson); !ok { + err = fmt.Errorf("MCompModel: GetList(data not support UnMarshalMapJson %T)", data) + return + } + n = 0 + 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) + n++ + if err = c.Decode(elem); err != nil { + return + } + if cdata, err = encoder.EncodeToMapJson(*((*unsafe.Pointer)(elemPtr))); err != nil { + return + } + key := this.ukeylist(uid, _id) + if err = this.Redis.HMSetForMap(key, cdata); err != nil { + return + } + keys[_id] = key + } + if len(keys) > 0 { + if err = this.Redis.HMSet(this.ukey(uid), keys); err != nil { + return + } + } + } + } + + return err +} + //读取单个数据中 多个字段数据 func (this *MCompModel) GetFields(uid string, data interface{}, fields ...string) (err error) { this.Redis.HMGet(this.ukey(uid), data, fields...) @@ -355,6 +466,21 @@ func (this *MCompModel) DelListlds(uid string, ids ...string) (err error) { return } +//获取用户通过扩展表 +func (this *MCompModel) GetUserExpand(uid string) (result *pb.DBUserExpand, err error) { + result = &pb.DBUserExpand{} + if err = this.Redis.HGetAll(this.ukey(uid), result); err != nil && err != redis.RedisNil { + return + } + if err == redis.RedisNil { + if err = this.DB.FindOne(core.SqlTable("userexpand"), bson.M{"uid": uid}).Decode(result); err != nil { + return + } + err = this.Redis.HMSet(this.ukey(uid), result) + } + return +} + //日志操作可选项 func (this *MCompModel) logOpt(uid string, data interface{}, attrs ...*cache.OperationAttr) error { ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil) diff --git a/modules/gateway/options.go b/modules/gateway/options.go index f042a61cb..12075275f 100644 --- a/modules/gateway/options.go +++ b/modules/gateway/options.go @@ -10,7 +10,9 @@ import ( type ( Options struct { - ListenPort int //websocket 监听端口 + Debug bool //日志开关 + GinDebug bool //web引擎日志开关 + ListenPort int //websocket 监听端口 } ) diff --git a/modules/gateway/wservice_comp.go b/modules/gateway/wservice_comp.go index d730369ff..8ae992983 100644 --- a/modules/gateway/wservice_comp.go +++ b/modules/gateway/wservice_comp.go @@ -25,11 +25,9 @@ func (this *WSServiceComp) Init(service core.IService, module core.IModule, comp err = this.ModuleCompBase.Init(service, module, comp, options) this.options = options.(*Options) this.module = module.(IGateway) - this.gin, err = gin.NewSys(gin.SetListenPort(this.options.ListenPort)) - + this.gin, err = gin.NewSys(gin.SetListenPort(this.options.ListenPort), gin.SetDebug(this.options.GinDebug)) // 游戏业务逻辑处理 this.gin.GET("/gateway", this.ws) - return } diff --git a/modules/web/api.go b/modules/gm/api.go similarity index 78% rename from modules/web/api.go rename to modules/gm/api.go index bf8cb3cd1..5ee8a6734 100644 --- a/modules/web/api.go +++ b/modules/gm/api.go @@ -1,4 +1,4 @@ -package web +package gm import ( "go_dreamfactory/lego/core" @@ -11,16 +11,16 @@ import ( */ type Api_Comp struct { cbase.ModuleCompBase - options *Options //模块参数 - moduleWeb *Web //当前模块对象 - gin gin.ISys //gin 框架 web的热门框架 + options *Options //模块参数 + module *GM //当前模块对象 + gin gin.ISys //gin 框架 web的热门框架 } //组件初始化接口 启动web服务 并注册api func (this *Api_Comp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { err = this.ModuleCompBase.Init(service, module, comp, options) this.options = options.(*Options) - this.moduleWeb = module.(*Web) + this.module = module.(*GM) this.gin, err = gin.NewSys(gin.SetListenPort(this.options.Port)) this.gin.POST("/register", this.Register) this.gin.GET("/serverlist", this.ServerList) diff --git a/modules/gm/api_createnotify.go b/modules/gm/api_createnotify.go new file mode 100644 index 000000000..b98a73a05 --- /dev/null +++ b/modules/gm/api_createnotify.go @@ -0,0 +1,46 @@ +package gm + +import ( + "go_dreamfactory/lego/sys/gin" + "go_dreamfactory/lego/sys/gin/engine" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/pb" + "net/http" +) + +type CreateNotifyReq struct { + pb.DBSystemNotify + Sign string `json:"sign"` +} + +//服务列表 +func (this *Api_Comp) CreateNotify(c *engine.Context) { + req := &CreateNotifyReq{} + c.BindJSON(&req) + defer log.Debugf("CreateNotify:%+v", req) + var ( + code pb.ErrorCode + msg string + data interface{} + err error + ) + c.JSON(http.StatusOK, &Respond{Code: code, Message: msg, Data: data}) + if sign := gin.ParamSign(this.options.Key, map[string]interface{}{"Title": req.Title, "Ctime": req.Ctime, "Rtime": req.Rtime}); sign != req.Sign { + log.Errorf("LoginByCaptchaReq SignError sgin:%s", sign) + code = pb.ErrorCode_SignError + msg = pb.GetErrorCodeMsg(code) + return + } + if len(req.Title) == 0 { + code = pb.ErrorCode_ReqParameterError + msg = pb.GetErrorCodeMsg(code) + return + } + if err = this.module.modelNotify.CreateSystemNotify(&req.DBSystemNotify); err != nil { + log.Errorf("LoginByCaptchaReq CreateSystemNotify err:%v", err) + code = pb.ErrorCode_DBError + msg = pb.GetErrorCodeMsg(code) + return + } + msg = pb.GetErrorCodeMsg(code) +} diff --git a/modules/web/api_register.go b/modules/gm/api_register.go similarity index 89% rename from modules/web/api_register.go rename to modules/gm/api_register.go index 2e191c4c6..424d72c9b 100644 --- a/modules/web/api_register.go +++ b/modules/gm/api_register.go @@ -1,4 +1,4 @@ -package web +package gm import ( "go_dreamfactory/lego/sys/gin/engine" @@ -13,7 +13,7 @@ func (this *Api_Comp) Register(c *engine.Context) { rsp := &pb.UserRegisterResp{} err := c.BindJSON(&req) if err == nil { - err := this.moduleWeb.modelUser.User_Create(&pb.DBUser{ + err := this.module.modelUser.User_Create(&pb.DBUser{ Binduid: req.Account, Sid: req.Sid, }) diff --git a/modules/web/api_srvlist.go b/modules/gm/api_srvlist.go similarity index 71% rename from modules/web/api_srvlist.go rename to modules/gm/api_srvlist.go index 96d2ed429..b4be53916 100644 --- a/modules/web/api_srvlist.go +++ b/modules/gm/api_srvlist.go @@ -1,4 +1,4 @@ -package web +package gm import ( "go_dreamfactory/lego/sys/gin/engine" @@ -7,7 +7,7 @@ import ( //服务列表 func (this *Api_Comp) ServerList(c *engine.Context) { - conf := this.moduleWeb.configure.getServerListConf() + conf := this.module.configure.getServerListConf() c.JSON(http.StatusOK, conf) } diff --git a/modules/web/config.go b/modules/gm/config.go similarity index 98% rename from modules/web/config.go rename to modules/gm/config.go index b714579a9..a3dff571f 100644 --- a/modules/web/config.go +++ b/modules/gm/config.go @@ -1,4 +1,4 @@ -package web +package gm import ( "fmt" diff --git a/modules/gm/core.go b/modules/gm/core.go new file mode 100644 index 000000000..27fdba7a7 --- /dev/null +++ b/modules/gm/core.go @@ -0,0 +1,9 @@ +package gm + +import "go_dreamfactory/pb" + +type Respond struct { + Code pb.ErrorCode `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} diff --git a/modules/gm/modelNotify.go b/modules/gm/modelNotify.go new file mode 100644 index 000000000..3a2704918 --- /dev/null +++ b/modules/gm/modelNotify.go @@ -0,0 +1,42 @@ +package gm + +import ( + "go_dreamfactory/lego/core" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/modules" + "go_dreamfactory/pb" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/x/bsonx" +) + +///论坛 数据组件 +type modelNotifyComp struct { + modules.MCompModel + module *GM +} + +//组件初始化接口 +func (this *modelNotifyComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.MCompModel.Init(service, module, comp, opt) + this.module = module.(*GM) + this.TableName = "notify" + //创建uid索引 + this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ + Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, + }) + return +} + +//创建系统公告 +func (this *modelNotifyComp) CreateSystemNotify(notify *pb.DBSystemNotify) (err error) { + if _, err = this.DB.InsertOne(core.SqlTable(this.TableName), notify); err != nil { + log.Errorf("CreateSystemNotify err:%v", err) + return + } + if err = this.Redis.HSet(this.TableName, notify.Id, notify); err != nil { + log.Errorf("CreateSystemNotify err:%v", err) + return + } + return +} diff --git a/modules/web/module.go b/modules/gm/module.go similarity index 53% rename from modules/web/module.go rename to modules/gm/module.go index aff0f40df..eb5b7368e 100644 --- a/modules/web/module.go +++ b/modules/gm/module.go @@ -1,4 +1,4 @@ -package web +package gm import ( "go_dreamfactory/comm" @@ -9,40 +9,41 @@ import ( ) /* -模块名:web -描述:为服务集群提供一些http服务接口 方便测试和后期运维实现 +模块名:gm +描述:提供管理员相关的http接口 开发:李伟 */ func NewModule() core.IModule { - m := new(Web) + m := new(GM) return m } -type Web struct { +type GM struct { cbase.ModuleBase - options *Options - api_comp *Api_Comp //提供weba pi服务的组件 - modelUser *user.ModelUser - configure *configureComp + options *Options + api_comp *Api_Comp //提供weba pi服务的组件 + modelUser *user.ModelUser + modelNotify *modelNotifyComp + configure *configureComp } //模块名 -func (this *Web) GetType() core.M_Modules { - return comm.ModuleWeb +func (this *GM) GetType() core.M_Modules { + return comm.ModuleGM } //模块自定义参数 -func (this *Web) NewOptions() (options core.IModuleOptions) { +func (this *GM) NewOptions() (options core.IModuleOptions) { return new(Options) } -func (this *Web) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { +func (this *GM) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { err = this.ModuleBase.Init(service, module, options) this.options = options.(*Options) return } -func (this *Web) OnInstallComp() { +func (this *GM) OnInstallComp() { this.ModuleBase.OnInstallComp() this.api_comp = this.RegisterComp(new(Api_Comp)).(*Api_Comp) this.modelUser = this.RegisterComp(new(user.ModelUser)).(*user.ModelUser) diff --git a/modules/web/options.go b/modules/gm/options.go similarity index 64% rename from modules/web/options.go rename to modules/gm/options.go index 3750894b2..014d10431 100644 --- a/modules/web/options.go +++ b/modules/gm/options.go @@ -1,17 +1,23 @@ -package web +package gm import ( "go_dreamfactory/lego/utils/mapstructure" + "go_dreamfactory/modules" ) type ( Options struct { + modules.Options Port int + Key string } ) func (this *Options) LoadConfig(settings map[string]interface{}) (err error) { if settings != nil { + if err = this.Options.LoadConfig(settings); err != nil { + return + } err = mapstructure.Decode(settings, this) } return diff --git a/modules/hero/model_hero.go b/modules/hero/model_hero.go index 02b50aaa3..82907b50b 100644 --- a/modules/hero/model_hero.go +++ b/modules/hero/model_hero.go @@ -11,6 +11,8 @@ import ( mengine "github.com/dengsgo/math-engine/engine" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/x/bsonx" ) type ModelHero struct { @@ -22,6 +24,10 @@ func (this *ModelHero) Init(service core.IService, module core.IModule, comp cor err = this.MCompModel.Init(service, module, comp, options) this.moduleHero = module.(*Hero) this.TableName = "hero" + // 通过uid创建索引 + this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ + Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, + }) return } diff --git a/modules/items/api_getlist.go b/modules/items/api_getlist.go index d66210dbf..6239280d1 100644 --- a/modules/items/api_getlist.go +++ b/modules/items/api_getlist.go @@ -2,7 +2,6 @@ package items import ( "go_dreamfactory/comm" - "go_dreamfactory/lego/sys/log" "go_dreamfactory/pb" "time" @@ -30,21 +29,25 @@ func (this *apiComp) Getlist(session comm.IUserSession, req *pb.ItemsGetlistReq) session.SendMsg(string(this.module.GetType()), "getlist", &pb.ItemsGetlistResp{Grids: grids}) if code == pb.ErrorCode_Success { go func() { //异步处理修改数据 - this.module.modelItems.Pack_UpdateUserPack(session.GetUserId(), modifys...) - this.module.modelItems.Pack_DeleteUserPack(session.GetUserId(), dels...) + if len(modifys) > 0 { + this.module.modelItems.Pack_UpdateUserPack(session.GetUserId(), modifys...) + } + if len(dels) > 0 { + this.module.modelItems.Pack_DeleteUserPack(session.GetUserId(), dels...) + } }() } }() if items, err = this.module.modelItems.Pack_QueryUserPack(session.GetUserId()); err != nil { - log.Errorf("QueryUserPackReq err:%v", err) + this.module.Errorf("QueryUserPackReq err:%v", err) code = pb.ErrorCode_CacheReadError return } else { tempgrids = this.module.configure.GetPackItemByType(items, req.IType) modifys = make([]*pb.DB_UserItemData, 0, len(tempgrids)) dels = make([]string, 0, len(tempgrids)) - grids = make([]*pb.DB_UserItemData, 0, len(grids)) + grids = make([]*pb.DB_UserItemData, 0, len(items)) nt = time.Now().Unix() for _, v := range tempgrids { if v.ETime > 0 && v.ETime < nt { //已经过期 diff --git a/modules/items/configure.go b/modules/items/configure.go index 9eb3972f2..e4b686cc3 100644 --- a/modules/items/configure.go +++ b/modules/items/configure.go @@ -7,7 +7,6 @@ import ( cfg "go_dreamfactory/sys/configure/structs" "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/log" ) const ( @@ -17,11 +16,13 @@ const ( ///背包配置管理组件 type ConfigureComp struct { modules.MCompConfigure + module *Items } //组件初始化接口 func (this *ConfigureComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.MCompConfigure.Init(service, module, comp, options) + this.module = module.(*Items) err = this.LoadConfigure(game_item, cfg.NewGame_item) return } @@ -32,7 +33,7 @@ func (this *ConfigureComp) GetItemsConfigure() (items map[int32]*cfg.Game_itemDa v interface{} ) if v, err = this.GetConfigure(game_item); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { items = v.(*cfg.Game_item).GetDataMap() @@ -47,12 +48,12 @@ func (this *ConfigureComp) GetItemConfigure(id int32) (item *cfg.Game_itemData, ok bool ) if v, err = this.GetConfigure(game_item); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { if item, ok = v.(*cfg.Game_item).GetDataMap()[id]; !ok { err = fmt.Errorf("no found item:%d configure", id) - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } } @@ -70,7 +71,7 @@ func (this *ConfigureComp) GetPackItemByType(itmes []*pb.DB_UserItemData, usetyp err error ) if v, err = this.GetConfigure(game_item); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { table = v.(*cfg.Game_item) @@ -80,7 +81,7 @@ func (this *ConfigureComp) GetPackItemByType(itmes []*pb.DB_UserItemData, usetyp result = append(result, v) } } else { - log.Errorf("no found itemConfigure:%d", v.ItemId) + this.module.Errorf("no found itemConfigure:%d", v.ItemId) } } } diff --git a/modules/items/modelitems.go b/modules/items/modelitems.go index 05bea94f6..d1a1b8e68 100644 --- a/modules/items/modelitems.go +++ b/modules/items/modelitems.go @@ -34,14 +34,18 @@ func (this *ModelItemsComp) Init(service core.IService, module core.IModule, com ///查询用户背包数据 func (this *ModelItemsComp) Pack_QueryUserPack(uId string) (itmes []*pb.DB_UserItemData, err error) { itmes = make([]*pb.DB_UserItemData, 0) - err = this.GetList(uId, &itmes) + if err = this.GetList(uId, &itmes); err != nil { + this.module.Errorf("err:%v", err) + } return } ///查询用户指定格子的物品数据 func (this *ModelItemsComp) Pack_QueryUserPackByGridId(uId string, grid string) (itme *pb.DB_UserItemData, err error) { itme = &pb.DB_UserItemData{} - err = this.GetListObj(uId, grid, itme) + if err = this.GetListObj(uId, grid, itme); err != nil { + this.module.Errorf("err:%v", err) + } return } @@ -55,7 +59,9 @@ func (this *ModelItemsComp) Pack_AddUserPack(uId string, itmes ...*pb.DB_UserIte //更新用户的背包信息 func (this *ModelItemsComp) Pack_DelUserPack(uId string, ids ...string) (err error) { - err = this.DelListlds(uId, ids...) + if err = this.DelListlds(uId, ids...); err != nil { + this.module.Errorf("err:%v", err) + } return } @@ -71,7 +77,10 @@ func (this *ModelItemsComp) Pack_UpdateUserPack(uId string, itmes ...*pb.DB_User //更新用户的背包信息 func (this *ModelItemsComp) Pack_DeleteUserPack(uId string, gridIds ...string) (err error) { - err = this.DelListlds(uId, gridIds...) + if err = this.DelListlds(uId, gridIds...); err != nil { + this.module.Errorf("err:%v", err) + return + } return } @@ -82,6 +91,7 @@ func (this *ModelItemsComp) Pack_QueryUserPackItemsAmount(uId string, itemid ... err error ) if itmes, err = this.Pack_QueryUserPack(uId); err != nil { + this.module.Errorf("err:%v", err) return } result = map[int32]uint32{} @@ -108,6 +118,7 @@ func (this *ModelItemsComp) Pack_AddItemToUserPack(uId string, itemId int32, add return } if itmes, err = this.Pack_QueryUserPack(uId); err != nil { + this.module.Errorf("err:%v", err) return } add, update, del, leftnum = this.pack_addItemToUserPack(itmes, itemId, addnum) @@ -120,16 +131,19 @@ func (this *ModelItemsComp) Pack_AddItemToUserPack(uId string, itemId int32, add } if len(add) > 0 { if err = this.Pack_AddUserPack(uId, add...); err != nil { + this.module.Errorf("err:%v", err) return } } if len(del) > 0 { if err = this.Pack_DeleteUserPack(uId, del...); err != nil { + this.module.Errorf("err:%v", err) return } } if len(update) > 0 { if err = this.Pack_UpdateUserPack(uId, update...); err != nil { + this.module.Errorf("err:%v", err) return } } @@ -147,6 +161,7 @@ func (this *ModelItemsComp) Pack_AddItemsToUserPack(uId string, items map[int32] leftnum int64 ) if itmes, err = this.Pack_QueryUserPack(uId); err != nil { + this.module.Errorf("err:%v", err) return } for k, v := range items { @@ -160,16 +175,19 @@ func (this *ModelItemsComp) Pack_AddItemsToUserPack(uId string, items map[int32] } if len(add) > 0 { if err = this.Pack_AddUserPack(uId, add...); err != nil { + this.module.Errorf("err:%v", err) return } } if len(del) > 0 { if err = this.Pack_DeleteUserPack(uId, del...); err != nil { + this.module.Errorf("err:%v", err) return } } if len(update) > 0 { if err = this.Pack_UpdateUserPack(uId, update...); err != nil { + this.module.Errorf("err:%v", err) return } } @@ -190,10 +208,12 @@ func (this *ModelItemsComp) Pack_AddItemToUserPackByGrid(uId string, gridid stri return } if conf, err = this.module.configure.GetItemConfigure(itemId); err != nil { + this.module.Errorf("err:%v", err) return } if itme, err = this.Pack_QueryUserPackByGridId(uId, gridid); err != nil { + this.module.Errorf("err:%v", err) return } amount = int64(itme.Amount) diff --git a/modules/items/module.go b/modules/items/module.go index 7958944d2..27a809184 100644 --- a/modules/items/module.go +++ b/modules/items/module.go @@ -6,7 +6,6 @@ import ( "go_dreamfactory/pb" "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/log" ) /* @@ -48,7 +47,7 @@ func (this *Items) OnInstallComp() { //IItems------------------------------------------------------------------------------------------------------------------------------- ///查询用户背包物品数量 func (this *Items) QueryItemAmount(source *comm.ModuleCallSource, uId string, itemid int32) (amount uint32) { - defer log.Debugf("获取物品 uId:%s itemid:%d addnum:%d ", uId, itemid, amount) + defer this.Debugf("获取物品 uId:%s itemid:%d addnum:%d ", uId, itemid, amount) amount = 0 if result := this.modelItems.Pack_QueryUserPackItemsAmount(uId, itemid); result != nil && len(result) > 0 { return result[itemid] @@ -65,9 +64,9 @@ func (this *Items) QueryItemsAmount(source *comm.ModuleCallSource, uId string, i ///添加单个物品到背包 (可以加物品和减物品) func (this *Items) AddItem(source *comm.ModuleCallSource, uId string, itemid, addnum int32) (code pb.ErrorCode) { var err error - defer log.Debugf("给用户添加物品 uId:%s itemid:%d addnum:%d issucc:%v", uId, itemid, addnum, err == nil) + defer this.Debugf("给用户添加物品 uId:%s itemid:%d addnum:%d issucc:%v", uId, itemid, addnum, err == nil) if err = this.modelItems.Pack_AddItemToUserPack(uId, itemid, addnum); err != nil { - log.Errorf("给用户添加物品 uId:%s itemid:%d addnum:%d err:%v", uId, itemid, addnum, err) + this.Errorf("给用户添加物品 uId:%s itemid:%d addnum:%d err:%v", uId, itemid, addnum, err) if err == ItemNotEnoughError { code = pb.ErrorCode_ItemsNoEnough } else if err == PackGridNumUpper { @@ -82,9 +81,9 @@ func (this *Items) AddItem(source *comm.ModuleCallSource, uId string, itemid, ad ///添加多个物品到背包 (可以加物品和减物品) func (this *Items) AddItems(source *comm.ModuleCallSource, uId string, items map[int32]int32) (code pb.ErrorCode) { var err error - defer log.Debugf("给用户添加物品 uId:%s items:%d items:%v", uId, items, err == nil) + defer this.Debugf("给用户添加物品 uId:%s items:%d items:%v", uId, items, err == nil) if err = this.modelItems.Pack_AddItemsToUserPack(uId, items); err != nil { - log.Errorf("给用户添加物品 uId:%s items:%d err:%v", uId, items, err) + this.Errorf("给用户添加物品 uId:%s items:%d err:%v", uId, items, err) if err == ItemNotEnoughError { code = pb.ErrorCode_ItemsNoEnough } else if err == PackGridNumUpper { diff --git a/modules/items/module_test.go b/modules/items/module_test.go index cee4d4ae1..448ad187a 100644 --- a/modules/items/module_test.go +++ b/modules/items/module_test.go @@ -11,6 +11,7 @@ import ( "go_dreamfactory/modules/equipment" "go_dreamfactory/modules/hero" "go_dreamfactory/modules/items" + "go_dreamfactory/modules/task" "go_dreamfactory/modules/user" "go_dreamfactory/pb" "go_dreamfactory/services" @@ -74,6 +75,7 @@ func TestMain(m *testing.M) { hero.NewModule(), user.NewModule(), equipment.NewModule(), + task.NewModule(), ) }() time.Sleep(time.Second * 3) @@ -81,10 +83,10 @@ func TestMain(m *testing.M) { } func Test_Modules(t *testing.T) { - data, _ := ptypes.MarshalAny(&pb.ItemsGetlistReq{}) - s_gateComp.ReceiveMsg(context.Background(), &pb.AgentMessage{MainType: "pack", SubType: "getlist", Message: data}, &pb.RPCMessageReply{}) - // items, err := module.db_comp.Pack_QueryUserPack("liwei1dao") - // log.Debugf("item:%v err:%v", items, err) + data, _ := ptypes.MarshalAny(&pb.ItemsGetlistReq{IType: 9}) + reply := &pb.RPCMessageReply{} + s_gateComp.ReceiveMsg(context.Background(), &pb.AgentMessage{UserId: "0_62cd5952f72cc4bdc2d85f6b", MainType: "items", SubType: "getlist", Message: data}, reply) + log.Debugf("reply:%v", reply) } func Test_Modules_AddItems(t *testing.T) { @@ -93,5 +95,5 @@ func Test_Modules_AddItems(t *testing.T) { FuncName: "Test_Modules_AddItems", Describe: "测试模块接口", }, "0_62c259916d8cf3e4e06311a8", map[int32]int32{10001: 1000}) - log.Debugf("Test_Modules_AddItems:%v code:%v", code) + log.Debugf("Test_Modules_AddItems code:%v", code) } diff --git a/modules/mail/api.go b/modules/mail/api.go index ad063b9a9..0e0aa3aca 100644 --- a/modules/mail/api.go +++ b/modules/mail/api.go @@ -6,14 +6,6 @@ import ( "go_dreamfactory/lego/core" ) -const ( - QueryUserMailResp = "queryusermailresp" - ReadUserMailResp = "readusermailresp" - GetUserMailAttachmentResp = "getusermailattachmentresp" - DelUserMailResp = "delusermailresp" - GetNewEMailResp = "getnewEmailresp" -) - type apiComp struct { modules.MCompGate service core.IService diff --git a/modules/mail/api_delmail.go b/modules/mail/api_delmail.go index 3c5efcbc5..504c55350 100644 --- a/modules/mail/api_delmail.go +++ b/modules/mail/api_delmail.go @@ -11,7 +11,7 @@ import ( //参数校验 func (this *apiComp) DelMailCheck(session comm.IUserSession, req *pb.MailDelMailReq) (code pb.ErrorCode) { if session.GetUserId() == "" || req.ObjID == "" { - code = pb.ErrorCode_NoLogin + code = pb.ErrorCode_ReqParameterError return } return @@ -23,7 +23,7 @@ func (this *apiComp) DelMail(session comm.IUserSession, req *pb.MailDelMailReq) var err error mailinfo := make([]*pb.DBMailData, 0) defer func() { - session.SendMsg(string(this.module.GetType()), DelUserMailResp, &pb.MailDelMailResp{Mail: mailinfo}) + session.SendMsg(string(this.module.GetType()), "delmail", &pb.MailDelMailResp{Mail: mailinfo}) }() code = this.DelMailCheck(session, req) // check if code != pb.ErrorCode_Success { diff --git a/modules/mail/api_getAttachment.go b/modules/mail/api_getAttachment.go index 72c733ac7..5773360f7 100644 --- a/modules/mail/api_getAttachment.go +++ b/modules/mail/api_getAttachment.go @@ -22,7 +22,7 @@ func (this *apiComp) GetUserMailAttachment(session comm.IUserSession, req *pb.Ma mail *pb.DBMailData ) defer func() { - session.SendMsg(string(this.module.GetType()), GetUserMailAttachmentResp, &pb.MailGetUserMailAttachmentResp{Mail: mail}) + session.SendMsg(string(this.module.GetType()), "getusermailattachment", &pb.MailGetUserMailAttachmentResp{Mail: mail}) }() code = this.GetUserMailAttachmentCheck(session, req) // check diff --git a/modules/mail/api_getmail.go b/modules/mail/api_getmail.go index 56af62a0f..cf610060a 100644 --- a/modules/mail/api_getmail.go +++ b/modules/mail/api_getmail.go @@ -18,7 +18,7 @@ func (this *apiComp) GetList(session comm.IUserSession, req *pb.MailGetListReq) var err error mailinfo := make([]*pb.DBMailData, 0) defer func() { - session.SendMsg(string(this.module.GetType()), QueryUserMailResp, &pb.MailGetListResp{Mails: mailinfo}) + session.SendMsg(string(this.module.GetType()), "getlist", &pb.MailGetListResp{Mails: mailinfo}) }() code = this.GetListCheck(session, req) // check if code != pb.ErrorCode_Success { diff --git a/modules/mail/api_readmail.go b/modules/mail/api_readmail.go index 81d222aca..0e4c4be7b 100644 --- a/modules/mail/api_readmail.go +++ b/modules/mail/api_readmail.go @@ -9,7 +9,7 @@ import ( func (this *apiComp) ReadMailCheck(session comm.IUserSession, req *pb.MailReadMailReq) (code pb.ErrorCode) { if session.GetUserId() == "" || req.ObjID == "" { - code = pb.ErrorCode_NoLogin + code = pb.ErrorCode_ReqParameterError return } return @@ -22,7 +22,7 @@ func (this *apiComp) ReadMail(session comm.IUserSession, req *pb.MailReadMailReq mail *pb.DBMailData ) defer func() { - session.SendMsg(string(this.module.GetType()), ReadUserMailResp, &pb.MailReadMailResp{Mail: mail}) + session.SendMsg(string(this.module.GetType()), "readmail", &pb.MailReadMailResp{Mail: mail}) }() code = this.ReadMailCheck(session, req) // check if code != pb.ErrorCode_Success { diff --git a/modules/mail/module.go b/modules/mail/module.go index 088a57d01..c652bc61a 100644 --- a/modules/mail/module.go +++ b/modules/mail/module.go @@ -62,6 +62,6 @@ func (this *Mail) CreateNewMail(uId string, mail *pb.DBMailData) bool { return false } - this.SendMsgToUser(string(this.GetType()), GetNewEMailResp, mail, _cache) + this.SendMsgToUser(string(this.GetType()), "newmail", mail, _cache) return true } diff --git a/modules/dbservice/core.go b/modules/mgolog/core.go similarity index 94% rename from modules/dbservice/core.go rename to modules/mgolog/core.go index 6c7345fa7..56bc17551 100644 --- a/modules/dbservice/core.go +++ b/modules/mgolog/core.go @@ -1,4 +1,4 @@ -package dbservice +package mgolog import ( "go_dreamfactory/lego/core" diff --git a/modules/dbservice/db_comp.go b/modules/mgolog/db_comp.go similarity index 99% rename from modules/dbservice/db_comp.go rename to modules/mgolog/db_comp.go index 366d945e1..858810e0e 100644 --- a/modules/dbservice/db_comp.go +++ b/modules/mgolog/db_comp.go @@ -1,4 +1,4 @@ -package dbservice +package mgolog import ( "context" diff --git a/modules/dbservice/module.go b/modules/mgolog/module.go similarity index 53% rename from modules/dbservice/module.go rename to modules/mgolog/module.go index 3e8a81eaa..5259cf42a 100644 --- a/modules/dbservice/module.go +++ b/modules/mgolog/module.go @@ -1,4 +1,4 @@ -package dbservice +package mgolog import ( "go_dreamfactory/comm" @@ -7,26 +7,26 @@ import ( ) func NewModule() core.IModule { - m := new(DBService) + m := new(MgoLog) return m } -type DBService struct { +type MgoLog struct { cbase.ModuleBase db_comp *DB_Comp } -func (this *DBService) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { +func (this *MgoLog) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { err = this.ModuleBase.Init(service, module, options) return } -func (this *DBService) GetType() core.M_Modules { - return comm.ModuleLogModel +func (this *MgoLog) GetType() core.M_Modules { + return comm.ModuleMgoLog } -func (this *DBService) OnInstallComp() { +func (this *MgoLog) OnInstallComp() { this.ModuleBase.OnInstallComp() this.db_comp = this.RegisterComp(new(DB_Comp)).(*DB_Comp) } diff --git a/modules/modulebase.go b/modules/modulebase.go index 21c5d6d87..52b611ccc 100644 --- a/modules/modulebase.go +++ b/modules/modulebase.go @@ -23,6 +23,7 @@ type ModuleBase struct { cbase.ModuleBase module core.IModule service base.IRPCXService + options IOptions scomp comm.ISC_GateRouteComp //网关服务组件 //常用的一些通用模块 在底层注册好 ModuleUser comm.IUser //用户模块 @@ -32,11 +33,17 @@ type ModuleBase struct { ModuleTask comm.ITask //任务 } +//重构模块配置对象 +func (this *ModuleBase) NewOptions() (options core.IModuleOptions) { + return new(Options) +} + //模块初始化接口 func (this *ModuleBase) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { err = this.ModuleBase.Init(service, module, options) this.service = service.(base.IRPCXService) this.module = module + this.options = options.(IOptions) return } @@ -228,3 +235,29 @@ func (this *ModuleBase) DispenseRes(uid string, res []*cfg.Game_atn) (code pb.Er } return } + +//日志接口 +func (this *ModuleBase) Debugf(format string, a ...interface{}) { + if this.options.GetDebug() { + this.options.GetLog().Debugf(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) + } +} +func (this *ModuleBase) Infof(format string, a ...interface{}) { + if this.options.GetDebug() { + this.options.GetLog().Infof(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) + } +} +func (this *ModuleBase) Warnf(format string, a ...interface{}) { + if this.options.GetDebug() { + this.options.GetLog().Warnf(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) + } +} +func (this *ModuleBase) Errorf(format string, a ...interface{}) { + this.options.GetLog().Errorf(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) +} +func (this *ModuleBase) Panicf(format string, a ...interface{}) { + this.options.GetLog().Panicf(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) +} +func (this *ModuleBase) Fatalf(format string, a ...interface{}) { + this.options.GetLog().Fatalf(fmt.Sprintf("[Module:%s] ", this.module.GetType())+format, a...) +} diff --git a/modules/notify/api.go b/modules/notify/api.go new file mode 100644 index 000000000..2158dd643 --- /dev/null +++ b/modules/notify/api.go @@ -0,0 +1,29 @@ +package notify + +import ( + "go_dreamfactory/modules" + + "go_dreamfactory/lego/core" +) + +/* +API +*/ +type apiComp struct { + modules.MCompGate + service core.IService + module *Notification +} + +//组件初始化接口 +func (this *apiComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.MCompGate.Init(service, module, comp, options) + this.module = module.(*Notification) + this.service = service + return +} + +func (this *apiComp) Start() (err error) { + err = this.MCompGate.Start() + return +} diff --git a/modules/notify/api_getlist.go b/modules/notify/api_getlist.go new file mode 100644 index 000000000..00c8028a2 --- /dev/null +++ b/modules/notify/api_getlist.go @@ -0,0 +1,38 @@ +package notify + +import ( + "go_dreamfactory/comm" + "go_dreamfactory/pb" + + "github.com/golang/protobuf/proto" +) + +//参数校验 +func (this *apiComp) GetlistCheck(session comm.IUserSession, req *pb.NotifyGetListReq) (code pb.ErrorCode) { + + return +} + +///获取系统公告 +func (this *apiComp) Getlist(session comm.IUserSession, req *pb.NotifyGetListReq) (code pb.ErrorCode, data proto.Message) { + var ( + err error + userexpand *pb.DBUserExpand + notify []*pb.DBSystemNotify + ) + defer func() { + session.SendMsg(string(this.module.GetType()), "getlist", &pb.NotifyGetListResp{LastReadTime: userexpand.Lastreadnotiftime, SysNotify: notify}) + }() + if notify, err = this.module.modelNotify.GetFullNotify(); err != nil { + code = pb.ErrorCode_DBError + return + } + if session.GetUserId() != "" { + if userexpand, err = this.module.modelNotify.GetUserExpand(session.GetUserId()); err != nil { + code = pb.ErrorCode_DBError + } + } else { + userexpand = &pb.DBUserExpand{} + } + return +} diff --git a/modules/notify/core.go b/modules/notify/core.go new file mode 100644 index 000000000..a3131f139 --- /dev/null +++ b/modules/notify/core.go @@ -0,0 +1 @@ +package notify diff --git a/modules/notify/modelNotify.go b/modules/notify/modelNotify.go new file mode 100644 index 000000000..dcb684ae4 --- /dev/null +++ b/modules/notify/modelNotify.go @@ -0,0 +1,69 @@ +package notify + +import ( + "context" + "go_dreamfactory/lego/core" + "go_dreamfactory/modules" + "go_dreamfactory/pb" + "time" + + "github.com/go-redis/redis/v8" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/x/bsonx" +) + +///论坛 数据组件 +type modelNotifyComp struct { + modules.MCompModel + module *Notification +} + +//组件初始化接口 +func (this *modelNotifyComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.MCompModel.Init(service, module, comp, opt) + this.module = module.(*Notification) + this.TableName = "notify" + //创建uid索引 + this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ + Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, + }) + return +} + +//获取全部公告 +func (this *modelNotifyComp) GetFullNotify() (result []*pb.DBSystemNotify, err error) { + var ( + notifys map[string]*pb.DBSystemNotify = make(map[string]*pb.DBSystemNotify) + c *mongo.Cursor + ) + if err = this.Redis.HGetAll(this.TableName, notifys); err != nil && err == redis.Nil { + if c, err = this.DB.Find(core.SqlTable(this.TableName), bson.M{}); err == nil { + for c.Next(context.Background()) { + notify := &pb.DBSystemNotify{} + if err = c.Decode(notify); err != nil { + this.module.Errorf("GetFullNotify err:%v", err) + break + } + notifys[notify.Id] = notify + } + if len(notifys) > 0 { + if err = this.Redis.HMSet(this.TableName, notifys); err != nil { + this.module.Errorf("GetFullNotify err:%v", err) + } + } + } + } + if len(notifys) > 0 { + n := 0 + now := time.Now().Unix() + result = make([]*pb.DBSystemNotify, len(notifys)) + for _, v := range notifys { + if now >= v.Rtime { + result[n] = v + n++ + } + } + } + return +} diff --git a/modules/notify/module.go b/modules/notify/module.go new file mode 100644 index 000000000..2b857732a --- /dev/null +++ b/modules/notify/module.go @@ -0,0 +1,42 @@ +package notify + +import ( + "go_dreamfactory/comm" + "go_dreamfactory/lego/core" + "go_dreamfactory/modules" +) + +/* +模块名:公告系统 +是否跨服:是 +描述:提供运营后台发布全服公告 +开发:李伟 +*/ +func NewModule() core.IModule { + m := new(Notification) + return m +} + +type Notification struct { + modules.ModuleBase + api_comp *apiComp + modelNotify *modelNotifyComp +} + +//模块名 +func (this *Notification) GetType() core.M_Modules { + return comm.ModuleEquipment +} + +//模块初始化接口 注册用户创建角色事件 +func (this *Notification) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { + err = this.ModuleBase.Init(service, module, options) + return +} + +//装备组件 +func (this *Notification) OnInstallComp() { + this.ModuleBase.OnInstallComp() + this.api_comp = this.RegisterComp(new(apiComp)).(*apiComp) + this.modelNotify = this.RegisterComp(new(modelNotifyComp)).(*modelNotifyComp) +} diff --git a/modules/notify/module_test.go b/modules/notify/module_test.go new file mode 100644 index 000000000..40eabc811 --- /dev/null +++ b/modules/notify/module_test.go @@ -0,0 +1,74 @@ +package notify + +import ( + "fmt" + "go_dreamfactory/comm" + "go_dreamfactory/lego" + "go_dreamfactory/lego/base/rpcx" + "go_dreamfactory/lego/core" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/services" + "go_dreamfactory/sys/cache" + "go_dreamfactory/sys/configure" + "go_dreamfactory/sys/db" + "os" + "testing" + "time" +) + +func newService(ops ...rpcx.Option) core.IService { + s := new(TestService) + s.Configure(ops...) + return s +} + +//梦工厂基础服务对象 +type TestService struct { + rpcx.RPCXService +} + +//初始化相关系统 +func (this *TestService) InitSys() { + this.RPCXService.InitSys() + if err := cache.OnInit(this.GetSettings().Sys["cache"]); err != nil { + panic(fmt.Sprintf("init sys.cache err: %s", err.Error())) + } else { + log.Infof("init sys.cache success!") + } + if err := db.OnInit(this.GetSettings().Sys["db"]); err != nil { + panic(fmt.Sprintf("init sys.db err: %s", err.Error())) + } else { + log.Infof("init sys.db success!") + } + if err := configure.OnInit(this.GetSettings().Sys["configure"]); err != nil { + panic(fmt.Sprintf("init sys.configure err: %s", err.Error())) + } else { + log.Infof("init sys.configure success!") + } +} + +var service core.IService +var s_gateComp comm.ISC_GateRouteComp = services.NewGateRouteComp() +var module = new(Notification) + +//测试环境下初始化db和cache 系统 +func TestMain(m *testing.M) { + service = newService( + rpcx.SetConfPath("../../bin/conf/worker_1.yaml"), + rpcx.SetVersion("1.0.0.0"), + ) + service.OnInstallComp( //装备组件 + s_gateComp, //此服务需要接受用户的消息 需要装备网关组件 + ) + go func() { + lego.Run(service, //运行模块 + module, + ) + }() + time.Sleep(time.Second * 3) + defer os.Exit(m.Run()) +} + +func Test_Module(t *testing.T) { + +} diff --git a/modules/options.go b/modules/options.go new file mode 100644 index 000000000..a24bca798 --- /dev/null +++ b/modules/options.go @@ -0,0 +1,42 @@ +package modules + +import ( + "fmt" + "go_dreamfactory/lego/core" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/lego/utils/mapstructure" +) + +type ( + IOptions interface { + core.IModuleOptions + GetDebug() bool + GetLog() log.ILog + } + Options struct { + Debug bool //日志是否开启 + Log log.ILog + } +) + +func (this *Options) GetDebug() bool { + return this.Debug +} + +func (this *Options) GetLog() log.ILog { + return this.Log +} + +func (this *Options) LoadConfig(settings map[string]interface{}) (err error) { + if settings != nil { + err = mapstructure.Decode(settings, this) + } + if this.Debug && this.Log == nil { + this.Log = log.Clone() + if this.Log == nil { + err = fmt.Errorf("Log is nil") + return + } + } + return +} diff --git a/modules/shop/configure.go b/modules/shop/configure.go index a646a6807..2fc1d3a0c 100644 --- a/modules/shop/configure.go +++ b/modules/shop/configure.go @@ -3,7 +3,6 @@ package shop import ( "fmt" "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" "go_dreamfactory/pb" cfg "go_dreamfactory/sys/configure/structs" @@ -17,11 +16,13 @@ const ( ///背包配置管理组件 type configureComp struct { modules.MCompConfigure + module *Shop } //组件初始化接口 func (this *configureComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.ModuleCompBase.Init(service, module, comp, options) + this.module = module.(*Shop) this.LoadConfigure(game_shop, cfg.NewGame_shop) this.LoadConfigure(game_shopitem, cfg.NewGame_shopitem) return @@ -34,12 +35,12 @@ func (this *configureComp) GetShopConfigure(id int32) (configure *cfg.Game_shopD ok bool ) if v, err = this.GetConfigure(game_shop); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { if configure, ok = v.(*cfg.Game_shop).GetDataMap()[id]; !ok { err = fmt.Errorf("ShopConfigure not found:%d ", id) - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } } @@ -53,12 +54,12 @@ func (this *configureComp) GetShopItemsConfigure(key int32) (result *cfg.Game_sh ok bool ) if v, err = this.GetConfigure(game_shopitem); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { if result, ok = v.(*cfg.Game_shopitem).GetDataMap()[key]; !ok { err = fmt.Errorf("ShopConfigure not found:%d ", key) - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } } @@ -73,7 +74,7 @@ func (this *configureComp) GetShopItemsConfigureByGroups(groupid int32, user *pb table *cfg.Game_shopitem ) if v, err = this.GetConfigure(game_shopitem); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { table = v.(*cfg.Game_shopitem) @@ -99,7 +100,7 @@ func (this *configureComp) GetShopItemsConfigureByIds(keys ...int32) (result []* ok bool ) if v, err = this.GetConfigure(game_shopitem); err != nil { - log.Errorf("err:%v", err) + this.module.Errorf("err:%v", err) return } else { table = v.(*cfg.Game_shopitem) @@ -107,7 +108,7 @@ func (this *configureComp) GetShopItemsConfigureByIds(keys ...int32) (result []* if item, ok = table.GetDataMap()[v]; ok { result = append(result, item) } else { - log.Errorf("no found GetShopItemsConfigureByIds:%d", v) + this.module.Errorf("no found GetShopItemsConfigureByIds:%d", v) } } } diff --git a/modules/shop/model_shopitems.go b/modules/shop/model_shopitems.go index 363067ebb..7f8b106d0 100644 --- a/modules/shop/model_shopitems.go +++ b/modules/shop/model_shopitems.go @@ -2,7 +2,6 @@ package shop import ( "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -35,6 +34,7 @@ func (this *modelShopItemsComp) QueryUserShopData(uId string) (result map[int32] result = make(map[int32]*pb.DBShopItem) data := make([]*pb.DBShopItem, 0) if err = this.GetList(uId, &data); err != nil && err != mgo.MongodbNil { + err = nil return } err = nil @@ -52,7 +52,7 @@ func (this *modelShopItemsComp) QueryUserShopDataByGoodId(uId string, goodId int ) data = make([]*pb.DBShopItem, 0) if err = this.GetList(uId, &data); err != nil { - log.Errorf("err%v", err) + this.module.Errorf("err%v", err) return } for _, v := range data { diff --git a/modules/story/api_challenge.go b/modules/story/api_challenge.go index 18ba35b79..9af8faae7 100644 --- a/modules/story/api_challenge.go +++ b/modules/story/api_challenge.go @@ -5,6 +5,7 @@ import ( "go_dreamfactory/pb" "sort" + "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/protobuf/proto" ) @@ -39,20 +40,35 @@ func (this *apiComp) Challenge(session comm.IUserSession, req *pb.StoryChallenge if len(list) > 0 { curChapter = list[0] // 取第一条(第一条肯定是最新的) } - if curChapter == nil { - code = pb.ErrorCode_StoryNotFindChapter // 没有找到主线关卡信息 - return - } + // 先校验是不是分支 chaptConfig := this.module.configure.GetStoryChapter(int32(req.ChapterId)) // 根据配置文件找 if chaptConfig == nil { code = pb.ErrorCode_ConfigNoFound return } + if curChapter == nil { + if len(chaptConfig.Fubendata) <= 0 { + code = pb.ErrorCode_ConfigNoFound + return + } + if int32(req.ChapterId) != 1 { + code = pb.ErrorCode_ReqParameterError + return + } + _data := &pb.DBStory{} + _data.Id = primitive.NewObjectID().Hex() + _data.ChapterId = int32(req.ChapterId) + _mData := make(map[string]interface{}, 0) + _mData[_data.Id] = _data + this.module.modelStory.addNewChapter(session.GetUserId(), _mData) + curChapter = _data + //curChapter.StoryId = chaptConfig.Fubendata[0] // 第一次挑战 + } // 根据难度找对应的配置文件 - if chaptConfig.Intensity == "1" { // 这里安临时配置读取 后面会修改 + if chaptConfig.Intensity == "1" { // 这里按临时配置读取 后面会修改 con := this.module.configure.GetStoryEasyChapter(int32(req.StoryId)) // 根据配置文件找 - if con != nil { + if con == nil { code = pb.ErrorCode_ConfigNoFound return } @@ -66,13 +82,16 @@ func (this *apiComp) Challenge(session comm.IUserSession, req *pb.StoryChallenge } } // TODO 调用战斗逻辑 + // 挑战成功 + curChapter.StoryId += 1 // 临时数据 后面配置表完善查找 if bBranch { curChapter.BranchID = append(curChapter.BranchID, int32(req.ChapterId)) // 记录分支关卡 } if curChapter.ChapterId == int32(req.ChapterId) && curChapter.StoryId == int32(req.StoryId) { update := map[string]interface{}{ - "storyId": req.StoryId, - "branchID": curChapter.BranchID, + "storyId": req.StoryId, + "ChapterId": req.ChapterId, + "branchID": curChapter.BranchID, } err = this.module.modelStory.modifyStoryData(session.GetUserId(), curChapter.Id, update) } diff --git a/modules/story/model_story.go b/modules/story/model_story.go index 057297d7b..8a5132fe9 100644 --- a/modules/story/model_story.go +++ b/modules/story/model_story.go @@ -2,6 +2,7 @@ package story import ( "go_dreamfactory/lego/core" + "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" "go_dreamfactory/pb" ) @@ -33,3 +34,13 @@ func (this *ModelStory) getStoryList(uid string) (storys []*pb.DBStory, err erro func (this *ModelStory) modifyStoryData(uid string, objid string, data map[string]interface{}) error { return this.moduleStory.modelStory.ChangeList(uid, objid, data) } + +// 增加新的章节数据 +func (this *ModelStory) addNewChapter(uId string, data map[string]interface{}) (err error) { + + if err = this.AddLists(uId, data); err != nil { + log.Errorf("err:%v", err) + return + } + return nil +} diff --git a/modules/user/api_res.go b/modules/user/api_res.go index f11d64639..817abd5c8 100644 --- a/modules/user/api_res.go +++ b/modules/user/api_res.go @@ -9,7 +9,7 @@ import ( ) func (this *apiComp) AddResCheck(session comm.IUserSession, req *pb.UserAddResReq) (code pb.ErrorCode) { - if req.Res.A == "" || req.Res.T == "" || req.Res.N > 0 { + if req.Res.A == "" || req.Res.T == "" || req.Res.N <= 0 { code = pb.ErrorCode_ReqParameterError } return diff --git a/pb/items_msg.pb.go b/pb/items_msg.pb.go index 2ee494aef..82183d34f 100644 --- a/pb/items_msg.pb.go +++ b/pb/items_msg.pb.go @@ -122,7 +122,7 @@ type ItemsUseItemReq struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - GridId int32 `protobuf:"varint,1,opt,name=GridId,proto3" json:"GridId"` //格子Id + GridId string `protobuf:"bytes,1,opt,name=GridId,proto3" json:"GridId"` //格子Id ItemId int32 `protobuf:"varint,2,opt,name=ItemId,proto3" json:"ItemId"` //物品Id Amount uint32 `protobuf:"varint,3,opt,name=Amount,proto3" json:"Amount"` //使用数量 } @@ -159,11 +159,11 @@ func (*ItemsUseItemReq) Descriptor() ([]byte, []int) { return file_items_items_msg_proto_rawDescGZIP(), []int{2} } -func (x *ItemsUseItemReq) GetGridId() int32 { +func (x *ItemsUseItemReq) GetGridId() string { if x != nil { return x.GridId } - return 0 + return "" } func (x *ItemsUseItemReq) GetItemId() int32 { @@ -225,7 +225,7 @@ type ItemsSellItemReq struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - GridId int32 `protobuf:"varint,1,opt,name=GridId,proto3" json:"GridId"` //格子Id + GridId string `protobuf:"bytes,1,opt,name=GridId,proto3" json:"GridId"` //格子Id ItemId int32 `protobuf:"varint,2,opt,name=ItemId,proto3" json:"ItemId"` //物品Id Amount uint32 `protobuf:"varint,3,opt,name=Amount,proto3" json:"Amount"` //使用数量 } @@ -262,11 +262,11 @@ func (*ItemsSellItemReq) Descriptor() ([]byte, []int) { return file_items_items_msg_proto_rawDescGZIP(), []int{4} } -func (x *ItemsSellItemReq) GetGridId() int32 { +func (x *ItemsSellItemReq) GetGridId() string { if x != nil { return x.GridId } - return 0 + return "" } func (x *ItemsSellItemReq) GetItemId() int32 { @@ -336,14 +336,14 @@ var file_items_items_msg_proto_rawDesc = []byte{ 0x73, 0x65, 0x72, 0x49, 0x74, 0x65, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x47, 0x72, 0x69, 0x64, 0x73, 0x22, 0x59, 0x0a, 0x0f, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x55, 0x73, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x55, 0x73, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x22, 0x5a, 0x0a, 0x10, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x53, 0x65, 0x6c, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x47, 0x72, 0x69, 0x64, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x13, 0x0a, diff --git a/pb/notify_db.pb.go b/pb/notify_db.pb.go new file mode 100644 index 000000000..5c24edd17 --- /dev/null +++ b/pb/notify_db.pb.go @@ -0,0 +1,189 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.0 +// source: notify/notify_db.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +//系统公告数据结构 +type DBSystemNotify struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` //数据公告Id + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title"` //公告标题 + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content"` //公告内容 + Istop bool `protobuf:"varint,4,opt,name=istop,proto3" json:"istop"` //是否置顶 + Ctime int64 `protobuf:"varint,5,opt,name=ctime,proto3" json:"ctime"` //创建时间 + Rtime int64 `protobuf:"varint,6,opt,name=rtime,proto3" json:"rtime"` //发布时间 +} + +func (x *DBSystemNotify) Reset() { + *x = DBSystemNotify{} + if protoimpl.UnsafeEnabled { + mi := &file_notify_notify_db_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DBSystemNotify) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DBSystemNotify) ProtoMessage() {} + +func (x *DBSystemNotify) ProtoReflect() protoreflect.Message { + mi := &file_notify_notify_db_proto_msgTypes[0] + 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 DBSystemNotify.ProtoReflect.Descriptor instead. +func (*DBSystemNotify) Descriptor() ([]byte, []int) { + return file_notify_notify_db_proto_rawDescGZIP(), []int{0} +} + +func (x *DBSystemNotify) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *DBSystemNotify) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *DBSystemNotify) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *DBSystemNotify) GetIstop() bool { + if x != nil { + return x.Istop + } + return false +} + +func (x *DBSystemNotify) GetCtime() int64 { + if x != nil { + return x.Ctime + } + return 0 +} + +func (x *DBSystemNotify) GetRtime() int64 { + if x != nil { + return x.Rtime + } + return 0 +} + +var File_notify_notify_db_proto protoreflect.FileDescriptor + +var file_notify_notify_db_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, + 0x64, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x01, 0x0a, 0x0e, 0x44, 0x42, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x73, 0x74, 0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x74, 0x6f, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x06, 0x5a, + 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_notify_notify_db_proto_rawDescOnce sync.Once + file_notify_notify_db_proto_rawDescData = file_notify_notify_db_proto_rawDesc +) + +func file_notify_notify_db_proto_rawDescGZIP() []byte { + file_notify_notify_db_proto_rawDescOnce.Do(func() { + file_notify_notify_db_proto_rawDescData = protoimpl.X.CompressGZIP(file_notify_notify_db_proto_rawDescData) + }) + return file_notify_notify_db_proto_rawDescData +} + +var file_notify_notify_db_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_notify_notify_db_proto_goTypes = []interface{}{ + (*DBSystemNotify)(nil), // 0: DBSystemNotify +} +var file_notify_notify_db_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_notify_notify_db_proto_init() } +func file_notify_notify_db_proto_init() { + if File_notify_notify_db_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_notify_notify_db_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DBSystemNotify); 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{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_notify_notify_db_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_notify_notify_db_proto_goTypes, + DependencyIndexes: file_notify_notify_db_proto_depIdxs, + MessageInfos: file_notify_notify_db_proto_msgTypes, + }.Build() + File_notify_notify_db_proto = out.File + file_notify_notify_db_proto_rawDesc = nil + file_notify_notify_db_proto_goTypes = nil + file_notify_notify_db_proto_depIdxs = nil +} diff --git a/pb/notify_msg.pb.go b/pb/notify_msg.pb.go index 52fdaef1a..3faf8c211 100644 --- a/pb/notify_msg.pb.go +++ b/pb/notify_msg.pb.go @@ -30,7 +30,7 @@ type NotifyErrorNotifyPush struct { ReqSubType string `protobuf:"bytes,2,opt,name=ReqSubType,proto3" json:"ReqSubType"` // 请求协议函数 例如:login 对应项目中 user的模块中 api_login 的处理函数 Code ErrorCode `protobuf:"varint,3,opt,name=Code,proto3,enum=ErrorCode" json:"Code"` // 执行返回错误码 对应 errorcode.proto 枚举 Message string `protobuf:"bytes,4,opt,name=Message,proto3" json:"Message"` // 错误消息 - Data string `protobuf:"bytes,6,opt,name=Data,proto3" json:"Data"` // 错误数据 + Data string `protobuf:"bytes,5,opt,name=Data,proto3" json:"Data"` // 错误数据 } func (x *NotifyErrorNotifyPush) Reset() { @@ -100,24 +100,128 @@ func (x *NotifyErrorNotifyPush) GetData() string { return "" } +//获取系统公告 请求 +type NotifyGetListReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyGetListReq) Reset() { + *x = NotifyGetListReq{} + if protoimpl.UnsafeEnabled { + mi := &file_notify_notify_msg_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyGetListReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyGetListReq) ProtoMessage() {} + +func (x *NotifyGetListReq) ProtoReflect() protoreflect.Message { + mi := &file_notify_notify_msg_proto_msgTypes[1] + 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 NotifyGetListReq.ProtoReflect.Descriptor instead. +func (*NotifyGetListReq) Descriptor() ([]byte, []int) { + return file_notify_notify_msg_proto_rawDescGZIP(), []int{1} +} + +//获取系统公告 回应 +type NotifyGetListResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastReadTime int64 `protobuf:"varint,1,opt,name=LastReadTime,proto3" json:"LastReadTime"` //最后一次阅读时间 + SysNotify []*DBSystemNotify `protobuf:"bytes,2,rep,name=SysNotify,proto3" json:"SysNotify"` //公告列表 +} + +func (x *NotifyGetListResp) Reset() { + *x = NotifyGetListResp{} + if protoimpl.UnsafeEnabled { + mi := &file_notify_notify_msg_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyGetListResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyGetListResp) ProtoMessage() {} + +func (x *NotifyGetListResp) ProtoReflect() protoreflect.Message { + mi := &file_notify_notify_msg_proto_msgTypes[2] + 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 NotifyGetListResp.ProtoReflect.Descriptor instead. +func (*NotifyGetListResp) Descriptor() ([]byte, []int) { + return file_notify_notify_msg_proto_rawDescGZIP(), []int{2} +} + +func (x *NotifyGetListResp) GetLastReadTime() int64 { + if x != nil { + return x.LastReadTime + } + return 0 +} + +func (x *NotifyGetListResp) GetSysNotify() []*DBSystemNotify { + if x != nil { + return x.SysNotify + } + return nil +} + var File_notify_notify_msg_proto protoreflect.FileDescriptor var file_notify_notify_msg_proto_rawDesc = []byte{ 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x6d, 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa7, 0x01, 0x0a, 0x15, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x50, 0x75, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x4d, 0x61, 0x69, 0x6e, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x71, 0x4d, 0x61, - 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x71, 0x53, 0x75, 0x62, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x52, 0x65, 0x71, 0x53, - 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, - 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x44, 0x61, 0x74, 0x61, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x64, 0x62, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xa7, 0x01, 0x0a, 0x15, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x50, 0x75, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, + 0x52, 0x65, 0x71, 0x4d, 0x61, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x52, 0x65, 0x71, 0x4d, 0x61, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x52, 0x65, 0x71, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x52, 0x65, 0x71, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, + 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x12, 0x0a, 0x10, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x22, 0x66, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x61, + 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x4c, 0x61, 0x73, + 0x74, 0x52, 0x65, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x53, 0x79, 0x73, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x44, + 0x42, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x09, 0x53, + 0x79, 0x73, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -132,18 +236,22 @@ func file_notify_notify_msg_proto_rawDescGZIP() []byte { return file_notify_notify_msg_proto_rawDescData } -var file_notify_notify_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_notify_notify_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_notify_notify_msg_proto_goTypes = []interface{}{ (*NotifyErrorNotifyPush)(nil), // 0: NotifyErrorNotifyPush - (ErrorCode)(0), // 1: ErrorCode + (*NotifyGetListReq)(nil), // 1: NotifyGetListReq + (*NotifyGetListResp)(nil), // 2: NotifyGetListResp + (ErrorCode)(0), // 3: ErrorCode + (*DBSystemNotify)(nil), // 4: DBSystemNotify } var file_notify_notify_msg_proto_depIdxs = []int32{ - 1, // 0: NotifyErrorNotifyPush.Code:type_name -> ErrorCode - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 3, // 0: NotifyErrorNotifyPush.Code:type_name -> ErrorCode + 4, // 1: NotifyGetListResp.SysNotify:type_name -> DBSystemNotify + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_notify_notify_msg_proto_init() } @@ -152,6 +260,7 @@ func file_notify_notify_msg_proto_init() { return } file_errorcode_proto_init() + file_notify_notify_db_proto_init() if !protoimpl.UnsafeEnabled { file_notify_notify_msg_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyErrorNotifyPush); i { @@ -165,6 +274,30 @@ func file_notify_notify_msg_proto_init() { return nil } } + file_notify_notify_msg_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyGetListReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_notify_notify_msg_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyGetListResp); 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{ @@ -172,7 +305,7 @@ func file_notify_notify_msg_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_notify_notify_msg_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/pb/proto/items/items_msg.proto b/pb/proto/items/items_msg.proto index a6e480837..83f52391c 100644 --- a/pb/proto/items/items_msg.proto +++ b/pb/proto/items/items_msg.proto @@ -14,7 +14,7 @@ message ItemsGetlistResp { //使用物品请求 message ItemsUseItemReq { - int32 GridId = 1; //格子Id + string GridId = 1; //格子Id int32 ItemId = 2; //物品Id uint32 Amount = 3; //使用数量 } @@ -26,7 +26,7 @@ message ItemsUseItemResp { //出售道具请求sailitem message ItemsSellItemReq { - int32 GridId = 1; //格子Id + string GridId = 1; //格子Id int32 ItemId = 2; //物品Id uint32 Amount = 3; //使用数量 } diff --git a/pb/proto/notify/notify_db.proto b/pb/proto/notify/notify_db.proto new file mode 100644 index 000000000..bee9b6d51 --- /dev/null +++ b/pb/proto/notify/notify_db.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +option go_package = ".;pb"; + +//系统公告数据结构 +message DBSystemNotify { + string id = 1; //数据公告Id + string title = 2; //公告标题 + string content = 3; //公告内容 + bool istop = 4; //是否置顶 + int64 ctime = 5; //创建时间 + int64 rtime = 6; //发布时间 +} \ No newline at end of file diff --git a/pb/proto/notify/notify_msg.proto b/pb/proto/notify/notify_msg.proto index 839c3c924..1008862eb 100644 --- a/pb/proto/notify/notify_msg.proto +++ b/pb/proto/notify/notify_msg.proto @@ -1,6 +1,7 @@ syntax = "proto3"; option go_package = ".;pb"; import "errorcode.proto"; +import "notify/notify_db.proto"; //统一错误码推送 message NotifyErrorNotifyPush { @@ -8,5 +9,15 @@ message NotifyErrorNotifyPush { string ReqSubType = 2; // 请求协议函数 例如:login 对应项目中 user的模块中 api_login 的处理函数 ErrorCode Code = 3; // 执行返回错误码 对应 errorcode.proto 枚举 string Message = 4; // 错误消息 - string Data = 6; // 错误数据 + string Data = 5; // 错误数据 } + +//获取系统公告 请求 +message NotifyGetListReq { +} + +//获取系统公告 回应 +message NotifyGetListResp { + int64 LastReadTime = 1; //最后一次阅读时间 + repeated DBSystemNotify SysNotify = 2; //公告列表 +} \ No newline at end of file diff --git a/pb/proto/userexpand.proto b/pb/proto/userexpand.proto new file mode 100644 index 000000000..d39b2e64c --- /dev/null +++ b/pb/proto/userexpand.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +option go_package = ".;pb"; + + +//用户扩展数据 +message DBUserExpand { + string id = 1; //主键id + string uid = 2; //用户id + int64 lastreadnotiftime = 3; //最后阅读公告时间 +} \ No newline at end of file diff --git a/pb/userexpand.pb.go b/pb/userexpand.pb.go new file mode 100644 index 000000000..c84ca5f69 --- /dev/null +++ b/pb/userexpand.pb.go @@ -0,0 +1,162 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.0 +// source: userexpand.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +//用户扩展数据 +type DBUserExpand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` //主键id + Uid string `protobuf:"bytes,2,opt,name=uid,proto3" json:"uid"` //用户id + Lastreadnotiftime int64 `protobuf:"varint,3,opt,name=lastreadnotiftime,proto3" json:"lastreadnotiftime"` //最后阅读公告时间 +} + +func (x *DBUserExpand) Reset() { + *x = DBUserExpand{} + if protoimpl.UnsafeEnabled { + mi := &file_userexpand_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DBUserExpand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DBUserExpand) ProtoMessage() {} + +func (x *DBUserExpand) ProtoReflect() protoreflect.Message { + mi := &file_userexpand_proto_msgTypes[0] + 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 DBUserExpand.ProtoReflect.Descriptor instead. +func (*DBUserExpand) Descriptor() ([]byte, []int) { + return file_userexpand_proto_rawDescGZIP(), []int{0} +} + +func (x *DBUserExpand) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *DBUserExpand) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +func (x *DBUserExpand) GetLastreadnotiftime() int64 { + if x != nil { + return x.Lastreadnotiftime + } + return 0 +} + +var File_userexpand_proto protoreflect.FileDescriptor + +var file_userexpand_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x5e, 0x0a, 0x0c, 0x44, 0x42, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x70, 0x61, + 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x11, 0x6c, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x74, 0x69, + 0x6d, 0x65, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_userexpand_proto_rawDescOnce sync.Once + file_userexpand_proto_rawDescData = file_userexpand_proto_rawDesc +) + +func file_userexpand_proto_rawDescGZIP() []byte { + file_userexpand_proto_rawDescOnce.Do(func() { + file_userexpand_proto_rawDescData = protoimpl.X.CompressGZIP(file_userexpand_proto_rawDescData) + }) + return file_userexpand_proto_rawDescData +} + +var file_userexpand_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_userexpand_proto_goTypes = []interface{}{ + (*DBUserExpand)(nil), // 0: DBUserExpand +} +var file_userexpand_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_userexpand_proto_init() } +func file_userexpand_proto_init() { + if File_userexpand_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_userexpand_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DBUserExpand); 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{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_userexpand_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_userexpand_proto_goTypes, + DependencyIndexes: file_userexpand_proto_depIdxs, + MessageInfos: file_userexpand_proto_msgTypes, + }.Build() + File_userexpand_proto = out.File + file_userexpand_proto_rawDesc = nil + file_userexpand_proto_goTypes = nil + file_userexpand_proto_depIdxs = nil +} diff --git a/services/comp_gateroute.go b/services/comp_gateroute.go index 0529b7e9e..07c4df6f6 100644 --- a/services/comp_gateroute.go +++ b/services/comp_gateroute.go @@ -15,11 +15,31 @@ import ( "go_dreamfactory/lego/core/cbase" "go_dreamfactory/lego/sys/event" "go_dreamfactory/lego/sys/log" + "go_dreamfactory/lego/utils/mapstructure" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) +//用户协议处理函数注册的反射对象 +type msghandle struct { + rcvr reflect.Value + msgType reflect.Type //消息请求类型 + handle reflect.Method //处理函数 +} + +//组件参数 +type CompOptions struct { + Debug bool +} + +func (this *CompOptions) LoadConfig(settings map[string]interface{}) (err error) { + if settings != nil { + err = mapstructure.Decode(settings, this) + } + return +} + /* 服务网关组件 用于接收网关服务发送过来的消息 */ @@ -29,16 +49,10 @@ func NewGateRouteComp() comm.ISC_GateRouteComp { return comp } -//用户协议处理函数注册的反射对象 -type msghandle struct { - rcvr reflect.Value - msgType reflect.Type //消息请求类型 - handle reflect.Method //处理函数 -} - //服务网关组件 type SCompGateRoute struct { cbase.ServiceCompBase + options *CompOptions service base.IRPCXService //rpc服务对象 通过这个对象可以发布服务和调用其他服务的接口 mrlock sync.RWMutex //msghandles 对象的锁 msghandles map[string]*msghandle //处理函数的管理对象 @@ -50,9 +64,14 @@ func (this *SCompGateRoute) GetName() core.S_Comps { return comm.SC_ServiceGateRouteComp } +func (this *SCompGateRoute) NewOptions() (options core.ICompOptions) { + return new(CompOptions) +} + //组件初始化函数 func (this *SCompGateRoute) Init(service core.IService, comp core.IServiceComp, options core.ICompOptions) (err error) { err = this.ServiceCompBase.Init(service, comp, options) + this.options = options.(*CompOptions) this.service = service.(base.IRPCXService) this.msghandles = make(map[string]*msghandle) this.pools = sync.Pool{ @@ -74,7 +93,7 @@ func (this *SCompGateRoute) Start() (err error) { //业务模块注册用户消息处理路由 func (this *SCompGateRoute) RegisterRoute(methodName string, comp reflect.Value, msg reflect.Type, handele reflect.Method) { - log.Debugf("注册用户路由【%s】", methodName) + //log.Debugf("注册用户路由【%s】", methodName) this.mrlock.RLock() _, ok := this.msghandles[methodName] this.mrlock.RUnlock() @@ -95,11 +114,11 @@ func (this *SCompGateRoute) RegisterRoute(methodName string, comp reflect.Value, func (this *SCompGateRoute) ReceiveMsg(ctx context.Context, args *pb.AgentMessage, reply *pb.RPCMessageReply) (err error) { defer func() { //程序异常 收集异常信息传递给前端显示 if r := recover(); r != nil { - buf := make([]byte, 1024) + buf := make([]byte, 4096) l := runtime.Stack(buf, false) reply.Code = pb.ErrorCode_Exception reply.ErrorMessage = fmt.Sprintf("%v: %s", r, buf[:l]) - log.Errorf("HandleUserMsg:[%s-%s] err:%s", args.MainType, args.SubType, reply.ErrorMessage) + log.Errorf("[Handle Api]:[%s-%s] err:%s", args.MainType, args.SubType, reply.ErrorMessage) } }() method := fmt.Sprintf("%s.%s", args.MainType, args.SubType) @@ -126,11 +145,10 @@ func (this *SCompGateRoute) ReceiveMsg(ctx context.Context, args *pb.AgentMessag //执行处理流 stime := time.Now() handlereturn := msghandle.handle.Func.Call([]reflect.Value{msghandle.rcvr, reflect.ValueOf(session), reflect.ValueOf(msg)}) - log.Debugf("[Handle Api] consumetime:%v method:%s uid:%s msg:%v", time.Since(stime), method, args.UserId, msg) errcode := pb.ErrorCode(handlereturn[0].Int()) errdata := handlereturn[1].Interface() if errcode != pb.ErrorCode_Success { //处理返货错误码 返回用户错误信息 - log.Errorf("[Handle Api] method:%s uid:%s msg:%v code:%d", method, msg, errcode) + log.Errorf("[Handle Api] method:%s msg:%v code:%d", method, msg, errcode) reply.Code = errcode reply.ErrorMessage = pb.GetErrorCodeMsg(errcode) if errdata != nil { @@ -139,6 +157,9 @@ func (this *SCompGateRoute) ReceiveMsg(ctx context.Context, args *pb.AgentMessag } } else { reply.Reply = session.Polls() + if this.options.Debug { + log.Debugf("[Handle Api] consumetime:%v method:%s uid:%s msg:%v reply:%#v", time.Since(stime), method, args.UserId, msg, reply) + } } } else { //未找到消息处理函数 log.Errorf("[Handle Api] no found handle %s", method) diff --git a/services/dbservice/main.go b/services/mainte/main.go similarity index 80% rename from services/dbservice/main.go rename to services/mainte/main.go index 84e957a20..9a1d6db47 100644 --- a/services/dbservice/main.go +++ b/services/mainte/main.go @@ -3,7 +3,8 @@ package main import ( "flag" "fmt" - "go_dreamfactory/modules/dbservice" + "go_dreamfactory/modules/gm" + "go_dreamfactory/modules/mgolog" "go_dreamfactory/services" "go_dreamfactory/sys/cache" "go_dreamfactory/sys/db" @@ -15,11 +16,11 @@ import ( ) /* - 服务类型:dbservice - 服务描述:处理梦工厂的具体业务需求,包含 user,pack,mail,friend...功能业务模块 + 服务类型:mainte + 服务描述:数据库维护以及GM后台接口 服务 */ var ( - conf = flag.String("conf", "./conf/dbservice.yaml", "获取需要启动的服务配置文件") //启动服务的Id + conf = flag.String("conf", "./conf/mainte.yaml", "获取需要启动的服务配置文件") //启动服务的Id ) /*服务启动的入口函数*/ @@ -33,9 +34,9 @@ func main() { //services.NewGateRouteComp(), //此服务需要接受用户的消息 需要装备网关组件 ) lego.Run(s, //运行模块 - dbservice.NewModule(), + mgolog.NewModule(), + gm.NewModule(), ) - } func NewService(ops ...rpcx.Option) core.IService { diff --git a/services/web/main.go b/services/web/main.go deleted file mode 100644 index a609ec6e9..000000000 --- a/services/web/main.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "go_dreamfactory/modules/web" - "go_dreamfactory/services" - "go_dreamfactory/sys/cache" - "go_dreamfactory/sys/db" - - "go_dreamfactory/lego" - "go_dreamfactory/lego/base/rpcx" - "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/log" -) - -/* - 服务类型:web - 服务描述:提供一些http服务,方便后期维护和开发过程中的测试,只包含 web 业务模块 -*/ -var ( - conf = flag.String("conf", "./conf/web_1.yaml", "获取需要启动的服务配置文件") //启动服务的Id -) - -func main() { - flag.Parse() - s := NewService( - rpcx.SetConfPath(*conf), - rpcx.SetVersion("1.0.0.0"), - ) - s.OnInstallComp( //装备组件 - ) - lego.Run(s, //运行模块 - web.NewModule(), - ) - -} - -func NewService(ops ...rpcx.Option) core.IService { - s := new(Service) - s.Configure(ops...) - return s -} - -type Service struct { - services.ServiceBase -} - -func (this *Service) InitSys() { - this.ServiceBase.InitSys() - if err := cache.OnInit(this.GetSettings().Sys["cache"]); err != nil { - panic(fmt.Sprintf("init sys.cache err: %s", err.Error())) - } else { - log.Infof("init sys.cache success!") - } - if err := db.OnInit(this.GetSettings().Sys["db"]); err != nil { - panic(fmt.Sprintf("init sys.db err: %s", err.Error())) - } else { - log.Infof("init sys.db success!") - } -} diff --git a/services/worker/main.go b/services/worker/main.go index 0519b14c6..9e2e6c9d1 100644 --- a/services/worker/main.go +++ b/services/worker/main.go @@ -27,7 +27,7 @@ import ( 服务描述:处理梦工厂的具体业务需求,包含 user,pack,mail,friend...功能业务模块 */ var ( - conf = flag.String("conf", "./conf/worker.yaml", "获取需要启动的服务配置文件") //启动服务的Id + conf = flag.String("conf", "./conf/worker_1.yaml", "获取需要启动的服务配置文件") //启动服务的Id ) /*服务启动的入口函数*/ diff --git a/sys/db/benchmark/query_test.go b/sys/db/benchmark/query_test.go index 30904ced0..99bdeb5e3 100644 --- a/sys/db/benchmark/query_test.go +++ b/sys/db/benchmark/query_test.go @@ -49,6 +49,15 @@ func TestMain(m *testing.M) { defer os.Exit(m.Run()) } +func Test_GetList(t *testing.T) { + heroes := []*DBHero{} + GetList(&heroes) +} +func Test_GetList0(t *testing.T) { + // heroes := []*DBHero{} + // GetListO(&heroes) +} + func BenchmarkMarsh(b *testing.B) { var ( // ncpu = runtime.NumCPU() @@ -109,7 +118,7 @@ func GetList(data interface{}) (err error) { //query from mgo // if c, err = mdb.Mgo().Find(core.SqlTable("hero"), bson.M{}); err != nil { - if c, err = mgoDb.Collection("hreo").Find(context.Background(), bson.M{}); err != nil { + if c, err = mgoDb.Collection("hero").Find(context.Background(), bson.M{}); err != nil { return err } else { var temp map[string]interface{} = make(map[string]interface{})