This commit is contained in:
2025-09-28 20:19:45 +03:00
parent 6638ef1b5f
commit 3fd63d5f32
21 changed files with 356 additions and 355 deletions

View File

@@ -1,132 +1,126 @@
package redis
import (
"bytes"
"compress/flate"
"compress/zlib"
"context"
"fmt"
"io"
"os"
"time"
"sipro-mps/internal/config"
"github.com/golang/protobuf/proto"
"github.com/redis/rueidis"
"go.uber.org/fx"
)
var Client *rueidis.Client
func InitClient(ctx context.Context) error {
func NewRedisClient(lc fx.Lifecycle, config config.Config) (rueidis.Client, error) {
var err error
host := os.Getenv("REDIS_HOST")
//host := "redis"
port := os.Getenv("REDIS_PORT")
password := os.Getenv("REDIS_PASSWORD")
host := config.Redis.Host
port := config.Redis.Port
password := config.Redis.Password
client, err := rueidis.NewClient(rueidis.ClientOption{
InitAddress: []string{host + ":" + port},
Password: password,
})
if err != nil {
return err
return nil, err
}
err = client.Do(ctx, client.B().Ping().Build()).Error()
if err != nil {
return err
}
Client = &client
return nil
lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
return client.Do(ctx, client.B().Ping().Build()).Error()
},
OnStop: func(ctx context.Context) error {
client.Close()
return nil
},
})
return client, nil
}
func CloseClient() {
if Client != nil {
(*Client).Close()
}
}
// WriteProtoMessage compresses and writes a protobuf message to Redis
func WriteProtoMessage(ctx context.Context, key string, message proto.Message, ttl ...time.Duration) error {
if Client == nil {
return fmt.Errorf("redis client not initialized")
}
if message == nil {
return fmt.Errorf("message is nil")
}
// Marshal protobuf message
bytesMessage, err := proto.Marshal(message)
if err != nil {
return fmt.Errorf("failed to marshal proto message: %w", err)
}
// Compress with zlib
var buf bytes.Buffer
w, err := zlib.NewWriterLevel(&buf, flate.BestCompression)
if err != nil {
return fmt.Errorf("failed to create zlib writer: %w", err)
}
defer w.Close() // гарантированное закрытие
if _, err := w.Write(bytesMessage); err != nil {
return fmt.Errorf("failed to write to zlib writer: %w", err)
}
if err := w.Close(); err != nil { // финализируем сжатие
return fmt.Errorf("failed to close zlib writer: %w", err)
}
var ttlDuration time.Duration
if len(ttl) > 0 {
ttlDuration = ttl[0]
} else {
ttlDuration = 3 * time.Hour // Default TTL of 24 hours
}
// Write to Redis
if err := (*Client).Do(ctx, (*Client).B().
Set().
Key(key).
Value(rueidis.BinaryString(buf.Bytes())).
Ex(ttlDuration).
Build()).
Error(); err != nil {
return fmt.Errorf("failed to write compressed data to Redis: %w", err)
}
return nil
}
// ReadProtoMessage reads and decompresses a protobuf message from Redis
func ReadProtoMessage(ctx context.Context, key string, message proto.Message) error {
if Client == nil {
return fmt.Errorf("redis client not initialized")
}
if message == nil {
return fmt.Errorf("message is nil")
}
// Get bytes from Redis
resp, err := (*Client).Do(ctx, (*Client).B().Get().Key(key).Build()).AsBytes()
if err != nil {
return fmt.Errorf("failed to read data from Redis: %w", err)
}
if resp == nil {
return fmt.Errorf("no data found for key: %s", key)
}
// Decompress
reader, err := zlib.NewReader(bytes.NewReader(resp))
if err != nil {
return fmt.Errorf("failed to create zlib reader: %w", err)
}
defer reader.Close()
decompressed, err := io.ReadAll(reader)
if err != nil {
return fmt.Errorf("failed to decompress data: %w", err)
}
// Unmarshal protobuf
if err := proto.Unmarshal(decompressed, message); err != nil {
return fmt.Errorf("failed to unmarshal proto message: %w", err)
}
return nil
}
//func CloseClient() {
// if Client != nil {
// (*Client).Close()
// }
//}
//
//// WriteProtoMessage compresses and writes a protobuf message to Redis
//func WriteProtoMessage(ctx context.Context, key string, message proto.Message, ttl ...time.Duration) error {
// if Client == nil {
// return fmt.Errorf("redis client not initialized")
// }
// if message == nil {
// return fmt.Errorf("message is nil")
// }
//
// // Marshal protobuf message
// bytesMessage, err := proto.Marshal(message)
// if err != nil {
// return fmt.Errorf("failed to marshal proto message: %w", err)
// }
//
// // Compress with zlib
// var buf bytes.Buffer
// w, err := zlib.NewWriterLevel(&buf, flate.BestCompression)
// if err != nil {
// return fmt.Errorf("failed to create zlib writer: %w", err)
// }
// defer w.Close() // гарантированное закрытие
//
// if _, err := w.Write(bytesMessage); err != nil {
// return fmt.Errorf("failed to write to zlib writer: %w", err)
// }
// if err := w.Close(); err != nil { // финализируем сжатие
// return fmt.Errorf("failed to close zlib writer: %w", err)
// }
//
// //var ttlDuration time.Duration
// //if len(ttl) > 0 {
// // ttlDuration = ttl[0]
// //} else {
// // ttlDuration = 3 * time.Hour // Default TTL of 24 hours
// //}
// // Write to Redis
// if err := (*Client).Do(ctx, (*Client).B().
// Set().
// Key(key).
// Value(rueidis.BinaryString(buf.Bytes())).
// Build()).
// Error(); err != nil {
// return fmt.Errorf("failed to write compressed data to Redis: %w", err)
// }
// return nil
//}
//
//// ReadProtoMessage reads and decompresses a protobuf message from Redis
//func ReadProtoMessage(ctx context.Context, key string, message proto.Message) error {
// if Client == nil {
// return fmt.Errorf("redis client not initialized")
// }
// if message == nil {
// return fmt.Errorf("message is nil")
// }
//
// // Get bytes from Redis
// resp, err := (*Client).Do(ctx, (*Client).B().Get().Key(key).Build()).AsBytes()
// if err != nil {
// return fmt.Errorf("failed to read data from Redis: %w", err)
// }
// if resp == nil {
// return fmt.Errorf("no data found for key: %s", key)
// }
//
// // Decompress
// reader, err := zlib.NewReader(bytes.NewReader(resp))
// if err != nil {
// return fmt.Errorf("failed to create zlib reader: %w", err)
// }
// defer reader.Close()
//
// decompressed, err := io.ReadAll(reader)
// if err != nil {
// return fmt.Errorf("failed to decompress data: %w", err)
// }
//
// // Unmarshal protobuf
// if err := proto.Unmarshal(decompressed, message); err != nil {
// return fmt.Errorf("failed to unmarshal proto message: %w", err)
// }
//
// return nil
//}

