From 835ef1b353e02d607ae7f2f25158ea705ea6379e Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Wed, 3 Jun 2026 19:50:19 +0530 Subject: [PATCH 01/25] Metrics for participant active, i. e. fully established. (#4557) * Metrics for participant active, i. e. fully established. - Egress stub for v2 API - Fix the participant canceled counter :facepalm: - Add active counter -> this is increment when a participant becomes active, i. e. primary peer connection established. Can be used to monitor node wise connection establishment issues. - Add singnalling validation fail counter. With this, we have - signalling validation fail - signalling failed --> this is when the `startSession` fails - signalling connected -> signalling is succesful and can send back joinResponse to client on media connection side - rtc_init -> start - rtc_connected -> participant session created (joined) - rtc_active -> primay peer connection established - rtc_canceled -> could not proceed with RTC connection due to not being able to resume. * signalling counters deps * revert pion/webrtc to 4.2.12 to get SCTP without interleaving * go back to pion/webrtc 4.2.11 and sctp 1.9.5 --- go.mod | 68 +++++++------- go.sum | 134 ++++++++++++++-------------- pkg/service/egress.go | 4 + pkg/service/rtcservice.go | 1 + pkg/telemetry/events.go | 1 + pkg/telemetry/prometheus/node.go | 126 +++++++++++++------------- pkg/telemetry/prometheus/packets.go | 52 +++++++---- 7 files changed, 207 insertions(+), 179 deletions(-) diff --git a/go.mod b/go.mod index 95ea8ef83..3ca613534 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9 - github.com/livekit/protocol v1.45.9-0.20260519061926-8381f2180c45 + github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff github.com/livekit/psrpc v0.7.1 github.com/mackerelio/go-osstat v0.2.7 github.com/magefile/mage v1.17.0 @@ -30,19 +30,19 @@ require ( github.com/olekukonko/tablewriter v1.1.4 github.com/ory/dockertest/v3 v3.12.0 github.com/pion/datachannel v1.6.0 - github.com/pion/dtls/v3 v3.1.2 - github.com/pion/ice/v4 v4.2.6 - github.com/pion/interceptor v0.1.44 + github.com/pion/dtls/v3 v3.1.3 + github.com/pion/ice/v4 v4.2.7 + github.com/pion/interceptor v0.1.45 github.com/pion/rtcp v1.2.16 - github.com/pion/rtp v1.10.1 + github.com/pion/rtp v1.10.2 github.com/pion/sctp v1.9.5 github.com/pion/sdp/v3 v3.0.18 - github.com/pion/transport/v4 v4.0.1 - github.com/pion/turn/v5 v5.0.4 + github.com/pion/transport/v4 v4.0.2 + github.com/pion/turn/v5 v5.0.7 github.com/pion/webrtc/v4 v4.2.11 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.23.2 - github.com/redis/go-redis/v9 v9.18.0 + github.com/redis/go-redis/v9 v9.20.0 github.com/rs/cors v1.11.1 github.com/stretchr/testify v1.11.1 github.com/thoas/go-funk v0.9.3 @@ -52,8 +52,8 @@ require ( github.com/urfave/negroni/v3 v3.1.1 go.uber.org/atomic v1.11.0 go.uber.org/multierr v1.11.0 - go.uber.org/zap v1.27.1 - golang.org/x/mod v0.34.0 + go.uber.org/zap v1.28.0 + golang.org/x/mod v0.36.0 golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 @@ -75,23 +75,24 @@ require ( github.com/olekukonko/errors v1.2.0 // indirect github.com/olekukonko/ll v0.1.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect - go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect go.opentelemetry.io/otel/sdk v1.43.0 // indirect - go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect golang.org/x/time v0.15.0 // indirect ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect - buf.build/go/protovalidate v1.1.3 // indirect - buf.build/go/protoyaml v0.6.0 // indirect - cel.dev/expr v0.25.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect + buf.build/go/protovalidate v1.2.0 // indirect + buf.build/go/protoyaml v0.7.0 // indirect + cel.dev/expr v0.25.2 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -103,16 +104,15 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/continuity v0.4.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/cli v27.4.1+incompatible // indirect github.com/docker/docker v27.1.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-jose/go-jose/v3 v3.0.5 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/cel-go v0.27.0 // indirect + github.com/google/cel-go v0.28.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/subcommands v1.2.0 // indirect @@ -120,7 +120,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.18.5 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lithammer/shortuuid/v4 v4.2.0 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect @@ -129,8 +129,8 @@ require ( github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nats-io/nats.go v1.50.0 // indirect - github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nats.go v1.52.0 // indirect + github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect @@ -138,8 +138,8 @@ require ( github.com/pion/logging v0.2.4 // indirect github.com/pion/mdns/v2 v2.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/srtp/v3 v3.0.10 // indirect - github.com/pion/stun/v3 v3.1.2 + github.com/pion/srtp/v3 v3.0.11 // indirect + github.com/pion/stun/v3 v3.1.4 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 // indirect @@ -153,13 +153,13 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zeebo/xxh3 v1.1.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/crypto v0.50.0 // indirect - golang.org/x/net v0.53.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/text v0.36.0 // indirect - golang.org/x/tools v0.43.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect - google.golang.org/grpc v1.80.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/tools v0.45.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/grpc v1.81.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index c7ec41f8a..8bf0ecc94 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,11 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 h1:PMmTMyvHScV9Mn8wc6ASge9uRcHy0jtqPd+fM35LmsQ= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= -buf.build/go/protovalidate v1.1.3 h1:m2GVEgQWd7rk+vIoAZ+f0ygGjvQTuqPQapBBdcpWVPE= -buf.build/go/protovalidate v1.1.3/go.mod h1:9XIuohWz+kj+9JVn3WQneHA5LZP50mjvneZMnbLkiIE= -buf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w= -buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q= -cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= -cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= +buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0= +buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4= +buf.build/go/protoyaml v0.7.0 h1:z4oVoFicbpPefhT7WAykxUdfp0yEQlhMQ2mCZOY5V38= +buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MGSQ0= +cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= +cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -57,8 +57,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/iters v1.2.2 h1:XH2/Etihiy9ZvPOVCR+icQXeYlhbvS7k0qro4x/2qQo= github.com/dennwc/iters v1.2.2/go.mod h1:M9KuuMBeyEXYTmB7EnI9SCyALFCmPWOIxn5W1L0CjGg= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= @@ -79,8 +77,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/frostbyte73/core v0.1.1 h1:ChhJOR7bAKOCPbA+lqDLE2cGKlCG5JXsDvvQr4YaJIA= github.com/frostbyte73/core v0.1.1/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ= github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g= github.com/gammazero/workerpool v1.2.1 h1:MEDvUJsNYGuCvl1RwIXNKu2YtQtHqCSF9XWF04N7lqs= @@ -100,8 +98,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo= -github.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw= +github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM= +github.com/google/cel-go v0.28.1/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -158,8 +156,8 @@ github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= -github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -181,8 +179,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9 h1:kFXGyfVN9c2b66e6Q87evOvKrJE5u9e1Gd28gtjSLPI= github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9/go.mod h1:KIBQV035+uwqfYvKPUh+7H3bXtaYO0TXhcxLosbhJ9A= -github.com/livekit/protocol v1.45.9-0.20260519061926-8381f2180c45 h1:gJQFJNjHuxeKroI6KTtVeXVcUMOaK8ksdiB6FoiDWmE= -github.com/livekit/protocol v1.45.9-0.20260519061926-8381f2180c45/go.mod h1:KEPIJ/ZdMFQ9tmmfv/uT9TjQEuEcZupCZBabuRGEC1k= +github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff h1:Iomgfa26isqi32kNdatQLxkoXrW5MF/Ro6TxUeVNyzM= +github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff/go.mod h1:KEPIJ/ZdMFQ9tmmfv/uT9TjQEuEcZupCZBabuRGEC1k= github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94= @@ -226,10 +224,10 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nats-io/nats.go v1.50.0 h1:5zAeQrTvyrKrWLJ0fu02W3br8ym57qf7csDzgLOpcds= -github.com/nats-io/nats.go v1.50.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= -github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= -github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= +github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= +github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= +github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nyaruka/phonenumbers v1.6.5 h1:aBCaUhfpRA7hU6fsXk+p7KF1aNx4nQlq9hGeo2qdFg8= @@ -254,12 +252,12 @@ github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCy github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= -github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= -github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= -github.com/pion/ice/v4 v4.2.6 h1:17SKPTupOmumCMAQ4ntf8rv6q6XEfVzuz1gSFrnhzPE= -github.com/pion/ice/v4 v4.2.6/go.mod h1:tmp90fBKpZhQDkHkp/QJb+Gn8vhMxuAcMq7PfhQWQHE= -github.com/pion/interceptor v0.1.44 h1:sNlZwM8dWXU9JQAkJh8xrarC0Etn8Oolcniukmuy0/I= -github.com/pion/interceptor v0.1.44/go.mod h1:4atVlBkcgXuUP+ykQF0qOCGU2j7pQzX2ofvPRFsY5RY= +github.com/pion/dtls/v3 v3.1.3 h1:OA6J5UCeA8DvRXD8ofaMnlNPXN3ISBLHHJ9P8SWL09E= +github.com/pion/dtls/v3 v3.1.3/go.mod h1:GEwid4EzCcakfrNvHXM7bs6ci2mASI5Y5Q4tbtLFuWs= +github.com/pion/ice/v4 v4.2.7 h1:zDEbC6MiEdhQpF8TxBOTws+NU6ZgGpveHrQq4Lc1kao= +github.com/pion/ice/v4 v4.2.7/go.mod h1:9SNPaq0c7El/ki8leJzyCkK10zsskprR3zTNbO3monY= +github.com/pion/interceptor v0.1.45 h1:6PUo/5829bIfRFIPPJQzuDn8EjxRTSB/CSD7QVCOaqo= +github.com/pion/interceptor v0.1.45/go.mod h1:gNDYM/uFKcLe/B3gS2/7+aw6z+RDiMy2qKTnF1LO31w= github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/mdns/v2 v2.1.0 h1:3IJ9+Xio6tWYjhN6WwuY142P/1jA0D5ERaIqawg/fOY= @@ -268,24 +266,24 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo= github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo= -github.com/pion/rtp v1.10.1 h1:xP1prZcCTUuhO2c83XtxyOHJteISg6o8iPsE2acaMtA= -github.com/pion/rtp v1.10.1/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= +github.com/pion/rtp v1.10.2 h1:l+f6tTDcAH6xwepaAoW791ddhuYsJlqRATOzirO04Mo= +github.com/pion/rtp v1.10.2/go.mod h1:Au8fc6cEByy8RLTwKTQTEeQqDB/SJDxwL4mZuxYA5Pk= github.com/pion/sctp v1.9.5 h1:QoSFB/drmAsmSeSFNQNI3xx010nW4HsycCZckRVWWag= github.com/pion/sctp v1.9.5/go.mod h1:N20Dq6LY+JvJDAh9VVh1JELngb2rQ8dPgds5yBWiPgw= github.com/pion/sdp/v3 v3.0.18 h1:l0bAXazKHpepazVdp+tPYnrsy9dfh7ZbT8DxesH5ZnI= github.com/pion/sdp/v3 v3.0.18/go.mod h1:ZREGo6A9ZygQ9XkqAj5xYCQtQpif0i6Pa81HOiAdqQ8= -github.com/pion/srtp/v3 v3.0.10 h1:tFirkpBb3XccP5VEXLi50GqXhv5SKPxqrdlhDCJlZrQ= -github.com/pion/srtp/v3 v3.0.10/go.mod h1:3mOTIB0cq9qlbn59V4ozvv9ClW/BSEbRp4cY0VtaR7M= -github.com/pion/stun/v3 v3.1.2 h1:86IhD8wFn6IDW4b1/0QzoQS+f5PeA8OHHRn8UZW5ErY= -github.com/pion/stun/v3 v3.1.2/go.mod h1:H7gDic7nNwlUL05pbs6T1dtaBehh/KjupxfWw3ZI7cA= +github.com/pion/srtp/v3 v3.0.11 h1:GiESUr54/K4UuPigfq/CvWUed80JenQAHXn0C2MQQIQ= +github.com/pion/srtp/v3 v3.0.11/go.mod h1:EeZOi/sd6glM1EXapg051gdNWO9yWT1YSsgQ4SlJkns= +github.com/pion/stun/v3 v3.1.4 h1:/7ZL0j0dmLroKOq4GfkyKQ6asByYqntwyHSp5sYLcGY= +github.com/pion/stun/v3 v3.1.4/go.mod h1:ET7PFiXo1nrD2ZNVpbEHDuT0kCPVXhKmyWdiePNMw/U= github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM= github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= -github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= -github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= +github.com/pion/transport/v4 v4.0.2 h1:ifYlPqNwsy6aKQ9y8yzxXlHae5431ZrH2avkD/Rn6Tk= +github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM= github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ= github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ= -github.com/pion/turn/v5 v5.0.4 h1:xKAnP1b5eCnjFPd55OgxkqIVoyzbHKZa06SxZ3fopXQ= -github.com/pion/turn/v5 v5.0.4/go.mod h1:zbPsMp+fIVhKt5uWu2jcjk88FcoRbGMBSzVsaTuhcmM= +github.com/pion/turn/v5 v5.0.7 h1:cA4zPYZR/tS1qZqOi5myHSQ+cwPENCvY8T/wMloP8Tg= +github.com/pion/turn/v5 v5.0.7/go.mod h1:1VwvxElZaOdJU0liJ/WUSm/Tsh+n2OxS5ISSDxgOWxU= github.com/pion/webrtc/v4 v4.2.11 h1:QUX1QZKlNIn4O7U5JxLPGP0sV5RTncZkzu9SPR3jVNU= github.com/pion/webrtc/v4 v4.2.11/go.mod h1:s/rAiyy77GyRFrZMx+Ls6aua26dIBPudH8/ZHYbIRWY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -302,8 +300,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs= -github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0= +github.com/redis/go-redis/v9 v9.20.0 h1:WnQYxLkgO2xiXTCJY0ldIiI8dNqCDlQAG+AtaH7a2a0= +github.com/redis/go-redis/v9 v9.20.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -353,20 +351,20 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -375,8 +373,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= @@ -388,16 +386,16 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -418,8 +416,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -460,8 +458,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -474,8 +472,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -484,20 +482,20 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4 h1:yOzSCGPx+cp5VO7IxvZ9SBFF7j1tZVcNtlHR2iYKtVo= -google.golang.org/genproto/googleapis/api v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:Q9HWtNeE7tM9npdIsEvqXj1QJIvVoeAV3rtXtS715Cw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= +google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/service/egress.go b/pkg/service/egress.go index 961685de0..2e37ce4c2 100644 --- a/pkg/service/egress.go +++ b/pkg/service/egress.go @@ -371,3 +371,7 @@ func (s *EgressService) StopEgress(ctx context.Context, req *livekit.StopEgressR return info, nil } + +func (s *EgressService) StartEgress(ctx context.Context, req *livekit.StartEgressRequest) (*livekit.EgressInfo, error) { + return nil, errors.New("not implemented") +} diff --git a/pkg/service/rtcservice.go b/pkg/service/rtcservice.go index 6f18356df..1b6171851 100644 --- a/pkg/service/rtcservice.go +++ b/pkg/service/rtcservice.go @@ -364,6 +364,7 @@ func (s *RTCService) serve(w http.ResponseWriter, r *http.Request, needsJoinRequ roomName, pi, code, err = s.validateInternal(pLogger, r, needsJoinRequest, false) if err != nil { + prometheus.IncrementParticipantJoinValidationFail(1) resolveLogger(true) HandleError(w, r, code, err, getLoggerFields()...) return diff --git a/pkg/telemetry/events.go b/pkg/telemetry/events.go index fb32e4c37..55a21f6a1 100644 --- a/pkg/telemetry/events.go +++ b/pkg/telemetry/events.go @@ -135,6 +135,7 @@ func (t *telemetryService) ParticipantActive( prometheus.AddParticipant() } worker.SetConnected() + prometheus.IncrementParticipantRtcActive(1) ev := newParticipantEvent(livekit.AnalyticsEventType_PARTICIPANT_ACTIVE, room, participant) ev.ClientMeta = clientMeta diff --git a/pkg/telemetry/prometheus/node.go b/pkg/telemetry/prometheus/node.go index 02229186f..c3a3fc3ca 100644 --- a/pkg/telemetry/prometheus/node.go +++ b/pkg/telemetry/prometheus/node.go @@ -149,40 +149,43 @@ func GetNodeStats(nodeStartedAt int64, prevStats []*livekit.NodeStats, rateInter promSysPacketGauge.WithLabelValues("dropped").Set(float64(sysDroppedPackets - sysDroppedPacketsStart)) stats := &livekit.NodeStats{ - StartedAt: nodeStartedAt, - UpdatedAt: time.Now().Unix(), - NumRooms: roomCurrent.Load(), - NumClients: participantCurrent.Load(), - NumTracksIn: trackPublishedCurrent.Load(), - NumTracksOut: trackSubscribedCurrent.Load(), - NumTrackPublishAttempts: trackPublishAttempts.Load(), - NumTrackPublishSuccess: trackPublishSuccess.Load(), - NumTrackPublishCancels: trackPublishCancels.Load(), - NumTrackSubscribeAttempts: trackSubscribeAttempts.Load(), - NumTrackSubscribeSuccess: trackSubscribeSuccess.Load(), - NumTrackSubscribeCancels: trackSubscribeCancels.Load(), - BytesIn: bytesIn.Load(), - BytesOut: bytesOut.Load(), - PacketsIn: packetsIn.Load(), - PacketsOut: packetsOut.Load(), - RetransmitBytesOut: retransmitBytes.Load(), - RetransmitPacketsOut: retransmitPackets.Load(), - NackTotal: nackTotal.Load(), - ParticipantSignalConnected: participantSignalConnected.Load(), - ParticipantRtcInit: participantRTCInit.Load(), - ParticipantRtcConnected: participantRTCConnected.Load(), - ParticipantRtcCanceled: participantRTCCanceled.Load(), - ForwardLatency: forwardLatency.Load(), - ForwardJitter: forwardJitter.Load(), - NumCpus: uint32(cpuStats.NumCPU()), // this will round down to the nearest integer - CpuLoad: float32(cpuStats.GetCPULoad()), - MemoryTotal: memTotal, - MemoryUsed: memUsed, - LoadAvgLast1Min: float32(loadAvg.Loadavg1), - LoadAvgLast5Min: float32(loadAvg.Loadavg5), - LoadAvgLast15Min: float32(loadAvg.Loadavg15), - SysPacketsOut: sysPackets, - SysPacketsDropped: sysDroppedPackets, + StartedAt: nodeStartedAt, + UpdatedAt: time.Now().Unix(), + NumRooms: roomCurrent.Load(), + NumClients: participantCurrent.Load(), + NumTracksIn: trackPublishedCurrent.Load(), + NumTracksOut: trackSubscribedCurrent.Load(), + NumTrackPublishAttempts: trackPublishAttempts.Load(), + NumTrackPublishSuccess: trackPublishSuccess.Load(), + NumTrackPublishCancels: trackPublishCancels.Load(), + NumTrackSubscribeAttempts: trackSubscribeAttempts.Load(), + NumTrackSubscribeSuccess: trackSubscribeSuccess.Load(), + NumTrackSubscribeCancels: trackSubscribeCancels.Load(), + BytesIn: bytesIn.Load(), + BytesOut: bytesOut.Load(), + PacketsIn: packetsIn.Load(), + PacketsOut: packetsOut.Load(), + RetransmitBytesOut: retransmitBytes.Load(), + RetransmitPacketsOut: retransmitPackets.Load(), + NackTotal: nackTotal.Load(), + ParticipantSignalConnected: participantSignalConnected.Load(), + ParticipantSignalFailed: participantSignalFailed.Load(), + ParticipantSignalValidationFailed: participantSignalValidationFailed.Load(), + ParticipantRtcInit: participantRTCInit.Load(), + ParticipantRtcConnected: participantRTCConnected.Load(), + ParticipantRtcCanceled: participantRTCCanceled.Load(), + ParticipantRtcActive: participantRTCActive.Load(), + ForwardLatency: forwardLatency.Load(), + ForwardJitter: forwardJitter.Load(), + NumCpus: uint32(cpuStats.NumCPU()), // this will round down to the nearest integer + CpuLoad: float32(cpuStats.GetCPULoad()), + MemoryTotal: memTotal, + MemoryUsed: memUsed, + LoadAvgLast1Min: float32(loadAvg.Loadavg1), + LoadAvgLast5Min: float32(loadAvg.Loadavg5), + LoadAvgLast15Min: float32(loadAvg.Loadavg15), + SysPacketsOut: sysPackets, + SysPacketsDropped: sysDroppedPackets, } for _, rateInterval := range rateIntervals { @@ -239,32 +242,35 @@ func getNodeStatsRate(statsHistory []*livekit.NodeStats) *livekit.NodeStatsRate earlier := statsHistory[0] later := statsHistory[len(statsHistory)-1] rate := &livekit.NodeStatsRate{ - StartedAt: earlier.UpdatedAt, - EndedAt: later.UpdatedAt, - Duration: elapsed, - BytesIn: perSec(earlier.BytesIn, later.BytesIn, elapsed), - BytesOut: perSec(earlier.BytesOut, later.BytesOut, elapsed), - PacketsIn: perSec(earlier.PacketsIn, later.PacketsIn, elapsed), - PacketsOut: perSec(earlier.PacketsOut, later.PacketsOut, elapsed), - RetransmitBytesOut: perSec(earlier.RetransmitBytesOut, later.RetransmitBytesOut, elapsed), - RetransmitPacketsOut: perSec(earlier.RetransmitPacketsOut, later.RetransmitPacketsOut, elapsed), - NackTotal: perSec(earlier.NackTotal, later.NackTotal, elapsed), - ParticipantSignalConnected: perSec(earlier.ParticipantSignalConnected, later.ParticipantSignalConnected, elapsed), - ParticipantRtcInit: perSec(earlier.ParticipantRtcInit, later.ParticipantRtcInit, elapsed), - ParticipantRtcConnected: perSec(earlier.ParticipantRtcConnected, later.ParticipantRtcConnected, elapsed), - ParticipantRtcCanceled: perSec(earlier.ParticipantRtcCanceled, later.ParticipantRtcCanceled, elapsed), - SysPacketsOut: perSec(uint64(earlier.SysPacketsOut), uint64(later.SysPacketsOut), elapsed), - SysPacketsDropped: perSec(uint64(earlier.SysPacketsDropped), uint64(later.SysPacketsDropped), elapsed), - TrackPublishAttempts: perSec(uint64(earlier.NumTrackPublishAttempts), uint64(later.NumTrackPublishAttempts), elapsed), - TrackPublishSuccess: perSec(uint64(earlier.NumTrackPublishSuccess), uint64(later.NumTrackPublishSuccess), elapsed), - TrackPublishCancels: perSec(uint64(earlier.NumTrackPublishCancels), uint64(later.NumTrackPublishCancels), elapsed), - TrackSubscribeAttempts: perSec(uint64(earlier.NumTrackSubscribeAttempts), uint64(later.NumTrackSubscribeAttempts), elapsed), - TrackSubscribeSuccess: perSec(uint64(earlier.NumTrackSubscribeSuccess), uint64(later.NumTrackSubscribeSuccess), elapsed), - TrackSubscribeCancels: perSec(uint64(earlier.NumTrackSubscribeCancels), uint64(later.NumTrackSubscribeCancels), elapsed), - CpuLoad: cpuLoad / float32(elapsed), - MemoryLoad: memoryLoad / float32(elapsed), - MemoryUsed: memoryUsed / float32(elapsed), - MemoryTotal: memoryTotal / float32(elapsed), + StartedAt: earlier.UpdatedAt, + EndedAt: later.UpdatedAt, + Duration: elapsed, + BytesIn: perSec(earlier.BytesIn, later.BytesIn, elapsed), + BytesOut: perSec(earlier.BytesOut, later.BytesOut, elapsed), + PacketsIn: perSec(earlier.PacketsIn, later.PacketsIn, elapsed), + PacketsOut: perSec(earlier.PacketsOut, later.PacketsOut, elapsed), + RetransmitBytesOut: perSec(earlier.RetransmitBytesOut, later.RetransmitBytesOut, elapsed), + RetransmitPacketsOut: perSec(earlier.RetransmitPacketsOut, later.RetransmitPacketsOut, elapsed), + NackTotal: perSec(earlier.NackTotal, later.NackTotal, elapsed), + ParticipantSignalConnected: perSec(earlier.ParticipantSignalConnected, later.ParticipantSignalConnected, elapsed), + ParticipantSignalFailed: perSec(earlier.ParticipantSignalFailed, later.ParticipantSignalFailed, elapsed), + ParticipantSignalValidationFailed: perSec(earlier.ParticipantSignalValidationFailed, later.ParticipantSignalValidationFailed, elapsed), + ParticipantRtcInit: perSec(earlier.ParticipantRtcInit, later.ParticipantRtcInit, elapsed), + ParticipantRtcConnected: perSec(earlier.ParticipantRtcConnected, later.ParticipantRtcConnected, elapsed), + ParticipantRtcCanceled: perSec(earlier.ParticipantRtcCanceled, later.ParticipantRtcCanceled, elapsed), + ParticipantRtcActive: perSec(earlier.ParticipantRtcActive, later.ParticipantRtcActive, elapsed), + SysPacketsOut: perSec(uint64(earlier.SysPacketsOut), uint64(later.SysPacketsOut), elapsed), + SysPacketsDropped: perSec(uint64(earlier.SysPacketsDropped), uint64(later.SysPacketsDropped), elapsed), + TrackPublishAttempts: perSec(uint64(earlier.NumTrackPublishAttempts), uint64(later.NumTrackPublishAttempts), elapsed), + TrackPublishSuccess: perSec(uint64(earlier.NumTrackPublishSuccess), uint64(later.NumTrackPublishSuccess), elapsed), + TrackPublishCancels: perSec(uint64(earlier.NumTrackPublishCancels), uint64(later.NumTrackPublishCancels), elapsed), + TrackSubscribeAttempts: perSec(uint64(earlier.NumTrackSubscribeAttempts), uint64(later.NumTrackSubscribeAttempts), elapsed), + TrackSubscribeSuccess: perSec(uint64(earlier.NumTrackSubscribeSuccess), uint64(later.NumTrackSubscribeSuccess), elapsed), + TrackSubscribeCancels: perSec(uint64(earlier.NumTrackSubscribeCancels), uint64(later.NumTrackSubscribeCancels), elapsed), + CpuLoad: cpuLoad / float32(elapsed), + MemoryLoad: memoryLoad / float32(elapsed), + MemoryUsed: memoryUsed / float32(elapsed), + MemoryTotal: memoryTotal / float32(elapsed), } return rate } diff --git a/pkg/telemetry/prometheus/packets.go b/pkg/telemetry/prometheus/packets.go index d8ac65610..a9f6684e1 100644 --- a/pkg/telemetry/prometheus/packets.go +++ b/pkg/telemetry/prometheus/packets.go @@ -36,19 +36,22 @@ const ( ) var ( - bytesIn atomic.Uint64 - bytesOut atomic.Uint64 - packetsIn atomic.Uint64 - packetsOut atomic.Uint64 - nackTotal atomic.Uint64 - retransmitBytes atomic.Uint64 - retransmitPackets atomic.Uint64 - participantSignalConnected atomic.Uint64 - participantRTCConnected atomic.Uint64 - participantRTCInit atomic.Uint64 - participantRTCCanceled atomic.Uint64 - forwardLatency atomic.Uint32 - forwardJitter atomic.Uint32 + bytesIn atomic.Uint64 + bytesOut atomic.Uint64 + packetsIn atomic.Uint64 + packetsOut atomic.Uint64 + nackTotal atomic.Uint64 + retransmitBytes atomic.Uint64 + retransmitPackets atomic.Uint64 + participantSignalConnected atomic.Uint64 + participantSignalFailed atomic.Uint64 + participantSignalValidationFailed atomic.Uint64 + participantRTCConnected atomic.Uint64 + participantRTCInit atomic.Uint64 + participantRTCCanceled atomic.Uint64 + participantRTCActive atomic.Uint64 + forwardLatency atomic.Uint32 + forwardJitter atomic.Uint32 promPacketLabels = []string{"direction", "transmission", "country"} promPacketTotal *prometheus.CounterVec @@ -300,9 +303,17 @@ func IncrementParticipantJoin(join uint32) { } } -func IncrementParticipantJoinFail(join uint32) { - if join > 0 { - promParticipantJoin.WithLabelValues("signal_failed").Add(float64(join)) +func IncrementParticipantJoinFail(fail uint32) { + if fail > 0 { + participantSignalFailed.Add(uint64(fail)) + promParticipantJoin.WithLabelValues("signal_failed").Add(float64(fail)) + } +} + +func IncrementParticipantJoinValidationFail(validationFail uint32) { + if validationFail > 0 { + participantSignalValidationFailed.Add(uint64(validationFail)) + promParticipantJoin.WithLabelValues("signal_validation_failed").Add(float64(validationFail)) } } @@ -320,9 +331,16 @@ func IncrementParticipantRtcConnected(join uint32) { } } +func IncrementParticipantRtcActive(active uint32) { + if active > 0 { + participantRTCActive.Add(uint64(active)) + promParticipantJoin.WithLabelValues("rtc_active").Add(float64(active)) + } +} + func IncrementParticipantRtcCanceled(numCancels uint64) { if numCancels > 0 { - participantRTCConnected.Add(numCancels) + participantRTCCanceled.Add(numCancels) promParticipantJoin.WithLabelValues("rtc_canceled").Add(float64(numCancels)) } } From 63be96f631f905a07be070d9091ba2bdefb631ca Mon Sep 17 00:00:00 2001 From: cnderrauber Date: Thu, 4 Jun 2026 10:32:24 +0800 Subject: [PATCH 02/25] Prevent panic from nil(illegal) syncState.Subscriptions message (#4560) --- pkg/rtc/room.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index 8a3118dcb..e696abddf 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -686,14 +686,14 @@ func (r *Room) onSyncState(participant types.LocalParticipant, state *livekit.Sy // synthesize a track setting for each disabled track, // can be set before adding subscriptions, // in fact it is done before so that setting can be updated immediately upon subscription. - for _, trackSid := range state.TrackSidsDisabled { + for _, trackSid := range state.GetTrackSidsDisabled() { participant.UpdateSubscribedTrackSettings(livekit.TrackID(trackSid), &livekit.UpdateTrackSettings{Disabled: true}) } participant.HandleUpdateSubscriptions( - livekit.StringsAsIDs[livekit.TrackID](state.Subscription.TrackSids), - state.Subscription.ParticipantTracks, - state.Subscription.Subscribe, + livekit.StringsAsIDs[livekit.TrackID](state.GetSubscription().GetTrackSids()), + state.GetSubscription().GetParticipantTracks(), + state.GetSubscription().GetSubscribe(), ) return nil } From 77ecf920ff690f426c812ec7364506b02a39de99 Mon Sep 17 00:00:00 2001 From: Paul Wells Date: Wed, 3 Jun 2026 21:35:39 -0700 Subject: [PATCH 03/25] rtc: report participant session end time on room move (#4561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MoveToRoom resets the participant reporter resolver to receive new (room, participant_session) keys for the destination, but the source room's participant_session row never gets an end_time — the periodic duration scrape only emits one once disconnectedAt is set, and a move doesn't transition the participant to DISCONNECTED. Report end_time immediately before the reset so the row is closed out cleanly. --- pkg/rtc/participant.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 39fdbf70a..2b71174fb 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -4069,6 +4069,7 @@ func (p *ParticipantImpl) MoveToRoom(params types.MoveToRoomParams) { p.telemetryGuard = &telemetry.ReferenceGuard{} p.lock.Unlock() + p.params.Reporter.ReportEndTime(time.Now()) p.params.LoggerResolver.Reset() p.params.ReporterResolver.Reset() p.setListener(params.Listener) From d290de8165cd71a135ec3c56b20d5cf1319e93f9 Mon Sep 17 00:00:00 2001 From: cnderrauber Date: Thu, 4 Jun 2026 16:43:59 +0800 Subject: [PATCH 04/25] Correct config comment (#4563) --- config-sample.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config-sample.yaml b/config-sample.yaml index 8b5891fdf..0559d7712 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -68,11 +68,11 @@ rtc: # # when set to true, advertises both mapped external and internal IPs to clients as server candidates. # # useful when clients connect from both private and public networks. # # works only when `use_external_ip` is set to true. + # # when both this and `external_ip_only` are set, SFU advertises all private IPs with their mapped external IPs and skips + # # private IPs that do not have a mapped external IP. # advertise_internal_ip: true # # when set to true, SFU skips external IP accessibility checks via self-ping. # # enable this when SFU is behind NAT that does not allow self-ping. only works when `use_external_ip` is set to true. - # # when both this and `external_ip_only` are set, SFU advertises all private IPs with their mapped external IPs and skips - # # private IPs that do not have a mapped external IP. # skip_external_ip_validation: true # # there are cases where the public IP determined via STUN is not the correct one # # in such cases, use this setting to set the public IP of the node From cdbbee1f8e76b0911d232165a0e7ac167fb89337 Mon Sep 17 00:00:00 2001 From: Paul Wells Date: Fri, 5 Jun 2026 14:48:51 -0700 Subject: [PATCH 05/25] deps: bump protocol + psrpc to latest tips (#4565) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deps: bump psrpc + protocol + cloud-protocol + backend-common to latest * deps: go get -u sweep + bump counterfeiter Direct deps bumped via go get -u ./...: clipperhouse/displaywidth 0.10.0 -> 0.11.0 clipperhouse/uax29/v2 2.6.0 -> 2.7.0 fatih/color 1.18.0 -> 1.19.0 florianl/go-tc 0.4.7 -> 0.4.8 hashicorp/go-version 1.8.0 -> 1.9.0 livekit/protocol -> a7a83da5 (latest) ua-parser bumped urfave/cli/v3 3.8.0 -> 3.9.0 otel/sdk 1.43.0 -> 1.44.0 yaml.in/yaml/v2 2.4.2 -> 2.4.4 Indirect: mdlayher/netlink + socket bumped, mattn/* bumped, olekukonko/* bumped, counterfeiter v6.11.1 -> v6.12.2. Newer-major audit: no actionable majors. +incompatible: twitchtv/twirp v8.1.3 (upstream choice, stays); docker/cli and docker/docker indirect. Notable stuck patterns worth a separate cleanup: - pkg/errors v0.9.1 direct dep (unmaintained; stdlib supplants) - go.uber.org/atomic + multierr direct deps - ory/dockertest/v3 v3.12.0 (v4 is available — cascade has migrated cloud-protocol, backend-common, psrpc to v4). * deps: pin pion/webrtc/v4 v4.2.11 + pion/sctp v1.9.5 * deps: pin protocol+psrpc+MTU to landed versions --- go.mod | 66 ++++++++++---------- go.sum | 194 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 128 insertions(+), 132 deletions(-) diff --git a/go.mod b/go.mod index 3ca613534..c79261f2c 100644 --- a/go.mod +++ b/go.mod @@ -8,21 +8,21 @@ require ( github.com/dennwc/iters v1.2.2 github.com/dustin/go-humanize v1.0.1 github.com/elliotchance/orderedmap/v3 v3.1.0 - github.com/florianl/go-tc v0.4.7 + github.com/florianl/go-tc v0.4.8 github.com/frostbyte73/core v0.1.1 github.com/gammazero/deque v1.2.1 github.com/gammazero/workerpool v1.2.1 github.com/google/uuid v1.6.0 github.com/google/wire v0.7.0 github.com/gorilla/websocket v1.5.3 - github.com/hashicorp/go-version v1.8.0 + github.com/hashicorp/go-version v1.9.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/jellydator/ttlcache/v3 v3.4.0 github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 - github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9 - github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff - github.com/livekit/psrpc v0.7.1 + github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e + github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 + github.com/livekit/psrpc v0.7.2 github.com/mackerelio/go-osstat v0.2.7 github.com/magefile/mage v1.17.0 github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 @@ -38,7 +38,7 @@ require ( github.com/pion/sctp v1.9.5 github.com/pion/sdp/v3 v3.0.18 github.com/pion/transport/v4 v4.0.2 - github.com/pion/turn/v5 v5.0.7 + github.com/pion/turn/v5 v5.0.8 github.com/pion/webrtc/v4 v4.2.11 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.23.2 @@ -48,7 +48,7 @@ require ( github.com/thoas/go-funk v0.9.3 github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e github.com/twitchtv/twirp v8.1.3+incompatible - github.com/ua-parser/uap-go v0.0.0-20251207011819-db9adb27a0b8 + github.com/ua-parser/uap-go v0.0.0-20260529044130-17c35e68e58c github.com/urfave/negroni/v3 v3.1.1 go.uber.org/atomic v1.11.0 go.uber.org/multierr v1.11.0 @@ -61,30 +61,32 @@ require ( require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect - github.com/clipperhouse/displaywidth v0.10.0 // indirect - github.com/clipperhouse/uax29/v2 v2.6.0 // indirect - github.com/fatih/color v1.18.0 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/fatih/color v1.19.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect + github.com/goccy/go-json v0.10.6 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect github.com/moby/sys/user v0.3.0 // indirect - github.com/nyaruka/phonenumbers v1.6.5 // indirect + github.com/nyaruka/phonenumbers v1.8.0 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect - github.com/olekukonko/errors v1.2.0 // indirect - github.com/olekukonko/ll v0.1.6 // indirect + github.com/olekukonko/errors v1.3.0 // indirect + github.com/olekukonko/ll v0.1.8 // indirect + github.com/puzpuzpuz/xsync/v4 v4.5.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel v1.44.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect - go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect + golang.org/x/exp v0.0.0-20260603202125-055de637280b // indirect golang.org/x/time v0.15.0 // indirect ) @@ -103,13 +105,12 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/continuity v0.4.5 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/cli v27.4.1+incompatible // indirect github.com/docker/docker v27.1.1+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-connections v0.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect - github.com/go-jose/go-jose/v3 v3.0.5 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/cel-go v0.28.1 // indirect @@ -117,15 +118,15 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/subcommands v1.2.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lithammer/shortuuid/v4 v4.2.0 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect - github.com/mdlayher/netlink v1.7.1 // indirect - github.com/mdlayher/socket v0.4.0 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect + github.com/mdlayher/netlink v1.11.2 // indirect + github.com/mdlayher/socket v0.6.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -133,20 +134,19 @@ require ( github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/runc v1.2.3 // indirect github.com/pion/logging v0.2.4 // indirect github.com/pion/mdns/v2 v2.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/srtp/v3 v3.0.11 // indirect github.com/pion/stun/v3 v3.1.4 - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect + github.com/prometheus/common v0.68.1 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/urfave/cli/v3 v3.8.0 + github.com/urfave/cli/v3 v3.9.0 github.com/wlynxg/anet v0.0.5 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/go.sum b/go.sum index 8bf0ecc94..9895db9aa 100644 --- a/go.sum +++ b/go.sum @@ -41,38 +41,47 @@ github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2u github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= -github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= -github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= -github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= -github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/d5/tengo/v2 v2.17.0 h1:BWUN9NoJzw48jZKiYDXDIF3QrIVZRm1uV1gTzeZ2lqM= github.com/d5/tengo/v2 v2.17.0/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/iters v1.2.2 h1:XH2/Etihiy9ZvPOVCR+icQXeYlhbvS7k0qro4x/2qQo= github.com/dennwc/iters v1.2.2/go.mod h1:M9KuuMBeyEXYTmB7EnI9SCyALFCmPWOIxn5W1L0CjGg= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= +github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg= github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/florianl/go-tc v0.4.7 h1:Ysai5TIx4PgOzqI/1cse/pquOFCEkWofKtc/EPumfrg= -github.com/florianl/go-tc v0.4.7/go.mod h1:Fdz6eHitQZwylSvpAW3y9R9cUrnS/zinuAdjJpD7XqY= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/florianl/go-tc v0.4.8 h1:hgmakUX1Nm0Ba1I0ZkbUl9CH6HbRwqSiwipnpmYp3Es= +github.com/florianl/go-tc v0.4.8/go.mod h1:B8GeOEnmrbOnxZtaCvsYJcgIzzmM8c/AIhtfCZsDj3Q= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/frostbyte73/core v0.1.1 h1:ChhJOR7bAKOCPbA+lqDLE2cGKlCG5JXsDvvQr4YaJIA= @@ -83,8 +92,6 @@ github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g= github.com/gammazero/workerpool v1.2.1 h1:MEDvUJsNYGuCvl1RwIXNKu2YtQtHqCSF9XWF04N7lqs= github.com/gammazero/workerpool v1.2.1/go.mod h1:E32GVRUanF4d6QtRmdss3AScgaDkIyrvPtgRQUWgmx4= -github.com/go-jose/go-jose/v3 v3.0.5 h1:BLLJWbC4nMZOfuPVxoZIxeYsn6Nl2r1fITaJ78UQlVQ= -github.com/go-jose/go-jose/v3 v3.0.5/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -94,8 +101,12 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM= @@ -128,10 +139,10 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= -github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= +github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -177,22 +188,22 @@ github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkI github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc= github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= -github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9 h1:kFXGyfVN9c2b66e6Q87evOvKrJE5u9e1Gd28gtjSLPI= -github.com/livekit/mediatransportutil v0.0.0-20260601042523-13d536af56d9/go.mod h1:KIBQV035+uwqfYvKPUh+7H3bXtaYO0TXhcxLosbhJ9A= -github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff h1:Iomgfa26isqi32kNdatQLxkoXrW5MF/Ro6TxUeVNyzM= -github.com/livekit/protocol v1.46.6-0.20260603092309-a47fcc406cff/go.mod h1:KEPIJ/ZdMFQ9tmmfv/uT9TjQEuEcZupCZBabuRGEC1k= -github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= -github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= +github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e h1:SkgQRcG2VYEhh80Qb/zYZo8rWKJzNfJcfUQnXe6su2M= +github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= +github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 h1:dkHHthyor9dwxxdBmbeG1ZUI4bPHpTEk9DjYJSSSIl4= +github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= +github.com/livekit/psrpc v0.7.2 h1:6oZ+NODJ2pLyaT6VqDq1F4Qc/3TpDUSpyphj/P9MhQc= +github.com/livekit/psrpc v0.7.2/go.mod h1:rAI+m2+/cb4x9RXhLRtUx5ZwdfjjXOl4zi46IjEetaw= github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94= github.com/mackerelio/go-osstat v0.2.7/go.mod h1:dwpYh5pIPmvk+IEwBKNIWRFMB92mrC08CmXOhDC7nQk= github.com/magefile/mage v1.17.0 h1:dS4tkq997Ism03akafC8509iqDjeE7TNTexI25Y7sXM= github.com/magefile/mage v1.17.0/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 h1:V23nK2R2B63g2GhygF9zVGpnigmhvoZoH8d0hrZwMGY= github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2/go.mod h1:Mr897yU9FmyKaQDPtRlVKibrjz40XXyOHUfyZBPSyZU= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= @@ -207,17 +218,21 @@ github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnN github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= -github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= -github.com/mdlayher/netlink v1.7.1 h1:FdUaT/e33HjEXagwELR8R3/KL1Fq5x3G5jgHLp/BTmg= -github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= +github.com/mdlayher/netlink v1.6.2/go.mod h1:O1HXX2sIWSMJ3Qn1BYZk1yZM+7iMki/uYGGiwGyq/iU= +github.com/mdlayher/netlink v1.11.2 h1:HKh2jqe+omdSWcQ88nrT7INE61B0NXfiSPFdgL4YbNI= +github.com/mdlayher/netlink v1.11.2/go.mod h1:uT2Yc/QLaZubzDpZIBi9d4GoeLwtp3x1AMeqSRrK2sA= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= -github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= -github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= +github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= +github.com/mdlayher/socket v0.6.1 h1:M7uj2NtuujUY4mYr1C57NmfNiRHbkKpnBxO856lsc3A= +github.com/mdlayher/socket v0.6.1/go.mod h1:+/SGtqc9V+5dAuRgQsU0fGBI+oRDiW7O2Obx10OIWfg= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg= +github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= +github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY= +github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ= github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -230,26 +245,28 @@ github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nyaruka/phonenumbers v1.6.5 h1:aBCaUhfpRA7hU6fsXk+p7KF1aNx4nQlq9hGeo2qdFg8= -github.com/nyaruka/phonenumbers v1.6.5/go.mod h1:7gjs+Lchqm49adhAKB5cdcng5ZXgt6x7Jgvi0ZorUtU= +github.com/nyaruka/phonenumbers v1.8.0 h1:TrXNJmbwcAHajzDqin3mLWw57vqLUA6ZjVdeNds0heQ= +github.com/nyaruka/phonenumbers v1.8.0/go.mod h1:fsKPJ70O9JetEA4ggnJadYTFWwtGPvu/lETTXNXq6Cs= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= -github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo= -github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= -github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= -github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= +github.com/ory/dockertest/v4 v4.0.0 h1:i19aFsO/VXE0VrMk4ifnKW4G/KIJ93PCjLOslxXoPME= +github.com/ory/dockertest/v4 v4.0.0/go.mod h1:b5Ofu8VIxWNhXFvQcLu17pRNQdoUBKtXBW74G4Ygzx8= github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= github.com/pion/dtls/v3 v3.1.3 h1:OA6J5UCeA8DvRXD8ofaMnlNPXN3ISBLHHJ9P8SWL09E= @@ -282,31 +299,32 @@ github.com/pion/transport/v4 v4.0.2 h1:ifYlPqNwsy6aKQ9y8yzxXlHae5431ZrH2avkD/Rn6 github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM= github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ= github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ= -github.com/pion/turn/v5 v5.0.7 h1:cA4zPYZR/tS1qZqOi5myHSQ+cwPENCvY8T/wMloP8Tg= -github.com/pion/turn/v5 v5.0.7/go.mod h1:1VwvxElZaOdJU0liJ/WUSm/Tsh+n2OxS5ISSDxgOWxU= +github.com/pion/turn/v5 v5.0.8 h1:pZUCtmwWCMkrRKqh/8pL3WoGADXBe0/lOPkN7oqFjK8= +github.com/pion/turn/v5 v5.0.8/go.mod h1:1VwvxElZaOdJU0liJ/WUSm/Tsh+n2OxS5ISSDxgOWxU= github.com/pion/webrtc/v4 v4.2.11 h1:QUX1QZKlNIn4O7U5JxLPGP0sV5RTncZkzu9SPR3jVNU= github.com/pion/webrtc/v4 v4.2.11/go.mod h1:s/rAiyy77GyRFrZMx+Ls6aua26dIBPudH8/ZHYbIRWY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= -github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/prometheus/common v0.68.1 h1:omjRRl4QP4komogpXuhfeOiisQg7xdy8VM1UY+pStaY= +github.com/prometheus/common v0.68.1/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/puzpuzpuz/xsync/v4 v4.5.0 h1:vOSWu6b57/emh+L/Cw0BeQfvxa/cogFywXHeGUxQxAg= +github.com/puzpuzpuz/xsync/v4 v4.5.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= github.com/redis/go-redis/v9 v9.20.0 h1:WnQYxLkgO2xiXTCJY0ldIiI8dNqCDlQAG+AtaH7a2a0= github.com/redis/go-redis/v9 v9.20.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= +github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= @@ -327,10 +345,10 @@ github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4n github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY= github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU= github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= -github.com/ua-parser/uap-go v0.0.0-20251207011819-db9adb27a0b8 h1:yS0rzVnj7Z/ZeHzvv5erQbO2b8gyTL4CeMNodl9SJMQ= -github.com/ua-parser/uap-go v0.0.0-20251207011819-db9adb27a0b8/go.mod h1:gwANdYmo9R8LLwGnyDFWK2PMsaXXX2HhAvCnb/UhZsM= -github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI= -github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/ua-parser/uap-go v0.0.0-20260529044130-17c35e68e58c h1:XbG4n3OWA1PcRTpbBA22E2ChPLvJCuwYRXO12tIyVL0= +github.com/ua-parser/uap-go v0.0.0-20260529044130-17c35e68e58c/go.mod h1:gwANdYmo9R8LLwGnyDFWK2PMsaXXX2HhAvCnb/UhZsM= +github.com/urfave/cli/v3 v3.9.0 h1:AV9lIiPv3ukYnxunaCUsHnEozptYmDN2F0+yWqLMn/c= +github.com/urfave/cli/v3 v3.9.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8hw= github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= @@ -344,25 +362,26 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= @@ -377,27 +396,24 @@ go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= -golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q= +golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -411,19 +427,14 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -448,30 +459,17 @@ golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= @@ -480,8 +478,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 6590570d7c6b767f4a62328ec1143458f4706beb Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Sat, 6 Jun 2026 20:36:10 +0530 Subject: [PATCH 06/25] Pin pion/dtls to v3.1.2 (#4570) --- go.mod | 5 +++++ go.sum | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c79261f2c..d2b5dad1e 100644 --- a/go.mod +++ b/go.mod @@ -163,3 +163,8 @@ require ( google.golang.org/grpc v1.81.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) + +// for gst whipsink compatibility +// it is unclear what in pion/dtls v3.1.3 breaks compatibility, +// but both sides sends their first flights and do not make further progress +replace github.com/pion/dtls/v3 => github.com/pion/dtls/v3 v3.1.2 diff --git a/go.sum b/go.sum index 9895db9aa..9021fffff 100644 --- a/go.sum +++ b/go.sum @@ -269,8 +269,8 @@ github.com/ory/dockertest/v4 v4.0.0 h1:i19aFsO/VXE0VrMk4ifnKW4G/KIJ93PCjLOslxXoP github.com/ory/dockertest/v4 v4.0.0/go.mod h1:b5Ofu8VIxWNhXFvQcLu17pRNQdoUBKtXBW74G4Ygzx8= github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= -github.com/pion/dtls/v3 v3.1.3 h1:OA6J5UCeA8DvRXD8ofaMnlNPXN3ISBLHHJ9P8SWL09E= -github.com/pion/dtls/v3 v3.1.3/go.mod h1:GEwid4EzCcakfrNvHXM7bs6ci2mASI5Y5Q4tbtLFuWs= +github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= +github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= github.com/pion/ice/v4 v4.2.7 h1:zDEbC6MiEdhQpF8TxBOTws+NU6ZgGpveHrQq4Lc1kao= github.com/pion/ice/v4 v4.2.7/go.mod h1:9SNPaq0c7El/ki8leJzyCkK10zsskprR3zTNbO3monY= github.com/pion/interceptor v0.1.45 h1:6PUo/5829bIfRFIPPJQzuDn8EjxRTSB/CSD7QVCOaqo= From 20fd1ad2c1d521b4447a769bf52469cb4415a239 Mon Sep 17 00:00:00 2001 From: Ben Mayer <90480641+Libadoxon@users.noreply.github.com> Date: Mon, 8 Jun 2026 05:18:14 +0200 Subject: [PATCH 07/25] turn: allow for providing secret via file (#4564) * turn: allow for providing secret via file * turn: improve secret_file changes --- cmd/server/main.go | 4 ++++ config-sample.yaml | 3 +++ pkg/config/config.go | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index ec2c0bf75..dde5b0adc 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -259,6 +259,10 @@ func startServer(ctx context.Context, c *cli.Command) error { return err } + if err = conf.LoadTURNSecrets(); err != nil { + return err + } + if cpuProfile := c.String("cpuprofile"); cpuProfile != "" { if f, err := os.Create(cpuProfile); err != nil { return err diff --git a/config-sample.yaml b/config-sample.yaml index 0559d7712..7a1eece37 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -98,6 +98,9 @@ rtc: # protocol: tls # # Shared secret for TURN server authentication # secret: "" + # # Path for file containing shared secret for TURN server authentication + # # When both secret and secret_file are set, secret takes precedence + # secret_file: "/var/lib/coturn/secret" # ttl: 14400 # seconds # # Insecure username/password authentication # username: "" diff --git a/pkg/config/config.go b/pkg/config/config.go index f155eb59d..6d65973f9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -49,8 +49,9 @@ const ( ) var ( - ErrKeyFileIncorrectPermission = errors.New("key file others permissions must be set to 0") - ErrKeysNotSet = errors.New("one of key-file or keys must be provided") + ErrKeyFileIncorrectPermission = errors.New("key file others permissions must be set to 0") + ErrTURNSecretFileIncorrectPermission = errors.New("turn secret file others permissions must be set to 0") + ErrKeysNotSet = errors.New("one of key-file or keys must be provided") ) type Config struct { @@ -149,6 +150,8 @@ type TURNServer struct { // Secret is used for TURN static auth secrets mechanism. When provided, // dynamic credentials are generated using HMAC-SHA1 instead of static Username/Credential Secret string `yaml:"secret,omitempty"` + // File containing the secret + SecretFile string `yaml:"secret_file,omitempty"` // TTL is the time-to-live in seconds for generated credentials when using Secret. // Defaults to 14400 seconds (4 hours) if not specified TTL int `yaml:"ttl,omitempty"` @@ -642,6 +645,33 @@ func (conf *Config) ValidateKeys() error { return nil } +func (conf *Config) LoadTURNSecrets() error { + var otherFilter os.FileMode = 0o007 + for i, s := range conf.RTC.TURNServers { + if s.SecretFile == "" { + continue + } + if s.Secret != "" { + logger.Warnw("both secret and secret_file are set for TURN server, the hardcoded secret will be used", nil, + "host", s.Host, "port", s.Port) + continue + } + st, err := os.Stat(s.SecretFile) + if err != nil { + return err + } + if st.Mode().Perm()&otherFilter != 0o000 { + return ErrTURNSecretFileIncorrectPermission + } + data, err := os.ReadFile(s.SecretFile) + if err != nil { + return fmt.Errorf("reading turn secret file %q: %w", s.SecretFile, err) + } + conf.RTC.TURNServers[i].Secret = strings.TrimSpace(string(data)) + } + return nil +} + func GenerateCLIFlags(existingFlags []cli.Flag, hidden bool) ([]cli.Flag, error) { defaultConfig := &DefaultConfig flags := make([]cli.Flag, 0) From dc8e0310ad3c5bdd0c8c504d5eee7039d3fba9fd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:07:40 -0700 Subject: [PATCH 08/25] Update go deps to v4 (#4482) * Update go deps to v4 Generated by renovateBot * update dockertest to v4 * fix --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: David Zhao --- go.mod | 28 +++++--------- go.sum | 76 ++------------------------------------ pkg/service/docker_test.go | 25 ++++++++----- 3 files changed, 28 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index d2b5dad1e..1939b7245 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,9 @@ require ( github.com/magefile/mage v1.17.0 github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 github.com/mitchellh/go-homedir v1.1.0 + github.com/moby/moby/client v0.4.1 github.com/olekukonko/tablewriter v1.1.4 - github.com/ory/dockertest/v3 v3.12.0 + github.com/ory/dockertest/v4 v4.0.0 github.com/pion/datachannel v1.6.0 github.com/pion/dtls/v3 v3.1.3 github.com/pion/ice/v4 v4.2.7 @@ -61,23 +62,28 @@ require ( require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cilium/ebpf v0.16.0 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/fatih/color v1.19.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/goccy/go-json v0.10.6 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.22 // indirect - github.com/moby/sys/user v0.3.0 // indirect + github.com/moby/moby/api v1.54.2 // indirect github.com/nyaruka/phonenumbers v1.8.0 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/errors v1.3.0 // indirect github.com/olekukonko/ll v0.1.8 // indirect github.com/puzpuzpuz/xsync/v4 v4.5.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 // indirect @@ -95,27 +101,18 @@ require ( buf.build/go/protovalidate v1.2.0 // indirect buf.build/go/protoyaml v0.7.0 // indirect cel.dev/expr v0.25.2 // indirect - dario.cat/mergo v1.0.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/containerd/continuity v0.4.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/docker/cli v27.4.1+incompatible // indirect - github.com/docker/docker v27.1.1+incompatible // indirect github.com/docker/go-connections v0.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/google/cel-go v0.28.1 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/subcommands v1.2.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect @@ -128,14 +125,12 @@ require ( github.com/mdlayher/netlink v1.11.2 // indirect github.com/mdlayher/socket v0.6.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/term v0.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nats.go v1.52.0 // indirect github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/opencontainers/runc v1.2.3 // indirect github.com/pion/logging v0.2.4 // indirect github.com/pion/mdns/v2 v2.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect @@ -145,12 +140,8 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.68.1 // indirect github.com/prometheus/procfs v0.20.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/urfave/cli/v3 v3.9.0 github.com/wlynxg/anet v0.0.5 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zeebo/xxh3 v1.1.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect golang.org/x/crypto v0.52.0 // indirect @@ -161,7 +152,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/grpc v1.81.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect ) // for gst whipsink compatibility diff --git a/go.sum b/go.sum index 9021fffff..92644c2e9 100644 --- a/go.sum +++ b/go.sum @@ -6,16 +6,8 @@ buf.build/go/protoyaml v0.7.0 h1:z4oVoFicbpPefhT7WAykxUdfp0yEQlhMQ2mCZOY5V38= buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MGSQ0= cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -30,8 +22,6 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -45,15 +35,11 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= -github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/d5/tengo/v2 v2.17.0 h1:BWUN9NoJzw48jZKiYDXDIF3QrIVZRm1uV1gTzeZ2lqM= github.com/d5/tengo/v2 v2.17.0/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -64,10 +50,6 @@ github.com/dennwc/iters v1.2.2 h1:XH2/Etihiy9ZvPOVCR+icQXeYlhbvS7k0qro4x/2qQo= github.com/dennwc/iters v1.2.2/go.mod h1:M9KuuMBeyEXYTmB7EnI9SCyALFCmPWOIxn5W1L0CjGg= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= -github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= -github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -97,14 +79,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= -github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -123,8 +99,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -165,8 +139,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786 h1:N527AHMa79 github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -182,8 +154,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkIcHO0h8c= github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc= @@ -233,10 +203,6 @@ github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg= github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY= github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ= -github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= -github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= @@ -261,10 +227,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= -github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= -github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= -github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/ory/dockertest/v4 v4.0.0 h1:i19aFsO/VXE0VrMk4ifnKW4G/KIJ93PCjLOslxXoPME= github.com/ory/dockertest/v4 v4.0.0/go.mod h1:b5Ofu8VIxWNhXFvQcLu17pRNQdoUBKtXBW74G4Ygzx8= github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= @@ -331,12 +293,8 @@ github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk= github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= @@ -353,15 +311,6 @@ github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8 github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= @@ -401,26 +350,20 @@ go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q= golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -430,9 +373,6 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= @@ -457,10 +397,8 @@ golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= @@ -475,13 +413,8 @@ golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= @@ -500,10 +433,9 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= diff --git a/pkg/service/docker_test.go b/pkg/service/docker_test.go index a3da60484..1168d5982 100644 --- a/pkg/service/docker_test.go +++ b/pkg/service/docker_test.go @@ -15,27 +15,31 @@ package service_test import ( + "context" "fmt" "log" "net" "os" "testing" + "time" "go.uber.org/atomic" - "github.com/ory/dockertest/v3" + mobyclient "github.com/moby/moby/client" + "github.com/ory/dockertest/v4" ) -var Docker *dockertest.Pool +var Docker dockertest.ClosablePool func TestMain(m *testing.M) { - pool, err := dockertest.NewPool("") + ctx := context.Background() + pool, err := dockertest.NewPool(ctx, "") if err != nil { log.Fatalf("Could not construct pool: %s", err) } // uses pool to try to connect to Docker - err = pool.Client.Ping() + _, err = pool.Client().Ping(ctx, mobyclient.PingOptions{}) if err != nil { log.Fatalf("Could not connect to Docker: %s", err) } @@ -46,7 +50,7 @@ func TestMain(m *testing.M) { } func waitTCPPort(t testing.TB, addr string) { - if err := Docker.Retry(func() error { + if err := Docker.Retry(t.Context(), 30*time.Second, func() error { conn, err := net.Dial("tcp", addr) if err != nil { t.Log(err) @@ -62,15 +66,16 @@ func waitTCPPort(t testing.TB, addr string) { var redisLast atomic.Uint32 func runRedis(t testing.TB) string { - c, err := Docker.RunWithOptions(&dockertest.RunOptions{ - Name: fmt.Sprintf("lktest-redis-%d", redisLast.Inc()), - Repository: "redis", Tag: "latest", - }) + c, err := Docker.Run(t.Context(), + "redis", + dockertest.WithName(fmt.Sprintf("lktest-redis-%d", redisLast.Inc())), + dockertest.WithTag("latest"), + ) if err != nil { t.Fatal(err) } t.Cleanup(func() { - _ = Docker.Purge(c) + _ = c.Close(t.Context()) }) addr := c.GetHostPort("6379/tcp") waitTCPPort(t, addr) From c4e41872c5f38652cd98ccead39e741808f1fed1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:08:05 -0700 Subject: [PATCH 09/25] Update go deps to v1.17.2 (#4462) Generated by renovateBot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1939b7245..5e86e399f 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 github.com/livekit/psrpc v0.7.2 github.com/mackerelio/go-osstat v0.2.7 - github.com/magefile/mage v1.17.0 + github.com/magefile/mage v1.17.2 github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 github.com/mitchellh/go-homedir v1.1.0 github.com/moby/moby/client v0.4.1 diff --git a/go.sum b/go.sum index 92644c2e9..f54806265 100644 --- a/go.sum +++ b/go.sum @@ -166,8 +166,8 @@ github.com/livekit/psrpc v0.7.2 h1:6oZ+NODJ2pLyaT6VqDq1F4Qc/3TpDUSpyphj/P9MhQc= github.com/livekit/psrpc v0.7.2/go.mod h1:rAI+m2+/cb4x9RXhLRtUx5ZwdfjjXOl4zi46IjEetaw= github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94= github.com/mackerelio/go-osstat v0.2.7/go.mod h1:dwpYh5pIPmvk+IEwBKNIWRFMB92mrC08CmXOhDC7nQk= -github.com/magefile/mage v1.17.0 h1:dS4tkq997Ism03akafC8509iqDjeE7TNTexI25Y7sXM= -github.com/magefile/mage v1.17.0/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA= +github.com/magefile/mage v1.17.2 h1:fyXVu1eadI8Ap1HCCNgEhJ5McIWiYhLR8uol64ZZc40= +github.com/magefile/mage v1.17.2/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= From 8be8c74a59ea37eb184d89e145c8906d00814db9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:08:50 -0700 Subject: [PATCH 10/25] Update github workflows (#4463) Generated by renovateBot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/buildtest.yaml | 2 +- .github/workflows/docker.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/buildtest.yaml b/.github/workflows/buildtest.yaml index be0e93d8f..284ecf87a 100644 --- a/.github/workflows/buildtest.yaml +++ b/.github/workflows/buildtest.yaml @@ -71,7 +71,7 @@ jobs: # Upload the original go test log as an artifact for later review. - name: Upload test log - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: test-log diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index feefd280f..1ee39fe6f 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -62,14 +62,14 @@ jobs: - name: Login to DockerHub if: github.event_name != 'pull_request' - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7 with: context: . push: ${{ github.event_name != 'pull_request' }} From fd452212c7ade49316d9aa029476b87bf383390f Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Mon, 8 Jun 2026 12:42:58 +0530 Subject: [PATCH 11/25] Update mediatransportutil to get ICE candidate timeout config (#4572) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5e86e399f..bddcbc300 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/jellydator/ttlcache/v3 v3.4.0 github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 - github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e + github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 github.com/livekit/psrpc v0.7.2 github.com/mackerelio/go-osstat v0.2.7 diff --git a/go.sum b/go.sum index f54806265..0e03e4731 100644 --- a/go.sum +++ b/go.sum @@ -158,8 +158,8 @@ github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkI github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc= github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= -github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e h1:SkgQRcG2VYEhh80Qb/zYZo8rWKJzNfJcfUQnXe6su2M= -github.com/livekit/mediatransportutil v0.0.0-20260605212259-862d4a7bcb1e/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= +github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 h1:XHNNzebIKZRkLimla/hFGrAIX5EMWHctrgt3hLw7s+I= +github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 h1:dkHHthyor9dwxxdBmbeG1ZUI4bPHpTEk9DjYJSSSIl4= github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= github.com/livekit/psrpc v0.7.2 h1:6oZ+NODJ2pLyaT6VqDq1F4Qc/3TpDUSpyphj/P9MhQc= From b93c1e160770d93179dc5b1c9027567befec5e62 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Mon, 8 Jun 2026 13:46:52 +0530 Subject: [PATCH 12/25] Release v1.13.0. (#4573) Please see note about TURN authentication without TTL backwards compatibility removal. --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ version/version.go | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7a77413..36f356366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.13.0] - 2026-06-08 + +## ATTENTION: This release removes backwards compatibility for TURN authentication without TTL. Please refer to change log of [1.12.0](https://github.com/livekit/livekit/releases/tag/v1.12.0) for details on changes to TURN authentication and permissions handling. It was removed in https://github.com/livekit/livekit/pull/4539. + +### Added + +- rtc: report participant kind code and details (#4534) +- Add IsIntentionalDisconnect (#4537) +- rtc: emit per-data-track bytes via BytesTrackStats (#4540) +- Start tracking Twirp method request latency in prometheus too, not just in logs (#4545) +- Config documentation for advertise_internal_ip and skip_external_ip_validation (#4552, #4554, #4563) +- Metrics for participant active, i. e. fully established. (#4557) +- turn: allow for providing secret via file (#4564) + +### Changed + +- Always enable rtx codec (#4533) +- Don't require media sections when joining (#4535) +- Use NACKQuueInterface type. (#4538) +- Remove backwards compatibility support for TURN auth. (#4539) +- telemetry: split webhook-processed hook out of NewTelemetryService (#4548) +- rtc: prevent duration reporting for inactive participants (#4550) +- rtc: report participant session end time on room move (#4561) +- Update mediatransportutil to get ICE candidate timeout config (#4572) + +### Fixed + +- Check Less and LessEq in version compare. (#4532) +- fix sip error categorization (#4528) +- handle nil clientInfo (#4546, #4547) +- Prevent panic from nil(illegal) syncState.Subscriptions message (#4560) + ## [1.12.0] - 2026-05-16 ## ATTENTION: This release introduces important changes to how TURN authentication and permissions are handled. These changes make the system more secure. This release maintains backwards compatibility. However, backwards compatibility will be removed in the next release. So, please plan accordingly. diff --git a/version/version.go b/version/version.go index 0abeb937f..94e557d56 100644 --- a/version/version.go +++ b/version/version.go @@ -14,4 +14,4 @@ package version -const Version = "1.12.0" +const Version = "1.13.0" From bfd9deffd74b849dccb825a1dbf3adda0423e46f Mon Sep 17 00:00:00 2001 From: Dan Root Date: Mon, 8 Jun 2026 09:07:08 -0500 Subject: [PATCH 13/25] expose TCPFallbackRTTThreshold and AllowUDPUnstableFallback via config (#4556) --- config-sample.yaml | 6 ++++ pkg/config/config.go | 12 ++++++++ pkg/service/roommanager.go | 58 ++++++++++++++++++++------------------ 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/config-sample.yaml b/config-sample.yaml index 7a1eece37..f264e721e 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -114,6 +114,12 @@ rtc: # allow_pause: true # # allows automatic connection fallback to TCP and TURN/TLS (if configured) when UDP has been unstable, default true # allow_tcp_fallback: true + # # signaling RTT (in milliseconds) below which ICE/TCP is attempted on a UDP failure; at or above it, + # # supporting clients fall back directly to TURN/TLS. 0 (default) disables the check (ICE/TCP always tried). + # # a positive value also enables allow_udp_unstable_fallback. + # tcp_fallback_rtt_threshold: 0 + # # migrate an established-but-lossy UDP connection to ICE/TCP or TURN/TLS. requires tcp_fallback_rtt_threshold > 0, default false + # allow_udp_unstable_fallback: false # # number of packets to buffer in the SFU for video, defaults to 500 # packet_buffer_size_video: 500 # # number of packets to buffer in the SFU for audio, defaults to 200 diff --git a/pkg/config/config.go b/pkg/config/config.go index 6d65973f9..68d3e8a2c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -116,6 +116,18 @@ type RTCConfig struct { // allow TCP and TURN/TLS fallback AllowTCPFallback *bool `yaml:"allow_tcp_fallback,omitempty"` + // Signaling RTT threshold (in milliseconds) governing ICE/TCP fallback. On a UDP + // failure, ICE/TCP is attempted only while the measured signaling RTT is below this + // value; at or above it, supporting clients fall back directly to TURN/TLS. When 0 + // (the default), the RTT check is disabled and ICE/TCP is always attempted (for + // clients that support it). A positive value also gates allow_udp_unstable_fallback. + TCPFallbackRTTThreshold int `yaml:"tcp_fallback_rtt_threshold,omitempty"` + + // When enabled, an established UDP connection reporting sustained high packet loss is + // migrated to ICE/TCP or TURN/TLS. Requires tcp_fallback_rtt_threshold to be set + // (> 0). Disabled by default. + AllowUDPUnstableFallback bool `yaml:"allow_udp_unstable_fallback,omitempty"` + // force a reconnect on a publication error ReconnectOnPublicationError *bool `yaml:"reconnect_on_publication_error,omitempty"` diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 65eeb5eda..9419e282e 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -471,34 +471,36 @@ func (r *RoomManager) StartSession( } participant, err = rtc.NewParticipant(rtc.ParticipantParams{ - Identity: pi.Identity, - Name: pi.Name, - SID: sid, - Config: &rtcConf, - Sink: responseSink, - AudioConfig: r.config.Audio, - VideoConfig: r.config.Video, - LimitConfig: r.config.Limit, - ProtocolVersion: pv, - SessionStartTime: sessionStartTime, - SessionTimer: observability.NewSessionTimer(sessionStartTime), - TelemetryListener: room.ParticipantTelemetryListener(), - Trailer: room.Trailer(), - PLIThrottleConfig: r.config.RTC.PLIThrottle, - CongestionControlConfig: r.config.RTC.CongestionControl, - PublishEnabledCodecs: enabledCodecs, - SubscribeEnabledCodecs: enabledCodecs, - Grants: pi.Grants, - Reconnect: pi.Reconnect, - Logger: pLogger, - Reporter: roomobs.NewNoopParticipantSessionReporter(), - ClientConf: clientConf, - ClientInfo: rtc.ClientInfo{ClientInfo: pi.Client}, - Region: pi.Region, - AdaptiveStream: pi.AdaptiveStream, - AllowTCPFallback: allowFallback, - TURNSEnabled: r.config.IsTURNSEnabled(), - ParticipantListener: room.LocalParticipantListener(), + Identity: pi.Identity, + Name: pi.Name, + SID: sid, + Config: &rtcConf, + Sink: responseSink, + AudioConfig: r.config.Audio, + VideoConfig: r.config.Video, + LimitConfig: r.config.Limit, + ProtocolVersion: pv, + SessionStartTime: sessionStartTime, + SessionTimer: observability.NewSessionTimer(sessionStartTime), + TelemetryListener: room.ParticipantTelemetryListener(), + Trailer: room.Trailer(), + PLIThrottleConfig: r.config.RTC.PLIThrottle, + CongestionControlConfig: r.config.RTC.CongestionControl, + PublishEnabledCodecs: enabledCodecs, + SubscribeEnabledCodecs: enabledCodecs, + Grants: pi.Grants, + Reconnect: pi.Reconnect, + Logger: pLogger, + Reporter: roomobs.NewNoopParticipantSessionReporter(), + ClientConf: clientConf, + ClientInfo: rtc.ClientInfo{ClientInfo: pi.Client}, + Region: pi.Region, + AdaptiveStream: pi.AdaptiveStream, + AllowTCPFallback: allowFallback, + TCPFallbackRTTThreshold: r.config.RTC.TCPFallbackRTTThreshold, + AllowUDPUnstableFallback: r.config.RTC.AllowUDPUnstableFallback, + TURNSEnabled: r.config.IsTURNSEnabled(), + ParticipantListener: room.LocalParticipantListener(), ParticipantHelper: &roomManagerParticipantHelper{ room: room, codecRegressionThreshold: r.config.Video.CodecRegressionThreshold, From e0815be27d1ae0490ddb101722fc6798e42ce097 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 8 Jun 2026 08:27:15 -0700 Subject: [PATCH 14/25] chore: improve docker test shutdown reliability (#4576) --- pkg/service/docker_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/service/docker_test.go b/pkg/service/docker_test.go index 1168d5982..9fc5b90bb 100644 --- a/pkg/service/docker_test.go +++ b/pkg/service/docker_test.go @@ -75,7 +75,9 @@ func runRedis(t testing.TB) string { t.Fatal(err) } t.Cleanup(func() { - _ = c.Close(t.Context()) + // t.Context() is canceled before cleanup funcs run, so use a + // non-canceled context to let the container stop/remove complete. + _ = c.Close(context.Background()) }) addr := c.GetHostPort("6379/tcp") waitTCPPort(t, addr) From 46c4309554d37d23ee8da88a8a7e02a68fba09c1 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 8 Jun 2026 16:15:09 -0700 Subject: [PATCH 15/25] fix goreleaser workflow, version 1.13.1 (#4577) --- .goreleaser.yaml | 5 ++++- CHANGELOG.md | 6 ++++++ version/version.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 44b98294b..22f3d0e4a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -53,7 +53,10 @@ changelog: - '^docs:' - '^test:' gomod: - proxy: true + # proxy must be disabled: it re-fetches modules from the Go proxy in a clean + # directory, which does not honor the replace directive in go.mod + # (replace github.com/pion/dtls/v3 => ... pinning v3.1.2 for gst whipsink compat) + proxy: false mod: mod checksum: name_template: 'checksums.txt' diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f356366..233153522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.13.1] - 2026-06-08 + +### Fixed + +- ci: disable goreleaser gomod proxy, incompatible with go.mod replace directive + ## [1.13.0] - 2026-06-08 ## ATTENTION: This release removes backwards compatibility for TURN authentication without TTL. Please refer to change log of [1.12.0](https://github.com/livekit/livekit/releases/tag/v1.12.0) for details on changes to TURN authentication and permissions handling. It was removed in https://github.com/livekit/livekit/pull/4539. diff --git a/version/version.go b/version/version.go index 94e557d56..fbc9dc1e2 100644 --- a/version/version.go +++ b/version/version.go @@ -14,4 +14,4 @@ package version -const Version = "1.13.0" +const Version = "1.13.1" From 8d2b827f44adf1b9c3ec84b4eb86b24eb59c7ca6 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Tue, 9 Jun 2026 16:11:03 +0530 Subject: [PATCH 16/25] Add prom metrics for peer connectino state. (#4574) * Add prom metrics for peer connectino state. By direction (PUBLISHER vs SUBSCRIBER) and state ("started" -> "connected"). This gives a way to track peer connections failing to finish establishment. The RTC active count can be useful for primary peer connection, but not for non-primary. This counter can be used to track any and can generally be used to understand success/failure rate of peer connection establishment. * add a couple of more states * clean up and avoid duplicate reporting fully established * staticcheck --- pkg/rtc/transport.go | 27 ++++++++++++++++++++++++++- pkg/telemetry/prometheus/rooms.go | 13 +++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/pkg/rtc/transport.go b/pkg/rtc/transport.go index 8f6a5e50a..0848ae137 100644 --- a/pkg/rtc/transport.go +++ b/pkg/rtc/transport.go @@ -232,6 +232,8 @@ type PCTransport struct { resetShortConnOnICERestart atomic.Bool signalingRTT atomic.Uint32 // milliseconds + hasFullyEstablishedRecorded bool + debouncedNegotiate *sfuutils.Debouncer debouncePending bool lastNegotiate time.Time @@ -717,6 +719,8 @@ func (t *PCTransport) setICEConnectedAt(at time.Time) { t.tcpICETimer.Stop() t.tcpICETimer = nil } + + prometheus.RecordPeerConnectionState(t.params.Transport, "ice_connected") } if t.mayFailedICEStatsTimer != nil { @@ -801,6 +805,7 @@ func (t *PCTransport) setConnectedAt(at time.Time) bool { t.firstConnectedAt = at prometheus.RecordServiceOperationSuccess("peer_connection") + prometheus.RecordPeerConnectionState(t.params.Transport, "connected") t.lock.Unlock() return true } @@ -964,6 +969,13 @@ func (t *PCTransport) onDataChannel(dc *webrtc.DataChannel) { func (t *PCTransport) maybeNotifyFullyEstablished() { if t.isFullyEstablished() { t.params.Handler.OnFullyEstablished() + + t.lock.Lock() + if !t.hasFullyEstablishedRecorded { + t.hasFullyEstablishedRecorded = true + prometheus.RecordPeerConnectionState(t.params.Transport, "fully_established") + } + t.lock.Unlock() } } @@ -2604,6 +2616,8 @@ func (t *PCTransport) createAndSendOffer(options *webrtc.OfferOptions) error { t.params.Logger.Debugw("local offer (unfiltered)", "sdp", offer.SDP) } + isStartOfConnectionSequence := t.pc.LocalDescription() == nil + err = t.pc.SetLocalDescription(offer) if err != nil { if errors.Is(err, webrtc.ErrConnectionClosed) { @@ -2615,6 +2629,10 @@ func (t *PCTransport) createAndSendOffer(options *webrtc.OfferOptions) error { return errors.Wrap(err, "setting local description failed") } + if isStartOfConnectionSequence { + prometheus.RecordPeerConnectionState(t.params.Transport, "started") + } + // // Filter after setting local description as pion expects the offer // to match between CreateOffer and SetLocalDescription. @@ -2788,7 +2806,7 @@ func (t *PCTransport) createAndSendAnswer() error { return errors.Wrap(err, "could not send answer") } t.localAnswerId.Store(answerId) - prometheus.RecordServiceOperationSuccess("asnwer") + prometheus.RecordServiceOperationSuccess("answer") if err := t.sendUnmatchedMediaRequirement(false); err != nil { return err @@ -2860,9 +2878,16 @@ func (t *PCTransport) handleRemoteOfferReceived(sd *webrtc.SessionDescription, o t.outputAndClearICEStats() } + isStartOfConnectionSequence := t.pc.RemoteDescription() == nil + if err := t.setRemoteDescription(*sd); err != nil { return err } + + if isStartOfConnectionSequence { + prometheus.RecordPeerConnectionState(t.params.Transport, "started") + } + t.params.Handler.OnSetRemoteDescriptionOffer() t.processSendersPendingConfig() diff --git a/pkg/telemetry/prometheus/rooms.go b/pkg/telemetry/prometheus/rooms.go index 00ec4b11c..4001c24d9 100644 --- a/pkg/telemetry/prometheus/rooms.go +++ b/pkg/telemetry/prometheus/rooms.go @@ -49,6 +49,8 @@ var ( promSessionStartTime *prometheus.HistogramVec promSessionDuration *prometheus.HistogramVec promPubSubTime *prometheus.HistogramVec + + promPeerConnection *prometheus.CounterVec ) func initRoomStats(nodeID string, nodeType livekit.NodeType) { @@ -118,6 +120,12 @@ func initRoomStats(nodeID string, nodeType livekit.NodeType) { ConstLabels: prometheus.Labels{"node_id": nodeID, "node_type": nodeType.String()}, Buckets: []float64{100, 200, 500, 700, 1000, 5000, 10000}, }, append(promStreamLabels, "sdk", "kind", "count")) + promPeerConnection = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: livekitNamespace, + Subsystem: "peer_connection", + Name: "state", + ConstLabels: prometheus.Labels{"node_id": nodeID, "node_type": nodeType.String()}, + }, []string{"transport", "state"}) prometheus.MustRegister(promRoomCurrent) prometheus.MustRegister(promRoomDuration) @@ -129,6 +137,7 @@ func initRoomStats(nodeID string, nodeType livekit.NodeType) { prometheus.MustRegister(promSessionStartTime) prometheus.MustRegister(promSessionDuration) prometheus.MustRegister(promPubSubTime) + prometheus.MustRegister(promPeerConnection) } func RoomStarted() { @@ -269,3 +278,7 @@ func RecordSessionStartTime(protocolVersion int, d time.Duration) { func RecordSessionDuration(protocolVersion int, d time.Duration) { promSessionDuration.WithLabelValues(strconv.Itoa(protocolVersion)).Observe(float64(d.Milliseconds())) } + +func RecordPeerConnectionState(transport livekit.SignalTarget, state string) { + promPeerConnection.WithLabelValues(transport.String(), state).Inc() +} From 7dc68777386a9185cf7943d2cd8390c70250e544 Mon Sep 17 00:00:00 2001 From: cnderrauber Date: Wed, 10 Jun 2026 14:51:10 +0800 Subject: [PATCH 17/25] Preserve original expiry when refreshing token (#4580) To avoid shortening the token expiration time during refreshing cause client reconnect failed after network down for a long time (>5min). --- go.mod | 2 +- go.sum | 4 +- pkg/routing/interfaces.go | 16 +++++ pkg/rtc/participant.go | 5 ++ pkg/rtc/types/interfaces.go | 1 + .../typesfakes/fake_local_participant.go | 63 +++++++++++++++++++ pkg/service/auth.go | 27 ++++++-- pkg/service/roommanager.go | 12 +++- pkg/service/rtcservice.go | 1 + pkg/service/utils.go | 3 + 10 files changed, 125 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index bddcbc300..889a72501 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 - github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 + github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6 github.com/livekit/psrpc v0.7.2 github.com/mackerelio/go-osstat v0.2.7 github.com/magefile/mage v1.17.2 diff --git a/go.sum b/go.sum index 0e03e4731..e16452377 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 h1:XHNNzebIKZRkLimla/hFGrAIX5EMWHctrgt3hLw7s+I= github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= -github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84 h1:dkHHthyor9dwxxdBmbeG1ZUI4bPHpTEk9DjYJSSSIl4= -github.com/livekit/protocol v1.46.7-0.20260605212020-c0615a2f6f84/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= +github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6 h1:AK8JNLn2H3+ixSfh9gdFDqI+IpBV1YASGAusqaV5gFs= +github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= github.com/livekit/psrpc v0.7.2 h1:6oZ+NODJ2pLyaT6VqDq1F4Qc/3TpDUSpyphj/P9MhQc= github.com/livekit/psrpc v0.7.2/go.mod h1:rAI+m2+/cb4x9RXhLRtUx5ZwdfjjXOl4zi46IjEetaw= github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94= diff --git a/pkg/routing/interfaces.go b/pkg/routing/interfaces.go index 6b2e1b6ce..08395efa0 100644 --- a/pkg/routing/interfaces.go +++ b/pkg/routing/interfaces.go @@ -17,6 +17,7 @@ package routing import ( "context" "encoding/json" + "time" "github.com/redis/go-redis/v9" "go.uber.org/atomic" @@ -192,6 +193,7 @@ type ParticipantInit struct { AutoSubscribeDataTrack *bool Client *livekit.ClientInfo Grants *auth.ClaimGrants + TokenExpiresAt time.Time Region string AdaptiveStream bool ID livekit.ParticipantID @@ -224,6 +226,9 @@ func (pi *ParticipantInit) MarshalLogObject(e zapcore.ObjectEncoder) error { logBoolPtr("AutoSubscribeDataTrack", pi.AutoSubscribeDataTrack) e.AddObject("Client", logger.Proto(utils.ClientInfoWithoutAddress(pi.Client))) e.AddObject("Grants", pi.Grants) + if !pi.TokenExpiresAt.IsZero() { + e.AddTime("TokenExpiresAt", pi.TokenExpiresAt) + } e.AddString("Region", pi.Region) logBoolPtr("AdaptiveStream", &pi.AdaptiveStream) e.AddString("ID", string(pi.ID)) @@ -243,6 +248,11 @@ func (pi *ParticipantInit) ToStartSession(roomName livekit.RoomName, connectionI return nil, err } + var tokenExpiresAt int64 + if !pi.TokenExpiresAt.IsZero() { + tokenExpiresAt = pi.TokenExpiresAt.Unix() + } + ss := &livekit.StartSession{ RoomName: string(roomName), Identity: string(pi.Identity), @@ -253,6 +263,7 @@ func (pi *ParticipantInit) ToStartSession(roomName livekit.RoomName, connectionI AutoSubscribe: pi.AutoSubscribe, Client: pi.Client, GrantsJson: string(claims), + TokenExpiresAt: tokenExpiresAt, AdaptiveStream: pi.AdaptiveStream, ParticipantId: string(pi.ID), DisableIceLite: pi.DisableICELite, @@ -279,6 +290,10 @@ func ParticipantInitFromStartSession(ss *livekit.StartSession, region string) (* if err := json.Unmarshal([]byte(ss.GrantsJson), claims); err != nil { return nil, err } + var tokenExpiresAt time.Time + if ss.TokenExpiresAt > 0 { + tokenExpiresAt = time.Unix(ss.TokenExpiresAt, 0) + } pi := &ParticipantInit{ Identity: livekit.ParticipantIdentity(ss.Identity), @@ -288,6 +303,7 @@ func ParticipantInitFromStartSession(ss *livekit.StartSession, region string) (* Client: ss.Client, AutoSubscribe: ss.AutoSubscribe, Grants: claims, + TokenExpiresAt: tokenExpiresAt, Region: region, AdaptiveStream: ss.AdaptiveStream, ID: livekit.ParticipantID(ss.ParticipantId), diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 2b71174fb..bf2ebdb5b 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -182,6 +182,7 @@ type ParticipantParams struct { ReporterResolver roomobs.ParticipantReporterResolver SimTracks map[uint32]interceptor.SimulcastTrackInfo Grants *auth.ClaimGrants + TokenExpiresAt time.Time InitialVersion uint32 ClientConf *livekit.ClientConfiguration ClientInfo ClientInfo @@ -781,6 +782,10 @@ func (p *ParticipantImpl) ClaimGrants() *auth.ClaimGrants { return p.grants.Load() } +func (p *ParticipantImpl) TokenExpiresAt() time.Time { + return p.params.TokenExpiresAt +} + func (p *ParticipantImpl) SetPermission(permission *livekit.ParticipantPermission) bool { if permission == nil { return false diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index e77393e80..e402c4614 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -441,6 +441,7 @@ type LocalParticipant interface { // permissions ClaimGrants() *auth.ClaimGrants + TokenExpiresAt() time.Time SetPermission(permission *livekit.ParticipantPermission) bool CanPublish() bool CanPublishSource(source livekit.TrackSource) bool diff --git a/pkg/rtc/types/typesfakes/fake_local_participant.go b/pkg/rtc/types/typesfakes/fake_local_participant.go index 96686a0d1..76c32d76b 100644 --- a/pkg/rtc/types/typesfakes/fake_local_participant.go +++ b/pkg/rtc/types/typesfakes/fake_local_participant.go @@ -1342,6 +1342,16 @@ type FakeLocalParticipant struct { result1 *livekit.ParticipantInfo result2 utils.TimedVersion } + TokenExpiresAtStub func() time.Time + tokenExpiresAtMutex sync.RWMutex + tokenExpiresAtArgsForCall []struct { + } + tokenExpiresAtReturns struct { + result1 time.Time + } + tokenExpiresAtReturnsOnCall map[int]struct { + result1 time.Time + } UncacheDownTrackStub func(*webrtc.RTPTransceiver) uncacheDownTrackMutex sync.RWMutex uncacheDownTrackArgsForCall []struct { @@ -8616,6 +8626,59 @@ func (fake *FakeLocalParticipant) ToProtoWithVersionReturnsOnCall(i int, result1 }{result1, result2} } +func (fake *FakeLocalParticipant) TokenExpiresAt() time.Time { + fake.tokenExpiresAtMutex.Lock() + ret, specificReturn := fake.tokenExpiresAtReturnsOnCall[len(fake.tokenExpiresAtArgsForCall)] + fake.tokenExpiresAtArgsForCall = append(fake.tokenExpiresAtArgsForCall, struct { + }{}) + stub := fake.TokenExpiresAtStub + fakeReturns := fake.tokenExpiresAtReturns + fake.recordInvocation("TokenExpiresAt", []interface{}{}) + fake.tokenExpiresAtMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeLocalParticipant) TokenExpiresAtCallCount() int { + fake.tokenExpiresAtMutex.RLock() + defer fake.tokenExpiresAtMutex.RUnlock() + return len(fake.tokenExpiresAtArgsForCall) +} + +func (fake *FakeLocalParticipant) TokenExpiresAtCalls(stub func() time.Time) { + fake.tokenExpiresAtMutex.Lock() + defer fake.tokenExpiresAtMutex.Unlock() + fake.TokenExpiresAtStub = stub +} + +func (fake *FakeLocalParticipant) TokenExpiresAtReturns(result1 time.Time) { + fake.tokenExpiresAtMutex.Lock() + defer fake.tokenExpiresAtMutex.Unlock() + fake.TokenExpiresAtStub = nil + fake.tokenExpiresAtReturns = struct { + result1 time.Time + }{result1} +} + +func (fake *FakeLocalParticipant) TokenExpiresAtReturnsOnCall(i int, result1 time.Time) { + fake.tokenExpiresAtMutex.Lock() + defer fake.tokenExpiresAtMutex.Unlock() + fake.TokenExpiresAtStub = nil + if fake.tokenExpiresAtReturnsOnCall == nil { + fake.tokenExpiresAtReturnsOnCall = make(map[int]struct { + result1 time.Time + }) + } + fake.tokenExpiresAtReturnsOnCall[i] = struct { + result1 time.Time + }{result1} +} + func (fake *FakeLocalParticipant) UncacheDownTrack(arg1 *webrtc.RTPTransceiver) { fake.uncacheDownTrackMutex.Lock() fake.uncacheDownTrackArgsForCall = append(fake.uncacheDownTrackArgsForCall, struct { diff --git a/pkg/service/auth.go b/pkg/service/auth.go index f8e6442b5..4550296de 100644 --- a/pkg/service/auth.go +++ b/pkg/service/auth.go @@ -19,6 +19,7 @@ import ( "errors" "net/http" "strings" + "time" "github.com/twitchtv/twirp" @@ -35,8 +36,9 @@ const ( type grantsKey struct{} type grantsValue struct { - claims *auth.ClaimGrants - apiKey string + claims *auth.ClaimGrants + apiKey string + expiresAt time.Time } var ( @@ -90,17 +92,23 @@ func (m *APIKeyAuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, return } - _, grants, err := v.Verify(secret) + claims, grants, err := v.Verify(secret) if err != nil { HandleError(w, r, http.StatusUnauthorized, errors.New("invalid token: "+authToken+", error: "+err.Error())) return } + var expiresAt time.Time + if claims != nil && claims.ExpiresAt != nil { + expiresAt = claims.ExpiresAt.Time + } + // set grants in context ctx := r.Context() r = r.WithContext(context.WithValue(ctx, grantsKey{}, &grantsValue{ - claims: grants, - apiKey: v.APIKey(), + claims: grants, + apiKey: v.APIKey(), + expiresAt: expiresAt, })) } @@ -123,6 +131,15 @@ func GetGrants(ctx context.Context) *auth.ClaimGrants { return v.claims } +func GetTokenExpiresAt(ctx context.Context) time.Time { + val := ctx.Value(grantsKey{}) + v, ok := val.(*grantsValue) + if !ok { + return time.Time{} + } + return v.expiresAt +} + func GetAPIKey(ctx context.Context) string { val := ctx.Value(grantsKey{}) v, ok := val.(*grantsValue) diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 9419e282e..172a7752e 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -489,6 +489,7 @@ func (r *RoomManager) StartSession( PublishEnabledCodecs: enabledCodecs, SubscribeEnabledCodecs: enabledCodecs, Grants: pi.Grants, + TokenExpiresAt: pi.TokenExpiresAt, Reconnect: pi.Reconnect, Logger: pLogger, Reporter: roomobs.NewNoopParticipantSessionReporter(), @@ -1124,11 +1125,20 @@ func (r *RoomManager) refreshToken(participant types.LocalParticipant) error { } grants := participant.ClaimGrants() + + // Preserve the original token's expiry + validFor := tokenDefaultTTL + if expiresAt := participant.TokenExpiresAt(); !expiresAt.IsZero() { + if remaining := time.Until(expiresAt); remaining > validFor { + validFor = remaining + } + } + token := auth.NewAccessToken(key, secret) token.SetName(grants.Name). SetIdentity(string(participant.Identity())). SetKind(grants.GetParticipantKind()). - SetValidFor(tokenDefaultTTL). + SetValidFor(validFor). SetMetadata(grants.Metadata). SetAttributes(grants.Attributes). SetVideoGrant(grants.Video). diff --git a/pkg/service/rtcservice.go b/pkg/service/rtcservice.go index 1b6171851..d4f83e7cb 100644 --- a/pkg/service/rtcservice.go +++ b/pkg/service/rtcservice.go @@ -218,6 +218,7 @@ func (s *RTCService) validateInternal( Identity: livekit.ParticipantIdentity(res.grants.Identity), Name: livekit.ParticipantName(res.grants.Name), Grants: res.grants, + TokenExpiresAt: res.tokenExpiresAt, Region: res.region, CreateRoom: res.createRoomRequest, UseSinglePeerConnection: useSinglePeerConnection, diff --git a/pkg/service/utils.go b/pkg/service/utils.go index e129e2f83..be7c0dc99 100644 --- a/pkg/service/utils.go +++ b/pkg/service/utils.go @@ -28,6 +28,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/ua-parser/uap-go/uaparser" "gopkg.in/yaml.v3" @@ -289,6 +290,7 @@ type ValidateConnectRequestParams struct { type ValidateConnectRequestResult struct { roomName livekit.RoomName grants *auth.ClaimGrants + tokenExpiresAt time.Time region string createRoomRequest *livekit.CreateRoomRequest } @@ -402,6 +404,7 @@ func ValidateConnectRequest( } res.grants = claims + res.tokenExpiresAt = GetTokenExpiresAt(r.Context()) return res, http.StatusOK, nil } From 816d37281d1110ad3a0085f9210633e4219612db Mon Sep 17 00:00:00 2001 From: cnderrauber Date: Wed, 10 Jun 2026 17:44:58 +0800 Subject: [PATCH 18/25] Add grants expiry to Auth context (#4581) --- pkg/service/auth.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/service/auth.go b/pkg/service/auth.go index 4550296de..d019c4aae 100644 --- a/pkg/service/auth.go +++ b/pkg/service/auth.go @@ -150,9 +150,14 @@ func GetAPIKey(ctx context.Context) string { } func WithGrants(ctx context.Context, grants *auth.ClaimGrants, apiKey string) context.Context { + return WithGrantsExpiry(ctx, grants, apiKey, time.Time{}) +} + +func WithGrantsExpiry(ctx context.Context, grants *auth.ClaimGrants, apiKey string, expiresAt time.Time) context.Context { return context.WithValue(ctx, grantsKey{}, &grantsValue{ - claims: grants, - apiKey: apiKey, + claims: grants, + apiKey: apiKey, + expiresAt: expiresAt, }) } From 675caa208f0b9540f87327241057a8f096fb2493 Mon Sep 17 00:00:00 2001 From: Benjamin Pracht Date: Wed, 10 Jun 2026 12:16:55 -0700 Subject: [PATCH 19/25] Add CODEOWNERS (#4583) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..f3afd16ec --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @livekit/cs-devs From 233a226438900d25d0615c26c26b58f8c60de9bd Mon Sep 17 00:00:00 2001 From: Trey Hakanson Date: Wed, 10 Jun 2026 21:23:39 -0700 Subject: [PATCH 20/25] Add ability to run pprof on dedicated HTTP server (#4584) This allows exposing the pprof/debug endpoints in a production environment more easily, where it shouldn't be exposed publicly. --- config-sample.yaml | 5 +++++ pkg/config/config.go | 5 +++++ pkg/service/server.go | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/config-sample.yaml b/config-sample.yaml index f264e721e..e4fd969c2 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -170,6 +170,11 @@ rtc: # when enabled, LiveKit will expose prometheus metrics on :6789/metrics # prometheus_port: 6789 +# expose /debug/pprof (and /debug/goroutine, /debug/rooms) on a dedicated port, +# separate from the public signalling port. only enabled when port is set. +# debug_handler_port: +# port: 7070 + # API key / secret pairs. # Keys are used for JWT authentication, server APIs would require a keypair in order to generate access tokens # and make calls to the server diff --git a/pkg/config/config.go b/pkg/config/config.go index 68d3e8a2c..692c0af38 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -60,6 +60,7 @@ type Config struct { // PrometheusPort is deprecated PrometheusPort uint32 `yaml:"prometheus_port,omitempty"` Prometheus PrometheusConfig `yaml:"prometheus,omitempty"` + DebugHandler DebugHandlerConfig `yaml:"debug_handler,omitempty"` RTC RTCConfig `yaml:"rtc,omitempty"` Redis redisLiveKit.RedisConfig `yaml:"redis,omitempty"` Audio sfu.AudioConfig `yaml:"audio,omitempty"` @@ -348,6 +349,10 @@ type PrometheusConfig struct { Password string `yaml:"password,omitempty"` } +type DebugHandlerConfig struct { + Port uint32 `yaml:"port,omitempty"` +} + type ForwardStatsConfig struct { SummaryInterval time.Duration `yaml:"summary_interval,omitempty"` ReportInterval time.Duration `yaml:"report_interval,omitempty"` diff --git a/pkg/service/server.go b/pkg/service/server.go index 4ca8561b0..05a51522c 100644 --- a/pkg/service/server.go +++ b/pkg/service/server.go @@ -21,7 +21,7 @@ import ( "fmt" "net" "net/http" - _ "net/http/pprof" + httppprof "net/http/pprof" "runtime" "runtime/pprof" "strconv" @@ -53,6 +53,7 @@ type LivekitServer struct { agentService *AgentService httpServer *http.Server promServer *http.Server + debugServer *http.Server router routing.Router roomManager *RoomManager signalServer *SignalServer @@ -171,6 +172,20 @@ func NewLivekitServer(conf *config.Config, } } + if conf.DebugHandler.Port > 0 { + debugMux := http.NewServeMux() + debugMux.HandleFunc("/debug/pprof/", httppprof.Index) + debugMux.HandleFunc("/debug/pprof/cmdline", httppprof.Cmdline) + debugMux.HandleFunc("/debug/pprof/profile", httppprof.Profile) + debugMux.HandleFunc("/debug/pprof/symbol", httppprof.Symbol) + debugMux.HandleFunc("/debug/pprof/trace", httppprof.Trace) + debugMux.HandleFunc("/debug/goroutine", s.debugGoroutines) + debugMux.HandleFunc("/debug/rooms", s.debugInfo) + s.debugServer = &http.Server{ + Handler: http.Handler(debugMux), + } + } + if err = router.RemoveDeadNodes(); err != nil { return } @@ -221,6 +236,7 @@ func (s *LivekitServer) Start() error { // ensure we could listen listeners := make([]net.Listener, 0) promListeners := make([]net.Listener, 0) + debugListeners := make([]net.Listener, 0) for _, addr := range addresses { ln, err := net.Listen("tcp", net.JoinHostPort(addr, strconv.Itoa(int(s.config.Port)))) if err != nil { @@ -235,6 +251,14 @@ func (s *LivekitServer) Start() error { } promListeners = append(promListeners, ln) } + + if s.debugServer != nil { + ln, err = net.Listen("tcp", net.JoinHostPort(addr, strconv.Itoa(int(s.config.DebugHandler.Port)))) + if err != nil { + return err + } + debugListeners = append(debugListeners, ln) + } } values := []any{ @@ -259,6 +283,9 @@ func (s *LivekitServer) Start() error { if s.config.Prometheus.Port != 0 { values = append(values, "portPrometheus", s.config.Prometheus.Port) } + if s.config.DebugHandler.Port != 0 { + values = append(values, "portDebugHandler", s.config.DebugHandler.Port) + } if s.config.Region != "" { values = append(values, "region", s.config.Region) } @@ -271,6 +298,10 @@ func (s *LivekitServer) Start() error { go s.promServer.Serve(promLn) } + for _, debugLn := range debugListeners { + go s.debugServer.Serve(debugLn) + } + if err := s.signalServer.Start(); err != nil { return err } @@ -302,6 +333,9 @@ func (s *LivekitServer) Start() error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() _ = s.httpServer.Shutdown(ctx) + if s.debugServer != nil { + _ = s.debugServer.Shutdown(ctx) + } if s.turnServer != nil { _ = s.turnServer.Close() From 8efc94eb68cf268ecfe446e6868e8556713b00b2 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Thu, 11 Jun 2026 12:23:55 +0530 Subject: [PATCH 21/25] Update DTLS to v3.1.4 (#4587) --- go.mod | 7 +------ go.sum | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 889a72501..1f478b7a2 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/olekukonko/tablewriter v1.1.4 github.com/ory/dockertest/v4 v4.0.0 github.com/pion/datachannel v1.6.0 - github.com/pion/dtls/v3 v3.1.3 + github.com/pion/dtls/v3 v3.1.4 github.com/pion/ice/v4 v4.2.7 github.com/pion/interceptor v0.1.45 github.com/pion/rtcp v1.2.16 @@ -153,8 +153,3 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/grpc v1.81.1 // indirect ) - -// for gst whipsink compatibility -// it is unclear what in pion/dtls v3.1.3 breaks compatibility, -// but both sides sends their first flights and do not make further progress -replace github.com/pion/dtls/v3 => github.com/pion/dtls/v3 v3.1.2 diff --git a/go.sum b/go.sum index e16452377..4fc8c8b0f 100644 --- a/go.sum +++ b/go.sum @@ -231,8 +231,8 @@ github.com/ory/dockertest/v4 v4.0.0 h1:i19aFsO/VXE0VrMk4ifnKW4G/KIJ93PCjLOslxXoP github.com/ory/dockertest/v4 v4.0.0/go.mod h1:b5Ofu8VIxWNhXFvQcLu17pRNQdoUBKtXBW74G4Ygzx8= github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= -github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= -github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= +github.com/pion/dtls/v3 v3.1.4 h1:QhvtMflMfu9Kf0RcDC5BJBle4caPskByrKQR6uuYqpY= +github.com/pion/dtls/v3 v3.1.4/go.mod h1:cr/qotLISUw/9C1m83ZPNZtj9WnXkYLpfCptPqbkInc= github.com/pion/ice/v4 v4.2.7 h1:zDEbC6MiEdhQpF8TxBOTws+NU6ZgGpveHrQq4Lc1kao= github.com/pion/ice/v4 v4.2.7/go.mod h1:9SNPaq0c7El/ki8leJzyCkK10zsskprR3zTNbO3monY= github.com/pion/interceptor v0.1.45 h1:6PUo/5829bIfRFIPPJQzuDn8EjxRTSB/CSD7QVCOaqo= From 688cc66ed8f1563fe490cd7e916ab1deed0f5379 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Thu, 11 Jun 2026 19:31:39 +0530 Subject: [PATCH 22/25] Add API to get latest node stats. (#4589) --- pkg/routing/nodestats.go | 11 ++++++++++- pkg/service/wire_gen.go | 4 ---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/routing/nodestats.go b/pkg/routing/nodestats.go index 999ae9cb3..ac16bb0ef 100644 --- a/pkg/routing/nodestats.go +++ b/pkg/routing/nodestats.go @@ -20,6 +20,7 @@ import ( "github.com/livekit/protocol/livekit" "github.com/livekit/protocol/logger" + "github.com/livekit/protocol/utils" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/telemetry/prometheus" @@ -29,7 +30,7 @@ type NodeStats struct { config config.NodeStatsConfig startedAt int64 - lock sync.Mutex + lock sync.RWMutex statsHistory []*livekit.NodeStats statsHistoryWritePtr int } @@ -80,3 +81,11 @@ func (n *NodeStats) UpdateAndGetNodeStats() (*livekit.NodeStats, error) { n.statsHistoryWritePtr = (n.statsHistoryWritePtr + 1) % len(n.statsHistory) return stats, nil } + +func (n *NodeStats) GetLatestNodeStats() *livekit.NodeStats { + n.lock.RLock() + defer n.lock.RUnlock() + + latestPtr := (n.statsHistoryWritePtr - 1 + len(n.statsHistory)) % len(n.statsHistory) + return utils.CloneProto(n.statsHistory[latestPtr]) +} diff --git a/pkg/service/wire_gen.go b/pkg/service/wire_gen.go index 5e9eff96c..45ebcf4d2 100644 --- a/pkg/service/wire_gen.go +++ b/pkg/service/wire_gen.go @@ -29,10 +29,6 @@ import ( "os" ) -import ( - _ "net/http/pprof" -) - // Injectors from wire.go: func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*LivekitServer, error) { From 08ab361e8ef85a7406bf134eea8e7838b1eb8699 Mon Sep 17 00:00:00 2001 From: shishirng Date: Thu, 11 Jun 2026 13:02:25 -0400 Subject: [PATCH 23/25] [WIP] rtc: add RestartSessionTimer to re-anchor participant session duration (#4566) * rtc: add RestartSessionTimer to re-anchor participant session duration Exposes ParticipantImpl.RestartSessionTimer so the session timer can be re-anchored to the actual join time. Duration is only ever emitted once the participant becomes active, so re-anchoring at join keeps pre-join wall-clock out of the reported/billed duration. Adds the method to the LocalParticipant interface (fake regenerated) and a local protocol replace to pick up SessionTimer.Reset. Co-Authored-By: Claude Opus 4.8 (1M context) * tidy * update protocol * report ended at for inactive sessions --------- Co-authored-by: Claude Opus 4.8 (1M context) Co-authored-by: Paul Wells --- go.mod | 2 +- go.sum | 4 ++-- pkg/rtc/participant.go | 18 +++++++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 1f478b7a2..cd376e81e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 - github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6 + github.com/livekit/protocol v1.46.7-0.20260611165352-04a0fe5b5051 github.com/livekit/psrpc v0.7.2 github.com/mackerelio/go-osstat v0.2.7 github.com/magefile/mage v1.17.2 diff --git a/go.sum b/go.sum index 4fc8c8b0f..454ef37c0 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0 h1:XHNNzebIKZRkLimla/hFGrAIX5EMWHctrgt3hLw7s+I= github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= -github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6 h1:AK8JNLn2H3+ixSfh9gdFDqI+IpBV1YASGAusqaV5gFs= -github.com/livekit/protocol v1.46.7-0.20260610055838-1459c54aadf6/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= +github.com/livekit/protocol v1.46.7-0.20260611165352-04a0fe5b5051 h1:IYqiW7z5pblZBn6o0OHNz8MHd3wJ/TLJG4gh6lCI0/s= +github.com/livekit/protocol v1.46.7-0.20260611165352-04a0fe5b5051/go.mod h1:jO+y05AU9Ec4JswDyuzKCZ4bhziOS0CzMqgnbj60Dzs= github.com/livekit/psrpc v0.7.2 h1:6oZ+NODJ2pLyaT6VqDq1F4Qc/3TpDUSpyphj/P9MhQc= github.com/livekit/psrpc v0.7.2/go.mod h1:rAI+m2+/cb4x9RXhLRtUx5ZwdfjjXOl4zi46IjEetaw= github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94= diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index bf2ebdb5b..f5f459e4e 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -405,19 +405,23 @@ func NewParticipant(params ParticipantParams) (*ParticipantImpl, error) { p.supervisor.OnPublicationError(p.onPublicationError) } + var timerStarted bool params.Reporter.RegisterFunc(func(ts time.Time, tx roomobs.ParticipantSessionTx) bool { - // Don't publish duration if participant never became active. Otherwise short-lived - // JOINING/JOINED -> DISCONNECTED transitions would still get rounded up to a - // minute by the session timer and inflate billed/reported duration. - if p.lastActiveAt.Load() == nil { - return !p.IsClosed() - } - if dts := p.disconnectedAt.Load(); dts != nil { ts = *dts tx.ReportEndTime(ts) } + // Don't publish duration if participant never became active. Otherwise short-lived + // JOINING/JOINED -> DISCONNECTED transitions would still get rounded up to a + // minute by the session timer and inflate billed/reported duration. + if lastActive := p.lastActiveAt.Load(); lastActive == nil { + return !p.IsClosed() + } else if !timerStarted { + timerStarted = true + p.params.SessionTimer.Reset(*lastActive) + } + tx.ReportKindCode(roomobs.ParticipantKindCode(p.Kind())) tx.ReportKindDetailsCodes(roomobs.ParticipantKindDetailsCodes(p.KindDetails())) From 9746c9a9d6a35d80ec6b54060051854f9053187c Mon Sep 17 00:00:00 2001 From: cnderrauber Date: Fri, 12 Jun 2026 16:02:12 +0800 Subject: [PATCH 24/25] Enforce subscriptio permission to data track (#4588) * Enforce subscriptio permission to data track * use revoke path as same as media track * nil check --- pkg/rtc/datadowntrack.go | 28 ++++ pkg/rtc/datatrack.go | 48 +++++- pkg/rtc/datatrack_test.go | 71 +++++++++ pkg/rtc/participant_data_track.go | 28 ++++ pkg/rtc/room.go | 10 ++ pkg/rtc/subscriptionmanager.go | 114 ++++++++------ pkg/rtc/subscriptionmanager_test.go | 140 +++++++++++++++++- pkg/rtc/types/interfaces.go | 8 +- .../types/typesfakes/fake_data_down_track.go | 37 +++++ pkg/rtc/types/typesfakes/fake_data_track.go | 77 ++++++++++ pkg/rtc/uptrackmanager.go | 9 +- test/singlenode_test.go | 22 ++- 12 files changed, 536 insertions(+), 56 deletions(-) create mode 100644 pkg/rtc/datatrack_test.go diff --git a/pkg/rtc/datadowntrack.go b/pkg/rtc/datadowntrack.go index 89c069f1b..45f5e19a8 100644 --- a/pkg/rtc/datadowntrack.go +++ b/pkg/rtc/datadowntrack.go @@ -16,6 +16,7 @@ package rtc import ( "fmt" + "sync" "time" "github.com/livekit/livekit-server/pkg/rtc/datatrack" @@ -40,6 +41,10 @@ type DataDownTrack struct { params DataDownTrackParams logger logger.Logger createdAt int64 + + lock sync.Mutex + closed bool + onClose func() } func NewDataDownTrack(params DataDownTrackParams) (*DataDownTrack, error) { @@ -59,11 +64,34 @@ func NewDataDownTrack(params DataDownTrackParams) (*DataDownTrack, error) { } func (d *DataDownTrack) Close() { + d.lock.Lock() + onClose := d.onClose + if d.closed { + d.lock.Unlock() + return + } + d.closed = true + d.lock.Unlock() + d.logger.Infow("closing data down track") if d.params.BytesTrackStats != nil { d.params.BytesTrackStats.Stop() } d.params.PublishDataTrack.DeleteDataDownTrack(d.SubscriberID()) + + if onClose != nil { + onClose() + } +} + +func (d *DataDownTrack) OnClose(fn func()) { + d.lock.Lock() + d.onClose = fn + closed := d.closed + d.lock.Unlock() + if closed && fn != nil { + fn() + } } func (d *DataDownTrack) Handle() uint16 { diff --git a/pkg/rtc/datatrack.go b/pkg/rtc/datatrack.go index 1e8c4d55c..fd22f6258 100644 --- a/pkg/rtc/datatrack.go +++ b/pkg/rtc/datatrack.go @@ -16,9 +16,11 @@ package rtc import ( "errors" + "slices" "sync" "github.com/frostbyte73/core" + "github.com/livekit/livekit-server/pkg/rtc/datatrack" "github.com/livekit/livekit-server/pkg/rtc/types" sfuutils "github.com/livekit/livekit-server/pkg/sfu/utils" @@ -40,6 +42,11 @@ type DataTrackParams struct { BytesTrackStats *BytesTrackStats } +type subscribedDataTrack struct { + subscriber types.LocalParticipant + dataDownTrack types.DataDownTrack +} + type DataTrack struct { params DataTrackParams @@ -47,7 +54,7 @@ type DataTrack struct { lock sync.Mutex dti *livekit.DataTrackInfo - subscribedTracks map[livekit.ParticipantID]types.DataDownTrack + subscribedTracks map[livekit.ParticipantID]subscribedDataTrack downTrackSpreader *sfuutils.DownTrackSpreader[types.DataTrackSender] @@ -60,7 +67,7 @@ func NewDataTrack(params DataTrackParams, dti *livekit.DataTrackInfo) *DataTrack d := &DataTrack{ params: params, dti: dti, - subscribedTracks: make(map[livekit.ParticipantID]types.DataDownTrack), + subscribedTracks: make(map[livekit.ParticipantID]subscribedDataTrack), } d.logger = params.Logger.WithValues("name", d.Name(), "handle", dti.PubHandle) d.downTrackSpreader = sfuutils.NewDownTrackSpreader[types.DataTrackSender](sfuutils.DownTrackSpreaderParams{ @@ -136,18 +143,21 @@ func (d *DataTrack) AddSubscriber(sub types.LocalParticipant) (types.DataDownTra return nil, err } - d.subscribedTracks[sub.ID()] = dataDownTrack + d.subscribedTracks[sub.ID()] = subscribedDataTrack{ + subscriber: sub, + dataDownTrack: dataDownTrack, + } return dataDownTrack, nil } func (d *DataTrack) RemoveSubscriber(subID livekit.ParticipantID) { d.lock.Lock() - dataDownTrack, ok := d.subscribedTracks[subID] + subscribedTrack, ok := d.subscribedTracks[subID] delete(d.subscribedTracks, subID) d.lock.Unlock() if ok { - dataDownTrack.Close() + subscribedTrack.dataDownTrack.Close() } } @@ -159,6 +169,34 @@ func (d *DataTrack) IsSubscriber(subID livekit.ParticipantID) bool { return ok } +func (d *DataTrack) RevokeDisallowedSubscribers(allowedSubscriberIdentities []livekit.ParticipantIdentity) []livekit.ParticipantIdentity { + var revokedSubscriberIdentities []livekit.ParticipantIdentity + + d.lock.Lock() + disallowed := make(map[livekit.ParticipantID]livekit.ParticipantIdentity) + for subID, subscribedTrack := range d.subscribedTracks { + if IsParticipantExemptFromTrackPermissionsRestrictions(subscribedTrack.subscriber) { + continue + } + + if !slices.Contains(allowedSubscriberIdentities, subscribedTrack.subscriber.Identity()) { + disallowed[subID] = subscribedTrack.subscriber.Identity() + } + } + d.lock.Unlock() + + for subID, subIdentity := range disallowed { + d.logger.Infow("revoking data track subscription", + "subscriber", subIdentity, + "subscriberID", subID, + ) + d.RemoveSubscriber(subID) + revokedSubscriberIdentities = append(revokedSubscriberIdentities, subIdentity) + } + + return revokedSubscriberIdentities +} + func (d *DataTrack) AddDataDownTrack(dts types.DataTrackSender) error { if d.closed.IsBroken() { return errReceiverClosed diff --git a/pkg/rtc/datatrack_test.go b/pkg/rtc/datatrack_test.go new file mode 100644 index 000000000..f2938a1f2 --- /dev/null +++ b/pkg/rtc/datatrack_test.go @@ -0,0 +1,71 @@ +// 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 rtc + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/livekit/livekit-server/pkg/rtc/types/typesfakes" + "github.com/livekit/protocol/livekit" + "github.com/livekit/protocol/logger" + "github.com/livekit/protocol/observability/roomobs" +) + +func newTestDataTrackSubscriber(id livekit.ParticipantID, identity livekit.ParticipantIdentity, isRecorder bool) *typesfakes.FakeLocalParticipant { + sub := &typesfakes.FakeLocalParticipant{} + sub.IDReturns(id) + sub.IdentityReturns(identity) + sub.IsRecorderReturns(isRecorder) + sub.GetLoggerReturns(logger.GetLogger()) + sub.GetReporterReturns(roomobs.NewNoopParticipantSessionReporter()) + sub.GetTelemetryListenerReturns(&typesfakes.FakeParticipantTelemetryListener{}) + return sub +} + +func TestDataTrackRevokeDisallowedSubscribers(t *testing.T) { + dt := NewDataTrack( + DataTrackParams{ + Logger: logger.GetLogger(), + ParticipantID: func() livekit.ParticipantID { return "pubID" }, + ParticipantIdentity: "pub", + }, + &livekit.DataTrackInfo{ + PubHandle: 1, + Sid: "DTR_test", + Name: "test", + }, + ) + defer dt.Close() + + allowed := newTestDataTrackSubscriber("allowedID", "allowed", false) + disallowed := newTestDataTrackSubscriber("disallowedID", "disallowed", false) + recorder := newTestDataTrackSubscriber("recorderID", "recorder", true) + + for _, sub := range []*typesfakes.FakeLocalParticipant{allowed, disallowed, recorder} { + _, err := dt.AddSubscriber(sub) + require.NoError(t, err) + require.True(t, dt.IsSubscriber(sub.ID())) + } + + revoked := dt.RevokeDisallowedSubscribers([]livekit.ParticipantIdentity{"allowed"}) + require.Equal(t, []livekit.ParticipantIdentity{"disallowed"}, revoked) + + // disallowed subscriber is removed, allowed and permission exempt (recorder) subscribers are kept + require.True(t, dt.IsSubscriber(allowed.ID())) + require.False(t, dt.IsSubscriber(disallowed.ID())) + require.True(t, dt.IsSubscriber(recorder.ID())) +} diff --git a/pkg/rtc/participant_data_track.go b/pkg/rtc/participant_data_track.go index 829beaf63..dbda1ede0 100644 --- a/pkg/rtc/participant_data_track.go +++ b/pkg/rtc/participant_data_track.go @@ -16,6 +16,7 @@ package rtc import ( "github.com/livekit/livekit-server/pkg/rtc/datatrack" + "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/protocol/livekit" "github.com/livekit/protocol/logger" "github.com/livekit/protocol/utils" @@ -156,6 +157,33 @@ func (p *ParticipantImpl) onReceivedDataTrackMessage(data []byte, arrivalTime in p.listener().OnDataTrackMessage(p, data, &packet) } +// wraps the promoted UpTrackManager.UpdateSubscriptionPermission to also revoke +// data track subscriptions that are no longer permitted +func (p *ParticipantImpl) UpdateSubscriptionPermission( + subscriptionPermission *livekit.SubscriptionPermission, + timedVersion utils.TimedVersion, + resolverBySid func(participantID livekit.ParticipantID) types.LocalParticipant, +) error { + if err := p.UpTrackManager.UpdateSubscriptionPermission(subscriptionPermission, timedVersion, resolverBySid); err != nil { + return err + } + + p.maybeRevokeDataTrackSubscriptions() + return nil +} + +func (p *ParticipantImpl) maybeRevokeDataTrackSubscriptions() { + for _, dt := range p.UpDataTrackManager.GetPublishedDataTracks() { + allowed := p.UpTrackManager.GetAllowedSubscribers(dt.ID()) + if allowed == nil { + // no restrictions + continue + } + + dt.RevokeDisallowedSubscribers(allowed) + } +} + func (p *ParticipantImpl) GetNextSubscribedDataTrackHandle() uint16 { p.lock.Lock() defer p.lock.Unlock() diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index e696abddf..2062b5179 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -705,6 +705,9 @@ func (r *Room) onUpdateSubscriptionPermission(participant types.LocalParticipant for _, track := range participant.GetPublishedTracks() { r.trackManager.NotifyTrackChanged(track.ID()) } + for _, track := range participant.GetPublishedDataTracks() { + r.trackManager.NotifyTrackChanged(track.ID()) + } return nil } @@ -746,6 +749,13 @@ func (r *Room) ResolveDataTrackForSubscriber(sub types.LocalParticipant, trackID res.TrackRemovedNotifier = r.trackManager.GetOrCreateTrackRemoveNotifier(trackID) res.PublisherIdentity = info.PublisherIdentity res.PublisherID = info.PublisherID + + pub := r.GetParticipantByID(info.PublisherID) + // when publisher is not found, we will assume it doesn't have permission to access + if pub != nil { + res.HasPermission = IsParticipantExemptFromTrackPermissionsRestrictions(sub) || pub.HasPermission(trackID, sub.Identity()) + } + return res } diff --git a/pkg/rtc/subscriptionmanager.go b/pkg/rtc/subscriptionmanager.go index 640742bfd..d421d0805 100644 --- a/pkg/rtc/subscriptionmanager.go +++ b/pkg/rtc/subscriptionmanager.go @@ -612,8 +612,9 @@ func (m *SubscriptionManager) reconcileDataTrackSubscription(s *dataTrackSubscri s.recordAttempt(false) switch err { - case ErrNoSubscribePermission: + case ErrNoTrackPermission, ErrNoSubscribePermission: // these are errors that are outside of our control, so we'll keep trying + // - ErrNoTrackPermission: publisher did not grant subscriber permission, may change any moment // - ErrNoSubscribePermission: participant was not granted canSubscribe, may change any moment case ErrTrackNotFound: // source track was never published or closed @@ -1083,6 +1084,14 @@ func (m *SubscriptionManager) subscribeDataTrack(sub *dataTrackSubscription) err sub.setPublisher(res.PublisherIdentity, res.PublisherID) + permChanged := sub.setHasPermission(res.HasPermission) + if permChanged { + m.params.Participant.SendSubscriptionPermissionUpdate(sub.getPublisherID(), trackID, res.HasPermission) + } + if !res.HasPermission { + return ErrNoTrackPermission + } + dataDownTrack, err := dataTrack.AddSubscriber(m.params.Participant) if err != nil && !errors.Is(err, errAlreadySubscribed) { return err @@ -1091,6 +1100,9 @@ func (m *SubscriptionManager) subscribeDataTrack(sub *dataTrackSubscription) err sub.logger.Debugw("already subscribed to data track") } if err == nil && dataDownTrack != nil { // subTrack could be nil if already subscribed + dataDownTrack.OnClose(func() { + m.handleDataDownTrackClose(sub) + }) sub.setDataDownTrack(dataDownTrack) sub.logger.Debugw("subscribed to data track") } @@ -1111,11 +1123,27 @@ func (m *SubscriptionManager) unsubscribeDataTrack(s *dataTrackSubscription) err dataTrack := dataDownTrack.PublishDataTrack() dataTrack.RemoveSubscriber(s.subscriberID) + return nil +} + +// DataDownTrack closing is how the publisher signifies that the subscription is no longer fulfilled +// this could be due to a few reasons: +// - subscriber-initiated unsubscribe +// - data track was unpublished +// - publisher revoked permissions for the participant +func (m *SubscriptionManager) handleDataDownTrackClose(s *dataTrackSubscription) { + s.logger.Debugw("data down track closed") + + if s.getDataDownTrack() == nil { + return + } + s.setDataDownTrack(nil) s.setChangedNotifier(nil) s.setRemovedNotifier(nil) m.unmarkSubscribedTo(s.getPublisherID(), s.trackID) - return nil + m.notifyDataTrackSubscriberHandles() + m.queueReconcileDataTrack(s.trackID) } func (m *SubscriptionManager) notifyDataTrackSubscriberHandles() { @@ -1208,12 +1236,14 @@ type trackSubscription struct { trackID livekit.TrackID logger logger.Logger - lock sync.RWMutex - desired bool - publisherID livekit.ParticipantID - publisherIdentity livekit.ParticipantIdentity - changedNotifier types.ChangeNotifier - removedNotifier types.ChangeNotifier + lock sync.RWMutex + desired bool + publisherID livekit.ParticipantID + publisherIdentity livekit.ParticipantIdentity + changedNotifier types.ChangeNotifier + removedNotifier types.ChangeNotifier + hasPermissionInitialized bool + hasPermission bool numAttempts atomic.Int32 @@ -1225,6 +1255,31 @@ type trackSubscription struct { subscribeAt atomic.Pointer[time.Time] } +// set permission and return true if it has changed +func (s *trackSubscription) setHasPermission(perm bool) bool { + s.lock.Lock() + defer s.lock.Unlock() + if s.hasPermissionInitialized && s.hasPermission == perm { + return false + } + + s.hasPermissionInitialized = true + s.hasPermission = perm + if s.hasPermission { + // when permission is granted, reset the timer so it has sufficient time to reconcile + t := time.Now() + s.subStartedAt.Store(&t) + s.subscribeAt.Store(&t) + } + return true +} + +func (s *trackSubscription) getHasPermission() bool { + s.lock.RLock() + defer s.lock.RUnlock() + return s.hasPermission +} + func (s *trackSubscription) setPublisher(publisherIdentity livekit.ParticipantIdentity, publisherID livekit.ParticipantID) { s.lock.Lock() defer s.lock.Unlock() @@ -1355,13 +1410,11 @@ func (s *trackSubscription) handleSourceTrackRemoved() { type mediaTrackSubscription struct { trackSubscription - settings *livekit.UpdateTrackSettings - hasPermissionInitialized bool - hasPermission bool - subscribedTrack types.SubscribedTrack - eventSent atomic.Bool - bound bool - kind atomic.Pointer[livekit.TrackType] + settings *livekit.UpdateTrackSettings + subscribedTrack types.SubscribedTrack + eventSent atomic.Bool + bound bool + kind atomic.Pointer[livekit.TrackType] succRecordCounter atomic.Int32 } @@ -1379,31 +1432,6 @@ func newMediaTrackSubscription(subscriberID livekit.ParticipantID, trackID livek return s } -// set permission and return true if it has changed -func (s *mediaTrackSubscription) setHasPermission(perm bool) bool { - s.lock.Lock() - defer s.lock.Unlock() - if s.hasPermissionInitialized && s.hasPermission == perm { - return false - } - - s.hasPermissionInitialized = true - s.hasPermission = perm - if s.hasPermission { - // when permission is granted, reset the timer so it has sufficient time to reconcile - t := time.Now() - s.subStartedAt.Store(&t) - s.subscribeAt.Store(&t) - } - return true -} - -func (s *mediaTrackSubscription) getHasPermission() bool { - s.lock.RLock() - defer s.lock.RUnlock() - return s.hasPermission -} - func (s *mediaTrackSubscription) setSubscribedTrack(track types.SubscribedTrack) { s.lock.Lock() oldTrack := s.subscribedTrack @@ -1573,6 +1601,7 @@ func (s *dataTrackSubscription) needsCleanup() bool { func (s *dataTrackSubscription) setDataDownTrack(dataDownTrack types.DataDownTrack) { s.lock.Lock() + oldDataDownTrack := s.dataDownTrack s.dataDownTrack = dataDownTrack subscriptionOptions := s.subscriptionOptions s.lock.Unlock() @@ -1581,8 +1610,9 @@ func (s *dataTrackSubscription) setDataDownTrack(dataDownTrack types.DataDownTra s.logger.Debugw("restoring data track subscription options", "subscriptionOptions", logger.Proto(subscriptionOptions)) dataDownTrack.UpdateSubscriptionOptions(subscriptionOptions) } - - // DT-TODO - DataTrack close callback on previous if not nil?, see setSubscribedTrack for example + if oldDataDownTrack != nil { + oldDataDownTrack.OnClose(nil) + } } func (s *dataTrackSubscription) getDataDownTrack() types.DataDownTrack { diff --git a/pkg/rtc/subscriptionmanager_test.go b/pkg/rtc/subscriptionmanager_test.go index bfbb5bf04..6c4618927 100644 --- a/pkg/rtc/subscriptionmanager_test.go +++ b/pkg/rtc/subscriptionmanager_test.go @@ -204,9 +204,9 @@ func TestUnsubscribe(t *testing.T) { publisherID: "pubID", publisherIdentity: "pub", logger: logger.GetLogger(), + hasPermission: true, }, - hasPermission: true, - bound: true, + bound: true, } // a bunch of unfortunate manual wiring res := resolver.Resolve(nil, s.trackID) @@ -445,6 +445,84 @@ func TestSubscriptionLimits(t *testing.T) { require.Len(t, sm.GetSubscribedTracks(), 1) } +func TestSubscribeDataTrack(t *testing.T) { + t.Run("no track permission", func(t *testing.T) { + sm := newTestSubscriptionManager() + defer sm.Close(false) + resolver := newTestDataTrackResolver(false, true, "pub", "pubID") + sm.params.DataTrackResolver = resolver.Resolve + + sm.SubscribeToDataTrack("track") + sm.lock.RLock() + s := sm.dataTrackSubscriptions["track"] + sm.lock.RUnlock() + require.Eventually(t, func() bool { + return !s.getHasPermission() + }, subSettleTimeout, subCheckInterval, "should not have permission to subscribe") + + time.Sleep(subscriptionTimeout) + + // isDesired remains unchanged, no subscriber added to the data track + require.True(t, s.isDesired()) + require.True(t, s.needsSubscribe()) + require.Equal(t, 0, resolver.dataTrack.AddSubscriberCallCount()) + + // subscriber should have been notified that permission was denied + p := sm.params.Participant.(*typesfakes.FakeLocalParticipant) + require.Equal(t, 1, p.SendSubscriptionPermissionUpdateCallCount()) + _, _, allowed := p.SendSubscriptionPermissionUpdateArgsForCall(0) + require.False(t, allowed) + + // give permissions now + resolver.SetHasPermission(true) + + require.Eventually(t, func() bool { + return !s.needsSubscribe() + }, subSettleTimeout, subCheckInterval, "should be subscribed") + require.NotNil(t, s.getDataDownTrack()) + require.Equal(t, 1, resolver.dataTrack.AddSubscriberCallCount()) + }) + + t.Run("permission revoked while subscribed", func(t *testing.T) { + sm := newTestSubscriptionManager() + defer sm.Close(false) + resolver := newTestDataTrackResolver(true, true, "pub", "pubID") + sm.params.DataTrackResolver = resolver.Resolve + + sm.SubscribeToDataTrack("track") + sm.lock.RLock() + s := sm.dataTrackSubscriptions["track"] + sm.lock.RUnlock() + require.Eventually(t, func() bool { + return !s.needsSubscribe() + }, subSettleTimeout, subCheckInterval, "should be subscribed") + + // revoke permission and close the down track like the publisher would + // (DataTrack.RevokeDisallowedSubscribers -> RemoveSubscriber -> DataDownTrack.Close) + resolver.SetHasPermission(false) + ddt := s.getDataDownTrack() + require.NotNil(t, ddt) + setTestDataDownTrackClosed(t, ddt) + + // subscription stays desired but is denied on resubscribe attempts + require.Nil(t, s.getDataDownTrack()) + require.True(t, s.isDesired()) + require.Eventually(t, func() bool { + return !s.getHasPermission() + }, subSettleTimeout, subCheckInterval, "should not have permission to resubscribe") + require.True(t, s.needsSubscribe()) + require.Equal(t, 1, resolver.dataTrack.AddSubscriberCallCount()) + + // give permission back, should resubscribe + resolver.SetHasPermission(true) + + require.Eventually(t, func() bool { + return !s.needsSubscribe() && s.getDataDownTrack() != nil + }, subSettleTimeout, subCheckInterval, "should be resubscribed") + require.Equal(t, 2, resolver.dataTrack.AddSubscriberCallCount()) + }) +} + type testSubscriptionParams struct { SubscriptionLimitAudio int32 SubscriptionLimitVideo int32 @@ -526,6 +604,57 @@ func (t *testResolver) Resolve(_subscriber types.LocalParticipant, trackID livek return res } +type testDataTrackResolver struct { + lock sync.Mutex + hasPermission bool + hasTrack bool + pubIdentity livekit.ParticipantIdentity + pubID livekit.ParticipantID + + dataTrack *typesfakes.FakeDataTrack +} + +func newTestDataTrackResolver(hasPermission bool, hasTrack bool, pubIdentity livekit.ParticipantIdentity, pubID livekit.ParticipantID) *testDataTrackResolver { + r := &testDataTrackResolver{ + hasPermission: hasPermission, + hasTrack: hasTrack, + pubIdentity: pubIdentity, + pubID: pubID, + dataTrack: &typesfakes.FakeDataTrack{}, + } + r.dataTrack.PublisherIDReturns(pubID) + r.dataTrack.PublisherIdentityReturns(pubIdentity) + r.dataTrack.AddSubscriberCalls(func(sub types.LocalParticipant) (types.DataDownTrack, error) { + ddt := &typesfakes.FakeDataDownTrack{} + ddt.PublishDataTrackReturns(r.dataTrack) + return ddt, nil + }) + return r +} + +func (t *testDataTrackResolver) SetHasPermission(hasPermission bool) { + t.lock.Lock() + defer t.lock.Unlock() + t.hasPermission = hasPermission +} + +func (t *testDataTrackResolver) Resolve(_subscriber types.LocalParticipant, trackID livekit.TrackID) types.DataResolverResult { + t.lock.Lock() + defer t.lock.Unlock() + res := types.DataResolverResult{ + TrackChangedNotifier: utils.NewChangeNotifier(), + TrackRemovedNotifier: utils.NewChangeNotifier(), + HasPermission: t.hasPermission, + PublisherID: t.pubID, + PublisherIdentity: t.pubIdentity, + } + if t.hasTrack { + t.dataTrack.IDReturns(trackID) + res.DataTrack = t.dataTrack + } + return res +} + func setTestSubscribedTrackBound(t *testing.T, st types.SubscribedTrack) { fst, ok := st.(*typesfakes.FakeSubscribedTrack) require.True(t, ok) @@ -541,3 +670,10 @@ func setTestSubscribedTrackClosed(t *testing.T, st types.SubscribedTrack, isExpe fst.OnCloseArgsForCall(0)(isExpectedToResume) } + +func setTestDataDownTrackClosed(t *testing.T, ddt types.DataDownTrack) { + fddt, ok := ddt.(*typesfakes.FakeDataDownTrack) + require.True(t, ok) + + fddt.OnCloseArgsForCall(0)() +} diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index e402c4614..194f529dd 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -826,6 +826,7 @@ type DataTrack interface { AddSubscriber(sub LocalParticipant) (DataDownTrack, error) RemoveSubscriber(participantID livekit.ParticipantID) IsSubscriber(subID livekit.ParticipantID) bool + RevokeDisallowedSubscribers(allowedSubscriberIdentities []livekit.ParticipantIdentity) []livekit.ParticipantIdentity AddDataDownTrack(sender DataTrackSender) error DeleteDataDownTrack(subscriberID livekit.ParticipantID) @@ -838,6 +839,7 @@ type DataTrack interface { //counterfeiter:generate . DataDownTrack type DataDownTrack interface { Close() + OnClose(fn func()) Handle() uint16 PublishDataTrack() DataTrack @@ -902,8 +904,10 @@ type DataResolverResult struct { TrackChangedNotifier ChangeNotifier TrackRemovedNotifier ChangeNotifier DataTrack DataTrack - PublisherID livekit.ParticipantID - PublisherIdentity livekit.ParticipantIdentity + // is permission given to the requesting participant + HasPermission bool + PublisherID livekit.ParticipantID + PublisherIdentity livekit.ParticipantIdentity } // MediaTrackResolver locates a specific media track for a subscriber diff --git a/pkg/rtc/types/typesfakes/fake_data_down_track.go b/pkg/rtc/types/typesfakes/fake_data_down_track.go index 56d0d102d..027fee113 100644 --- a/pkg/rtc/types/typesfakes/fake_data_down_track.go +++ b/pkg/rtc/types/typesfakes/fake_data_down_track.go @@ -23,6 +23,11 @@ type FakeDataDownTrack struct { handleReturnsOnCall map[int]struct { result1 uint16 } + OnCloseStub func(func()) + onCloseMutex sync.RWMutex + onCloseArgsForCall []struct { + arg1 func() + } PublishDataTrackStub func() types.DataTrack publishDataTrackMutex sync.RWMutex publishDataTrackArgsForCall []struct { @@ -119,6 +124,38 @@ func (fake *FakeDataDownTrack) HandleReturnsOnCall(i int, result1 uint16) { }{result1} } +func (fake *FakeDataDownTrack) OnClose(arg1 func()) { + fake.onCloseMutex.Lock() + fake.onCloseArgsForCall = append(fake.onCloseArgsForCall, struct { + arg1 func() + }{arg1}) + stub := fake.OnCloseStub + fake.recordInvocation("OnClose", []interface{}{arg1}) + fake.onCloseMutex.Unlock() + if stub != nil { + fake.OnCloseStub(arg1) + } +} + +func (fake *FakeDataDownTrack) OnCloseCallCount() int { + fake.onCloseMutex.RLock() + defer fake.onCloseMutex.RUnlock() + return len(fake.onCloseArgsForCall) +} + +func (fake *FakeDataDownTrack) OnCloseCalls(stub func(func())) { + fake.onCloseMutex.Lock() + defer fake.onCloseMutex.Unlock() + fake.OnCloseStub = stub +} + +func (fake *FakeDataDownTrack) OnCloseArgsForCall(i int) func() { + fake.onCloseMutex.RLock() + defer fake.onCloseMutex.RUnlock() + argsForCall := fake.onCloseArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeDataDownTrack) PublishDataTrack() types.DataTrack { fake.publishDataTrackMutex.Lock() ret, specificReturn := fake.publishDataTrackReturnsOnCall[len(fake.publishDataTrackArgsForCall)] diff --git a/pkg/rtc/types/typesfakes/fake_data_track.go b/pkg/rtc/types/typesfakes/fake_data_track.go index c54d77c54..07a49f9b1 100644 --- a/pkg/rtc/types/typesfakes/fake_data_track.go +++ b/pkg/rtc/types/typesfakes/fake_data_track.go @@ -116,6 +116,17 @@ type FakeDataTrack struct { removeSubscriberArgsForCall []struct { arg1 livekit.ParticipantID } + RevokeDisallowedSubscribersStub func([]livekit.ParticipantIdentity) []livekit.ParticipantIdentity + revokeDisallowedSubscribersMutex sync.RWMutex + revokeDisallowedSubscribersArgsForCall []struct { + arg1 []livekit.ParticipantIdentity + } + revokeDisallowedSubscribersReturns struct { + result1 []livekit.ParticipantIdentity + } + revokeDisallowedSubscribersReturnsOnCall map[int]struct { + result1 []livekit.ParticipantIdentity + } ToProtoStub func() *livekit.DataTrackInfo toProtoMutex sync.RWMutex toProtoArgsForCall []struct { @@ -708,6 +719,72 @@ func (fake *FakeDataTrack) RemoveSubscriberArgsForCall(i int) livekit.Participan return argsForCall.arg1 } +func (fake *FakeDataTrack) RevokeDisallowedSubscribers(arg1 []livekit.ParticipantIdentity) []livekit.ParticipantIdentity { + var arg1Copy []livekit.ParticipantIdentity + if arg1 != nil { + arg1Copy = make([]livekit.ParticipantIdentity, len(arg1)) + copy(arg1Copy, arg1) + } + fake.revokeDisallowedSubscribersMutex.Lock() + ret, specificReturn := fake.revokeDisallowedSubscribersReturnsOnCall[len(fake.revokeDisallowedSubscribersArgsForCall)] + fake.revokeDisallowedSubscribersArgsForCall = append(fake.revokeDisallowedSubscribersArgsForCall, struct { + arg1 []livekit.ParticipantIdentity + }{arg1Copy}) + stub := fake.RevokeDisallowedSubscribersStub + fakeReturns := fake.revokeDisallowedSubscribersReturns + fake.recordInvocation("RevokeDisallowedSubscribers", []interface{}{arg1Copy}) + fake.revokeDisallowedSubscribersMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeDataTrack) RevokeDisallowedSubscribersCallCount() int { + fake.revokeDisallowedSubscribersMutex.RLock() + defer fake.revokeDisallowedSubscribersMutex.RUnlock() + return len(fake.revokeDisallowedSubscribersArgsForCall) +} + +func (fake *FakeDataTrack) RevokeDisallowedSubscribersCalls(stub func([]livekit.ParticipantIdentity) []livekit.ParticipantIdentity) { + fake.revokeDisallowedSubscribersMutex.Lock() + defer fake.revokeDisallowedSubscribersMutex.Unlock() + fake.RevokeDisallowedSubscribersStub = stub +} + +func (fake *FakeDataTrack) RevokeDisallowedSubscribersArgsForCall(i int) []livekit.ParticipantIdentity { + fake.revokeDisallowedSubscribersMutex.RLock() + defer fake.revokeDisallowedSubscribersMutex.RUnlock() + argsForCall := fake.revokeDisallowedSubscribersArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeDataTrack) RevokeDisallowedSubscribersReturns(result1 []livekit.ParticipantIdentity) { + fake.revokeDisallowedSubscribersMutex.Lock() + defer fake.revokeDisallowedSubscribersMutex.Unlock() + fake.RevokeDisallowedSubscribersStub = nil + fake.revokeDisallowedSubscribersReturns = struct { + result1 []livekit.ParticipantIdentity + }{result1} +} + +func (fake *FakeDataTrack) RevokeDisallowedSubscribersReturnsOnCall(i int, result1 []livekit.ParticipantIdentity) { + fake.revokeDisallowedSubscribersMutex.Lock() + defer fake.revokeDisallowedSubscribersMutex.Unlock() + fake.RevokeDisallowedSubscribersStub = nil + if fake.revokeDisallowedSubscribersReturnsOnCall == nil { + fake.revokeDisallowedSubscribersReturnsOnCall = make(map[int]struct { + result1 []livekit.ParticipantIdentity + }) + } + fake.revokeDisallowedSubscribersReturnsOnCall[i] = struct { + result1 []livekit.ParticipantIdentity + }{result1} +} + func (fake *FakeDataTrack) ToProto() *livekit.DataTrackInfo { fake.toProtoMutex.Lock() ret, specificReturn := fake.toProtoReturnsOnCall[len(fake.toProtoArgsForCall)] diff --git a/pkg/rtc/uptrackmanager.go b/pkg/rtc/uptrackmanager.go index f75f501c8..fefc7f459 100644 --- a/pkg/rtc/uptrackmanager.go +++ b/pkg/rtc/uptrackmanager.go @@ -49,7 +49,7 @@ type UpTrackManager struct { // publishedTracks that participant is publishing publishedTracks map[livekit.TrackID]types.MediaTrack subscriptionPermission *livekit.SubscriptionPermission - // subscriber permission for published tracks + // subscriber permission for published tracks (both media and data) subscriberPermissions map[livekit.ParticipantIdentity]*livekit.TrackPermission // subscriberIdentity => *livekit.TrackPermission lock sync.RWMutex @@ -235,6 +235,13 @@ func (u *UpTrackManager) HasPermission(trackID livekit.TrackID, subIdentity live return u.hasPermissionLocked(trackID, subIdentity) } +func (u *UpTrackManager) GetAllowedSubscribers(trackID livekit.TrackID) []livekit.ParticipantIdentity { + u.lock.RLock() + defer u.lock.RUnlock() + + return u.getAllowedSubscribersLocked(trackID) +} + func (u *UpTrackManager) UpdatePublishedAudioTrack(update *livekit.UpdateLocalAudioTrack) types.MediaTrack { track := u.GetPublishedTrack(livekit.TrackID(update.TrackSid)) if track != nil { diff --git a/test/singlenode_test.go b/test/singlenode_test.go index 6d571dadf..cf09473f3 100644 --- a/test/singlenode_test.go +++ b/test/singlenode_test.go @@ -765,13 +765,21 @@ func TestSingleNodeUpdateSubscriptionPermissions(t *testing.T) { SetIdentity("sub") token, err := at.ToJWT() require.NoError(t, err) - sub := createRTCClientWithToken(token, defaultServerPort, testRTCServicePath, nil) + sub := createRTCClientWithToken(token, defaultServerPort, testRTCServicePath, &testclient.Options{ + AutoSubscribe: true, + AutoSubscribeDataTrack: true, + }) waitUntilConnected(t, pub, sub) writers := publishTracksForClients(t, pub) defer stopWriters(writers...) + // publish a data track as well + dtw, err := pub.PublishDataTrack() + require.NoError(t, err) + defer dtw.Stop() + // wait sub receives tracks testutils.WithTimeout(t, func() string { pubRemote := sub.GetRemoteParticipant(pub.ID()) @@ -784,6 +792,10 @@ func TestSingleNodeUpdateSubscriptionPermissions(t *testing.T) { return "" }) + // no subscriptions should have been made while canSubscribe is false + require.Empty(t, sub.SubscribedTracks()[pub.ID()]) + require.Empty(t, sub.SubscribedDataTracks()[pub.ID()]) + // set permissions out of band ctx := contextWithToken(adminRoomToken(testRoom)) _, err = roomClient.UpdateParticipant(ctx, &livekit.UpdateParticipantRequest{ @@ -798,11 +810,13 @@ func TestSingleNodeUpdateSubscriptionPermissions(t *testing.T) { testutils.WithTimeout(t, func() string { tracks := sub.SubscribedTracks()[pub.ID()] - if len(tracks) == 2 { - return "" - } else { + if len(tracks) != 2 { return fmt.Sprintf("expected 2 tracks subscribed, actual: %d", len(tracks)) } + if len(sub.SubscribedDataTracks()[pub.ID()]) != 1 { + return "expected data track to be subscribed" + } + return "" }) }) } From 1f3e06107bd152438c8c1df4d8c8c80a69d75a25 Mon Sep 17 00:00:00 2001 From: David Colburn Date: Fri, 12 Jun 2026 15:17:02 -0400 Subject: [PATCH 25/25] egress v2 api (#4592) * egress v2 * reorganize --- pkg/service/egress.go | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/pkg/service/egress.go b/pkg/service/egress.go index 2e37ce4c2..697aecbb4 100644 --- a/pkg/service/egress.go +++ b/pkg/service/egress.go @@ -72,6 +72,33 @@ func NewEgressLauncher(client rpc.EgressClient, io IOClient, store ServiceStore) } } +func (s *EgressService) StartEgress(ctx context.Context, req *livekit.StartEgressRequest) (*livekit.EgressInfo, error) { + sourceType, outputType := egress.GetTypes(&livekit.EgressInfo_Egress{Egress: req}) + fields := []any{ + "room", req.RoomName, + "sourceType", sourceType, + "outputType", outputType, + } + defer func() { + AppendLogFields(ctx, fields...) + }() + + egressID, idFromCtx := EgressID(ctx) + ei, err := s.startEgress(ctx, &rpc.StartEgressRequest{ + EgressId: egressID, + Request: &rpc.StartEgressRequest_Egress{ + Egress: req, + }, + }) + if err != nil { + return nil, err + } + if !idFromCtx { + fields = append(fields, "egressID", ei.EgressId) + } + return ei, err +} + func (s *EgressService) StartRoomCompositeEgress(ctx context.Context, req *livekit.RoomCompositeEgressRequest) (*livekit.EgressInfo, error) { fields := []any{ "room", req.RoomName, @@ -230,6 +257,8 @@ func (s *egressLauncher) StartEgress(ctx context.Context, req *rpc.StartEgressRe roomName = v.TrackComposite.RoomName case *rpc.StartEgressRequest_Track: roomName = v.Track.RoomName + case *rpc.StartEgressRequest_Egress: + roomName = v.Egress.RoomName } if roomName != "" { @@ -254,13 +283,6 @@ func (s *egressLauncher) StartEgress(ctx context.Context, req *rpc.StartEgressRe return info, nil } -func (s *egressLauncher) StopEgress(ctx context.Context, req *livekit.StopEgressRequest) (*livekit.EgressInfo, error) { - if s.client == nil { - return nil, ErrEgressNotConnected - } - return s.client.StopEgress(ctx, req.EgressId, req) -} - type LayoutMetadata struct { Layout string `json:"layout"` } @@ -372,6 +394,9 @@ func (s *EgressService) StopEgress(ctx context.Context, req *livekit.StopEgressR return info, nil } -func (s *EgressService) StartEgress(ctx context.Context, req *livekit.StartEgressRequest) (*livekit.EgressInfo, error) { - return nil, errors.New("not implemented") +func (s *egressLauncher) StopEgress(ctx context.Context, req *livekit.StopEgressRequest) (*livekit.EgressInfo, error) { + if s.client == nil { + return nil, ErrEgressNotConnected + } + return s.client.StopEgress(ctx, req.EgressId, req) }