From fc628f1666df4a6e2bfca0e4fe134b1392878d91 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:24:44 -0800 Subject: [PATCH 01/10] feat: brings response types up to standards --- incubating/simple_cache_client.go | 22 +--- internal/models/requests.go | 18 +-- internal/models/responses.go | 101 +------------- internal/services/scs_control_service.go | 42 +----- internal/services/scs_data_service.go | 102 +++++++++------ internal/utility/utility.go | 56 +++++++- momento/cache_requests.go | 21 +-- momento/cache_responses.go | 145 +++++++------------- momento/simple_cache_client.go | 160 +++++------------------ momento/simple_cache_client_test.go | 99 ++++++-------- 10 files changed, 246 insertions(+), 520 deletions(-) diff --git a/incubating/simple_cache_client.go b/incubating/simple_cache_client.go index 586f3734..3686e54b 100644 --- a/incubating/simple_cache_client.go +++ b/incubating/simple_cache_client.go @@ -112,39 +112,21 @@ func convertMomentoSvcErrorToCustomerError(e momentoerrors.MomentoSvcErr) moment } return momento.NewMomentoError(e.Code(), e.Message(), e.OriginalErr()) } - func (c *DefaultScsClient) CreateCache(ctx context.Context, request *momento.CreateCacheRequest) error { return c.internalClient.CreateCache(ctx, request) } - func (c *DefaultScsClient) DeleteCache(ctx context.Context, request *momento.DeleteCacheRequest) error { return c.internalClient.DeleteCache(ctx, request) } - func (c *DefaultScsClient) ListCaches(ctx context.Context, request *momento.ListCachesRequest) (*momento.ListCachesResponse, error) { return c.internalClient.ListCaches(ctx, request) } - -func (c *DefaultScsClient) CreateSigningKey(ctx context.Context, request *momento.CreateSigningKeyRequest) (*momento.CreateSigningKeyResponse, error) { - return c.internalClient.CreateSigningKey(ctx, request) -} - -func (c *DefaultScsClient) RevokeSigningKey(ctx context.Context, request *momento.RevokeSigningKeyRequest) error { - return c.internalClient.RevokeSigningKey(ctx, request) -} - -func (c *DefaultScsClient) ListSigningKeys(ctx context.Context, request *momento.ListSigningKeysRequest) (*momento.ListSigningKeysResponse, error) { - return c.internalClient.ListSigningKeys(ctx, request) -} - -func (c *DefaultScsClient) Set(ctx context.Context, request *momento.CacheSetRequest) (*momento.SetCacheResponse, error) { +func (c *DefaultScsClient) Set(ctx context.Context, request *momento.CacheSetRequest) error { return c.internalClient.Set(ctx, request) } - -func (c *DefaultScsClient) Get(ctx context.Context, request *momento.CacheGetRequest) (*momento.GetCacheResponse, error) { +func (c *DefaultScsClient) Get(ctx context.Context, request *momento.CacheGetRequest) (*momento.CacheGetResponse, error) { return c.internalClient.Get(ctx, request) } - func (c *DefaultScsClient) Delete(ctx context.Context, request *momento.CacheDeleteRequest) error { return c.internalClient.Delete(ctx, request) } diff --git a/internal/models/requests.go b/internal/models/requests.go index aab975a7..f9c16ebc 100644 --- a/internal/models/requests.go +++ b/internal/models/requests.go @@ -1,11 +1,8 @@ package models import ( - "fmt" - "github.com/momentohq/client-sdk-go/auth" "github.com/momentohq/client-sdk-go/config" - "github.com/momentohq/client-sdk-go/internal/momentoerrors" pb "github.com/momentohq/client-sdk-go/internal/protos" ) @@ -20,6 +17,10 @@ type DataGrpcManagerRequest struct { type LocalDataGrpcManagerRequest struct { Endpoint string } +type CacheGetRequest struct { + CacheName string + Key interface{} +} type ControlClientRequest struct { Configuration config.Configuration @@ -46,14 +47,3 @@ type ConvertEcacheResultRequest struct { Message string OpName string } - -func ConvertEcacheResult(request ConvertEcacheResultRequest) momentoerrors.MomentoSvcErr { - return momentoerrors.NewMomentoSvcErr( - momentoerrors.InternalServerError, - fmt.Sprintf( - "CacheService returned an unexpected result: %v for operation: %s with message: %s", - request.ECacheResult, request.OpName, request.Message, - ), - nil, - ) -} diff --git a/internal/models/responses.go b/internal/models/responses.go index 57bf4a9b..5ce9c4f5 100644 --- a/internal/models/responses.go +++ b/internal/models/responses.go @@ -1,10 +1,6 @@ package models import ( - "encoding/json" - "time" - - "github.com/momentohq/client-sdk-go/internal/momentoerrors" pb "github.com/momentohq/client-sdk-go/internal/protos" ) @@ -41,95 +37,16 @@ func NewCacheInfo(cache *pb.XCache) CacheInfo { return CacheInfo{Name: cache.CacheName} } -type CreateSigningKeyRequest struct { - TtlMinutes uint32 -} - -type CreateSigningKeyResponse struct { - KeyId string - Endpoint string - Key string - ExpiresAt time.Time -} - -func NewCreateSigningKeyResponse(endpoint string, resp *pb.XCreateSigningKeyResponse) (*CreateSigningKeyResponse, error) { - var keyObj map[string]string - err := json.Unmarshal([]byte(resp.GetKey()), &keyObj) - if err != nil { - return nil, err - } - return &CreateSigningKeyResponse{ - KeyId: keyObj["kid"], - Endpoint: endpoint, - Key: resp.GetKey(), - ExpiresAt: time.Unix(int64(resp.GetExpiresAt()), 0), - }, nil -} - -type RevokeSigningKeyRequest struct { - KeyId string -} - -type ListSigningKeysRequest struct { - NextToken string -} - -type ListSigningKeysResponse struct { - NextToken string - SigningKeys []SigningKey -} - -func NewListSigningKeysResponse(endpoint string, resp *pb.XListSigningKeysResponse) *ListSigningKeysResponse { - var signingKeys []SigningKey - for _, signingKey := range resp.SigningKey { - signingKeys = append(signingKeys, NewSigningKey(endpoint, signingKey)) - } - return &ListSigningKeysResponse{NextToken: resp.GetNextToken(), SigningKeys: signingKeys} -} - -type SigningKey struct { - KeyId string - Endpoint string - ExpiresAt time.Time -} - -func NewSigningKey(endpoint string, signingKey *pb.XSigningKey) SigningKey { - return SigningKey{ - KeyId: signingKey.GetKeyId(), - Endpoint: endpoint, - ExpiresAt: time.Unix(int64(signingKey.GetExpiresAt()), 0), - } -} +type CacheResult string const ( - HIT string = "HIT" - MISS string = "MISS" + HIT CacheResult = "HIT" + MISS CacheResult = "MISS" ) -type CacheGetRequest struct { - CacheName string - Key interface{} -} - -type GetCacheResponse struct { +type CacheGetResponse struct { Value []byte - Result string -} - -func NewGetCacheResponse(resp *pb.XGetResponse) (*GetCacheResponse, momentoerrors.MomentoSvcErr) { - var result string - if resp.Result == pb.ECacheResult_Hit { - result = HIT - } else if resp.Result == pb.ECacheResult_Miss { - result = MISS - } else { - return nil, ConvertEcacheResult(ConvertEcacheResultRequest{ - ECacheResult: resp.Result, - Message: resp.Message, - OpName: "GET", - }) - } - return &GetCacheResponse{Value: resp.CacheBody, Result: result}, nil + Result CacheResult } type CacheSetRequest struct { @@ -139,14 +56,6 @@ type CacheSetRequest struct { TtlSeconds uint32 } -type SetCacheResponse struct { - Value []byte -} - -func NewSetCacheResponse(resp *pb.XSetResponse, value []byte) *SetCacheResponse { - return &SetCacheResponse{Value: value} -} - type CacheDeleteRequest struct { CacheName string Key interface{} diff --git a/internal/services/scs_control_service.go b/internal/services/scs_control_service.go index 7a989940..645af742 100644 --- a/internal/services/scs_control_service.go +++ b/internal/services/scs_control_service.go @@ -33,8 +33,8 @@ func (client *ScsControlClient) Close() momentoerrors.MomentoSvcErr { } func (client *ScsControlClient) CreateCache(ctx context.Context, request *models.CreateCacheRequest) momentoerrors.MomentoSvcErr { - if !utility.IsCacheNameValid(request.CacheName) { - return momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) + if err := utility.IsCacheNameValid(request.CacheName); err != nil { + return err } ctx, cancel := context.WithTimeout(ctx, ControlCtxTimeout) defer cancel() @@ -46,8 +46,8 @@ func (client *ScsControlClient) CreateCache(ctx context.Context, request *models } func (client *ScsControlClient) DeleteCache(ctx context.Context, request *models.DeleteCacheRequest) momentoerrors.MomentoSvcErr { - if !utility.IsCacheNameValid(request.CacheName) { - return momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) + if err := utility.IsCacheNameValid(request.CacheName); err != nil { + return err } ctx, cancel := context.WithTimeout(ctx, ControlCtxTimeout) defer cancel() @@ -67,37 +67,3 @@ func (client *ScsControlClient) ListCaches(ctx context.Context, request *models. } return models.NewListCacheResponse(resp), nil } - -func (client *ScsControlClient) CreateSigningKey(ctx context.Context, endpoint string, request *models.CreateSigningKeyRequest) (*models.CreateSigningKeyResponse, momentoerrors.MomentoSvcErr) { - ctx, cancel := context.WithTimeout(ctx, ControlCtxTimeout) - defer cancel() - resp, err := client.grpcClient.CreateSigningKey(ctx, &pb.XCreateSigningKeyRequest{TtlMinutes: request.TtlMinutes}) - if err != nil { - return nil, momentoerrors.ConvertSvcErr(err) - } - createResp, err := models.NewCreateSigningKeyResponse(endpoint, resp) - if err != nil { - return nil, momentoerrors.ConvertSvcErr(err) - } - return createResp, nil -} - -func (client *ScsControlClient) RevokeSigningKey(ctx context.Context, request *models.RevokeSigningKeyRequest) momentoerrors.MomentoSvcErr { - ctx, cancel := context.WithTimeout(ctx, ControlCtxTimeout) - defer cancel() - _, err := client.grpcClient.RevokeSigningKey(ctx, &pb.XRevokeSigningKeyRequest{KeyId: request.KeyId}) - if err != nil { - return momentoerrors.ConvertSvcErr(err) - } - return nil -} - -func (client *ScsControlClient) ListSigningKeys(ctx context.Context, endpoint string, request *models.ListSigningKeysRequest) (*models.ListSigningKeysResponse, momentoerrors.MomentoSvcErr) { - ctx, cancel := context.WithTimeout(ctx, ControlCtxTimeout) - defer cancel() - resp, err := client.grpcClient.ListSigningKeys(ctx, &pb.XListSigningKeysRequest{NextToken: request.NextToken}) - if err != nil { - return nil, momentoerrors.ConvertSvcErr(err) - } - return models.NewListSigningKeysResponse(endpoint, resp), nil -} diff --git a/internal/services/scs_data_service.go b/internal/services/scs_data_service.go index e6d3e4d0..6f1072b8 100644 --- a/internal/services/scs_data_service.go +++ b/internal/services/scs_data_service.go @@ -3,7 +3,6 @@ package services import ( "context" "fmt" - "reflect" "time" "github.com/momentohq/client-sdk-go/internal/grpcmanagers" @@ -36,7 +35,7 @@ func NewScsDataClient(request *models.DataClientRequest) (*ScsDataClient, moment if request.Configuration.GetClientSideTimeoutMillis() < 1 { timeout = time.Duration(defaultRequestTimeoutSeconds) * time.Second } else { - timeout = time.Duration(request.Configuration.GetClientSideTimeoutMillis()) * time.Second + timeout = request.Configuration.GetClientSideTimeoutMillis() * time.Second } return &ScsDataClient{ grpcManager: dataManager, @@ -55,25 +54,31 @@ func (client *ScsDataClient) Close() momentoerrors.MomentoSvcErr { return client.grpcManager.Close() } -func (client *ScsDataClient) Set(ctx context.Context, request *models.CacheSetRequest) (*models.SetCacheResponse, momentoerrors.MomentoSvcErr) { - if !utility.IsCacheNameValid(request.CacheName) { - return nil, momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) +func (client *ScsDataClient) Set(ctx context.Context, request *models.CacheSetRequest) momentoerrors.MomentoSvcErr { + // Validate input + if err := utility.IsKeyValid(request.Key); err != nil { + return err } - byteKey, momentoSvcErr := asBytes(request.Key, "Unsupported type for key: ") - if momentoSvcErr != nil { - return nil, momentoSvcErr + if err := utility.IsCacheNameValid(request.CacheName); err != nil { + return err } - byteValue, momentoSvcErr := asBytes(request.Value, "Unsupported type for value: ") - if momentoSvcErr != nil { - return nil, momentoSvcErr + byteKey, svcErr := utility.EncodeKey(request.Key) + if svcErr != nil { + return svcErr } + byteValue, svcErr := utility.EncodeValue(request.Value) + if svcErr != nil { + return svcErr + } + itemTtlMils := client.defaultTtlSeconds * 1000 if request.TtlSeconds > 0 { itemTtlMils = uint64(request.TtlSeconds * 1000) } + ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) defer cancel() - resp, err := client.grpcClient.Set( + _, err := client.grpcClient.Set( metadata.NewOutgoingContext(ctx, createNewMetadata(request.CacheName)), &pb.XSetRequest{ CacheKey: byteKey, @@ -82,44 +87,68 @@ func (client *ScsDataClient) Set(ctx context.Context, request *models.CacheSetRe }, ) if err != nil { - return nil, momentoerrors.ConvertSvcErr(err) + return momentoerrors.ConvertSvcErr(err) } - return models.NewSetCacheResponse(resp, byteValue), nil + return nil } -func (client *ScsDataClient) Get(ctx context.Context, request *models.CacheGetRequest) (*models.GetCacheResponse, momentoerrors.MomentoSvcErr) { - if !utility.IsCacheNameValid(request.CacheName) { - return nil, momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) +func (client *ScsDataClient) Get(ctx context.Context, request *models.CacheGetRequest) (*models.CacheGetResponse, momentoerrors.MomentoSvcErr) { + + // Validate input + if err := utility.IsKeyValid(request.Key); err != nil { + return nil, err + } + if err := utility.IsCacheNameValid(request.CacheName); err != nil { + return nil, err } - byteKey, momentoSvcErr := asBytes(request.Key, "Unsupported type for key: ") - if momentoSvcErr != nil { - return nil, momentoSvcErr + key, svcErr := utility.EncodeKey(request.Key) + if svcErr != nil { + return nil, svcErr } + + // Execute request ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) defer cancel() resp, err := client.grpcClient.Get( metadata.NewOutgoingContext(ctx, createNewMetadata(request.CacheName)), - &pb.XGetRequest{CacheKey: byteKey}, + &pb.XGetRequest{CacheKey: key}, ) if err != nil { return nil, momentoerrors.ConvertSvcErr(err) } - newResp, momentoSvcErr := models.NewGetCacheResponse(resp) - if momentoSvcErr != nil { - return nil, momentoSvcErr - } - return newResp, nil + // Convert from grpc struct to internal struct + if resp.Result == pb.ECacheResult_Hit { + return &models.CacheGetResponse{ + Value: resp.CacheBody, + Result: models.HIT, + }, nil + } else if resp.Result == pb.ECacheResult_Miss { + return &models.CacheGetResponse{ + Value: resp.CacheBody, + Result: models.MISS, + }, nil + } else { + return nil, momentoerrors.NewMomentoSvcErr( + momentoerrors.InternalServerError, + fmt.Sprintf( + "CacheService returned an unexpected result: %v for operation: %s with message: %s", + resp.Result, "GET", resp.Message, + ), + nil, + ) + } } func (client *ScsDataClient) Delete(ctx context.Context, request *models.CacheDeleteRequest) momentoerrors.MomentoSvcErr { - if !utility.IsCacheNameValid(request.CacheName) { - return momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) + if err := utility.IsCacheNameValid(request.CacheName); err != nil { + return err } - byteKey, momentoSvcErr := asBytes(request.Key, "Unsupported type for key: ") - if momentoSvcErr != nil { - return momentoSvcErr + byteKey, svcErr := utility.EncodeKey(request.Key) + if svcErr != nil { + return svcErr } + ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) defer cancel() _, err := client.grpcClient.Delete( @@ -133,17 +162,6 @@ func (client *ScsDataClient) Delete(ctx context.Context, request *models.CacheDe } -func asBytes(data interface{}, message string) ([]byte, momentoerrors.MomentoSvcErr) { - switch data.(type) { - case string: - return []byte(reflect.ValueOf(data).String()), nil - case []byte: - return reflect.ValueOf(data).Bytes(), nil - default: - return nil, momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, fmt.Sprintf("%s %s", message, reflect.TypeOf(data).String()), nil) - } -} - func createNewMetadata(cacheName string) metadata.MD { return metadata.Pairs("cache", cacheName) } diff --git a/internal/utility/utility.go b/internal/utility/utility.go index 30ef0891..41a724b9 100644 --- a/internal/utility/utility.go +++ b/internal/utility/utility.go @@ -1,13 +1,17 @@ package utility import ( + "reflect" "strings" "github.com/momentohq/client-sdk-go/internal/momentoerrors" ) -func IsCacheNameValid(cacheName string) bool { - return len(strings.TrimSpace(cacheName)) != 0 +func IsCacheNameValid(cacheName string) momentoerrors.MomentoSvcErr { + if len(strings.TrimSpace(cacheName)) < 1 { + return momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "Cache name cannot be empty", nil) + } + return nil } func IsKeyValid(key interface{}) momentoerrors.MomentoSvcErr { @@ -23,3 +27,51 @@ func IsValueValid(value interface{}) momentoerrors.MomentoSvcErr { } return nil } + +func EncodeKey(key interface{}) ([]byte, momentoerrors.MomentoSvcErr) { + switch key.(type) { + case string: + return []byte(reflect.ValueOf(key).String()), nil + case []byte: + return reflect.ValueOf(key).Bytes(), nil + default: + // If target is not string or byte[] then use default gob encoder. + return nil, momentoerrors.NewMomentoSvcErr( + momentoerrors.InvalidArgumentError, + "error encoding cache key only support []byte or string currently", + nil, + ) + } +} + +func EncodeValue(value interface{}) ([]byte, momentoerrors.MomentoSvcErr) { + switch value.(type) { + case string: + return []byte(reflect.ValueOf(value).String()), nil + case []byte: + return reflect.ValueOf(value).Bytes(), nil + default: + // If target is not string or byte[] then use default gob encoder. + return nil, momentoerrors.NewMomentoSvcErr( + momentoerrors.InvalidArgumentError, + "error encoding cache value only support []byte or string currently", nil, + ) + } +} + +func DecodeValue(rawBytes []byte, target interface{}) momentoerrors.MomentoSvcErr { + switch target.(type) { + case []byte: + target = rawBytes + case string: + target = string(rawBytes) + default: + // If target is not string or byte[] + return momentoerrors.NewMomentoSvcErr( + momentoerrors.InvalidArgumentError, + "error decoding cache value only support []byte or string currently", + nil, + ) + } + return nil +} diff --git a/momento/cache_requests.go b/momento/cache_requests.go index 9b05118e..868f2510 100644 --- a/momento/cache_requests.go +++ b/momento/cache_requests.go @@ -15,21 +15,6 @@ type ListCachesRequest struct { NextToken string } -type CreateSigningKeyRequest struct { - // Ttl in minutes before the Momento signing key expires - TtlMinutes uint32 -} - -type RevokeSigningKeyRequest struct { - // Id of Momento signing key to revoke - KeyId string -} - -type ListSigningKeysRequest struct { - // Token to continue paginating through the list. It's used to handle large paginated lists. - NextToken string -} - type CacheSetRequest struct { // Name of the cache to store the item in. CacheName string @@ -42,7 +27,7 @@ type CacheSetRequest struct { TtlSeconds TimeToLive } -// Helper function that returns an initialized TimeToLive containing a pointer to ttl. +// TTL Helper function that returns an initialized TimeToLive containing a pointer to ttl. func TTL(ttl uint32) TimeToLive { pInt := &ttl return TimeToLive{ @@ -56,10 +41,8 @@ type TimeToLive struct { } type CacheGetRequest struct { - // Name of the cache to get the item from CacheName string - // string ot byte key to be used to retrieve the item. - Key interface{} + Key interface{} } type CacheDeleteRequest struct { diff --git a/momento/cache_responses.go b/momento/cache_responses.go index 61df3ccb..38c01bd0 100644 --- a/momento/cache_responses.go +++ b/momento/cache_responses.go @@ -1,148 +1,93 @@ package momento -import "time" +type SuccessResponse struct{} -// Output of the List caches operation. +// ListCachesResponse Output of the List caches operation. type ListCachesResponse struct { nextToken string caches []CacheInfo } -// Next Page Token returned by Simple Cache Service along with the list of caches. +// NextToken Next Page Token returned by Simple Cache Service along with the list of caches. // If nextToken is present, then this token must be provided in the next call to continue paginating through the list. // This is done by setting this value in ListCachesRequest. func (resp *ListCachesResponse) NextToken() string { return resp.nextToken } -// Returns all caches. +// Caches Returns all caches. func (resp *ListCachesResponse) Caches() []CacheInfo { return resp.caches } -// Output of the Create Signing Key operationn -type CreateSigningKeyResponse struct { - keyId string - endpoint string - key string - expiresAt time.Time -} - -// Returns the Momento signing key's ID -func (resp *CreateSigningKeyResponse) KeyId() string { - return resp.keyId -} - -// Returns the Momento signing key's endpoint -func (resp *CreateSigningKeyResponse) Endpoint() string { - return resp.endpoint -} - -// Returns the Momento signing key's metadata as a JSON string -func (resp *CreateSigningKeyResponse) Key() string { - return resp.key -} - -// Returns the Momento signing key's time in which it expires -func (resp *CreateSigningKeyResponse) ExpiresAt() time.Time { - return resp.expiresAt -} - -// Output of the List Signing Keys operation -type ListSigningKeysResponse struct { - nextToken string - signingKeys []SigningKey -} - -// Next Page Token returned by Simple Cache Service along with the list of Momento signing keys. -// If nextToken is present, then this token must be provided in the next call to continue paginating through the list. -// This is done by setting this value in ListSigningKeysRequest. -func (resp *ListSigningKeysResponse) NextToken() string { - return resp.nextToken -} - -// Returns all Momento signing keys -func (resp *ListSigningKeysResponse) SigningKeys() []SigningKey { - return resp.signingKeys -} - -// Information about the Signing Key -type SigningKey struct { - keyId string - endpoint string - expiresAt time.Time -} - -// Returns the Momento signing key's ID -func (sk SigningKey) KeyId() string { - return sk.keyId -} - -// Returns the Momento signing key's endpoint -func (sk SigningKey) Endpoint() string { - return sk.endpoint -} - -// Returns the Momento signing key's time in which it expires -func (sk SigningKey) ExpiresAt() time.Time { - return sk.expiresAt -} - -// Information about the Cache. +// CacheInfo Information about a Cache. type CacheInfo struct { name string } -// Returns cache's name. +// Name Returns cache's name. func (ci CacheInfo) Name() string { return ci.name } +type cacheGetResponseTypes string + const ( - // Represents cache hit. - HIT string = "HIT" - // Represents cache miss. - MISS string = "MISS" + hit cacheGetResponseTypes = "HIT" + miss cacheGetResponseTypes = "MISS" ) -// Initializes GetCacheResponse to handle gRPC get response. -type GetCacheResponse struct { - value []byte - result string +// CacheGetResponse Base type for possible responses a cache GET can return. Miss || Hit +type CacheGetResponse struct { + responseType cacheGetResponseTypes + value []byte } -// Returns value stored in cache as string if there was Hit. Returns an empty string otherwise. -func (resp *GetCacheResponse) StringValue() string { - if resp.result == HIT { - return string(resp.value) +// IsHit returns true if successfully fetched request item from cache otherwise returns false +func (r *CacheGetResponse) IsHit() bool { + if r.responseType == hit { + return true } - return "" + return false } -// Returns value stored in cache as bytes if there was Hit. Returns nil otherwise. -func (resp *GetCacheResponse) ByteValue() []byte { - if resp.result == HIT { - return resp.value +// AsHit returns CacheGetHitResponse pointer if successfully fetched request item otherwise returns nil +func (r *CacheGetResponse) AsHit() *CacheGetHitResponse { + if r.IsHit() { + return &CacheGetHitResponse{ + value: r.value, + } } return nil } -// Returns get operation result such as HIT or MISS. -func (resp *GetCacheResponse) Result() string { - return resp.result +func (r *CacheGetResponse) IsMiss() bool { + if r.responseType == miss { + return true + } + return false } +func (r *CacheGetResponse) AsMiss() *CacheGetMissResponse { + if r.IsMiss() { + return &CacheGetMissResponse{} + } + return nil +} + +// CacheGetMissResponse Miss Response to a cache Get api request. +type CacheGetMissResponse struct{} -// Initializes SetCacheResponse to handle gRPC set response. -type SetCacheResponse struct { +// CacheGetHitResponse Hit Response to a cache Get api request. +type CacheGetHitResponse struct { value []byte } -// Decodes and returns byte value set in cache to string. -func (resp *SetCacheResponse) StringValue() string { +// StringValue Returns value stored in cache as string if there was Hit. Returns an empty string otherwise. +func (resp *CacheGetHitResponse) StringValue() string { return string(resp.value) } -// Returns byte value set in cache. -func (resp *SetCacheResponse) ByteValue() []byte { +// ByteValue Returns value stored in cache as bytes if there was Hit. Returns nil otherwise. +func (resp *CacheGetHitResponse) ByteValue() []byte { return resp.value } diff --git a/momento/simple_cache_client.go b/momento/simple_cache_client.go index d6387b57..10be29da 100644 --- a/momento/simple_cache_client.go +++ b/momento/simple_cache_client.go @@ -15,18 +15,21 @@ import ( // ScsClient wraps lower level cache control and data operations. type ScsClient interface { + // CreateCache Create a new cache in your Momento account. CreateCache(ctx context.Context, request *CreateCacheRequest) error + // DeleteCache Deletes a cache and all the items within your Momento account. DeleteCache(ctx context.Context, request *DeleteCacheRequest) error + // ListCaches Lists all caches in your Momento account. ListCaches(ctx context.Context, request *ListCachesRequest) (*ListCachesResponse, error) - CreateSigningKey(ctx context.Context, request *CreateSigningKeyRequest) (*CreateSigningKeyResponse, error) - RevokeSigningKey(ctx context.Context, request *RevokeSigningKeyRequest) error - ListSigningKeys(ctx context.Context, request *ListSigningKeysRequest) (*ListSigningKeysResponse, error) - - Set(ctx context.Context, request *CacheSetRequest) (*SetCacheResponse, error) - Get(ctx context.Context, request *CacheGetRequest) (*GetCacheResponse, error) + // Set Stores an item in cache. + Set(ctx context.Context, request *CacheSetRequest) error + // Get Retrieve an item from the cache. Using cache key of type []bytes. + Get(ctx context.Context, request *CacheGetRequest) (*CacheGetResponse, error) + // Delete an item from the cache. Delete(ctx context.Context, request *CacheDeleteRequest) error + // Close Closes the client. Close() } @@ -51,7 +54,6 @@ func NewSimpleCacheClient(props *SimpleCacheClientProps) (ScsClient, error) { } client := &DefaultScsClient{ credentialProvider: props.CredentialProvider, - defaultTtlSeconds: props.DefaultTtlSeconds, } controlClient, err := services.NewScsControlClient(&models.ControlClientRequest{ @@ -77,11 +79,6 @@ func NewSimpleCacheClient(props *SimpleCacheClientProps) (ScsClient, error) { return client, nil } -// CreateCache Create a new cache in your Momento account. -// The following are possible errors that can be returned: -// InvalidArgumentError: If provided CacheName is empty. -// AlreadyExistsError: If cache with the given name already exists. -// ClientSdkError: For any SDK checks that fail. func (c *DefaultScsClient) CreateCache(ctx context.Context, request *CreateCacheRequest) error { err := c.controlClient.CreateCache(ctx, &models.CreateCacheRequest{ CacheName: request.CacheName, @@ -92,11 +89,6 @@ func (c *DefaultScsClient) CreateCache(ctx context.Context, request *CreateCache return nil } -// DeleteCache Deletes a cache and all the items within your Momento account. -// The following are possible errors that can be returned: -// InvalidArgumentError: If provided CacheName is empty. -// NotFoundError: If an attempt is made to delete a MomentoCache that doesn't exist. -// ClientSdkError: For any SDK checks that fail. func (c *DefaultScsClient) DeleteCache(ctx context.Context, request *DeleteCacheRequest) error { err := c.controlClient.DeleteCache(ctx, &models.DeleteCacheRequest{ CacheName: request.CacheName, @@ -107,9 +99,6 @@ func (c *DefaultScsClient) DeleteCache(ctx context.Context, request *DeleteCache return nil } -// ListCaches Lists all caches in your Momento account. -// The following is a possible error that can be returned: -// AuthenticationError: If the provided Momento Auth Token is invalid. func (c *DefaultScsClient) ListCaches(ctx context.Context, request *ListCachesRequest) (*ListCachesResponse, error) { rsp, err := c.controlClient.ListCaches(ctx, &models.ListCachesRequest{ NextToken: request.NextToken, @@ -123,99 +112,21 @@ func (c *DefaultScsClient) ListCaches(ctx context.Context, request *ListCachesRe }, nil } -// CreateSigningKey Creates a Momento signing key in your Momento account -// The following are possible errors that can be returned: -// AuthenticationError: If the provided Momento Auth Token is invalid. -// InvalidArgumentError: If provided TtlMinutes is negative -// ClientSdkError: For any SDK checks that fail. -func (c *DefaultScsClient) CreateSigningKey(ctx context.Context, request *CreateSigningKeyRequest) (*CreateSigningKeyResponse, error) { - rsp, err := c.controlClient.CreateSigningKey(ctx, c.dataClient.Endpoint(), &models.CreateSigningKeyRequest{ - TtlMinutes: request.TtlMinutes, - }) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } - return &CreateSigningKeyResponse{ - keyId: rsp.KeyId, - endpoint: rsp.Endpoint, - key: rsp.Key, - expiresAt: rsp.ExpiresAt, - }, nil -} - -// RevokeSigningKey Revokes a Momento signing key in your Momento account, all tokens signed by which will be invalid -// The following are possible errors that can be returned: -// AuthenticationError: If the provided Momento Auth Token is invalid. -// ClientSdkError: For any SDK checks that fail. -func (c *DefaultScsClient) RevokeSigningKey(ctx context.Context, request *RevokeSigningKeyRequest) error { - err := c.controlClient.RevokeSigningKey(ctx, &models.RevokeSigningKeyRequest{ - KeyId: request.KeyId, - }) - if err != nil { - return convertMomentoSvcErrorToCustomerError(err) - } - return nil -} - -// ListSigningKeys Lists all Momento signing keys in your Momento account -// The following are possible errors that can be returned: -// AuthenticationError: If the provided Momento Auth Token is invalid. -// ClientSdkError: For any SDK checks that fail. -func (c *DefaultScsClient) ListSigningKeys(ctx context.Context, request *ListSigningKeysRequest) (*ListSigningKeysResponse, error) { - rsp, err := c.controlClient.ListSigningKeys(ctx, c.dataClient.Endpoint(), &models.ListSigningKeysRequest{ - NextToken: request.NextToken, - }) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } - return &ListSigningKeysResponse{ - nextToken: rsp.NextToken, - signingKeys: convertSigningKey(rsp.SigningKeys), - }, nil -} - -// Set Stores an item in cache. -// The following are possible errors that can be returned: -// InvalidArgumentError: If provided CacheName is empty. -// NotFoundError: If the cache with the given name doesn't exist. -// InternalServerError: If server encountered an unknown error while trying to store the item. -func (c *DefaultScsClient) Set(ctx context.Context, request *CacheSetRequest) (*SetCacheResponse, error) { +func (c *DefaultScsClient) Set(ctx context.Context, request *CacheSetRequest) error { ttlToUse := c.defaultTtlSeconds if request.TtlSeconds._ttl != nil { ttlToUse = *request.TtlSeconds._ttl } - err := utility.IsKeyValid(request.Key) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } - err = utility.IsValueValid(request.Value) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } - rsp, err := c.dataClient.Set(ctx, &models.CacheSetRequest{ + err := c.dataClient.Set(ctx, &models.CacheSetRequest{ CacheName: request.CacheName, Key: request.Key, Value: request.Value, TtlSeconds: ttlToUse, }) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } - return &SetCacheResponse{ - value: rsp.Value, - }, nil + return convertMomentoSvcErrorToCustomerError(err) } -// Get Retrieve an item from the cache. -// The following are possible errors that can be returned: -// InvalidArgumentError: If provided CacheName is empty. -// NotFoundError: If the cache with the given name doesn't exist. -// InternalServerError: If server encountered an unknown error while trying to store the item. -func (c *DefaultScsClient) Get(ctx context.Context, request *CacheGetRequest) (*GetCacheResponse, error) { - err := utility.IsKeyValid(request.Key) - if err != nil { - return nil, convertMomentoSvcErrorToCustomerError(err) - } +func (c *DefaultScsClient) Get(ctx context.Context, request *CacheGetRequest) (*CacheGetResponse, error) { rsp, err := c.dataClient.Get(ctx, &models.CacheGetRequest{ CacheName: request.CacheName, Key: request.Key, @@ -223,17 +134,9 @@ func (c *DefaultScsClient) Get(ctx context.Context, request *CacheGetRequest) (* if err != nil { return nil, convertMomentoSvcErrorToCustomerError(err) } - return &GetCacheResponse{ - value: rsp.Value, - result: rsp.Result, - }, nil + return convertCacheGetResponse(rsp), nil } -// Delete an item from the cache. -// The following are possible errors that can be returned: -// InvalidArgumentError: If provided CacheName is empty. -// NotFoundError: If the cache with the given name doesn't exist. -// InternalServerError: If server encountered an unknown error while trying to delete the item. func (c *DefaultScsClient) Delete(ctx context.Context, request *CacheDeleteRequest) error { err := utility.IsKeyValid(request.Key) if err != nil { @@ -243,18 +146,31 @@ func (c *DefaultScsClient) Delete(ctx context.Context, request *CacheDeleteReque CacheName: request.CacheName, Key: request.Key, }) - if err != nil { - return convertMomentoSvcErrorToCustomerError(err) - } - return nil + return convertMomentoSvcErrorToCustomerError(err) } -// Close Closes the client. func (c *DefaultScsClient) Close() { defer c.controlClient.Close() defer c.dataClient.Close() } +func convertCacheGetResponse(r *models.CacheGetResponse) *CacheGetResponse { + var response *CacheGetResponse + switch r.Result { + case models.MISS: + response = &CacheGetResponse{ + responseType: miss, + value: r.Value, + } + case models.HIT: + response = &CacheGetResponse{ + responseType: hit, + value: r.Value, + } + } + return response +} + func convertMomentoSvcErrorToCustomerError(e momentoerrors.MomentoSvcErr) MomentoError { if e == nil { return nil @@ -271,15 +187,3 @@ func convertCacheInfo(i []models.CacheInfo) []CacheInfo { } return convertedList } - -func convertSigningKey(sk []models.SigningKey) []SigningKey { - var convertedList []SigningKey - for _, s := range sk { - convertedList = append(convertedList, SigningKey{ - keyId: s.KeyId, - endpoint: s.Endpoint, - expiresAt: s.ExpiresAt, - }) - } - return convertedList -} diff --git a/momento/simple_cache_client_test.go b/momento/simple_cache_client_test.go index e6bd74c0..189a721d 100644 --- a/momento/simple_cache_client_test.go +++ b/momento/simple_cache_client_test.go @@ -41,7 +41,7 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { t.Error(fmt.Errorf("error occurred creating cache err=%+v", err)) } - _, err = client.Set(ctx, &CacheSetRequest{ + err = client.Set(ctx, &CacheSetRequest{ CacheName: cacheName, Key: key, Value: value, @@ -50,7 +50,7 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { t.Errorf("error occurred setting key err=%+v", err) } - _, err = client.Set(ctx, &CacheSetRequest{ + err = client.Set(ctx, &CacheSetRequest{ CacheName: cacheName, Key: uuid.NewString(), Value: value, @@ -69,13 +69,13 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { return } - if getResp.Result() != HIT { - t.Errorf("unexpected result when getting test key got=%+v expected=%+v", getResp.Result(), HIT) + if !getResp.IsHit() { + t.Errorf("unexpected responseType when getting test key got=%+v expected=%+v", getResp, CacheGetHitResponse{}) } - if !bytes.Equal(getResp.ByteValue(), value) { + if !bytes.Equal(getResp.AsHit().ByteValue(), value) { t.Errorf( "set byte value and returned byte value are not equal "+ - "got=%+v expected=%+v", getResp.ByteValue(), value, + "got=%+v expected=%+v", getResp.AsHit().ByteValue(), value, ) } @@ -87,10 +87,10 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { t.Error(err.Error()) } - if existingCacheResp.Result() != MISS { + if !existingCacheResp.IsMiss() { t.Errorf( "key: %s shouldn't exist in %s since it's never set. got=%s", string(key), - testCacheName, existingCacheResp.StringValue(), + testCacheName, existingCacheResp.AsHit().StringValue(), ) } @@ -120,7 +120,7 @@ func TestBasicHappyPathDelete(t *testing.T) { t.Error(fmt.Errorf("error occurred creating cache err=%+v", err)) } - _, err = client.Set(ctx, &CacheSetRequest{ + err = client.Set(ctx, &CacheSetRequest{ CacheName: cacheName, Key: key, Value: value, @@ -138,13 +138,13 @@ func TestBasicHappyPathDelete(t *testing.T) { return } - if getResp.Result() != HIT { - t.Errorf("unexpected result when getting test key got=%+v expected=%+v", getResp.Result(), HIT) + if !getResp.IsHit() { + t.Errorf("unexpected responseType when getting test key got=%+v expected=%+v", getResp, CacheGetHitResponse{}) } - if !bytes.Equal(getResp.ByteValue(), value) { + if !bytes.Equal(getResp.AsHit().ByteValue(), value) { t.Errorf( "set byte value and returned byte value are not equal "+ - "got=%+v expected=%+v", getResp.ByteValue(), value, + "got=%+v expected=%+v", getResp.AsHit().ByteValue(), value, ) } err = client.Delete(ctx, &CacheDeleteRequest{ @@ -162,10 +162,10 @@ func TestBasicHappyPathDelete(t *testing.T) { t.Error(err.Error()) } - if existingCacheResp.Result() != MISS { + if !existingCacheResp.IsMiss() { t.Errorf( - "key: %s shouldn't exist in %s since it's never set. got=%s", string(key), - testCacheName, existingCacheResp.StringValue(), + "key: %s shouldn't exist in %s since it's never set. got=%s", + string(key), testCacheName, existingCacheResp.AsHit().StringValue(), ) } @@ -418,36 +418,6 @@ func TestListCache(t *testing.T) { } } -func TestCreateListRevokeSigningKeys(t *testing.T) { - ctx := context.Background() - client, err := newTestClient(testCredentialProvider) - if err != nil { - t.Error(fmt.Errorf("error occurred setting up client err=%+v", err)) - } - createSigningKeyResponse, err := client.CreateSigningKey(ctx, &CreateSigningKeyRequest{TtlMinutes: 30}) - if err != nil { - t.Errorf("unexpected error occurred on create signing key err=%+v", err) - } - listSigningKeysResponse, err := client.ListSigningKeys(ctx, &ListSigningKeysRequest{}) - if err != nil { - t.Errorf("unexpected error occurred on list signing keys err=%+v", err) - } - var signingKeyFound = false - for _, signingKey := range listSigningKeysResponse.SigningKeys() { - if signingKey.KeyId() == createSigningKeyResponse.KeyId() { - signingKeyFound = true - err = client.RevokeSigningKey(ctx, &RevokeSigningKeyRequest{KeyId: createSigningKeyResponse.KeyId()}) - if err != nil { - t.Errorf("unexpected error on revoke signing key err=%+v", err) - } - } - } - if !signingKeyFound { - t.Errorf("expected to find %s keyId in ListSigningKeysResponse, never found", createSigningKeyResponse.KeyId()) - } - cleanUpClient(client) -} - func TestSetGet(t *testing.T) { ctx := context.Background() tests := map[string]struct { @@ -489,13 +459,13 @@ func TestSetGet(t *testing.T) { t.Parallel() if tt.ttl == 0 { // set string key/value with default ttl - _, err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value}) + err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value}) if err != nil { t.Errorf("unexpected error occurred on setting cache err=%+v", err) } } else { // set string key/value with different ttl - _, err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value, TtlSeconds: TTL(tt.ttl)}) + err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value, TtlSeconds: TTL(tt.ttl)}) if err != nil { t.Errorf("unexpected error occurred on setting cache err=%+v", err) } @@ -505,25 +475,32 @@ func TestSetGet(t *testing.T) { if err != nil { t.Errorf("unexpected error occurred on getting cache err=%+v", err) } - if tt.value != resp.StringValue() { - t.Errorf("set string value=%s is not the same as returned string value=%s", tt.value, resp.StringValue()) + if !resp.IsHit() { + t.Errorf("expected hit but got responseType=%+v", resp) } - if tt.expectedGetResult != resp.Result() { - t.Errorf("expected result=%s but got result=%s", tt.expectedGetResult, resp.Result()) + if tt.value != resp.AsHit().StringValue() { + t.Errorf( + "set string value=%s is not the same as returned string value=%s", + tt.value, resp.AsHit().StringValue(), + ) } } else { - // make sure result it cache miss after ttl is expired + // make sure responseType it cache miss after ttl is expired time.Sleep(5 * time.Second) resp, err := client.Get(ctx, &CacheGetRequest{CacheName: testCacheName, Key: tt.key}) if err != nil { t.Errorf("unexpected error occurred on getting cache err=%+v", err) } - if tt.expectedGetResult != resp.Result() { - t.Errorf("expected result=%s but got result=%s", tt.expectedGetResult, resp.Result()) + if !resp.IsMiss() { + t.Errorf("expected miss but got responseType=%+v", resp) } } // set byte key/value - _, err = client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: []byte(tt.key), Value: []byte(tt.value)}) + err = client.Set(ctx, &CacheSetRequest{ + CacheName: testCacheName, + Key: []byte(tt.key), + Value: []byte(tt.value)}, + ) if err != nil { t.Errorf("unexpected error occurred on setting cache err=%+v", err) } @@ -532,11 +509,11 @@ func TestSetGet(t *testing.T) { if err != nil { t.Errorf("unexpected error occurred on getting cache err=%+v", err) } - if tt.value != string(resp.ByteValue()) { - t.Errorf("set byte value=%s is not the same as returned byte value=%s", tt.value, resp.ByteValue()) + if !resp.IsHit() { + t.Errorf("expected hit but got responseType=%+v", resp) } - if tt.expectedGetResult != resp.Result() { - t.Errorf("expected result=%s but got result=%s", tt.expectedGetResult, resp.Result()) + if tt.value != string(resp.AsHit().ByteValue()) { + t.Errorf("set byte value=%s is not the same as returned byte value=%s", tt.value, resp.AsHit().ByteValue()) } } cleanUpClient(client) @@ -597,7 +574,7 @@ func TestSet(t *testing.T) { tt := tt // for t.Parallel() t.Run(name, func(t *testing.T) { t.Parallel() - _, err := client.Set(ctx, &CacheSetRequest{CacheName: tt.cacheName, Key: tt.key, Value: tt.value}) + err := client.Set(ctx, &CacheSetRequest{CacheName: tt.cacheName, Key: tt.key, Value: tt.value}) if tt.expectedErr != "" && err == nil { t.Errorf("expected error but got none expected=%+v got=%+v", tt.expectedErr, err) } From 4fba34fe849450170e483d97c10d9682757318f8 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:32:30 -0800 Subject: [PATCH 02/10] chore: clean up comments --- internal/utility/utility.go | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/internal/utility/utility.go b/internal/utility/utility.go index 41a724b9..01258c68 100644 --- a/internal/utility/utility.go +++ b/internal/utility/utility.go @@ -35,7 +35,7 @@ func EncodeKey(key interface{}) ([]byte, momentoerrors.MomentoSvcErr) { case []byte: return reflect.ValueOf(key).Bytes(), nil default: - // If target is not string or byte[] then use default gob encoder. + // If target is not string or byte[] then throw error for now. In future should do marshaling here. return nil, momentoerrors.NewMomentoSvcErr( momentoerrors.InvalidArgumentError, "error encoding cache key only support []byte or string currently", @@ -51,27 +51,10 @@ func EncodeValue(value interface{}) ([]byte, momentoerrors.MomentoSvcErr) { case []byte: return reflect.ValueOf(value).Bytes(), nil default: - // If target is not string or byte[] then use default gob encoder. + // If target is not string or byte[] then throw error. In future should do marshaling here. return nil, momentoerrors.NewMomentoSvcErr( momentoerrors.InvalidArgumentError, "error encoding cache value only support []byte or string currently", nil, ) } } - -func DecodeValue(rawBytes []byte, target interface{}) momentoerrors.MomentoSvcErr { - switch target.(type) { - case []byte: - target = rawBytes - case string: - target = string(rawBytes) - default: - // If target is not string or byte[] - return momentoerrors.NewMomentoSvcErr( - momentoerrors.InvalidArgumentError, - "error decoding cache value only support []byte or string currently", - nil, - ) - } - return nil -} From 50ff1d856af3a8b18bcb6e7bb8c00eefd84d75b7 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:39:43 -0800 Subject: [PATCH 03/10] chore: clean up dead code --- momento/cache_responses.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/momento/cache_responses.go b/momento/cache_responses.go index 38c01bd0..5244517a 100644 --- a/momento/cache_responses.go +++ b/momento/cache_responses.go @@ -1,7 +1,5 @@ package momento -type SuccessResponse struct{} - // ListCachesResponse Output of the List caches operation. type ListCachesResponse struct { nextToken string From d2654a8ec37800c72ae6cf9dd0999c5de33baac9 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:53:53 -0800 Subject: [PATCH 04/10] chore: adds docs --- internal/models/requests.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/models/requests.go b/internal/models/requests.go index f9c16ebc..b0fcce9d 100644 --- a/internal/models/requests.go +++ b/internal/models/requests.go @@ -18,8 +18,10 @@ type LocalDataGrpcManagerRequest struct { Endpoint string } type CacheGetRequest struct { + // CacheName Name of the cache to get the item from CacheName string - Key interface{} + // Key string ot []byte key to be used to retrieve the item. + Key interface{} } type ControlClientRequest struct { From 0f5a65869993ea43176896c1387d01c836c6f69f Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:00:47 -0800 Subject: [PATCH 05/10] chore: fix golint errors --- momento/cache_responses.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/momento/cache_responses.go b/momento/cache_responses.go index 5244517a..9d0d501c 100644 --- a/momento/cache_responses.go +++ b/momento/cache_responses.go @@ -43,10 +43,7 @@ type CacheGetResponse struct { // IsHit returns true if successfully fetched request item from cache otherwise returns false func (r *CacheGetResponse) IsHit() bool { - if r.responseType == hit { - return true - } - return false + return r.responseType == hit } // AsHit returns CacheGetHitResponse pointer if successfully fetched request item otherwise returns nil @@ -60,10 +57,7 @@ func (r *CacheGetResponse) AsHit() *CacheGetHitResponse { } func (r *CacheGetResponse) IsMiss() bool { - if r.responseType == miss { - return true - } - return false + return r.responseType == miss } func (r *CacheGetResponse) AsMiss() *CacheGetMissResponse { if r.IsMiss() { From 79028be226703d526e80491403289a5be9b2574c Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+eaddingtonwhite@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:52:18 -0800 Subject: [PATCH 06/10] chore: fix doc typo Co-authored-by: pgautier404 --- internal/models/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/models/requests.go b/internal/models/requests.go index b0fcce9d..c39a5cd7 100644 --- a/internal/models/requests.go +++ b/internal/models/requests.go @@ -20,7 +20,7 @@ type LocalDataGrpcManagerRequest struct { type CacheGetRequest struct { // CacheName Name of the cache to get the item from CacheName string - // Key string ot []byte key to be used to retrieve the item. + // Key string or []byte key to be used to retrieve the item. Key interface{} } From 7d81c58cd1ea74731f578f34c6babbdea4bce465 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:56:22 -0800 Subject: [PATCH 07/10] chore: refactor value helper funcs for get rsp --- momento/cache_responses.go | 8 ++++---- momento/simple_cache_client_test.go | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/momento/cache_responses.go b/momento/cache_responses.go index 9d0d501c..42f6a98f 100644 --- a/momento/cache_responses.go +++ b/momento/cache_responses.go @@ -74,12 +74,12 @@ type CacheGetHitResponse struct { value []byte } -// StringValue Returns value stored in cache as string if there was Hit. Returns an empty string otherwise. -func (resp *CacheGetHitResponse) StringValue() string { +// ValueString Returns value stored in cache as string if there was Hit. Returns an empty string otherwise. +func (resp *CacheGetHitResponse) ValueString() string { return string(resp.value) } -// ByteValue Returns value stored in cache as bytes if there was Hit. Returns nil otherwise. -func (resp *CacheGetHitResponse) ByteValue() []byte { +// ValueByte Returns value stored in cache as bytes if there was Hit. Returns nil otherwise. +func (resp *CacheGetHitResponse) ValueByte() []byte { return resp.value } diff --git a/momento/simple_cache_client_test.go b/momento/simple_cache_client_test.go index 189a721d..2e418abd 100644 --- a/momento/simple_cache_client_test.go +++ b/momento/simple_cache_client_test.go @@ -72,10 +72,10 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { if !getResp.IsHit() { t.Errorf("unexpected responseType when getting test key got=%+v expected=%+v", getResp, CacheGetHitResponse{}) } - if !bytes.Equal(getResp.AsHit().ByteValue(), value) { + if !bytes.Equal(getResp.AsHit().ValueByte(), value) { t.Errorf( "set byte value and returned byte value are not equal "+ - "got=%+v expected=%+v", getResp.AsHit().ByteValue(), value, + "got=%+v expected=%+v", getResp.AsHit().ValueByte(), value, ) } @@ -90,7 +90,7 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { if !existingCacheResp.IsMiss() { t.Errorf( "key: %s shouldn't exist in %s since it's never set. got=%s", string(key), - testCacheName, existingCacheResp.AsHit().StringValue(), + testCacheName, existingCacheResp.AsHit().ValueString(), ) } @@ -141,10 +141,10 @@ func TestBasicHappyPathDelete(t *testing.T) { if !getResp.IsHit() { t.Errorf("unexpected responseType when getting test key got=%+v expected=%+v", getResp, CacheGetHitResponse{}) } - if !bytes.Equal(getResp.AsHit().ByteValue(), value) { + if !bytes.Equal(getResp.AsHit().ValueByte(), value) { t.Errorf( "set byte value and returned byte value are not equal "+ - "got=%+v expected=%+v", getResp.AsHit().ByteValue(), value, + "got=%+v expected=%+v", getResp.AsHit().ValueByte(), value, ) } err = client.Delete(ctx, &CacheDeleteRequest{ @@ -165,7 +165,7 @@ func TestBasicHappyPathDelete(t *testing.T) { if !existingCacheResp.IsMiss() { t.Errorf( "key: %s shouldn't exist in %s since it's never set. got=%s", - string(key), testCacheName, existingCacheResp.AsHit().StringValue(), + string(key), testCacheName, existingCacheResp.AsHit().ValueString(), ) } @@ -478,10 +478,10 @@ func TestSetGet(t *testing.T) { if !resp.IsHit() { t.Errorf("expected hit but got responseType=%+v", resp) } - if tt.value != resp.AsHit().StringValue() { + if tt.value != resp.AsHit().ValueString() { t.Errorf( "set string value=%s is not the same as returned string value=%s", - tt.value, resp.AsHit().StringValue(), + tt.value, resp.AsHit().ValueString(), ) } } else { @@ -512,8 +512,8 @@ func TestSetGet(t *testing.T) { if !resp.IsHit() { t.Errorf("expected hit but got responseType=%+v", resp) } - if tt.value != string(resp.AsHit().ByteValue()) { - t.Errorf("set byte value=%s is not the same as returned byte value=%s", tt.value, resp.AsHit().ByteValue()) + if tt.value != string(resp.AsHit().ValueByte()) { + t.Errorf("set byte value=%s is not the same as returned byte value=%s", tt.value, resp.AsHit().ValueByte()) } } cleanUpClient(client) From b08ed0892b4e6283f76533f752cce56b4ffd3517 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 12:09:53 -0800 Subject: [PATCH 08/10] fix: make all places dealing w/ client side timeout time.Duration --- config/config.go | 6 ++--- internal/services/scs_data_service.go | 34 +++++++++++++-------------- momento/simple_cache_client.go | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/config/config.go b/config/config.go index 447c8016..aca92316 100644 --- a/config/config.go +++ b/config/config.go @@ -14,8 +14,8 @@ type Configuration interface { //with the specified momento.TransportStrategy WithTransportStrategy(transportStrategy TransportStrategy) Configuration - // GetClientSideTimeoutMillis Returns the current configuration options for client side timeout with the Momento service - GetClientSideTimeoutMillis() time.Duration + // GetClientSideTimeout Returns the current configuration options for client side timeout with the Momento service + GetClientSideTimeout() time.Duration // WithClientTimeoutMillis Copy constructor for overriding TransportStrategy client side timeout. Returns a new Configuration object // with the specified momento.TransportStrategy using passed client side timeout. @@ -26,7 +26,7 @@ type SimpleCacheConfiguration struct { transportStrategy TransportStrategy } -func (s *SimpleCacheConfiguration) GetClientSideTimeoutMillis() time.Duration { +func (s *SimpleCacheConfiguration) GetClientSideTimeout() time.Duration { return s.transportStrategy.GetClientSideTimeout() } diff --git a/internal/services/scs_data_service.go b/internal/services/scs_data_service.go index 6f1072b8..604b5889 100644 --- a/internal/services/scs_data_service.go +++ b/internal/services/scs_data_service.go @@ -14,14 +14,14 @@ import ( "google.golang.org/grpc/metadata" ) -const defaultRequestTimeoutSeconds = 5 +const defaultRequestTimeout = 5 * time.Second type ScsDataClient struct { - grpcManager *grpcmanagers.DataGrpcManager - grpcClient pb.ScsClient - defaultTtlSeconds uint64 - requestTimeoutSeconds time.Duration - endpoint string + grpcManager *grpcmanagers.DataGrpcManager + grpcClient pb.ScsClient + defaultTtlSeconds uint64 + requestTimeout time.Duration + endpoint string } func NewScsDataClient(request *models.DataClientRequest) (*ScsDataClient, momentoerrors.MomentoSvcErr) { @@ -32,17 +32,17 @@ func NewScsDataClient(request *models.DataClientRequest) (*ScsDataClient, moment return nil, err } var timeout time.Duration - if request.Configuration.GetClientSideTimeoutMillis() < 1 { - timeout = time.Duration(defaultRequestTimeoutSeconds) * time.Second + if request.Configuration.GetClientSideTimeout() < 1 { + timeout = defaultRequestTimeout } else { - timeout = request.Configuration.GetClientSideTimeoutMillis() * time.Second + timeout = request.Configuration.GetClientSideTimeout() } return &ScsDataClient{ - grpcManager: dataManager, - grpcClient: pb.NewScsClient(dataManager.Conn), - defaultTtlSeconds: uint64(request.DefaultTtlSeconds), - requestTimeoutSeconds: timeout, - endpoint: request.CredentialProvider.GetCacheEndpoint(), + grpcManager: dataManager, + grpcClient: pb.NewScsClient(dataManager.Conn), + defaultTtlSeconds: uint64(request.DefaultTtlSeconds), + requestTimeout: timeout, + endpoint: request.CredentialProvider.GetCacheEndpoint(), }, nil } @@ -76,7 +76,7 @@ func (client *ScsDataClient) Set(ctx context.Context, request *models.CacheSetRe itemTtlMils = uint64(request.TtlSeconds * 1000) } - ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) + ctx, cancel := context.WithTimeout(ctx, client.requestTimeout) defer cancel() _, err := client.grpcClient.Set( metadata.NewOutgoingContext(ctx, createNewMetadata(request.CacheName)), @@ -107,7 +107,7 @@ func (client *ScsDataClient) Get(ctx context.Context, request *models.CacheGetRe } // Execute request - ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) + ctx, cancel := context.WithTimeout(ctx, client.requestTimeout) defer cancel() resp, err := client.grpcClient.Get( metadata.NewOutgoingContext(ctx, createNewMetadata(request.CacheName)), @@ -149,7 +149,7 @@ func (client *ScsDataClient) Delete(ctx context.Context, request *models.CacheDe return svcErr } - ctx, cancel := context.WithTimeout(ctx, client.requestTimeoutSeconds) + ctx, cancel := context.WithTimeout(ctx, client.requestTimeout) defer cancel() _, err := client.grpcClient.Delete( metadata.NewOutgoingContext(ctx, createNewMetadata(request.CacheName)), diff --git a/momento/simple_cache_client.go b/momento/simple_cache_client.go index 10be29da..7d8f591e 100644 --- a/momento/simple_cache_client.go +++ b/momento/simple_cache_client.go @@ -49,7 +49,7 @@ type SimpleCacheClientProps struct { // NewSimpleCacheClient returns a new ScsClient with provided authToken, DefaultTtlSeconds, and opts arguments. func NewSimpleCacheClient(props *SimpleCacheClientProps) (ScsClient, error) { - if props.Configuration.GetClientSideTimeoutMillis() < 1 { + if props.Configuration.GetClientSideTimeout() < 1 { return nil, momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "request timeout must not be 0", nil) } client := &DefaultScsClient{ From 07f9223695d82e5e1dbc6906f86561a144562ded Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 12:18:58 -0800 Subject: [PATCH 09/10] chore: fix some golint errors --- auth/credential_provider.go | 8 ++++---- examples/main.go | 4 ++-- incubating/momento_local_server_test.go | 2 +- incubating/simple_cache_client.go | 1 - momento/cache_requests.go | 2 +- momento/simple_cache_client.go | 15 +++++++-------- momento/simple_cache_client_test.go | 20 ++++++++++---------- 7 files changed, 25 insertions(+), 27 deletions(-) diff --git a/auth/credential_provider.go b/auth/credential_provider.go index 4b244065..d8da6ca8 100644 --- a/auth/credential_provider.go +++ b/auth/credential_provider.go @@ -72,8 +72,8 @@ func NewEnvMomentoTokenProvider(envVariableName string) (CredentialProvider, err const ( momentoControlEndpointPrefix = "control." momentoCacheEndpointPrefix = "cache." - controlEndpointClaimId = "cp" - cacheEndpointClaimId = "c" + controlEndpointClaimID = "cp" + cacheEndpointClaimID = "c" ) func resolve(request *ResolveRequest) (*Endpoints, momentoerrors.MomentoSvcErr) { @@ -93,8 +93,8 @@ func getEndpointsFromToken(authToken string) (*Endpoints, momentoerrors.MomentoS } if claims, ok := token.Claims.(jwt.MapClaims); ok { return &Endpoints{ - ControlEndpoint: reflect.ValueOf(claims[controlEndpointClaimId]).String(), - CacheEndpoint: reflect.ValueOf(claims[cacheEndpointClaimId]).String(), + ControlEndpoint: reflect.ValueOf(claims[controlEndpointClaimID]).String(), + CacheEndpoint: reflect.ValueOf(claims[cacheEndpointClaimID]).String(), }, nil } return nil, momentoerrors.NewMomentoSvcErr( diff --git a/examples/main.go b/examples/main.go index 68674f91..aab72caf 100644 --- a/examples/main.go +++ b/examples/main.go @@ -12,7 +12,7 @@ func main() { var authToken = os.Getenv("MOMENTO_AUTH_TOKEN") const ( cacheName = "cache" - itemDefaultTtlSeconds = 60 + itemDefaultTTLSeconds = 60 ) if authToken == "" { @@ -20,7 +20,7 @@ func main() { } // Initializes Momento - client, err := momento.NewSimpleCacheClient(authToken, itemDefaultTtlSeconds) + client, err := momento.NewSimpleCacheClient(authToken, itemDefaultTTLSeconds) if err != nil { panic(err) } diff --git a/incubating/momento_local_server_test.go b/incubating/momento_local_server_test.go index e3c7c1a9..c4638870 100644 --- a/incubating/momento_local_server_test.go +++ b/incubating/momento_local_server_test.go @@ -53,7 +53,7 @@ func (t TestMomentoLocalServer) Subscribe(req *pb.XSubscriptionRequest, server p if err != nil { return err } - count += 1 + count++ } return nil } diff --git a/incubating/simple_cache_client.go b/incubating/simple_cache_client.go index 3686e54b..a298d5c4 100644 --- a/incubating/simple_cache_client.go +++ b/incubating/simple_cache_client.go @@ -1,5 +1,4 @@ // Package incubating represents experimental packages and clients for Momento - package incubating import ( diff --git a/momento/cache_requests.go b/momento/cache_requests.go index 868f2510..685188e8 100644 --- a/momento/cache_requests.go +++ b/momento/cache_requests.go @@ -24,7 +24,7 @@ type CacheSetRequest struct { Value interface{} // Optional Time to live in cache in seconds. // If not provided, then default TTL for the cache client instance is used. - TtlSeconds TimeToLive + TTLSeconds TimeToLive } // TTL Helper function that returns an initialized TimeToLive containing a pointer to ttl. diff --git a/momento/simple_cache_client.go b/momento/simple_cache_client.go index 7d8f591e..066b85bc 100644 --- a/momento/simple_cache_client.go +++ b/momento/simple_cache_client.go @@ -1,5 +1,4 @@ // Package momento represents API ScsClient interface accessors including control/data operations, errors, operation requests and responses for the SDK. - package momento import ( @@ -38,16 +37,16 @@ type DefaultScsClient struct { credentialProvider auth.CredentialProvider controlClient *services.ScsControlClient dataClient *services.ScsDataClient - defaultTtlSeconds uint32 + defaultTTLSeconds uint32 } type SimpleCacheClientProps struct { Configuration config.Configuration CredentialProvider auth.CredentialProvider - DefaultTtlSeconds uint32 + DefaultTTLSeconds uint32 } -// NewSimpleCacheClient returns a new ScsClient with provided authToken, DefaultTtlSeconds, and opts arguments. +// NewSimpleCacheClient returns a new ScsClient with provided authToken, DefaultTTLSeconds, and opts arguments. func NewSimpleCacheClient(props *SimpleCacheClientProps) (ScsClient, error) { if props.Configuration.GetClientSideTimeout() < 1 { return nil, momentoerrors.NewMomentoSvcErr(momentoerrors.InvalidArgumentError, "request timeout must not be 0", nil) @@ -67,7 +66,7 @@ func NewSimpleCacheClient(props *SimpleCacheClientProps) (ScsClient, error) { dataClient, err := services.NewScsDataClient(&models.DataClientRequest{ CredentialProvider: props.CredentialProvider, Configuration: props.Configuration, - DefaultTtlSeconds: props.DefaultTtlSeconds, + DefaultTtlSeconds: props.DefaultTTLSeconds, }) if err != nil { return nil, convertMomentoSvcErrorToCustomerError(momentoerrors.ConvertSvcErr(err)) @@ -113,9 +112,9 @@ func (c *DefaultScsClient) ListCaches(ctx context.Context, request *ListCachesRe } func (c *DefaultScsClient) Set(ctx context.Context, request *CacheSetRequest) error { - ttlToUse := c.defaultTtlSeconds - if request.TtlSeconds._ttl != nil { - ttlToUse = *request.TtlSeconds._ttl + ttlToUse := c.defaultTTLSeconds + if request.TTLSeconds._ttl != nil { + ttlToUse = *request.TTLSeconds._ttl } err := c.dataClient.Set(ctx, &models.CacheSetRequest{ CacheName: request.CacheName, diff --git a/momento/simple_cache_client_test.go b/momento/simple_cache_client_test.go index 2e418abd..e1a93584 100644 --- a/momento/simple_cache_client_test.go +++ b/momento/simple_cache_client_test.go @@ -21,7 +21,7 @@ var ( ) const ( - defaultTtlSeconds = 3 + defaultTTLSeconds = 3 ) // Basic happy path test - create a cache, operate set/get, and delete the cache @@ -54,7 +54,7 @@ func TestBasicHappyPathSDKFlow(t *testing.T) { CacheName: cacheName, Key: uuid.NewString(), Value: value, - TtlSeconds: TTL(1), + TTLSeconds: TTL(1), }) if err != nil { t.Errorf("error occurred setting key with custom ttl err=%+v", err) @@ -201,19 +201,19 @@ func TestClientInitialization(t *testing.T) { badRequestTimeout := 0 * time.Second tests := map[string]struct { expectedErr string - defaultTtlSeconds uint32 + defaultTTLSeconds uint32 requestTimeout *time.Duration }{ "happy path": { - defaultTtlSeconds: defaultTtlSeconds, + defaultTTLSeconds: defaultTTLSeconds, }, "happy path custom timeout": { - defaultTtlSeconds: defaultTtlSeconds, + defaultTTLSeconds: defaultTTLSeconds, requestTimeout: &testRequestTimeout, }, "test invalid request timeout": { expectedErr: InvalidArgumentError, - defaultTtlSeconds: defaultTtlSeconds, + defaultTTLSeconds: defaultTTLSeconds, requestTimeout: &badRequestTimeout, }, } @@ -224,13 +224,13 @@ func TestClientInitialization(t *testing.T) { c, err := NewSimpleCacheClient(&SimpleCacheClientProps{ Configuration: config.LatestLaptopConfig(), CredentialProvider: testCredentialProvider, - DefaultTtlSeconds: tt.defaultTtlSeconds, + DefaultTTLSeconds: tt.defaultTTLSeconds, }) if tt.requestTimeout != nil { c, err = NewSimpleCacheClient(&SimpleCacheClientProps{ Configuration: config.LatestLaptopConfig().WithClientTimeoutMillis(*tt.requestTimeout), CredentialProvider: testCredentialProvider, - DefaultTtlSeconds: tt.defaultTtlSeconds, + DefaultTTLSeconds: tt.defaultTTLSeconds, }) } if tt.expectedErr != "" && err == nil { @@ -465,7 +465,7 @@ func TestSetGet(t *testing.T) { } } else { // set string key/value with different ttl - err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value, TtlSeconds: TTL(tt.ttl)}) + err := client.Set(ctx, &CacheSetRequest{CacheName: testCacheName, Key: tt.key, Value: tt.value, TTLSeconds: TTL(tt.ttl)}) if err != nil { t.Errorf("unexpected error occurred on setting cache err=%+v", err) } @@ -729,7 +729,7 @@ func newTestClient(credentialProvider auth.CredentialProvider) (ScsClient, error client, err := NewSimpleCacheClient(&SimpleCacheClientProps{ Configuration: config.LatestLaptopConfig(), CredentialProvider: credentialProvider, - DefaultTtlSeconds: defaultTtlSeconds, + DefaultTTLSeconds: defaultTTLSeconds, }) if err != nil { return nil, err From e9615e029004ed864a84ec18e5e0d4cf4ebe9f6a Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Fri, 27 Jan 2023 12:20:24 -0800 Subject: [PATCH 10/10] chore: remove unessarry passback of value on miss --- internal/services/scs_data_service.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/services/scs_data_service.go b/internal/services/scs_data_service.go index 604b5889..a0c4cd0b 100644 --- a/internal/services/scs_data_service.go +++ b/internal/services/scs_data_service.go @@ -125,7 +125,6 @@ func (client *ScsDataClient) Get(ctx context.Context, request *models.CacheGetRe }, nil } else if resp.Result == pb.ECacheResult_Miss { return &models.CacheGetResponse{ - Value: resp.CacheBody, Result: models.MISS, }, nil } else {