From fcbf9b62a2f7dd2d8a158c565bd68f0d4ada563b Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 21 Jul 2024 00:39:48 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BA=D0=B5=D1=88=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=8E=D0=B7=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 1 + src/cache_inmem.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++ src/service.go | 28 ++++++++++++++--- 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/cache_inmem.go diff --git a/main.go b/main.go index ee4376b..ea37104 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,7 @@ func main() { Jwt: jwtUtil, Bcrypt: bcryptUtil, Db: db, + Cache: src.NewCacheInmem[string, src.UserDTO](60 * 60), }) r := gin.New() diff --git a/src/cache_inmem.go b/src/cache_inmem.go new file mode 100644 index 0000000..57ff597 --- /dev/null +++ b/src/cache_inmem.go @@ -0,0 +1,76 @@ +package src + +import ( + "sync" + "time" +) + +type Cache[K comparable, V any] interface { + Get(key K) (V, bool) + Set(key K, value V, ttlSeconds int) + Del(key K) +} + +func NewCacheInmem[K comparable, V any](ttlSeconds int) Cache[K, V] { + return &cacheInmem[K, V]{ + m: &sync.Mutex{}, + data: map[K]*cacheInmemItem[V]{}, + ttlSeconds: ttlSeconds, + } +} + +type cacheInmemItem[T any] struct { + Value T + Ttl int64 + Expiration int64 +} + +type cacheInmem[K comparable, V any] struct { + m *sync.Mutex + data map[K]*cacheInmemItem[V] + ttlSeconds int +} + +func (c *cacheInmem[K, V]) Get(key K) (V, bool) { + c.m.Lock() + defer c.m.Unlock() + + item, ok := c.data[key] + if !ok { + var v V + return v, false + } + + timestamp := time.Now().Unix() + if item.Expiration > timestamp { + item.Expiration = timestamp + item.Ttl + return item.Value, true + } + + delete(c.data, key) + + var v V + return v, false +} + +func (c *cacheInmem[K, V]) Set(key K, value V, ttlSeconds int) { + c.m.Lock() + defer c.m.Unlock() + + ttl := int64(c.ttlSeconds) + + expiration := time.Now().Unix() + ttl + item := &cacheInmemItem[V]{ + Value: value, + Ttl: ttl, + Expiration: expiration, + } + c.data[key] = item +} + +func (c *cacheInmem[K, V]) Del(key K) { + c.m.Lock() + defer c.m.Unlock() + + delete(c.data, key) +} diff --git a/src/service.go b/src/service.go index 0abf417..f0f45da 100644 --- a/src/service.go +++ b/src/service.go @@ -27,6 +27,7 @@ type UserServiceDeps struct { Db DB Jwt JwtUtil Bcrypt BCryptUtil + Cache Cache[string, UserDTO] } type userService struct { @@ -64,6 +65,8 @@ func (u *userService) CreateUser(ctx context.Context, params UserCreateParams) ( return nil, err } + u.deps.Cache.Set(result.Id, *result, -1) + return result, nil } @@ -85,22 +88,39 @@ func (u *userService) AuthenticateUser(ctx context.Context, login, password stri return "", err } + u.deps.Cache.Set(user.Id, *user, -1) + return jwt, nil } +func (u *userService) getUserById(ctx context.Context, userId string) (*UserDTO, error) { + if user, ok := u.deps.Cache.Get(userId); ok { + return &user, nil + } + + user, err := u.deps.Db.GetUserById(ctx, userId) + if err != nil { + return nil, err + } + if user == nil { + return nil, ErrUserNotExists + } + + u.deps.Cache.Set(user.Id, *user, -1) + + return user, nil +} + func (u *userService) ValidateToken(ctx context.Context, tokenStr string) (*UserDTO, error) { payload, err := u.deps.Jwt.Parse(tokenStr) if err != nil { return nil, ErrUserWrongToken } - user, err := u.deps.Db.GetUserById(ctx, payload.UserId) + user, err := u.getUserById(ctx, payload.UserId) if err != nil { return nil, err } - if user == nil { - return nil, ErrUserNotExists - } return user, nil }