github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf. 6 7 package gsession 8 9 import ( 10 "context" 11 "time" 12 13 "github.com/wangyougui/gf/v2/container/gmap" 14 "github.com/wangyougui/gf/v2/database/gredis" 15 "github.com/wangyougui/gf/v2/internal/intlog" 16 ) 17 18 // StorageRedisHashTable implements the Session Storage interface with redis hash table. 19 type StorageRedisHashTable struct { 20 StorageBase 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 // Get retrieves session value with given key. 41 // It returns nil if the key does not exist in the session. 42 func (s *StorageRedisHashTable) Get(ctx context.Context, sessionId string, key string) (value interface{}, err error) { 43 v, err := s.redis.HGet(ctx, s.sessionIdToRedisKey(sessionId), key) 44 if err != nil { 45 return nil, err 46 } 47 if v.IsNil() { 48 return nil, nil 49 } 50 return v.String(), nil 51 } 52 53 // Data retrieves all key-value pairs as map from storage. 54 func (s *StorageRedisHashTable) Data(ctx context.Context, sessionId string) (data map[string]interface{}, err error) { 55 m, err := s.redis.HGetAll(ctx, s.sessionIdToRedisKey(sessionId)) 56 if err != nil { 57 return nil, err 58 } 59 return m.Map(), nil 60 } 61 62 // GetSize retrieves the size of key-value pairs from storage. 63 func (s *StorageRedisHashTable) GetSize(ctx context.Context, sessionId string) (size int, err error) { 64 v, err := s.redis.HLen(ctx, s.sessionIdToRedisKey(sessionId)) 65 return int(v), err 66 } 67 68 // Set sets key-value session pair to the storage. 69 // The parameter `ttl` specifies the TTL for the session id (not for the key-value pair). 70 func (s *StorageRedisHashTable) Set(ctx context.Context, sessionId string, key string, value interface{}, ttl time.Duration) error { 71 _, err := s.redis.HSet(ctx, s.sessionIdToRedisKey(sessionId), map[string]interface{}{ 72 key: value, 73 }) 74 return err 75 } 76 77 // SetMap batch sets key-value session pairs with map to the storage. 78 // The parameter `ttl` specifies the TTL for the session id(not for the key-value pair). 79 func (s *StorageRedisHashTable) SetMap(ctx context.Context, sessionId string, data map[string]interface{}, ttl time.Duration) error { 80 err := s.redis.HMSet(ctx, s.sessionIdToRedisKey(sessionId), data) 81 return err 82 } 83 84 // Remove deletes key with its value from storage. 85 func (s *StorageRedisHashTable) Remove(ctx context.Context, sessionId string, key string) error { 86 _, err := s.redis.HDel(ctx, s.sessionIdToRedisKey(sessionId), key) 87 return err 88 } 89 90 // RemoveAll deletes all key-value pairs from storage. 91 func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, sessionId string) error { 92 _, err := s.redis.Del(ctx, s.sessionIdToRedisKey(sessionId)) 93 return err 94 } 95 96 // GetSession returns the session data as *gmap.StrAnyMap for given session id from storage. 97 // 98 // The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded. 99 // The parameter `data` is the current old session data stored in memory, 100 // and for some storage it might be nil if memory storage is disabled. 101 // 102 // This function is called ever when session starts. 103 func (s *StorageRedisHashTable) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) { 104 intlog.Printf(ctx, "StorageRedisHashTable.GetSession: %s, %v", sessionId, ttl) 105 v, err := s.redis.Exists(ctx, s.sessionIdToRedisKey(sessionId)) 106 if err != nil { 107 return nil, err 108 } 109 if v > 0 { 110 // It does not store the session data in memory, it so returns an empty map. 111 // It retrieves session data items directly through redis server each time. 112 return gmap.NewStrAnyMap(true), nil 113 } 114 return nil, nil 115 } 116 117 // SetSession updates the data map for specified session id. 118 // This function is called ever after session, which is changed dirty, is closed. 119 // This copy all session data map from memory to storage. 120 func (s *StorageRedisHashTable) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error { 121 intlog.Printf(ctx, "StorageRedisHashTable.SetSession: %s, %v", sessionId, ttl) 122 _, err := s.redis.Expire(ctx, s.sessionIdToRedisKey(sessionId), int64(ttl.Seconds())) 123 return err 124 } 125 126 // UpdateTTL updates the TTL for specified session id. 127 // This function is called ever after session, which is not dirty, is closed. 128 // It just adds the session id to the async handling queue. 129 func (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error { 130 intlog.Printf(ctx, "StorageRedisHashTable.UpdateTTL: %s, %v", sessionId, ttl) 131 _, err := s.redis.Expire(ctx, s.sessionIdToRedisKey(sessionId), int64(ttl.Seconds())) 132 return err 133 } 134 135 // sessionIdToRedisKey converts and returns the redis key for given session id. 136 func (s *StorageRedisHashTable) sessionIdToRedisKey(sessionId string) string { 137 return s.prefix + sessionId 138 }