feat: Controller support, performance enchancements, multi-stage images, fixes (#304)

## Description
Oops.. another massive PR 🥲 

This PR contains multiple improvements and changes.

Firstly, thanks gst-wayland-display's PR
[here](https://github.com/games-on-whales/gst-wayland-display/pull/20).
NVIDIA path is now way more efficient than before.

Secondly, adding controller support was a massive hurdle, requiring me
to start another project
[vimputti](https://github.com/DatCaptainHorse/vimputti) - which allows
simple virtual controller inputs in isolated containers. Well, it's not
simple, it includes LD_PRELOAD shims and other craziness, but the
library API is simple to use..

Thirdly, split runner image into 3 separate stages, base + build +
runtime, should help keep things in check in future, also added GitHub
Actions CI builds for v2 to v4 builds (hopefully they pass..).

Fourth, replaced the runner's runtime Steam patching with better and
simpler bubblewrap patch, massive thanks to `games-on-whales` to
figuring it out better!

Fifth, relay for once needed some changes, the new changes are still
mostly WIP, but I'll deal with them next time I have energy.. I'm spent
now. Needed to include these changes as relay needed a minor change to
allow rumble events to flow back to client peer.

Sixth.. tons of package updates, minor code improvements and the usual. 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* End-to-end gamepad/controller support (attach/detach, buttons, sticks,
triggers, rumble) with client/server integration and virtual controller
plumbing.
  * Optional Prometheus metrics endpoint and WebTransport support.
  * Background vimputti manager process added for controller handling.

* **Improvements**
  * Multi-variant container image builds and streamlined runtime images.
  * Zero-copy video pipeline and encoder improvements for lower latency.
  * Updated Steam compat mapping and dependency/toolchain refreshes.

* **Bug Fixes**
* More robust GPU detection, input/fullscreen lifecycle,
startup/entrypoint, and container runtime fixes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
This commit is contained in:
Kristian Ollikainen
2025-10-20 11:20:05 +03:00
committed by GitHub
parent a3ee9aadd9
commit c62a22b552
62 changed files with 4203 additions and 2278 deletions

View File

@@ -0,0 +1 @@
persist-data/

View File

@@ -1,59 +1,50 @@
module relay
go 1.24
go 1.25.0
require (
github.com/libp2p/go-libp2p v0.41.1
github.com/libp2p/go-libp2p-pubsub v0.13.1
github.com/libp2p/go-libp2p v0.44.0
github.com/libp2p/go-libp2p-pubsub v0.15.0
github.com/libp2p/go-reuseport v0.4.0
github.com/multiformats/go-multiaddr v0.15.0
github.com/multiformats/go-multiaddr v0.16.1
github.com/oklog/ulid/v2 v2.1.1
github.com/pion/ice/v4 v4.0.10
github.com/pion/interceptor v0.1.38
github.com/pion/rtp v1.8.15
github.com/pion/webrtc/v4 v4.1.1
google.golang.org/protobuf v1.36.6
github.com/pion/interceptor v0.1.41
github.com/pion/rtp v1.8.24
github.com/pion/webrtc/v4 v4.1.6
github.com/prometheus/client_golang v1.23.2
google.golang.org/protobuf v1.36.10
)
require (
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/elastic/gosigar v0.14.3 // indirect
github.com/filecoin-project/go-clock v0.1.0 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/huin/goupnp v1.3.0 // indirect
github.com/ipfs/go-cid v0.5.0 // indirect
github.com/ipfs/go-log/v2 v2.6.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/koron/go-ssdp v0.0.6 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/koron/go-ssdp v0.1.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.3.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-netroute v0.2.2 // indirect
github.com/libp2p/go-yamux/v5 v5.0.0 // indirect
github.com/libp2p/go-netroute v0.3.0 // indirect
github.com/libp2p/go-yamux/v5 v5.1.0 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.66 // indirect
github.com/miekg/dns v1.1.68 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
@@ -63,54 +54,51 @@ require (
github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multicodec v0.10.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.6.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/multiformats/go-multistream v0.6.1 // indirect
github.com/multiformats/go-varint v0.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
github.com/opencontainers/runtime-spec v1.2.1 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/dtls/v3 v3.0.6 // indirect
github.com/pion/logging v0.2.3 // indirect
github.com/pion/dtls/v3 v3.0.7 // indirect
github.com/pion/logging v0.2.4 // indirect
github.com/pion/mdns/v2 v2.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.15 // indirect
github.com/pion/sctp v1.8.39 // indirect
github.com/pion/sdp/v3 v3.0.13 // indirect
github.com/pion/srtp/v3 v3.0.4 // indirect
github.com/pion/rtcp v1.2.16 // indirect
github.com/pion/sctp v1.8.40 // indirect
github.com/pion/sdp/v3 v3.0.16 // indirect
github.com/pion/srtp/v3 v3.0.8 // indirect
github.com/pion/stun v0.6.1 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v2 v2.2.10 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
github.com/pion/turn/v4 v4.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/pion/transport/v3 v3.0.8 // indirect
github.com/pion/turn/v4 v4.1.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.64.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/common v0.67.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.52.0 // indirect
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/quic-go/quic-go v0.55.0 // indirect
github.com/quic-go/webtransport-go v0.9.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/dig v1.19.0 // indirect
go.uber.org/fx v1.24.0 // indirect
go.uber.org/mock v0.5.2 // indirect
go.uber.org/mock v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.33.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/telemetry v0.0.0-20251014153721-24f779f6aaef // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.38.0 // indirect
lukechampine.com/blake3 v1.4.1 // indirect
)

View File

@@ -9,7 +9,6 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -19,17 +18,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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=
@@ -39,13 +29,7 @@ github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
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.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo=
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU=
github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
@@ -57,16 +41,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -77,17 +52,12 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
@@ -103,8 +73,6 @@ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=
github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk=
github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg=
github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
@@ -112,15 +80,14 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
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.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU=
github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI=
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/koron/go-ssdp v0.1.0 h1:ckl5x5H6qSNFmi+wCuROvvGUu2FQnMbQrU95IHCcv3Y=
github.com/koron/go-ssdp v0.1.0/go.mod h1:GltaDBjtK1kemZOusWYLGotV0kBeEf59Bp0wtSB0uyU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -130,39 +97,41 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
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/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE=
github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI=
github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs=
github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-pubsub v0.13.1 h1:tV3ttzzZSCk0EtEXnxVmWIXgjVxXx+20Jwjbs/Ctzjo=
github.com/libp2p/go-libp2p-pubsub v0.13.1/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44=
github.com/libp2p/go-libp2p-pubsub v0.15.0 h1:cG7Cng2BT82WttmPFMi50gDNV+58K626m/wR00vGL1o=
github.com/libp2p/go-libp2p-pubsub v0.15.0/go.mod h1:lr4oE8bFgQaifRcoc2uWhWWiK6tPdOEKpUuR408GFN4=
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc=
github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po=
github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU=
github.com/libp2p/go-yamux/v5 v5.1.0 h1:8Qlxj4E9JGJAQVW6+uj2o7mqkqsIVlSUGmTWhlXzoHE=
github.com/libp2p/go-yamux/v5 v5.1.0/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o=
github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q=
github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg=
github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
@@ -183,36 +152,29 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.15.0 h1:zB/HeaI/apcZiTDwhY5YqMvNVl/oQYvs3XySU+qeAVo=
github.com/multiformats/go-multiaddr v0.15.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=
github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw=
github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=
github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M=
github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
github.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=
github.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA=
github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ=
github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw=
github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI=
github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI=
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/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
@@ -222,29 +184,29 @@ github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oL
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=
github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E=
github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU=
github.com/pion/dtls/v3 v3.0.7 h1:bItXtTYYhZwkPFk4t1n3Kkf5TDrfj6+4wG+CZR8uI9Q=
github.com/pion/dtls/v3 v3.0.7/go.mod h1:uDlH5VPrgOQIw59irKYkMudSFprY9IEFCqz/eTz16f8=
github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4=
github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
github.com/pion/interceptor v0.1.38 h1:Mgt3XIIq47uR5vcLLahfRucE6tFPjxHak+z5ZZFEzLU=
github.com/pion/interceptor v0.1.38/go.mod h1:HS9X+Ue5LDE6q2C2tuvOuO83XkBdJFgn6MBDtfoJX4Q=
github.com/pion/interceptor v0.1.41 h1:NpvX3HgWIukTf2yTBVjVGFXtpSpWgXjqz7IIpu7NsOw=
github.com/pion/interceptor v0.1.41/go.mod h1:nEt4187unvRXJFyjiw00GKo+kIuXMWQI9K89fsosDLY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
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.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
github.com/pion/rtp v1.8.15 h1:MuhuGn1cxpVCPLNY1lI7F1tQ8Spntpgf12ob+pOYT8s=
github.com/pion/rtp v1.8.15/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4=
github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
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.8.24 h1:+ICyZXUQDv95EsHN70RrA4XKJf5MGWyC6QQc1u6/ynI=
github.com/pion/rtp v1.8.24/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM=
github.com/pion/sctp v1.8.40 h1:bqbgWYOrUhsYItEnRObUYZuzvOMsVplS3oNgzedBlG8=
github.com/pion/sctp v1.8.40/go.mod h1:SPBBUENXE6ThkEksN5ZavfAhFYll+h+66ZiG6IZQuzo=
github.com/pion/sdp/v3 v3.0.16 h1:0dKzYO6gTAvuLaAKQkC02eCPjMIi4NuAr/ibAwrGDCo=
github.com/pion/sdp/v3 v3.0.16/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo=
github.com/pion/srtp/v3 v3.0.8 h1:RjRrjcIeQsilPzxvdaElN0CpuQZdMvcl9VZ5UY9suUM=
github.com/pion/srtp/v3 v3.0.8/go.mod h1:2Sq6YnDH7/UDCvkSoHSDNDeyBcFgWL0sAVycVbAsXFg=
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
@@ -253,43 +215,36 @@ github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1A
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=
github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps=
github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs=
github.com/pion/webrtc/v4 v4.1.1 h1:PMFPtLg1kpD2pVtun+LGUzA3k54JdFl87WO0Z1+HKug=
github.com/pion/webrtc/v4 v4.1.1/go.mod h1:cgEGkcpxGkT6Di2ClBYO5lP9mFXbCfEOrkYUpjjCQO4=
github.com/pion/transport/v3 v3.0.8 h1:oI3myyYnTKUSTthu/NZZ8eu2I5sHbxbUNNFW62olaYc=
github.com/pion/transport/v3 v3.0.8/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ=
github.com/pion/turn/v4 v4.1.1 h1:9UnY2HB99tpDyz3cVVZguSxcqkJ1DsTSZ+8TGruh4fc=
github.com/pion/turn/v4 v4.1.1/go.mod h1:2123tHk1O++vmjI5VSD0awT50NywDAq5A2NNNU4Jjs8=
github.com/pion/webrtc/v4 v4.1.6 h1:srHH2HwvCGwPba25EYJgUzgLqCQoXl1VCUnrGQMSzUw=
github.com/pion/webrtc/v4 v4.1.6/go.mod h1:wKecGRlkl3ox/As/MYghJL+b/cVXMEhoPMJWPuGQFhU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
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.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
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.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI=
github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
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/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
@@ -311,10 +266,8 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@@ -323,15 +276,13 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
@@ -341,20 +292,20 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg=
go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo=
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/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
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.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -369,22 +320,20 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw=
golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -406,8 +355,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -423,17 +372,14 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -444,13 +390,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251014153721-24f779f6aaef h1:5xFtU4tmJMJSxSeDlr1dgBff2tDXrq0laLdS1EA3LYw=
golang.org/x/telemetry v0.0.0-20251014153721-24f779f6aaef/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
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=
@@ -467,24 +414,24 @@ 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.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
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=
@@ -505,10 +452,9 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=

View File

@@ -30,29 +30,12 @@ func InitWebRTCAPI() error {
return fmt.Errorf("failed to register extensions: %w", err)
}
// Default codecs cover most of our needs
// Default codecs cover our needs
err = mediaEngine.RegisterDefaultCodecs()
if err != nil {
return err
}
// Add H.265 for special cases
videoRTCPFeedback := []webrtc.RTCPFeedback{{"goog-remb", ""}, {"ccm", "fir"}, {"nack", ""}, {"nack", "pli"}}
for _, codec := range []webrtc.RTPCodecParameters{
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH265, ClockRate: 90000, RTCPFeedback: videoRTCPFeedback},
PayloadType: 48,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeRTX, ClockRate: 90000, SDPFmtpLine: "apt=48"},
PayloadType: 49,
},
} {
if err = mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeVideo); err != nil {
return err
}
}
// Interceptor registry
interceptorRegistry := &interceptor.Registry{}
@@ -98,7 +81,8 @@ func InitWebRTCAPI() error {
slog.Info("Using WebRTC UDP Port Range", "start", flags.WebRTCUDPStart, "end", flags.WebRTCUDPEnd)
}
settingEngine.SetIncludeLoopbackCandidate(true) // Just in case
// Improves speed when sending offers to browsers (https://github.com/pion/webrtc/issues/3174)
settingEngine.SetIncludeLoopbackCandidate(true)
// Create a new API object with our customized settings
globalWebRTCAPI = webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine), webrtc.WithSettingEngine(settingEngine), webrtc.WithInterceptorRegistry(interceptorRegistry))

