mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 21:35:52 +00:00
5698353652
Add some generic type hook wrappers to first decode the data There seems to be a pattern for Validation, Mutation and Write Authorization hooks where they first need to decode the Any data before doing the domain specific work. This PR introduces 3 new functions to generate wrappers around the other hooks to pre-decode the data into a DecodedResource and pass that in instead of the original pbresource.Resource. This PR also updates the various catalog data types to use the new hook generators.
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package resource
|
|
|
|
import (
|
|
"context"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/hashicorp/consul/proto-public/pbresource"
|
|
)
|
|
|
|
// DecodedResource is a generic holder to contain an original Resource and its
|
|
// decoded contents.
|
|
type DecodedResource[T proto.Message] struct {
|
|
// Embedding here allows us to shadow the Resource.Data Any field to fake out
|
|
// using a single struct with inlined data.
|
|
*pbresource.Resource
|
|
Data T
|
|
}
|
|
|
|
func (d *DecodedResource[T]) GetResource() *pbresource.Resource {
|
|
if d == nil {
|
|
return nil
|
|
}
|
|
|
|
return d.Resource
|
|
}
|
|
|
|
func (d *DecodedResource[T]) GetData() T {
|
|
if d == nil {
|
|
var zero T
|
|
return zero
|
|
}
|
|
|
|
return d.Data
|
|
}
|
|
|
|
// Decode will generically decode the provided resource into a 2-field
|
|
// structure that holds onto the original Resource and the decoded contents.
|
|
//
|
|
// Returns an ErrDataParse on unmarshalling errors.
|
|
func Decode[T proto.Message](res *pbresource.Resource) (*DecodedResource[T], error) {
|
|
var zero T
|
|
data := zero.ProtoReflect().New().Interface().(T)
|
|
// check that there is data to unmarshall
|
|
if res.Data != nil {
|
|
if err := res.Data.UnmarshalTo(data); err != nil {
|
|
return nil, NewErrDataParse(data, err)
|
|
}
|
|
}
|
|
return &DecodedResource[T]{
|
|
Resource: res,
|
|
Data: data,
|
|
}, nil
|
|
}
|
|
|
|
// GetDecodedResource will generically read the requested resource using the
|
|
// client and either return nil on a NotFound or decode the response value.
|
|
func GetDecodedResource[T proto.Message](ctx context.Context, client pbresource.ResourceServiceClient, id *pbresource.ID) (*DecodedResource[T], error) {
|
|
rsp, err := client.Read(ctx, &pbresource.ReadRequest{Id: id})
|
|
switch {
|
|
case status.Code(err) == codes.NotFound:
|
|
return nil, nil
|
|
case err != nil:
|
|
return nil, err
|
|
}
|
|
return Decode[T](rsp.Resource)
|
|
}
|