mirror of
https://github.com/livekit/livekit.git
synced 2026-11-12 20:49:07 +00:00
rtc: do not send lk.rtc. attributes to clients (#5180)
* rtc: do not send lk.rtc. attributes to other participants Older JS SDKs fire ParticipantAttributesChanged for each new remote participant that carries a server-set lk.rtc. attribute, and some crash on it. Drop those attributes from participant updates and the join response for everyone except the receiver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * rtc: strip lk.rtc. attributes for every receiver Also drop them from the receiver's own info and from the room moved response, so no client sees them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: expect the join request time attribute to stay on the server Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
22df5618f4
commit
8af97efcf8
3 files changed
+51
-9
No files matched your search
@@ -553,6 +553,23 @@ func TestOutOfOrderUpdates(t *testing.T) {
|
||||
require.Equal(t, "second update", sent.GetUpdate().Participants[0].Metadata)
|
||||
}
|
||||
|
||||
func TestServerAttributesNotSent(t *testing.T) {
|
||||
p := newParticipantForTest("test")
|
||||
p.updateState(livekit.ParticipantInfo_JOINED)
|
||||
sink := p.GetResponseSink().(*routingfakes.FakeMessageSink)
|
||||
|
||||
attrs := map[string]string{"lk.rtc.joinRequestTime": "1", "app": "a"}
|
||||
other := &livekit.ParticipantInfo{Sid: "PA_other", Identity: "other", Version: 1, Attributes: attrs}
|
||||
self := &livekit.ParticipantInfo{Sid: string(p.ID()), Identity: "test", Version: 1, Attributes: attrs}
|
||||
require.NoError(t, p.SendParticipantUpdate([]*livekit.ParticipantInfo{other, self}))
|
||||
|
||||
sent := sink.WriteMessageArgsForCall(0).(*livekit.SignalResponse).GetUpdate().Participants
|
||||
require.Equal(t, map[string]string{"app": "a"}, sent[0].Attributes)
|
||||
require.Equal(t, map[string]string{"app": "a"}, sent[1].Attributes)
|
||||
// the shared input is not changed
|
||||
require.Len(t, other.Attributes, 2)
|
||||
}
|
||||
|
||||
func TestRecentlyDisconnectedKeepsUpdateOrder(t *testing.T) {
|
||||
p := newParticipantForTest("test")
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
package rtc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/livekit/protocol/livekit"
|
||||
"github.com/livekit/protocol/logger"
|
||||
@@ -40,9 +42,12 @@ func (p *ParticipantImpl) CloseSignalConnection(reason types.SignallingCloseReas
|
||||
}
|
||||
|
||||
func (p *ParticipantImpl) SendJoinResponse(joinResponse *livekit.JoinResponse) error {
|
||||
joinResponse.Participant = withoutServerAttributes(joinResponse.Participant)
|
||||
|
||||
// keep track of participant updates and versions
|
||||
p.updateLock.Lock()
|
||||
for _, op := range joinResponse.OtherParticipants {
|
||||
for i, op := range joinResponse.OtherParticipants {
|
||||
joinResponse.OtherParticipants[i] = withoutServerAttributes(op)
|
||||
p.updateCache.Add(livekit.ParticipantID(op.Sid), participantUpdateInfo{
|
||||
identity: livekit.ParticipantIdentity(op.Identity),
|
||||
version: op.Version,
|
||||
@@ -118,7 +123,7 @@ func (p *ParticipantImpl) SendParticipantUpdate(participantsToUpdate []*livekit.
|
||||
state: pi.State,
|
||||
updatedAt: time.Now(),
|
||||
})
|
||||
validUpdates = append(validUpdates, pi)
|
||||
validUpdates = append(validUpdates, withoutServerAttributes(pi))
|
||||
}
|
||||
}
|
||||
p.updateLock.Unlock()
|
||||
@@ -126,6 +131,27 @@ func (p *ParticipantImpl) SendParticipantUpdate(participantsToUpdate []*livekit.
|
||||
return p.signaller.WriteMessage(p.signalling.SignalParticipantUpdate(validUpdates))
|
||||
}
|
||||
|
||||
// serverAttributePrefix marks attributes the server sets for its own use; older clients
|
||||
// treat them as attribute changes, so they are never sent to clients.
|
||||
const serverAttributePrefix = "lk.rtc."
|
||||
|
||||
// withoutServerAttributes returns pi, or a copy without server attributes when it has any.
|
||||
// The input is shared across participants, so it is never changed.
|
||||
func withoutServerAttributes(pi *livekit.ParticipantInfo) *livekit.ParticipantInfo {
|
||||
for k := range pi.GetAttributes() {
|
||||
if strings.HasPrefix(k, serverAttributePrefix) {
|
||||
cloned := proto.CloneOf(pi)
|
||||
for ck := range cloned.Attributes {
|
||||
if strings.HasPrefix(ck, serverAttributePrefix) {
|
||||
delete(cloned.Attributes, ck)
|
||||
}
|
||||
}
|
||||
return cloned
|
||||
}
|
||||
}
|
||||
return pi
|
||||
}
|
||||
|
||||
// SendSpeakerUpdate notifies participant changes to speakers. only send members that have changed since last update
|
||||
func (p *ParticipantImpl) SendSpeakerUpdate(speakers []*livekit.SpeakerInfo, force bool) error {
|
||||
if !p.IsReady() {
|
||||
@@ -172,6 +198,10 @@ func (p *ParticipantImpl) sendRequestResponse(requestResponse *livekit.RequestRe
|
||||
}
|
||||
|
||||
func (p *ParticipantImpl) SendRoomMovedResponse(roomMovedResponse *livekit.RoomMovedResponse) error {
|
||||
roomMovedResponse.Participant = withoutServerAttributes(roomMovedResponse.Participant)
|
||||
for i, op := range roomMovedResponse.OtherParticipants {
|
||||
roomMovedResponse.OtherParticipants[i] = withoutServerAttributes(op)
|
||||
}
|
||||
return p.signaller.WriteMessage(p.signalling.SignalRoomMovedResponse(roomMovedResponse))
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
@@ -865,12 +864,8 @@ func TestSingleNodeAttributes(t *testing.T) {
|
||||
if pubRemote == nil {
|
||||
return "could not find remote publisher"
|
||||
}
|
||||
attrs := maps.Clone(pubRemote.Attributes)
|
||||
// the server stamps when it received the join request
|
||||
if attrs[livekit.AttrRTCJoinRequestTime] == "" {
|
||||
return fmt.Sprintf("did not receive the join request time: %v", attrs)
|
||||
}
|
||||
delete(attrs, livekit.AttrRTCJoinRequestTime)
|
||||
// the server-set join request time is not sent to clients
|
||||
attrs := pubRemote.Attributes
|
||||
if !reflect.DeepEqual(attrs, map[string]string{
|
||||
"a": "0",
|
||||
"b": "2",
|
||||
|
||||
Reference in new issue
Block a user