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