Compare commits
4 Commits
main
...
video-to-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5186108a6 | ||
|
|
32f84ffd84 | ||
|
|
4f1c06741a | ||
|
|
5ecdf3bc87 |
5
.changeset/short-deer-eat.md
Normal file
5
.changeset/short-deer-eat.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"github.com/livekit/protocol": patch
|
||||
---
|
||||
|
||||
support parsing rtc as grant in addition to video
|
||||
@@ -15,6 +15,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"maps"
|
||||
"strings"
|
||||
@@ -245,6 +246,58 @@ func (c *ClaimGrants) MarshalLogObject(e zapcore.ObjectEncoder) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// claimGrantsJSON is used for JSON marshaling/unmarshaling to support both
|
||||
// "video" (legacy) and "rtc" (new) field names for VideoGrant.
|
||||
// This enables backwards compatibility during the migration from VideoGrant to RTCGrant.
|
||||
type claimGrantsJSON struct {
|
||||
Identity string `json:"identity,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
KindDetails []string `json:"kindDetails,omitempty"`
|
||||
Video *VideoGrant `json:"video,omitempty"`
|
||||
RTC *VideoGrant `json:"rtc,omitempty"`
|
||||
SIP *SIPGrant `json:"sip,omitempty"`
|
||||
Agent *AgentGrant `json:"agent,omitempty"`
|
||||
Inference *InferenceGrant `json:"inference,omitempty"`
|
||||
Observability *ObservabilityGrant `json:"observability,omitempty"`
|
||||
RoomConfig *RoomConfiguration `json:"roomConfig,omitempty"`
|
||||
RoomPreset string `json:"roomPreset,omitempty"`
|
||||
Sha256 string `json:"sha256,omitempty"`
|
||||
Metadata string `json:"metadata,omitempty"`
|
||||
Attributes map[string]string `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ClaimGrants) UnmarshalJSON(data []byte) error {
|
||||
var j claimGrantsJSON
|
||||
if err := json.Unmarshal(data, &j); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Identity = j.Identity
|
||||
c.Name = j.Name
|
||||
c.Kind = j.Kind
|
||||
c.KindDetails = j.KindDetails
|
||||
c.SIP = j.SIP
|
||||
c.Agent = j.Agent
|
||||
c.Inference = j.Inference
|
||||
c.Observability = j.Observability
|
||||
c.RoomConfig = j.RoomConfig
|
||||
c.RoomPreset = j.RoomPreset
|
||||
c.Sha256 = j.Sha256
|
||||
c.Metadata = j.Metadata
|
||||
c.Attributes = j.Attributes
|
||||
|
||||
// Support both "video" (legacy) and "rtc" (new) field names.
|
||||
// If both are present, "rtc" takes precedence.
|
||||
if j.RTC != nil {
|
||||
c.Video = j.RTC
|
||||
} else {
|
||||
c.Video = j.Video
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
type VideoGrant struct {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -159,6 +160,120 @@ func TestGrants(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestClaimGrantsVideoRTCCompat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("unmarshal with video field", func(t *testing.T) {
|
||||
jsonData := `{"identity":"user1","video":{"roomJoin":true,"room":"test-room","canPublish":true}}`
|
||||
|
||||
var grants ClaimGrants
|
||||
err := json.Unmarshal([]byte(jsonData), &grants)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "user1", grants.Identity)
|
||||
require.NotNil(t, grants.Video)
|
||||
require.True(t, grants.Video.RoomJoin)
|
||||
require.Equal(t, "test-room", grants.Video.Room)
|
||||
require.True(t, grants.Video.GetCanPublish())
|
||||
})
|
||||
|
||||
t.Run("unmarshal with rtc field", func(t *testing.T) {
|
||||
jsonData := `{"identity":"user2","rtc":{"roomJoin":true,"room":"rtc-room","canSubscribe":false}}`
|
||||
|
||||
var grants ClaimGrants
|
||||
err := json.Unmarshal([]byte(jsonData), &grants)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "user2", grants.Identity)
|
||||
require.NotNil(t, grants.Video)
|
||||
require.True(t, grants.Video.RoomJoin)
|
||||
require.Equal(t, "rtc-room", grants.Video.Room)
|
||||
require.False(t, grants.Video.GetCanSubscribe())
|
||||
})
|
||||
|
||||
t.Run("unmarshal with both video and rtc fields prefers rtc", func(t *testing.T) {
|
||||
jsonData := `{"identity":"user3","video":{"room":"video-room"},"rtc":{"room":"rtc-room"}}`
|
||||
|
||||
var grants ClaimGrants
|
||||
err := json.Unmarshal([]byte(jsonData), &grants)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, grants.Video)
|
||||
require.Equal(t, "rtc-room", grants.Video.Room, "rtc field should take precedence over video")
|
||||
})
|
||||
|
||||
t.Run("marshal outputs video field", func(t *testing.T) {
|
||||
grants := &ClaimGrants{
|
||||
Identity: "user4",
|
||||
Video: &VideoGrant{
|
||||
RoomJoin: true,
|
||||
Room: "my-room",
|
||||
},
|
||||
}
|
||||
|
||||
data, err := json.Marshal(grants)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the output contains "video" not "rtc"
|
||||
var rawMap map[string]interface{}
|
||||
err = json.Unmarshal(data, &rawMap)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, rawMap, "video", "marshaled JSON should contain 'video' field")
|
||||
require.NotContains(t, rawMap, "rtc", "marshaled JSON should not contain 'rtc' field")
|
||||
})
|
||||
|
||||
t.Run("roundtrip with video field preserves data", func(t *testing.T) {
|
||||
original := &ClaimGrants{
|
||||
Identity: "user5",
|
||||
Name: "Test User",
|
||||
Video: &VideoGrant{
|
||||
RoomJoin: true,
|
||||
Room: "test-room",
|
||||
RoomCreate: true,
|
||||
},
|
||||
SIP: &SIPGrant{Admin: true},
|
||||
}
|
||||
|
||||
data, err := json.Marshal(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
var decoded ClaimGrants
|
||||
err = json.Unmarshal(data, &decoded)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, original.Identity, decoded.Identity)
|
||||
require.Equal(t, original.Name, decoded.Name)
|
||||
require.Equal(t, original.Video.RoomJoin, decoded.Video.RoomJoin)
|
||||
require.Equal(t, original.Video.Room, decoded.Video.Room)
|
||||
require.Equal(t, original.Video.RoomCreate, decoded.Video.RoomCreate)
|
||||
require.Equal(t, original.SIP.Admin, decoded.SIP.Admin)
|
||||
})
|
||||
|
||||
t.Run("unmarshal with all grant types via rtc", func(t *testing.T) {
|
||||
jsonData := `{
|
||||
"identity": "agent1",
|
||||
"kind": "agent",
|
||||
"rtc": {"roomJoin": true, "room": "agent-room", "agent": true},
|
||||
"sip": {"admin": true},
|
||||
"agent": {"admin": true},
|
||||
"inference": {"perform": true}
|
||||
}`
|
||||
|
||||
var grants ClaimGrants
|
||||
err := json.Unmarshal([]byte(jsonData), &grants)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "agent1", grants.Identity)
|
||||
require.Equal(t, "agent", grants.Kind)
|
||||
require.NotNil(t, grants.Video)
|
||||
require.True(t, grants.Video.RoomJoin)
|
||||
require.Equal(t, "agent-room", grants.Video.Room)
|
||||
require.True(t, grants.Video.Agent)
|
||||
require.NotNil(t, grants.SIP)
|
||||
require.True(t, grants.SIP.Admin)
|
||||
require.NotNil(t, grants.Agent)
|
||||
require.True(t, grants.Agent.Admin)
|
||||
require.NotNil(t, grants.Inference)
|
||||
require.True(t, grants.Inference.Perform)
|
||||
})
|
||||
}
|
||||
|
||||
func TestParticipantKind(t *testing.T) {
|
||||
const kindMin, kindMax = livekit.ParticipantInfo_STANDARD, livekit.ParticipantInfo_AGENT
|
||||
for k := kindMin; k <= kindMax; k++ {
|
||||
|
||||
Reference in New Issue
Block a user