go-sdk/client/invoke.go

139 lines
3.9 KiB
Go

package client
import (
"context"
"encoding/json"
"strings"
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
anypb "github.com/golang/protobuf/ptypes/any"
"github.com/pkg/errors"
)
// DataContent the service invocation content
type DataContent struct {
// Data is the input data
Data []byte
// ContentType is the type of the data content
ContentType string
}
func (c *GRPCClient) invokeServiceWithRequest(ctx context.Context, req *pb.InvokeServiceRequest) (out []byte, err error) {
if req == nil {
return nil, errors.New("nil request")
}
resp, err := c.protoClient.InvokeService(c.withAuthToken(ctx), req)
if err != nil {
return nil, err
}
// allow for service to not return any value
if resp != nil && resp.GetData() != nil {
out = resp.GetData().Value
return
}
out = nil
return
}
func queryAndVerbToHTTPExtension(query string, verb string) *v1.HTTPExtension {
if v, ok := v1.HTTPExtension_Verb_value[strings.ToUpper(verb)]; ok {
return &v1.HTTPExtension{Verb: v1.HTTPExtension_Verb(v), Querystring: query}
}
return &v1.HTTPExtension{Verb: v1.HTTPExtension_NONE}
}
func hasRequiredInvokeArgs(appID, methodName, verb string) error {
if appID == "" {
return errors.New("appID")
}
if methodName == "" {
return errors.New("methodName")
}
if verb == "" {
return errors.New("verb")
}
return nil
}
// InvokeMethod invokes service without raw data ([]byte).
func (c *GRPCClient) InvokeMethod(ctx context.Context, appID, methodName, verb string) (out []byte, err error) {
if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
return nil, errors.Wrap(err, "missing required parameter")
}
method, query := extractMethodAndQuery(methodName)
req := &pb.InvokeServiceRequest{
Id: appID,
Message: &v1.InvokeRequest{
Method: method,
HttpExtension: queryAndVerbToHTTPExtension(query, verb),
},
}
return c.invokeServiceWithRequest(ctx, req)
}
// InvokeMethodWithContent invokes service with content (data + content type).
func (c *GRPCClient) InvokeMethodWithContent(ctx context.Context, appID, methodName, verb string, content *DataContent) (out []byte, err error) {
if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
return nil, errors.Wrap(err, "missing required parameter")
}
if content == nil {
return nil, errors.New("content required")
}
method, query := extractMethodAndQuery(methodName)
req := &pb.InvokeServiceRequest{
Id: appID,
Message: &v1.InvokeRequest{
Method: method,
Data: &anypb.Any{Value: content.Data},
ContentType: content.ContentType,
HttpExtension: queryAndVerbToHTTPExtension(query, verb),
},
}
return c.invokeServiceWithRequest(ctx, req)
}
// InvokeMethodWithCustomContent invokes service with custom content (struct + content type).
func (c *GRPCClient) InvokeMethodWithCustomContent(ctx context.Context, appID, methodName, verb string, contentType string, content interface{}) (out []byte, err error) {
if err := hasRequiredInvokeArgs(appID, methodName, verb); err != nil {
return nil, errors.Wrap(err, "missing required parameter")
}
if contentType == "" {
return nil, errors.New("content type required")
}
if content == nil {
return nil, errors.New("content required")
}
contentData, err := json.Marshal(content)
if err != nil {
return nil, errors.WithMessage(err, "error serializing input struct")
}
method, query := extractMethodAndQuery(methodName)
req := &pb.InvokeServiceRequest{
Id: appID,
Message: &v1.InvokeRequest{
Method: method,
Data: &anypb.Any{Value: contentData},
ContentType: contentType,
HttpExtension: queryAndVerbToHTTPExtension(query, verb),
},
}
return c.invokeServiceWithRequest(ctx, req)
}
func extractMethodAndQuery(name string) (method, query string) {
splitStr := strings.SplitN(name, "?", 2)
method = splitStr[0]
if len(splitStr) == 2 {
query = splitStr[1]
}
return
}