github.com/ava-labs/avalanchego@v1.11.11/vms/rpcchainvm/grpcutils/util.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package grpcutils
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"time"
    10  
    11  	"google.golang.org/grpc/status"
    12  	"google.golang.org/protobuf/proto"
    13  	"google.golang.org/protobuf/types/known/anypb"
    14  
    15  	httppb "github.com/ava-labs/avalanchego/proto/pb/http"
    16  	spb "google.golang.org/genproto/googleapis/rpc/status"
    17  	tspb "google.golang.org/protobuf/types/known/timestamppb"
    18  )
    19  
    20  // GetGRPCErrorFromHTTPResponse takes an HandleSimpleHTTPResponse as input and returns a gRPC error.
    21  func GetGRPCErrorFromHTTPResponse(resp *httppb.HandleSimpleHTTPResponse) error {
    22  	a, err := anypb.New(resp)
    23  	if err != nil {
    24  		return err
    25  	}
    26  
    27  	return status.ErrorProto(&spb.Status{
    28  		Code:    resp.Code,
    29  		Message: string(resp.Body),
    30  		Details: []*anypb.Any{a},
    31  	})
    32  }
    33  
    34  // GetHTTPResponseFromError takes an gRPC error as input and returns a gRPC
    35  // HandleSimpleHTTPResponse.
    36  func GetHTTPResponseFromError(err error) (*httppb.HandleSimpleHTTPResponse, bool) {
    37  	s, ok := status.FromError(err)
    38  	if !ok {
    39  		return nil, false
    40  	}
    41  
    42  	status := s.Proto()
    43  	if len(status.Details) != 1 {
    44  		return nil, false
    45  	}
    46  
    47  	var resp httppb.HandleSimpleHTTPResponse
    48  	if err := anypb.UnmarshalTo(status.Details[0], &resp, proto.UnmarshalOptions{}); err != nil {
    49  		return nil, false
    50  	}
    51  
    52  	return &resp, true
    53  }
    54  
    55  // GetHTTPHeader takes an http.Header as input and returns a slice of Header.
    56  func GetHTTPHeader(hs http.Header) []*httppb.Element {
    57  	result := make([]*httppb.Element, 0, len(hs))
    58  	for k, vs := range hs {
    59  		result = append(result, &httppb.Element{
    60  			Key:    k,
    61  			Values: vs,
    62  		})
    63  	}
    64  	return result
    65  }
    66  
    67  // MergeHTTPHeader takes a slice of Header and merges with http.Header map.
    68  func MergeHTTPHeader(hs []*httppb.Element, header http.Header) {
    69  	for _, h := range hs {
    70  		header[h.Key] = h.Values
    71  	}
    72  }
    73  
    74  // TimestampAsTime validates timestamppb timestamp and returns time.Time.
    75  func TimestampAsTime(ts *tspb.Timestamp) (time.Time, error) {
    76  	if err := ts.CheckValid(); err != nil {
    77  		return time.Time{}, fmt.Errorf("invalid timestamp: %w", err)
    78  	}
    79  	return ts.AsTime(), nil
    80  }
    81  
    82  // TimestampFromTime converts time.Time to a timestamppb timestamp.
    83  func TimestampFromTime(time time.Time) *tspb.Timestamp {
    84  	return tspb.New(time)
    85  }
    86  
    87  // EnsureValidResponseCode ensures that the response code is valid otherwise it returns 500.
    88  func EnsureValidResponseCode(code int) int {
    89  	// Response code outside of this range is invalid and could panic.
    90  	// ref. https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    91  	if code < 100 || code > 599 {
    92  		return http.StatusInternalServerError
    93  	}
    94  	return code
    95  }