Files
protocol/utils/proto.go
Raja Subramanian 4c2f9b22da Utility to clone a proto with redaction. (#1316)
* Utility to clone a proto with redaction.

Would be nice to set size of redacted field back into the message, but
that does not work for all types.

* generated protobuf

* Recursive proto redact.

* generated protobuf

* remove redact_format from TrackInfo name

* generated protobuf

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-20 12:55:00 +05:30

78 lines
1.8 KiB
Go

// Copyright 2023 LiveKit, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package utils
import (
"github.com/livekit/protocol/livekit/logger"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
func CloneProto[T proto.Message](m T) T {
return proto.Clone(m).(T)
}
func CloneProtoSlice[T proto.Message](ms []T) []T {
cs := make([]T, len(ms))
for i := range ms {
cs[i] = CloneProto(ms[i])
}
return cs
}
func CloneProtoRedacted[T proto.Message](m T) T {
clone := proto.Clone(m).(T)
var redact func(msg proto.Message)
redact = func(msg proto.Message) {
if msg == nil {
return
}
reflected := msg.ProtoReflect()
reflected.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if proto.HasExtension(fd.Options(), logger.E_Redact) {
reflected.Clear(fd)
}
if fd.Kind() == protoreflect.MessageKind {
switch {
case fd.IsList():
src := v.List()
for i := 0; i < src.Len(); i++ {
elem := src.Get(i).Message().Interface()
redact(elem)
}
case fd.IsMap():
src := v.Map()
src.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
elem := val.Message().Interface()
redact(elem)
return true
})
default:
redact(v.Message().Interface())
}
}
return true
})
}
redact(clone)
return clone
}