View File

@@ -24,6 +24,8 @@ type Flags struct {
AutoAddLocalIP bool // Automatically add local IP to NAT 1 to 1 IPs
NAT11IP string // WebRTC NAT 1 to 1 IP - allows specifying IP of relay if behind NAT
PersistDir string // Directory to save persistent data to
Metrics bool // Enable metrics endpoint
MetricsPort int // Port for metrics endpoint
}
func (flags *Flags) DebugLog() {
@@ -39,6 +41,8 @@ func (flags *Flags) DebugLog() {
"autoAddLocalIP", flags.AutoAddLocalIP,
"webrtcNAT11IPs", flags.NAT11IP,
"persistDir", flags.PersistDir,
"metrics", flags.Metrics,
"metricsPort", flags.MetricsPort,
)
}
@@ -79,12 +83,14 @@ func InitFlags() {
flag.IntVar(&globalFlags.WebRTCUDPStart, "webrtcUDPStart", getEnvAsInt("WEBRTC_UDP_START", 0), "WebRTC UDP port range start")
flag.IntVar(&globalFlags.WebRTCUDPEnd, "webrtcUDPEnd", getEnvAsInt("WEBRTC_UDP_END", 0), "WebRTC UDP port range end")
flag.StringVar(&globalFlags.STUNServer, "stunServer", getEnvAsString("STUN_SERVER", "stun.l.google.com:19302"), "WebRTC STUN server")
flag.IntVar(&globalFlags.UDPMuxPort, "webrtcUDPMux", getEnvAsInt("WEBRTC_UDP_MUX", 8088), "WebRTC UDP mux port")
flag.BoolVar(&globalFlags.AutoAddLocalIP, "autoAddLocalIP", getEnvAsBool("AUTO_ADD_LOCAL_IP", true), "Automatically add local IP to NAT 1 to 1 IPs")
flag.IntVar(&globalFlags.UDPMuxPort, "webrtcUDPMux", getEnvAsInt("WEBRTC_UDP_MUX", 9099), "WebRTC UDP mux port")
flag.BoolVar(&globalFlags.AutoAddLocalIP, "autoAddLocalIP", getEnvAsBool("AUTO_ADD_LOCAL_IP", false), "Automatically add local IP to NAT 1 to 1 IPs")
// String with comma separated IPs
nat11IP := ""
flag.StringVar(&nat11IP, "webrtcNAT11IP", getEnvAsString("WEBRTC_NAT_IP", ""), "WebRTC NAT 1 to 1 IP")
flag.StringVar(&globalFlags.PersistDir, "persistDir", getEnvAsString("PERSIST_DIR", "./persist-data"), "Directory to save persistent data to")
flag.BoolVar(&globalFlags.Metrics, "metrics", getEnvAsBool("METRICS", false), "Enable metrics endpoint")
flag.IntVar(&globalFlags.MetricsPort, "metricsPort", getEnvAsInt("METRICS_PORT", 3030), "Port for metrics endpoint")
// Parse flags
flag.Parse()

View File

@@ -4,24 +4,31 @@ import (
"context"
"crypto/ed25519"
"fmt"
"log"
"log/slog"
"net/http"
"os"
"relay/internal/common"
"relay/internal/shared"
"time"
"github.com/libp2p/go-libp2p"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
"github.com/multiformats/go-multiaddr"
"github.com/oklog/ulid/v2"
"github.com/pion/webrtc/v4"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// -- Variables --
@@ -30,17 +37,9 @@ var globalRelay *Relay
// -- Structs --
// RelayInfo contains light information of Relay, in mesh-friendly format
type RelayInfo struct {
ID peer.ID
MeshAddrs []string // Addresses of this relay
MeshRooms *common.SafeMap[string, shared.RoomInfo] // Rooms hosted by this relay
MeshLatencies *common.SafeMap[string, time.Duration] // Latencies to other peers from this relay
}
// Relay structure enhanced with metrics and state
type Relay struct {
RelayInfo
*PeerInfo
Host host.Host // libp2p host for peer-to-peer networking
PubSub *pubsub.PubSub // PubSub for state synchronization
@@ -48,7 +47,6 @@ type Relay struct {
// Local
LocalRooms *common.SafeMap[ulid.ULID, *shared.Room] // room ID -> local Room struct (hosted by this relay)
LocalMeshPeers *common.SafeMap[peer.ID, *RelayInfo] // peer ID -> mesh peer relay info (connected to this relay)
LocalMeshConnections *common.SafeMap[peer.ID, *webrtc.PeerConnection] // peer ID -> PeerConnection (connected to this relay)
// Protocols
@@ -60,11 +58,43 @@ type Relay struct {
}
func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay, error) {
// If metrics are enabled, start the metrics server first
metricsOpts := make([]libp2p.Option, 0)
var rmgr network.ResourceManager
if common.GetFlags().Metrics {
go func() {
slog.Info("Starting prometheus metrics server at '/debug/metrics/prometheus'", "port", common.GetFlags().MetricsPort)
http.Handle("/debug/metrics/prometheus", promhttp.Handler())
if err := http.ListenAndServe(fmt.Sprintf(":%d", common.GetFlags().MetricsPort), nil); err != nil {
slog.Error("Failed to start metrics server", "err", err)
}
}()
rcmgr.MustRegisterWith(prometheus.DefaultRegisterer)
str, err := rcmgr.NewStatsTraceReporter()
if err != nil {
log.Fatal(err)
}
rmgr, err = rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(str))
if err != nil {
log.Fatal(err)
}
metricsOpts = append(metricsOpts, libp2p.ResourceManager(rmgr))
metricsOpts = append(metricsOpts, libp2p.PrometheusRegisterer(prometheus.DefaultRegisterer))
} else {
rmgr = nil
}
listenAddrs := []string{
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port), // IPv4 - Raw TCP
fmt.Sprintf("/ip6/::/tcp/%d", port), // IPv6 - Raw TCP
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d/ws", port), // IPv4 - TCP WebSocket
fmt.Sprintf("/ip6/::/tcp/%d/ws", port), // IPv6 - TCP WebSocket
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port), // IPv4 - Raw TCP
fmt.Sprintf("/ip6/::/tcp/%d", port), // IPv6 - Raw TCP
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d/ws", port), // IPv4 - TCP WebSocket
fmt.Sprintf("/ip6/::/tcp/%d/ws", port), // IPv6 - TCP WebSocket
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1/webtransport", port), // IPv4 - UDP QUIC WebTransport
fmt.Sprintf("/ip6/::/udp/%d/quic-v1/webtransport", port), // IPv6 - UDP QUIC WebTransport
}
var muAddrs []multiaddr.Multiaddr
@@ -78,11 +108,12 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
// Initialize libp2p host
p2pHost, err := libp2p.New(
// TODO: Currently static identity
libp2p.ChainOptions(metricsOpts...),
libp2p.Identity(identityKey),
// Enable required transports
libp2p.Transport(tcp.NewTCPTransport),
libp2p.Transport(ws.New),
libp2p.Transport(webtransport.New),
// Other options
libp2p.ListenAddrs(muAddrs...),
libp2p.Security(noise.ID, noise.New),
@@ -91,6 +122,7 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
libp2p.EnableNATService(),
libp2p.EnableAutoNATv2(),
libp2p.ShareTCPListener(),
libp2p.QUICReuse(quicreuse.NewConnManager),
)
if err != nil {
return nil, fmt.Errorf("failed to create libp2p host for relay: %w", err)
@@ -105,23 +137,13 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
// Initialize Ping Service
pingSvc := ping.NewPingService(p2pHost)
var addresses []string
for _, addr := range p2pHost.Addrs() {
addresses = append(addresses, addr.String())
}
r := &Relay{
RelayInfo: RelayInfo{
ID: p2pHost.ID(),
MeshAddrs: addresses,
MeshRooms: common.NewSafeMap[string, shared.RoomInfo](),
MeshLatencies: common.NewSafeMap[string, time.Duration](),
},
Host: p2pHost,
PubSub: p2pPubsub,
PingService: pingSvc,
LocalRooms: common.NewSafeMap[ulid.ULID, *shared.Room](),
LocalMeshPeers: common.NewSafeMap[peer.ID, *RelayInfo](),
PeerInfo: NewPeerInfo(p2pHost.ID(), p2pHost.Addrs()),
Host: p2pHost,
PubSub: p2pPubsub,
PingService: pingSvc,
LocalRooms: common.NewSafeMap[ulid.ULID, *shared.Room](),
LocalMeshConnections: common.NewSafeMap[peer.ID, *webrtc.PeerConnection](),
}
// Add network notifier after relay is initialized
@@ -152,7 +174,7 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
return r, nil
}
func InitRelay(ctx context.Context, ctxCancel context.CancelFunc) error {
func InitRelay(ctx context.Context, ctxCancel context.CancelFunc) (*Relay, error) {
var err error
persistentDir := common.GetFlags().PersistDir
@@ -164,7 +186,7 @@ func InitRelay(ctx context.Context, ctxCancel context.CancelFunc) error {
if hasIdentity {
_, err = os.Stat(persistentDir + "/identity.key")
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to check identity key file: %w", err)
return nil, fmt.Errorf("failed to check identity key file: %w", err)
} else if os.IsNotExist(err) {
hasIdentity = false
}
@@ -172,17 +194,17 @@ func InitRelay(ctx context.Context, ctxCancel context.CancelFunc) error {
if !hasIdentity {
// Make sure the persistent directory exists
if err = os.MkdirAll(persistentDir, 0700); err != nil {
return fmt.Errorf("failed to create persistent data directory: %w", err)
return nil, fmt.Errorf("failed to create persistent data directory: %w", err)
}
// Generate
slog.Info("Generating new identity for relay")
privKey, err = common.GenerateED25519Key()
if err != nil {
return fmt.Errorf("failed to generate new identity: %w", err)
return nil, fmt.Errorf("failed to generate new identity: %w", err)
}
// Save the key
if err = common.SaveED25519Key(privKey, persistentDir+"/identity.key"); err != nil {
return fmt.Errorf("failed to save identity key: %w", err)
return nil, fmt.Errorf("failed to save identity key: %w", err)
}
slog.Info("New identity generated and saved", "path", persistentDir+"/identity.key")
} else {
@@ -190,25 +212,45 @@ func InitRelay(ctx context.Context, ctxCancel context.CancelFunc) error {
// Load the key
privKey, err = common.LoadED25519Key(persistentDir + "/identity.key")
if err != nil {
return fmt.Errorf("failed to load identity key: %w", err)
return nil, fmt.Errorf("failed to load identity key: %w", err)
}
}
// Convert to libp2p crypto.PrivKey
identityKey, err = crypto.UnmarshalEd25519PrivateKey(privKey)
if err != nil {
return fmt.Errorf("failed to unmarshal ED25519 private key: %w", err)
return nil, fmt.Errorf("failed to unmarshal ED25519 private key: %w", err)
}
globalRelay, err = NewRelay(ctx, common.GetFlags().EndpointPort, identityKey)
if err != nil {
return fmt.Errorf("failed to create relay: %w", err)
return nil, fmt.Errorf("failed to create relay: %w", err)
}
if err = common.InitWebRTCAPI(); err != nil {
return err
return nil, err
}
slog.Info("Relay initialized", "id", globalRelay.ID)
return nil
// Load previous peers on startup
defaultFile := common.GetFlags().PersistDir + "/peerstore.json"
if err = globalRelay.LoadFromFile(defaultFile); err != nil {
slog.Warn("Failed to load previous peer store", "error", err)
} else {
globalRelay.Peers.Range(func(id peer.ID, pi *PeerInfo) bool {
if len(pi.Addrs) <= 0 {
slog.Warn("Peer from peer store has no addresses", "peer", id)
return true
}
// Connect to first address only
if err = globalRelay.ConnectToPeer(context.Background(), pi.Addrs[0]); err != nil {
slog.Error("Failed to connect to peer from peer store", "peer", id, "error", err)
}
return true
})
}
return globalRelay, nil
}

View File

@@ -19,7 +19,7 @@ type discoveryNotifee struct {
func (d *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) {
if d.relay != nil {
if err := d.relay.connectToRelay(context.Background(), &pi); err != nil {
if err := d.relay.connectToPeer(context.Background(), &pi); err != nil {
slog.Error("failed to connect to discovered relay", "peer", pi.ID, "error", err)
}
}

View File

@@ -46,7 +46,7 @@ func (r *Relay) publishRelayMetrics(ctx context.Context) error {
// Check all peer latencies
r.checkAllPeerLatencies(ctx)
data, err := json.Marshal(r.RelayInfo)
data, err := json.Marshal(r.PeerInfo)
if err != nil {
return fmt.Errorf("failed to marshal relay status: %w", err)
}
@@ -109,8 +109,8 @@ func (r *Relay) measureLatencyToPeer(ctx context.Context, peerID peer.ID) {
if result.Error != nil {
slog.Warn("Latency check failed, removing peer from local peers map", "peer", peerID, "err", result.Error)
// Remove from MeshPeers if ping failed
if r.LocalMeshPeers.Has(peerID) {
r.LocalMeshPeers.Delete(peerID)
if r.Peers.Has(peerID) {
r.Peers.Delete(peerID)
}
return
}
@@ -123,6 +123,6 @@ func (r *Relay) measureLatencyToPeer(ctx context.Context, peerID peer.ID) {
latency = 1 * time.Microsecond
}
r.RelayInfo.MeshLatencies.Set(peerID.String(), latency)
r.PeerInfo.Latencies.Set(peerID, latency)
}
}

View File

@@ -22,7 +22,7 @@ type networkNotifier struct {
// Connected is called when a connection is established
func (n *networkNotifier) Connected(net network.Network, conn network.Conn) {
if n.relay == nil {
if n.relay != nil {
n.relay.onPeerConnected(conn.RemotePeer())
}
}
@@ -75,8 +75,8 @@ func (r *Relay) setupPubSub(ctx context.Context) error {
// --- Connection Management ---
// connectToRelay is internal method to connect to a relay peer using multiaddresses
func (r *Relay) connectToRelay(ctx context.Context, peerInfo *peer.AddrInfo) error {
// connectToPeer is internal method to connect to a peer using multiaddresses
func (r *Relay) connectToPeer(ctx context.Context, peerInfo *peer.AddrInfo) error {
if peerInfo.ID == r.ID {
return errors.New("cannot connect to self")
}
@@ -94,19 +94,14 @@ func (r *Relay) connectToRelay(ctx context.Context, peerInfo *peer.AddrInfo) err
return nil
}
// ConnectToRelay connects to another relay by its multiaddress.
func (r *Relay) ConnectToRelay(ctx context.Context, addr string) error {
ma, err := multiaddr.NewMultiaddr(addr)
if err != nil {
return fmt.Errorf("invalid multiaddress: %w", err)
}
peerInfo, err := peer.AddrInfoFromP2pAddr(ma)
// ConnectToPeer connects to another peer by its multiaddress.
func (r *Relay) ConnectToPeer(ctx context.Context, addr multiaddr.Multiaddr) error {
peerInfo, err := peer.AddrInfoFromP2pAddr(addr)
if err != nil {
return fmt.Errorf("failed to extract peer info: %w", err)
}
return r.connectToRelay(ctx, peerInfo)
return r.connectToPeer(ctx, peerInfo)
}
// printConnectInstructions logs the multiaddresses for connecting to this relay.

View File

@@ -0,0 +1,77 @@
package core
import (
"errors"
"log/slog"
"os"
"relay/internal/common"
"relay/internal/shared"
"time"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
)
// PeerInfo contains information of a peer, in light transmit-friendly format
type PeerInfo struct {
ID peer.ID
Addrs []multiaddr.Multiaddr // Addresses of this peer
Peers *common.SafeMap[peer.ID, *PeerInfo] // Peers connected to this peer
Latencies *common.SafeMap[peer.ID, time.Duration] // Latencies to other peers from this peer
Rooms *common.SafeMap[string, shared.RoomInfo] // Rooms this peer is part of or owner of
}
func NewPeerInfo(id peer.ID, addrs []multiaddr.Multiaddr) *PeerInfo {
return &PeerInfo{
ID: id,
Addrs: addrs,
Peers: common.NewSafeMap[peer.ID, *PeerInfo](),
Latencies: common.NewSafeMap[peer.ID, time.Duration](),
Rooms: common.NewSafeMap[string, shared.RoomInfo](),
}
}
// SaveToFile saves the peer store to a JSON file in persistent path
func (pi *PeerInfo) SaveToFile(filePath string) error {
if len(filePath) <= 0 {
return errors.New("filepath is not set")
}
// Marshal the peer store to JSON array (we don't need to store IDs..)
data, err := pi.Peers.MarshalJSON()
if err != nil {
return errors.New("failed to marshal peer store data: " + err.Error())
}
// Save the data to a file
if err = os.WriteFile(filePath, data, 0644); err != nil {
return errors.New("failed to save peer store to file: " + err.Error())
}
slog.Info("PeerStore saved to file", "path", filePath)
return nil
}
// LoadFromFile loads the peer store from a JSON file in persistent path
func (pi *PeerInfo) LoadFromFile(filePath string) error {
if len(filePath) <= 0 {
return errors.New("filepath is not set")
}
data, err := os.ReadFile(filePath)
if err != nil {
if os.IsNotExist(err) {
slog.Info("PeerStore file does not exist, starting with empty store")
return nil // No peers to load
}
return errors.New("failed to read peer store file: " + err.Error())
}
// Unmarshal the JSON data into the peer store
if err = pi.Peers.UnmarshalJSON(data); err != nil {
return errors.New("failed to unmarshal peer store data: " + err.Error())
}
slog.Info("PeerStore loaded from file", "path", filePath)
return nil
}

View File

@@ -40,15 +40,15 @@ type StreamConnection struct {
// StreamProtocol deals with meshed stream forwarding
type StreamProtocol struct {
relay *Relay
servedConns *common.SafeMap[peer.ID, *StreamConnection] // peer ID -> StreamConnection (for served streams)
incomingConns *common.SafeMap[string, *StreamConnection] // room name -> StreamConnection (for incoming pushed streams)
requestedConns *common.SafeMap[string, *StreamConnection] // room name -> StreamConnection (for requested streams from other relays)
servedConns *common.SafeMap[string, *common.SafeMap[peer.ID, *StreamConnection]] // room name -> (peer ID -> StreamConnection) (for served streams)
incomingConns *common.SafeMap[string, *StreamConnection] // room name -> StreamConnection (for incoming pushed streams)
requestedConns *common.SafeMap[string, *StreamConnection] // room name -> StreamConnection (for requested streams from other relays)
}
func NewStreamProtocol(relay *Relay) *StreamProtocol {
protocol := &StreamProtocol{
relay: relay,
servedConns: common.NewSafeMap[peer.ID, *StreamConnection](),
servedConns: common.NewSafeMap[string, *common.SafeMap[peer.ID, *StreamConnection]](),
incomingConns: common.NewSafeMap[string, *StreamConnection](),
requestedConns: common.NewSafeMap[string, *StreamConnection](),
}
@@ -66,6 +66,7 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
brw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
safeBRW := common.NewSafeBufioRW(brw)
var currentRoomName string // Track the current room for this stream
iceHolder := make([]webrtc.ICECandidateInit, 0)
for {
data, err := safeBRW.Receive()
@@ -101,7 +102,9 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
continue
}
currentRoomName = roomName // Store the room name
slog.Info("Received stream request for room", "room", roomName)
room := sp.relay.GetRoomByName(roomName)
if room == nil || !room.IsOnline() || room.OwnerID != sp.relay.ID {
// TODO: Allow forward requests to other relays from here?
@@ -126,8 +129,12 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
pc, err := common.CreatePeerConnection(func() {
slog.Info("PeerConnection closed for requested stream", "room", roomName)
// Cleanup the stream connection
if ok := sp.servedConns.Has(stream.Conn().RemotePeer()); ok {
sp.servedConns.Delete(stream.Conn().RemotePeer())
if roomMap, ok := sp.servedConns.Get(roomName); ok {
roomMap.Delete(stream.Conn().RemotePeer())
// If the room map is empty, delete it
if roomMap.Len() == 0 {
sp.servedConns.Delete(roomName)
}
}
})
if err != nil {
@@ -204,7 +211,12 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
}
// Store the connection
sp.servedConns.Set(stream.Conn().RemotePeer(), &StreamConnection{
roomMap, ok := sp.servedConns.Get(roomName)
if !ok {
roomMap = common.NewSafeMap[peer.ID, *StreamConnection]()
sp.servedConns.Set(roomName, roomMap)
}
roomMap.Set(stream.Conn().RemotePeer(), &StreamConnection{
pc: pc,
ndc: ndc,
})
@@ -216,17 +228,25 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
slog.Error("Failed to unmarshal ICE message", "err", err)
continue
}
if conn, ok := sp.servedConns.Get(stream.Conn().RemotePeer()); ok && conn.pc.RemoteDescription() != nil {
if err := conn.pc.AddICECandidate(iceMsg.Candidate); err != nil {
slog.Error("Failed to add ICE candidate", "err", err)
}
for _, heldIce := range iceHolder {
if err := conn.pc.AddICECandidate(heldIce); err != nil {
slog.Error("Failed to add held ICE candidate", "err", err)
// Use currentRoomName to get the connection from nested map
if len(currentRoomName) > 0 {
if roomMap, ok := sp.servedConns.Get(currentRoomName); ok {
if conn, ok := roomMap.Get(stream.Conn().RemotePeer()); ok && conn.pc.RemoteDescription() != nil {
if err := conn.pc.AddICECandidate(iceMsg.Candidate); err != nil {
slog.Error("Failed to add ICE candidate", "err", err)
}
for _, heldIce := range iceHolder {
if err := conn.pc.AddICECandidate(heldIce); err != nil {
slog.Error("Failed to add held ICE candidate", "err", err)
}
}
// Clear the held candidates
iceHolder = make([]webrtc.ICECandidateInit, 0)
} else {
// Hold the candidate until remote description is set
iceHolder = append(iceHolder, iceMsg.Candidate)
}
}
// Clear the held candidates
iceHolder = make([]webrtc.ICECandidateInit, 0)
} else {
// Hold the candidate until remote description is set
iceHolder = append(iceHolder, iceMsg.Candidate)
@@ -237,12 +257,19 @@ func (sp *StreamProtocol) handleStreamRequest(stream network.Stream) {
slog.Error("Failed to unmarshal answer from signaling message", "err", err)
continue
}
if conn, ok := sp.servedConns.Get(stream.Conn().RemotePeer()); ok {
if err := conn.pc.SetRemoteDescription(answerMsg.SDP); err != nil {
slog.Error("Failed to set remote description for answer", "err", err)
continue
// Use currentRoomName to get the connection from nested map
if len(currentRoomName) > 0 {
if roomMap, ok := sp.servedConns.Get(currentRoomName); ok {
if conn, ok := roomMap.Get(stream.Conn().RemotePeer()); ok {
if err := conn.pc.SetRemoteDescription(answerMsg.SDP); err != nil {
slog.Error("Failed to set remote description for answer", "err", err)
continue
}
slog.Debug("Set remote description for answer")
} else {
slog.Warn("Received answer without active PeerConnection")
}
}
slog.Debug("Set remote description for answer")
} else {
slog.Warn("Received answer without active PeerConnection")
}
@@ -452,7 +479,7 @@ func (sp *StreamProtocol) handleStreamPush(stream network.Stream) {
data, err := safeBRW.Receive()
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, network.ErrReset) {
slog.Debug("Stream push connection closed by peer", "peer", stream.Conn().RemotePeer())
slog.Debug("Stream push connection closed by peer", "peer", stream.Conn().RemotePeer(), "error", err)
return
}
@@ -568,6 +595,21 @@ func (sp *StreamProtocol) handleStreamPush(stream network.Stream) {
room.DataChannel.RegisterOnClose(func() {
slog.Debug("DataChannel closed for pushed stream", "room", room.Name)
})
room.DataChannel.RegisterMessageCallback("input", func(data []byte) {
if room.DataChannel != nil {
// Pass to servedConns DataChannels for this specific room
if roomMap, ok := sp.servedConns.Get(room.Name); ok {
roomMap.Range(func(peerID peer.ID, conn *StreamConnection) bool {
if conn.ndc != nil {
if err = conn.ndc.SendBinary(data); err != nil {
slog.Error("Failed to forward input message from pushed stream to viewer", "room", room.Name, "peer", peerID, "err", err)
}
}
return true // Continue iteration
})
}
}
})
// Set the DataChannel in the incomingConns map
if conn, ok := sp.incomingConns.Get(room.Name); ok {
@@ -687,7 +729,7 @@ func (sp *StreamProtocol) handleStreamPush(stream network.Stream) {
func (sp *StreamProtocol) RequestStream(ctx context.Context, room *shared.Room, peerID peer.ID) error {
stream, err := sp.relay.Host.NewStream(ctx, peerID, protocolStreamRequest)
if err != nil {
return fmt.Errorf("failed to create stream request: %w", err)
return fmt.Errorf("failed to create stream: %w", err)
}
return sp.requestStream(stream, room)

View File

@@ -57,15 +57,15 @@ func (r *Relay) DeleteRoomIfEmpty(room *shared.Room) {
// GetRemoteRoomByName returns room from mesh by name
func (r *Relay) GetRemoteRoomByName(roomName string) *shared.RoomInfo {
for _, room := range r.MeshRooms.Copy() {
for _, room := range r.Rooms.Copy() {
if room.Name == roomName && room.OwnerID != r.ID {
// Make sure connection is alive
if r.Host.Network().Connectedness(room.OwnerID) == network.Connected {
return &room
} else {
slog.Debug("Removing stale peer, owns a room without connection", "room", roomName, "peer", room.OwnerID)
r.onPeerDisconnected(room.OwnerID)
}
slog.Debug("Removing stale peer, owns a room without connection", "room", roomName, "peer", room.OwnerID)
r.onPeerDisconnected(room.OwnerID)
}
}
return nil

View File

@@ -72,8 +72,8 @@ func (r *Relay) handleRelayMetricsMessages(ctx context.Context, sub *pubsub.Subs
continue
}
var info RelayInfo
if err := json.Unmarshal(msg.Data, &info); err != nil {
var info PeerInfo
if err = json.Unmarshal(msg.Data, &info); err != nil {
slog.Error("Failed to unmarshal relay status", "from", msg.GetFrom(), "data_len", len(msg.Data), "err", err)
continue
}
@@ -89,7 +89,7 @@ func (r *Relay) handleRelayMetricsMessages(ctx context.Context, sub *pubsub.Subs
// --- State Check Functions ---
// hasConnectedPeer checks if peer is in map and has a valid connection
func (r *Relay) hasConnectedPeer(peerID peer.ID) bool {
if _, ok := r.LocalMeshPeers.Get(peerID); !ok {
if _, ok := r.Peers.Get(peerID); !ok {
return false
}
if r.Host.Network().Connectedness(peerID) != network.Connected {
@@ -102,14 +102,14 @@ func (r *Relay) hasConnectedPeer(peerID peer.ID) bool {
// --- State Change Functions ---
// onPeerStatus updates the status of a peer based on received metrics, adding local perspective
func (r *Relay) onPeerStatus(recvInfo RelayInfo) {
r.LocalMeshPeers.Set(recvInfo.ID, &recvInfo)
func (r *Relay) onPeerStatus(recvInfo PeerInfo) {
r.Peers.Set(recvInfo.ID, &recvInfo)
}
// onPeerConnected is called when a new peer connects to the relay
func (r *Relay) onPeerConnected(peerID peer.ID) {
// Add to local peer map
r.LocalMeshPeers.Set(peerID, &RelayInfo{
r.Peers.Set(peerID, &PeerInfo{
ID: peerID,
})
@@ -131,16 +131,12 @@ func (r *Relay) onPeerConnected(peerID peer.ID) {
func (r *Relay) onPeerDisconnected(peerID peer.ID) {
slog.Info("Mesh peer disconnected, deleting from local peer map", "peer", peerID)
// Remove peer from local mesh peers
if r.LocalMeshPeers.Has(peerID) {
r.LocalMeshPeers.Delete(peerID)
if r.Peers.Has(peerID) {
r.Peers.Delete(peerID)
}
// Remove any rooms associated with this peer
if r.MeshRooms.Has(peerID.String()) {
r.MeshRooms.Delete(peerID.String())
}
// Remove any latencies associated with this peer
if r.LocalMeshPeers.Has(peerID) {
r.LocalMeshPeers.Delete(peerID)
if r.Rooms.Has(peerID.String()) {
r.Rooms.Delete(peerID.String())
}
// TODO: If any rooms were routed through this peer, handle that case
@@ -155,7 +151,7 @@ func (r *Relay) updateMeshRoomStates(peerID peer.ID, states []shared.RoomInfo) {
}
// If previously did not exist, but does now, request a connection if participants exist for our room
existed := r.MeshRooms.Has(state.ID.String())
existed := r.Rooms.Has(state.ID.String())
if !existed {
// Request connection to this peer if we have participants in our local room
if room, ok := r.LocalRooms.Get(state.ID); ok {
@@ -168,6 +164,6 @@ func (r *Relay) updateMeshRoomStates(peerID peer.ID, states []shared.RoomInfo) {
}
}
r.MeshRooms.Set(state.ID.String(), state)
r.Rooms.Set(state.ID.String(), state)
}
}

View File

@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc-gen-go v1.36.10
// protoc (unknown)
// source: latency_tracker.proto

View File

@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc-gen-go v1.36.10
// protoc (unknown)
// source: messages.proto

View File

@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc-gen-go v1.36.10
// protoc (unknown)
// source: types.proto
@@ -416,6 +416,481 @@ func (x *ProtoKeyUp) GetKey() int32 {
return 0
}
// ControllerAttach message
type ProtoControllerAttach struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerAttach"
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` // One of the following enums: "ps", "xbox" or "switch"
Slot int32 `protobuf:"varint,3,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerAttach) Reset() {
*x = ProtoControllerAttach{}
mi := &file_types_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerAttach) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerAttach) ProtoMessage() {}
func (x *ProtoControllerAttach) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerAttach.ProtoReflect.Descriptor instead.
func (*ProtoControllerAttach) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{7}
}
func (x *ProtoControllerAttach) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerAttach) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *ProtoControllerAttach) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
// ControllerDetach message
type ProtoControllerDetach struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerDetach"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerDetach) Reset() {
*x = ProtoControllerDetach{}
mi := &file_types_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerDetach) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerDetach) ProtoMessage() {}
func (x *ProtoControllerDetach) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerDetach.ProtoReflect.Descriptor instead.
func (*ProtoControllerDetach) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{8}
}
func (x *ProtoControllerDetach) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerDetach) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
// ControllerButton message
type ProtoControllerButton struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerButtons"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
Button int32 `protobuf:"varint,3,opt,name=button,proto3" json:"button,omitempty"` // Button code (linux input event code)
Pressed bool `protobuf:"varint,4,opt,name=pressed,proto3" json:"pressed,omitempty"` // true if pressed, false if released
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerButton) Reset() {
*x = ProtoControllerButton{}
mi := &file_types_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerButton) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerButton) ProtoMessage() {}
func (x *ProtoControllerButton) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerButton.ProtoReflect.Descriptor instead.
func (*ProtoControllerButton) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{9}
}
func (x *ProtoControllerButton) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerButton) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
func (x *ProtoControllerButton) GetButton() int32 {
if x != nil {
return x.Button
}
return 0
}
func (x *ProtoControllerButton) GetPressed() bool {
if x != nil {
return x.Pressed
}
return false
}
// ControllerTriggers message
type ProtoControllerTrigger struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerTriggers"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
Trigger int32 `protobuf:"varint,3,opt,name=trigger,proto3" json:"trigger,omitempty"` // Trigger number (0 for left, 1 for right)
Value int32 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"` // trigger value (-32768 to 32767)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerTrigger) Reset() {
*x = ProtoControllerTrigger{}
mi := &file_types_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerTrigger) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerTrigger) ProtoMessage() {}
func (x *ProtoControllerTrigger) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerTrigger.ProtoReflect.Descriptor instead.
func (*ProtoControllerTrigger) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{10}
}
func (x *ProtoControllerTrigger) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerTrigger) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
func (x *ProtoControllerTrigger) GetTrigger() int32 {
if x != nil {
return x.Trigger
}
return 0
}
func (x *ProtoControllerTrigger) GetValue() int32 {
if x != nil {
return x.Value
}
return 0
}
// ControllerSticks message
type ProtoControllerStick struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerStick"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
Stick int32 `protobuf:"varint,3,opt,name=stick,proto3" json:"stick,omitempty"` // Stick number (0 for left, 1 for right)
X int32 `protobuf:"varint,4,opt,name=x,proto3" json:"x,omitempty"` // X axis value (-32768 to 32767)
Y int32 `protobuf:"varint,5,opt,name=y,proto3" json:"y,omitempty"` // Y axis value (-32768 to 32767)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerStick) Reset() {
*x = ProtoControllerStick{}
mi := &file_types_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerStick) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerStick) ProtoMessage() {}
func (x *ProtoControllerStick) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerStick.ProtoReflect.Descriptor instead.
func (*ProtoControllerStick) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{11}
}
func (x *ProtoControllerStick) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerStick) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
func (x *ProtoControllerStick) GetStick() int32 {
if x != nil {
return x.Stick
}
return 0
}
func (x *ProtoControllerStick) GetX() int32 {
if x != nil {
return x.X
}
return 0
}
func (x *ProtoControllerStick) GetY() int32 {
if x != nil {
return x.Y
}
return 0
}
// ControllerAxis message
type ProtoControllerAxis struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerAxis"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
Axis int32 `protobuf:"varint,3,opt,name=axis,proto3" json:"axis,omitempty"` // Axis number (0 for d-pad horizontal, 1 for d-pad vertical)
Value int32 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"` // axis value (-1 to 1)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerAxis) Reset() {
*x = ProtoControllerAxis{}
mi := &file_types_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerAxis) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerAxis) ProtoMessage() {}
func (x *ProtoControllerAxis) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerAxis.ProtoReflect.Descriptor instead.
func (*ProtoControllerAxis) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{12}
}
func (x *ProtoControllerAxis) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerAxis) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
func (x *ProtoControllerAxis) GetAxis() int32 {
if x != nil {
return x.Axis
}
return 0
}
func (x *ProtoControllerAxis) GetValue() int32 {
if x != nil {
return x.Value
}
return 0
}
// ControllerRumble message
type ProtoControllerRumble struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "ControllerRumble"
Slot int32 `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty"` // Slot number (0-3)
LowFrequency int32 `protobuf:"varint,3,opt,name=low_frequency,json=lowFrequency,proto3" json:"low_frequency,omitempty"` // Low frequency rumble (0-65535)
HighFrequency int32 `protobuf:"varint,4,opt,name=high_frequency,json=highFrequency,proto3" json:"high_frequency,omitempty"` // High frequency rumble (0-65535)
Duration int32 `protobuf:"varint,5,opt,name=duration,proto3" json:"duration,omitempty"` // Duration in milliseconds
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtoControllerRumble) Reset() {
*x = ProtoControllerRumble{}
mi := &file_types_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtoControllerRumble) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtoControllerRumble) ProtoMessage() {}
func (x *ProtoControllerRumble) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtoControllerRumble.ProtoReflect.Descriptor instead.
func (*ProtoControllerRumble) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{13}
}
func (x *ProtoControllerRumble) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *ProtoControllerRumble) GetSlot() int32 {
if x != nil {
return x.Slot
}
return 0
}
func (x *ProtoControllerRumble) GetLowFrequency() int32 {
if x != nil {
return x.LowFrequency
}
return 0
}
func (x *ProtoControllerRumble) GetHighFrequency() int32 {
if x != nil {
return x.HighFrequency
}
return 0
}
func (x *ProtoControllerRumble) GetDuration() int32 {
if x != nil {
return x.Duration
}
return 0
}
// Union of all Input types
type ProtoInput struct {
state protoimpl.MessageState `protogen:"open.v1"`
@@ -428,6 +903,13 @@ type ProtoInput struct {
// *ProtoInput_MouseKeyUp
// *ProtoInput_KeyDown
// *ProtoInput_KeyUp
// *ProtoInput_ControllerAttach
// *ProtoInput_ControllerDetach
// *ProtoInput_ControllerButton
// *ProtoInput_ControllerTrigger
// *ProtoInput_ControllerStick
// *ProtoInput_ControllerAxis
// *ProtoInput_ControllerRumble
InputType isProtoInput_InputType `protobuf_oneof:"input_type"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@@ -435,7 +917,7 @@ type ProtoInput struct {
func (x *ProtoInput) Reset() {
*x = ProtoInput{}
mi := &file_types_proto_msgTypes[7]
mi := &file_types_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -447,7 +929,7 @@ func (x *ProtoInput) String() string {
func (*ProtoInput) ProtoMessage() {}
func (x *ProtoInput) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[7]
mi := &file_types_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -460,7 +942,7 @@ func (x *ProtoInput) ProtoReflect() protoreflect.Message {
// Deprecated: Use ProtoInput.ProtoReflect.Descriptor instead.
func (*ProtoInput) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{7}
return file_types_proto_rawDescGZIP(), []int{14}
}
func (x *ProtoInput) GetInputType() isProtoInput_InputType {
@@ -533,6 +1015,69 @@ func (x *ProtoInput) GetKeyUp() *ProtoKeyUp {
return nil
}
func (x *ProtoInput) GetControllerAttach() *ProtoControllerAttach {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerAttach); ok {
return x.ControllerAttach
}
}
return nil
}
func (x *ProtoInput) GetControllerDetach() *ProtoControllerDetach {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerDetach); ok {
return x.ControllerDetach
}
}
return nil
}
func (x *ProtoInput) GetControllerButton() *ProtoControllerButton {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerButton); ok {
return x.ControllerButton
}
}
return nil
}
func (x *ProtoInput) GetControllerTrigger() *ProtoControllerTrigger {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerTrigger); ok {
return x.ControllerTrigger
}
}
return nil
}
func (x *ProtoInput) GetControllerStick() *ProtoControllerStick {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerStick); ok {
return x.ControllerStick
}
}
return nil
}
func (x *ProtoInput) GetControllerAxis() *ProtoControllerAxis {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerAxis); ok {
return x.ControllerAxis
}
}
return nil
}
func (x *ProtoInput) GetControllerRumble() *ProtoControllerRumble {
if x != nil {
if x, ok := x.InputType.(*ProtoInput_ControllerRumble); ok {
return x.ControllerRumble
}
}
return nil
}
type isProtoInput_InputType interface {
isProtoInput_InputType()
}
@@ -565,6 +1110,34 @@ type ProtoInput_KeyUp struct {
KeyUp *ProtoKeyUp `protobuf:"bytes,7,opt,name=key_up,json=keyUp,proto3,oneof"`
}
type ProtoInput_ControllerAttach struct {
ControllerAttach *ProtoControllerAttach `protobuf:"bytes,8,opt,name=controller_attach,json=controllerAttach,proto3,oneof"`
}
type ProtoInput_ControllerDetach struct {
ControllerDetach *ProtoControllerDetach `protobuf:"bytes,9,opt,name=controller_detach,json=controllerDetach,proto3,oneof"`
}
type ProtoInput_ControllerButton struct {
ControllerButton *ProtoControllerButton `protobuf:"bytes,10,opt,name=controller_button,json=controllerButton,proto3,oneof"`
}
type ProtoInput_ControllerTrigger struct {
ControllerTrigger *ProtoControllerTrigger `protobuf:"bytes,11,opt,name=controller_trigger,json=controllerTrigger,proto3,oneof"`
}
type ProtoInput_ControllerStick struct {
ControllerStick *ProtoControllerStick `protobuf:"bytes,12,opt,name=controller_stick,json=controllerStick,proto3,oneof"`
}
type ProtoInput_ControllerAxis struct {
ControllerAxis *ProtoControllerAxis `protobuf:"bytes,13,opt,name=controller_axis,json=controllerAxis,proto3,oneof"`
}
type ProtoInput_ControllerRumble struct {
ControllerRumble *ProtoControllerRumble `protobuf:"bytes,14,opt,name=controller_rumble,json=controllerRumble,proto3,oneof"`
}
func (*ProtoInput_MouseMove) isProtoInput_InputType() {}
func (*ProtoInput_MouseMoveAbs) isProtoInput_InputType() {}
@@ -579,6 +1152,20 @@ func (*ProtoInput_KeyDown) isProtoInput_InputType() {}
func (*ProtoInput_KeyUp) isProtoInput_InputType() {}
func (*ProtoInput_ControllerAttach) isProtoInput_InputType() {}
func (*ProtoInput_ControllerDetach) isProtoInput_InputType() {}
func (*ProtoInput_ControllerButton) isProtoInput_InputType() {}
func (*ProtoInput_ControllerTrigger) isProtoInput_InputType() {}
func (*ProtoInput_ControllerStick) isProtoInput_InputType() {}
func (*ProtoInput_ControllerAxis) isProtoInput_InputType() {}
func (*ProtoInput_ControllerRumble) isProtoInput_InputType() {}
var File_types_proto protoreflect.FileDescriptor
const file_types_proto_rawDesc = "" +
@@ -608,7 +1195,41 @@ const file_types_proto_rawDesc = "" +
"\n" +
"ProtoKeyUp\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x10\n" +
"\x03key\x18\x02 \x01(\x05R\x03key\"\xab\x03\n" +
"\x03key\x18\x02 \x01(\x05R\x03key\"O\n" +
"\x15ProtoControllerAttach\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x0e\n" +
"\x02id\x18\x02 \x01(\tR\x02id\x12\x12\n" +
"\x04slot\x18\x03 \x01(\x05R\x04slot\"?\n" +
"\x15ProtoControllerDetach\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\"q\n" +
"\x15ProtoControllerButton\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\x12\x16\n" +
"\x06button\x18\x03 \x01(\x05R\x06button\x12\x18\n" +
"\apressed\x18\x04 \x01(\bR\apressed\"p\n" +
"\x16ProtoControllerTrigger\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\x12\x18\n" +
"\atrigger\x18\x03 \x01(\x05R\atrigger\x12\x14\n" +
"\x05value\x18\x04 \x01(\x05R\x05value\"p\n" +
"\x14ProtoControllerStick\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\x12\x14\n" +
"\x05stick\x18\x03 \x01(\x05R\x05stick\x12\f\n" +
"\x01x\x18\x04 \x01(\x05R\x01x\x12\f\n" +
"\x01y\x18\x05 \x01(\x05R\x01y\"g\n" +
"\x13ProtoControllerAxis\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\x12\x12\n" +
"\x04axis\x18\x03 \x01(\x05R\x04axis\x12\x14\n" +
"\x05value\x18\x04 \x01(\x05R\x05value\"\xa7\x01\n" +
"\x15ProtoControllerRumble\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" +
"\x04slot\x18\x02 \x01(\x05R\x04slot\x12#\n" +
"\rlow_frequency\x18\x03 \x01(\x05R\flowFrequency\x12%\n" +
"\x0ehigh_frequency\x18\x04 \x01(\x05R\rhighFrequency\x12\x1a\n" +
"\bduration\x18\x05 \x01(\x05R\bduration\"\xc0\a\n" +
"\n" +
"ProtoInput\x126\n" +
"\n" +
@@ -620,7 +1241,15 @@ const file_types_proto_rawDesc = "" +
"\fmouse_key_up\x18\x05 \x01(\v2\x16.proto.ProtoMouseKeyUpH\x00R\n" +
"mouseKeyUp\x120\n" +
"\bkey_down\x18\x06 \x01(\v2\x13.proto.ProtoKeyDownH\x00R\akeyDown\x12*\n" +
"\x06key_up\x18\a \x01(\v2\x11.proto.ProtoKeyUpH\x00R\x05keyUpB\f\n" +
"\x06key_up\x18\a \x01(\v2\x11.proto.ProtoKeyUpH\x00R\x05keyUp\x12K\n" +
"\x11controller_attach\x18\b \x01(\v2\x1c.proto.ProtoControllerAttachH\x00R\x10controllerAttach\x12K\n" +
"\x11controller_detach\x18\t \x01(\v2\x1c.proto.ProtoControllerDetachH\x00R\x10controllerDetach\x12K\n" +
"\x11controller_button\x18\n" +
" \x01(\v2\x1c.proto.ProtoControllerButtonH\x00R\x10controllerButton\x12N\n" +
"\x12controller_trigger\x18\v \x01(\v2\x1d.proto.ProtoControllerTriggerH\x00R\x11controllerTrigger\x12H\n" +
"\x10controller_stick\x18\f \x01(\v2\x1b.proto.ProtoControllerStickH\x00R\x0fcontrollerStick\x12E\n" +
"\x0fcontroller_axis\x18\r \x01(\v2\x1a.proto.ProtoControllerAxisH\x00R\x0econtrollerAxis\x12K\n" +
"\x11controller_rumble\x18\x0e \x01(\v2\x1c.proto.ProtoControllerRumbleH\x00R\x10controllerRumbleB\f\n" +
"\n" +
"input_typeB\x16Z\x14relay/internal/protob\x06proto3"
@@ -636,30 +1265,44 @@ func file_types_proto_rawDescGZIP() []byte {
return file_types_proto_rawDescData
}
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_types_proto_goTypes = []any{
(*ProtoMouseMove)(nil), // 0: proto.ProtoMouseMove
(*ProtoMouseMoveAbs)(nil), // 1: proto.ProtoMouseMoveAbs
(*ProtoMouseWheel)(nil), // 2: proto.ProtoMouseWheel
(*ProtoMouseKeyDown)(nil), // 3: proto.ProtoMouseKeyDown
(*ProtoMouseKeyUp)(nil), // 4: proto.ProtoMouseKeyUp
(*ProtoKeyDown)(nil), // 5: proto.ProtoKeyDown
(*ProtoKeyUp)(nil), // 6: proto.ProtoKeyUp
(*ProtoInput)(nil), // 7: proto.ProtoInput
(*ProtoMouseMove)(nil), // 0: proto.ProtoMouseMove
(*ProtoMouseMoveAbs)(nil), // 1: proto.ProtoMouseMoveAbs
(*ProtoMouseWheel)(nil), // 2: proto.ProtoMouseWheel
(*ProtoMouseKeyDown)(nil), // 3: proto.ProtoMouseKeyDown
(*ProtoMouseKeyUp)(nil), // 4: proto.ProtoMouseKeyUp
(*ProtoKeyDown)(nil), // 5: proto.ProtoKeyDown
(*ProtoKeyUp)(nil), // 6: proto.ProtoKeyUp
(*ProtoControllerAttach)(nil), // 7: proto.ProtoControllerAttach
(*ProtoControllerDetach)(nil), // 8: proto.ProtoControllerDetach
(*ProtoControllerButton)(nil), // 9: proto.ProtoControllerButton
(*ProtoControllerTrigger)(nil), // 10: proto.ProtoControllerTrigger
(*ProtoControllerStick)(nil), // 11: proto.ProtoControllerStick
(*ProtoControllerAxis)(nil), // 12: proto.ProtoControllerAxis
(*ProtoControllerRumble)(nil), // 13: proto.ProtoControllerRumble
(*ProtoInput)(nil), // 14: proto.ProtoInput
}
var file_types_proto_depIdxs = []int32{
0, // 0: proto.ProtoInput.mouse_move:type_name -> proto.ProtoMouseMove
1, // 1: proto.ProtoInput.mouse_move_abs:type_name -> proto.ProtoMouseMoveAbs
2, // 2: proto.ProtoInput.mouse_wheel:type_name -> proto.ProtoMouseWheel
3, // 3: proto.ProtoInput.mouse_key_down:type_name -> proto.ProtoMouseKeyDown
4, // 4: proto.ProtoInput.mouse_key_up:type_name -> proto.ProtoMouseKeyUp
5, // 5: proto.ProtoInput.key_down:type_name -> proto.ProtoKeyDown
6, // 6: proto.ProtoInput.key_up:type_name -> proto.ProtoKeyUp
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
0, // 0: proto.ProtoInput.mouse_move:type_name -> proto.ProtoMouseMove
1, // 1: proto.ProtoInput.mouse_move_abs:type_name -> proto.ProtoMouseMoveAbs
2, // 2: proto.ProtoInput.mouse_wheel:type_name -> proto.ProtoMouseWheel
3, // 3: proto.ProtoInput.mouse_key_down:type_name -> proto.ProtoMouseKeyDown
4, // 4: proto.ProtoInput.mouse_key_up:type_name -> proto.ProtoMouseKeyUp
5, // 5: proto.ProtoInput.key_down:type_name -> proto.ProtoKeyDown
6, // 6: proto.ProtoInput.key_up:type_name -> proto.ProtoKeyUp
7, // 7: proto.ProtoInput.controller_attach:type_name -> proto.ProtoControllerAttach
8, // 8: proto.ProtoInput.controller_detach:type_name -> proto.ProtoControllerDetach
9, // 9: proto.ProtoInput.controller_button:type_name -> proto.ProtoControllerButton
10, // 10: proto.ProtoInput.controller_trigger:type_name -> proto.ProtoControllerTrigger
11, // 11: proto.ProtoInput.controller_stick:type_name -> proto.ProtoControllerStick
12, // 12: proto.ProtoInput.controller_axis:type_name -> proto.ProtoControllerAxis
13, // 13: proto.ProtoInput.controller_rumble:type_name -> proto.ProtoControllerRumble
14, // [14:14] is the sub-list for method output_type
14, // [14:14] is the sub-list for method input_type
14, // [14:14] is the sub-list for extension type_name
14, // [14:14] is the sub-list for extension extendee
0, // [0:14] is the sub-list for field type_name
}
func init() { file_types_proto_init() }
@@ -667,7 +1310,7 @@ func file_types_proto_init() {
if File_types_proto != nil {
return
}
file_types_proto_msgTypes[7].OneofWrappers = []any{
file_types_proto_msgTypes[14].OneofWrappers = []any{
(*ProtoInput_MouseMove)(nil),
(*ProtoInput_MouseMoveAbs)(nil),
(*ProtoInput_MouseWheel)(nil),
@@ -675,6 +1318,13 @@ func file_types_proto_init() {
(*ProtoInput_MouseKeyUp)(nil),
(*ProtoInput_KeyDown)(nil),
(*ProtoInput_KeyUp)(nil),
(*ProtoInput_ControllerAttach)(nil),
(*ProtoInput_ControllerDetach)(nil),
(*ProtoInput_ControllerButton)(nil),
(*ProtoInput_ControllerTrigger)(nil),
(*ProtoInput_ControllerStick)(nil),
(*ProtoInput_ControllerAxis)(nil),
(*ProtoInput_ControllerRumble)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -682,7 +1332,7 @@ func file_types_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
NumEnums: 0,
NumMessages: 8,
NumMessages: 15,
NumExtensions: 0,
NumServices: 0,
},

View File

@@ -49,25 +49,12 @@ func (r *Room) removeParticipantByID(pID ulid.ULID) {
}
}
// Removes all participants from a Room
/*func (r *Room) removeAllParticipants() {
for id, participant := range r.Participants.Copy() {
if err := r.signalParticipantOffline(participant); err != nil {
slog.Error("Failed to signal participant offline", "participant", participant.ID, "room", r.Name, "err", err)
}
r.Participants.Delete(id)
slog.Debug("Removed participant from room", "participant", id, "room", r.Name)
}
}*/
// IsOnline checks if the room is online (has both audio and video tracks)
func (r *Room) IsOnline() bool {
return r.AudioTrack != nil && r.VideoTrack != nil
}
func (r *Room) SetTrack(trackType webrtc.RTPCodecType, track *webrtc.TrackLocalStaticRTP) {
//oldOnline := r.IsOnline()
switch trackType {
case webrtc.RTPCodecTypeAudio:
r.AudioTrack = track
@@ -76,69 +63,4 @@ func (r *Room) SetTrack(trackType webrtc.RTPCodecType, track *webrtc.TrackLocalS
default:
slog.Warn("Unknown track type", "room", r.Name, "trackType", trackType)
}
/*newOnline := r.IsOnline()
if oldOnline != newOnline {
if newOnline {
slog.Debug("Room online, participants will be signaled", "room", r.Name)
r.signalParticipantsWithTracks()
} else {
slog.Debug("Room offline, signaling participants", "room", r.Name)
r.signalParticipantsOffline()
}
// TODO: Publish updated state to mesh
go func() {
if err := r.Relay.publishRoomStates(context.Background()); err != nil {
slog.Error("Failed to publish room states on change", "room", r.Name, "err", err)
}
}()
}*/
}
/* TODO: libp2p'ify
func (r *Room) signalParticipantsWithTracks() {
for _, participant := range r.Participants.Copy() {
if err := r.signalParticipantWithTracks(participant); err != nil {
slog.Error("Failed to signal participant with tracks", "participant", participant.ID, "room", r.Name, "err", err)
}
}
}
func (r *Room) signalParticipantWithTracks(participant *Participant) error {
if r.AudioTrack != nil {
if err := participant.addTrack(r.AudioTrack); err != nil {
return fmt.Errorf("failed to add audio track: %w", err)
}
}
if r.VideoTrack != nil {
if err := participant.addTrack(r.VideoTrack); err != nil {
return fmt.Errorf("failed to add video track: %w", err)
}
}
if err := participant.signalOffer(); err != nil {
return fmt.Errorf("failed to signal offer: %w", err)
}
return nil
}
func (r *Room) signalParticipantsOffline() {
for _, participant := range r.Participants.Copy() {
if err := r.signalParticipantOffline(participant); err != nil {
slog.Error("Failed to signal participant offline", "participant", participant.ID, "room", r.Name, "err", err)
}
}
}
// signalParticipantOffline signals a single participant offline
func (r *Room) signalParticipantOffline(participant *Participant) error {
// Skip if websocket is nil or closed
if participant.WebSocket == nil || participant.WebSocket.IsClosed() {
return nil
}
if err := participant.WebSocket.SendAnswerMessageWS(connections.AnswerOffline); err != nil {
return err
}
return nil
}
*/

View File

@@ -32,7 +32,7 @@ func main() {
slog.SetDefault(logger)
// Start relay
err := core.InitRelay(mainCtx, mainStopper)
relay, err := core.InitRelay(mainCtx, mainStopper)
if err != nil {
slog.Error("Failed to initialize relay", "err", err)
mainStopper()
@@ -41,5 +41,10 @@ func main() {
// Wait for exit signal
<-mainCtx.Done()
slog.Info("Shutting down gracefully by signal...")
slog.Info("Shutting down gracefully by signal..")
defaultFile := common.GetFlags().PersistDir + "/peerstore.json"
if err = relay.SaveToFile(defaultFile); err != nil {
slog.Error("Failed to save peer store", "err", err)
}
}