From 89ee5478d283a341825eaa7ae1879c444ed87ec3 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 12 Jul 2022 17:13:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=BA=95=E5=B1=82=E5=8F=8D?= =?UTF-8?q?=E5=B0=84=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lego/sys/codec/codec.go | 2 +- lego/sys/codec/core.go | 11 ++- lego/sys/codec/factory/factory_optional.go | 9 ++ lego/sys/codec/sys_test.go | 7 +- lego/sys/redis/cluster/hash.go | 26 +++++ lego/sys/redis/core.go | 5 + lego/sys/redis/redis.go | 8 ++ lego/sys/redis/single/hash.go | 25 +++++ modules/comp_model.go | 109 ++++++++++++++++++++- modules/items/module_test.go | 2 +- 10 files changed, 198 insertions(+), 6 deletions(-) diff --git a/lego/sys/codec/codec.go b/lego/sys/codec/codec.go index 3fa30b128..6ac194841 100644 --- a/lego/sys/codec/codec.go +++ b/lego/sys/codec/codec.go @@ -100,7 +100,7 @@ func (this *Codec) DecoderOf(typ reflect2.Type) core.IDecoder { Encoders: map[reflect2.Type]core.IEncoder{}, } ptrType := typ.(*reflect2.UnsafePtrType) - decoder = factory.DecoderOfType(ctx, ptrType.Elem()) + decoder = factory.DecoderOfType(ctx, ptrType) this.addDecoderToCache(cacheKey, decoder) return decoder } diff --git a/lego/sys/codec/core.go b/lego/sys/codec/core.go index 69255ec36..b83970fa9 100644 --- a/lego/sys/codec/core.go +++ b/lego/sys/codec/core.go @@ -2,10 +2,14 @@ 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) @@ -26,7 +30,12 @@ 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...) } diff --git a/lego/sys/codec/factory/factory_optional.go b/lego/sys/codec/factory/factory_optional.go index f1d1f2f75..ff5af87e0 100644 --- a/lego/sys/codec/factory/factory_optional.go +++ b/lego/sys/codec/factory/factory_optional.go @@ -48,6 +48,15 @@ func (this *OptionalDecoder) Decode(ptr unsafe.Pointer, extra core.IExtractor) { } } +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 } diff --git a/lego/sys/codec/sys_test.go b/lego/sys/codec/sys_test.go index 9d74319bc..80e2235f2 100644 --- a/lego/sys/codec/sys_test.go +++ b/lego/sys/codec/sys_test.go @@ -57,7 +57,7 @@ func Test_sys_mapjson(t *testing.T) { } func Test_sys_reflect2(t *testing.T) { - data := []string{"123"} + data := []*Test1Data{} ptr := reflect2.TypeOf(&data) kind := ptr.Kind() switch kind { @@ -76,6 +76,11 @@ func Test_sys_reflect2(t *testing.T) { 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 diff --git a/lego/sys/redis/cluster/hash.go b/lego/sys/redis/cluster/hash.go index db0bdae6a..7c36be40c 100644 --- a/lego/sys/redis/cluster/hash.go +++ b/lego/sys/redis/cluster/hash.go @@ -46,6 +46,17 @@ 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 命令用于返回哈希表中指定字段的值 */ @@ -81,6 +92,21 @@ func (this *Redis) HGetAll(key string, v interface{}) (err error) { 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 +} + /* Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值。 增量也可以为负数,相当于对指定字段进行减法操作。 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/redis.go b/lego/sys/redis/redis.go index 30d4c87da..5ac350bbb 100644 --- a/lego/sys/redis/redis.go +++ b/lego/sys/redis/redis.go @@ -213,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) } @@ -231,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) } diff --git a/lego/sys/redis/single/hash.go b/lego/sys/redis/single/hash.go index bc418451c..863abf46e 100644 --- a/lego/sys/redis/single/hash.go +++ b/lego/sys/redis/single/hash.go @@ -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 命令用于返回哈希表中指定字段的值 @@ -76,6 +86,21 @@ func (this *Redis) HGetAll(key string, v interface{}) (err error) { 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 +} + /* Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值。 增量也可以为负数,相当于对指定字段进行减法操作。 diff --git a/modules/comp_model.go b/modules/comp_model.go index 06ae6eb63..d67a3b36c 100644 --- a/modules/comp_model.go +++ b/modules/comp_model.go @@ -6,6 +6,8 @@ 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" @@ -13,7 +15,9 @@ import ( "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" @@ -221,8 +225,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 +316,107 @@ 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 + } + 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 err = this.Redis.HMSetForMap(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...) diff --git a/modules/items/module_test.go b/modules/items/module_test.go index 3f7471f1c..0cd055dd4 100644 --- a/modules/items/module_test.go +++ b/modules/items/module_test.go @@ -84,7 +84,7 @@ func TestMain(m *testing.M) { func Test_Modules(t *testing.T) { data, _ := ptypes.MarshalAny(&pb.ItemsGetlistReq{}) - s_gateComp.ReceiveMsg(context.Background(), &pb.AgentMessage{UserId: "0_62c259916d8cf3e4e06311a8", MainType: "items", SubType: "getlist", Message: data}, &pb.RPCMessageReply{}) + s_gateComp.ReceiveMsg(context.Background(), &pb.AgentMessage{UserId: "0_62bd7bc609320345a244f372", MainType: "items", SubType: "getlist", Message: data}, &pb.RPCMessageReply{}) // items, err := module.db_comp.Pack_QueryUserPack("liwei1dao") log.Debugf("data:%v", data) }