mirror of
https://github.com/livekit/livekit.git
synced 2026-08-28 09:24:08 +00:00
Merge remote-tracking branch 'origin/master' into raja_async_attributes
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* @livekit/cs-devs
|
||||
@@ -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
|
||||
|
||||
@@ -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' }}
|
||||
|
||||
+4
-1
@@ -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'
|
||||
|
||||
@@ -2,6 +2,44 @@
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
+16
-2
@@ -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
|
||||
@@ -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: ""
|
||||
@@ -111,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
|
||||
@@ -161,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
|
||||
|
||||
@@ -8,52 +8,53 @@ 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.45.9-0.20260519061926-8381f2180c45
|
||||
github.com/livekit/psrpc v0.7.1
|
||||
github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0
|
||||
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.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
|
||||
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.2
|
||||
github.com/pion/ice/v4 v4.2.6
|
||||
github.com/pion/interceptor v0.1.44
|
||||
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
|
||||
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.8
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -61,107 +62,96 @@ 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/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-jose/go-jose/v3 v3.0.5 // 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/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/moby/sys/user v0.3.0 // indirect
|
||||
github.com/nyaruka/phonenumbers v1.6.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-isatty v0.0.22 // 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.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/v3 v3.5.1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.43.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/sdk v1.43.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.43.0 // 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
|
||||
go.opentelemetry.io/otel/metric v1.44.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
|
||||
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-20260603202125-055de637280b // 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
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // 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
|
||||
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.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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/go-connections v0.7.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.5 // 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.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
|
||||
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.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
|
||||
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
|
||||
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
|
||||
github.com/opencontainers/runc v1.2.3 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // 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.10 // indirect
|
||||
github.com/pion/stun/v3 v3.1.2
|
||||
github.com/pmezard/go-difflib v1.0.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.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/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/urfave/cli/v3 v3.8.0
|
||||
github.com/prometheus/common v0.68.1 // indirect
|
||||
github.com/prometheus/procfs v0.20.1 // 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.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
|
||||
gopkg.in/yaml.v2 v2.4.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
|
||||
)
|
||||
|
||||
replace github.com/livekit/protocol => ../protocol
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
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=
|
||||
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=
|
||||
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=
|
||||
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=
|
||||
@@ -41,46 +31,45 @@ 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/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
|
||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
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/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/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=
|
||||
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/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/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=
|
||||
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=
|
||||
@@ -92,16 +81,12 @@ 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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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/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=
|
||||
@@ -114,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=
|
||||
@@ -130,10 +113,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=
|
||||
@@ -156,10 +139,8 @@ 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.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=
|
||||
@@ -173,26 +154,24 @@ 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=
|
||||
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/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-20260608063931-a3417d38cda0 h1:XHNNzebIKZRkLimla/hFGrAIX5EMWHctrgt3hLw7s+I=
|
||||
github.com/livekit/mediatransportutil v0.0.0-20260608063931-a3417d38cda0/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU=
|
||||
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/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=
|
||||
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,57 +186,55 @@ 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/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/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/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=
|
||||
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/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/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/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.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.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=
|
||||
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=
|
||||
@@ -266,57 +243,55 @@ 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.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/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/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=
|
||||
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=
|
||||
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=
|
||||
@@ -327,23 +302,14 @@ 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=
|
||||
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/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=
|
||||
@@ -351,20 +317,22 @@ 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/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/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/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.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.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=
|
||||
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=
|
||||
@@ -373,56 +341,50 @@ 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=
|
||||
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.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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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.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-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=
|
||||
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.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
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=
|
||||
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.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/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=
|
||||
@@ -446,20 +408,16 @@ 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-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-20220319134239-a9b59b0215f8/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-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.0.0-20220728004956-3c1f35247d10/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.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=
|
||||
@@ -472,30 +430,27 @@ 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=
|
||||
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.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=
|
||||
@@ -504,10 +459,10 @@ 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=
|
||||
|
||||
+49
-2
@@ -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 {
|
||||
@@ -59,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"`
|
||||
@@ -117,6 +119,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"`
|
||||
|
||||
@@ -151,6 +165,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"`
|
||||
@@ -370,6 +386,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"`
|
||||
@@ -681,6 +701,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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+43
-5
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
+68
-58
@@ -174,57 +174,58 @@ type ParticipantParams struct {
|
||||
PLIThrottleConfig sfu.PLIThrottleConfig
|
||||
CongestionControlConfig config.CongestionControlConfig
|
||||
// codecs that are enabled for this room
|
||||
PublishEnabledCodecs []*livekit.Codec
|
||||
SubscribeEnabledCodecs []*livekit.Codec
|
||||
Logger logger.Logger
|
||||
LoggerResolver logger.DeferredFieldResolver
|
||||
Reporter roomobs.ParticipantSessionReporter
|
||||
ReporterResolver roomobs.ParticipantReporterResolver
|
||||
SimTracks map[uint32]interceptor.SimulcastTrackInfo
|
||||
Grants *auth.ClaimGrants
|
||||
InitialVersion uint32
|
||||
ClientConf *livekit.ClientConfiguration
|
||||
ClientInfo ClientInfo
|
||||
Region string
|
||||
Migration bool
|
||||
Reconnect bool
|
||||
AdaptiveStream bool
|
||||
AllowTCPFallback bool
|
||||
TCPFallbackRTTThreshold int
|
||||
AllowUDPUnstableFallback bool
|
||||
TURNSEnabled bool
|
||||
ParticipantListener types.LocalParticipantListener
|
||||
ParticipantHelper types.LocalParticipantHelper
|
||||
DisableSupervisor bool
|
||||
ReconnectOnPublicationError bool
|
||||
ReconnectOnSubscriptionError bool
|
||||
ReconnectOnDataChannelError bool
|
||||
VersionGenerator utils.TimedVersionGenerator
|
||||
DisableDynacast bool
|
||||
SubscriberAllowPause bool
|
||||
SubscriptionLimitAudio int32
|
||||
SubscriptionLimitVideo int32
|
||||
PlayoutDelay *livekit.PlayoutDelay
|
||||
SyncStreams bool
|
||||
ForwardStats *sfu.ForwardStats
|
||||
DisableSenderReportPassThrough bool
|
||||
MetricConfig metric.MetricConfig
|
||||
UseOneShotSignallingMode bool
|
||||
EnableMetrics bool
|
||||
DataChannelMaxBufferedAmount uint64
|
||||
DatachannelSlowThreshold int
|
||||
DatachannelLossyTargetLatency time.Duration
|
||||
FireOnTrackBySdp bool
|
||||
DisableCodecRegression bool
|
||||
LastPubReliableSeq uint32
|
||||
Country string
|
||||
PreferVideoSizeFromMedia bool
|
||||
UseSinglePeerConnection bool
|
||||
EnableDataTracks bool
|
||||
EnableRTPStreamRestartDetection bool
|
||||
ForceBackupCodecPolicySimulcast bool
|
||||
DisableTransceiverReuseForE2EE bool
|
||||
EnableParticipantAsyncAttributes bool
|
||||
PublishEnabledCodecs []*livekit.Codec
|
||||
SubscribeEnabledCodecs []*livekit.Codec
|
||||
Logger logger.Logger
|
||||
LoggerResolver logger.DeferredFieldResolver
|
||||
Reporter roomobs.ParticipantSessionReporter
|
||||
ReporterResolver roomobs.ParticipantReporterResolver
|
||||
SimTracks map[uint32]interceptor.SimulcastTrackInfo
|
||||
Grants *auth.ClaimGrants
|
||||
TokenExpiresAt time.Time
|
||||
InitialVersion uint32
|
||||
ClientConf *livekit.ClientConfiguration
|
||||
ClientInfo ClientInfo
|
||||
Region string
|
||||
Migration bool
|
||||
Reconnect bool
|
||||
AdaptiveStream bool
|
||||
AllowTCPFallback bool
|
||||
TCPFallbackRTTThreshold int
|
||||
AllowUDPUnstableFallback bool
|
||||
TURNSEnabled bool
|
||||
ParticipantListener types.LocalParticipantListener
|
||||
ParticipantHelper types.LocalParticipantHelper
|
||||
DisableSupervisor bool
|
||||
ReconnectOnPublicationError bool
|
||||
ReconnectOnSubscriptionError bool
|
||||
ReconnectOnDataChannelError bool
|
||||
VersionGenerator utils.TimedVersionGenerator
|
||||
DisableDynacast bool
|
||||
SubscriberAllowPause bool
|
||||
SubscriptionLimitAudio int32
|
||||
SubscriptionLimitVideo int32
|
||||
PlayoutDelay *livekit.PlayoutDelay
|
||||
SyncStreams bool
|
||||
ForwardStats *sfu.ForwardStats
|
||||
DisableSenderReportPassThrough bool
|
||||
MetricConfig metric.MetricConfig
|
||||
UseOneShotSignallingMode bool
|
||||
EnableMetrics bool
|
||||
DataChannelMaxBufferedAmount uint64
|
||||
DatachannelSlowThreshold int
|
||||
DatachannelLossyTargetLatency time.Duration
|
||||
FireOnTrackBySdp bool
|
||||
DisableCodecRegression bool
|
||||
LastPubReliableSeq uint32
|
||||
Country string
|
||||
PreferVideoSizeFromMedia bool
|
||||
UseSinglePeerConnection bool
|
||||
EnableDataTracks bool
|
||||
EnableRTPStreamRestartDetection bool
|
||||
ForceBackupCodecPolicySimulcast bool
|
||||
DisableTransceiverReuseForE2EE bool
|
||||
EnableParticipantDataBlobs bool
|
||||
}
|
||||
|
||||
type ParticipantImpl struct {
|
||||
@@ -410,19 +411,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()))
|
||||
|
||||
@@ -787,6 +792,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
|
||||
@@ -4075,6 +4084,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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
+14
-4
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)()
|
||||
}
|
||||
|
||||
+26
-1
@@ -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()
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ type LocalParticipant interface {
|
||||
|
||||
// permissions
|
||||
ClaimGrants() *auth.ClaimGrants
|
||||
TokenExpiresAt() time.Time
|
||||
SetPermission(permission *livekit.ParticipantPermission) bool
|
||||
CanPublish() bool
|
||||
CanPublishSource(source livekit.TrackSource) bool
|
||||
@@ -839,6 +840,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)
|
||||
@@ -851,6 +853,7 @@ type DataTrack interface {
|
||||
//counterfeiter:generate . DataDownTrack
|
||||
type DataDownTrack interface {
|
||||
Close()
|
||||
OnClose(fn func())
|
||||
|
||||
Handle() uint16
|
||||
PublishDataTrack() DataTrack
|
||||
@@ -915,8 +918,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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -1384,6 +1384,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 {
|
||||
@@ -8901,6 +8911,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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+29
-7
@@ -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)
|
||||
@@ -133,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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+17
-10
@@ -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,18 @@ 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)
|
||||
// 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)
|
||||
|
||||
+36
-7
@@ -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"`
|
||||
}
|
||||
@@ -371,3 +393,10 @@ func (s *EgressService) StopEgress(ctx context.Context, req *livekit.StopEgressR
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
+41
-29
@@ -471,34 +471,37 @@ 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,
|
||||
TokenExpiresAt: pi.TokenExpiresAt,
|
||||
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,
|
||||
@@ -1123,11 +1126,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).
|
||||
|
||||
@@ -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,
|
||||
@@ -364,6 +365,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
|
||||
|
||||
+35
-1
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,6 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
import (
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
// Injectors from wire.go:
|
||||
|
||||
func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*LivekitServer, error) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
+18
-4
@@ -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 ""
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@
|
||||
|
||||
package version
|
||||
|
||||
const Version = "1.12.0"
|
||||
const Version = "1.13.1"
|
||||
|
||||
Reference in New Issue
Block a user