zeuszhao 1 rok pred
commit
0522eac7bf
7 zmenil súbory, kde vykonal 225 pridanie a 0 odobranie
  1. 2 0
      .gitignore
  2. 23 0
      cache/cache.go
  3. 37 0
      cache/memory.go
  4. 77 0
      cache/memory_test.go
  5. 56 0
      cache/redis.go
  6. 13 0
      go.mod
  7. 17 0
      go.sum

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.idea/
+.vscode

+ 23 - 0
cache/cache.go

@@ -0,0 +1,23 @@
+package cache
+
+import (
+	"context"
+	"errors"
+	"time"
+)
+
+var (
+	ErrorCache         = errors.New("cache error")
+	ErrorCacheNotFound = errors.New("cache not found")
+)
+
+var (
+	Redis  = "redis"
+	Memory = "memory"
+)
+
+type Cache interface {
+	Set(ctx context.Context, key, val string, t time.Duration) (bool, error)
+	Get(ctx context.Context, key string) (string, error)
+	Delete(ctx context.Context, key string) (bool, error)
+}

+ 37 - 0
cache/memory.go

@@ -0,0 +1,37 @@
+package cache
+
+import (
+	"context"
+	"github.com/patrickmn/go-cache"
+	"time"
+)
+
+type memory struct {
+	c *cache.Cache
+}
+
+func (c *memory) Set(ctx context.Context, key, val string, t time.Duration) (bool, error) {
+	c.c.Set(key, val, t)
+	return true, nil
+}
+
+func (c *memory) Get(ctx context.Context, key string) (string, error) {
+	v, ok := c.c.Get(key)
+	if !ok {
+		return "", ErrorCacheNotFound
+	}
+	vv, ok := v.(string)
+	if !ok {
+		return "", ErrorCache
+	}
+	return vv, nil
+}
+
+func (c *memory) Delete(ctx context.Context, key string) (bool, error) {
+	c.c.Delete(key)
+	return true, nil
+}
+
+func NewMemory() Cache {
+	return &memory{c: cache.New(5*time.Minute, 10*time.Minute)}
+}

+ 77 - 0
cache/memory_test.go

@@ -0,0 +1,77 @@
+package cache
+
+import (
+	"context"
+	"testing"
+	"time"
+)
+
+func TestMemorySetGetDelete(t *testing.T) {
+	// 创建一个新的 memory Cache 实例
+	memCache := NewMemory()
+
+	// 设置一个键值对
+	key := "testKey"
+	val := "testValue"
+	ttl := 1 * time.Minute
+	_, err := memCache.Set(context.Background(), key, val, ttl)
+	if err != nil {
+		t.Errorf("Failed to set key-value pair: %v", err)
+	}
+
+	// 获取键对应的值
+	result, err := memCache.Get(context.Background(), key)
+	if err != nil {
+		t.Errorf("Failed to get value for key: %v", err)
+	}
+	if result != val {
+		t.Errorf("Expected value %s, but got %s", val, result)
+	}
+
+	// 删除键值对
+	_, err = memCache.Delete(context.Background(), key)
+	if err != nil {
+		t.Errorf("Failed to delete key-value pair: %v", err)
+	}
+
+	// 再次尝试获取键对应的值,应该返回 ErrorCacheNotFound 错误
+	_, err = memCache.Get(context.Background(), key)
+	if err != ErrorCacheNotFound {
+		t.Errorf("Expected error ErrorCacheNotFound, but got %v", err)
+	}
+}
+
+func BenchmarkMemorySet(b *testing.B) {
+	memCache := NewMemory()
+	key := "testKey"
+	val := "testValue"
+	ttl := 1 * time.Minute
+
+	for i := 0; i < b.N; i++ {
+		_, _ = memCache.Set(context.Background(), key, val, ttl)
+	}
+}
+
+func BenchmarkMemoryGet(b *testing.B) {
+	memCache := NewMemory()
+	key := "testKey"
+	val := "testValue"
+	ttl := 1 * time.Minute
+	_, _ = memCache.Set(context.Background(), key, val, ttl)
+
+	for i := 0; i < b.N; i++ {
+		_, _ = memCache.Get(context.Background(), key)
+	}
+}
+
+func BenchmarkMemoryDelete(b *testing.B) {
+	memCache := NewMemory()
+	key := "testKey"
+	val := "testValue"
+	ttl := 1 * time.Minute
+	_, _ = memCache.Set(context.Background(), key, val, ttl)
+
+	for i := 0; i < b.N; i++ {
+		_, _ = memCache.Delete(context.Background(), key)
+	}
+}

+ 56 - 0
cache/redis.go

@@ -0,0 +1,56 @@
+package cache
+
+import (
+	"context"
+	"errors"
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+type rediscli struct {
+	c *redis.Client
+}
+
+type Options redis.Options
+
+func (c *rediscli) Set(ctx context.Context, key, val string, t time.Duration) (bool, error) {
+	_, err := c.c.Set(ctx, key, val, t).Result()
+	if err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+func (c *rediscli) Get(ctx context.Context, key string) (string, error) {
+	v, err := c.c.Get(ctx, key).Result()
+	if err != nil {
+		if errors.Is(err, redis.Nil) {
+			return "", ErrorCacheNotFound
+		}
+		return "", err
+	}
+	return v, nil
+}
+
+func (c *rediscli) Delete(ctx context.Context, key string) (bool, error) {
+	_, err := c.c.Del(ctx, key).Result()
+	if err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+func NewRedis(o *Options) Cache {
+	return &rediscli{c: newRedisClient(o)}
+}
+
+func newRedisClient(o *Options) *redis.Client {
+	redisClient := redis.NewClient((*redis.Options)(o))
+	timeout, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+	defer cancel()
+	_, err := redisClient.Ping(timeout).Result()
+	if err != nil {
+		panic(err)
+	}
+	return redisClient
+}

+ 13 - 0
go.mod

@@ -0,0 +1,13 @@
+module git.ttmylife.com/zeuszhao/kit
+
+go 1.19
+
+require (
+	github.com/go-redis/redis/v8 v8.11.5
+	github.com/patrickmn/go-cache v2.1.0+incompatible
+)
+
+require (
+	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+)

+ 17 - 0
go.sum

@@ -0,0 +1,17 @@
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=