diff --git a/bindings/http/http.go b/bindings/http/http.go index 853deea602..521a52d1d7 100644 --- a/bindings/http/http.go +++ b/bindings/http/http.go @@ -30,8 +30,6 @@ import ( "strings" "time" - "k8s.io/apimachinery/pkg/api/resource" - "github.com/dapr/components-contrib/bindings" "github.com/dapr/components-contrib/internal/utils" "github.com/dapr/components-contrib/metadata" @@ -74,7 +72,7 @@ type httpMetadata struct { // This can either be an integer which is interpreted in bytes, or a string with an added unit such as Mi. // A value <= 0 means no limit. // Default: 100MB - MaxResponseBodySize *resource.Quantity `mapstructure:"maxResponseBodySize"` + MaxResponseBodySize metadata.ResourceQuantity `mapstructure:"maxResponseBodySize"` maxResponseBodySizeBytes int64 } @@ -89,7 +87,7 @@ func NewHTTP(logger logger.Logger) bindings.OutputBinding { // Init performs metadata parsing. func (h *HTTPSource) Init(_ context.Context, meta bindings.Metadata) error { h.metadata = httpMetadata{ - MaxResponseBodySize: resource.NewQuantity(defaultMaxResponseBodySizeBytes, resource.BinarySI), + MaxResponseBodySize: metadata.NewResourceQuantityBytes(defaultMaxResponseBodySizeBytes), } err := metadata.DecodeMetadata(meta.Properties, &h.metadata) if err != nil { @@ -113,12 +111,9 @@ func (h *HTTPSource) Init(_ context.Context, meta bindings.Metadata) error { } } - if h.metadata.MaxResponseBodySize != nil && !h.metadata.MaxResponseBodySize.IsZero() { - val, ok := h.metadata.MaxResponseBodySize.AsInt64() - if !ok { - return fmt.Errorf("value for maxResponseBodySize cannot be converted to integer: %v", h.metadata.MaxResponseBodySize) - } - h.metadata.maxResponseBodySizeBytes = val + h.metadata.maxResponseBodySizeBytes, err = h.metadata.MaxResponseBodySize.GetBytes() + if err != nil { + return fmt.Errorf("invalid value for maxResponseBodySize: %w", err) } // See guidance on proper HTTP client settings here: diff --git a/metadata/resource.go b/metadata/resource.go index 33d3249e2b..7c5a17a095 100644 --- a/metadata/resource.go +++ b/metadata/resource.go @@ -22,9 +22,37 @@ import ( "k8s.io/apimachinery/pkg/api/resource" ) -func toResourceHookFunc() mapstructure.DecodeHookFunc { - quantityType := reflect.TypeOf(resource.Quantity{}) - quantityPtrType := reflect.TypeOf(&resource.Quantity{}) +// ResourceQuantity contains a quantity for a resource, such as data size. +// This extends the resource.Quantity struct from k8s.io/apimachinery to add some utility methods specific for Dapr. +type ResourceQuantity struct { + resource.Quantity +} + +// NewResourceQuantityBytes returns a new ResourceQuantity with a default value in bytes. +func NewResourceQuantityBytes(defaultBytesValue int64) ResourceQuantity { + return ResourceQuantity{ + Quantity: *resource.NewQuantity(defaultBytesValue, resource.BinarySI), + } +} + +// GetBytes returns the number of bytes in the quantity. +// Note: this operation is expensive, so it's recommended to cache the returned value. +func (q *ResourceQuantity) GetBytes() (int64, error) { + if q == nil || q.IsZero() { + return 0, nil + } + + val, ok := q.AsInt64() + if !ok { + return 0, fmt.Errorf("cannot get bytes from resource quantity value '%v'", q) + } + + return val, nil +} + +func toResourceQuantityHookFunc() mapstructure.DecodeHookFunc { + quantityType := reflect.TypeOf(ResourceQuantity{}) + quantityPtrType := reflect.TypeOf(&ResourceQuantity{}) return func( f reflect.Type, @@ -55,9 +83,10 @@ func toResourceHookFunc() mapstructure.DecodeHookFunc { } // Return a pointer if desired + res := ResourceQuantity{Quantity: q} if isPtr { - return &q, nil + return &res, nil } - return q, nil + return res, nil } } diff --git a/metadata/utils.go b/metadata/utils.go index bda37ce118..058617ea84 100644 --- a/metadata/utils.go +++ b/metadata/utils.go @@ -170,7 +170,7 @@ func DecodeMetadata(input any, result any) error { toTimeDurationHookFunc(), toTruthyBoolHookFunc(), toStringArrayHookFunc(), - toResourceHookFunc(), + toResourceQuantityHookFunc(), ), Metadata: nil, Result: result, diff --git a/metadata/utils_test.go b/metadata/utils_test.go index f5802aa47f..7273fa8c58 100644 --- a/metadata/utils_test.go +++ b/metadata/utils_test.go @@ -21,7 +21,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" - "k8s.io/apimachinery/pkg/api/resource" ) func TestIsRawPayload(t *testing.T) { @@ -241,13 +240,13 @@ func TestMetadataDecode(t *testing.T) { t.Run("Test metadata decode hook for resources", func(t *testing.T) { type testMetadata struct { - ResourceValue1 resource.Quantity - ResourceValue2 resource.Quantity - ResourceValue3 resource.Quantity - ResourceValue4 resource.Quantity - ResourceValueNotProvided resource.Quantity - ResourceValuePtr *resource.Quantity - ResourceValuePtrNotProvided *resource.Quantity + ResourceValue1 ResourceQuantity + ResourceValue2 ResourceQuantity + ResourceValue3 ResourceQuantity + ResourceValue4 ResourceQuantity + ResourceValueNotProvided ResourceQuantity + ResourceValuePtr *ResourceQuantity + ResourceValuePtrNotProvided *ResourceQuantity } var m testMetadata