From 134e774e8093d2d329a4fbe28cc7cbaabd05396b Mon Sep 17 00:00:00 2001 From: Muhammed Efe Cetin Date: Sun, 9 Feb 2025 20:18:23 +0300 Subject: [PATCH] minio: add support for context management --- minio/minio.go | 66 +++++++++++++++++++++-------------- minio/minio_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 29 deletions(-) diff --git a/minio/minio.go b/minio/minio.go index 4649020a..7427979a 100644 --- a/minio/minio.go +++ b/minio/minio.go @@ -18,7 +18,6 @@ import ( type Storage struct { minio *minio.Client cfg Config - ctx context.Context mu sync.Mutex } @@ -41,7 +40,7 @@ func New(config ...Config) *Storage { panic(err) } - storage := &Storage{minio: minioClient, cfg: cfg, ctx: context.Background()} + storage := &Storage{minio: minioClient, cfg: cfg} // Reset all entries if set to true if cfg.Reset { @@ -63,15 +62,14 @@ func New(config ...Config) *Storage { return storage } -// Get value by key -func (s *Storage) Get(key string) ([]byte, error) { - +// GetWithContext value by key with context +func (s *Storage) GetWithContext(ctx context.Context, key string) ([]byte, error) { if len(key) <= 0 { return nil, errors.New("the key value is required") } // get object - object, err := s.minio.GetObject(s.ctx, s.cfg.Bucket, key, s.cfg.GetObjectOptions) + object, err := s.minio.GetObject(ctx, s.cfg.Bucket, key, s.cfg.GetObjectOptions) if err != nil { return nil, err } @@ -91,9 +89,13 @@ func (s *Storage) Get(key string) ([]byte, error) { return bb.Bytes(), nil } -// Set key with value -func (s *Storage) Set(key string, val []byte, exp time.Duration) error { +// Get value by key +func (s *Storage) Get(key string) ([]byte, error) { + return s.GetWithContext(context.Background(), key) +} +// SetWithContext key with value with context +func (s *Storage) SetWithContext(ctx context.Context, key string, val []byte, exp time.Duration) error { if len(key) <= 0 { return errors.New("the key value is required") } @@ -106,35 +108,43 @@ func (s *Storage) Set(key string, val []byte, exp time.Duration) error { s.cfg.PutObjectOptions.ContentType = http.DetectContentType(val) // put object - _, err := s.minio.PutObject(s.ctx, s.cfg.Bucket, key, file, file.Size(), s.cfg.PutObjectOptions) + _, err := s.minio.PutObject(ctx, s.cfg.Bucket, key, file, file.Size(), s.cfg.PutObjectOptions) s.mu.Unlock() return err } +// Set key with value +func (s *Storage) Set(key string, val []byte, exp time.Duration) error { + return s.SetWithContext(context.Background(), key, val, exp) +} + +// DeleteWithContext key with value with context +func (s *Storage) DeleteWithContext(ctx context.Context, key string) error { + if len(key) <= 0 { + return errors.New("the key value is required") + } + + // remove + err := s.minio.RemoveObject(ctx, s.cfg.Bucket, key, s.cfg.RemoveObjectOptions) + + return err +} + // Delete entry by key func (s *Storage) Delete(key string) error { - - if len(key) <= 0 { - return errors.New("the key value is required") - } - - // remove - err := s.minio.RemoveObject(s.ctx, s.cfg.Bucket, key, s.cfg.RemoveObjectOptions) - - return err + return s.DeleteWithContext(context.Background(), key) } -// Reset all entries, including unexpired -func (s *Storage) Reset() error { - +// ResetWithContext all keys with context +func (s *Storage) ResetWithContext(ctx context.Context) error { objectsCh := make(chan minio.ObjectInfo) // Send object names that are needed to be removed to objectsCh go func() { defer close(objectsCh) // List all objects from a bucket-name with a matching prefix. - for object := range s.minio.ListObjects(s.ctx, s.cfg.Bucket, s.cfg.ListObjectsOptions) { + for object := range s.minio.ListObjects(ctx, s.cfg.Bucket, s.cfg.ListObjectsOptions) { if object.Err != nil { log.Println(object.Err) } @@ -147,13 +157,17 @@ func (s *Storage) Reset() error { } var errs []error - for err := range s.minio.RemoveObjects(s.ctx, s.cfg.Bucket, objectsCh, opts) { + for err := range s.minio.RemoveObjects(ctx, s.cfg.Bucket, objectsCh, opts) { errs = append(errs, err.Err) } return errors.Join(errs...) } +func (s *Storage) Reset() error { + return s.ResetWithContext(context.Background()) +} + // Close the storage func (s *Storage) Close() error { return nil @@ -161,7 +175,7 @@ func (s *Storage) Close() error { // CheckBucket Check to see if bucket already exists func (s *Storage) CheckBucket() error { - exists, err := s.minio.BucketExists(s.ctx, s.cfg.Bucket) + exists, err := s.minio.BucketExists(context.Background(), s.cfg.Bucket) if !exists || err != nil { return errors.New("the specified bucket does not exist") } @@ -170,12 +184,12 @@ func (s *Storage) CheckBucket() error { // CreateBucket Bucket not found so Make a new bucket func (s *Storage) CreateBucket() error { - return s.minio.MakeBucket(s.ctx, s.cfg.Bucket, minio.MakeBucketOptions{Region: s.cfg.Region}) + return s.minio.MakeBucket(context.Background(), s.cfg.Bucket, minio.MakeBucketOptions{Region: s.cfg.Region}) } // RemoveBucket Bucket remove if bucket is empty func (s *Storage) RemoveBucket() error { - return s.minio.RemoveBucket(s.ctx, s.cfg.Bucket) + return s.minio.RemoveBucket(context.Background(), s.cfg.Bucket) } // Conn Return minio client diff --git a/minio/minio_test.go b/minio/minio_test.go index 2aeb7d81..faa1f616 100644 --- a/minio/minio_test.go +++ b/minio/minio_test.go @@ -81,6 +81,25 @@ func Test_Get(t *testing.T) { require.Zero(t, len(result)) } +func Test_GetWithContext(t *testing.T) { + var ( + key = "john" + val = []byte("doe") + ) + + testStore := newTestStore(t) + + err := testStore.Set(key, val, 0) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + result, err := testStore.GetWithContext(ctx, key) + require.ErrorIs(t, err, context.Canceled) + require.Zero(t, len(result)) +} + func Test_Get_Empty_Key(t *testing.T) { var ( key = "" @@ -137,6 +156,21 @@ func Test_Set(t *testing.T) { require.NoError(t, err) } +func Test_SetWithContext(t *testing.T) { + var ( + key = "john" + val = []byte("doe") + ) + + testStore := newTestStore(t) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err := testStore.SetWithContext(ctx, key, val, 0) + require.ErrorIs(t, err, context.Canceled) +} + func Test_Set_Empty_Key(t *testing.T) { var ( key = "" @@ -185,6 +219,28 @@ func Test_Delete(t *testing.T) { require.NoError(t, err) } +func Test_DeleteWithContext(t *testing.T) { + var ( + key = "john" + val = []byte("doe") + ) + + testStore := newTestStore(t) + + err := testStore.Set(key, val, 0) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err = testStore.DeleteWithContext(ctx, key) + require.ErrorIs(t, err, context.Canceled) + + valRet, err := testStore.Get(key) + require.NoError(t, err) + require.Equal(t, val, valRet) +} + func Test_Delete_Empty_Key(t *testing.T) { var ( key = "" @@ -237,14 +293,35 @@ func Test_Reset(t *testing.T) { require.Zero(t, len(result)) } +func Test_ResetWithContext(t *testing.T) { + var ( + val = []byte("doe") + ) + + testStore := newTestStore(t) + + err := testStore.Set("john1", val, 0) + require.NoError(t, err) + + err = testStore.Set("john2", val, 0) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err = testStore.ResetWithContext(ctx) + require.NoError(t, err) + + result, err := testStore.Get("john1") + require.NoError(t, err) + require.Equal(t, val, result) +} + func Test_Reset_Not_Exists_Bucket(t *testing.T) { testStore := newTestStore(t) defer testStore.Close() err := testStore.RemoveBucket() - require.NoError(t, err) - - err = testStore.Reset() require.Error(t, err) require.EqualError(t, err, "The specified bucket does not exist") }