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  }