From 81f0247969ca50e7d9f351850ccca10e1c1fc4b3 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 9 Aug 2022 18:39:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=95=B0=E6=8D=AE=E5=B1=82?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- comm/const.go | 42 ++ lego/sys/redis/cluster/list.go | 10 + lego/sys/redis/core.go | 10 +- lego/sys/redis/pipe/core.go | 78 ++++ lego/sys/redis/pipe/hash.go | 197 +++++++++ lego/sys/redis/pipe/key.go | 85 ++++ lego/sys/redis/pipe/list.go | 228 ++++++++++ lego/sys/redis/pipe/set.go | 159 +++++++ lego/sys/redis/pipe/string.go | 182 ++++++++ lego/sys/redis/pipe/zset.go | 185 ++++++++ lego/sys/redis/redis.go | 8 +- lego/sys/redis/single/list.go | 9 + modules/chat/api_send.go | 4 +- modules/chat/api_spansend.go | 2 +- modules/chat/modelChat.go | 51 +-- modules/comp_model.go | 628 ++-------------------------- modules/equipment/modelEquipment.go | 3 +- modules/forum/modelForum.go | 24 +- modules/friend/model_friend.go | 11 +- modules/hero/model_hero.go | 6 +- modules/hero/model_record.go | 3 +- modules/items/modelitems.go | 3 +- modules/mail/model_mail.go | 28 +- modules/mainline/model_story.go | 7 +- modules/mgolog/db_comp.go | 2 +- modules/notify/modelNotify.go | 3 +- modules/shop/model_shop.go | 3 +- modules/shop/model_shopitems.go | 4 +- modules/shop/module.go | 3 +- modules/task/model_active.go | 6 +- modules/task/model_task.go | 6 +- modules/user/api_login.go | 6 +- modules/user/model_expand.go | 3 +- modules/user/model_session.go | 3 +- modules/user/model_setting.go | 3 +- modules/user/model_user.go | 10 +- modules/user/module.go | 8 +- modules/web/modelMail.go | 2 +- modules/web/modelNotify.go | 2 +- modules/web/modelUser.go | 3 +- sys/db/db.go | 36 -- sys/db/dbconn.go | 545 ++++++++++++++++++++++++ sys/db/init_test.go | 2 + sys/db/options.go | 32 ++ sys/db/redislua.go | 241 +++++++++++ 45 files changed, 2137 insertions(+), 749 deletions(-) create mode 100644 lego/sys/redis/pipe/core.go create mode 100644 lego/sys/redis/pipe/hash.go create mode 100644 lego/sys/redis/pipe/key.go create mode 100644 lego/sys/redis/pipe/list.go create mode 100644 lego/sys/redis/pipe/set.go create mode 100644 lego/sys/redis/pipe/string.go create mode 100644 lego/sys/redis/pipe/zset.go create mode 100644 sys/db/dbconn.go create mode 100644 sys/db/redislua.go diff --git a/comm/const.go b/comm/const.go index d8e5b3dee..bbd9f9047 100644 --- a/comm/const.go +++ b/comm/const.go @@ -47,6 +47,48 @@ const ( ModuleGM core.M_Modules = "gm" //gm模块 ) +//数据表名定义处 +const ( + ///数据日志表 + TableModellog = "model_log" + ///用户会话数据表 + TableSession = "session" + ///用户扩展数据表 + TableUserExpand = "userexpand" + ///玩家设置数据表 + TableSetting = "setting" + ///用户表 + TableUser = "user" + ///任务活跃度表 + TableTaskActive = "taskactive" + ///每日任务表 + TableTask = "task" + ///商店数据表 + TableShop = "shop" + ///商店物品数据表 + TableShopitems = "shopitems" + ///公告信息表 + TableNotify = "notify" + ///主线数据表 + TableMainline = "mainline" + ///邮件表 + TableMail = "mail" + ///道具背包表 + TableItems = "items" + ///英雄数据表 + TableHero = "hero" + ///用户记录 + TableUserRecord = "userrecord" + ///好友数据表 + TableFriend = "friend" + //论坛数据表 + TableForum = "forum" + //装备数据表 + TableEquipment = "equipment" + ///聊天数据表 + TableChat = "chat" +) + //RPC服务接口定义处 const ( //Rpc //Gateway 网关消息 diff --git a/lego/sys/redis/cluster/list.go b/lego/sys/redis/cluster/list.go index e7871c8c8..a03685b5e 100644 --- a/lego/sys/redis/cluster/list.go +++ b/lego/sys/redis/cluster/list.go @@ -108,6 +108,16 @@ func (this *Redis) LRange(key string, start, end int, v interface{}) (err error) return } +/* +Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素, +以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *Redis) LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd { + cmd := redis.NewStringSliceCmd(this.client.Context(), "LRANGE", key, start, end) + this.client.Process(this.client.Context(), cmd) + return cmd +} + /* Redis Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。 COUNT 的值可以是以下几种: diff --git a/lego/sys/redis/core.go b/lego/sys/redis/core.go index e7c23a443..0b1c66e80 100644 --- a/lego/sys/redis/core.go +++ b/lego/sys/redis/core.go @@ -2,6 +2,7 @@ package redis import ( "context" + "go_dreamfactory/lego/sys/redis/pipe" "time" "github.com/go-redis/redis/v8" @@ -56,6 +57,7 @@ type ( LPush(key string, values ...interface{}) (err error) LPushX(key string, values ...interface{}) (err error) LRange(key string, start, end int, v interface{}) (err error) + LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd LRem(key string, count int, target interface{}) (err error) LSet(key string, index int, value interface{}) (err error) Ltrim(key string, start, stop int) (err error) @@ -127,6 +129,7 @@ type ( ISys interface { IRedis GetClient() IRedis + RedisPipe(ctx context.Context) *pipe.RedisPipe /*Lock*/ NewRedisMutex(key string, opt ...RMutexOption) (result *RedisMutex, err error) } @@ -156,7 +159,9 @@ func Close() (err error) { func GetClient() IRedis { return defsys.GetClient() } - +func RedisPipe(ctx context.Context) *pipe.RedisPipe { + return defsys.RedisPipe(ctx) +} func Context() context.Context { return defsys.Context() } @@ -296,6 +301,9 @@ func LPushX(key string, values ...interface{}) (err error) { func LRange(key string, start, end int, v interface{}) (err error) { return defsys.LRange(key, start, end, v) } +func LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd { + return defsys.LRangeToStringSlice(key, start, end) +} func LRem(key string, count int, target interface{}) (err error) { return defsys.LRem(key, count, target) } diff --git a/lego/sys/redis/pipe/core.go b/lego/sys/redis/pipe/core.go new file mode 100644 index 000000000..1db297106 --- /dev/null +++ b/lego/sys/redis/pipe/core.go @@ -0,0 +1,78 @@ +package pipe + +import ( + "context" + + "go_dreamfactory/lego/sys/redis/core" + + "github.com/go-redis/redis/v8" +) + +func NewPipe(ctx context.Context, pipe redis.Pipeliner, codec core.ICodec) *RedisPipe { + return &RedisPipe{ + ctx: ctx, + client: pipe, + codec: codec, + } +} + +type RedisPipe struct { + ctx context.Context + client redis.Pipeliner + codec core.ICodec +} + +func (this *RedisPipe) Exec() ([]redis.Cmder, error) { + return this.client.Exec(this.ctx) +} + +/// 命令接口 +func (this *RedisPipe) Do(args ...interface{}) *redis.Cmd { + return this.client.Do(this.ctx, args...) +} + +///批处理 +func (this *RedisPipe) Pipeline() redis.Pipeliner { + return this.client.Pipeline() +} + +///批处理 +func (this *RedisPipe) Pipelined(fn func(pipe redis.Pipeliner) error) (err error) { + _, err = this.client.Pipelined(this.ctx, fn) + return +} + +///事务 +func (this *RedisPipe) TxPipelined(fn func(pipe redis.Pipeliner) error) (err error) { + _, err = this.client.TxPipelined(this.ctx, fn) + return +} + +//锁 +func (this *RedisPipe) Lock(key string, outTime int) (result bool, err error) { + cmd := redis.NewBoolCmd(this.ctx, "set", key, 1, "ex", outTime, "nx") + this.client.Process(this.ctx, cmd) + result, err = cmd.Result() + return +} + +//锁 +func (this *RedisPipe) UnLock(key string) (err error) { + err = this.Delete(key) + return +} + +//lua Script +func (this *RedisPipe) NewScript(src string) *redis.StringCmd { + script := redis.NewScript(src) + return script.Load(this.ctx, this.client) +} +func (this *RedisPipe) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd { + return this.client.Eval(ctx, script, keys, args...) +} +func (this *RedisPipe) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd { + return this.client.EvalSha(ctx, sha1, keys, args...) +} +func (this *RedisPipe) ScriptExists(ctx context.Context, hashes ...string) *redis.BoolSliceCmd { + return this.client.ScriptExists(ctx, hashes...) +} diff --git a/lego/sys/redis/pipe/hash.go b/lego/sys/redis/pipe/hash.go new file mode 100644 index 000000000..9067171dc --- /dev/null +++ b/lego/sys/redis/pipe/hash.go @@ -0,0 +1,197 @@ +package pipe + +import ( + "go_dreamfactory/lego/sys/redis/core" + + "github.com/go-redis/redis/v8" +) + +/* +Redis Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略 +*/ +func (this *RedisPipe) HDel(key string, fields ...string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "HDEL") + agrs = append(agrs, key) + for _, v := range fields { + agrs = append(agrs, v) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Hexists 命令用于查看哈希表的指定字段是否存在 +*/ +func (this *RedisPipe) HExists(key string, field string) (result bool, err error) { + result, err = this.client.Do(this.ctx, "HEXISTS", key, field).Bool() + return +} + +/* +Redis Hmset 命令用于同时将多个 field-value (字段-值)对设置到哈希表中。 +此命令会覆盖哈希表中已存在的字段。 +如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作 +*/ +func (this *RedisPipe) HMSet(key string, v interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "HMSET") + agrs = append(agrs, key) + var data map[string]string + if data, err = this.codec.MarshalMap(v); err != nil { + return + } + for k, v := range data { + agrs = append(agrs, k, v) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +func (this *RedisPipe) 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.ctx, agrs...).Err() + return +} + +/* +Redis Hget 命令用于返回哈希表中指定字段的值 +*/ +func (this *RedisPipe) HGet(key string, field string, v interface{}) (err error) { + cmd := redis.NewStringCmd(this.ctx, "HGET", key, field) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + if len(_result) == 0 { + err = redis.Nil + return + } + err = this.codec.Unmarshal(_result, v) + } + return +} + +/* +Redis Hgetall 命令用于返回哈希表中,所有的字段和值。 +在返回值里,紧跟每个字段名(field name)之后是字段的值(value),所以返回值的长度是哈希表大小的两倍 +*/ +func (this *RedisPipe) HGetAll(key string, v interface{}) (err error) { + cmd := redis.NewStringStringMapCmd(this.ctx, "HGETALL", key) + this.client.Process(this.ctx, cmd) + var _result map[string]string + if _result, err = cmd.Result(); err == nil { + if len(_result) == 0 { + err = redis.Nil + return + } + err = this.codec.UnmarshalMap(_result, v) + } + return +} + +/* + 读取全部hash集合数据到map中 +*/ +func (this *RedisPipe) HGetAllToMapString(key string) (cmd *redis.StringStringMapCmd) { + return this.client.HGetAll(this.ctx, key) +} + +/* +Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值。 +增量也可以为负数,相当于对指定字段进行减法操作。 +如果哈希表的 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。 +如果指定的字段不存在,那么在执行命令前,字段的值被初始化为 0 。 +对一个储存字符串值的字段执行 HINCRBY 命令将造成一个错误。 +本操作的值被限制在 64 位(bit)有符号数字表示之内 +*/ +func (this *RedisPipe) HIncrBy(key string, field string, value int) (err error) { + err = this.client.Do(this.ctx, "HINCRBY", key, field, value).Err() + return +} + +/* +Redis Hincrbyfloat 命令用于为哈希表中的字段值加上指定浮点数增量值。 +如果指定的字段不存在,那么在执行命令前,字段的值被初始化为 0 +*/ +func (this *RedisPipe) HIncrByFloat(key string, field string, value float32) (err error) { + err = this.client.Do(this.ctx, "HINCRBYFLOAT", key, field, value).Err() + return +} + +/* +Redis Hkeys 命令用于获取哈希表中的所有域(field) +*/ +func (this *RedisPipe) Hkeys(key string) (result []string, err error) { + cmd := redis.NewStringSliceCmd(this.ctx, "HKEYS", key) + this.client.Process(this.ctx, cmd) + result, err = cmd.Result() + return +} + +/* +Redis Hlen 命令用于获取哈希表中字段的数量 +*/ +func (this *RedisPipe) Hlen(key string) (result int, err error) { + result, err = this.client.Do(this.ctx, "HLEN", key).Int() + return +} + +/* +Redis Hmget 命令用于返回哈希表中,一个或多个给定字段的值。 +如果指定的字段不存在于哈希表,那么返回一个 nil 值 +*/ +func (this *RedisPipe) HMGet(key string, v interface{}, fields ...string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "HMGET") + agrs = append(agrs, key) + for _, v := range fields { + agrs = append(agrs, v) + } + cmd := redis.NewStringStringMapCmd(this.ctx, agrs...) + this.client.Process(this.ctx, cmd) + var _result map[string]string + if _result, err = cmd.Result(); err == nil { + if len(_result) == 0 { + err = redis.Nil + return + } + err = this.codec.UnmarshalMap(_result, v) + } + return +} + +/* +Redis Hset 命令用于为哈希表中的字段赋值 +如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作 +如果字段已经存在于哈希表中,旧值将被覆盖 +*/ +func (this *RedisPipe) HSet(key string, field string, value interface{}) (err error) { + var resultvalue []byte + if !core.IsBaseType(value) { + if resultvalue, err = this.codec.Marshal(value); err == nil { + err = this.client.Do(this.ctx, "HSET", key, field, resultvalue).Err() + } + } else { + err = this.client.Do(this.ctx, "HSET", key, field, value).Err() + } + return +} + +/* +Redis Hsetnx 命令用于为哈希表中不存在的的字段赋值 +如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作 +如果字段已经存在于哈希表中,操作无效 +如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令 +*/ +func (this *RedisPipe) HSetNX(key string, field string, value interface{}) (err error) { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(value); err == nil { + err = this.client.Do(this.ctx, "HSETNX", key, field, resultvalue).Err() + } + return +} diff --git a/lego/sys/redis/pipe/key.go b/lego/sys/redis/pipe/key.go new file mode 100644 index 000000000..9e8684856 --- /dev/null +++ b/lego/sys/redis/pipe/key.go @@ -0,0 +1,85 @@ +package pipe + +import ( + "time" +) + +/* Key *******************************************************************************/ + +///删除redis key +func (this *RedisPipe) Delete(key string) (err error) { + err = this.client.Do(this.ctx, "DEL", key).Err() + return +} + +///判断是否存在key +func (this *RedisPipe) ExistsKey(key string) (iskeep bool, err error) { + iskeep, err = this.client.Do(this.ctx, "EXISTS", key).Bool() + return +} + +///设置key的过期时间 单位以秒级 +func (this *RedisPipe) Expire(key string, expiration time.Duration) (err error) { + this.client.Expire(this.ctx, key, expiration) + return +} + +///设置key的过期时间戳 秒级时间戳 +func (this *RedisPipe) ExpireAt(key string, tm time.Time) (err error) { + err = this.client.ExpireAt(this.ctx, key, tm).Err() + return +} + +///设置key的过期时间 单位以毫秒级 +func (this *RedisPipe) PExpire(key string, expiration time.Duration) (err error) { + err = this.client.PExpire(this.ctx, key, expiration).Err() + return +} + +///设置key的过期时间戳 单位以豪秒级 +func (this *RedisPipe) PExpireAt(key string, tm time.Time) (err error) { + err = this.client.PExpireAt(this.ctx, key, tm).Err() + return +} + +///移除Key的过期时间 +func (this *RedisPipe) Persist(key string) (err error) { + err = this.client.Persist(this.ctx, key).Err() + return +} + +///获取key剩余过期时间 单位毫秒 +func (this *RedisPipe) PTTL(key string) (leftexpire time.Duration, err error) { + leftexpire, err = this.client.PTTL(this.ctx, key).Result() + return +} + +///获取key剩余过期时间 单位秒 +func (this *RedisPipe) TTL(key string) (leftexpire time.Duration, err error) { + leftexpire, err = this.client.TTL(this.ctx, key).Result() + return +} + +///重命名Key +func (this *RedisPipe) Rename(oldkey string, newkey string) (err error) { + err = this.client.Rename(this.ctx, oldkey, newkey).Err() + return +} + +///重命名key 在新的 key 不存在时修改 key 的名称 +func (this *RedisPipe) RenameNX(oldkey string, newkey string) (err error) { + err = this.client.RenameNX(this.ctx, oldkey, newkey).Err() + return +} + +///判断是否存在key pattern:key* +func (this *RedisPipe) Keys(pattern string) (keys []string, err error) { + keys, err = this.client.Keys(this.ctx, pattern).Result() + return +} + +///获取键类型 +func (this *RedisPipe) Type(key string) (ty string, err error) { + ty, err = this.client.Type(this.ctx, key).Result() + return +} diff --git a/lego/sys/redis/pipe/list.go b/lego/sys/redis/pipe/list.go new file mode 100644 index 000000000..f9d238675 --- /dev/null +++ b/lego/sys/redis/pipe/list.go @@ -0,0 +1,228 @@ +package pipe + +import ( + "github.com/go-redis/redis/v8" +) + +/* +Redis Lindex 命令用于通过索引获取列表中的元素。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *RedisPipe) Lindex(key string, v interface{}) (err error) { + cmd := redis.NewStringCmd(this.ctx, "LINDEX", key) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + if len(_result) == 0 { + err = redis.Nil + return + } + err = this.codec.Unmarshal(_result, v) + } + return +} + +/* +Redis Linsert 命令用于在列表的元素前或者后插入元素。当指定元素不存在于列表中时,不执行任何操作。 +当列表不存在时,被视为空列表,不执行任何操作。 +如果 key 不是列表类型,返回一个错误 +*/ +func (this *RedisPipe) Linsert(key string, isbefore bool, tager interface{}, value interface{}) (err error) { + var ( + tagervalue []byte + resultvalue []byte + ) + if tagervalue, err = this.codec.Marshal(tager); err != nil { + return + } + if resultvalue, err = this.codec.Marshal(value); err != nil { + return + } + if isbefore { + err = this.client.Do(this.ctx, "LINSERT", key, "BEFORE", tagervalue, resultvalue).Err() + } else { + err = this.client.Do(this.ctx, "LINSERT", key, "AFTER", tagervalue, resultvalue).Err() + } + return +} + +/* +Redis Llen 命令用于返回列表的长度。 如果列表 key 不存在,则 key 被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误 +*/ +func (this *RedisPipe) Llen(key string) *redis.IntCmd { + return this.client.LLen(this.ctx, key) +} + +/* +Redis Lpop 命令用于移除并返回列表的第一个元素 +*/ +func (this *RedisPipe) LPop(key string, v interface{}) (err error) { + cmd := redis.NewStringCmd(this.ctx, "LPOP", key) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) + } + return +} + +/* +Redis Lpush 命令将一个或多个值插入到列表头部。 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 当 key 存在但不是列表类型时,返回一个错误 +*/ +func (this *RedisPipe) LPush(key string, values ...interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "LPUSH") + for _, v := range values { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Lpushx 将一个值插入到已存在的列表头部,列表不存在时操作无效 +*/ +func (this *RedisPipe) LPushX(key string, values ...interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "LPUSHX") + for _, v := range values { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素, +以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *RedisPipe) LRange(key string, start, end int, v interface{}) (err error) { + var _result []string + cmd := redis.NewStringSliceCmd(this.ctx, "LRANGE", key, start, end) + this.client.Process(this.ctx, cmd) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素, +以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *RedisPipe) LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd { + cmd := redis.NewStringSliceCmd(this.ctx, "LRANGE", key, start, end) + this.client.Process(this.ctx, cmd) + return cmd +} + +/* +Redis Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。 +COUNT 的值可以是以下几种: +count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。 +count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。 +count = 0 : 移除表中所有与 VALUE 相等的值 +*/ +func (this *RedisPipe) LRem(key string, count int, target interface{}) (err error) { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(target); err != nil { + return + } + err = this.client.Do(this.ctx, "LREM", key, count, resultvalue).Err() + return +} + +/* +Redis Lset 通过索引来设置元素的值。 +当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误 +*/ +func (this *RedisPipe) LSet(key string, index int, value interface{}) (err error) { + var resultvalue []byte + if resultvalue, err = this.codec.Marshal(value); err == nil { + return + } + err = this.client.Do(this.ctx, "LSET", key, index, resultvalue).Err() + return +} + +/* +Redis Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 +下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标, +以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *RedisPipe) Ltrim(key string, start, stop int) (err error) { + err = this.client.Do(this.ctx, "LTRIM", key, start, stop).Err() + return +} + +/* +Redis Rpop 命令用于移除列表的最后一个元素,返回值为移除的元素 +*/ +func (this *RedisPipe) Rpop(key string, v interface{}) (err error) { + cmd := redis.NewStringCmd(this.ctx, "RPOP", key) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) + } + return +} + +/* +Redis Rpoplpush 命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回 +*/ +func (this *RedisPipe) RPopLPush(oldkey string, newkey string, v interface{}) (err error) { + cmd := redis.NewStringCmd(this.ctx, "RPOPLPUSH", oldkey, newkey) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, v) + } + return +} + +/* +Redis Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)。 +如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 当列表存在但不是列表类型时,返回一个错误。 +注意:在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值 +*/ +func (this *RedisPipe) RPush(key string, values ...interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "RPUSH") + for _, v := range values { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)。 +如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 当列表存在但不是列表类型时,返回一个错误。 +注意:在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值 +*/ +func (this *RedisPipe) RPushForStringSlice(key string, values ...string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "RPUSH") + for _, v := range values { + agrs = append(agrs, v) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Rpushx 命令用于将一个值插入到已存在的列表尾部(最右边)。如果列表不存在,操作无效 +*/ +func (this *RedisPipe) RPushX(key string, values ...interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "RPUSHX") + for _, v := range values { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} diff --git a/lego/sys/redis/pipe/set.go b/lego/sys/redis/pipe/set.go new file mode 100644 index 000000000..0c2a9c082 --- /dev/null +++ b/lego/sys/redis/pipe/set.go @@ -0,0 +1,159 @@ +package pipe + +/* +Redis Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。 +假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。 +当集合 key 不是集合类型时,返回一个错误。 +*/ +func (this *RedisPipe) SAdd(key string, values ...interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "SADD") + agrs = append(agrs, key) + for _, v := range values { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Scard 命令返回集合中元素的数量 +*/ +func (this *RedisPipe) SCard(key string) (result int64, err error) { + result, err = this.client.SCard(this.ctx, key).Result() + return +} + +/* +Redis Sdiff 命令返回第一个集合与其他集合之间的差异,也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。 +差集的结果来自前面的 FIRST_KEY ,而不是后面的 OTHER_KEY1,也不是整个 FIRST_KEY OTHER_KEY1..OTHER_KEYN 的差集。 +实例: +*/ +func (this *RedisPipe) SDiff(v interface{}, keys ...string) (err error) { + var _result []string + cmd := this.client.SDiff(this.ctx, keys...) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis Sdiffstore 命令将给定集合之间的差集合存储在指定的集合中。 +*/ +func (this *RedisPipe) SDiffStore(destination string, keys ...string) (result int64, err error) { + result, err = this.client.SDiffStore(this.ctx, destination, keys...).Result() + return +} + +/* +Redis Sismember 命令返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 +*/ +func (this *RedisPipe) SInter(v interface{}, keys ...string) (err error) { + var _result []string + cmd := this.client.SInter(this.ctx, keys...) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis Sinterstore 决定将给定集合之间的交集在指定的集合中。如果指定的集合已经存在,则将其覆盖 +*/ +func (this *RedisPipe) SInterStore(destination string, keys ...string) (result int64, err error) { + result, err = this.client.SInterStore(this.ctx, destination, keys...).Result() + return +} + +/* +Redis Sismember 命令判断成员元素是否是集合的成员 +*/ +func (this *RedisPipe) Sismember(key string, value interface{}) (iskeep bool, err error) { + iskeep, err = this.client.SIsMember(this.ctx, key, value).Result() + return +} + +/* +Redis Smembers 号召返回集合中的所有成员。 +*/ +func (this *RedisPipe) SMembers(v interface{}, key string) (err error) { + var _result []string + cmd := this.client.SMembers(this.ctx, key) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis Smove 命令将指定成员 member 元素从 source 集合移动到 destination 集合。 +SMOVE 是原子性操作。 +如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。 +当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。 +当 source 或 destination 不是集合类型时,返回一个错误。 +*/ +func (this *RedisPipe) SMove(source string, destination string, member interface{}) (result bool, err error) { + result, err = this.client.SMove(this.ctx, source, destination, member).Result() + return +} + +/* +Redis Spop命令用于移除集合中的指定键的一个或多个随机元素,移除后会返回移除的元素。 +该命令类似于Srandmember命令,但SPOP将随机元素从集合中移除并返回,而Srandmember则返回元素,而不是对集合进行任何改动。 +*/ +func (this *RedisPipe) Spop(key string) (result string, err error) { + result, err = this.client.SPop(this.ctx, key).Result() + return +} + +/* +Redis Srandmember 命令用于返回集合中的一个随机元素。 +从 Redis 2.6 版本开始, Srandmember 命令接受可选的 count 参数: +如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。 +如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。 +该操作和 SPOP 相似,但 SPOP 将随机元素从集合中移除并返回,而 Srandmember 则仅仅返回随机元素,而不对集合进行任何改动。 +*/ +func (this *RedisPipe) Srandmember(key string) (result string, err error) { + result, err = this.client.SRandMember(this.ctx, key).Result() + return +} + +/* +Redis Srem 呼吁用于移除集合中的一个或多个元素元素,不存在的元素元素会被忽略。 +当键不是集合类型,返回一个错误。 +在 Redis 2.4 版本以前,SREM 只接受个别成员值。 +*/ +func (this *RedisPipe) SRem(key string, members ...interface{}) (result int64, err error) { + result, err = this.client.SRem(this.ctx, key, members...).Result() + return +} + +/* +Redis Sunion 命令返回给定集合的并集。 +*/ +func (this *RedisPipe) SUnion(v interface{}, keys ...string) (err error) { + var _result []string + cmd := this.client.SUnion(this.ctx, keys...) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis Sunionstore 命令将给定集合的并集存储在指定的集合 destination 中。如果 destination 已经存在,则将其覆盖。 +*/ +func (this *RedisPipe) Sunionstore(destination string, keys ...string) (result int64, err error) { + result, err = this.client.SUnionStore(this.ctx, destination, keys...).Result() + return +} + +/* +Redis Sscan 用于继承集合中键的元素,Sscan 继承自Scan。 +*/ +func (this *RedisPipe) Sscan(key string, _cursor uint64, match string, count int64) (keys []string, cursor uint64, err error) { + keys, cursor, err = this.client.SScan(this.ctx, key, _cursor, match, count).Result() + return +} diff --git a/lego/sys/redis/pipe/string.go b/lego/sys/redis/pipe/string.go new file mode 100644 index 000000000..b784b5a76 --- /dev/null +++ b/lego/sys/redis/pipe/string.go @@ -0,0 +1,182 @@ +package pipe + +import ( + "time" + + "github.com/go-redis/redis/v8" +) + +/* String *******************************************************************************/ +/* +命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。 +*/ +func (this *RedisPipe) Set(key string, value interface{}, expiration time.Duration) (err error) { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { + return + } + err = this.client.Set(this.ctx, key, result, expiration).Err() + return +} + +/* +指定的 key 不存在时,为 key 设置指定的值 +*/ +func (this *RedisPipe) SetNX(key string, value interface{}) (result int64, err error) { + cmd := redis.NewIntCmd(this.ctx, "SETNX", key, value) + this.client.Process(this.ctx, cmd) + result, err = cmd.Result() + // } + return +} + +/* +同时设置一个或多个 key-value 对 +*/ +func (this *RedisPipe) MSet(v map[string]interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "MSET") + for k, v := range v { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, k, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +命令用于所有给定 key 都不存在时,同时设置一个或多个 key-value 对 +*/ +func (this *RedisPipe) MSetNX(v map[string]interface{}) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "MSETNX") + for k, v := range v { + result, _ := this.codec.Marshal(v) + agrs = append(agrs, k, result) + } + err = this.client.Do(this.ctx, agrs...).Err() + return +} + +/* +Redis Incr 命令将 key 中储存的数字值增一。 +如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。 +如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 +本操作的值限制在 64 位(bit)有符号数字表示之内。 +*/ +func (this *RedisPipe) Incr(key string) (err error) { + err = this.client.Do(this.ctx, "INCR", key).Err() + return +} + +/* +Redis Incrby 命令将 key 中储存的数字加上指定的增量值。 +如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。 +如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 +本操作的值限制在 64 位(bit)有符号数字表示之内 +*/ +func (this *RedisPipe) IncrBY(key string, value int) (err error) { + err = this.client.Do(this.ctx, "INCRBY", key, value).Err() + return +} + +/* +Redis Incrbyfloat 命令为 key 中所储存的值加上指定的浮点数增量值。 +如果 key 不存在,那么 INCRBYFLOAT 会先将 key 的值设为 0 ,再执行加法操作 +*/ +func (this *RedisPipe) Incrbyfloat(key string, value float32) (err error) { + err = this.client.Do(this.ctx, "INCRBYFLOAT", key, value).Err() + return +} + +/* +Redis Decr 命令将 key 中储存的数字值减一。 +如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。 +如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 +本操作的值限制在 64 位(bit)有符号数字表示之内 +*/ +func (this *RedisPipe) Decr(key string, value int) (err error) { + err = this.client.Do(this.ctx, "DECR", key, value).Err() + return +} + +/* +Redis Decrby 命令将 key 所储存的值减去指定的减量值。 +如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。 +如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 +本操作的值限制在 64 位(bit)有符号数字表示之内 +*/ +func (this *RedisPipe) DecrBy(key string, value int) (err error) { + err = this.client.Do(this.ctx, "DECRBY", key, value).Err() + return +} + +/* +Redis Append 命令用于为指定的 key 追加值。 +如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 +如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。 +*/ +func (this *RedisPipe) Append(key string, value interface{}) (err error) { + var result []byte + if result, err = this.codec.Marshal(value); err != nil { + return + } + err = this.client.Do(this.ctx, "APPEND", key, result).Err() + return +} + +/* +命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型 +*/ +func (this *RedisPipe) Get(key string, value interface{}) (err error) { + var result []byte + if result, err = this.client.Get(this.ctx, key).Bytes(); err == nil { + err = this.codec.Unmarshal(result, value) + } + return +} + +/* +设置指定 key 的值,并返回 key 的旧值 +*/ +func (this *RedisPipe) GetSet(key string, value interface{}, result interface{}) (err error) { + var ( + _value []byte + ) + if _value, err = this.codec.Marshal(value); err == nil { + cmd := redis.NewStringCmd(this.ctx, "GETSET", key, _value) + this.client.Process(this.ctx, cmd) + var _result []byte + if _result, err = cmd.Bytes(); err == nil { + err = this.codec.Unmarshal(_result, result) + } + } + return +} + +/* +返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil +*/ +func (this *RedisPipe) MGet(v interface{}, keys ...string) (err error) { + agrs := make([]interface{}, 0) + agrs = append(agrs, "MGET") + for _, v := range keys { + agrs = append(agrs, v) + } + cmd := redis.NewStringSliceCmd(this.ctx, agrs...) + this.client.Process(this.ctx, cmd) + var result []string + if result, err = cmd.Result(); err != nil { + return + } + err = this.codec.UnmarshalSlice(result, v) + return +} + +///判断是否存在key pattern:key* +func (this *RedisPipe) INCRBY(key string, amount int64) (result int64, err error) { + cmd := redis.NewIntCmd(this.ctx, "INCRBY", key, amount) + this.client.Process(this.ctx, cmd) + result, err = cmd.Result() + return +} diff --git a/lego/sys/redis/pipe/zset.go b/lego/sys/redis/pipe/zset.go new file mode 100644 index 000000000..8910c6d90 --- /dev/null +++ b/lego/sys/redis/pipe/zset.go @@ -0,0 +1,185 @@ +package pipe + +import ( + "github.com/go-redis/redis/v8" +) + +/* +Redis ZAdd 向有序集合添加一个或多个成员,或者更新已存在成员的分数 +*/ +func (this *RedisPipe) ZAdd(key string, members ...*redis.Z) (err error) { + this.client.ZAdd(this.ctx, key, members...) + return +} + +/* +Redis Zcard 用于计算集合中元素的数量。 +*/ +func (this *RedisPipe) ZCard(key string) (result int64, err error) { + result, err = this.client.ZCard(this.ctx, key).Result() + return +} + +/* +Redis ZCount 用于计算集合中指定的范围内的数量 +*/ +func (this *RedisPipe) ZCount(key string, min string, max string) (result int64, err error) { + result, err = this.client.ZCount(this.ctx, key, min, max).Result() + return +} + +/* +Redis ZIncrBy 有序集合中对指定成员的分数加上增量 increment +*/ +func (this *RedisPipe) ZIncrBy(key string, increment float64, member string) (result float64, err error) { + result, err = this.client.ZIncrBy(this.ctx, key, increment, member).Result() + return +} + +/* +Redis ZInterStore 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中 +*/ +func (this *RedisPipe) ZInterStore(destination string, store *redis.ZStore) (result int64, err error) { + result, err = this.client.ZInterStore(this.ctx, destination, store).Result() + return +} + +/* +Redis ZLexCount 在有序集合中计算指定字典区间内成员数量 +*/ +func (this *RedisPipe) ZLexCount(key string, min string, max string) (result int64, err error) { + result, err = this.client.ZLexCount(this.ctx, key, min, max).Result() + return +} + +/* +Redis ZRange 通过索引区间返回有序集合指定区间内的成员 +*/ +func (this *RedisPipe) ZRange(key string, start int64, stop int64, v interface{}) (err error) { + var _result []string + cmd := this.client.ZRange(this.ctx, key, start, stop) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis ZRangeByLex 通过字典区间返回有序集合的成员 +*/ +func (this *RedisPipe) ZRangeByLex(key string, opt *redis.ZRangeBy, v interface{}) (err error) { + var _result []string + cmd := this.client.ZRangeByLex(this.ctx, key, opt) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis ZRangeByScore 通过分数返回有序集合指定区间内的成员 +*/ +func (this *RedisPipe) ZRangeByScore(key string, opt *redis.ZRangeBy, v interface{}) (err error) { + var _result []string + cmd := this.client.ZRangeByScore(this.ctx, key, opt) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis ZRank 返回有序集合中指定成员的索引 +*/ +func (this *RedisPipe) ZRank(key string, member string) (result int64, err error) { + result, err = this.client.ZRank(this.ctx, key, member).Result() + return +} + +/* +Redis ZRem 移除有序集合中的一个或多个成员 +*/ +func (this *RedisPipe) ZRem(key string, members ...interface{}) (result int64, err error) { + result, err = this.client.ZRem(this.ctx, key, members...).Result() + return +} + +/* +Redis ZRemRangeByLex 移除有序集合中给定的字典区间的所有成员 +*/ +func (this *RedisPipe) ZRemRangeByLex(key string, min string, max string) (result int64, err error) { + result, err = this.client.ZRemRangeByLex(this.ctx, key, min, max).Result() + return +} + +/* +Redis ZRemRangeByRank 移除有序集合中给定的排名区间的所有成员 +*/ +func (this *RedisPipe) ZRemRangeByRank(key string, start int64, stop int64) (result int64, err error) { + result, err = this.client.ZRemRangeByRank(this.ctx, key, start, stop).Result() + return +} + +/* +Redis ZRemRangeByScore 移除有序集合中给定的分数区间的所有成员 +*/ +func (this *RedisPipe) ZRemRangeByScore(key string, min string, max string) (result int64, err error) { + result, err = this.client.ZRemRangeByScore(this.ctx, key, min, max).Result() + return +} + +/* +Redis ZRevRange 返回有序集中指定区间内的成员,通过索引,分数从高到低 ZREVRANGE +*/ +func (this *RedisPipe) ZRevRange(key string, start int64, stop int64, v interface{}) (err error) { + var _result []string + cmd := this.client.ZRevRange(this.ctx, key, start, stop) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis ZRevRangeByScore 返回有序集中指定分数区间内的成员,分数从高到低排序 +*/ +func (this *RedisPipe) ZRevRangeByScore(key string, opt *redis.ZRangeBy, v interface{}) (err error) { + var _result []string + cmd := this.client.ZRevRangeByScore(this.ctx, key, opt) + if _result, err = cmd.Result(); err == nil { + err = this.codec.UnmarshalSlice(_result, v) + } + return +} + +/* +Redis ZRevRank 返回有序集中指定分数区间内的成员,分数从高到低排序 +*/ +func (this *RedisPipe) ZRevRank(key string, member string) (result int64, err error) { + result, err = this.client.ZRevRank(this.ctx, key, member).Result() + return +} + +/* +Redis ZScore 返回有序集中指定分数区间内的成员,分数从高到低排序 +*/ +func (this *RedisPipe) ZScore(key string, member string) (result float64, err error) { + result, err = this.client.ZScore(this.ctx, key, member).Result() + return +} + +/* +Redis ZScore 返回有序集中指定分数区间内的成员,分数从高到低排序 ZUNIONSTORE +*/ +func (this *RedisPipe) ZUnionStore(dest string, store *redis.ZStore) (result int64, err error) { + result, err = this.client.ZUnionStore(this.ctx, dest, store).Result() + return +} + +/* +Redis ZScan 迭代有序集合中的元素(包括元素成员和元素分值) +*/ +func (this *RedisPipe) ZScan(key string, _cursor uint64, match string, count int64) (keys []string, cursor uint64, err error) { + keys, cursor, err = this.client.ZScan(this.ctx, key, _cursor, match, count).Result() + return +} diff --git a/lego/sys/redis/redis.go b/lego/sys/redis/redis.go index 261b66321..a674a83da 100644 --- a/lego/sys/redis/redis.go +++ b/lego/sys/redis/redis.go @@ -6,6 +6,7 @@ import ( "time" "go_dreamfactory/lego/sys/redis/cluster" + "go_dreamfactory/lego/sys/redis/pipe" "go_dreamfactory/lego/sys/redis/single" "go_dreamfactory/lego/utils/codec/json" @@ -54,10 +55,12 @@ func (this *Redis) GetClient() IRedis { func (this *Redis) Context() context.Context { return this.client.Context() } - func (this *Redis) Do(ctx context.Context, args ...interface{}) *redis.Cmd { return this.client.Do(ctx, args...) } +func (this *Redis) RedisPipe(ctx context.Context) *pipe.RedisPipe { + return pipe.NewPipe(ctx, this.client.Pipeline(), this) +} func (this *Redis) Pipeline() redis.Pipeliner { return this.client.Pipeline() } @@ -182,6 +185,9 @@ func (this *Redis) LPushX(key string, values ...interface{}) (err error) { func (this *Redis) LRange(key string, start, end int, v interface{}) (err error) { return this.client.LRange(key, start, end, v) } +func (this *Redis) LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd { + return this.client.LRangeToStringSlice(key, start, end) +} func (this *Redis) LRem(key string, count int, target interface{}) (err error) { return this.client.LRem(key, count, target) } diff --git a/lego/sys/redis/single/list.go b/lego/sys/redis/single/list.go index 2a9f708a0..141274734 100644 --- a/lego/sys/redis/single/list.go +++ b/lego/sys/redis/single/list.go @@ -103,6 +103,15 @@ func (this *Redis) LRange(key string, start, end int, v interface{}) (err error) } return } +/* +Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素, +以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推 +*/ +func (this *Redis) LRangeToStringSlice(key string, start, end int) *redis.StringSliceCmd { + cmd := redis.NewStringSliceCmd(this.client.Context(), "LRANGE", key, start, end) + this.client.Process(this.client.Context(), cmd) + return cmd +} /* Redis Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。 diff --git a/modules/chat/api_send.go b/modules/chat/api_send.go index 193f2a539..5501ba104 100644 --- a/modules/chat/api_send.go +++ b/modules/chat/api_send.go @@ -54,7 +54,7 @@ func (this *apiComp) Send(session comm.IUserSession, req *pb.ChatSendReq) (code } switch msg.Channel { case pb.ChatChannel_World: - if err = this.module.modelChat.addChatMsg(worldchatkey, max, msg); err != nil { + if err = this.module.modelChat.addChatMsg(worldchatkey, int64(max), msg); err != nil { code = pb.ErrorCode_DBError return } @@ -65,7 +65,7 @@ func (this *apiComp) Send(session comm.IUserSession, req *pb.ChatSendReq) (code break case pb.ChatChannel_Union: msg.UnionId = req.TargetId - if err = this.module.modelChat.addChatMsg(fmt.Sprintf("%s:%s", unionchatkey, req.TargetId), max_chat, msg); err != nil { + if err = this.module.modelChat.addChatMsg(fmt.Sprintf("%s:%s", unionchatkey, req.TargetId), int64(max_chat), msg); err != nil { code = pb.ErrorCode_DBError return } diff --git a/modules/chat/api_spansend.go b/modules/chat/api_spansend.go index 8021bc915..dec9ae684 100644 --- a/modules/chat/api_spansend.go +++ b/modules/chat/api_spansend.go @@ -48,7 +48,7 @@ func (this *apiComp) SpanSend(session comm.IUserSession, req *pb.ChatSpanSendReq } switch msg.Channel { case pb.ChatChannel_CrossServer: - if err = this.module.modelChat.addChatMsg(fmt.Sprintf("%s:%d--%d", crosschatkey, group, userexpand.Chatchannel), max_chat, msg); err != nil { + if err = this.module.modelChat.addChatMsg(fmt.Sprintf("%s:%d--%d", crosschatkey, group, userexpand.Chatchannel), int64(max_chat), msg); err != nil { code = pb.ErrorCode_DBError return } diff --git a/modules/chat/modelChat.go b/modules/chat/modelChat.go index 67b3fef80..2cd527602 100644 --- a/modules/chat/modelChat.go +++ b/modules/chat/modelChat.go @@ -6,9 +6,9 @@ import ( "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/redis" - "go_dreamfactory/lego/utils/codec/json" "go_dreamfactory/modules" "go_dreamfactory/pb" + "strings" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -28,9 +28,9 @@ type modelChatComp struct { //组件初始化接口 func (this *modelChatComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableChat this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Chat) - this.TableName = "chat" //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "ruid", Value: bsonx.Int32(1)}}, @@ -66,7 +66,6 @@ func (this *modelChatComp) QueryUserMsg(uid string) (result []*pb.DBChat, err er func (this *modelChatComp) GetChatQueue(channel pb.ChatChannel, union, group, area int32) (result []*pb.DBChat, err error) { var ( key string - cdata []map[string]string find bson.M c *mongo.Cursor n int @@ -97,17 +96,8 @@ func (this *modelChatComp) GetChatQueue(channel pb.ChatChannel, union, group, ar if readmax_chat, err = this.module.configure.GetChannelReadRecordNum(); err != nil { return } - if cdata, err = this.Batchgetqueues(key, readmax_chat); err == nil { - result = make([]*pb.DBChat, len(cdata)) - for i, v := range cdata { - chat := &pb.DBChat{} - if err = json.UnmarshalMap(v, chat); err != nil { - return - } - result[i] = chat - } - } - + result = make([]*pb.DBChat, 0) + err = this.GetQueues(key, int(readmax_chat), &result) if err == redis.RedisNil { //query from mgo if c, err = this.DB.Find(core.SqlTable(this.TableName), find); err != nil { @@ -123,7 +113,7 @@ func (this *modelChatComp) GetChatQueue(channel pb.ChatChannel, union, group, ar n++ } if len(result) > 0 { - this.addChatMsg(key, max_chat, result...) + this.addChatMsg(key, int64(max_chat), result...) } } } @@ -244,27 +234,17 @@ func (this *modelChatComp) SaveUserMsg(msg *pb.DBChat) (err error) { return } -func (this *modelChatComp) addChatMsg(key string, count int32, msgs ...*pb.DBChat) (err error) { +func (this *modelChatComp) addChatMsg(key string, count int64, msgs ...*pb.DBChat) (err error) { var ( - tempdata map[string]string - outkey []string - ks []string - vs []map[string]string - values []interface{} + data map[string]*pb.DBChat = make(map[string]*pb.DBChat, len(msgs)) + values []interface{} = make([]interface{}, len(msgs)) + outkey []string ) - ks = make([]string, len(msgs)) - vs = make([]map[string]string, len(msgs)) - values = make([]interface{}, len(msgs)) for i, v := range msgs { - if tempdata, err = json.MarshalMap(v); err != nil { - this.module.Errorf("err:%v", err) - return - } - ks[i] = fmt.Sprintf("%s-%s", key, v.Id) - vs[i] = tempdata + data[fmt.Sprintf("%s-%s", key, v.Id)] = v values[i] = v } - if outkey, err = this.Batchsetqueues(key, count, ks, vs); err != nil { + if outkey, err = this.AddQueues(key, count, data); err != nil { this.module.Errorf("err:%v", err) return } @@ -273,7 +253,14 @@ func (this *modelChatComp) addChatMsg(key string, count int32, msgs ...*pb.DBCha return } if len(outkey) > 0 { - if err = this.DeleteModelLogs(this.TableName, "", bson.M{"_id": bson.M{"$in": outkey}}); err != nil { + delkeys := make([]string, 0) + for _, v := range outkey { + temp := strings.Split(v, "_") + if len(temp) == 2 { + delkeys = append(delkeys, temp[1]) + } + } + if err = this.DeleteModelLogs(this.TableName, "", bson.M{"_id": bson.M{"$in": delkeys}}); err != nil { this.module.Errorf("err:%v", err) return } diff --git a/modules/comp_model.go b/modules/comp_model.go index e5adc37be..991261f7a 100644 --- a/modules/comp_model.go +++ b/modules/comp_model.go @@ -1,667 +1,123 @@ package modules import ( - "context" - "fmt" - "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/core/cbase" - "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/lego/sys/redis" - "go_dreamfactory/lego/utils/codec" - "go_dreamfactory/lego/utils/codec/codecore" - "go_dreamfactory/lego/utils/codec/json" "go_dreamfactory/sys/db" - "reflect" - "unsafe" + "log" - "github.com/modern-go/reflect2" "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" ) -var defconf = &codecore.Config{ - SortMapKeys: true, - IndentionStep: 1, - OnlyTaggedField: false, - DisallowUnknownFields: false, - CaseSensitive: false, - TagKey: "json", -} - -//Redis 自定义脚本 批量读取列表数据 -var LuaScriptgetList = ` -local key = tostring(KEYS[1]) -local keys = redis.call("HGETALL", key) -local data = {} -local n = 1 -for i, v in ipairs(keys) do - if i%2 == 0 then - data[n] = redis.call("HGETALL", v) - n = n+1 - end -end -return data -` - -//Redis 自定义脚本 批量写入列表数据 -var LuaScriptsetList = ` -local n = 1 -for i, v in ipairs(KEYS) do - local key = v - local argv = {} - for i=n,#ARGV,1 do - n = n+1 - if ARGV[i] == "#end" then - redis.call("HMSet", key,unpack(argv)) - break - else - table.insert(argv, ARGV[i]) - end - end -end -return "OK" -` - -//Redis 自定义脚本 批量卸载列表数据 -var LuaScriptdelList = ` -local key = tostring(KEYS[1]) -local keys = redis.call("HGETALL", key) -for i, v in ipairs(keys) do - if i%2 == 0 then - redis.call("DEL", v) - end -end -redis.call("DEL", key) -return "OK" -` - -//Redis 自定义脚本 批量读取队列数据 -var LuaScriptgetQueue = ` -local key = tostring(KEYS[1]) -local count = tonumber(ARGV[1]) * -1 -local keys = redis.call("LRANGE", key,count,-1) -local data = {} -for i, v in ipairs(keys) do - data[i] = redis.call("HGETALL", v) -end -return data -` - -//Redis 自定义脚本 批量写入队列数据 -var LuaScriptsetQueue = ` -local count = tonumber(ARGV[1]) -local k = tostring(ARGV[3]) -local keys = {} -local out = {} -local n = 1 -for i, v in ipairs(KEYS) do - if (i == 1) then - for i=n,#ARGV,1 do - n = n+1 - if ARGV[i] == "#end" then - break - end - end - elseif (i == 2) then - for i=n,#ARGV,1 do - n = n+1 - if ARGV[i] == "#end" then - break - end - end - else - local key = v - local argv = {} - table.insert(keys, key) - for i=n,#ARGV,1 do - n = n+1 - if ARGV[i] == "#end" then - redis.call("HMSet", key,unpack(argv)) - break - else - table.insert(argv, ARGV[i]) - end - end - end -end -redis.call("RPush", k,unpack(keys)) -local c = tonumber(redis.call("LLEN", k)) -count = count * 3 -if (c > count) then - local off = c-count - out = redis.call("LRANGE", k,0,off-1) - redis.call("LTRIM", k,off,-1) - for i, v in ipairs(out) do - redis.call("DEL", v) - end -end -return out -` - /* 基础组件 缓存组件 读写缓存数据 DB组件也封装进来 */ type MCompModel struct { cbase.ModuleCompBase - Redis redis.ISys - DB mgo.ISys - - TableName string //redis key前缀 - getListSha1 string //getList LusScript 的shal值 - setListSha1 string //getList LusScript 的shal值 - dellListSha1 string //getList LusScript 的shal值 - getQueueSha1 string //getList LusScript 的shal值 - setQueueSha1 string //getList LusScript 的shal值 + TableName string + Redis redis.ISys + DB mgo.ISys + DBModel *db.DBModel } -const ( - DB_ModelTable core.SqlTable = "model_log" -) - //组件初始化接口 func (this *MCompModel) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.ModuleCompBase.Init(service, module, comp, options) - this.Redis = db.Local().Redis this.DB = db.Local().Mgo + this.Redis = db.Local().Redis + if this.TableName == "" { + log.Panicf("TableName is nil") + return + } + this.DBModel = db.NewDBModel(this.TableName, db.Local()) return } -func (this *MCompModel) Start() (err error) { - err = this.ModuleCompBase.Start() - if this.getListSha1, err = this.Redis.NewScript(LuaScriptgetList).Result(); err != nil { - return - } - if this.setListSha1, err = this.Redis.NewScript(LuaScriptsetList).Result(); err != nil { - return - } - if this.dellListSha1, err = this.Redis.NewScript(LuaScriptdelList).Result(); err != nil { - return - } - if this.getQueueSha1, err = this.Redis.NewScript(LuaScriptgetQueue).Result(); err != nil { - return - } - if this.setQueueSha1, err = this.Redis.NewScript(LuaScriptsetQueue).Result(); err != nil { - return - } - return -} - -func (this *MCompModel) ukey(uid string) string { - return fmt.Sprintf("%s:%s{%s}", this.TableName, uid, this.TableName) -} -func (this *MCompModel) ukeylist(uid string, id string) string { - return fmt.Sprintf("%s:%s-%s{%s}", this.TableName, uid, id, this.TableName) -} func (this *MCompModel) InsertModelLogs(table string, uID string, target interface{}) (err error) { - - data := &comm.Autogenerated{ - ID: primitive.NewObjectID().Hex(), - UID: uID, - Act: string(comm.LogHandleType_Insert), - } - data.D = append(data.D, table) // D[0] - data.D = append(data.D, target) // D[1] - - _, err = this.DB.InsertOne(DB_ModelTable, data) - if err != nil { - log.Errorf("insert model db err %v", err) - } - - return err + return this.DBModel.InsertModelLogs(table, uID, target) } - func (this *MCompModel) DeleteModelLogs(table string, uID string, where interface{}) (err error) { - - data := &comm.Autogenerated{ - ID: primitive.NewObjectID().Hex(), - UID: uID, - Act: string(comm.LogHandleType_Delete), - } - - data.D = append(data.D, table) // D[0] - data.D = append(data.D, where) // D[1] - - _, err = this.DB.InsertOne(DB_ModelTable, data) - if err != nil { - log.Errorf("insert model db err %v", err) - } - - return err + return this.DBModel.DeleteModelLogs(table, uID, where) } func (this *MCompModel) UpdateModelLogs(table string, uID string, where bson.M, target interface{}) (err error) { - - data := &comm.Autogenerated{ - ID: primitive.NewObjectID().Hex(), - UID: uID, - Act: string(comm.LogHandleType_Update), - } - data.D = append(data.D, table) // D[0] - data.D = append(data.D, where) // D[1] - data.D = append(data.D, target) // D[2] - - _, err = this.DB.InsertOne(DB_ModelTable, data) - if err != nil { - log.Errorf("insert model db err %v", err) - } - - return err + return this.DBModel.UpdateModelLogs(table, uID, where, target) } //添加新的数据 -func (this *MCompModel) Add(uid string, data interface{}, opt ...DBOption) (err error) { - if err = this.Redis.HMSet(this.ukey(uid), data); err != nil { - return - } - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.InsertModelLogs(this.TableName, uid, []interface{}{data}) - } - if option.Expire > 0 { - err = this.Redis.Expire(this.ukey(uid), option.Expire) - } - return +func (this *MCompModel) Add(uid string, data interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.Add(uid, data) } //添加新的数据到列表 -func (this *MCompModel) AddList(uid string, id string, data interface{}, opt ...DBOption) (err error) { - key := this.ukeylist(uid, id) - if err = this.Redis.HMSet(key, data); err != nil { - return - } - if err = this.Redis.HSet(this.ukey(uid), id, key); err != nil { - return - } - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.InsertModelLogs(this.TableName, uid, []interface{}{data}) - } - if option.Expire > 0 { - err = this.Redis.Expire(this.ukey(uid), option.Expire) - } - return +func (this *MCompModel) AddList(uid string, id string, data interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.AddList(uid, id, data, opt...) } //添加新的多个数据到列表 data map[string]type -func (this *MCompModel) AddLists(uid string, data interface{}, opt ...DBOption) (err error) { - vof := reflect.ValueOf(data) - if !vof.IsValid() { - return fmt.Errorf("Model_Comp: AddLists(nil)") - } - if vof.Kind() != reflect.Map { - return fmt.Errorf("Model_Comp: AddLists(non-pointer %T)", data) - } - listskeys := make(map[string]string) - keys := vof.MapKeys() - lists := make([]interface{}, len(keys)) - for i, k := range keys { - value := vof.MapIndex(k) - keydata := k.Interface().(string) - valuedata := value.Interface() - key := this.ukeylist(uid, keydata) +func (this *MCompModel) AddLists(uid string, data interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.AddLists(uid, data, opt...) +} - if err = this.Redis.HMSet(key, valuedata); err != nil { - return - } - listskeys[keydata] = key - lists[i] = valuedata - } - - if err = this.Redis.HMSetForMap(this.ukey(uid), listskeys); err != nil { - return - } - - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.InsertModelLogs(this.TableName, uid, lists) - } - if option.Expire > 0 { - this.Redis.Expire(this.ukey(uid), option.Expire) - for _, v := range listskeys { - this.Redis.Expire(v, option.Expire) - } - } - return +//添加新的多个数据到队列中 data map[string]type +func (this *MCompModel) AddQueues(key string, uplimit int64, data interface{}) (outkey []string, err error) { + return this.DBModel.AddQueues(key, uplimit, data) } //修改数据多个字段 uid 作为主键 -func (this *MCompModel) Change(uid string, data map[string]interface{}, opt ...DBOption) (err error) { - if err = this.Redis.HMSet(this.ukey(uid), data); err != nil { - return - } - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.UpdateModelLogs(this.TableName, uid, bson.M{"uid": uid}, data) - } - if option.Expire > 0 { - this.Redis.Expire(this.ukey(uid), option.Expire) - } - return nil +func (this *MCompModel) Change(uid string, data map[string]interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.Change(uid, data, opt...) } //修改数据多个字段 uid 作为主键 -func (this *MCompModel) ChangeList(uid string, _id string, data map[string]interface{}, opt ...DBOption) (err error) { - if err = this.Redis.HMSet(this.ukeylist(uid, _id), data); err != nil { - return - } - - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.UpdateModelLogs(this.TableName, uid, bson.M{"_id": _id, "uid": uid}, data) - } - if option.Expire > 0 { - this.Redis.Expire(this.ukey(uid), option.Expire) - } - return nil +func (this *MCompModel) ChangeList(uid string, _id string, data map[string]interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.ChangeList(uid, _id, data, opt...) } //读取全部数据 -func (this *MCompModel) Get(uid string, data interface{}, opt ...DBOption) (err error) { - if err = this.Redis.HGetAll(this.ukey(uid), data); err != nil && err != redis.RedisNil { - return - } - if err == redis.RedisNil { - if err = this.DB.FindOne(core.SqlTable(this.TableName), bson.M{"uid": uid}).Decode(data); err != nil { - return - } - err = this.Redis.HMSet(this.ukey(uid), data) - } - option := newDBOption(opt...) - if option.Expire > 0 { - this.Redis.Expire(this.ukey(uid), option.Expire) - } - return +func (this *MCompModel) Get(uid string, data interface{}, opt ...db.DBOption) (err error) { + return this.DBModel.Get(uid, data, opt...) } //获取列表数据 注意 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 codecore.IDecoderMapJson - encoder codecore.IEncoderMapJson - dptr unsafe.Pointer - elemPtr unsafe.Pointer - n int - ok bool - keys map[string]string - cdata []map[string]string - wdata map[string]map[string]string - tempdata 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, defconf).(codecore.IDecoderMapJson); !ok { - err = fmt.Errorf("MCompModel: GetList(data not support MarshalMapJson %T)", data) - return - } - sliceelemType = sliceelemType.(*reflect2.UnsafePtrType).Elem() - if cdata, err = this.Batchgetlists(this.ukey(uid)); err == nil { - for _, v := range cdata { - sliceType.UnsafeGrow(dptr, n+1) - elemPtr = sliceType.UnsafeGetIndex(dptr, n) - if *((*unsafe.Pointer)(elemPtr)) == nil { - newPtr := sliceelemType.UnsafeNew() - if err = decoder.DecodeForMapJson(newPtr, json.GetReader([]byte{}), v); err != nil { - log.Errorf("err:%v", err) - return - } - *((*unsafe.Pointer)(elemPtr)) = newPtr - } else { - decoder.DecodeForMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetReader([]byte{}), v) - } - 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, defconf).(codecore.IEncoderMapJson); !ok { - err = fmt.Errorf("MCompModel: GetList(data not support UnMarshalMapJson %T)", data) - return - } - n = 0 - wdata = make(map[string]map[string]string) - for c.Next(context.Background()) { - _id := c.Current.Lookup("_id").StringValue() - sliceType.UnsafeGrow(dptr, n+1) - elemPtr = sliceType.UnsafeGetIndex(dptr, n) - if *((*unsafe.Pointer)(elemPtr)) == nil { - newPtr := sliceelemType.UnsafeNew() - *((*unsafe.Pointer)(elemPtr)) = newPtr - } - elem := sliceType.GetIndex(data, n) - if err = c.Decode(elem); err != nil { - return - } - if tempdata, err = encoder.EncodeToMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetWriter()); err != nil { - return - } - key := this.ukeylist(uid, _id) - wdata[key] = tempdata - keys[_id] = key - n++ - } - if len(wdata) > 0 { - wdata[this.ukey(uid)] = keys - err = this.Batchsetlists(wdata) - } - } - } + return this.DBModel.GetFields(uid, data) +} - return err +//查询队列信息 +func (this *MCompModel) GetQueues(key string, count int, data interface{}) (err error) { + return this.DBModel.GetQueues(key, count, data) } //读取单个数据中 多个字段数据 func (this *MCompModel) GetFields(uid string, data interface{}, fields ...string) (err error) { - this.Redis.HMGet(this.ukey(uid), data, fields...) - return + return this.DBModel.GetFields(uid, data, fields...) } //读取List列表中单个数据中 多个字段数据 func (this *MCompModel) GetListFields(uid string, id string, data interface{}, fields ...string) (err error) { - this.Redis.HMGet(this.ukeylist(uid, id), data, fields...) - return + return this.DBModel.GetListFields(uid, id, data, fields...) } //读取列表数据中单个数据 func (this *MCompModel) GetListObj(uid string, id string, data interface{}) (err error) { - err = this.Redis.HGetAll(this.ukeylist(uid, id), data) - return + return this.DBModel.GetListObj(uid, id, data) } //删除用户数据 -func (this *MCompModel) Del(uid string, opt ...DBOption) (err error) { - err = this.Redis.Delete(this.ukey(uid)) - if err != nil { - return err - } - option := newDBOption(opt...) - if option.IsMgoLog { - err = this.DeleteModelLogs(this.TableName, uid, bson.M{"uid": uid}) - } - return nil +func (this *MCompModel) Del(uid string, opt ...db.DBOption) (err error) { + return this.DBModel.Del(uid, opt...) } //删除多条数据 func (this *MCompModel) DelListlds(uid string, ids ...string) (err error) { - listkey := this.ukey(uid) - for _, v := range ids { - key := this.ukeylist(uid, v) - if err = this.Redis.Delete(key); err != nil { - return - } - } - if err = this.Redis.HDel(listkey, ids...); err == nil { - err = this.DeleteModelLogs(this.TableName, uid, bson.M{"_id": bson.M{"$in": ids}}) - } - return -} - -// 清除玩家英雄缓存信息 -// func (this *MCompModel) ClearnHeroCache(uid string, ids ...string) (err error) { -// listkey := this.ukey(uid) -// for _, v := range ids { -// key := this.ukeylist(uid, v) -// if err = this.Redis.Delete(key); err != nil { -// return -// } -// } -// err = this.Redis.HDel(listkey, ids...) -// return -// } - -//批量读取列表数据 -func (this *MCompModel) Batchgetlists(key string) (result []map[string]string, err error) { - var data interface{} - ret := this.Redis.EvalSha(this.Redis.Context(), this.getListSha1, []string{key}) - if data, err = ret.Result(); err != nil { - fmt.Printf("Execute batchgetlists err: %v", err.Error()) - } else { - temp1 := data.([]interface{}) - result = make([]map[string]string, len(temp1)) - for i, v := range temp1 { - temp2 := v.([]interface{}) - result[i] = make(map[string]string) - for n := 0; n < len(temp2); n += 2 { - result[i][temp2[n].(string)] = temp2[n+1].(string) - } - } - if len(result) == 0 { - err = redis.RedisNil - return - } - } - return -} - -//批量写入数据 -func (this *MCompModel) Batchsetlists(data map[string]map[string]string) (err error) { - var ( - n int - keys []string - values []interface{} - ) - keys = make([]string, len(data)) - values = make([]interface{}, 0) - - for k, v := range data { - keys[n] = k - for k1, v1 := range v { - values = append(values, k1, v1) - } - values = append(values, "#end") - n++ - } - ret := this.Redis.EvalSha(this.Redis.Context(), this.setListSha1, keys, values...) - if _, err := ret.Result(); err != nil { - fmt.Printf("Execute batchsetlists err: %v", err.Error()) - } - return -} - -//批量读取队列数据 -func (this *MCompModel) Batchgetqueues(key string, count int32) (result []map[string]string, err error) { - var data interface{} - ret := this.Redis.EvalSha(this.Redis.Context(), this.getQueueSha1, []string{key}, count) - if data, err = ret.Result(); err != nil { - fmt.Printf("Execute batchgetqueues err: %v", err.Error()) - } else { - temp1 := data.([]interface{}) - result = make([]map[string]string, len(temp1)) - for i, v := range temp1 { - temp2 := v.([]interface{}) - result[i] = make(map[string]string) - for n := 0; n < len(temp2); n += 2 { - result[i][temp2[n].(string)] = temp2[n+1].(string) - } - } - if len(result) == 0 { - err = redis.RedisNil - return - } - } - return -} - -//批量写入队列 并返回移除队列 -func (this *MCompModel) Batchsetqueues(key string, count int32, ks []string, vs []map[string]string) (outkey []string, err error) { - var ( - n int - keys []string - values []interface{} - result interface{} - ) - keys = make([]string, len(ks)+2) - values = make([]interface{}, 0) - keys[0] = "count" - values = append(values, count) - values = append(values, "#end") - keys[1] = "key" - values = append(values, key) - values = append(values, "#end") - n = 2 - for i, v := range ks { - keys[n] = v - for k1, v1 := range vs[i] { - values = append(values, k1, v1) - } - values = append(values, "#end") - n++ - } - ret := this.Redis.EvalSha(this.Redis.Context(), this.setQueueSha1, keys, values...) - if result, err = ret.Result(); err != nil { - fmt.Printf("Execute batchsetqueues err: %v", err.Error()) - } else { - outkey = make([]string, len(result.([]interface{}))) - for i, v := range result.([]interface{}) { - outkey[i] = v.(string) - } - } - return + return this.DBModel.DelListlds(uid, ids...) } //批量删除数据 func (this *MCompModel) BatchDelLists(uid string) (err error) { - ret := this.Redis.EvalSha(this.Redis.Context(), this.dellListSha1, []string{this.ukey(uid)}) - if _, err := ret.Result(); err != nil { - fmt.Printf("Execute batchsetlists err: %v", err.Error()) - } - return -} - -// 删除玩家缓存信息 -func (this *MCompModel) CleanUserRecord(uid string) (err error) { - err = this.Redis.Delete(this.ukey(uid)) - if err != nil { - return err - } - return + return this.DBModel.BatchDelLists(uid) } diff --git a/modules/equipment/modelEquipment.go b/modules/equipment/modelEquipment.go index 8c2a60dd1..2c32c57c8 100644 --- a/modules/equipment/modelEquipment.go +++ b/modules/equipment/modelEquipment.go @@ -1,6 +1,7 @@ package equipment import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" @@ -22,9 +23,9 @@ type modelEquipmentComp struct { //组件初始化接口 func (this *modelEquipmentComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableEquipment this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Equipment) - this.TableName = "equipment" //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, diff --git a/modules/forum/modelForum.go b/modules/forum/modelForum.go index 11ac17547..8643d3464 100644 --- a/modules/forum/modelForum.go +++ b/modules/forum/modelForum.go @@ -1,9 +1,8 @@ package forum import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" - "go_dreamfactory/lego/sys/redis" - "go_dreamfactory/lego/utils/codec/json" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -19,9 +18,10 @@ type modelForumComp struct { //组件初始化接口 func (this *modelForumComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableForum this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Forum) - this.TableName = "forum" + //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "heroid", Value: bsonx.Int32(1)}}, @@ -31,25 +31,7 @@ func (this *modelForumComp) Init(service core.IService, module core.IModule, com //查询用户未读消息 func (this *modelForumComp) GetComment(herocId string) (result []*pb.DBComment, err error) { - var ( - key string - cdata []map[string]string - readmax_chat int32 - ) - if cdata, err = this.Batchgetqueues(key, readmax_chat); err == nil { - result = make([]*pb.DBComment, len(cdata)) - for i, v := range cdata { - comment := &pb.DBComment{} - if err = json.UnmarshalMap(v, comment); err != nil { - return - } - result[i] = comment - } - } - if err == redis.RedisNil { - err = nil - } return } diff --git a/modules/friend/model_friend.go b/modules/friend/model_friend.go index d983c49f2..cbc2ca330 100644 --- a/modules/friend/model_friend.go +++ b/modules/friend/model_friend.go @@ -1,6 +1,7 @@ package friend import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/redis" @@ -11,24 +12,20 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -const ( - TableFriend core.SqlTable = "friend" - TableUser core.SqlTable = "user" //用户表 -) - type ModelFriend struct { modules.MCompModel } func (this *ModelFriend) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableFriend err = this.MCompModel.Init(service, module, comp, options) - this.TableName = string(TableFriend) + return } func (this *ModelFriend) Frined_FindCond(nickName string) *pb.DBUser { var user *pb.DBUser - err := this.DB.FindOne(TableUser, bson.M{ + err := this.DB.FindOne(comm.TableUser, bson.M{ "name": nickName, }).Decode(&user) if err != nil { diff --git a/modules/hero/model_hero.go b/modules/hero/model_hero.go index 5cd2a954a..553ab0fad 100644 --- a/modules/hero/model_hero.go +++ b/modules/hero/model_hero.go @@ -23,9 +23,9 @@ type ModelHero struct { } func (this *ModelHero) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableHero 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)}}, @@ -217,7 +217,7 @@ func (this *ModelHero) createMultiHero(uid string, heroCfgIds ...string) error { //获取一个英雄(参数唯一objID) func (this *ModelHero) getOneHero(uid, heroId string) *pb.DBHero { hero := &pb.DBHero{} - err := this.moduleHero.modelHero.GetListObj(uid, heroId, hero) + err := this.GetListObj(uid, heroId, hero) if err != nil { return nil } @@ -241,7 +241,7 @@ func (this *ModelHero) consumeHeroCard(uid string, hero *pb.DBHero, count int32) } hero.SameCount -= count // 数量-1 if hero.SameCount == 0 { - if err := this.moduleHero.modelHero.DelListlds(uid, hero.Id); err != nil { + if err := this.DelListlds(uid, hero.Id); err != nil { this.moduleHero.Errorf("%v", err) } } else { diff --git a/modules/hero/model_record.go b/modules/hero/model_record.go index 4c31cf6da..3fa2e041b 100644 --- a/modules/hero/model_record.go +++ b/modules/hero/model_record.go @@ -1,6 +1,7 @@ package hero import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" @@ -14,8 +15,8 @@ type ModelRecord struct { } func (this *ModelRecord) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableUserRecord err = this.MCompModel.Init(service, module, comp, options) - this.TableName = "userrecord" return } diff --git a/modules/items/modelitems.go b/modules/items/modelitems.go index 752cc353a..6bc09a8f1 100644 --- a/modules/items/modelitems.go +++ b/modules/items/modelitems.go @@ -2,6 +2,7 @@ package items import ( "fmt" + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -21,9 +22,9 @@ type ModelItemsComp struct { //组件初始化接口 func (this *ModelItemsComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableItems this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Items) - this.TableName = "items" //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, diff --git a/modules/mail/model_mail.go b/modules/mail/model_mail.go index 5fb0e1b98..94063f0f9 100644 --- a/modules/mail/model_mail.go +++ b/modules/mail/model_mail.go @@ -2,6 +2,7 @@ package mail import ( "context" + "go_dreamfactory/comm" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -14,19 +15,16 @@ import ( "go.mongodb.org/mongo-driver/x/bsonx" ) -const ( - DB_MailTable core.SqlTable = "mail" -) - type modelMail struct { modules.MCompModel } func (this *modelMail) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableMail this.MCompModel.Init(service, module, comp, options) - this.TableName = "mail" + //创建uid索引 - this.DB.CreateIndex(core.SqlTable(DB_MailTable), mongo.IndexModel{ + this.DB.CreateIndex(core.SqlTable(comm.TableMail), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, }) return @@ -34,7 +32,7 @@ func (this *modelMail) Init(service core.IService, module core.IModule, comp cor func (this *modelMail) MailQueryUserMail(uId string) (mail []*pb.DBMailData, err error) { - if _data, err := this.DB.Find(DB_MailTable, bson.M{"uid": uId}); err == nil { + if _data, err := this.DB.Find(comm.TableMail, bson.M{"uid": uId}); err == nil { for _data.Next(context.TODO()) { temp := &pb.DBMailData{} if err = _data.Decode(temp); err == nil { @@ -55,7 +53,7 @@ func (this *modelMail) MailInsertUserMail(mail *pb.DBMailData) (err error) { if len(mail.GetItems()) > 0 { mail.Reward = false } - _, err = this.DB.InsertOne(DB_MailTable, mail) + _, err = this.DB.InsertOne(comm.TableMail, mail) return err } @@ -63,7 +61,7 @@ func (this *modelMail) MailInsertUserMail(mail *pb.DBMailData) (err error) { func (this *modelMail) MailReadOneMail(objId string) (mail *pb.DBMailData, err error) { err = this.DB.FindOneAndUpdate( - DB_MailTable, + comm.TableMail, bson.M{"_id": objId}, bson.M{"$set": bson.M{ "check": true, @@ -78,7 +76,7 @@ func (this *modelMail) MailReadOneMail(objId string) (mail *pb.DBMailData, err e func (this *modelMail) MailGetMailAttachment(objId string) (itmes []*pb.UserAssets, err error) { var nd *pb.DBMailData - err = this.DB.FindOne(DB_MailTable, bson.M{"_id": objId}).Decode(&nd) + err = this.DB.FindOne(comm.TableMail, bson.M{"_id": objId}).Decode(&nd) if err == nil { itmes = nd.GetItems() } @@ -88,7 +86,7 @@ func (this *modelMail) MailGetMailAttachment(objId string) (itmes []*pb.UserAsse // 查看领取附件状态 func (this *modelMail) MailGetMailAttachmentState(objId string) (*pb.DBMailData, error) { var nd *pb.DBMailData - err := this.DB.FindOne(DB_MailTable, bson.M{"_id": objId}).Decode(&nd) + err := this.DB.FindOne(comm.TableMail, bson.M{"_id": objId}).Decode(&nd) return nd, err //return !nd.Reward && len(nd.GetItems()) > 0 && nd.Uid == uid @@ -97,7 +95,7 @@ func (this *modelMail) MailGetMailAttachmentState(objId string) (*pb.DBMailData, // 更新领取附件状态 func (this *modelMail) MailUpdateMailAttachmentState(objId string) bool { this.DB.FindOneAndUpdate( - DB_MailTable, + comm.TableMail, bson.M{"_id": objId}, bson.M{"$set": bson.M{ "reward": true, @@ -112,18 +110,18 @@ func (this *modelMail) MailUpdateMailAttachmentState(objId string) bool { // 删除一封邮件 func (this *modelMail) MailDelUserMail(objId string) bool { var obj *pb.DBMailData - err := this.DB.FindOne(DB_MailTable, bson.M{"_id": objId}).Decode(&obj) + err := this.DB.FindOne(comm.TableMail, bson.M{"_id": objId}).Decode(&obj) if err != nil { return false } - this.DB.DeleteOne(DB_MailTable, bson.M{"_id": objId}) + this.DB.DeleteOne(comm.TableMail, bson.M{"_id": objId}) return true } func (this *modelMail) MailQueryUserMailByReard(uId string) (mail []*pb.DBMailData, err error) { - if _data, err := this.DB.Find(DB_MailTable, bson.M{"uid": uId, "reward": false}); err == nil { + if _data, err := this.DB.Find(comm.TableMail, bson.M{"uid": uId, "reward": false}); err == nil { for _data.Next(context.TODO()) { temp := &pb.DBMailData{} if err = _data.Decode(temp); err == nil { diff --git a/modules/mainline/model_story.go b/modules/mainline/model_story.go index 7f18500d5..2b835cc08 100644 --- a/modules/mainline/model_story.go +++ b/modules/mainline/model_story.go @@ -1,24 +1,21 @@ package mainline import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" ) -const ( //Redis - TableMainline core.SqlTable = "mainline" -) - type ModelMainline struct { modules.MCompModel module *Mainline } func (this *ModelMainline) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableMainline err = this.MCompModel.Init(service, module, comp, options) this.module = module.(*Mainline) - this.TableName = string(TableMainline) return } diff --git a/modules/mgolog/db_comp.go b/modules/mgolog/db_comp.go index 6ecf2205f..340b9c5d5 100644 --- a/modules/mgolog/db_comp.go +++ b/modules/mgolog/db_comp.go @@ -20,9 +20,9 @@ type DB_Comp struct { } func (this *DB_Comp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableModellog this.MCompModel.Init(service, module, comp, options) this.task = make(chan string, TaskMaxNum) - this.TableName = "model_log" return } diff --git a/modules/notify/modelNotify.go b/modules/notify/modelNotify.go index 16c9ed060..19ccc8d69 100644 --- a/modules/notify/modelNotify.go +++ b/modules/notify/modelNotify.go @@ -2,6 +2,7 @@ package notify import ( "context" + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -21,9 +22,9 @@ type modelNotifyComp struct { //组件初始化接口 func (this *modelNotifyComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableNotify this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Notify) - this.TableName = "notify" //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, diff --git a/modules/shop/model_shop.go b/modules/shop/model_shop.go index 97eb4b8af..0119ecd08 100644 --- a/modules/shop/model_shop.go +++ b/modules/shop/model_shop.go @@ -1,6 +1,7 @@ package shop import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -17,9 +18,9 @@ type modelShopComp struct { //组件初始化接口 func (this *modelShopComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableShop this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Shop) - this.TableName = "shop" //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, diff --git a/modules/shop/model_shopitems.go b/modules/shop/model_shopitems.go index 8a46d6b3a..e56429e47 100644 --- a/modules/shop/model_shopitems.go +++ b/modules/shop/model_shopitems.go @@ -1,6 +1,7 @@ package shop import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/modules" @@ -18,10 +19,9 @@ type modelShopItemsComp struct { //组件初始化接口 func (this *modelShopItemsComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableShopitems this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Shop) - this.TableName = "shopitems" - //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}, {Key: "goodsid", Value: bsonx.Int32(1)}}, diff --git a/modules/shop/module.go b/modules/shop/module.go index 6839a8b1d..d33d49f64 100644 --- a/modules/shop/module.go +++ b/modules/shop/module.go @@ -4,6 +4,7 @@ import ( "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" + "go_dreamfactory/sys/db" ) /* @@ -46,6 +47,6 @@ func (this *Shop) OnInstallComp() { //Event------------------------------------------------------------------------------------------------------------ func (this *Shop) EventUserOffline(session comm.IUserSession) { - this.modelShop.Del(session.GetUserId(), modules.SetDBMgoLog(false)) + this.modelShop.Del(session.GetUserId(), db.SetDBMgoLog(false)) this.modelShopItems.BatchDelLists(session.GetUserId()) } diff --git a/modules/task/model_active.go b/modules/task/model_active.go index fd0e60ea4..138cd7ccd 100644 --- a/modules/task/model_active.go +++ b/modules/task/model_active.go @@ -10,19 +10,15 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) -const ( //Redis - TableTaskActive core.SqlTable = "taskactive" //活跃度表 -) - type ModelTaskActive struct { modules.MCompModel moduleTask *ModuleTask } func (this *ModelTaskActive) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableTaskActive err = this.MCompModel.Init(service, module, comp, options) this.moduleTask = module.(*ModuleTask) - this.TableName = string(TableTaskActive) return } diff --git a/modules/task/model_task.go b/modules/task/model_task.go index a3bd5f138..fd0133986 100644 --- a/modules/task/model_task.go +++ b/modules/task/model_task.go @@ -11,19 +11,15 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" ) -const ( //Redis - TableTask core.SqlTable = "task" //每日任务表 -) - type ModelTask struct { modules.MCompModel moduleTask *ModuleTask } func (this *ModelTask) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableTask err = this.MCompModel.Init(service, module, comp, options) this.moduleTask = module.(*ModuleTask) - this.TableName = string(TableTask) return } diff --git a/modules/user/api_login.go b/modules/user/api_login.go index 40da35484..e36771d73 100644 --- a/modules/user/api_login.go +++ b/modules/user/api_login.go @@ -4,8 +4,8 @@ import ( "go_dreamfactory/comm" "go_dreamfactory/lego/sys/event" "go_dreamfactory/lego/sys/log" - "go_dreamfactory/modules" "go_dreamfactory/pb" + "go_dreamfactory/sys/db" "go_dreamfactory/utils" "time" @@ -87,8 +87,8 @@ func (this *apiComp) Login(session comm.IUserSession, req *pb.UserLoginReq) (cod "gatewayServiceId": session.GetGatewayServiceId(), "ip": session.GetIP(), }, - modules.SetDBExpire(time.Hour*12), - modules.SetDBMgoLog(false)) + db.SetDBExpire(time.Hour*12), + db.SetDBMgoLog(false)) if err != nil { code = pb.ErrorCode_DBError return diff --git a/modules/user/model_expand.go b/modules/user/model_expand.go index edf4777ab..0b4f0884d 100644 --- a/modules/user/model_expand.go +++ b/modules/user/model_expand.go @@ -1,6 +1,7 @@ package user import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" @@ -14,8 +15,8 @@ type ModelExpand struct { } func (this *ModelExpand) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableUserExpand err = this.MCompModel.Init(service, module, comp, options) - this.TableName = "userexpand" this.moduleUser = module.(*User) return } diff --git a/modules/user/model_session.go b/modules/user/model_session.go index 04cfba88b..b8d613146 100644 --- a/modules/user/model_session.go +++ b/modules/user/model_session.go @@ -1,6 +1,7 @@ package user import ( + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/modules" @@ -12,8 +13,8 @@ type ModelSession struct { } func (this *ModelSession) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableSession err = this.MCompModel.Init(service, module, comp, options) - this.TableName = "session" return } diff --git a/modules/user/model_setting.go b/modules/user/model_setting.go index 051129027..506925bb9 100644 --- a/modules/user/model_setting.go +++ b/modules/user/model_setting.go @@ -2,6 +2,7 @@ package user import ( "fmt" + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/redis" "go_dreamfactory/modules" @@ -18,9 +19,9 @@ type ModelSetting struct { } func (this *ModelSetting) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableSetting err = this.MCompModel.Init(service, module, comp, options) this.moduleUser = module.(*User) - this.TableName = "setting" return } diff --git a/modules/user/model_user.go b/modules/user/model_user.go index bdc8c23bc..0b55e5ec2 100644 --- a/modules/user/model_user.go +++ b/modules/user/model_user.go @@ -17,10 +17,6 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -const ( //Redis - TableUser core.SqlTable = "user" //用户表 -) - type ModelUser struct { modules.MCompModel moduleUser *User @@ -28,8 +24,8 @@ type ModelUser struct { } func (this *ModelUser) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { + this.TableName = comm.TableUser err = this.MCompModel.Init(service, module, comp, options) - this.TableName = string(TableUser) this.moduleUser = module.(*User) this.eventApp = event_v2.NewApp() this.eventApp.Listen(comm.EventUserChanged, this.ChangeExp) @@ -42,7 +38,7 @@ func (this *ModelUser) FindByAccount(sid int32, account string) (*pb.DBUser, err "sid": sid, "binduid": account, } - sr := this.DB.FindOne(TableUser, filter) + sr := this.DB.FindOne(comm.TableUser, filter) var nd *pb.DBUser err := sr.Decode(&nd) return nd, err @@ -50,7 +46,7 @@ func (this *ModelUser) FindByAccount(sid int32, account string) (*pb.DBUser, err //查询昵称 func (this *ModelUser) NickNameIsExist(name string) bool { - if err := this.DB.FindOne(TableUser, bson.M{"name": name}).Err(); err != nil { + if err := this.DB.FindOne(comm.TableUser, bson.M{"name": name}).Err(); err != nil { if err == mongo.ErrNoDocuments { //无记录 return true } diff --git a/modules/user/module.go b/modules/user/module.go index 8a474e8bb..0fae4fb39 100644 --- a/modules/user/module.go +++ b/modules/user/module.go @@ -4,6 +4,7 @@ import ( "go_dreamfactory/comm" "go_dreamfactory/modules" "go_dreamfactory/pb" + "go_dreamfactory/sys/db" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/event" @@ -31,7 +32,6 @@ func (this *User) GetType() core.M_Modules { func (this *User) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) { err = this.ModuleBase.Init(service, module, options) - return } @@ -70,10 +70,10 @@ func (this *User) GetUserSession(uid string) *pb.CacheUser { // 清除session func (this *User) CleanSession(session comm.IUserSession) { - this.modelSession.Del(session.GetUserId(), modules.SetDBMgoLog(false)) - this.modelUser.Del(session.GetUserId(), modules.SetDBMgoLog(false)) + this.modelSession.Del(session.GetUserId(), db.SetDBMgoLog(false)) + this.modelUser.Del(session.GetUserId(), db.SetDBMgoLog(false)) //this.modelExpand.Del(session.GetUserId(), modules.SetDBMgoLog(false)) // 暂时不清 - this.modelSetting.Del(session.GetUserId(), modules.SetDBMgoLog(false)) + this.modelSetting.Del(session.GetUserId(), db.SetDBMgoLog(false)) } //查询用户属性值 例如 金币 经验 diff --git a/modules/web/modelMail.go b/modules/web/modelMail.go index e211f019c..213a417ee 100644 --- a/modules/web/modelMail.go +++ b/modules/web/modelMail.go @@ -17,9 +17,9 @@ type modelMailComp struct { } func (this *modelMailComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = "mail" this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Web) - this.TableName = "mail" return } diff --git a/modules/web/modelNotify.go b/modules/web/modelNotify.go index f9fd5b6d3..4a6719515 100644 --- a/modules/web/modelNotify.go +++ b/modules/web/modelNotify.go @@ -16,9 +16,9 @@ type modelNotifyComp struct { } func (this *modelNotifyComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = "notify" this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Web) - this.TableName = "notify" return } diff --git a/modules/web/modelUser.go b/modules/web/modelUser.go index 8e7fe4f56..7b65b0fb6 100644 --- a/modules/web/modelUser.go +++ b/modules/web/modelUser.go @@ -2,6 +2,7 @@ package web import ( "fmt" + "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" @@ -18,9 +19,9 @@ type modelUserComp struct { } func (this *modelUserComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { + this.TableName = comm.TableUser this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Web) - this.TableName = "user" return } diff --git a/sys/db/db.go b/sys/db/db.go index 129646c84..bc9b4e237 100644 --- a/sys/db/db.go +++ b/sys/db/db.go @@ -2,44 +2,8 @@ package db import ( "go_dreamfactory/lego/sys/log" - "go_dreamfactory/lego/sys/mgo" - "go_dreamfactory/lego/sys/redis" ) -type DBConn struct { - Redis redis.ISys - Mgo mgo.ISys -} - -func newDBConn(conf DBConfig) (conn *DBConn, err error) { - conn = &DBConn{} - if conf.RedisIsCluster { - conn.Redis, err = redis.NewSys( - redis.SetRedisType(redis.Redis_Cluster), - redis.SetRedis_Cluster_Addr(conf.RedisAddr), - redis.SetRedis_Cluster_Password(conf.RedisPassword)) - } else { - conn.Redis, err = redis.NewSys( - redis.SetRedisType(redis.Redis_Single), - redis.SetRedis_Single_Addr(conf.RedisAddr[0]), - redis.SetRedis_Single_Password(conf.RedisPassword), - redis.SetRedis_Single_DB(conf.RedisDB), - ) - } - if err != nil { - log.Error(err.Error(), log.Field{"config", conf}) - return - } - if conn.Mgo, err = mgo.NewSys( - mgo.SetMongodbUrl(conf.MongodbUrl), - mgo.SetMongodbDatabase(conf.MongodbDatabase), - ); err != nil { - log.Error(err.Error(), log.Field{"config", conf}) - return - } - return -} - func newSys(options *Options) (sys *DB, err error) { sys = &DB{options: options} err = sys.init() diff --git a/sys/db/dbconn.go b/sys/db/dbconn.go new file mode 100644 index 000000000..d018088d7 --- /dev/null +++ b/sys/db/dbconn.go @@ -0,0 +1,545 @@ +package db + +import ( + "context" + "fmt" + "go_dreamfactory/comm" + "go_dreamfactory/lego/core" + "go_dreamfactory/lego/sys/log" + "go_dreamfactory/lego/sys/mgo" + lgredis "go_dreamfactory/lego/sys/redis" + "go_dreamfactory/lego/utils/codec" + "go_dreamfactory/lego/utils/codec/codecore" + "go_dreamfactory/lego/utils/codec/json" + "reflect" + "unsafe" + + "github.com/go-redis/redis/v8" + + "github.com/modern-go/reflect2" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +var defconf = &codecore.Config{ + SortMapKeys: true, + IndentionStep: 1, + OnlyTaggedField: false, + DisallowUnknownFields: false, + CaseSensitive: false, + TagKey: "json", +} + +const ( + DB_ModelTable core.SqlTable = "model_log" +) + +func newDBConn(conf DBConfig) (conn *DBConn, err error) { + conn = &DBConn{} + if conf.RedisIsCluster { + conn.Redis, err = lgredis.NewSys( + lgredis.SetRedisType(lgredis.Redis_Cluster), + lgredis.SetRedis_Cluster_Addr(conf.RedisAddr), + lgredis.SetRedis_Cluster_Password(conf.RedisPassword)) + } else { + conn.Redis, err = lgredis.NewSys( + lgredis.SetRedisType(lgredis.Redis_Single), + lgredis.SetRedis_Single_Addr(conf.RedisAddr[0]), + lgredis.SetRedis_Single_Password(conf.RedisPassword), + lgredis.SetRedis_Single_DB(conf.RedisDB), + ) + } + if err != nil { + log.Error(err.Error(), log.Field{"config", conf}) + return + } + if conn.Mgo, err = mgo.NewSys( + mgo.SetMongodbUrl(conf.MongodbUrl), + mgo.SetMongodbDatabase(conf.MongodbDatabase), + ); err != nil { + log.Error(err.Error(), log.Field{"config", conf}) + return + } + return +} + +type DBConn struct { + Redis lgredis.ISys + Mgo mgo.ISys +} + +func NewDBModel(TableName string, conn *DBConn) *DBModel { + return &DBModel{ + TableName: TableName, + Redis: conn.Redis, + DB: conn.Mgo, + } +} + +//DB模型 +type DBModel struct { + TableName string + Redis lgredis.ISys + DB mgo.ISys +} + +func (this *DBModel) ukey(uid string) string { + return fmt.Sprintf("%s:%s{%s}", this.TableName, uid, this.TableName) +} +func (this *DBModel) ukeylist(uid string, id string) string { + return fmt.Sprintf("%s:%s-%s{%s}", this.TableName, uid, id, this.TableName) +} +func (this *DBModel) InsertModelLogs(table string, uID string, target interface{}) (err error) { + + data := &comm.Autogenerated{ + ID: primitive.NewObjectID().Hex(), + UID: uID, + Act: string(comm.LogHandleType_Insert), + } + data.D = append(data.D, table) // D[0] + data.D = append(data.D, target) // D[1] + + _, err = this.DB.InsertOne(DB_ModelTable, data) + if err != nil { + log.Errorf("insert model db err %v", err) + } + + return err +} +func (this *DBModel) DeleteModelLogs(table string, uID string, where interface{}) (err error) { + + data := &comm.Autogenerated{ + ID: primitive.NewObjectID().Hex(), + UID: uID, + Act: string(comm.LogHandleType_Delete), + } + + data.D = append(data.D, table) // D[0] + data.D = append(data.D, where) // D[1] + + _, err = this.DB.InsertOne(DB_ModelTable, data) + if err != nil { + log.Errorf("insert model db err %v", err) + } + + return err +} + +func (this *DBModel) UpdateModelLogs(table string, uID string, where bson.M, target interface{}) (err error) { + + data := &comm.Autogenerated{ + ID: primitive.NewObjectID().Hex(), + UID: uID, + Act: string(comm.LogHandleType_Update), + } + data.D = append(data.D, table) // D[0] + data.D = append(data.D, where) // D[1] + data.D = append(data.D, target) // D[2] + + _, err = this.DB.InsertOne(DB_ModelTable, data) + if err != nil { + log.Errorf("insert model db err %v", err) + } + + return err +} + +//添加新的数据 +func (this *DBModel) Add(uid string, data interface{}, opt ...DBOption) (err error) { + if err = this.Redis.HMSet(this.ukey(uid), data); err != nil { + return + } + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.InsertModelLogs(this.TableName, uid, []interface{}{data}) + } + if option.Expire > 0 { + err = this.Redis.Expire(this.ukey(uid), option.Expire) + } + return +} + +//添加新的数据到列表 +func (this *DBModel) AddList(uid string, id string, data interface{}, opt ...DBOption) (err error) { + key := this.ukeylist(uid, id) + if err = this.Redis.HMSet(key, data); err != nil { + return + } + if err = this.Redis.HSet(this.ukey(uid), id, key); err != nil { + return + } + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.InsertModelLogs(this.TableName, uid, []interface{}{data}) + } + if option.Expire > 0 { + err = this.Redis.Expire(this.ukey(uid), option.Expire) + } + return +} + +//添加新的多个数据到列表 data map[string]type +func (this *DBModel) AddLists(uid string, data interface{}, opt ...DBOption) (err error) { + vof := reflect.ValueOf(data) + if !vof.IsValid() { + return fmt.Errorf("Model_Comp: AddLists(nil)") + } + if vof.Kind() != reflect.Map { + return fmt.Errorf("Model_Comp: AddLists(non-pointer %T)", data) + } + listskeys := make(map[string]string) + keys := vof.MapKeys() + lists := make([]interface{}, len(keys)) + pipe := this.Redis.RedisPipe(context.TODO()) + for _, k := range keys { + value := vof.MapIndex(k) + keydata := k.Interface().(string) + valuedata := value.Interface() + key := this.ukeylist(uid, keydata) + pipe.HMSet(key, valuedata) + listskeys[keydata] = key + } + pipe.HMSetForMap(this.ukey(uid), listskeys) + if _, err = pipe.Exec(); err != nil { + return + } + + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.InsertModelLogs(this.TableName, uid, lists) + } + if option.Expire > 0 { + this.Redis.Expire(this.ukey(uid), option.Expire) + for _, v := range listskeys { + this.Redis.Expire(v, option.Expire) + } + } + return +} + +//添加队列 +func (this *DBModel) AddQueues(key string, uplimit int64, data interface{}) (outkey []string, err error) { + vof := reflect.ValueOf(data) + if !vof.IsValid() { + err = fmt.Errorf("Model_Comp: AddLists(nil)") + return + } + if vof.Kind() != reflect.Map { + err = fmt.Errorf("Model_Comp: AddLists(non-pointer %T)", data) + return + } + keys := make([]string, 0) + pipe := this.Redis.RedisPipe(context.TODO()) + for _, k := range vof.MapKeys() { + value := vof.MapIndex(k) + tkey := k.Interface().(string) + valuedata := value.Interface() + pipe.HMSet(tkey, valuedata) + keys = append(keys, tkey) + } + pipe.RPushForStringSlice(key, keys...) + lcmd := pipe.Llen(key) + pipe.Exec() + if lcmd.Err() == nil { + if lcmd.Val() > uplimit*3 { //操作3倍上限移除多余数据 + off := uplimit - lcmd.Val() + if outkey, err = this.Redis.LRangeToStringSlice(key, 0, int(off-1)).Result(); err != nil { + return + } + pipe.Ltrim(key, int(off), -1) + for _, v := range outkey { + pipe.Delete(v) + } + _, err = pipe.Exec() + } + } + return +} + +//修改数据多个字段 uid 作为主键 +func (this *DBModel) Change(uid string, data map[string]interface{}, opt ...DBOption) (err error) { + if err = this.Redis.HMSet(this.ukey(uid), data); err != nil { + return + } + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.UpdateModelLogs(this.TableName, uid, bson.M{"uid": uid}, data) + } + if option.Expire > 0 { + this.Redis.Expire(this.ukey(uid), option.Expire) + } + return nil +} + +//修改数据多个字段 uid 作为主键 +func (this *DBModel) ChangeList(uid string, _id string, data map[string]interface{}, opt ...DBOption) (err error) { + if err = this.Redis.HMSet(this.ukeylist(uid, _id), data); err != nil { + return + } + + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.UpdateModelLogs(this.TableName, uid, bson.M{"_id": _id, "uid": uid}, data) + } + if option.Expire > 0 { + this.Redis.Expire(this.ukey(uid), option.Expire) + } + return nil +} + +//读取全部数据 +func (this *DBModel) Get(uid string, data interface{}, opt ...DBOption) (err error) { + if err = this.Redis.HGetAll(this.ukey(uid), data); err != nil && err != lgredis.RedisNil { + return + } + if err == lgredis.RedisNil { + if err = this.DB.FindOne(core.SqlTable(this.TableName), bson.M{"uid": uid}).Decode(data); err != nil { + return + } + err = this.Redis.HMSet(this.ukey(uid), data) + } + option := newDBOption(opt...) + if option.Expire > 0 { + this.Redis.Expire(this.ukey(uid), option.Expire) + } + return +} + +//获取列表数据 注意 data 必须是 切片的指针 *[]type +func (this *DBModel) GetList(uid string, data interface{}) (err error) { + var ( + dtype reflect2.Type + dkind reflect.Kind + sType reflect2.Type + sliceType *reflect2.UnsafeSliceType + sliceelemType reflect2.Type + decoder codecore.IDecoderMapJson + encoder codecore.IEncoderMapJson + dptr unsafe.Pointer + elemPtr unsafe.Pointer + n int + ok bool + keys map[string]string + tempdata map[string]string + result []*redis.StringStringMapCmd + 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, defconf).(codecore.IDecoderMapJson); !ok { + err = fmt.Errorf("MCompModel: GetList(data not support MarshalMapJson %T)", data) + return + } + sliceelemType = sliceelemType.(*reflect2.UnsafePtrType).Elem() + pipe := this.Redis.RedisPipe(context.TODO()) + if keys, err = this.Redis.HGetAllToMapString(this.ukey(uid)); err == nil { + result = make([]*redis.StringStringMapCmd, 0) + for _, v := range keys { + cmd := pipe.HGetAllToMapString(v) + result = append(result, cmd) + } + pipe.Exec() + for _, v := range result { + tempdata, err = v.Result() + sliceType.UnsafeGrow(dptr, n+1) + elemPtr = sliceType.UnsafeGetIndex(dptr, n) + if *((*unsafe.Pointer)(elemPtr)) == nil { + newPtr := sliceelemType.UnsafeNew() + if err = decoder.DecodeForMapJson(newPtr, json.GetReader([]byte{}), tempdata); err != nil { + log.Errorf("err:%v", err) + return + } + *((*unsafe.Pointer)(elemPtr)) = newPtr + } else { + decoder.DecodeForMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetReader([]byte{}), tempdata) + } + n++ + } + } + if err == lgredis.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, defconf).(codecore.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) + if err = c.Decode(elem); err != nil { + return + } + if tempdata, err = encoder.EncodeToMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetWriter()); err != nil { + return + } + key := this.ukeylist(uid, _id) + pipe.HMSetForMap(key, tempdata) + keys[_id] = key + n++ + } + if len(keys) > 0 { + pipe.HMSetForMap(this.ukey(uid), keys) + _, err = pipe.Exec() + } + } + } + + return err +} + +//获取队列数据 +func (this *DBModel) GetQueues(key string, count int, data interface{}) (err error) { + var ( + dtype reflect2.Type + dkind reflect.Kind + sType reflect2.Type + sliceType *reflect2.UnsafeSliceType + sliceelemType reflect2.Type + dptr unsafe.Pointer + elemPtr unsafe.Pointer + decoder codecore.IDecoderMapJson + ok bool + n int + keys = make([]string, 0) + result = make([]*redis.StringStringMapCmd, 0) + tempdata 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, defconf).(codecore.IDecoderMapJson); !ok { + err = fmt.Errorf("MCompModel: GetList(data not support MarshalMapJson %T)", data) + return + } + sliceelemType = sliceelemType.(*reflect2.UnsafePtrType).Elem() + + pipe := this.Redis.RedisPipe(context.TODO()) + if err = this.Redis.LRange(key, -1*count, -1, keys); err == nil { + result = make([]*redis.StringStringMapCmd, 0) + for _, v := range keys { + cmd := pipe.HGetAllToMapString(v) + result = append(result, cmd) + } + pipe.Exec() + for _, v := range result { + tempdata, err = v.Result() + sliceType.UnsafeGrow(dptr, n+1) + elemPtr = sliceType.UnsafeGetIndex(dptr, n) + if *((*unsafe.Pointer)(elemPtr)) == nil { + newPtr := sliceelemType.UnsafeNew() + if err = decoder.DecodeForMapJson(newPtr, json.GetReader([]byte{}), tempdata); err != nil { + log.Errorf("err:%v", err) + return + } + *((*unsafe.Pointer)(elemPtr)) = newPtr + } else { + decoder.DecodeForMapJson(*((*unsafe.Pointer)(elemPtr)), json.GetReader([]byte{}), tempdata) + } + n++ + } + } + return +} + +//读取单个数据中 多个字段数据 +func (this *DBModel) GetFields(uid string, data interface{}, fields ...string) (err error) { + this.Redis.HMGet(this.ukey(uid), data, fields...) + return +} + +//读取List列表中单个数据中 多个字段数据 +func (this *DBModel) GetListFields(uid string, id string, data interface{}, fields ...string) (err error) { + this.Redis.HMGet(this.ukeylist(uid, id), data, fields...) + return +} + +//读取列表数据中单个数据 +func (this *DBModel) GetListObj(uid string, id string, data interface{}) (err error) { + err = this.Redis.HGetAll(this.ukeylist(uid, id), data) + return +} + +//删除用户数据 +func (this *DBModel) Del(uid string, opt ...DBOption) (err error) { + err = this.Redis.Delete(this.ukey(uid)) + if err != nil { + return err + } + option := newDBOption(opt...) + if option.IsMgoLog { + err = this.DeleteModelLogs(this.TableName, uid, bson.M{"uid": uid}) + } + return nil +} + +//删除多条数据 +func (this *DBModel) DelListlds(uid string, ids ...string) (err error) { + listkey := this.ukey(uid) + pipe := this.Redis.RedisPipe(context.TODO()) + for _, v := range ids { + key := this.ukeylist(uid, v) + pipe.Delete(key) + } + pipe.HDel(listkey, ids...) + if _, err = pipe.Exec(); err == nil { + err = this.DeleteModelLogs(this.TableName, uid, bson.M{"_id": bson.M{"$in": ids}}) + } + return +} + +//批量删除数据 +func (this *DBModel) BatchDelLists(uid string) (err error) { + var keys map[string]string + pipe := this.Redis.RedisPipe(context.TODO()) + if keys, err = this.Redis.HGetAllToMapString(this.ukey(uid)); err == nil { + for _, v := range keys { + pipe.Delete(v) + } + pipe.Delete(this.ukey(uid)) + pipe.Exec() + } + return +} diff --git a/sys/db/init_test.go b/sys/db/init_test.go index 3a49c63e3..bbef68466 100644 --- a/sys/db/init_test.go +++ b/sys/db/init_test.go @@ -1 +1,3 @@ package db + + diff --git a/sys/db/options.go b/sys/db/options.go index 82e9b607b..6e4496cae 100644 --- a/sys/db/options.go +++ b/sys/db/options.go @@ -2,6 +2,7 @@ package db import ( "go_dreamfactory/lego/utils/mapstructure" + "time" ) //DB层配置 @@ -67,3 +68,34 @@ func newOptionsByOption(opts ...Option) (options *Options, err error) { } return } + +type DBOption func(*DBOptions) +type DBOptions struct { + IsMgoLog bool //是否写mgolog + Expire time.Duration //过期时间 +} + +//设置是否写mgor日志 +func SetDBMgoLog(v bool) DBOption { + return func(o *DBOptions) { + o.IsMgoLog = v + } +} + +//设置过期时间 +func SetDBExpire(v time.Duration) DBOption { + return func(o *DBOptions) { + o.Expire = v + } +} + +//更具 Option 序列化 系统参数对象 +func newDBOption(opts ...DBOption) DBOptions { + options := DBOptions{ + IsMgoLog: true, + } + for _, o := range opts { + o(&options) + } + return options +} diff --git a/sys/db/redislua.go b/sys/db/redislua.go new file mode 100644 index 000000000..85e9af758 --- /dev/null +++ b/sys/db/redislua.go @@ -0,0 +1,241 @@ +package db + +/* +Redis Lua 脚本备份 +*/ + +//Redis 自定义脚本 批量读取列表数据 +var LuaScriptgetList = ` +local key = tostring(KEYS[1]) +local keys = redis.call("HGETALL", key) +local data = {} +local n = 1 +for i, v in ipairs(keys) do + if i%2 == 0 then + data[n] = redis.call("HGETALL", v) + n = n+1 + end +end +return data +` + +//Redis 自定义脚本 批量写入列表数据 +var LuaScriptsetList = ` +local n = 1 +for i, v in ipairs(KEYS) do + local key = v + local argv = {} + for i=n,#ARGV,1 do + n = n+1 + if ARGV[i] == "#end" then + redis.call("HMSet", key,unpack(argv)) + break + else + table.insert(argv, ARGV[i]) + end + end +end +return "OK" +` + +//Redis 自定义脚本 批量卸载列表数据 +var LuaScriptdelList = ` +local key = tostring(KEYS[1]) +local keys = redis.call("HGETALL", key) +for i, v in ipairs(keys) do + if i%2 == 0 then + redis.call("DEL", v) + end +end +redis.call("DEL", key) +return "OK" +` + +//Redis 自定义脚本 批量读取队列数据 +var LuaScriptgetQueue = ` +local key = tostring(KEYS[1]) +local count = tonumber(ARGV[1]) * -1 +local keys = redis.call("LRANGE", key,count,-1) +local data = {} +for i, v in ipairs(keys) do + data[i] = redis.call("HGETALL", v) +end +return data +` + +//Redis 自定义脚本 批量写入队列数据 +var LuaScriptsetQueue = ` +local count = tonumber(ARGV[1]) +local k = tostring(ARGV[3]) +local keys = {} +local out = {} +local n = 1 +for i, v in ipairs(KEYS) do + if (i == 1) then + for i=n,#ARGV,1 do + n = n+1 + if ARGV[i] == "#end" then + break + end + end + elseif (i == 2) then + for i=n,#ARGV,1 do + n = n+1 + if ARGV[i] == "#end" then + break + end + end + else + local key = v + local argv = {} + table.insert(keys, key) + for i=n,#ARGV,1 do + n = n+1 + if ARGV[i] == "#end" then + redis.call("HMSet", key,unpack(argv)) + break + else + table.insert(argv, ARGV[i]) + end + end + end +end +redis.call("RPush", k,unpack(keys)) +local c = tonumber(redis.call("LLEN", k)) +count = count * 3 +if (c > count) then + local off = c-count + out = redis.call("LRANGE", k,0,off-1) + redis.call("LTRIM", k,off,-1) + for i, v in ipairs(out) do + redis.call("DEL", v) + end +end +return out +` + +/* + + + +//批量读取列表数据 +func (this *MCompModel) Batchgetlists(key string) (result []map[string]string, err error) { + var data interface{} + ret := this.Redis.EvalSha(this.Redis.Context(), this.getListSha1, []string{key}) + if data, err = ret.Result(); err != nil { + fmt.Printf("Execute batchgetlists err: %v", err.Error()) + } else { + temp1 := data.([]interface{}) + result = make([]map[string]string, len(temp1)) + for i, v := range temp1 { + temp2 := v.([]interface{}) + result[i] = make(map[string]string) + for n := 0; n < len(temp2); n += 2 { + result[i][temp2[n].(string)] = temp2[n+1].(string) + } + } + if len(result) == 0 { + err = redis.RedisNil + return + } + } + return +} + +//批量写入数据 +func (this *MCompModel) Batchsetlists(data map[string]map[string]string) (err error) { + var ( + n int + keys []string + values []interface{} + ) + keys = make([]string, len(data)) + values = make([]interface{}, 0) + + for k, v := range data { + keys[n] = k + for k1, v1 := range v { + values = append(values, k1, v1) + } + values = append(values, "#end") + n++ + } + ret := this.Redis.EvalSha(this.Redis.Context(), this.setListSha1, keys, values...) + if _, err := ret.Result(); err != nil { + fmt.Printf("Execute batchsetlists err: %v", err.Error()) + } + return +} + +//批量读取队列数据 +func (this *MCompModel) Batchgetqueues(key string, count int32) (result []map[string]string, err error) { + var data interface{} + ret := this.Redis.EvalSha(this.Redis.Context(), this.getQueueSha1, []string{key}, count) + if data, err = ret.Result(); err != nil { + fmt.Printf("Execute batchgetqueues err: %v", err.Error()) + } else { + temp1 := data.([]interface{}) + result = make([]map[string]string, len(temp1)) + for i, v := range temp1 { + temp2 := v.([]interface{}) + result[i] = make(map[string]string) + for n := 0; n < len(temp2); n += 2 { + result[i][temp2[n].(string)] = temp2[n+1].(string) + } + } + if len(result) == 0 { + err = redis.RedisNil + return + } + } + return +} + +//批量写入队列 并返回移除队列 +func (this *MCompModel) Batchsetqueues(key string, count int32, ks []string, vs []map[string]string) (outkey []string, err error) { + var ( + n int + keys []string + values []interface{} + result interface{} + ) + keys = make([]string, len(ks)+2) + values = make([]interface{}, 0) + keys[0] = "count" + values = append(values, count) + values = append(values, "#end") + keys[1] = "key" + values = append(values, key) + values = append(values, "#end") + n = 2 + for i, v := range ks { + keys[n] = v + for k1, v1 := range vs[i] { + values = append(values, k1, v1) + } + values = append(values, "#end") + n++ + } + ret := this.Redis.EvalSha(this.Redis.Context(), this.setQueueSha1, keys, values...) + if result, err = ret.Result(); err != nil { + fmt.Printf("Execute batchsetqueues err: %v", err.Error()) + } else { + outkey = make([]string, len(result.([]interface{}))) + for i, v := range result.([]interface{}) { + outkey[i] = v.(string) + } + } + return +} + +//批量删除数据 +func (this *MCompModel) BatchDelLists(uid string) (err error) { + ret := this.Redis.EvalSha(this.Redis.Context(), this.dellListSha1, []string{this.ukey(uid)}) + if _, err := ret.Result(); err != nil { + fmt.Printf("Execute batchsetlists err: %v", err.Error()) + } + return +} + + +*/