From 965ba94e3c16b187c80ff3b9642cf6aa753a4644 Mon Sep 17 00:00:00 2001 From: "bogdanova.valen" Date: Fri, 1 Nov 2024 17:44:06 +0300 Subject: [PATCH] add redis lib; fix go mod; go sum --- go.mod | 1 + go.sum | 2 + pkg/client/cache/client.go | 17 +++ pkg/client/cache/config/config.go | 12 ++ pkg/client/cache/redis/client.go | 180 ++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 pkg/client/cache/client.go create mode 100644 pkg/client/cache/config/config.go create mode 100644 pkg/client/cache/redis/client.go diff --git a/go.mod b/go.mod index 1df4a7a..afa88dc 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gomodule/redigo v1.9.2 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index 8b54171..902da84 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gojuno/minimock/v3 v3.4.1 h1:Flf735K7TT45TKCUMG4fz1vwadW/cW0Q0wH8x7eJKos= github.com/gojuno/minimock/v3 v3.4.1/go.mod h1:mpNkl275+w8a6CYjeCHIRfN8QzN2R7ejT6jEDUdweuo= +github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= diff --git a/pkg/client/cache/client.go b/pkg/client/cache/client.go new file mode 100644 index 0000000..9dcdd20 --- /dev/null +++ b/pkg/client/cache/client.go @@ -0,0 +1,17 @@ +package cache + +import ( + "context" + "time" +) + +// RedisClient is interface for redis client calls +type RedisClient interface { + HashSet(ctx context.Context, key string, values interface{}) error + Set(ctx context.Context, key string, value interface{}) error + HGetAll(ctx context.Context, key string) ([]interface{}, error) + Get(ctx context.Context, key string) (interface{}, error) + Expire(ctx context.Context, key string, expiration time.Duration) error + Ping(ctx context.Context) error + Delete(ctx context.Context, key string) error +} diff --git a/pkg/client/cache/config/config.go b/pkg/client/cache/config/config.go new file mode 100644 index 0000000..803bd46 --- /dev/null +++ b/pkg/client/cache/config/config.go @@ -0,0 +1,12 @@ +package config + +import "time" + +// RedisConfig is interface for redis config settings +type RedisConfig interface { + Address() string + ConnectionTimeout() time.Duration + MaxIdle() int + IdleTimeout() time.Duration + ElementTTL() time.Duration +} diff --git a/pkg/client/cache/redis/client.go b/pkg/client/cache/redis/client.go new file mode 100644 index 0000000..fce050a --- /dev/null +++ b/pkg/client/cache/redis/client.go @@ -0,0 +1,180 @@ +package redis + +import ( + "context" + "log" + "time" + + "github.com/gomodule/redigo/redis" + + "github.com/valek177/platform-common/pkg/client/cache" + "github.com/valek177/platform-common/pkg/client/cache/config" +) + +var _ cache.RedisClient = (*client)(nil) + +type handler func(ctx context.Context, conn redis.Conn) error + +type client struct { + pool *redis.Pool + config config.RedisConfig +} + +// NewClient creates new redis client +func NewClient(pool *redis.Pool, config config.RedisConfig) *client { + return &client{ + pool: pool, + config: config, + } +} + +func (c *client) HashSet(ctx context.Context, key string, values interface{}) error { + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + _, err := conn.Do("HSET", redis.Args{key}.AddFlat(values)...) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (c *client) Set(ctx context.Context, key string, value interface{}) error { + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + _, err := conn.Do("SET", redis.Args{key}.Add(value)...) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (c *client) HGetAll(ctx context.Context, key string) ([]interface{}, error) { + var values []interface{} + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + var errEx error + values, errEx = redis.Values(conn.Do("HGETALL", key)) + if errEx != nil { + return errEx + } + + return nil + }) + if err != nil { + return nil, err + } + + return values, nil +} + +func (c *client) Get(ctx context.Context, key string) (interface{}, error) { + var value interface{} + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + var errEx error + value, errEx = conn.Do("GET", key) + if errEx != nil { + return errEx + } + + return nil + }) + if err != nil { + return nil, err + } + + return value, nil +} + +func (c *client) Expire(ctx context.Context, key string, expiration time.Duration) error { + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + _, err := conn.Do("EXPIRE", key, int(expiration.Seconds())) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (c *client) Ping(ctx context.Context) error { + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + _, err := conn.Do("PING") + if err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (c *client) Delete(ctx context.Context, key string) error { + err := c.execute(ctx, func(_ context.Context, conn redis.Conn) error { + _, err := conn.Do("DEL", key) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return err + } + + return nil +} + +func (c *client) execute(ctx context.Context, handler handler) error { + conn, err := c.getConnect(ctx) + if err != nil { + return err + } + defer func() { + err = conn.Close() + if err != nil { + log.Printf("failed to close redis connection: %v\n", err) + } + }() + + err = handler(ctx, conn) + if err != nil { + return err + } + + return nil +} + +func (c *client) getConnect(ctx context.Context) (redis.Conn, error) { + getConnTimeoutCtx, cancel := context.WithTimeout(ctx, c.config.ConnectionTimeout()) + defer cancel() + + conn, err := c.pool.GetContext(getConnTimeoutCtx) + if err != nil { + log.Printf("failed to get redis connection: %v\n", err) + + _ = conn.Close() + return nil, err + } + + return conn, nil +}