diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..cc36cf7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: gomod + directory: / + schedule: + interval: monthly + open-pull-requests-limit: 10 + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + open-pull-requests-limit: 10 + - package-ecosystem: npm + directory: /ui + open-pull-requests-limit: 10 + schedule: + interval: monthly diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bf4b13..c7cbb22 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,9 +23,9 @@ jobs: cache: "npm" cache-dependency-path: "**/package-lock.json" - name: Set up Golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: "1.24.3" + go-version: "1.24.4" - name: Build frontend run: | make frontend diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 0a74064..3ce3ef3 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -24,9 +24,9 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@19bb51245e9c80abacb2e91cc42b33fa478b8639 # v4.2.1 with: - go-version: 1.24.3 + go-version: 1.24.4 - name: Create empty resource directory run: | mkdir -p static && touch static/.gitkeep diff --git a/.github/workflows/smoketest.yml b/.github/workflows/smoketest.yml index 46f0198..ebce418 100644 --- a/.github/workflows/smoketest.yml +++ b/.github/workflows/smoketest.yml @@ -104,9 +104,9 @@ jobs: EOF ssh jkci "cat /tmp/device-tests.json" > device-tests.json - name: Set up Golang - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: "1.24.3" + go-version: "1.24.4" - name: Golang Test Report uses: becheran/go-testreport@v0.3.2 with: diff --git a/Makefile b/Makefile index 8262698..2f3c74a 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,14 @@ BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) BUILDDATE ?= $(shell date -u +%FT%T%z) BUILDTS ?= $(shell date -u +%s) REVISION ?= $(shell git rev-parse HEAD) -VERSION_DEV := 0.4.2-dev$(shell date +%Y%m%d%H%M) -VERSION := 0.4.1 +VERSION_DEV ?= 0.4.5-dev$(shell date +%Y%m%d%H%M) +VERSION ?= 0.4.4 PROMETHEUS_TAG := github.com/prometheus/common/version KVM_PKG_NAME := github.com/jetkvm/kvm +GO_BUILD_ARGS := -tags netgo +GO_RELEASE_BUILD_ARGS := -trimpath $(GO_BUILD_ARGS) GO_LDFLAGS := \ -s -w \ -X $(PROMETHEUS_TAG).Branch=$(BRANCH) \ @@ -27,7 +29,7 @@ build_dev: hash_resource @echo "Building..." $(GO_CMD) build \ -ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION_DEV)" \ - -trimpath \ + $(GO_RELEASE_BUILD_ARGS) \ -o $(BIN_DIR)/jetkvm_app cmd/main.go build_test2json: @@ -50,6 +52,7 @@ build_dev_test: build_test2json build_gotestsum test_filename=$$(echo $$test_pkg_name | sed 's/\//__/g')_test; \ $(GO_CMD) test -v \ -ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION_DEV)" \ + $(GO_BUILD_ARGS) \ -c -o $(BIN_DIR)/tests/$$test_filename $$test; \ echo "runTest ./$$test_filename $$test_pkg_full_name" >> $(BIN_DIR)/tests/run_all_tests; \ done; \ @@ -71,7 +74,7 @@ build_release: frontend hash_resource @echo "Building release..." $(GO_CMD) build \ -ldflags="$(GO_LDFLAGS) -X $(KVM_PKG_NAME).builtAppVersion=$(VERSION)" \ - -trimpath \ + $(GO_RELEASE_BUILD_ARGS) \ -o bin/jetkvm_app cmd/main.go release: diff --git a/cloud.go b/cloud.go index fb1998a..cec749e 100644 --- a/cloud.go +++ b/cloud.go @@ -51,34 +51,34 @@ var ( ) metricCloudConnectionEstablishedTimestamp = promauto.NewGauge( prometheus.GaugeOpts{ - Name: "jetkvm_cloud_connection_established_timestamp", + Name: "jetkvm_cloud_connection_established_timestamp_seconds", Help: "The timestamp when the cloud connection was established", }, ) metricConnectionLastPingTimestamp = promauto.NewGaugeVec( prometheus.GaugeOpts{ - Name: "jetkvm_connection_last_ping_timestamp", + Name: "jetkvm_connection_last_ping_timestamp_seconds", Help: "The timestamp when the last ping response was received", }, []string{"type", "source"}, ) metricConnectionLastPingReceivedTimestamp = promauto.NewGaugeVec( prometheus.GaugeOpts{ - Name: "jetkvm_connection_last_ping_received_timestamp", + Name: "jetkvm_connection_last_ping_received_timestamp_seconds", Help: "The timestamp when the last ping request was received", }, []string{"type", "source"}, ) metricConnectionLastPingDuration = promauto.NewGaugeVec( prometheus.GaugeOpts{ - Name: "jetkvm_connection_last_ping_duration", + Name: "jetkvm_connection_last_ping_duration_seconds", Help: "The duration of the last ping response", }, []string{"type", "source"}, ) metricConnectionPingDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ - Name: "jetkvm_connection_ping_duration", + Name: "jetkvm_connection_ping_duration_seconds", Help: "The duration of the ping response", Buckets: []float64{ 0.1, 0.5, 1, 10, @@ -88,28 +88,28 @@ var ( ) metricConnectionTotalPingSentCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_connection_total_ping_sent", + Name: "jetkvm_connection_ping_sent_total", Help: "The total number of pings sent to the connection", }, []string{"type", "source"}, ) metricConnectionTotalPingReceivedCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_connection_total_ping_received", + Name: "jetkvm_connection_ping_received_total", Help: "The total number of pings received from the connection", }, []string{"type", "source"}, ) metricConnectionSessionRequestCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_connection_session_total_requests", + Name: "jetkvm_connection_session_requests_total", Help: "The total number of session requests received", }, []string{"type", "source"}, ) metricConnectionSessionRequestDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ - Name: "jetkvm_connection_session_request_duration", + Name: "jetkvm_connection_session_request_duration_seconds", Help: "The duration of session requests", Buckets: []float64{ 0.1, 0.5, 1, 10, @@ -119,7 +119,7 @@ var ( ) metricConnectionLastSessionRequestTimestamp = promauto.NewGaugeVec( prometheus.GaugeOpts{ - Name: "jetkvm_connection_last_session_request_timestamp", + Name: "jetkvm_connection_last_session_request_timestamp_seconds", Help: "The timestamp of the last session request", }, []string{"type", "source"}, @@ -133,7 +133,7 @@ var ( ) metricCloudConnectionFailureCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_cloud_connection_failure_count", + Name: "jetkvm_cloud_connection_failure_total", Help: "The number of times the cloud connection has failed", }, ) diff --git a/config.go b/config.go index 04f2a4e..3e88457 100644 --- a/config.go +++ b/config.go @@ -111,7 +111,7 @@ var defaultConfig = &Config{ ActiveExtension: "", KeyboardMacros: []KeyboardMacro{}, DisplayRotation: "270", - KeyboardLayout: "en-US", + KeyboardLayout: "en_US", DisplayMaxBrightness: 64, DisplayDimAfterSec: 120, // 2 minutes DisplayOffAfterSec: 1800, // 30 minutes diff --git a/dev_deploy.sh b/dev_deploy.sh index a2d32ed..059e416 100755 --- a/dev_deploy.sh +++ b/dev_deploy.sh @@ -174,7 +174,7 @@ cd "${REMOTE_PATH}" chmod +x jetkvm_app_debug # Run the application in the background -PION_LOG_TRACE=${LOG_TRACE_SCOPES} ./jetkvm_app_debug +PION_LOG_TRACE=${LOG_TRACE_SCOPES} GODEBUG=netdns=1 ./jetkvm_app_debug EOF echo "Deployment complete." \ No newline at end of file diff --git a/display.go b/display.go index 2a22351..cf1a0cc 100644 --- a/display.go +++ b/display.go @@ -339,10 +339,18 @@ func startBacklightTickers() { return } - if dimTicker == nil && config.DisplayDimAfterSec != 0 { + // Stop existing tickers to prevent multiple active instances on repeated calls + if dimTicker != nil { + dimTicker.Stop() + } + + if offTicker != nil { + offTicker.Stop() + } + + if config.DisplayDimAfterSec != 0 { displayLogger.Info().Msg("dim_ticker has started") dimTicker = time.NewTicker(time.Duration(config.DisplayDimAfterSec) * time.Second) - defer dimTicker.Stop() go func() { for { //nolint:staticcheck @@ -354,10 +362,9 @@ func startBacklightTickers() { }() } - if offTicker == nil && config.DisplayOffAfterSec != 0 { + if config.DisplayOffAfterSec != 0 { displayLogger.Info().Msg("off_ticker has started") offTicker = time.NewTicker(time.Duration(config.DisplayOffAfterSec) * time.Second) - defer offTicker.Stop() go func() { for { //nolint:staticcheck diff --git a/go.mod b/go.mod index 4abd752..3e38ac1 100644 --- a/go.mod +++ b/go.mod @@ -5,33 +5,33 @@ go 1.23.4 toolchain go1.24.3 require ( - github.com/Masterminds/semver/v3 v3.3.0 - github.com/beevik/ntp v1.3.1 + github.com/Masterminds/semver/v3 v3.3.1 + github.com/beevik/ntp v1.4.3 github.com/coder/websocket v1.8.13 github.com/coreos/go-oidc/v3 v3.11.0 github.com/creack/pty v1.1.23 github.com/fsnotify/fsnotify v1.9.0 - github.com/gin-contrib/logger v1.2.5 - github.com/gin-gonic/gin v1.10.0 + github.com/gin-contrib/logger v1.2.6 + github.com/gin-gonic/gin v1.10.1 github.com/google/uuid v1.6.0 github.com/guregu/null/v6 v6.0.0 github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf - github.com/hanwen/go-fuse/v2 v2.5.1 - github.com/pion/logging v0.2.2 + github.com/hanwen/go-fuse/v2 v2.8.0 + github.com/pion/logging v0.2.3 github.com/pion/mdns/v2 v2.0.7 - github.com/pion/webrtc/v4 v4.0.0 + github.com/pion/webrtc/v4 v4.0.16 github.com/pojntfx/go-nbd v0.3.2 - github.com/prometheus/client_golang v1.21.0 + github.com/prometheus/client_golang v1.22.0 github.com/prometheus/common v0.62.0 - github.com/prometheus/procfs v0.15.1 + github.com/prometheus/procfs v0.16.1 github.com/psanford/httpreadat v0.1.0 github.com/rs/zerolog v1.34.0 github.com/sourcegraph/tf-dag v0.2.2-0.20250131204052-3e8ff1477b4f github.com/stretchr/testify v1.10.0 github.com/vishvananda/netlink v1.3.0 go.bug.st/serial v1.6.2 - golang.org/x/crypto v0.38.0 - golang.org/x/net v0.40.0 + golang.org/x/crypto v0.39.0 + golang.org/x/net v0.41.0 golang.org/x/sys v0.33.0 ) @@ -45,16 +45,14 @@ require ( github.com/cloudwego/base64x v0.1.5 // indirect github.com/creack/goselect v0.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect - github.com/gin-contrib/sse v1.0.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/google/go-cmp v0.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -62,21 +60,21 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pilebones/go-udev v0.9.0 // indirect - github.com/pion/datachannel v1.5.9 // indirect - github.com/pion/dtls/v3 v3.0.3 // indirect - github.com/pion/ice/v4 v4.0.2 // indirect - github.com/pion/interceptor v0.1.37 // indirect + github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/ice/v4 v4.0.10 // indirect + github.com/pion/interceptor v0.1.40 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.9 // indirect - github.com/pion/sctp v1.8.33 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v3 v3.0.4 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.18 // 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.5 // indirect github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v3 v3.0.7 // indirect - github.com/pion/turn/v4 v4.0.0 // indirect + github.com/pion/turn/v4 v4.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect @@ -84,9 +82,9 @@ require ( github.com/ugorji/go/codec v1.2.12 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/wlynxg/anet v0.0.5 // indirect - golang.org/x/arch v0.15.0 // indirect + golang.org/x/arch v0.17.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 63ebc96..6e7e5d5 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/beevik/ntp v1.3.1 h1:Y/srlT8L1yQr58kyPWFPZIxRL8ttx2SRIpVYJqZIlAM= -github.com/beevik/ntp v1.3.1/go.mod h1:fT6PylBq86Tsq23ZMEe47b7QQrZfYBFPnpzt0a9kJxw= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho= +github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= @@ -30,16 +30,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/gin-contrib/logger v1.2.5 h1:qVQI4omayQecuN4zX9ZZnsOq7w9J/ZLds3J/FMn8ypM= -github.com/gin-contrib/logger v1.2.5/go.mod h1:/bj+vNMuA2xOEQ1aRHoJ1m9+uyaaXIAxQTvM2llsc6I= -github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= -github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= -github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/gin-contrib/logger v1.2.6 h1:EPolruKUTzNXMVBD9LuAFQmRjTs7AH7yKGuXgYqrKWc= +github.com/gin-contrib/logger v1.2.6/go.mod h1:7niPrd7F0Nscw/zvgz8RiGJxSdbKM2yfQNy8xCHcm64= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -60,12 +60,12 @@ github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ= github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ= github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf h1:JO6ISZIvEUitto5zjQ3/VEnDM5rPbqIFuOhS0U0ByeA= github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf/go.mod h1:5Kt9XkWvkGi2OHOq0QsGxebHmhCcqJ8KCbNg/a6+n+g= -github.com/hanwen/go-fuse/v2 v2.5.1 h1:OQBE8zVemSocRxA4OaFJbjJ5hlpCmIWbGr7r0M4uoQQ= -github.com/hanwen/go-fuse/v2 v2.5.1/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= +github.com/hanwen/go-fuse/v2 v2.8.0 h1:wV8rG7rmCz8XHSOwBZhG5YcVqcYjkzivjmbaMafPlAs= +github.com/hanwen/go-fuse/v2 v2.8.0/go.mod h1:yE6D2PqWwm3CbYRxFXV9xUd8Md5d6NG0WBs5spCswmI= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +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.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= @@ -77,7 +77,6 @@ github.com/kr/pty v1.1.1/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 v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= 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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -89,8 +88,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -98,53 +97,53 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pilebones/go-udev v0.9.0 h1:N1uEO/SxUwtIctc0WLU0t69JeBxIYEYnj8lT/Nabl9Q= github.com/pilebones/go-udev v0.9.0/go.mod h1:T2eI2tUSK0hA2WS5QLjXJUfQkluZQu+18Cqvem3CaXI= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= -github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM= -github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU= -github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s= -github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg= -github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= -github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +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/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.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= +github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +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/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.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= -github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.18 h1:yEAb4+4a8nkPCecWzQB6V/uEU18X1lQCGAQCjP+pyvU= +github.com/pion/rtp v1.8.18/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.5 h1:8XLB6Dt3QXkMkRFpoqC3314BemkpMQK2mZeJc4pUKqo= +github.com/pion/srtp/v3 v3.0.5/go.mod h1:r1G7y5r1scZRLe2QJI/is+/O83W2d+JoEsuIexpw+uM= github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= 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.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= -github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= -github.com/pion/webrtc/v4 v4.0.0 h1:x8ec7uJQPP3D1iI8ojPAiTOylPI7Fa7QgqZrhpLyqZ8= -github.com/pion/webrtc/v4 v4.0.0/go.mod h1:SfNn8CcFxR6OUVjLXVslAQ3a3994JhyE3Hw1jAuqEto= +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.0.16 h1:5f8QMVIbNvJr2mPRGi2QamkPa/LVUB6NWolOCwphKHA= +github.com/pion/webrtc/v4 v4.0.16/go.mod h1:C3uTCPzVafUA0eUzru9f47OgNt3nEO7ZJ6zNY6VSJno= 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/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= -github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +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_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE= github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -157,14 +156,11 @@ github.com/sourcegraph/tf-dag v0.2.2-0.20250131204052-3e8ff1477b4f/go.mod h1:pzr github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -179,16 +175,14 @@ github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8= go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE= -golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= -golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= -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/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= +golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -196,8 +190,8 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -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.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/timesync/http.go b/internal/timesync/http.go index 3a51463..ff0668a 100644 --- a/internal/timesync/http.go +++ b/internal/timesync/http.go @@ -95,16 +95,27 @@ func (t *TimeSync) queryMultipleHttp(urls []string, timeout time.Duration) (now } else if errors.Is(err, context.Canceled) { metricHttpCancelCount.WithLabelValues(url).Inc() metricHttpTotalCancelCount.Inc() + results <- nil } else { scopedLogger.Warn(). Str("error", err.Error()). Int("status", status). Msg("failed to query HTTP server") + results <- nil } }(url) } - return <-results + for range urls { + result := <-results + if result == nil { + continue + } + now = result + return + } + + return } func queryHttpTime( diff --git a/internal/timesync/metrics.go b/internal/timesync/metrics.go index 0e28acb..5aa2e92 100644 --- a/internal/timesync/metrics.go +++ b/internal/timesync/metrics.go @@ -14,44 +14,44 @@ var ( ) metricTimeSyncCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_count", + Name: "jetkvm_timesync_total", Help: "The number of times the timesync has been run", }, ) metricTimeSyncSuccessCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_success_count", + Name: "jetkvm_timesync_success_total", Help: "The number of times the timesync has been successful", }, ) metricRTCUpdateCount = promauto.NewCounter( //nolint:unused prometheus.CounterOpts{ - Name: "jetkvm_timesync_rtc_update_count", + Name: "jetkvm_timesync_rtc_update_total", Help: "The number of times the RTC has been updated", }, ) metricNtpTotalSuccessCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_ntp_total_success_count", + Name: "jetkvm_timesync_ntp_total_success_total", Help: "The total number of successful NTP requests", }, ) metricNtpTotalRequestCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_ntp_total_request_count", + Name: "jetkvm_timesync_ntp_total_request_total", Help: "The total number of NTP requests sent", }, ) metricNtpSuccessCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_timesync_ntp_success_count", + Name: "jetkvm_timesync_ntp_success_total", Help: "The number of successful NTP requests", }, []string{"url"}, ) metricNtpRequestCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_timesync_ntp_request_count", + Name: "jetkvm_timesync_ntp_request_total", Help: "The number of NTP requests sent to the server", }, []string{"url"}, @@ -83,39 +83,39 @@ var ( metricHttpTotalSuccessCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_total_success_count", + Name: "jetkvm_timesync_http_total_success_total", Help: "The total number of successful HTTP requests", }, ) metricHttpTotalRequestCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_total_request_count", + Name: "jetkvm_timesync_http_total_request_total", Help: "The total number of HTTP requests sent", }, ) metricHttpTotalCancelCount = promauto.NewCounter( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_total_cancel_count", + Name: "jetkvm_timesync_http_total_cancel_total", Help: "The total number of HTTP requests cancelled", }, ) metricHttpSuccessCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_success_count", + Name: "jetkvm_timesync_http_success_total", Help: "The number of successful HTTP requests", }, []string{"url"}, ) metricHttpRequestCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_request_count", + Name: "jetkvm_timesync_http_request_total", Help: "The number of HTTP requests sent to the server", }, []string{"url"}, ) metricHttpCancelCount = promauto.NewCounterVec( prometheus.CounterOpts{ - Name: "jetkvm_timesync_http_cancel_count", + Name: "jetkvm_timesync_http_cancel_total", Help: "The number of HTTP requests cancelled", }, []string{"url"}, diff --git a/internal/udhcpc/udhcpc.go b/internal/udhcpc/udhcpc.go index 70ac1b8..128ea66 100644 --- a/internal/udhcpc/udhcpc.go +++ b/internal/udhcpc/udhcpc.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "reflect" "time" "github.com/fsnotify/fsnotify" @@ -149,6 +150,12 @@ func (c *DHCPClient) loadLeaseFile() error { } isFirstLoad := c.lease == nil + + // Skip processing if lease hasn't changed to avoid unnecessary wake-ups. + if reflect.DeepEqual(c.lease, lease) { + return nil + } + c.lease = lease if lease.IPAddress == nil { diff --git a/internal/usbgadget/hid_keyboard.go b/internal/usbgadget/hid_keyboard.go index 12b0de9..4585784 100644 --- a/internal/usbgadget/hid_keyboard.go +++ b/internal/usbgadget/hid_keyboard.go @@ -143,15 +143,21 @@ func (u *UsbGadget) listenKeyboardEvents() { default: l.Trace().Msg("reading from keyboard") if u.keyboardHidFile == nil { - l.Error().Msg("keyboardHidFile is nil") + u.logWithSupression("keyboardHidFileNil", 100, &l, nil, "keyboardHidFile is nil") + // show the error every 100 times to avoid spamming the logs time.Sleep(time.Second) continue } + // reset the counter + u.resetLogSuppressionCounter("keyboardHidFileNil") + n, err := u.keyboardHidFile.Read(buf) if err != nil { - l.Error().Err(err).Msg("failed to read") + u.logWithSupression("keyboardHidFileRead", 100, &l, err, "failed to read") continue } + u.resetLogSuppressionCounter("keyboardHidFileRead") + l.Trace().Int("n", n).Bytes("buf", buf).Msg("got data from keyboard") if n != 1 { l.Trace().Int("n", n).Msg("expected 1 byte, got") @@ -195,12 +201,12 @@ func (u *UsbGadget) keyboardWriteHidFile(data []byte) error { _, err := u.keyboardHidFile.Write(data) if err != nil { - u.log.Error().Err(err).Msg("failed to write to hidg0") + u.logWithSupression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0") u.keyboardHidFile.Close() u.keyboardHidFile = nil return err } - + u.resetLogSuppressionCounter("keyboardWriteHidFile") return nil } diff --git a/internal/usbgadget/hid_mouse_absolute.go b/internal/usbgadget/hid_mouse_absolute.go index b1c7428..d05a763 100644 --- a/internal/usbgadget/hid_mouse_absolute.go +++ b/internal/usbgadget/hid_mouse_absolute.go @@ -12,7 +12,7 @@ var absoluteMouseConfig = gadgetConfigItem{ configPath: []string{"hid.usb1"}, attrs: gadgetAttributes{ "protocol": "2", - "subclass": "1", + "subclass": "0", "report_length": "6", }, reportDesc: absoluteMouseCombinedReportDesc, @@ -75,11 +75,12 @@ func (u *UsbGadget) absMouseWriteHidFile(data []byte) error { _, err := u.absMouseHidFile.Write(data) if err != nil { - u.log.Error().Err(err).Msg("failed to write to hidg1") + u.logWithSupression("absMouseWriteHidFile", 100, u.log, err, "failed to write to hidg1") u.absMouseHidFile.Close() u.absMouseHidFile = nil return err } + u.resetLogSuppressionCounter("absMouseWriteHidFile") return nil } diff --git a/internal/usbgadget/hid_mouse_relative.go b/internal/usbgadget/hid_mouse_relative.go index af2d028..42e9ab1 100644 --- a/internal/usbgadget/hid_mouse_relative.go +++ b/internal/usbgadget/hid_mouse_relative.go @@ -65,11 +65,12 @@ func (u *UsbGadget) relMouseWriteHidFile(data []byte) error { _, err := u.relMouseHidFile.Write(data) if err != nil { - u.log.Error().Err(err).Msg("failed to write to hidg2") + u.logWithSupression("relMouseWriteHidFile", 100, u.log, err, "failed to write to hidg2") u.relMouseHidFile.Close() u.relMouseHidFile = nil return err } + u.resetLogSuppressionCounter("relMouseWriteHidFile") return nil } diff --git a/internal/usbgadget/usbgadget.go b/internal/usbgadget/usbgadget.go index 2eab822..fb28297 100644 --- a/internal/usbgadget/usbgadget.go +++ b/internal/usbgadget/usbgadget.go @@ -79,6 +79,8 @@ type UsbGadget struct { onKeyboardStateChange *func(state KeyboardState) log *zerolog.Logger + + logSuppressionCounter map[string]int } const configFSPath = "/sys/kernel/config" @@ -126,6 +128,8 @@ func newUsbGadget(name string, configMap map[string]gadgetConfigItem, enabledDev strictMode: config.strictMode, + logSuppressionCounter: make(map[string]int), + absMouseAccumulatedWheelY: 0, } if err := g.Init(); err != nil { diff --git a/internal/usbgadget/utils.go b/internal/usbgadget/utils.go index 7a6d1db..2e9a1d0 100644 --- a/internal/usbgadget/utils.go +++ b/internal/usbgadget/utils.go @@ -6,6 +6,8 @@ import ( "path/filepath" "strconv" "strings" + + "github.com/rs/zerolog" ) func joinPath(basePath string, paths []string) string { @@ -78,3 +80,27 @@ func compareFileContent(oldContent []byte, newContent []byte, looserMatch bool) return false } + +func (u *UsbGadget) logWithSupression(counterName string, every int, logger *zerolog.Logger, err error, msg string, args ...interface{}) { + if _, ok := u.logSuppressionCounter[counterName]; !ok { + u.logSuppressionCounter[counterName] = 0 + } else { + u.logSuppressionCounter[counterName]++ + } + + l := logger.With().Int("counter", u.logSuppressionCounter[counterName]).Logger() + + if u.logSuppressionCounter[counterName]%every == 0 { + if err != nil { + l.Error().Err(err).Msgf(msg, args...) + } else { + l.Error().Msgf(msg, args...) + } + } +} + +func (u *UsbGadget) resetLogSuppressionCounter(counterName string) { + if _, ok := u.logSuppressionCounter[counterName]; !ok { + u.logSuppressionCounter[counterName] = 0 + } +} diff --git a/native.go b/native.go index 496f580..e2da36a 100644 --- a/native.go +++ b/native.go @@ -8,6 +8,7 @@ import ( "io" "net" "os" + "os/exec" "sync" "time" @@ -41,6 +42,11 @@ var ongoingRequests = make(map[int32]chan *CtrlResponse) var lock = &sync.Mutex{} +var ( + nativeCmd *exec.Cmd + nativeCmdLock = &sync.Mutex{} +) + func CallCtrlAction(action string, params map[string]interface{}) (*CtrlResponse, error) { lock.Lock() defer lock.Unlock() @@ -129,16 +135,26 @@ func StartNativeSocketServer(socketPath string, handleClient func(net.Conn), isC scopedLogger.Info().Msg("server listening") go func() { - conn, err := listener.Accept() - listener.Close() - if err != nil { - scopedLogger.Warn().Err(err).Msg("failed to accept socket") + for { + conn, err := listener.Accept() + + if err != nil { + scopedLogger.Warn().Err(err).Msg("failed to accept socket") + continue + } + if isCtrl { + // check if the channel is closed + select { + case <-ctrlClientConnected: + scopedLogger.Debug().Msg("ctrl client reconnected") + default: + close(ctrlClientConnected) + scopedLogger.Debug().Msg("first native ctrl socket client connected") + } + } + + go handleClient(conn) } - if isCtrl { - close(ctrlClientConnected) - scopedLogger.Debug().Msg("first native ctrl socket client connected") - } - handleClient(conn) }() return listener @@ -235,6 +251,51 @@ func handleVideoClient(conn net.Conn) { } } +func startNativeBinaryWithLock(binaryPath string) (*exec.Cmd, error) { + nativeCmdLock.Lock() + defer nativeCmdLock.Unlock() + + cmd, err := startNativeBinary(binaryPath) + if err != nil { + return nil, err + } + nativeCmd = cmd + return cmd, nil +} + +func restartNativeBinary(binaryPath string) error { + time.Sleep(10 * time.Second) + // restart the binary + nativeLogger.Info().Msg("restarting jetkvm_native binary") + cmd, err := startNativeBinary(binaryPath) + if err != nil { + nativeLogger.Warn().Err(err).Msg("failed to restart binary") + } + nativeCmd = cmd + return err +} + +func superviseNativeBinary(binaryPath string) error { + nativeCmdLock.Lock() + defer nativeCmdLock.Unlock() + + if nativeCmd == nil || nativeCmd.Process == nil { + return restartNativeBinary(binaryPath) + } + + err := nativeCmd.Wait() + + if err == nil { + nativeLogger.Info().Err(err).Msg("jetkvm_native binary exited with no error") + } else if exiterr, ok := err.(*exec.ExitError); ok { + nativeLogger.Warn().Int("exit_code", exiterr.ExitCode()).Msg("jetkvm_native binary exited with error") + } else { + nativeLogger.Warn().Err(err).Msg("jetkvm_native binary exited with unknown error") + } + + return restartNativeBinary(binaryPath) +} + func ExtractAndRunNativeBin() error { binaryPath := "/userdata/jetkvm/bin/jetkvm_native" if err := ensureBinaryUpdated(binaryPath); err != nil { @@ -246,12 +307,28 @@ func ExtractAndRunNativeBin() error { return fmt.Errorf("failed to make binary executable: %w", err) } // Run the binary in the background - cmd, err := startNativeBinary(binaryPath) + cmd, err := startNativeBinaryWithLock(binaryPath) if err != nil { return fmt.Errorf("failed to start binary: %w", err) } - //TODO: add auto restart + // check if the binary is still running every 10 seconds + go func() { + for { + select { + case <-appCtx.Done(): + nativeLogger.Info().Msg("stopping native binary supervisor") + return + default: + err := superviseNativeBinary(binaryPath) + if err != nil { + nativeLogger.Warn().Err(err).Msg("failed to supervise native binary") + time.Sleep(1 * time.Second) // Add a short delay to prevent rapid successive calls + } + } + } + }() + go func() { <-appCtx.Done() nativeLogger.Info().Int("pid", cmd.Process.Pid).Msg("killing process") diff --git a/network.go b/network.go index 8d9261b..2208a47 100644 --- a/network.go +++ b/network.go @@ -21,6 +21,7 @@ func networkStateChanged() { // always restart mDNS when the network state changes if mDNS != nil { + _ = mDNS.SetListenOptions(config.NetworkConfig.GetMDNSMode()) _ = mDNS.SetLocalNames([]string{ networkState.GetHostname(), networkState.GetFQDN(), @@ -54,14 +55,6 @@ func initNetwork() error { OnConfigChange: func(networkConfig *network.NetworkConfig) { config.NetworkConfig = networkConfig networkStateChanged() - - if mDNS != nil { - _ = mDNS.SetListenOptions(networkConfig.GetMDNSMode()) - _ = mDNS.SetLocalNames([]string{ - networkState.GetHostname(), - networkState.GetFQDN(), - }, true) - } }, }) diff --git a/terminal.go b/terminal.go index e98b4de..e06e5cd 100644 --- a/terminal.go +++ b/terminal.go @@ -1,6 +1,7 @@ package kvm import ( + "bytes" "encoding/json" "io" "os" @@ -55,18 +56,23 @@ func handleTerminalChannel(d *webrtc.DataChannel) { return } if msg.IsString { - var size TerminalSize - err := json.Unmarshal([]byte(msg.Data), &size) - if err == nil { - err = pty.Setsize(ptmx, &pty.Winsize{ - Rows: uint16(size.Rows), - Cols: uint16(size.Cols), - }) + maybeJson := bytes.TrimSpace(msg.Data) + // Cheap check to see if this resembles JSON + if len(maybeJson) > 1 && maybeJson[0] == '{' && maybeJson[len(maybeJson)-1] == '}' { + var size TerminalSize + err := json.Unmarshal(maybeJson, &size) if err == nil { - return + err = pty.Setsize(ptmx, &pty.Winsize{ + Rows: uint16(size.Rows), + Cols: uint16(size.Cols), + }) + if err == nil { + scopedLogger.Info().Int("rows", size.Rows).Int("cols", size.Cols).Msg("Set terminal size") + return + } } + scopedLogger.Warn().Err(err).Msg("Failed to parse terminal size") } - scopedLogger.Warn().Err(err).Msg("Failed to parse terminal size") } _, err := ptmx.Write(msg.Data) if err != nil { diff --git a/ui/src/components/ActionBar.tsx b/ui/src/components/ActionBar.tsx index 7de4571..4289e42 100644 --- a/ui/src/components/ActionBar.tsx +++ b/ui/src/components/ActionBar.tsx @@ -1,6 +1,6 @@ import { MdOutlineContentPasteGo } from "react-icons/md"; import { LuCable, LuHardDrive, LuMaximize, LuSettings, LuSignal } from "react-icons/lu"; -import { FaKeyboard, FaLock} from "react-icons/fa6"; +import { FaKeyboard } from "react-icons/fa6"; import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; import { Fragment, useCallback, useRef } from "react"; import { CommandLineIcon } from "@heroicons/react/20/solid"; @@ -19,8 +19,6 @@ import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index"; import MountPopopover from "@/components/popovers/MountPopover"; import ExtensionPopover from "@/components/popovers/ExtensionPopover"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; -import useKeyboard from "@/hooks/useKeyboard"; -import { keys, modifiers } from "@/keyboardMappings"; export default function Actionbar({ requestFullscreen, @@ -58,8 +56,6 @@ export default function Actionbar({ [setDisableFocusTrap], ); - const { sendKeyboardEvent, resetKeyboardState } = useKeyboard(); - return (
- {useSettingsStore().actionBarCtrlAltDel && ( + {/* {useSettingsStore().actionBarCtrlAltDel && (
- )} + )} */}
+ +