8
internal/redis/fx.go Normal file
View File

@@ -0,0 +1,8 @@
package redis
import "go.uber.org/fx"
var Module = fx.Options(
fx.Provide(NewRedisClient),
fx.Provide(NewRedisLocker),
)

View File

@@ -1,30 +1,29 @@
package redis
import (
"context"
"os"
"github.com/redis/rueidis"
"github.com/redis/rueidis/rueidislock"
"go.uber.org/fx"
)
var Locker *rueidislock.Locker
func InitLocker() error {
func NewRedisLocker(lc fx.Lifecycle) (rueidislock.Locker, error) {
redisAddr := os.Getenv("REDIS_ADDR")
password := os.Getenv("REDIS_PASSWORD")
locker, err := rueidislock.NewLocker(rueidislock.LockerOption{
ClientOption: rueidis.ClientOption{InitAddress: []string{redisAddr}, Password: password},
})
if err != nil {
return err
return nil, err
}
Locker = &locker
return nil
}
func CloseLocker() {
if Locker != nil {
(*Locker).Close()
}
Locker = nil
lc.Append(fx.Hook{
OnStop: func(_ context.Context) error {
locker.Close()
return nil
},
})
return locker, nil
}

33
internal/redis/utils.go Normal file
View File

@@ -0,0 +1,33 @@
package redis
//
//func WriteString(ctx context.Context, key string, value string, ttl ...time.Duration) error {
// if Client == nil {
// return rueidis.Nil
// }
// var expiration time.Duration
// if len(ttl) > 0 {
// expiration = ttl[0]
//
// }
// return (*Client).Do(ctx, (*Client).B().
// Set().
// Key(key).
// Value(value).
// Ex(expiration).
// Build()).Error()
//}
//
//func ReadString(ctx context.Context, key string) (string, error) {
// if Client == nil {
// return "", rueidis.Nil
// }
// resp := (*Client).Do(ctx, (*Client).B().
// Get().
// Key(key).
// Build())
// if resp.Error() != nil {
// return "", resp.Error()
// }
// return resp.ToString()
//}