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 }