istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/util/protoconv/protoconv.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package protoconv 16 17 import ( 18 "fmt" 19 20 udpa "github.com/cncf/xds/go/udpa/type/v1" 21 "google.golang.org/protobuf/encoding/prototext" 22 "google.golang.org/protobuf/proto" 23 "google.golang.org/protobuf/types/known/anypb" 24 "google.golang.org/protobuf/types/known/structpb" 25 26 "istio.io/istio/pilot/pkg/features" 27 "istio.io/istio/pkg/log" 28 ) 29 30 // MessageToAnyWithError converts from proto message to proto Any 31 func MessageToAnyWithError(msg proto.Message) (*anypb.Any, error) { 32 b, err := marshal(msg) 33 if err != nil { 34 return nil, err 35 } 36 return &anypb.Any{ 37 // nolint: staticcheck 38 TypeUrl: "type.googleapis.com/" + string(msg.ProtoReflect().Descriptor().FullName()), 39 Value: b, 40 }, nil 41 } 42 43 func marshal(msg proto.Message) ([]byte, error) { 44 if features.EnableVtprotobuf { 45 if vt, ok := msg.(vtStrictMarshal); ok { 46 // Attempt to use more efficient implementation 47 // "Strict" is the equivalent to Deterministic=true below 48 return vt.MarshalVTStrict() 49 } 50 } 51 // If not available, fallback to normal implementation 52 return proto.MarshalOptions{Deterministic: true}.Marshal(msg) 53 } 54 55 // MessageToAny converts from proto message to proto Any 56 func MessageToAny(msg proto.Message) *anypb.Any { 57 out, err := MessageToAnyWithError(msg) 58 if err != nil { 59 log.Error(fmt.Sprintf("error marshaling Any %s: %v", prototext.Format(msg), err)) 60 return nil 61 } 62 return out 63 } 64 65 func TypedStructWithFields(typeURL string, fields map[string]interface{}) *anypb.Any { 66 value, err := structpb.NewStruct(fields) 67 if err != nil { 68 log.Error(fmt.Sprintf("error marshaling struct %s: %v", typeURL, err)) 69 } 70 return MessageToAny(&udpa.TypedStruct{ 71 TypeUrl: typeURL, 72 Value: value, 73 }) 74 } 75 76 func SilentlyUnmarshalAny[T any](a *anypb.Any) *T { 77 res, err := UnmarshalAny[T](a) 78 if err != nil { 79 return nil 80 } 81 return res 82 } 83 84 func UnmarshalAny[T any](a *anypb.Any) (*T, error) { 85 dst := any(new(T)).(proto.Message) 86 if err := a.UnmarshalTo(dst); err != nil { 87 return nil, fmt.Errorf("failed to unmarshal to %T: %v", dst, err) 88 } 89 return any(dst).(*T), nil 90 } 91 92 // https://github.com/planetscale/vtprotobuf#available-features 93 type vtStrictMarshal interface { 94 MarshalVTStrict() ([]byte, error) 95 }