182 lines
4.9 KiB
Go
182 lines
4.9 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
"github.com/rwadurian/mpc-system/services/account/application/ports"
|
|
)
|
|
|
|
// CacheAdapter implements CacheService using Redis
|
|
type CacheAdapter struct {
|
|
client *redis.Client
|
|
}
|
|
|
|
// NewCacheAdapter creates a new CacheAdapter
|
|
func NewCacheAdapter(client *redis.Client) ports.CacheService {
|
|
return &CacheAdapter{client: client}
|
|
}
|
|
|
|
// Set sets a value in the cache
|
|
func (c *CacheAdapter) Set(ctx context.Context, key string, value interface{}, ttlSeconds int) error {
|
|
data, err := json.Marshal(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.client.Set(ctx, key, data, time.Duration(ttlSeconds)*time.Second).Err()
|
|
}
|
|
|
|
// Get gets a value from the cache
|
|
func (c *CacheAdapter) Get(ctx context.Context, key string) (interface{}, error) {
|
|
data, err := c.client.Get(ctx, key).Bytes()
|
|
if err != nil {
|
|
if err == redis.Nil {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var value interface{}
|
|
if err := json.Unmarshal(data, &value); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
// Delete deletes a value from the cache
|
|
func (c *CacheAdapter) Delete(ctx context.Context, key string) error {
|
|
return c.client.Del(ctx, key).Err()
|
|
}
|
|
|
|
// Exists checks if a key exists in the cache
|
|
func (c *CacheAdapter) Exists(ctx context.Context, key string) (bool, error) {
|
|
result, err := c.client.Exists(ctx, key).Result()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return result > 0, nil
|
|
}
|
|
|
|
// AccountCacheAdapter provides account-specific caching
|
|
type AccountCacheAdapter struct {
|
|
client *redis.Client
|
|
keyPrefix string
|
|
}
|
|
|
|
// NewAccountCacheAdapter creates a new AccountCacheAdapter
|
|
func NewAccountCacheAdapter(client *redis.Client) *AccountCacheAdapter {
|
|
return &AccountCacheAdapter{
|
|
client: client,
|
|
keyPrefix: "account:",
|
|
}
|
|
}
|
|
|
|
// CacheAccount caches an account
|
|
func (c *AccountCacheAdapter) CacheAccount(ctx context.Context, accountID string, data interface{}, ttl time.Duration) error {
|
|
key := c.keyPrefix + accountID
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.client.Set(ctx, key, jsonData, ttl).Err()
|
|
}
|
|
|
|
// GetCachedAccount gets a cached account
|
|
func (c *AccountCacheAdapter) GetCachedAccount(ctx context.Context, accountID string) (map[string]interface{}, error) {
|
|
key := c.keyPrefix + accountID
|
|
data, err := c.client.Get(ctx, key).Bytes()
|
|
if err != nil {
|
|
if err == redis.Nil {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// InvalidateAccount invalidates cached account data
|
|
func (c *AccountCacheAdapter) InvalidateAccount(ctx context.Context, accountID string) error {
|
|
key := c.keyPrefix + accountID
|
|
return c.client.Del(ctx, key).Err()
|
|
}
|
|
|
|
// CacheLoginChallenge caches a login challenge
|
|
func (c *AccountCacheAdapter) CacheLoginChallenge(ctx context.Context, challengeID string, data map[string]interface{}) error {
|
|
key := "login_challenge:" + challengeID
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.client.Set(ctx, key, jsonData, 5*time.Minute).Err()
|
|
}
|
|
|
|
// GetLoginChallenge gets a login challenge
|
|
func (c *AccountCacheAdapter) GetLoginChallenge(ctx context.Context, challengeID string) (map[string]interface{}, error) {
|
|
key := "login_challenge:" + challengeID
|
|
data, err := c.client.Get(ctx, key).Bytes()
|
|
if err != nil {
|
|
if err == redis.Nil {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// DeleteLoginChallenge deletes a login challenge after use
|
|
func (c *AccountCacheAdapter) DeleteLoginChallenge(ctx context.Context, challengeID string) error {
|
|
key := "login_challenge:" + challengeID
|
|
return c.client.Del(ctx, key).Err()
|
|
}
|
|
|
|
// IncrementLoginAttempts increments failed login attempts
|
|
func (c *AccountCacheAdapter) IncrementLoginAttempts(ctx context.Context, username string) (int64, error) {
|
|
key := "login_attempts:" + username
|
|
count, err := c.client.Incr(ctx, key).Result()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Set expiry on first attempt
|
|
if count == 1 {
|
|
c.client.Expire(ctx, key, 15*time.Minute)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// GetLoginAttempts gets the current login attempt count
|
|
func (c *AccountCacheAdapter) GetLoginAttempts(ctx context.Context, username string) (int64, error) {
|
|
key := "login_attempts:" + username
|
|
count, err := c.client.Get(ctx, key).Int64()
|
|
if err != nil {
|
|
if err == redis.Nil {
|
|
return 0, nil
|
|
}
|
|
return 0, err
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
// ResetLoginAttempts resets login attempts after successful login
|
|
func (c *AccountCacheAdapter) ResetLoginAttempts(ctx context.Context, username string) error {
|
|
key := "login_attempts:" + username
|
|
return c.client.Del(ctx, key).Err()
|
|
}
|