Skip to content

Commit

Permalink
feat: add cache, token config, verify signature (#15)
Browse files Browse the repository at this point in the history
* feat: add cache, token config, verify signature

* bet
  • Loading branch information
hoanguyenkh authored Nov 21, 2024
1 parent 7d9c1e9 commit 2a36653
Show file tree
Hide file tree
Showing 12 changed files with 1,115 additions and 27 deletions.
37 changes: 37 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cache

import (
"github.com/dgraph-io/ristretto"
"time"
)

type Cache interface {
Set(key string, value interface{}, ttl time.Duration) error
Get(key string, result any) error
Del(key string) error
}

type CfgCache struct {
*ristretto.Config
Type string
RedisUrl string
}

func NewCache(cfg *CfgCache) Cache {
var cache Cache
if cfg.Type == "redis" && cfg.RedisUrl != "" {
cache = NewRedisCache(cfg.RedisUrl)
} else {
if cfg.Config == nil {
cache, _ = NewRistrettoCacheDefault()
} else {
cache, _ = NewRistrettoCache(&ristretto.Config{
NumCounters: cfg.NumCounters,
MaxCost: cfg.MaxCost,
BufferItems: cfg.BufferItems,
})
}
}

return cache
}
180 changes: 180 additions & 0 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package cache_test

import (
"github.com/KyberNetwork/kutils/cache"
"github.com/stretchr/testify/require"
"testing"
"time"
)

func TestCache(t *testing.T) {
cacheTypes := []struct {
name string
config *cache.CfgCache
}{
{"Ristretto", &cache.CfgCache{
Type: "ristretto",
}},
{"Redis", &cache.CfgCache{
Type: "ristretto",
RedisUrl: "localhost:6379",
}},
}

type example struct {
Name string
Age int
Value uint64
}

for _, ct := range cacheTypes {
t.Run(ct.name, func(t *testing.T) {
var err error

sCache := cache.NewCache(ct.config)
// Example usage
key1 := "exampleKey"
key2 := "exampleKey1"
input1 := example{
Name: t.Name(),
Value: 1,
}
input2 := "demo 123"
ttl := 5 * time.Minute

err = sCache.Set(key1, input1, ttl)
require.NoError(t, err, "Error setting cache")
err = sCache.Set(key2, input2, ttl)
require.NoError(t, err, "Error setting cache")
var res1 *example
err = sCache.Get(key1, &res1)
require.NoError(t, err, "Error getting cache")
require.Equal(t, input1, *res1, "Error expected cache value")

var res2 string
err = sCache.Get(key2, &res2)
require.NoError(t, err, "Error getting cache")
require.Equal(t, input2, res2, "Error expected cache value")
})
t.Run("Pointer Types", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "pointerTest"
input := &example{Name: "pointer", Age: 25, Value: 100}
err := sCache.Set(key, input, time.Minute)
require.NoError(t, err)

var result *example
err = sCache.Get(key, &result)
require.NoError(t, err)
require.Equal(t, input, result)
})

t.Run("Non-existent Key", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
var result string
err := sCache.Get("nonexistentKey", &result)
require.Error(t, err)
require.Contains(t, err.Error(), "key not found")
})

t.Run("Type Mismatch", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "typeMismatch"
err := sCache.Set(key, 42, time.Minute)
require.NoError(t, err)

var result string
err = sCache.Get(key, &result)
require.Error(t, err)
})

t.Run("Nil Pointer", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "nilPointer"
err := sCache.Set(key, "test", time.Minute)
require.NoError(t, err)

var result *string
err = sCache.Get(key, result) // passing nil pointer
require.Error(t, err)
require.Contains(t, err.Error(), "nil")
})

t.Run("Non-existent Key", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
var result string
err := sCache.Get("nonexistentKey", &result)
require.Error(t, err)
require.Contains(t, err.Error(), "key not found")
})

t.Run("Type Mismatch", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "typeMismatch"
err := sCache.Set(key, 42, time.Minute)
require.NoError(t, err)

var result string
err = sCache.Get(key, &result)
require.Error(t, err)
})

t.Run("Nil Pointer", func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "nilPointer"
err := sCache.Set(key, "test", time.Minute)
require.NoError(t, err)

var result *string
err = sCache.Get(key, result) // passing nil pointer
require.Error(t, err)
require.Contains(t, err.Error(), "nil")
})

//t.Run("Complex Types", func(t *testing.T) {
// sCache := cache.NewCache(ct.config)
// key := "complexType"
// input := map[string]interface{}{
// "name": "test",
// "data": []int{1, 2, 3},
// }
// err := sCache.Set(key, input, time.Minute)
// require.NoError(t, err)
//
// var result *map[string]interface{}
// err = sCache.Get(key, &result)
// require.NoError(t, err)
// require.Equal(t, input, *result)
//})
}
}

func TestDelKey(t *testing.T) {
cacheTypes := []struct {
name string
config *cache.CfgCache
}{
{"Ristretto", &cache.CfgCache{
Type: "ristretto",
}},
{"Redis", &cache.CfgCache{
Type: "ristretto",
RedisUrl: "localhost:6379",
}},
}
for _, ct := range cacheTypes {
t.Run(ct.name, func(t *testing.T) {
sCache := cache.NewCache(ct.config)
key := "test_key"
value := "123test"
err := sCache.Set(key, value, time.Minute)
require.NoError(t, err)
err = sCache.Del(key)
require.NoError(t, err)

var result string
err = sCache.Get(key, &result)
require.Error(t, err)
})
}
}
44 changes: 44 additions & 0 deletions cache/redis_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cache

import (
"context"
"encoding/json"
"errors"
"fmt"
"time"

"github.com/redis/go-redis/v9"
)

type RedisCache struct {
client *redis.Client
}

func NewRedisCache(redisURL string) *RedisCache {
client := redis.NewClient(&redis.Options{
Addr: redisURL,
})
return &RedisCache{client: client}
}

func (r *RedisCache) Set(key string, value interface{}, ttl time.Duration) error {
// Marshal the value to JSON
jsonData, err := json.Marshal(value)
if err != nil {
return fmt.Errorf("failed to marshal value: %w", err)
}
return r.client.Set(context.Background(), key, jsonData, ttl).Err()
}

func (r *RedisCache) Get(key string, result any) error {
value, err := r.client.Get(context.Background(), key).Result()
if errors.Is(err, redis.Nil) {
return fmt.Errorf("key not found")
}
err = json.Unmarshal([]byte(value), result)
return err
}

func (r *RedisCache) Del(key string) error {
return r.client.Del(context.Background(), key).Err()
}
Loading

0 comments on commit 2a36653

Please sign in to comment.