@ -10,6 +10,7 @@ import (
"context"
"encoding/json"
"fmt"
"sync"
"time"
"github.com/redis/go-redis/v9"
@ -17,168 +18,248 @@ import (
)
var (
Client * redis . Client
Ctx = context . Background ( )
)
// Init 初始化Redis连接
func Init ( ) error {
if cfg . Global . Redis . Addr == "" || cfg . Global . Redis . Addr == "memory" {
return nil
}
Ctx = context . Background ( )
Client = redis . NewClient ( & redis . Options {
Addr : cfg . Global . Redis . Addr ,
Password : cfg . Global . Redis . Password ,
DB : cfg . Global . Redis . DB ,
} )
if err := Client . Ping ( Ctx ) . Err ( ) ; err != nil {
return fmt . Errorf ( "failed to connect redis: %w" , err )
}
// Memory store fallback
memStore sync . Map
)
return nil
type memItem struct {
Value [ ] byte
Expiration int64
}
// IsEnabled 是否启用 缓存
// IsEnabled 是否启用 Redis 缓存
func IsEnabled ( ) bool {
return cfg . Global . Redis . Addr != "" && cfg . Global . Redis . Addr != "memory" && Client != nil
if cfg . Global . Redis . Addr == "" || cfg . Global . Redis . Addr == "memory" {
return false
}
return cfg . Redis ( ) != nil
}
// Get 获取字符串值
func Get ( key string ) ( string , error ) {
if ! IsEnabled ( ) {
return "" , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . Get ( Ctx , key ) . Result ( )
}
return Client . Get ( Ctx , key ) . Result ( )
// Memory fallback
val , ok := memStore . Load ( key )
if ! ok {
return "" , redis . Nil
}
item := val . ( memItem )
if item . Expiration > 0 && time . Now ( ) . UnixNano ( ) > item . Expiration {
memStore . Delete ( key )
return "" , redis . Nil
}
return string ( item . Value ) , nil
}
// GetObject 获取并反序列化对象
func GetObject ( key string , dest interface { } ) error {
if ! IsEnabled ( ) {
return fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
data , err := cfg . Redis ( ) . Get ( Ctx , key ) . Bytes ( )
if err != nil {
return err
}
return json . Unmarshal ( data , dest )
}
data , err := Client . Get ( Ctx , key ) . Bytes ( )
if err != nil {
return err
// Memory fallback
val , ok := memStore . Load ( key )
if ! ok {
return redis . Nil
}
return json . Unmarshal ( data , dest )
item := val . ( memItem )
if item . Expiration > 0 && time . Now ( ) . UnixNano ( ) > item . Expiration {
memStore . Delete ( key )
return redis . Nil
}
return json . Unmarshal ( item . Value , dest )
}
// Set 设置字符串值
func Set ( key string , value string , expiration time . Duration ) error {
if ! IsEnabled ( ) {
return nil
if IsEnabled ( ) {
return cfg . Redis ( ) . Set ( Ctx , key , value , expiration ) . Err ( )
}
// Memory fallback
exp := int64 ( 0 )
if expiration > 0 {
exp = time . Now ( ) . Add ( expiration ) . UnixNano ( )
}
return Client . Set ( Ctx , key , value , expiration ) . Err ( )
memStore . Store ( key , memItem {
Value : [ ] byte ( value ) ,
Expiration : exp ,
} )
return nil
}
// SetObject 序列化并设置对象
func SetObject ( key string , value interface { } , expiration time . Duration ) error {
if ! IsEnabled ( ) {
return nil
}
data , err := json . Marshal ( value )
if err != nil {
return err
}
return Client . Set ( Ctx , key , data , expiration ) . Err ( )
if IsEnabled ( ) {
return cfg . Redis ( ) . Set ( Ctx , key , data , expiration ) . Err ( )
}
// Memory fallback
exp := int64 ( 0 )
if expiration > 0 {
exp = time . Now ( ) . Add ( expiration ) . UnixNano ( )
}
memStore . Store ( key , memItem {
Value : data ,
Expiration : exp ,
} )
return nil
}
// Delete 删除key
func Delete ( keys ... string ) error {
if ! IsEnabled ( ) {
return nil
if IsEnabled ( ) {
return cfg . Redis ( ) . Del ( Ctx , keys ... ) . Err ( )
}
return Client . Del ( Ctx , keys ... ) . Err ( )
// Memory fallback
for _ , key := range keys {
memStore . Delete ( key )
}
return nil
}
// Exists 检查key是否存在
func Exists ( keys ... string ) ( int64 , error ) {
if ! IsEnabled ( ) {
return 0 , nil
if IsEnabled ( ) {
return cfg . Redis ( ) . Exists ( Ctx , keys ... ) . Result ( )
}
// Memory fallback
count := int64 ( 0 )
for _ , key := range keys {
if val , ok := memStore . Load ( key ) ; ok {
item := val . ( memItem )
if item . Expiration == 0 || time . Now ( ) . UnixNano ( ) <= item . Expiration {
count ++
} else {
memStore . Delete ( key )
}
}
}
return Client . Exists ( Ctx , keys ... ) . Result ( )
return count, nil
}
// Expire 设置过期时间
func Expire ( key string , expiration time . Duration ) error {
if ! IsEnabled ( ) {
if IsEnabled ( ) {
return cfg . Redis ( ) . Expire ( Ctx , key , expiration ) . Err ( )
}
// Memory fallback
if val , ok := memStore . Load ( key ) ; ok {
item := val . ( memItem )
item . Expiration = time . Now ( ) . Add ( expiration ) . UnixNano ( )
memStore . Store ( key , item )
return nil
}
return Client . Expire ( Ctx , key , expiration ) . Err ( )
return nil // Key not found, ignore
}
// TTL 获取剩余过期时间
func TTL ( key string ) ( time . Duration , error ) {
if ! IsEnabled ( ) {
return 0 , nil
if IsEnabled ( ) {
return cfg . Redis ( ) . TTL ( Ctx , key ) . Result ( )
}
return Client . TTL ( Ctx , key ) . Result ( )
// Memory fallback
if val , ok := memStore . Load ( key ) ; ok {
item := val . ( memItem )
if item . Expiration == 0 {
return - 1 , nil // No expiration
}
ttl := time . Duration ( item . Expiration - time . Now ( ) . UnixNano ( ) )
if ttl <= 0 {
memStore . Delete ( key )
return - 2 , nil // Expired
}
return ttl , nil
}
return - 2 , nil // Not found
}
// Incr 自增
func Incr ( key string ) ( int64 , error ) {
if ! IsEnabled ( ) {
return 0 , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . Incr ( Ctx , key ) . Result ( )
}
return Client . Incr ( Ctx , key ) . Result ( )
// Memory fallback not implemented for counters
return 0 , fmt . Errorf ( "memory cache: incr not implemented" )
}
// IncrBy 增加指定值
func IncrBy ( key string , value int64 ) ( int64 , error ) {
if ! IsEnabled ( ) {
return 0 , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . IncrBy ( Ctx , key , value ) . Result ( )
}
return Client . IncrBy ( Ctx , key , value ) . Result ( )
return 0 , fmt . Errorf ( "memory cache: incrby not implemented" )
}
// Decr 自减
func Decr ( key string ) ( int64 , error ) {
if ! IsEnabled ( ) {
return 0 , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . Decr ( Ctx , key ) . Result ( )
}
return Client . Decr ( Ctx , key ) . Result ( )
return 0 , fmt . Errorf ( "memory cache: decr not implemented" )
}
// HSet 设置hash字段
func HSet ( key string , values ... interface { } ) error {
if ! IsEnabled ( ) {
return nil
if IsEnabled ( ) {
return cfg . Redis ( ) . HSet ( Ctx , key , values ... ) . Err ( )
}
return Client. HSet ( Ctx , key , values ... ) . Err ( )
return fmt. Errorf ( "memory cache: hset not implemented" )
}
// HGet 获取hash字段
func HGet ( key , field string ) ( string , error ) {
if ! IsEnabled ( ) {
return "" , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . HGet ( Ctx , key , field ) . Result ( )
}
return Client . HGet ( Ctx , key , field ) . Result ( )
return "" , fmt . Errorf ( "memory cache: hget not implemented" )
}
// HGetAll 获取hash所有字段
func HGetAll ( key string ) ( map [ string ] string , error ) {
if ! IsEnabled ( ) {
return nil , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . HGetAll ( Ctx , key ) . Result ( )
}
return Client . HGetAll ( Ctx , key ) . Result ( )
return nil , fmt . Errorf ( "memory cache: hgetall not implemented" )
}
// HDel 删除hash字段
func HDel ( key string , fields ... string ) error {
if ! IsEnabled ( ) {
return nil
if IsEnabled ( ) {
return cfg . Redis ( ) . HDel ( Ctx , key , fields ... ) . Err ( )
}
return Client. HDel ( Ctx , key , fields ... ) . Err ( )
return fmt. Errorf ( "memory cache: hdel not implemented" )
}
// SetNX 仅当key不存在时才设置( 用于分布式锁)
func SetNX ( key string , value interface { } , expiration time . Duration ) ( bool , error ) {
if ! IsEnabled ( ) {
return false , fmt . Errorf ( "redis not enabled" )
if IsEnabled ( ) {
return cfg . Redis ( ) . SetNX ( Ctx , key , value , expiration ) . Result ( )
}
// Simple memory implementation
if _ , ok := memStore . Load ( key ) ; ok {
return false , nil
}
return Client . SetNX ( Ctx , key , value , expiration ) . Result ( )
SetObject ( key , value , expiration )
return true , nil
}
// ==================== 用户缓存 ====================
@ -224,6 +305,12 @@ func RateLimitKey(identifier, path string) string {
// IncrRateLimit 增加限流计数
func IncrRateLimit ( identifier , path string , window time . Duration ) ( int64 , error ) {
key := RateLimitKey ( identifier , path )
// For memory cache, we need a special implementation or just skip rate limiting
if ! IsEnabled ( ) {
// Simple bypass for memory mode
return 1 , nil
}
count , err := Incr ( key )
if err != nil {
return 0 , err