github.com/gogf/gf@v1.16.9/os/gsession/gsession_storage_redis_hashtable.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gsession 8 9 import ( 10 "context" 11 "time" 12 13 "github.com/gogf/gf/container/gmap" 14 "github.com/gogf/gf/database/gredis" 15 "github.com/gogf/gf/internal/intlog" 16 "github.com/gogf/gf/util/gconv" 17 ) 18 19 // StorageRedisHashTable implements the Session Storage interface with redis hash table. 20 type StorageRedisHashTable struct { 21 redis *gredis.Redis // Redis client for session storage. 22 prefix string // Redis key prefix for session id. 23 } 24 25 // NewStorageRedisHashTable creates and returns a redis hash table storage object for session. 26 func NewStorageRedisHashTable(redis *gredis.Redis, prefix ...string) *StorageRedisHashTable { 27 if redis == nil { 28 panic("redis instance for storage cannot be empty") 29 return nil 30 } 31 s := &StorageRedisHashTable{ 32 redis: redis, 33 } 34 if len(prefix) > 0 && prefix[0] != "" { 35 s.prefix = prefix[0] 36 } 37 return s 38 } 39 40 // New creates a session id. 41 // This function can be used for custom session creation. 42 func (s *StorageRedisHashTable) New(ctx context.Context, ttl time.Duration) (id string, err error) { 43 return "", ErrorDisabled 44 } 45 46 // Get retrieves session value with given key. 47 // It returns nil if the key does not exist in the session. 48 func (s *StorageRedisHashTable) Get(ctx context.Context, id string, key string) (value interface{}, err error) { 49 value, err = s.redis.Ctx(ctx).Do("HGET", s.key(id), key) 50 if value != nil { 51 value = gconv.String(value) 52 } 53 return 54 } 55 56 // GetMap retrieves all key-value pairs as map from storage. 57 func (s *StorageRedisHashTable) GetMap(ctx context.Context, id string) (data map[string]interface{}, err error) { 58 r, err := s.redis.Ctx(ctx).DoVar("HGETALL", s.key(id)) 59 if err != nil { 60 return nil, err 61 } 62 data = make(map[string]interface{}) 63 array := r.Interfaces() 64 for i := 0; i < len(array); i += 2 { 65 if array[i+1] != nil { 66 data[gconv.String(array[i])] = gconv.String(array[i+1]) 67 } else { 68 data[gconv.String(array[i])] = array[i+1] 69 } 70 } 71 return data, nil 72 } 73 74 // GetSize retrieves the size of key-value pairs from storage. 75 func (s *StorageRedisHashTable) GetSize(ctx context.Context, id string) (size int, err error) { 76 r, err := s.redis.Ctx(ctx).DoVar("HLEN", s.key(id)) 77 if err != nil { 78 return -1, err 79 } 80 return r.Int(), nil 81 } 82 83 // Set sets key-value session pair to the storage. 84 // The parameter `ttl` specifies the TTL for the session id (not for the key-value pair). 85 func (s *StorageRedisHashTable) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error { 86 _, err := s.redis.Ctx(ctx).Do("HSET", s.key(id), key, value) 87 return err 88 } 89 90 // SetMap batch sets key-value session pairs with map to the storage. 91 // The parameter `ttl` specifies the TTL for the session id(not for the key-value pair). 92 func (s *StorageRedisHashTable) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error { 93 array := make([]interface{}, len(data)*2+1) 94 array[0] = s.key(id) 95 96 index := 1 97 for k, v := range data { 98 array[index] = k 99 array[index+1] = v 100 index += 2 101 } 102 _, err := s.redis.Ctx(ctx).Do("HMSET", array...) 103 return err 104 } 105 106 // Remove deletes key with its value from storage. 107 func (s *StorageRedisHashTable) Remove(ctx context.Context, id string, key string) error { 108 _, err := s.redis.Ctx(ctx).Do("HDEL", s.key(id), key) 109 return err 110 } 111 112 // RemoveAll deletes all key-value pairs from storage. 113 func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, id string) error { 114 _, err := s.redis.Ctx(ctx).Do("DEL", s.key(id)) 115 return err 116 } 117 118 // GetSession returns the session data as *gmap.StrAnyMap for given session id from storage. 119 // 120 // The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded. 121 // The parameter `data` is the current old session data stored in memory, 122 // and for some storage it might be nil if memory storage is disabled. 123 // 124 // This function is called ever when session starts. 125 func (s *StorageRedisHashTable) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { 126 intlog.Printf(ctx, "StorageRedisHashTable.GetSession: %s, %v", id, ttl) 127 r, err := s.redis.Ctx(ctx).DoVar("EXISTS", s.key(id)) 128 if err != nil { 129 return nil, err 130 } 131 if r.Bool() { 132 return gmap.NewStrAnyMap(true), nil 133 } 134 return nil, nil 135 } 136 137 // SetSession updates the data map for specified session id. 138 // This function is called ever after session, which is changed dirty, is closed. 139 // This copy all session data map from memory to storage. 140 func (s *StorageRedisHashTable) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error { 141 intlog.Printf(ctx, "StorageRedisHashTable.SetSession: %s, %v", id, ttl) 142 _, err := s.redis.Ctx(ctx).Do("EXPIRE", s.key(id), int64(ttl.Seconds())) 143 return err 144 } 145 146 // UpdateTTL updates the TTL for specified session id. 147 // This function is called ever after session, which is not dirty, is closed. 148 // It just adds the session id to the async handling queue. 149 func (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error { 150 intlog.Printf(ctx, "StorageRedisHashTable.UpdateTTL: %s, %v", id, ttl) 151 _, err := s.redis.Do("EXPIRE", s.key(id), int64(ttl.Seconds())) 152 return err 153 } 154 155 func (s *StorageRedisHashTable) key(id string) string { 156 return s.prefix + id 157 }