diff --git a/ctxcdb/pebble/pebble.go b/ctxcdb/pebble/pebble.go index f756a19aa8..237a670629 100644 --- a/ctxcdb/pebble/pebble.go +++ b/ctxcdb/pebble/pebble.go @@ -220,7 +220,8 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( {TargetFileSize: 16 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, {TargetFileSize: 32 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, {TargetFileSize: 64 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, - {TargetFileSize: 128 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + // Pebble doesn't use the Bloom filter at level6 for read efficiency. + {TargetFileSize: 128 * 1024 * 1024}, }, ReadOnly: readonly, EventListener: &pebble.EventListener{ @@ -251,9 +252,6 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( // debt will be less than 1GB, but with more frequent compactions scheduled. L0CompactionThreshold: 2, } - // Disable seek compaction explicitly. Check https://github.com/CortexFoundation/CortexTheseus/pull/20130 - // for more details. - opt.Experimental.ReadSamplingMultiplier = -1 // Open the db and recover any potential corruptions innerDB, err := pebble.Open(file, opt) diff --git a/go.mod b/go.mod index 71539ea3a3..8942528f3a 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,15 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 github.com/CortexFoundation/inference v1.0.2-0.20230307032835-9197d586a4e8 github.com/CortexFoundation/statik v0.0.0-20210315012922-8bb8a7b5dc66 - github.com/CortexFoundation/torrentfs v1.0.73-0.20251124184227-7b581860e3c0 + github.com/CortexFoundation/torrentfs v1.0.73-0.20251202154802-316eb23b5a00 github.com/Microsoft/go-winio v0.6.2 github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251119083800-2aa1d4cc79d7 github.com/VictoriaMetrics/fastcache v1.13.2 github.com/arsham/figurine v1.3.0 github.com/aws/aws-sdk-go-v2 v1.40.0 - github.com/aws/aws-sdk-go-v2/config v1.32.1 - github.com/aws/aws-sdk-go-v2/credentials v1.19.1 - github.com/aws/aws-sdk-go-v2/service/route53 v1.60.1 + github.com/aws/aws-sdk-go-v2/config v1.32.2 + github.com/aws/aws-sdk-go-v2/credentials v1.19.2 + github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 github.com/cespare/cp v1.1.1 github.com/charmbracelet/bubbletea v1.3.10 github.com/cloudflare/cloudflare-go v0.116.0 @@ -25,7 +25,7 @@ require ( github.com/dchest/siphash v1.2.3 github.com/deckarep/golang-set/v2 v2.8.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 - github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86 + github.com/dop251/goja v0.0.0-20251201205617-2bb4c724c0f9 github.com/ethereum/c-kzg-4844 v1.0.3 github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab github.com/ethereum/go-verkle v0.2.2 @@ -86,12 +86,12 @@ require ( github.com/CortexFoundation/wormhole v0.0.2-0.20250807143819-52807b74f358 // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/RoaringBitmap/roaring v1.9.4 // indirect - github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect + github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8 // indirect github.com/anacrolix/chansync v0.7.0 // indirect github.com/anacrolix/dht/v2 v2.23.0 // indirect github.com/anacrolix/envpprof v1.4.0 // indirect - github.com/anacrolix/generics v0.1.0 // indirect + github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b // indirect github.com/anacrolix/go-libutp v1.3.2 // indirect github.com/anacrolix/log v0.17.1-0.20251118025802-918f1157b7bb // indirect github.com/anacrolix/missinggo v1.3.0 // indirect @@ -101,7 +101,7 @@ require ( github.com/anacrolix/multiless v0.4.0 // indirect github.com/anacrolix/stm v0.5.0 // indirect github.com/anacrolix/sync v0.5.5-0.20251119100342-d78dd1f686f1 // indirect - github.com/anacrolix/torrent v1.59.2-0.20251121022239-29ca7fdf5c63 // indirect + github.com/anacrolix/torrent v1.59.2-0.20251201070025-62f62628d9b8 // indirect github.com/anacrolix/upnp v0.1.4 // indirect github.com/anacrolix/utp v0.2.0 // indirect github.com/antlabs/stl v0.0.2 // indirect @@ -114,11 +114,11 @@ require ( github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 // indirect - github.com/aws/smithy-go v1.23.2 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 // indirect + github.com/aws/smithy-go v1.24.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/immutable v0.4.3 // indirect @@ -130,10 +130,10 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.3.3 // indirect github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/x/ansi v0.11.1 // indirect + github.com/charmbracelet/x/ansi v0.11.2 // indirect github.com/charmbracelet/x/cellbuf v0.0.14 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect - github.com/clipperhouse/displaywidth v0.6.0 // indirect + github.com/clipperhouse/displaywidth v0.6.1 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.12.0 // indirect @@ -153,7 +153,7 @@ require ( github.com/emicklei/dot v1.9.2 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/getsentry/sentry-go v0.39.0 // indirect + github.com/getsentry/sentry-go v0.40.0 // indirect github.com/go-llsqlite/adapter v0.2.0 // indirect github.com/go-llsqlite/crawshaw v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -172,7 +172,7 @@ require ( github.com/huandu/xstrings v1.5.0 // indirect github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect github.com/jedib0t/go-pretty/v6 v6.7.5 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -196,16 +196,16 @@ require ( github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/dtls/v3 v3.0.7 // indirect - github.com/pion/ice/v4 v4.0.10 // indirect + github.com/pion/ice/v4 v4.0.12 // indirect github.com/pion/interceptor v0.1.42 // indirect github.com/pion/logging v0.2.4 // indirect github.com/pion/mdns/v2 v2.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.16 // indirect github.com/pion/rtp v1.8.25 // indirect - github.com/pion/sctp v1.8.40 // indirect + github.com/pion/sctp v1.8.41 // indirect github.com/pion/sdp/v3 v3.0.16 // indirect - github.com/pion/srtp/v3 v3.0.8 // indirect + github.com/pion/srtp/v3 v3.0.9 // indirect github.com/pion/stun/v3 v3.0.1 // indirect github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.1.1 // indirect @@ -233,7 +233,7 @@ require ( github.com/tklauser/numcpus v0.11.0 // indirect github.com/ucwong/filecache v1.0.7 // indirect github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb // indirect - github.com/ucwong/golang-kv v1.0.24-0.20251109124133-d3b517c91775 // indirect + github.com/ucwong/golang-kv v1.0.24-0.20251129161750-0c74710bc499 // indirect github.com/ucwong/shard v1.0.1-0.20250814204722-892131bad5ef // indirect github.com/wlynxg/anet v0.0.5 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect @@ -248,7 +248,7 @@ require ( go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect + golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/term v0.37.0 // indirect @@ -261,5 +261,3 @@ require ( modernc.org/sqlite v1.40.1 // indirect zombiezen.com/go/sqlite v1.4.2 // indirect ) - -replace github.com/ajwerner/btree => github.com/anacrolix/btree v0.0.0-20251103085645-fd1051eb0009 diff --git a/go.sum b/go.sum index 2687f57a31..cfaff561d0 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/CortexFoundation/statik v0.0.0-20210315012922-8bb8a7b5dc66/go.mod h1: github.com/CortexFoundation/torrentfs v1.0.13-0.20200623060705-ce027f43f2f8/go.mod h1:Ma+tGhPPvz4CEZHaqEJQMOEGOfHeQBiAoNd1zyc/w3Q= github.com/CortexFoundation/torrentfs v1.0.14-0.20200703071639-3fcabcabf274/go.mod h1:qnb3YlIJmuetVBtC6Lsejr0Xru+1DNmDCdTqnwy7lhk= github.com/CortexFoundation/torrentfs v1.0.20-0.20200810031954-d36d26f82fcc/go.mod h1:N5BsicP5ynjXIi/Npl/SRzlJ630n1PJV2sRj0Z0t2HA= -github.com/CortexFoundation/torrentfs v1.0.73-0.20251124184227-7b581860e3c0 h1:l0eQ4N4oPK8FaJbsTSxeDOHJ/E+cN5qaXRS4coIqJ8E= -github.com/CortexFoundation/torrentfs v1.0.73-0.20251124184227-7b581860e3c0/go.mod h1:bsykjYORUrq3JAlolkr6GC24NnkvcjozHaGBkmxyP68= +github.com/CortexFoundation/torrentfs v1.0.73-0.20251202154802-316eb23b5a00 h1:QmjMzBOx5VmeoZrphhtO0qrhFXJ/RZM3iM5azL7amNU= +github.com/CortexFoundation/torrentfs v1.0.73-0.20251202154802-316eb23b5a00/go.mod h1:8PMnWIABNffxQS6qCO8nuRT3/OTtSDuozwmDcksZiNk= github.com/CortexFoundation/wormhole v0.0.2-0.20250807143819-52807b74f358 h1:y0QMrHsFxmrKBJDjYTnsXw8h/rtjO+tMnmK2OdUzZ/w= github.com/CortexFoundation/wormhole v0.0.2-0.20250807143819-52807b74f358/go.mod h1:R/2T+BS27RdmRWWhoDdgSlordZpUBjVTh8hi4fHoioE= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -126,8 +126,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache/v2 v2.2.2/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY= github.com/allegro/bigcache/v2 v2.2.3/go.mod h1:FppZsIO+IZk7gCuj5FiIDHGygD9xvWQcqg1uIPMb6tY= -github.com/anacrolix/btree v0.0.0-20251103085645-fd1051eb0009 h1:T2JC1fRU8kEIoD/G5vhcINK+LCifxrLetLem4Gpp0k4= -github.com/anacrolix/btree v0.0.0-20251103085645-fd1051eb0009/go.mod h1:rqyEQbKCmu4lwgcNmbxgA96MluhDnlx6mEUIm8WCZ9k= +github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8 h1:c02PsmoaChabVqAFm7pqPI1UIkDdDAjUaWa6ZmfxybQ= +github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8/go.mod h1:7stWJ39LeusmMI8mjJuhFNRqep//vx0AsaySRoK9or0= github.com/anacrolix/chansync v0.7.0 h1:wgwxbsJRmOqNjil4INpxHrDp4rlqQhECxR8/WBP4Et0= github.com/anacrolix/chansync v0.7.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k= github.com/anacrolix/dht v0.0.0-20180412060941-24cbf25b72a4/go.mod h1:hQfX2BrtuQsLQMYQwsypFAab/GvHg8qxwVi4OJdR1WI= @@ -146,8 +146,8 @@ github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAK github.com/anacrolix/envpprof v1.4.0 h1:QHeIcrgHcRChhnxR8l6rlaLlRQx9zd7Q2NII6Zbt83w= github.com/anacrolix/envpprof v1.4.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0= github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= -github.com/anacrolix/generics v0.1.0 h1:r6OgogjCdml3K5A8ixUG0X9DM4jrQiMfIkZiBOGvIfg= -github.com/anacrolix/generics v0.1.0/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8= +github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b h1:Kuvx/A/TTJuT9x8mn7DeGx2KW9tWn1LI8bira67xdT0= +github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b/go.mod h1:NGehhfeXJPBujPx0s6cstSj8B+TERsTY32Xckfx5ftc= github.com/anacrolix/go-libutp v0.0.0-20180522111405-6baeb806518d/go.mod h1:beQSaSxwH2d9Eeu5ijrEnHei5Qhk+J6cDm1QkWFru4E= github.com/anacrolix/go-libutp v1.0.2/go.mod h1:uIH0A72V++j0D1nnmTjjZUiH/ujPkFxYWkxQ02+7S0U= github.com/anacrolix/go-libutp v1.0.3/go.mod h1:8vSGX5g0b4eebsDBNVQHUXSCwYaN18Lnkse0hUW8/5w= @@ -225,8 +225,8 @@ github.com/anacrolix/torrent v1.15.0/go.mod h1:MFc6KcbpAyfwGqOyRkdarUK9QnKA/FkVg github.com/anacrolix/torrent v1.15.1-0.20200504230043-cc5d2abe18e5/go.mod h1:QlOfgrCz5kbvhOz8M58dUwHY5SfZ9VbIvReZ0z0MdIk= github.com/anacrolix/torrent v1.15.1-0.20200619022403-dd51e99b88cc/go.mod h1:wuopQPC5+/M+zHYvhcA2vp5UCTm9rUc+VqjyBa882Q8= github.com/anacrolix/torrent v1.15.1-0.20200715061614-dd906f8fa72e/go.mod h1:XWo/fJN1oKgcjgxM+pUZpvalHfqHDs27BY5mBZjIQWo= -github.com/anacrolix/torrent v1.59.2-0.20251121022239-29ca7fdf5c63 h1:n4UI9pVxg8+FVQPP11vwfV008ec+aGSBe0BwtJtx56w= -github.com/anacrolix/torrent v1.59.2-0.20251121022239-29ca7fdf5c63/go.mod h1:tAKR6fnCaTDIVsri9k8549Q4lFR4EiWSfmBVlU2AtNU= +github.com/anacrolix/torrent v1.59.2-0.20251201070025-62f62628d9b8 h1:wnOgDw8yJWcW2k2oaFf6mRxCSE7ANJ5w2bjwtZ3C8Xk= +github.com/anacrolix/torrent v1.59.2-0.20251201070025-62f62628d9b8/go.mod h1:1rOC6i0O+NUAahpMtELyBh4aWsckjjz1adItbAQg3HY= github.com/anacrolix/upnp v0.1.1/go.mod h1:LXsbsp5h+WGN7YR+0A7iVXm5BL1LYryDev1zuJMWYQo= github.com/anacrolix/upnp v0.1.2-0.20200416075019-5e9378ed1425/go.mod h1:Pz94W3kl8rf+wxH3IbCa9Sq+DTJr8OSbV2Q3/y51vYs= github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U= @@ -269,10 +269,10 @@ github.com/aws/aws-sdk-go v1.31.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= -github.com/aws/aws-sdk-go-v2/config v1.32.1 h1:iODUDLgk3q8/flEC7ymhmxjfoAnBDwEEYEVyKZ9mzjU= -github.com/aws/aws-sdk-go-v2/config v1.32.1/go.mod h1:xoAgo17AGrPpJBSLg81W+ikM0cpOZG8ad04T2r+d5P0= -github.com/aws/aws-sdk-go-v2/credentials v1.19.1 h1:JeW+EwmtTE0yXFK8SmklrFh/cGTTXsQJumgMZNlbxfM= -github.com/aws/aws-sdk-go-v2/credentials v1.19.1/go.mod h1:BOoXiStwTF+fT2XufhO0Efssbi1CNIO/ZXpZu87N0pw= +github.com/aws/aws-sdk-go-v2/config v1.32.2 h1:4liUsdEpUUPZs5WVapsJLx5NPmQhQdez7nYFcovrytk= +github.com/aws/aws-sdk-go-v2/config v1.32.2/go.mod h1:l0hs06IFz1eCT+jTacU/qZtC33nvcnLADAPL/XyrkZI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.2 h1:qZry8VUyTK4VIo5aEdUcBjPZHL2v4FyQ3QEOaWcFLu4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.2/go.mod h1:YUqm5a1/kBnoK+/NY5WEiMocZihKSo15/tJdmdXnM5g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= @@ -285,18 +285,18 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/A github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E= -github.com/aws/aws-sdk-go-v2/service/route53 v1.60.1 h1:dU7oc4LXR9j4mi1DtD8549D/rUtKA4rcWNY1HPoKzx8= -github.com/aws/aws-sdk-go-v2/service/route53 v1.60.1/go.mod h1:Wa3q5R2uwIfIL3HZH+vG1/P9y7CjjfzTgcz5IWXlsZs= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 h1:BDgIUYGEo5TkayOWv/oBLPphWwNm/A91AebUjAu5L5g= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.1/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 h1:U//SlnkE1wOQiIImxzdY5PXat4Wq+8rlfVEw4Y7J8as= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.4/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 h1:LU8S9W/mPDAU9q0FjCLi0TrCheLMGwzbRpvUMwYspcA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 h1:GdGmKtG+/Krag7VfyOXV17xjTCz0i9NT+JnqLTOI5nA= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.1/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso= -github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= -github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 h1:W3+0Cbc9awFBr9Yt7nFUkvB4N4e7vVIGtKD1qDttXn4= +github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0/go.mod h1:Wa3q5R2uwIfIL3HZH+vG1/P9y7CjjfzTgcz5IWXlsZs= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 h1:MxMBdKTYBjPQChlJhi4qlEueqB1p1KcbTEa7tD5aqPs= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.2/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 h1:ksUT5KtgpZd3SAiFJNJ0AFEJVva3gjBmN7eXUZjzUwQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.5/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 h1:GtsxyiF3Nd3JahRBJbxLCCdYW9ltGQYrFWg8XdkGDd8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 h1:a5UTtD4mHBU3t0o6aHQZFJTNKVfxFWfPX7J0Lr7G+uY= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.2/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -349,8 +349,8 @@ github.com/charmbracelet/colorprofile v0.3.3 h1:DjJzJtLP6/NZ8p7Cgjno0CKGr7wwRJGx github.com/charmbracelet/colorprofile v0.3.3/go.mod h1:nB1FugsAbzq284eJcjfah2nhdSLppN2NqvfotkfRYP4= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/x/ansi v0.11.1 h1:iXAC8SyMQDJgtcz9Jnw+HU8WMEctHzoTAETIeA3JXMk= -github.com/charmbracelet/x/ansi v0.11.1/go.mod h1:M49wjzpIujwPceJ+t5w3qh2i87+HRtHohgb5iTyepL0= +github.com/charmbracelet/x/ansi v0.11.2 h1:XAG3FSjiVtFvgEgGrNBkCNNYrsucAt8c6bfxHyROLLs= +github.com/charmbracelet/x/ansi v0.11.2/go.mod h1:9tY2bzX5SiJCU0iWyskjBeI2BRQfvPqI+J760Mjf+Rg= github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4= github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -361,8 +361,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s= -github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= +github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY= +github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= @@ -439,8 +439,8 @@ github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cn github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86 h1:iY/kk+Fw7k49PRM4cS2wz9CVxO0jB61+h//XN9bbAS4= -github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= +github.com/dop251/goja v0.0.0-20251201205617-2bb4c724c0f9 h1:3uSSOd6mVlwcX3k5OYOpiDqFgRmaE2dBfLvVIFWWHrw= +github.com/dop251/goja v0.0.0-20251201205617-2bb4c724c0f9/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -506,8 +506,8 @@ github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05 github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-libpcsclite v0.0.0-20250918194357-1ec6f2e601c6 h1:ko+DlyhLqUHpgrvwqs5ybydoGAqjpJQTXpAS7vUqVlM= github.com/gballet/go-libpcsclite v0.0.0-20250918194357-1ec6f2e601c6/go.mod h1:3IVE7v4II2gS2V5amIH7F7NeYQtbbORtQtjdflgS1vk= -github.com/getsentry/sentry-go v0.39.0 h1:uhnexj8PNCyCve37GSqxXOeXHh4cJNLNNB4w70Jtgo0= -github.com/getsentry/sentry-go v0.39.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= +github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= +github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -767,8 +767,8 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -974,8 +974,8 @@ 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 v0.7.13/go.mod h1:U3ERMkJgkPMlBjzMe2XxIQPl6ZrfRHyENwGCBoFrWWk= github.com/pion/ice v0.7.14/go.mod h1:/Lz6jAUhsvXed7kNJImXtvVSgjtcdGKoZAZIYb9WEm0= -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/ice/v4 v4.0.12 h1:vuI3h9OD5M0Z+V304qLC1/o16ahHVnDgqNCWbONv6s0= +github.com/pion/ice/v4 v4.0.12/go.mod h1:tAp574oAufhHRHr8EO1xgPmVKVDBROX+708WggYD6NE= github.com/pion/interceptor v0.1.42 h1:0/4tvNtruXflBxLfApMVoMubUMik57VZ+94U0J7cmkQ= github.com/pion/interceptor v0.1.42/go.mod h1:g6XYTChs9XyolIQFhRHOOUS+bGVGLRfgTCUzH29EfVU= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= @@ -995,15 +995,15 @@ github.com/pion/rtp v1.4.0/go.mod h1:/l4cvcKd0D3u9JLs2xSVI95YkfXW87a3br3nqmVtSlE github.com/pion/rtp v1.8.25 h1:b8+y44GNbwOJTYWuVan7SglX/hMlicVCAtL50ztyZHw= github.com/pion/rtp v1.8.25/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= github.com/pion/sctp v1.7.6/go.mod h1:ichkYQ5tlgCQwEwvgfdcAolqx1nHbYCxo4D7zK/K0X8= -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/sctp v1.8.41 h1:20R4OHAno4Vky3/iE4xccInAScAa83X6nWUfyc65MIs= +github.com/pion/sctp v1.8.41/go.mod h1:2wO6HBycUH7iCssuGyc2e9+0giXVW0pyCv3ZuL8LiyY= github.com/pion/sdp/v2 v2.3.7/go.mod h1:+ZZf35r1+zbaWYiZLfPutWfx58DAWcGb2QsS3D/s9M8= 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 v1.3.1/go.mod h1:nxEytDDGTN+eNKJ1l5gzOCWQFuksgijorsSlgEjc40Y= github.com/pion/srtp v1.3.2/go.mod h1:snPrfN+gVpRBpmats49oxLWfcFB01eH1N9F+N7+dxKI= -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/srtp/v3 v3.0.9 h1:lRGF4G61xxj+m/YluB3ZnBpiALSri2lTzba0kGZMrQY= +github.com/pion/srtp/v3 v3.0.9/go.mod h1:E+AuWd7Ug2Fp5u38MKnhduvpVkveXJX6J4Lq4rxUYt8= github.com/pion/stun v0.3.3/go.mod h1:xrCld6XM+6GWDZdvjPlLMsTU21rNxnO6UO8XsAvHr/M= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= @@ -1242,8 +1242,8 @@ github.com/ucwong/filecache v1.0.7 h1:2ingbpnDpTt5WoWT+vLWdiM3M5LQjpZFIYkkx3x86U github.com/ucwong/filecache v1.0.7/go.mod h1:ddwX+NCjMZPdpzcGh1fcEbNTUTCtKgt2hC2rqvmLKgA= github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb h1:dVZH3AH9f7zB3VBmsjn25B7lfcAyMP4QxdFYTrfj7tg= github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb/go.mod h1:3yswsBsVuwsOjDvFfC5Na9XSEf4HC7mj3W3g6jvSY/s= -github.com/ucwong/golang-kv v1.0.24-0.20251109124133-d3b517c91775 h1:c7v0npsHammMHYQkXJSH6X7IikyakqyFwlhTHvlqR2g= -github.com/ucwong/golang-kv v1.0.24-0.20251109124133-d3b517c91775/go.mod h1:EsQXlK0Ax6w7zNcgBVXl7ErZ2jGz4DV6qd4xrSjbNY0= +github.com/ucwong/golang-kv v1.0.24-0.20251129161750-0c74710bc499 h1:INXN/7KulMXtuU7IbWLRiTscusGB9NdFXNTrOEsBP2g= +github.com/ucwong/golang-kv v1.0.24-0.20251129161750-0c74710bc499/go.mod h1:zj4iJ83PKunYUdteBa+Dz3N3x+lgbe+ui2dlTCXSCfo= github.com/ucwong/golang-set v1.8.1-0.20200419153428-d7b0b1ac2d43/go.mod h1:xu0FaiQFGbBcFZj2o7udZ5rbA8jRTsv47hkPoG5qQNM= github.com/ucwong/goleveldb v1.0.3-0.20200508074755-578cba616f37/go.mod h1:dgJUTtDxq/ne6/JzZhHzF24OL/uqILz9IWk8HmT4V2g= github.com/ucwong/goleveldb v1.0.3-0.20200618184106-f1c6bc3a428b/go.mod h1:7Sq6w7AfEZuB/a6mrlvHCSXCSkqojCMMrM3Ei12QAT0= @@ -1376,8 +1376,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= diff --git a/vendor/github.com/ajwerner/btree/LICENSE b/vendor/github.com/anacrolix/btree/LICENSE similarity index 100% rename from vendor/github.com/ajwerner/btree/LICENSE rename to vendor/github.com/anacrolix/btree/LICENSE diff --git a/vendor/github.com/ajwerner/btree/README.md b/vendor/github.com/anacrolix/btree/README.md similarity index 100% rename from vendor/github.com/ajwerner/btree/README.md rename to vendor/github.com/anacrolix/btree/README.md diff --git a/vendor/github.com/ajwerner/btree/btree.go b/vendor/github.com/anacrolix/btree/btree.go similarity index 97% rename from vendor/github.com/ajwerner/btree/btree.go rename to vendor/github.com/anacrolix/btree/btree.go index 6cf04af292..bfcab7e6cd 100644 --- a/vendor/github.com/ajwerner/btree/btree.go +++ b/vendor/github.com/anacrolix/btree/btree.go @@ -14,7 +14,7 @@ package btree -import "github.com/ajwerner/btree/internal/abstract" +import "github.com/anacrolix/btree/internal/abstract" // Map is a ordered map from K to V. type Map[K, V any] struct { diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/aug_btree.go b/vendor/github.com/anacrolix/btree/internal/abstract/aug_btree.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/aug_btree.go rename to vendor/github.com/anacrolix/btree/internal/abstract/aug_btree.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/config.go b/vendor/github.com/anacrolix/btree/internal/abstract/config.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/config.go rename to vendor/github.com/anacrolix/btree/internal/abstract/config.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/iter_stack.go b/vendor/github.com/anacrolix/btree/internal/abstract/iter_stack.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/iter_stack.go rename to vendor/github.com/anacrolix/btree/internal/abstract/iter_stack.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/iterator.go b/vendor/github.com/anacrolix/btree/internal/abstract/iterator.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/iterator.go rename to vendor/github.com/anacrolix/btree/internal/abstract/iterator.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/low_level.go b/vendor/github.com/anacrolix/btree/internal/abstract/low_level.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/low_level.go rename to vendor/github.com/anacrolix/btree/internal/abstract/low_level.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/node.go b/vendor/github.com/anacrolix/btree/internal/abstract/node.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/node.go rename to vendor/github.com/anacrolix/btree/internal/abstract/node.go diff --git a/vendor/github.com/ajwerner/btree/internal/abstract/node_pool.go b/vendor/github.com/anacrolix/btree/internal/abstract/node_pool.go similarity index 100% rename from vendor/github.com/ajwerner/btree/internal/abstract/node_pool.go rename to vendor/github.com/anacrolix/btree/internal/abstract/node_pool.go diff --git a/vendor/github.com/anacrolix/generics/option.go b/vendor/github.com/anacrolix/generics/option.go index 1316e7b8b3..cfb23f5774 100644 --- a/vendor/github.com/anacrolix/generics/option.go +++ b/vendor/github.com/anacrolix/generics/option.go @@ -2,9 +2,9 @@ package generics import ( "fmt" - "iter" ) +// Any functions that include types additional to V must be global and are in the option package. type Option[V any] struct { // Value must be zeroed when Ok is false for deterministic comparability. Value V @@ -116,10 +116,15 @@ func (me Option[V]) AsTuple() (V, bool) { } // Yields value for use as iter.Seq such as in range expression. -func (me Option[V]) Iter() iter.Seq[V] { - return func(yield func(V) bool) { - if me.Ok { - yield(me.Value) - } +func (me Option[V]) Iter(yield func(V) bool) { + if me.Ok { + yield(me.Value) } } + +func (me Option[V]) Filter(f func(V) bool) Option[V] { + if me.Ok && !f(me.Value) { + me.SetNone() + } + return me +} diff --git a/vendor/github.com/anacrolix/torrent/client-piece-request-order.go b/vendor/github.com/anacrolix/torrent/client-piece-request-order.go index 0984b40996..48749cbe5a 100644 --- a/vendor/github.com/anacrolix/torrent/client-piece-request-order.go +++ b/vendor/github.com/anacrolix/torrent/client-piece-request-order.go @@ -31,7 +31,7 @@ type clientPieceRequestOrderSharedStorageTorrentKey clientPieceRequestOrderKey[s func (c clientPieceRequestOrderSharedStorageTorrentKey) getRequestStrategyInput(cl *Client) requestStrategy.Input { return requestStrategyInputMultiTorrent{ requestStrategyInputCommon: cl.getRequestStrategyInputCommon(), - torrents: cl.torrentsByShortHash, + torrents: &cl.torrentsByShortHash, capFunc: c.inner, } } diff --git a/vendor/github.com/anacrolix/torrent/client-tracker-announcer.go b/vendor/github.com/anacrolix/torrent/client-tracker-announcer.go index 249359ba3b..7a2ba4575b 100644 --- a/vendor/github.com/anacrolix/torrent/client-tracker-announcer.go +++ b/vendor/github.com/anacrolix/torrent/client-tracker-announcer.go @@ -174,7 +174,7 @@ func (me *regularTrackerAnnounceDispatcher) init(client *Client) { input.infohashActive = new.Value.count return input }, - )) + ).Exists) } }) me.trackerAnnouncing.Init(cmp.Compare) @@ -341,7 +341,7 @@ func (me *regularTrackerAnnounceDispatcher) updateOverdue() { var last g.Option[torrentTrackerAnnouncerKey] again: for { - for r := range indexed.FirstInRange(me.overdueIndex, start, end).Iter() { + for r := range indexed.FirstInRange(me.overdueIndex, start, end).Iter { // Check we're making progress. if last.Ok { if last.Value.Compare(r.torrentTrackerAnnouncerKey) == 0 { @@ -369,7 +369,7 @@ again: value.overdue = value.When.Compare(now) <= 0 panicif.Eq(value.overdue, oldOverdue) return value - })) + }).Exists) continue again } break @@ -413,7 +413,8 @@ func (me *regularTrackerAnnounceDispatcher) addKey(key torrentTrackerAnnouncerKe // Returns nil if the torrent was dropped. func (me *regularTrackerAnnounceDispatcher) torrentFromShortInfohash(short shortInfohash) *Torrent { - return me.torrentClient.torrentsByShortHash[short] + t, _ := me.torrentClient.torrentsByShortHash.Get(short) + return t } const maxConcurrentAnnouncesPerTracker = 2 @@ -454,7 +455,7 @@ func (me *regularTrackerAnnounceDispatcher) startAnnounce(key torrentTrackerAnno panicif.True(r.active) r.active = true return r - })) + }).Exists) me.alterInfohashConcurrency(key.ShortInfohash, func(existing int) int { return existing + 1 }) @@ -500,11 +501,12 @@ func (me *regularTrackerAnnounceDispatcher) syncAnnounceState(key torrentTracker func (me *regularTrackerAnnounceDispatcher) updateTorrentInput(t *Torrent) { input := me.makeTorrentInput(t) + changed := false for key := range t.regularTrackerAnnounceState { panicif.Zero(key.url) panicif.Zero(key.ShortInfohash) // Avoid clobbering derived and unrelated values (overdue and active). - exists := me.announceData.Update( + res := me.announceData.Update( key, func(av nextAnnounceInput) nextAnnounceInput { av.torrent = input @@ -513,9 +515,13 @@ func (me *regularTrackerAnnounceDispatcher) updateTorrentInput(t *Torrent) { return av }, ) - panicif.False(exists) + panicif.False(res.Exists) + changed = changed || res.Changed + } + // 'Twould be better to have a change trigger on nextAnnounce, but I'm in a hurry. + if changed { + me.updateTimer() } - me.updateTimer() } func (me *regularTrackerAnnounceDispatcher) nextTimerDelay() mytimer.TimeValue { @@ -733,7 +739,7 @@ type nextAnnounceTorrentInput struct { HasActiveWebseedRequests bool } -// TODO: Expand this to do Completed. when.IsZero if there's nothing to do and the data can be forgotten. +// when.IsZero if there's nothing to do and the data can be forgotten. func (me *regularTrackerAnnounceDispatcher) nextAnnounceEvent(key torrentTrackerAnnouncerKey) (event tracker.AnnounceEvent, when time.Time) { state := g.MapMustGet(me.announceStates, key) lastOk := state.lastOk diff --git a/vendor/github.com/anacrolix/torrent/client.go b/vendor/github.com/anacrolix/torrent/client.go index 59d6e61cc9..306b8e897c 100644 --- a/vendor/github.com/anacrolix/torrent/client.go +++ b/vendor/github.com/anacrolix/torrent/client.go @@ -93,7 +93,7 @@ type Client struct { // All Torrents by their short infohashes (v1 if valid, and truncated v2 if valid). Unless the // info has been obtained, there's no knowing if an infohash belongs to v1 or v2. TODO: Make // this a weak pointer. - torrentsByShortHash map[InfoHash]*Torrent + torrentsByShortHash syncMapTorrentsByShortHash // Piece request orderings grouped by storage. Value is value type because all fields are // references. @@ -274,9 +274,8 @@ func (cl *Client) init(cfg *ClientConfig) { cl.regularTrackerAnnounceDispatcher.init(cl) cfg.setRateLimiterBursts() g.MakeMap(&cl.dopplegangerAddrs) - g.MakeMap(&cl.torrentsByShortHash) + cl.torrentsByShortHash.Init() g.MakeMap(&cl.torrents) - cl.torrentsByShortHash = make(map[metainfo.Hash]*Torrent) cl.event.L = cl.locker() cl.ipBlockList = cfg.IPBlocklist cl.httpClient = &http.Client{ @@ -331,7 +330,7 @@ func (cl *Client) init(cfg *ClientConfig) { ) { cl.lock() defer cl.unlock() - t, ok := cl.torrentsByShortHash[infoHash] + t, ok := cl.torrentsByShortHash.Get(infoHash) if !ok { return tracker.AnnounceRequest{}, errors.New("torrent not tracked by client") } @@ -345,7 +344,7 @@ func (cl *Client) init(cfg *ClientConfig) { OnConn: func(dc webtorrent.DataChannelConn, dcc webtorrent.DataChannelContext) { cl.lock() defer cl.unlock() - t, ok := cl.torrentsByShortHash[dcc.InfoHash] + t, ok := cl.torrentsByShortHash.Get(dcc.InfoHash) if !ok { cl.logger.WithDefaultLevel(log.Warning).Printf( "got webrtc conn for unloaded torrent with infohash %x", @@ -543,7 +542,6 @@ func (cl *Client) Close() (errs []error) { } // Can we not modify cl.torrents as we delete from it? panicif.NotZero(len(cl.torrents)) - panicif.NotZero(len(cl.torrentsByShortHash)) cl.clearPortMappings() for i := range cl.onClose { cl.onClose[len(cl.onClose)-1-i]() @@ -696,10 +694,7 @@ func (cl *Client) incomingConnection(nc net.Conn) { // Returns a handle to the given torrent, if it's present in the client. func (cl *Client) Torrent(ih metainfo.Hash) (t *Torrent, ok bool) { - cl.rLock() - defer cl.rUnlock() - t, ok = cl.torrentsByShortHash[ih] - return + return cl.torrentsByShortHash.Get(ih) } type DialResult struct { @@ -1022,32 +1017,17 @@ func (cl *Client) initiateHandshakes(ctx context.Context, c *PeerConn, t *Torren // Calls f with any secret keys. Note that it takes the Client lock, and so must be used from code // that won't also try to take the lock. This saves us copying all the infohashes everytime. -func (cl *Client) forSkeys(f func([]byte) bool) { - cl.rLock() - defer cl.rUnlock() - if false { // Emulate the bug from #114 - var firstIh InfoHash - for ih := range cl.torrentsByShortHash { - firstIh = ih - break - } - for range cl.torrentsByShortHash { - if !f(firstIh[:]) { - break - } - } - return - } - for ih := range cl.torrentsByShortHash { - if !f(ih[:]) { - break +func (cl *Client) forSkeys(yield func([20]byte) bool) { + for ih := range cl.torrentsByShortHash.IterKeys { + if !yield(ih) { + return } } } func (cl *Client) handshakeReceiverSecretKeys() mse.SecretKeyIter { - if ret := cl.config.Callbacks.ReceiveEncryptedHandshakeSkeys; ret != nil { - return ret + if cb := cl.config.Callbacks.ReceiveEncryptedHandshakeSkeys; cb != nil { + return cb } return cl.forSkeys } @@ -1086,13 +1066,18 @@ func (cl *Client) receiveHandshakes(c *PeerConn) (t *Torrent, err error) { return nil, fmt.Errorf("during bt handshake: %w", err) } - cl.lock() - t = cl.torrentsByShortHash[ih] - if t != nil && t.infoHashV2.Ok && *t.infoHashV2.Value.ToShort() == ih { - torrent.Add("v2 handshakes received", 1) - c.v2 = true + // Hooray for atomics. + t, _ = cl.torrentsByShortHash.Get(ih) + if t != nil { + cl.rLock() + isV2 := t.infoHashV2.Ok && *t.infoHashV2.Value.ToShort() == ih + cl.rUnlock() + if isV2 { + torrent.Add("v2 handshakes received", 1) + // PeerConn isn't owned by the Client yet. + c.v2 = true + } } - cl.unlock() return } @@ -1475,53 +1460,54 @@ func (cl *Client) AddTorrentInfoHash(infoHash metainfo.Hash) (t *Torrent, new bo return cl.AddTorrentInfoHashWithStorage(infoHash, nil) } -// Deprecated. Adds a torrent by InfoHash with a custom Storage implementation. -// If the torrent already exists then this Storage is ignored and the -// existing torrent returned with `new` set to `false` +// Deprecated. Adds a torrent by InfoHash with a custom Storage implementation. If the torrent +// already exists then this Storage is ignored and the existing torrent returned with `new` set to +// `false` func (cl *Client) AddTorrentInfoHashWithStorage( infoHash metainfo.Hash, specStorage storage.ClientImpl, ) (t *Torrent, new bool) { - cl.lock() - defer cl.unlock() - t, ok := cl.torrentsByShortHash[infoHash] - if ok { - return - } - new = true + return cl.AddTorrentOpt(AddTorrentOpts{ + InfoHash: infoHash, + Storage: specStorage, + }) +} - t = cl.newTorrent(infoHash, specStorage) - cl.eachDhtServer(func(s DhtServer) { - if cl.config.PeriodicallyAnnounceTorrentsToDht { - go t.dhtAnnouncer(s) +func (cl *Client) addTorrentReturningExisting(opts AddTorrentOpts) (t *Torrent, ok bool) { + t, ok = cl.torrentsByShortHash.Get(opts.InfoHash) + if !ok { + if opts.InfoHashV2.Ok { + t, ok = cl.torrentsByShortHash.Get(*opts.InfoHashV2.Value.ToShort()) } - }) - cl.torrentsByShortHash[infoHash] = t - cl.torrents[t] = struct{}{} - cl.clearAcceptLimits() - t.updateWantPeersEvent() - // Tickle Client.waitAccept, new torrent may want conns. - cl.event.Broadcast() + } return } // Adds a torrent by InfoHash with a custom Storage implementation. If the torrent already exists // then this Storage is ignored and the existing torrent returned with `new` set to `false`. func (cl *Client) AddTorrentOpt(opts AddTorrentOpts) (t *Torrent, new bool) { - infoHash := opts.InfoHash - panicif.Zero(infoHash) + panicif.Zero(opts.InfoHash) + + t, ok := cl.addTorrentReturningExisting(opts) + if ok && !t.closed.IsSet() { + return + } + cl.lock() defer cl.unlock() - t, ok := cl.torrentsByShortHash[infoHash] + + t, ok = cl.addTorrentReturningExisting(opts) if ok { - return - } - if opts.InfoHashV2.Ok { - t, ok = cl.torrentsByShortHash[*opts.InfoHashV2.Value.ToShort()] - if ok { + if !t.closed.IsSet() { return } + // Do we have to nuke this? Can't we just clobber it? + t.eachShortInfohash(func(short [20]byte) { + cl.torrentsByShortHash.Delete(short) + }) } + + infoHash := opts.InfoHash new = true t = cl.newTorrentOpt(opts) @@ -1530,7 +1516,7 @@ func (cl *Client) AddTorrentOpt(opts AddTorrentOpts) (t *Torrent, new bool) { go t.dhtAnnouncer(s) } }) - cl.torrentsByShortHash[infoHash] = t + panicif.False(cl.torrentsByShortHash.Set(infoHash, t)) t.setInfoBytesLocked(opts.InfoBytes) cl.clearAcceptLimits() t.updateWantPeersEvent() @@ -1776,23 +1762,16 @@ func (cl *Client) newConnection(nc net.Conn, opts newConnectionOpts) (c *PeerCon } func (cl *Client) newDownloadRateLimitedReader(r io.Reader) io.Reader { - if cl.config.DownloadRateLimiter == nil { - return r - } - // Why if the limit is Inf? Because it can be dynamically adjusted. - return rateLimitedReader{ - l: cl.config.DownloadRateLimiter, - r: r, - } + return newRateLimitedReader(r, cl.config.DownloadRateLimiter) } func (cl *Client) onDHTAnnouncePeer(ih metainfo.Hash, ip net.IP, port int, portOk bool) { - cl.lock() - defer cl.unlock() - t := cl.torrentsByShortHash[ih] - if t == nil { + t, ok := cl.torrentsByShortHash.Get(ih) + if !ok { return } + cl.lock() + defer cl.unlock() t.addPeers([]PeerInfo{{ Addr: ipPortAddr{ip, port}, Source: PeerSourceDhtAnnouncePeer, diff --git a/vendor/github.com/anacrolix/torrent/internal/indexed/btree.go b/vendor/github.com/anacrolix/torrent/internal/indexed/btree.go index 4e61fcf7a9..b24aaddc6e 100644 --- a/vendor/github.com/anacrolix/torrent/internal/indexed/btree.go +++ b/vendor/github.com/anacrolix/torrent/internal/indexed/btree.go @@ -1,7 +1,7 @@ package indexed import ( - "github.com/ajwerner/btree" + "github.com/anacrolix/btree" ) type btreeIterator[R any] struct { diff --git a/vendor/github.com/anacrolix/torrent/internal/indexed/funcs.go b/vendor/github.com/anacrolix/torrent/internal/indexed/funcs.go index 1464e3f4a7..09153347b3 100644 --- a/vendor/github.com/anacrolix/torrent/internal/indexed/funcs.go +++ b/vendor/github.com/anacrolix/torrent/internal/indexed/funcs.go @@ -14,6 +14,7 @@ import ( func IterClusteredWhere[R any](t relation[R], gte R, where func(r R) bool) Iter[R] { return func(yield func(R) bool) { first := true + // TODO: This function is allocating.. checkFirst := func(r g.Option[R]) { if !first { return diff --git a/vendor/github.com/anacrolix/torrent/internal/indexed/internal-table.go b/vendor/github.com/anacrolix/torrent/internal/indexed/internal-table.go index 3ef0ff4ae3..612c615aac 100644 --- a/vendor/github.com/anacrolix/torrent/internal/indexed/internal-table.go +++ b/vendor/github.com/anacrolix/torrent/internal/indexed/internal-table.go @@ -4,7 +4,7 @@ import ( "fmt" "iter" - "github.com/ajwerner/btree" + "github.com/anacrolix/btree" g "github.com/anacrolix/generics" "github.com/anacrolix/missinggo/v2/panicif" "github.com/anacrolix/torrent/internal/amortize" @@ -188,10 +188,18 @@ func (me *table[R]) Contains(r R) (ok bool) { } func (me *table[R]) Changed(old, new g.Option[R]) { + // You should not even be trying to change a table underneath iterators. We want to know about + // this even if nothing happens. + me.incVersion() if !old.Ok && !new.Ok { return } - me.incVersion() + if old.Ok && new.Ok { + // I believe we have that Records are value-comparable. + if old.Value == new.Value { + return + } + } for _, t := range me.indexTriggers { t(old, new) } diff --git a/vendor/github.com/anacrolix/torrent/internal/indexed/map.go b/vendor/github.com/anacrolix/torrent/internal/indexed/map.go index 8224e68a6a..4bea860897 100644 --- a/vendor/github.com/anacrolix/torrent/internal/indexed/map.go +++ b/vendor/github.com/anacrolix/torrent/internal/indexed/map.go @@ -25,7 +25,12 @@ func (me *Map[K, V]) Init(cmp func(a, b K) int) { me.keyCmp = cmp } -func (me *Map[K, V]) Update(key K, updateFunc func(V) V) (exists bool) { +type UpdateResult struct { + Exists bool + Changed bool +} + +func (me *Map[K, V]) Update(key K, updateFunc func(V) V) (res UpdateResult) { start := Pair[K, V]{Left: key} gte := me.GetGte(start) if !gte.Ok { @@ -35,7 +40,7 @@ func (me *Map[K, V]) Update(key K, updateFunc func(V) V) (exists bool) { if me.keyCmp(old.Left, key) != 0 { return } - exists = true + res.Exists = true new := old new.Right = updateFunc(old.Right) if new.Right == old.Right { @@ -45,6 +50,8 @@ func (me *Map[K, V]) Update(key K, updateFunc func(V) V) (exists bool) { panicif.False(overwrote) panicif.NotEq(replaced, old) panicif.NotZero(me.cmp(replaced, old)) + // Is this lazy? Should the caller be triggering instead? + res.Changed = true me.Changed(g.Some(old), g.Some(new)) return } diff --git a/vendor/github.com/anacrolix/torrent/internal/request-strategy/ajwerner-btree.go b/vendor/github.com/anacrolix/torrent/internal/request-strategy/ajwerner-btree.go index 53fe190f3c..ff97f60215 100644 --- a/vendor/github.com/anacrolix/torrent/internal/request-strategy/ajwerner-btree.go +++ b/vendor/github.com/anacrolix/torrent/internal/request-strategy/ajwerner-btree.go @@ -1,7 +1,7 @@ package requestStrategy import ( - "github.com/ajwerner/btree" + "github.com/anacrolix/btree" ) type ajwernerBtree struct { diff --git a/vendor/github.com/anacrolix/torrent/mse/mse.go b/vendor/github.com/anacrolix/torrent/mse/mse.go index f566c63f79..e351a764a0 100644 --- a/vendor/github.com/anacrolix/torrent/mse/mse.go +++ b/vendor/github.com/anacrolix/torrent/mse/mse.go @@ -13,6 +13,7 @@ import ( "expvar" "fmt" "io" + "iter" "math" "math/big" "strconv" @@ -437,19 +438,18 @@ func (h *handshake) receiverSteps(ctx context.Context) (ret io.ReadWriter, chose eachHash := sha1.New() var sum, xored [sha1.Size]byte err = ErrNoSecretKeyMatch - h.skeys(func(skey []byte) bool { + for skey := range h.skeys { eachHash.Reset() eachHash.Write(req2) - eachHash.Write(skey) + eachHash.Write(skey[:]) eachHash.Sum(sum[:0]) xorInPlace(xored[:], sum[:], expectedHash) if bytes.Equal(xored[:], b[:]) { - h.skey = skey + h.skey = skey[:] err = nil - return false + break } - return true - }) + } if err != nil { return } @@ -598,9 +598,12 @@ func ReceiveHandshakeEx( return } -// A function that given a function, calls it with secret keys until it -// returns false or exhausted. -type SecretKeyIter func(callback func(skey []byte) (more bool)) +type ( + // For performance reasons prefer a static-sized array rather than []byte. + SecretKey = [20]byte + // A function that given a function, calls it with secret keys until it returns false or exhausted. + SecretKeyIter = iter.Seq[SecretKey] +) func DefaultCryptoSelector(provided CryptoMethod) CryptoMethod { // We prefer plaintext for performance reasons. diff --git a/vendor/github.com/anacrolix/torrent/peerconn.go b/vendor/github.com/anacrolix/torrent/peerconn.go index 607ec10358..bb097e9e60 100644 --- a/vendor/github.com/anacrolix/torrent/peerconn.go +++ b/vendor/github.com/anacrolix/torrent/peerconn.go @@ -881,6 +881,8 @@ func (c *PeerConn) mainReadLoop() (err error) { var msg pp.Message func() { cl.unlock() + // TODO: Could TryLock and pump for more messages here until we can get the lock and + // process them in a batch. defer cl.lock() err = decoder.Decode(&msg) if err != nil { diff --git a/vendor/github.com/anacrolix/torrent/ratelimitreader.go b/vendor/github.com/anacrolix/torrent/ratelimitreader.go index 39df932628..0a6468ceab 100644 --- a/vendor/github.com/anacrolix/torrent/ratelimitreader.go +++ b/vendor/github.com/anacrolix/torrent/ratelimitreader.go @@ -33,10 +33,10 @@ func (me rateLimitedReader) Read(b []byte) (n int, err error) { if me.l.Burst() != 0 { b = b[:min(len(b), me.l.Burst())] } - t := time.Now() n, err = me.r.Read(b) - r := me.l.ReserveN(t, n) + // golang.org/x/time/rate is completely fucking busted. TODO: Write my own rate limiter. + r := me.l.ReserveN(time.Now(), n) panicif.False(r.OK()) - time.Sleep(r.DelayFrom(t)) + time.Sleep(r.Delay()) return } diff --git a/vendor/github.com/anacrolix/torrent/request-strategy-impls.go b/vendor/github.com/anacrolix/torrent/request-strategy-impls.go index e67bb9f0e3..d375c4b121 100644 --- a/vendor/github.com/anacrolix/torrent/request-strategy-impls.go +++ b/vendor/github.com/anacrolix/torrent/request-strategy-impls.go @@ -1,7 +1,7 @@ package torrent import ( - g "github.com/anacrolix/generics" + "github.com/anacrolix/missinggo/v2/panicif" requestStrategy "github.com/anacrolix/torrent/internal/request-strategy" "github.com/anacrolix/torrent/metainfo" @@ -16,14 +16,20 @@ func (r requestStrategyInputCommon) MaxUnverifiedBytes() int64 { return r.maxUnverifiedBytes } +type torrentFromHashGetter interface { + Get(shortInfohash) (*Torrent, bool) +} + type requestStrategyInputMultiTorrent struct { requestStrategyInputCommon - torrents map[metainfo.Hash]*Torrent + torrents torrentFromHashGetter capFunc storage.TorrentCapacity } func (r requestStrategyInputMultiTorrent) Torrent(ih metainfo.Hash) requestStrategy.Torrent { - return requestStrategyTorrent{g.MapMustGet(r.torrents, ih)} + t, ok := r.torrents.Get(ih) + panicif.False(ok) + return requestStrategyTorrent{t} } func (r requestStrategyInputMultiTorrent) Capacity() (int64, bool) { diff --git a/vendor/github.com/anacrolix/torrent/torrent.go b/vendor/github.com/anacrolix/torrent/torrent.go index 993234add6..31bfc06c74 100644 --- a/vendor/github.com/anacrolix/torrent/torrent.go +++ b/vendor/github.com/anacrolix/torrent/torrent.go @@ -621,7 +621,7 @@ func (t *Torrent) hashInfoBytes(b []byte, info *metainfo.Info) error { if v1Hash == t.infoHash.Value { if info.HasV2() { t.infoHashV2.Set(v2Hash) - cl.torrentsByShortHash[*v2Hash.ToShort()] = t + cl.torrentsByShortHash.Set(*v2Hash.ToShort(), t) } } else if *v2Hash.ToShort() == t.infoHash.Value { if !info.HasV2() { @@ -630,7 +630,7 @@ func (t *Torrent) hashInfoBytes(b []byte, info *metainfo.Info) error { t.infoHashV2.Set(v2Hash) t.infoHash.SetNone() if info.HasV1() { - cl.torrentsByShortHash[v1Hash] = t + cl.torrentsByShortHash.Set(v1Hash, t) t.infoHash.Set(v1Hash) } } @@ -647,7 +647,7 @@ func (t *Torrent) hashInfoBytes(b []byte, info *metainfo.Info) error { } if info.HasV1() { t.infoHash.Set(v1Hash) - cl.torrentsByShortHash[v1Hash] = t + cl.torrentsByShortHash.Set(v1Hash, t) } } else { panic("no expected infohashes") @@ -1102,9 +1102,7 @@ func (t *Torrent) numPiecesCompleted() (num pieceIndex) { func (t *Torrent) close(wg *sync.WaitGroup) { // Should only be called from the Client. panicif.False(t.closed.Set()) - t.eachShortInfohash(func(short [20]byte) { - delete(t.cl.torrentsByShortHash, short) - }) + // We now keep a weak pointer in torrentsByShortHash for asynchronous cleanup like announcing Stopped. t.deferUpdateRegularTrackerAnnouncing() t.closedCtxCancel(errTorrentClosed) t.getInfoCtxCancel(errTorrentClosed) @@ -1801,7 +1799,7 @@ func (t *Torrent) setCachedPieceCompletion(piece int, uncached g.Option[bool]) b // This is missing conditions... do we care? if t.haveAllPieces() { // We may be able to send Completed event. - t.cl.unlockHandlers.deferUpdateTorrentRegularTrackerAnnouncing(t) + t.deferUpdateRegularTrackerAnnouncing() } } } else { @@ -2528,6 +2526,9 @@ func (t *Torrent) newConnsAllowed() bool { if t.closed.IsSet() { return false } + if rl := t.cl.config.DownloadRateLimiter; rl != nil && rl.Tokens() <= 0 { + return false + } if t.needData() { return true } diff --git a/vendor/github.com/anacrolix/torrent/torrents-by-short-infohash.go b/vendor/github.com/anacrolix/torrent/torrents-by-short-infohash.go new file mode 100644 index 0000000000..f3ca331d31 --- /dev/null +++ b/vendor/github.com/anacrolix/torrent/torrents-by-short-infohash.go @@ -0,0 +1,90 @@ +package torrent + +import ( + "iter" + "sync" + "unique" + "weak" +) + +type torrentsByShortHash interface { + Get(key shortInfohash) (*Torrent, bool) + IterKeys() iter.Seq[shortInfohash] + Init() +} + +type syncMapTorrentsByShortHash struct { + inner sync.Map +} + +type ( + syncMapTorrentsByShortHashKey = unique.Handle[shortInfohash] + syncMapTorrentsByShortHashValue = weak.Pointer[Torrent] +) + +// sync.Map is zero initialized, but we want this function in case we switch implementations. +func (me *syncMapTorrentsByShortHash) Init() {} + +func (me *syncMapTorrentsByShortHash) IterKeys(yield func(shortInfohash) bool) { + // Do we have to check the values for weak pointers? Probably should to keep the map clean + // to speed up iteration. I wonder if it will introduce overhead to forSkeys. + for key := range me.iter() { + if !yield(key) { + return + } + } +} + +func (me *syncMapTorrentsByShortHash) iter() iter.Seq2[shortInfohash, *Torrent] { + return func(yield func(shortInfohash, *Torrent) bool) { + me.inner.Range(func(key, value any) bool { + uk := key.(syncMapTorrentsByShortHashKey) + v, ok := me.derefValueOrDelete(uk, value.(syncMapTorrentsByShortHashValue)) + if !ok { + // Current value was lost, move on. + return true + } + return yield(uk.Value(), v) + }) + } +} + +func (me *syncMapTorrentsByShortHash) IsEmpty() bool { + for range me.iter() { + return false + } + return true +} + +func (me *syncMapTorrentsByShortHash) derefValueOrDelete( + key syncMapTorrentsByShortHashKey, + wp syncMapTorrentsByShortHashValue, +) (*Torrent, bool) { + t := wp.Value() + if t != nil { + return t, true + } + me.inner.CompareAndDelete(key, wp) + return nil, false +} + +func (me *syncMapTorrentsByShortHash) Get(ih shortInfohash) (t *Torrent, ok bool) { + key := unique.Make(ih) + v, ok := me.inner.Load(key) + if !ok { + return + } + wp := v.(syncMapTorrentsByShortHashValue) + return me.derefValueOrDelete(key, wp) +} + +// Returns true if the key was newly inserted. +func (me *syncMapTorrentsByShortHash) Set(ih shortInfohash, t *Torrent) bool { + _, loaded := me.inner.Swap(unique.Make(ih), weak.Make(t)) + return !loaded +} + +// Returns true if the key was newly inserted. +func (me *syncMapTorrentsByShortHash) Delete(ih shortInfohash) { + me.inner.Delete(unique.Make(ih)) +} diff --git a/vendor/github.com/anacrolix/torrent/webseed-requesting.go b/vendor/github.com/anacrolix/torrent/webseed-requesting.go index 5f0705aeb9..ba509be5ff 100644 --- a/vendor/github.com/anacrolix/torrent/webseed-requesting.go +++ b/vendor/github.com/anacrolix/torrent/webseed-requesting.go @@ -380,7 +380,8 @@ func (cl *Client) iterPossibleWebseedRequests() iter.Seq2[webseedUniqueRequestKe input, value.pieces, func(ih metainfo.Hash, pieceIndex int, orderState requestStrategy.PieceRequestOrderState) bool { - t := cl.torrentsByShortHash[ih] + t, ok := cl.torrentsByShortHash.Get(ih) + panicif.False(ok) if len(t.webSeeds) == 0 { return true } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md index db27711896..37b9f3f7ed 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.32.2 (2025-11-25) + +* **Dependency Update**: Updated to the latest SDK module versions + # v1.32.1 (2025-11-21) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go index d7a47bc944..d59007fa72 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go @@ -3,4 +3,4 @@ package config // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.32.1" +const goModuleVersion = "1.32.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md index b85786cfa3..547c330072 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.19.2 (2025-11-25) + +* **Dependency Update**: Updated to the latest SDK module versions + # v1.19.1 (2025-11-21) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go index 1464f249c5..ff8fa09d1c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go @@ -3,4 +3,4 @@ package credentials // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.19.1" +const goModuleVersion = "1.19.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/CHANGELOG.md index f9c5fe1ecf..d2fb967dd0 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.61.0 (2025-11-25) + +* **Feature**: Adds support for new route53 feature: accelerated recovery. +* **Bug Fix**: Add error check for endpoint param binding during auth scheme resolution to fix panic reported in #3234 + # v1.60.1 (2025-11-19.2) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_client.go index fe3889813b..fa3cbc39cb 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_client.go @@ -1092,6 +1092,13 @@ func sanitizeURLInput(input interface{}) error { i.Id = &v } + case *UpdateHostedZoneFeaturesInput: + if i.HostedZoneId != nil { + idx := strings.LastIndex(*i.HostedZoneId, `/`) + v := (*i.HostedZoneId)[idx+1:] + i.HostedZoneId = &v + } + default: break } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHealthCheck.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHealthCheck.go index 6019894ddd..80bf6f97a1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHealthCheck.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHealthCheck.go @@ -104,8 +104,8 @@ type UpdateHealthCheckInput struct { // healthy or vice versa. For more information, see [How Amazon Route 53 Determines Whether an Endpoint Is Healthy]in the Amazon Route 53 // Developer Guide. // - // If you don't specify a value for FailureThreshold , the default value is three - // health checks. + // Otherwise, if you don't specify a value for FailureThreshold , the default value + // is three health checks. // // [How Amazon Route 53 Determines Whether an Endpoint Is Healthy]: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-determining-health-of-endpoints.html FailureThreshold *int32 diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHostedZoneFeatures.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHostedZoneFeatures.go new file mode 100644 index 0000000000..6ba1977eb4 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/api_op_UpdateHostedZoneFeatures.go @@ -0,0 +1,165 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package route53 + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// Updates the features configuration for a hosted zone. This operation allows you +// to enable or disable specific features for your hosted zone, such as accelerated +// recovery. +// +// Accelerated recovery enables you to update DNS records in your public hosted +// zone even when the us-east-1 region is unavailable. +func (c *Client) UpdateHostedZoneFeatures(ctx context.Context, params *UpdateHostedZoneFeaturesInput, optFns ...func(*Options)) (*UpdateHostedZoneFeaturesOutput, error) { + if params == nil { + params = &UpdateHostedZoneFeaturesInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "UpdateHostedZoneFeatures", params, optFns, c.addOperationUpdateHostedZoneFeaturesMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*UpdateHostedZoneFeaturesOutput) + out.ResultMetadata = metadata + return out, nil +} + +type UpdateHostedZoneFeaturesInput struct { + + // The ID of the hosted zone for which you want to update features. This is the + // unique identifier for your hosted zone. + // + // This member is required. + HostedZoneId *string + + // Specifies whether to enable accelerated recovery for the hosted zone. Set to + // true to enable accelerated recovery, or false to disable it. + EnableAcceleratedRecovery *bool + + noSmithyDocumentSerde +} + +type UpdateHostedZoneFeaturesOutput struct { + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationUpdateHostedZoneFeaturesMiddlewares(stack *middleware.Stack, options Options) (err error) { + if err := stack.Serialize.Add(&setOperationInputMiddleware{}, middleware.After); err != nil { + return err + } + err = stack.Serialize.Add(&awsRestxml_serializeOpUpdateHostedZoneFeatures{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpUpdateHostedZoneFeatures{}, middleware.After) + if err != nil { + return err + } + if err := addProtocolFinalizerMiddlewares(stack, options, "UpdateHostedZoneFeatures"); err != nil { + return fmt.Errorf("add protocol finalizers: %v", err) + } + + if err = addlegacyEndpointContextSetter(stack, options); err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = addClientRequestID(stack); err != nil { + return err + } + if err = addComputeContentLength(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addComputePayloadSHA256(stack); err != nil { + return err + } + if err = addRetry(stack, options); err != nil { + return err + } + if err = addRawResponseToMetadata(stack); err != nil { + return err + } + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { + return err + } + if err = addClientUserAgent(stack, options); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { + return err + } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } + if err = addCredentialSource(stack, options); err != nil { + return err + } + if err = addOpUpdateHostedZoneFeaturesValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opUpdateHostedZoneFeatures(options.Region), middleware.Before); err != nil { + return err + } + if err = addRecursionDetection(stack); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addSanitizeURLMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + if err = addDisableHTTPSMiddleware(stack, options); err != nil { + return err + } + if err = addInterceptBeforeRetryLoop(stack, options); err != nil { + return err + } + if err = addInterceptAttempt(stack, options); err != nil { + return err + } + if err = addInterceptors(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opUpdateHostedZoneFeatures(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "UpdateHostedZoneFeatures", + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/auth.go index aa2929ba64..f76bb1a035 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/auth.go @@ -16,8 +16,9 @@ import ( "strings" ) -func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) error { params.Region = options.Region + return nil } type setLegacyContextSigningOptionsMiddleware struct { @@ -94,14 +95,16 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) (*AuthResolverParameters, error) { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(ctx, params, input, options) + if err := bindAuthParamsRegion(ctx, params, input, options); err != nil { + return nil, err + } - return params + return params, nil } // AuthSchemeResolver returns a set of possible authentication options for an @@ -152,7 +155,10 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") defer span.End() - params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + params, err := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + if err != nil { + return out, metadata, fmt.Errorf("bind auth scheme params: %w", err) + } options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/deserializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/deserializers.go index ddd97661dd..0fde002600 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/deserializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/deserializers.go @@ -10808,6 +10808,87 @@ func awsRestxml_deserializeOpDocumentUpdateHostedZoneCommentOutput(v **UpdateHos return nil } +type awsRestxml_deserializeOpUpdateHostedZoneFeatures struct { +} + +func (*awsRestxml_deserializeOpUpdateHostedZoneFeatures) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpUpdateHostedZoneFeatures) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorUpdateHostedZoneFeatures(response, &metadata) + } + output := &UpdateHostedZoneFeaturesOutput{} + out.Result = output + + span.End() + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorUpdateHostedZoneFeatures(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + case strings.EqualFold("InvalidInput", errorCode): + return awsRestxml_deserializeErrorInvalidInput(response, errorBody) + + case strings.EqualFold("LimitsExceeded", errorCode): + return awsRestxml_deserializeErrorLimitsExceeded(response, errorBody) + + case strings.EqualFold("NoSuchHostedZone", errorCode): + return awsRestxml_deserializeErrorNoSuchHostedZone(response, errorBody) + + case strings.EqualFold("PriorRequestNotComplete", errorCode): + return awsRestxml_deserializeErrorPriorRequestNotComplete(response, errorBody) + + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsRestxml_deserializeOpUpdateTrafficPolicyComment struct { } @@ -17568,6 +17649,12 @@ func awsRestxml_deserializeDocumentHostedZone(v **types.HostedZone, decoder smit return err } + case strings.EqualFold("Features", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentHostedZoneFeatures(&sv.Features, nodeDecoder); err != nil { + return err + } + case strings.EqualFold("Id", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -17745,6 +17832,110 @@ func awsRestxml_deserializeDocumentHostedZoneConfig(v **types.HostedZoneConfig, return nil } +func awsRestxml_deserializeDocumentHostedZoneFailureReasons(v **types.HostedZoneFailureReasons, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.HostedZoneFailureReasons + if *v == nil { + sv = &types.HostedZoneFailureReasons{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("AcceleratedRecovery", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.AcceleratedRecovery = ptr.String(xtv) + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentHostedZoneFeatures(v **types.HostedZoneFeatures, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.HostedZoneFeatures + if *v == nil { + sv = &types.HostedZoneFeatures{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("AcceleratedRecoveryStatus", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.AcceleratedRecoveryStatus = types.AcceleratedRecoveryStatus(xtv) + } + + case strings.EqualFold("FailureReasons", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentHostedZoneFailureReasons(&sv.FailureReasons, nodeDecoder); err != nil { + return err + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + func awsRestxml_deserializeDocumentHostedZoneLimit(v **types.HostedZoneLimit, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/endpoints.go index 6482bf9394..b4764240a5 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/endpoints.go @@ -15,6 +15,7 @@ import ( smithy "github.com/aws/smithy-go" smithyauth "github.com/aws/smithy-go/auth" smithyendpoints "github.com/aws/smithy-go/endpoints" + "github.com/aws/smithy-go/endpoints/private/rulesfn" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" "github.com/aws/smithy-go/tracing" @@ -222,7 +223,7 @@ func bindRegion(region string) (*string, error) { if region == "" { return nil, nil } - if !smithyhttp.ValidHostLabel(region) { + if !rulesfn.IsValidHostLabel(region, true) { return nil, fmt.Errorf("invalid input region %s", region) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/generated.json b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/generated.json index fe7396fcc5..e88535a567 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/generated.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/generated.json @@ -76,6 +76,7 @@ "api_op_TestDNSAnswer.go", "api_op_UpdateHealthCheck.go", "api_op_UpdateHostedZoneComment.go", + "api_op_UpdateHostedZoneFeatures.go", "api_op_UpdateTrafficPolicyComment.go", "api_op_UpdateTrafficPolicyInstance.go", "auth.go", diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/go_module_metadata.go index 4ea376f326..f61847792a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/go_module_metadata.go @@ -3,4 +3,4 @@ package route53 // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.60.1" +const goModuleVersion = "1.61.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/internal/endpoints/endpoints.go index e761afdcef..6594a28a18 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/internal/endpoints/endpoints.go @@ -219,6 +219,13 @@ var defaultPartitions = endpoints.Partitions{ { ID: "aws-eusc", Defaults: map[endpoints.DefaultKey]endpoints.Endpoint{ + { + Variant: endpoints.DualStackVariant, + }: { + Hostname: "route53.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: endpoints.FIPSVariant, }: { @@ -226,6 +233,13 @@ var defaultPartitions = endpoints.Partitions{ Protocols: []string{"https"}, SignatureVersions: []string{"v4"}, }, + { + Variant: endpoints.FIPSVariant | endpoints.DualStackVariant, + }: { + Hostname: "route53-fips.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: 0, }: { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/serializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/serializers.go index f2c0d921a0..a6ed5ade62 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/serializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/serializers.go @@ -5986,6 +5986,111 @@ func awsRestxml_serializeOpDocumentUpdateHostedZoneCommentInput(v *UpdateHostedZ return nil } +type awsRestxml_serializeOpUpdateHostedZoneFeatures struct { +} + +func (*awsRestxml_serializeOpUpdateHostedZoneFeatures) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpUpdateHostedZoneFeatures) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*UpdateHostedZoneFeaturesInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/2013-04-01/hostedzone/{HostedZoneId}/features") + request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath) + request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery) + request.Method = "POST" + var restEncoder *httpbinding.Encoder + if request.URL.RawPath == "" { + restEncoder, err = httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + } else { + request.URL.RawPath = smithyhttp.JoinPath(request.URL.RawPath, opPath) + restEncoder, err = httpbinding.NewEncoderWithRawPath(request.URL.Path, request.URL.RawPath, request.URL.RawQuery, request.Header) + } + + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if err := awsRestxml_serializeOpHttpBindingsUpdateHostedZoneFeaturesInput(input, restEncoder); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + restEncoder.SetHeader("Content-Type").String("application/xml") + + xmlEncoder := smithyxml.NewEncoder(bytes.NewBuffer(nil)) + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "UpdateHostedZoneFeaturesRequest", + }, + Attr: rootAttr, + } + root.Attr = append(root.Attr, smithyxml.NewNamespaceAttribute("", "https://route53.amazonaws.com/doc/2013-04-01/")) + if err := awsRestxml_serializeOpDocumentUpdateHostedZoneFeaturesInput(input, xmlEncoder.RootElement(root)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + if request, err = request.SetStream(bytes.NewReader(xmlEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + endTimer() + span.End() + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsUpdateHostedZoneFeaturesInput(v *UpdateHostedZoneFeaturesInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + if v.HostedZoneId == nil || len(*v.HostedZoneId) == 0 { + return &smithy.SerializationError{Err: fmt.Errorf("input member HostedZoneId must not be empty")} + } + if v.HostedZoneId != nil { + if err := encoder.SetURI("HostedZoneId").String(*v.HostedZoneId); err != nil { + return err + } + } + + return nil +} + +func awsRestxml_serializeOpDocumentUpdateHostedZoneFeaturesInput(v *UpdateHostedZoneFeaturesInput, value smithyxml.Value) error { + defer value.Close() + if v.EnableAcceleratedRecovery != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "EnableAcceleratedRecovery", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.Boolean(*v.EnableAcceleratedRecovery) + } + return nil +} + type awsRestxml_serializeOpUpdateTrafficPolicyComment struct { } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/enums.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/enums.go index a2e7926f87..e6d21f422c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/enums.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/enums.go @@ -2,6 +2,37 @@ package types +type AcceleratedRecoveryStatus string + +// Enum values for AcceleratedRecoveryStatus +const ( + AcceleratedRecoveryStatusEnabling AcceleratedRecoveryStatus = "ENABLING" + AcceleratedRecoveryStatusEnableFailed AcceleratedRecoveryStatus = "ENABLE_FAILED" + AcceleratedRecoveryStatusEnablingHostedZoneLocked AcceleratedRecoveryStatus = "ENABLING_HOSTED_ZONE_LOCKED" + AcceleratedRecoveryStatusEnabled AcceleratedRecoveryStatus = "ENABLED" + AcceleratedRecoveryStatusDisabling AcceleratedRecoveryStatus = "DISABLING" + AcceleratedRecoveryStatusDisableFailed AcceleratedRecoveryStatus = "DISABLE_FAILED" + AcceleratedRecoveryStatusDisabled AcceleratedRecoveryStatus = "DISABLED" + AcceleratedRecoveryStatusDisablingHostedZoneLocked AcceleratedRecoveryStatus = "DISABLING_HOSTED_ZONE_LOCKED" +) + +// Values returns all known values for AcceleratedRecoveryStatus. Note that this +// can be expanded in the future, and so it is only as up to date as the client. +// +// The ordering of this slice is not guaranteed to be stable across updates. +func (AcceleratedRecoveryStatus) Values() []AcceleratedRecoveryStatus { + return []AcceleratedRecoveryStatus{ + "ENABLING", + "ENABLE_FAILED", + "ENABLING_HOSTED_ZONE_LOCKED", + "ENABLED", + "DISABLING", + "DISABLE_FAILED", + "DISABLED", + "DISABLING_HOSTED_ZONE_LOCKED", + } +} + type AccountLimitType string // Enum values for AccountLimitType diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/types.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/types.go index e7a9ae9d4d..63bc9dd711 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/types.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/types/types.go @@ -995,8 +995,11 @@ type HealthCheckConfig struct { // healthy or vice versa. For more information, see [How Amazon Route 53 Determines Whether an Endpoint Is Healthy]in the Amazon Route 53 // Developer Guide. // - // If you don't specify a value for FailureThreshold , the default value is three - // health checks. + // FailureThreshold is not supported when you specify a value for Type of + // RECOVERY_CONTROL . + // + // Otherwise, if you don't specify a value for FailureThreshold , the default value + // is three health checks. // // [How Amazon Route 53 Determines Whether an Endpoint Is Healthy]: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-determining-health-of-endpoints.html FailureThreshold *int32 @@ -1143,6 +1146,9 @@ type HealthCheckConfig struct { // display CloudWatch latency graphs on the Health Checks page in the Route 53 // console. // + // MeasureLatency is not supported when you specify a value for Type of + // RECOVERY_CONTROL . + // // You can't change the value of MeasureLatency after you create a health check. MeasureLatency *bool @@ -1169,6 +1175,9 @@ type HealthCheckConfig struct { // from your endpoint and the time that it sends the next health check request. // Each Route 53 health checker makes requests at this interval. // + // RequestInterval is not supported when you specify a value for Type of + // RECOVERY_CONTROL . + // // You can't change the value of RequestInterval after you create a health check. // // If you don't specify a value for RequestInterval , the default value is 30 @@ -1250,6 +1259,10 @@ type HostedZone struct { // and Comment elements don't appear in the response. Config *HostedZoneConfig + // The features configuration for the hosted zone, including accelerated recovery + // settings and status information. + Features *HostedZoneFeatures + // If the hosted zone was created by another service, the service that created the // hosted zone. When a hosted zone is created by another service, you can't edit or // delete it using Route 53. @@ -1275,6 +1288,31 @@ type HostedZoneConfig struct { noSmithyDocumentSerde } +// Contains information about why certain features failed to be enabled or +// configured for the hosted zone. +type HostedZoneFailureReasons struct { + + // The reason why accelerated recovery failed to be enabled or disabled for the + // hosted zone, if applicable. + AcceleratedRecovery *string + + noSmithyDocumentSerde +} + +// Represents the features configuration for a hosted zone, including the status +// of various features and any associated failure reasons. +type HostedZoneFeatures struct { + + // The current status of accelerated recovery for the hosted zone. + AcceleratedRecoveryStatus AcceleratedRecoveryStatus + + // Information about any failures that occurred when attempting to enable or + // configure features for the hosted zone. + FailureReasons *HostedZoneFailureReasons + + noSmithyDocumentSerde +} + // A complex type that contains the type of limit that you specified in the // request and the current value for that limit. type HostedZoneLimit struct { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/validators.go b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/validators.go index d34881a781..e021931748 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/route53/validators.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/route53/validators.go @@ -1090,6 +1090,26 @@ func (m *validateOpUpdateHostedZoneComment) HandleInitialize(ctx context.Context return next.HandleInitialize(ctx, in) } +type validateOpUpdateHostedZoneFeatures struct { +} + +func (*validateOpUpdateHostedZoneFeatures) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpUpdateHostedZoneFeatures) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*UpdateHostedZoneFeaturesInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpUpdateHostedZoneFeaturesInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + type validateOpUpdateTrafficPolicyComment struct { } @@ -1346,6 +1366,10 @@ func addOpUpdateHostedZoneCommentValidationMiddleware(stack *middleware.Stack) e return stack.Initialize.Add(&validateOpUpdateHostedZoneComment{}, middleware.After) } +func addOpUpdateHostedZoneFeaturesValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpUpdateHostedZoneFeatures{}, middleware.After) +} + func addOpUpdateTrafficPolicyCommentValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpUpdateTrafficPolicyComment{}, middleware.After) } @@ -2558,6 +2582,21 @@ func validateOpUpdateHostedZoneCommentInput(v *UpdateHostedZoneCommentInput) err } } +func validateOpUpdateHostedZoneFeaturesInput(v *UpdateHostedZoneFeaturesInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "UpdateHostedZoneFeaturesInput"} + if v.HostedZoneId == nil { + invalidParams.Add(smithy.NewErrParamRequired("HostedZoneId")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + func validateOpUpdateTrafficPolicyCommentInput(v *UpdateTrafficPolicyCommentInput) error { if v == nil { return nil diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md index 420bc4949e..fa50673703 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.0.2 (2025-11-25) + +* **Bug Fix**: Add error check for endpoint param binding during auth scheme resolution to fix panic reported in #3234 + # v1.0.1 (2025-11-19.2) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/auth.go index a9fadf4d10..cf6b365041 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/auth.go @@ -16,8 +16,9 @@ import ( "strings" ) -func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) error { params.Region = options.Region + return nil } type setLegacyContextSigningOptionsMiddleware struct { @@ -94,14 +95,16 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) (*AuthResolverParameters, error) { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(ctx, params, input, options) + if err := bindAuthParamsRegion(ctx, params, input, options); err != nil { + return nil, err + } - return params + return params, nil } // AuthSchemeResolver returns a set of possible authentication options for an @@ -158,7 +161,10 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") defer span.End() - params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + params, err := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + if err != nil { + return out, metadata, fmt.Errorf("bind auth scheme params: %w", err) + } options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/endpoints.go index b9b0eac28b..db2e6a62a3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/endpoints.go @@ -14,6 +14,7 @@ import ( internalendpoints "github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints" smithyauth "github.com/aws/smithy-go/auth" smithyendpoints "github.com/aws/smithy-go/endpoints" + "github.com/aws/smithy-go/endpoints/private/rulesfn" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" "github.com/aws/smithy-go/tracing" @@ -221,7 +222,7 @@ func bindRegion(region string) (*string, error) { if region == "" { return nil, nil } - if !smithyhttp.ValidHostLabel(region) { + if !rulesfn.IsValidHostLabel(region, true) { return nil, fmt.Errorf("invalid input region %s", region) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go index f794373ee7..4b1b814d13 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go @@ -3,4 +3,4 @@ package signin // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.0.1" +const goModuleVersion = "1.0.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints/endpoints.go index ad431b9e91..cfb2efea8a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints/endpoints.go @@ -179,6 +179,13 @@ var defaultPartitions = endpoints.Partitions{ { ID: "aws-eusc", Defaults: map[endpoints.DefaultKey]endpoints.Endpoint{ + { + Variant: endpoints.DualStackVariant, + }: { + Hostname: "signin.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: endpoints.FIPSVariant, }: { @@ -186,6 +193,13 @@ var defaultPartitions = endpoints.Partitions{ Protocols: []string{"https"}, SignatureVersions: []string{"v4"}, }, + { + Variant: endpoints.FIPSVariant | endpoints.DualStackVariant, + }: { + Hostname: "signin-fips.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: 0, }: { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md index 83a1199982..4c047bfd3d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.30.5 (2025-11-25) + +* **Bug Fix**: Add error check for endpoint param binding during auth scheme resolution to fix panic reported in #3234 + # v1.30.4 (2025-11-19.2) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go index 708e53c5ad..c658615fde 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go @@ -16,8 +16,9 @@ import ( "strings" ) -func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) error { params.Region = options.Region + return nil } type setLegacyContextSigningOptionsMiddleware struct { @@ -94,14 +95,16 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) (*AuthResolverParameters, error) { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(ctx, params, input, options) + if err := bindAuthParamsRegion(ctx, params, input, options); err != nil { + return nil, err + } - return params + return params, nil } // AuthSchemeResolver returns a set of possible authentication options for an @@ -176,7 +179,10 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") defer span.End() - params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + params, err := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + if err != nil { + return out, metadata, fmt.Errorf("bind auth scheme params: %w", err) + } options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go index dfeacc1076..551f05974e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go @@ -14,6 +14,7 @@ import ( internalendpoints "github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints" smithyauth "github.com/aws/smithy-go/auth" smithyendpoints "github.com/aws/smithy-go/endpoints" + "github.com/aws/smithy-go/endpoints/private/rulesfn" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" "github.com/aws/smithy-go/tracing" @@ -221,7 +222,7 @@ func bindRegion(region string) (*string, error) { if region == "" { return nil, nil } - if !smithyhttp.ValidHostLabel(region) { + if !rulesfn.IsValidHostLabel(region, true) { return nil, fmt.Errorf("invalid input region %s", region) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go index 376b96cbcb..29242d0e06 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go @@ -3,4 +3,4 @@ package sso // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.30.4" +const goModuleVersion = "1.30.5" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go index 8bb8730be0..bbac359645 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go @@ -445,6 +445,13 @@ var defaultPartitions = endpoints.Partitions{ { ID: "aws-eusc", Defaults: map[endpoints.DefaultKey]endpoints.Endpoint{ + { + Variant: endpoints.DualStackVariant, + }: { + Hostname: "portal.sso.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: endpoints.FIPSVariant, }: { @@ -452,6 +459,13 @@ var defaultPartitions = endpoints.Partitions{ Protocols: []string{"https"}, SignatureVersions: []string{"v4"}, }, + { + Variant: endpoints.FIPSVariant | endpoints.DualStackVariant, + }: { + Hostname: "portal.sso-fips.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: 0, }: { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md index afc024c5d3..bc047472e9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.35.10 (2025-11-25) + +* **Bug Fix**: Add error check for endpoint param binding during auth scheme resolution to fix panic reported in #3234 + # v1.35.9 (2025-11-21) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go index 89b01c629d..5f253df305 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go @@ -16,8 +16,9 @@ import ( "strings" ) -func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) error { params.Region = options.Region + return nil } type setLegacyContextSigningOptionsMiddleware struct { @@ -94,14 +95,16 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) (*AuthResolverParameters, error) { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(ctx, params, input, options) + if err := bindAuthParamsRegion(ctx, params, input, options); err != nil { + return nil, err + } - return params + return params, nil } // AuthSchemeResolver returns a set of possible authentication options for an @@ -170,7 +173,10 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") defer span.End() - params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + params, err := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + if err != nil { + return out, metadata, fmt.Errorf("bind auth scheme params: %w", err) + } options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go index 3deb443b28..884983eb4d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go @@ -14,6 +14,7 @@ import ( internalendpoints "github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints" smithyauth "github.com/aws/smithy-go/auth" smithyendpoints "github.com/aws/smithy-go/endpoints" + "github.com/aws/smithy-go/endpoints/private/rulesfn" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" "github.com/aws/smithy-go/tracing" @@ -221,7 +222,7 @@ func bindRegion(region string) (*string, error) { if region == "" { return nil, nil } - if !smithyhttp.ValidHostLabel(region) { + if !rulesfn.IsValidHostLabel(region, true) { return nil, fmt.Errorf("invalid input region %s", region) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go index fec9a00512..d93030ff97 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go @@ -3,4 +3,4 @@ package ssooidc // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.35.9" +const goModuleVersion = "1.35.10" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go index 1144a8659d..2088fc7fb2 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go @@ -448,6 +448,13 @@ var defaultPartitions = endpoints.Partitions{ { ID: "aws-eusc", Defaults: map[endpoints.DefaultKey]endpoints.Endpoint{ + { + Variant: endpoints.DualStackVariant, + }: { + Hostname: "oidc.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: endpoints.FIPSVariant, }: { @@ -455,6 +462,13 @@ var defaultPartitions = endpoints.Partitions{ Protocols: []string{"https"}, SignatureVersions: []string{"v4"}, }, + { + Variant: endpoints.FIPSVariant | endpoints.DualStackVariant, + }: { + Hostname: "oidc-fips.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: 0, }: { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md index cf957394d7..166c58455b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.41.2 (2025-11-25) + +* **Bug Fix**: Add error check for endpoint param binding during auth scheme resolution to fix panic reported in #3234 + # v1.41.1 (2025-11-19.2) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go index 2a81b3fb19..4db5a51f93 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go @@ -16,8 +16,9 @@ import ( "strings" ) -func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) error { params.Region = options.Region + return nil } type setLegacyContextSigningOptionsMiddleware struct { @@ -94,14 +95,16 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) (*AuthResolverParameters, error) { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(ctx, params, input, options) + if err := bindAuthParamsRegion(ctx, params, input, options); err != nil { + return nil, err + } - return params + return params, nil } // AuthSchemeResolver returns a set of possible authentication options for an @@ -164,7 +167,10 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") defer span.End() - params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + params, err := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) + if err != nil { + return out, metadata, fmt.Errorf("bind auth scheme params: %w", err) + } options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go index 962596a6ef..c8f9526c78 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go @@ -15,6 +15,7 @@ import ( smithy "github.com/aws/smithy-go" smithyauth "github.com/aws/smithy-go/auth" smithyendpoints "github.com/aws/smithy-go/endpoints" + "github.com/aws/smithy-go/endpoints/private/rulesfn" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" "github.com/aws/smithy-go/tracing" @@ -222,7 +223,7 @@ func bindRegion(region string) (*string, error) { if region == "" { return nil, nil } - if !smithyhttp.ValidHostLabel(region) { + if !rulesfn.IsValidHostLabel(region, true) { return nil, fmt.Errorf("invalid input region %s", region) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go index 6bae0079f3..86a1e11737 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go @@ -3,4 +3,4 @@ package sts // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.41.1" +const goModuleVersion = "1.41.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go index 1ec1ecf652..b2b933c566 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go @@ -359,6 +359,13 @@ var defaultPartitions = endpoints.Partitions{ { ID: "aws-eusc", Defaults: map[endpoints.DefaultKey]endpoints.Endpoint{ + { + Variant: endpoints.DualStackVariant, + }: { + Hostname: "sts.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: endpoints.FIPSVariant, }: { @@ -366,6 +373,13 @@ var defaultPartitions = endpoints.Partitions{ Protocols: []string{"https"}, SignatureVersions: []string{"v4"}, }, + { + Variant: endpoints.FIPSVariant | endpoints.DualStackVariant, + }: { + Hostname: "sts-fips.{region}.api.amazonwebservices.eu", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, { Variant: 0, }: { diff --git a/vendor/github.com/aws/smithy-go/CHANGELOG.md b/vendor/github.com/aws/smithy-go/CHANGELOG.md index 8193f4b396..80af245f08 100644 --- a/vendor/github.com/aws/smithy-go/CHANGELOG.md +++ b/vendor/github.com/aws/smithy-go/CHANGELOG.md @@ -1,3 +1,12 @@ +# Release (2025-12-01) + +## General Highlights +* **Dependency Update**: Updated to the latest SDK module versions + +## Module Highlights +* `github.com/aws/smithy-go`: v1.24.0 + * **Feature**: Improve allocation footprint of the middleware stack. This should convey a ~10% reduction in allocations per SDK request. + # Release (2025-11-03) ## General Highlights diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/doc.go b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/doc.go new file mode 100644 index 0000000000..e24e190dca --- /dev/null +++ b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/doc.go @@ -0,0 +1,4 @@ +// Package rulesfn provides endpoint rule functions for evaluating endpoint +// resolution rules. + +package rulesfn diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/strings.go b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/strings.go new file mode 100644 index 0000000000..5cf4a7b02d --- /dev/null +++ b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/strings.go @@ -0,0 +1,25 @@ +package rulesfn + +// Substring returns the substring of the input provided. If the start or stop +// indexes are not valid for the input nil will be returned. If errors occur +// they will be added to the provided [ErrorCollector]. +func SubString(input string, start, stop int, reverse bool) *string { + if start < 0 || stop < 1 || start >= stop || len(input) < stop { + return nil + } + + for _, r := range input { + if r > 127 { + return nil + } + } + + if !reverse { + v := input[start:stop] + return &v + } + + rStart := len(input) - stop + rStop := len(input) - start + return SubString(input, rStart, rStop, false) +} diff --git a/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/uri.go b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/uri.go new file mode 100644 index 0000000000..0c11541276 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/uri.go @@ -0,0 +1,130 @@ +package rulesfn + +import ( + "fmt" + "net" + "net/url" + "strings" + + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// IsValidHostLabel returns if the input is a single valid [RFC 1123] host +// label. If allowSubDomains is true, will allow validation to include nested +// host labels. Returns false if the input is not a valid host label. If errors +// occur they will be added to the provided [ErrorCollector]. +// +// [RFC 1123]: https://www.ietf.org/rfc/rfc1123.txt +func IsValidHostLabel(input string, allowSubDomains bool) bool { + var labels []string + if allowSubDomains { + labels = strings.Split(input, ".") + } else { + labels = []string{input} + } + + for _, label := range labels { + if !smithyhttp.ValidHostLabel(label) { + return false + } + } + + return true +} + +// ParseURL returns a [URL] if the provided string could be parsed. Returns nil +// if the string could not be parsed. Any parsing error will be added to the +// [ErrorCollector]. +// +// If the input URL string contains an IP6 address with a zone index. The +// returned [builtin.URL.Authority] value will contain the percent escaped (%) +// zone index separator. +func ParseURL(input string) *URL { + u, err := url.Parse(input) + if err != nil { + return nil + } + + if u.RawQuery != "" { + return nil + } + + if u.Scheme != "http" && u.Scheme != "https" { + return nil + } + + normalizedPath := u.Path + if !strings.HasPrefix(normalizedPath, "/") { + normalizedPath = "/" + normalizedPath + } + if !strings.HasSuffix(normalizedPath, "/") { + normalizedPath = normalizedPath + "/" + } + + // IP6 hosts may have zone indexes that need to be escaped to be valid in a + // URI. The Go URL parser will unescape the `%25` into `%`. This needs to + // be reverted since the returned URL will be used in string builders. + authority := strings.ReplaceAll(u.Host, "%", "%25") + + return &URL{ + Scheme: u.Scheme, + Authority: authority, + Path: u.Path, + NormalizedPath: normalizedPath, + IsIp: net.ParseIP(hostnameWithoutZone(u)) != nil, + } +} + +// URL provides the structure describing the parts of a parsed URL returned by +// [ParseURL]. +type URL struct { + Scheme string // https://www.rfc-editor.org/rfc/rfc3986#section-3.1 + Authority string // https://www.rfc-editor.org/rfc/rfc3986#section-3.2 + Path string // https://www.rfc-editor.org/rfc/rfc3986#section-3.3 + NormalizedPath string // https://www.rfc-editor.org/rfc/rfc3986#section-6.2.3 + IsIp bool +} + +// URIEncode returns an percent-encoded [RFC3986 section 2.1] version of the +// input string. +// +// [RFC3986 section 2.1]: https://www.rfc-editor.org/rfc/rfc3986#section-2.1 +func URIEncode(input string) string { + var output strings.Builder + for _, c := range []byte(input) { + if validPercentEncodedChar(c) { + output.WriteByte(c) + continue + } + + fmt.Fprintf(&output, "%%%X", c) + } + + return output.String() +} + +func validPercentEncodedChar(c byte) bool { + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_' || c == '.' || c == '~' +} + +// hostname implements u.Hostname() but strips the ipv6 zone ID (if present) +// such that net.ParseIP can still recognize IPv6 addresses with zone IDs. +// +// FUTURE(10/2023): netip.ParseAddr handles this natively but we can't take +// that package as a dependency yet due to our min go version (1.15, netip +// starts in 1.18). When we align with go runtime deprecation policy in +// 10/2023, we can remove this. +func hostnameWithoutZone(u *url.URL) string { + full := u.Hostname() + + // this more or less mimics the internals of net/ (see unexported + // splitHostZone in that source) but throws the zone away because we don't + // need it + if i := strings.LastIndex(full, "%"); i > -1 { + return full[:i] + } + return full +} diff --git a/vendor/github.com/aws/smithy-go/go_module_metadata.go b/vendor/github.com/aws/smithy-go/go_module_metadata.go index 263059014b..b6c4c2f51c 100644 --- a/vendor/github.com/aws/smithy-go/go_module_metadata.go +++ b/vendor/github.com/aws/smithy-go/go_module_metadata.go @@ -3,4 +3,4 @@ package smithy // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.23.2" +const goModuleVersion = "1.24.0" diff --git a/vendor/github.com/aws/smithy-go/middleware/step_build.go b/vendor/github.com/aws/smithy-go/middleware/step_build.go index cc7fe89c94..db8c26715c 100644 --- a/vendor/github.com/aws/smithy-go/middleware/step_build.go +++ b/vendor/github.com/aws/smithy-go/middleware/step_build.go @@ -1,7 +1,9 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware import ( "context" + "fmt" ) // BuildInput provides the input parameters for the BuildMiddleware to consume. @@ -25,14 +27,14 @@ type BuildHandler interface { } // BuildMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next BuildHandler for further +// build step. Delegates to the next BuildHandler for further // processing. type BuildMiddleware interface { - // Unique ID for the middleware in theBuildStep. The step does not allow - // duplicate IDs. + // ID returns a unique ID for the middleware in the BuildStep. The step does not + // allow duplicate IDs. ID() string - // Invokes the middleware behavior which must delegate to the next handler + // HandleBuild invokes the middleware behavior which must delegate to the next handler // for the middleware chain to continue. The method must return a result or // error to its caller. HandleBuild(ctx context.Context, in BuildInput, next BuildHandler) ( @@ -54,7 +56,9 @@ type buildMiddlewareFunc struct { id string // Middleware function to be called. - fn func(context.Context, BuildInput, BuildHandler) (BuildOutput, Metadata, error) + fn func(context.Context, BuildInput, BuildHandler) ( + BuildOutput, Metadata, error, + ) } // ID returns the unique ID for the middleware. @@ -69,23 +73,22 @@ func (s buildMiddlewareFunc) HandleBuild(ctx context.Context, in BuildInput, nex var _ BuildMiddleware = (buildMiddlewareFunc{}) -// BuildStep provides the ordered grouping of BuildMiddleware to be invoked on -// a handler. +// BuildStep provides the ordered grouping of BuildMiddleware to be +// invoked on a handler. type BuildStep struct { - ids *orderedIDs + head *decoratedBuildHandler + tail *decoratedBuildHandler } -// NewBuildStep returns a BuildStep ready to have middleware for -// initialization added to it. +// NewBuildStep returns an BuildStep ready to have middleware for +// build added to it. func NewBuildStep() *BuildStep { - return &BuildStep{ - ids: newOrderedIDs(baseOrderedItems), - } + return &BuildStep{} } var _ Middleware = (*BuildStep)(nil) -// ID returns the unique name of the step as a middleware. +// ID returns the unique ID of the step as a middleware. func (s *BuildStep) ID() string { return "Build stack step" } @@ -97,77 +100,161 @@ func (s *BuildStep) ID() string { func (s *BuildStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h BuildHandler = buildWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedBuildHandler{ - Next: h, - With: order[i].(BuildMiddleware), - } - } - sIn := BuildInput{ Request: in, } - res, metadata, err := h.HandleBuild(ctx, sIn) + wh := &buildWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleBuild(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleBuild(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *BuildStep) Get(id string) (BuildMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { + found, _ := s.get(id) + if found == nil { return nil, false } - return get.(BuildMiddleware), ok + + return found.With, true } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *BuildStep) Add(m BuildMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedBuildHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedBuildHandler{s.head, m} + } else { + tail := &decoratedBuildHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } -// Insert injects the middleware relative to an existing middleware id. -// Returns an error if the original middleware does not exist, or the middleware +// Insert injects the middleware relative to an existing middleware ID. +// Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *BuildStep) Insert(m BuildMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + found, prev := s.get(relativeTo) + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedBuildHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedBuildHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedBuildHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedBuildHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. -// Returns the middleware removed, or an error if the middleware to be removed +// Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *BuildStep) Swap(id string, m BuildMiddleware) (BuildMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + found, _ := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", m.ID()) } - return removed.(BuildMiddleware), nil + swapped := found.With + found.With = m + return swapped, nil } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *BuildStep) Remove(id string) (BuildMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + found, prev := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", id) } - return removed.(BuildMiddleware), nil + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedBuildHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle + } + + return found.With, nil } // List returns a list of the middleware in the step. func (s *BuildStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *buildWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedBuildHandler); ok { + h = hnext + } else { + break + } + } + return ids } // Clear removes all middleware in the step. func (s *BuildStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil +} + +func (s *BuildStep) get(id string) (found, prev *decoratedBuildHandler) { + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + return + } + prev = h + if h.Next == nil { + return + } + + // once executed, tail.Next of the list will be set to an + // *buildWrapHandler + h, _ = h.Next.(*decoratedBuildHandler) + } + return } type buildWrapHandler struct { @@ -176,7 +263,7 @@ type buildWrapHandler struct { var _ BuildHandler = (*buildWrapHandler)(nil) -// Implements BuildHandler, converts types and delegates to underlying +// HandleBuild implements BuildHandler, converts types and delegates to underlying // generic handler. func (w buildWrapHandler) HandleBuild(ctx context.Context, in BuildInput) ( out BuildOutput, metadata Metadata, err error, @@ -200,12 +287,12 @@ func (h decoratedBuildHandler) HandleBuild(ctx context.Context, in BuildInput) ( return h.With.HandleBuild(ctx, in, h.Next) } -// BuildHandlerFunc provides a wrapper around a function to be used as a build middleware handler. +// BuildHandlerFunc provides a wrapper around a function to be used as buildMiddleware. type BuildHandlerFunc func(context.Context, BuildInput) (BuildOutput, Metadata, error) -// HandleBuild invokes the wrapped function with the provided arguments. -func (b BuildHandlerFunc) HandleBuild(ctx context.Context, in BuildInput) (BuildOutput, Metadata, error) { - return b(ctx, in) +// HandleBuild calls the wrapped function with the provided arguments. +func (f BuildHandlerFunc) HandleBuild(ctx context.Context, in BuildInput) (BuildOutput, Metadata, error) { + return f(ctx, in) } var _ BuildHandler = BuildHandlerFunc(nil) diff --git a/vendor/github.com/aws/smithy-go/middleware/step_deserialize.go b/vendor/github.com/aws/smithy-go/middleware/step_deserialize.go index 9a6679a59b..1f337f2dbc 100644 --- a/vendor/github.com/aws/smithy-go/middleware/step_deserialize.go +++ b/vendor/github.com/aws/smithy-go/middleware/step_deserialize.go @@ -1,7 +1,9 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware import ( "context" + "fmt" ) // DeserializeInput provides the input parameters for the DeserializeInput to @@ -11,10 +13,7 @@ type DeserializeInput struct { Request interface{} } -// DeserializeOutput provides the result returned by the next -// DeserializeHandler. The DeserializeMiddleware should deserialize the -// RawResponse into a Result that can be consumed by middleware higher up in -// the stack. +// DeserializeOutput provides the result returned by the next DeserializeHandler. type DeserializeOutput struct { RawResponse interface{} Result interface{} @@ -29,7 +28,7 @@ type DeserializeHandler interface { } // DeserializeMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next DeserializeHandler for further +// deserialize step. Delegates to the next DeserializeHandler for further // processing. type DeserializeMiddleware interface { // ID returns a unique ID for the middleware in the DeserializeStep. The step does not @@ -44,8 +43,8 @@ type DeserializeMiddleware interface { ) } -// DeserializeMiddlewareFunc returns a DeserializeMiddleware with the unique ID -// provided, and the func to be invoked. +// DeserializeMiddlewareFunc returns a DeserializeMiddleware with the unique ID provided, +// and the func to be invoked. func DeserializeMiddlewareFunc(id string, fn func(context.Context, DeserializeInput, DeserializeHandler) (DeserializeOutput, Metadata, error)) DeserializeMiddleware { return deserializeMiddlewareFunc{ id: id, @@ -78,16 +77,14 @@ var _ DeserializeMiddleware = (deserializeMiddlewareFunc{}) // DeserializeStep provides the ordered grouping of DeserializeMiddleware to be // invoked on a handler. type DeserializeStep struct { - ids *orderedIDs + head *decoratedDeserializeHandler + tail *decoratedDeserializeHandler } -// NewDeserializeStep returns a DeserializeStep ready to have middleware for -// initialization added to it. +// NewDeserializeStep returns an DeserializeStep ready to have middleware for +// deserialize added to it. func NewDeserializeStep() *DeserializeStep { - return &DeserializeStep{ - // downstream SDK typically has larger Deserialize step - ids: newOrderedIDs(baseOrderedItems * 2), - } + return &DeserializeStep{} } var _ Middleware = (*DeserializeStep)(nil) @@ -104,77 +101,161 @@ func (s *DeserializeStep) ID() string { func (s *DeserializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h DeserializeHandler = deserializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedDeserializeHandler{ - Next: h, - With: order[i].(DeserializeMiddleware), - } - } - sIn := DeserializeInput{ Request: in, } - res, metadata, err := h.HandleDeserialize(ctx, sIn) + wh := &deserializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleDeserialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleDeserialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *DeserializeStep) Get(id string) (DeserializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { + found, _ := s.get(id) + if found == nil { return nil, false } - return get.(DeserializeMiddleware), ok + + return found.With, true } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *DeserializeStep) Add(m DeserializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedDeserializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedDeserializeHandler{s.head, m} + } else { + tail := &decoratedDeserializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *DeserializeStep) Insert(m DeserializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + found, prev := s.get(relativeTo) + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedDeserializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedDeserializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedDeserializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedDeserializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *DeserializeStep) Swap(id string, m DeserializeMiddleware) (DeserializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + found, _ := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", m.ID()) } - return removed.(DeserializeMiddleware), nil + swapped := found.With + found.With = m + return swapped, nil } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *DeserializeStep) Remove(id string) (DeserializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + found, prev := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedDeserializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(DeserializeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *DeserializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *deserializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedDeserializeHandler); ok { + h = hnext + } else { + break + } + } + return ids } // Clear removes all middleware in the step. func (s *DeserializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil +} + +func (s *DeserializeStep) get(id string) (found, prev *decoratedDeserializeHandler) { + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + return + } + prev = h + if h.Next == nil { + return + } + + // once executed, tail.Next of the list will be set to an + // *deserializeWrapHandler + h, _ = h.Next.(*decoratedDeserializeHandler) + } + return } type deserializeWrapHandler struct { @@ -188,9 +269,10 @@ var _ DeserializeHandler = (*deserializeWrapHandler)(nil) func (w deserializeWrapHandler) HandleDeserialize(ctx context.Context, in DeserializeInput) ( out DeserializeOutput, metadata Metadata, err error, ) { - resp, metadata, err := w.Next.Handle(ctx, in.Request) + res, metadata, err := w.Next.Handle(ctx, in.Request) return DeserializeOutput{ - RawResponse: resp, + RawResponse: res, + Result: nil, }, metadata, err } @@ -207,12 +289,12 @@ func (h decoratedDeserializeHandler) HandleDeserialize(ctx context.Context, in D return h.With.HandleDeserialize(ctx, in, h.Next) } -// DeserializeHandlerFunc provides a wrapper around a function to be used as a deserialize middleware handler. +// DeserializeHandlerFunc provides a wrapper around a function to be used as deserializeMiddleware. type DeserializeHandlerFunc func(context.Context, DeserializeInput) (DeserializeOutput, Metadata, error) -// HandleDeserialize invokes the wrapped function with the given arguments. -func (d DeserializeHandlerFunc) HandleDeserialize(ctx context.Context, in DeserializeInput) (DeserializeOutput, Metadata, error) { - return d(ctx, in) +// HandleDeserialize calls the wrapped function with the provided arguments. +func (f DeserializeHandlerFunc) HandleDeserialize(ctx context.Context, in DeserializeInput) (DeserializeOutput, Metadata, error) { + return f(ctx, in) } var _ DeserializeHandler = DeserializeHandlerFunc(nil) diff --git a/vendor/github.com/aws/smithy-go/middleware/step_finalize.go b/vendor/github.com/aws/smithy-go/middleware/step_finalize.go index 76eab24909..1a0ad9fb88 100644 --- a/vendor/github.com/aws/smithy-go/middleware/step_finalize.go +++ b/vendor/github.com/aws/smithy-go/middleware/step_finalize.go @@ -1,6 +1,10 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // FinalizeInput provides the input parameters for the FinalizeMiddleware to // consume. FinalizeMiddleware may modify the Request value before forwarding @@ -23,7 +27,7 @@ type FinalizeHandler interface { } // FinalizeMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next FinalizeHandler for further +// finalize step. Delegates to the next FinalizeHandler for further // processing. type FinalizeMiddleware interface { // ID returns a unique ID for the middleware in the FinalizeStep. The step does not @@ -38,8 +42,8 @@ type FinalizeMiddleware interface { ) } -// FinalizeMiddlewareFunc returns a FinalizeMiddleware with the unique ID -// provided, and the func to be invoked. +// FinalizeMiddlewareFunc returns a FinalizeMiddleware with the unique ID provided, +// and the func to be invoked. func FinalizeMiddlewareFunc(id string, fn func(context.Context, FinalizeInput, FinalizeHandler) (FinalizeOutput, Metadata, error)) FinalizeMiddleware { return finalizeMiddlewareFunc{ id: id, @@ -72,21 +76,19 @@ var _ FinalizeMiddleware = (finalizeMiddlewareFunc{}) // FinalizeStep provides the ordered grouping of FinalizeMiddleware to be // invoked on a handler. type FinalizeStep struct { - ids *orderedIDs + head *decoratedFinalizeHandler + tail *decoratedFinalizeHandler } -// NewFinalizeStep returns a FinalizeStep ready to have middleware for -// initialization added to it. +// NewFinalizeStep returns an FinalizeStep ready to have middleware for +// finalize added to it. func NewFinalizeStep() *FinalizeStep { - return &FinalizeStep{ - // downstream SDK typically has larger Finalize step - ids: newOrderedIDs(baseOrderedItems * 2), - } + return &FinalizeStep{} } var _ Middleware = (*FinalizeStep)(nil) -// ID returns the unique id of the step as a middleware. +// ID returns the unique ID of the step as a middleware. func (s *FinalizeStep) ID() string { return "Finalize stack step" } @@ -98,77 +100,161 @@ func (s *FinalizeStep) ID() string { func (s *FinalizeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h FinalizeHandler = finalizeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedFinalizeHandler{ - Next: h, - With: order[i].(FinalizeMiddleware), - } - } - sIn := FinalizeInput{ Request: in, } - res, metadata, err := h.HandleFinalize(ctx, sIn) + wh := &finalizeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleFinalize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleFinalize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *FinalizeStep) Get(id string) (FinalizeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { + found, _ := s.get(id) + if found == nil { return nil, false } - return get.(FinalizeMiddleware), ok + + return found.With, true } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *FinalizeStep) Add(m FinalizeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedFinalizeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedFinalizeHandler{s.head, m} + } else { + tail := &decoratedFinalizeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *FinalizeStep) Insert(m FinalizeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + found, prev := s.get(relativeTo) + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedFinalizeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedFinalizeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedFinalizeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedFinalizeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *FinalizeStep) Swap(id string, m FinalizeMiddleware) (FinalizeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + found, _ := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", m.ID()) } - return removed.(FinalizeMiddleware), nil + swapped := found.With + found.With = m + return swapped, nil } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *FinalizeStep) Remove(id string) (FinalizeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + found, prev := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedFinalizeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(FinalizeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *FinalizeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *finalizeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedFinalizeHandler); ok { + h = hnext + } else { + break + } + } + return ids } // Clear removes all middleware in the step. func (s *FinalizeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil +} + +func (s *FinalizeStep) get(id string) (found, prev *decoratedFinalizeHandler) { + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + return + } + prev = h + if h.Next == nil { + return + } + + // once executed, tail.Next of the list will be set to an + // *finalizeWrapHandler + h, _ = h.Next.(*decoratedFinalizeHandler) + } + return } type finalizeWrapHandler struct { @@ -201,10 +287,10 @@ func (h decoratedFinalizeHandler) HandleFinalize(ctx context.Context, in Finaliz return h.With.HandleFinalize(ctx, in, h.Next) } -// FinalizeHandlerFunc provides a wrapper around a function to be used as a finalize middleware handler. +// FinalizeHandlerFunc provides a wrapper around a function to be used as finalizeMiddleware. type FinalizeHandlerFunc func(context.Context, FinalizeInput) (FinalizeOutput, Metadata, error) -// HandleFinalize invokes the wrapped function with the given arguments. +// HandleFinalize calls the wrapped function with the provided arguments. func (f FinalizeHandlerFunc) HandleFinalize(ctx context.Context, in FinalizeInput) (FinalizeOutput, Metadata, error) { return f(ctx, in) } diff --git a/vendor/github.com/aws/smithy-go/middleware/step_initialize.go b/vendor/github.com/aws/smithy-go/middleware/step_initialize.go index 312be3a331..446f3b7bb9 100644 --- a/vendor/github.com/aws/smithy-go/middleware/step_initialize.go +++ b/vendor/github.com/aws/smithy-go/middleware/step_initialize.go @@ -1,10 +1,15 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // InitializeInput wraps the input parameters for the InitializeMiddlewares to // consume. InitializeMiddleware may modify the parameter value before // forwarding it along to the next InitializeHandler. + type InitializeInput struct { Parameters interface{} } @@ -72,15 +77,14 @@ var _ InitializeMiddleware = (initializeMiddlewareFunc{}) // InitializeStep provides the ordered grouping of InitializeMiddleware to be // invoked on a handler. type InitializeStep struct { - ids *orderedIDs + head *decoratedInitializeHandler + tail *decoratedInitializeHandler } // NewInitializeStep returns an InitializeStep ready to have middleware for -// initialization added to it. +// initialize added to it. func NewInitializeStep() *InitializeStep { - return &InitializeStep{ - ids: newOrderedIDs(baseOrderedItems), - } + return &InitializeStep{} } var _ Middleware = (*InitializeStep)(nil) @@ -97,77 +101,161 @@ func (s *InitializeStep) ID() string { func (s *InitializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h InitializeHandler = initializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedInitializeHandler{ - Next: h, - With: order[i].(InitializeMiddleware), - } - } - sIn := InitializeInput{ Parameters: in, } - res, metadata, err := h.HandleInitialize(ctx, sIn) + wh := &initializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleInitialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleInitialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *InitializeStep) Get(id string) (InitializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { + found, _ := s.get(id) + if found == nil { return nil, false } - return get.(InitializeMiddleware), ok + + return found.With, true } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *InitializeStep) Add(m InitializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedInitializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedInitializeHandler{s.head, m} + } else { + tail := &decoratedInitializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *InitializeStep) Insert(m InitializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + found, prev := s.get(relativeTo) + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedInitializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedInitializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedInitializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedInitializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *InitializeStep) Swap(id string, m InitializeMiddleware) (InitializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + found, _ := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", m.ID()) } - return removed.(InitializeMiddleware), nil + swapped := found.With + found.With = m + return swapped, nil } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *InitializeStep) Remove(id string) (InitializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + found, prev := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", id) } - return removed.(InitializeMiddleware), nil + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedInitializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle + } + + return found.With, nil } // List returns a list of the middleware in the step. func (s *InitializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *initializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedInitializeHandler); ok { + h = hnext + } else { + break + } + } + return ids } // Clear removes all middleware in the step. func (s *InitializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil +} + +func (s *InitializeStep) get(id string) (found, prev *decoratedInitializeHandler) { + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + return + } + prev = h + if h.Next == nil { + return + } + + // once executed, tail.Next of the list will be set to an + // *initializeWrapHandler + h, _ = h.Next.(*decoratedInitializeHandler) + } + return } type initializeWrapHandler struct { @@ -200,12 +288,12 @@ func (h decoratedInitializeHandler) HandleInitialize(ctx context.Context, in Ini return h.With.HandleInitialize(ctx, in, h.Next) } -// InitializeHandlerFunc provides a wrapper around a function to be used as an initialize middleware handler. +// InitializeHandlerFunc provides a wrapper around a function to be used as initializeMiddleware. type InitializeHandlerFunc func(context.Context, InitializeInput) (InitializeOutput, Metadata, error) // HandleInitialize calls the wrapped function with the provided arguments. -func (i InitializeHandlerFunc) HandleInitialize(ctx context.Context, in InitializeInput) (InitializeOutput, Metadata, error) { - return i(ctx, in) +func (f InitializeHandlerFunc) HandleInitialize(ctx context.Context, in InitializeInput) (InitializeOutput, Metadata, error) { + return f(ctx, in) } var _ InitializeHandler = InitializeHandlerFunc(nil) diff --git a/vendor/github.com/aws/smithy-go/middleware/step_serialize.go b/vendor/github.com/aws/smithy-go/middleware/step_serialize.go index a4ce4bee3b..942ebb4f3e 100644 --- a/vendor/github.com/aws/smithy-go/middleware/step_serialize.go +++ b/vendor/github.com/aws/smithy-go/middleware/step_serialize.go @@ -1,6 +1,10 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // SerializeInput provides the input parameters for the SerializeMiddleware to // consume. SerializeMiddleware may modify the Request value before forwarding @@ -41,8 +45,8 @@ type SerializeMiddleware interface { ) } -// SerializeMiddlewareFunc returns a SerializeMiddleware with the unique ID -// provided, and the func to be invoked. +// SerializeMiddlewareFunc returns a SerializeMiddleware with the unique ID provided, +// and the func to be invoked. func SerializeMiddlewareFunc(id string, fn func(context.Context, SerializeInput, SerializeHandler) (SerializeOutput, Metadata, error)) SerializeMiddleware { return serializeMiddlewareFunc{ id: id, @@ -75,17 +79,15 @@ var _ SerializeMiddleware = (serializeMiddlewareFunc{}) // SerializeStep provides the ordered grouping of SerializeMiddleware to be // invoked on a handler. type SerializeStep struct { + head *decoratedSerializeHandler + tail *decoratedSerializeHandler newRequest func() interface{} - ids *orderedIDs } -// NewSerializeStep returns a SerializeStep ready to have middleware for -// initialization added to it. The newRequest func parameter is used to -// initialize the transport specific request for the stack SerializeStep to -// serialize the input parameters into. +// NewSerializeStep returns an SerializeStep ready to have middleware for +// serialize added to it. func NewSerializeStep(newRequest func() interface{}) *SerializeStep { return &SerializeStep{ - ids: newOrderedIDs(baseOrderedItems), newRequest: newRequest, } } @@ -104,78 +106,162 @@ func (s *SerializeStep) ID() string { func (s *SerializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h SerializeHandler = serializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedSerializeHandler{ - Next: h, - With: order[i].(SerializeMiddleware), - } - } - sIn := SerializeInput{ Parameters: in, Request: s.newRequest(), } - res, metadata, err := h.HandleSerialize(ctx, sIn) + wh := &serializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleSerialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleSerialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *SerializeStep) Get(id string) (SerializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { + found, _ := s.get(id) + if found == nil { return nil, false } - return get.(SerializeMiddleware), ok + + return found.With, true } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *SerializeStep) Add(m SerializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedSerializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedSerializeHandler{s.head, m} + } else { + tail := &decoratedSerializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *SerializeStep) Insert(m SerializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + found, prev := s.get(relativeTo) + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedSerializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedSerializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedSerializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedSerializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *SerializeStep) Swap(id string, m SerializeMiddleware) (SerializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + found, _ := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", m.ID()) } - return removed.(SerializeMiddleware), nil + swapped := found.With + found.With = m + return swapped, nil } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *SerializeStep) Remove(id string) (SerializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + found, prev := s.get(id) + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedSerializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(SerializeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *SerializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *serializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedSerializeHandler); ok { + h = hnext + } else { + break + } + } + return ids } // Clear removes all middleware in the step. func (s *SerializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil +} + +func (s *SerializeStep) get(id string) (found, prev *decoratedSerializeHandler) { + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + return + } + prev = h + if h.Next == nil { + return + } + + // once executed, tail.Next of the list will be set to an + // *serializeWrapHandler + h, _ = h.Next.(*decoratedSerializeHandler) + } + return } type serializeWrapHandler struct { @@ -184,7 +270,7 @@ type serializeWrapHandler struct { var _ SerializeHandler = (*serializeWrapHandler)(nil) -// Implements SerializeHandler, converts types and delegates to underlying +// HandleSerialize implements SerializeHandler, converts types and delegates to underlying // generic handler. func (w serializeWrapHandler) HandleSerialize(ctx context.Context, in SerializeInput) ( out SerializeOutput, metadata Metadata, err error, @@ -208,12 +294,12 @@ func (h decoratedSerializeHandler) HandleSerialize(ctx context.Context, in Seria return h.With.HandleSerialize(ctx, in, h.Next) } -// SerializeHandlerFunc provides a wrapper around a function to be used as a serialize middleware handler. +// SerializeHandlerFunc provides a wrapper around a function to be used as serializeMiddleware. type SerializeHandlerFunc func(context.Context, SerializeInput) (SerializeOutput, Metadata, error) // HandleSerialize calls the wrapped function with the provided arguments. -func (s SerializeHandlerFunc) HandleSerialize(ctx context.Context, in SerializeInput) (SerializeOutput, Metadata, error) { - return s(ctx, in) +func (f SerializeHandlerFunc) HandleSerialize(ctx context.Context, in SerializeInput) (SerializeOutput, Metadata, error) { + return f(ctx, in) } var _ SerializeHandler = SerializeHandlerFunc(nil) diff --git a/vendor/github.com/charmbracelet/x/ansi/cursor.go b/vendor/github.com/charmbracelet/x/ansi/cursor.go index 4adf689648..3c0f8912ef 100644 --- a/vendor/github.com/charmbracelet/x/ansi/cursor.go +++ b/vendor/github.com/charmbracelet/x/ansi/cursor.go @@ -261,7 +261,7 @@ func CHA(col int) string { // // See: https://vt100.net/docs/vt510-rm/CUP.html func CursorPosition(col, row int) string { - if row <= 0 && col <= 0 { + if row <= 1 && col <= 1 { return CursorHomePosition } @@ -281,7 +281,9 @@ func CUP(col, row int) string { } // CursorHomePosition is a sequence for moving the cursor to the upper left -// corner of the scrolling region. This is equivalent to `CursorPosition(1, 1)`. +// corner of the scrolling region. +// +// This is equivalent to [CursorPosition](1, 1). const CursorHomePosition = "\x1b[H" // SetCursorPosition (CUP) returns a sequence for setting the cursor to the diff --git a/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md index ae1919a867..c97ce3b813 100644 --- a/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md +++ b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [0.6.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.0...v0.6.1) + +### Changed +- Perf improvements: replaced the ASCII lookup table with a simple + function. A bit more cache-friendly. More inlining. +- Bug fix: single regional indicators are now treated as width 2, since that + is what actual terminals do. + ## [0.6.0] [Compare](https://github.com/clipperhouse/displaywidth/compare/v0.5.0...v0.6.0) diff --git a/vendor/github.com/clipperhouse/displaywidth/README.md b/vendor/github.com/clipperhouse/displaywidth/README.md index c423b99524..e9a513cae9 100644 --- a/vendor/github.com/clipperhouse/displaywidth/README.md +++ b/vendor/github.com/clipperhouse/displaywidth/README.md @@ -33,42 +33,82 @@ func main() { } ``` -For most purposes, you should use the `String` or `Bytes` methods. +For most purposes, you should use the `String` or `Bytes` methods. They sum +the widths of grapheme clusters in the string or byte slice. +> Note: in your application, iterating over runes to measure width is likely incorrect; +the smallest unit of display is a grapheme, not a rune. + +### Iterating over graphemes + +If you need the individual graphemes: + +```go +import ( + "fmt" + "github.com/clipperhouse/displaywidth" +) + +func main() { + g := displaywidth.StringGraphemes("Hello, 世界!") + for g.Next() { + width := g.Width() + value := g.Value() + // do something with the width or value + } +} +``` ### Options -You can specify East Asian Width settings. When false (default), -[East Asian Ambiguous characters](https://www.unicode.org/reports/tr11/#Ambiguous) -are treated as width 1. When true, East Asian Ambiguous characters are treated -as width 2. +There is one option, `displaywidth.Options.EastAsianWidth`, which defines +how [East Asian Ambiguous characters](https://www.unicode.org/reports/tr11/#Ambiguous) +are treated. + +When `false` (default), East Asian Ambiguous characters are treated as width 1. +When `true`, they are treated as width 2. + +You may wish to configure this based on environment variables or locale. + `go-runewidth`, for example, does so + [during package initialization](https://github.com/mattn/go-runewidth/blob/master/runewidth.go#L26C1-L45C2). + +`displaywidth` does not do this automatically, we prefer to leave it to you. +You might do something like: ```go -myOptions := displaywidth.Options{ - EastAsianWidth: true, +var width displaywidth.Options // zero value is default + +func init() { + if os.Getenv("EAST_ASIAN_WIDTH") == "true" { + width = displaywidth.Options{EastAsianWidth: true} + } + // or check locale, or any other logic you want } -width := myOptions.String("Hello, 世界!") -fmt.Println(width) +// use it in your logic +func myApp() { + fmt.Println(width.String("Hello, 世界!")) +} ``` -## Technical details +## Technical standards and compatibility This package implements the Unicode East Asian Width standard -([UAX #11](https://www.unicode.org/reports/tr11/)), and handles +([UAX #11](https://www.unicode.org/reports/tr11/tr11-43.html)), and handles [version selectors](https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block)), and [regional indicator pairs](https://en.wikipedia.org/wiki/Regional_indicator_symbol) -(flags). We implement [Unicode TR51](https://unicode.org/reports/tr51/). +(flags). We implement [Unicode TR51](https://www.unicode.org/reports/tr51/tr51-27.html). We are keeping +an eye on [emerging standards](https://www.jeffquast.com/post/state-of-terminal-emulation-2025/). + `clipperhouse/displaywidth`, `mattn/go-runewidth`, and `rivo/uniseg` will -give the same outputs for most real-world text. See extensive details in the +give the same outputs for most real-world text. Extensive details are in the [compatibility analysis](comparison/COMPATIBILITY_ANALYSIS.md). If you wish to investigate the core logic, see the `lookupProperties` and `width` -functions in [width.go](width.go#L135). The essential trie generation logic is in -`buildPropertyBitmap` in [unicode.go](internal/gen/unicode.go#L317). +functions in [width.go](width.go#L139). The essential trie generation logic is in +`buildPropertyBitmap` in [unicode.go](internal/gen/unicode.go#L316). -I (@clipperhouse) am keeping an eye on [emerging standards and test suites](https://www.jeffquast.com/post/state-of-terminal-emulation-2025/). ## Prior Art @@ -93,31 +133,33 @@ goarch: arm64 pkg: github.com/clipperhouse/displaywidth/comparison cpu: Apple M2 -BenchmarkString_Mixed/clipperhouse/displaywidth-8 10469 ns/op 161.15 MB/s 0 B/op 0 allocs/op -BenchmarkString_Mixed/mattn/go-runewidth-8 14250 ns/op 118.39 MB/s 0 B/op 0 allocs/op -BenchmarkString_Mixed/rivo/uniseg-8 19258 ns/op 87.60 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/clipperhouse/displaywidth-8 10326 ns/op 163.37 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/mattn/go-runewidth-8 14415 ns/op 117.03 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/rivo/uniseg-8 19343 ns/op 87.21 MB/s 0 B/op 0 allocs/op -BenchmarkString_EastAsian/clipperhouse/displaywidth-8 10518 ns/op 160.39 MB/s 0 B/op 0 allocs/op -BenchmarkString_EastAsian/mattn/go-runewidth-8 23827 ns/op 70.80 MB/s 0 B/op 0 allocs/op -BenchmarkString_EastAsian/rivo/uniseg-8 19537 ns/op 86.35 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/clipperhouse/displaywidth-8 10561 ns/op 159.74 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/mattn/go-runewidth-8 23790 ns/op 70.91 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/rivo/uniseg-8 19322 ns/op 87.31 MB/s 0 B/op 0 allocs/op -BenchmarkString_ASCII/clipperhouse/displaywidth-8 1027 ns/op 124.61 MB/s 0 B/op 0 allocs/op -BenchmarkString_ASCII/mattn/go-runewidth-8 1166 ns/op 109.78 MB/s 0 B/op 0 allocs/op -BenchmarkString_ASCII/rivo/uniseg-8 1551 ns/op 82.52 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/clipperhouse/displaywidth-8 1033 ns/op 123.88 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/mattn/go-runewidth-8 1168 ns/op 109.59 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/rivo/uniseg-8 1585 ns/op 80.74 MB/s 0 B/op 0 allocs/op -BenchmarkString_Emoji/clipperhouse/displaywidth-8 3164 ns/op 228.84 MB/s 0 B/op 0 allocs/op -BenchmarkString_Emoji/mattn/go-runewidth-8 4728 ns/op 153.13 MB/s 0 B/op 0 allocs/op -BenchmarkString_Emoji/rivo/uniseg-8 6489 ns/op 111.57 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/clipperhouse/displaywidth-8 3034 ns/op 238.61 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/mattn/go-runewidth-8 4797 ns/op 150.94 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/rivo/uniseg-8 6612 ns/op 109.50 MB/s 0 B/op 0 allocs/op -BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3429 ns/op 491.96 MB/s 0 B/op 0 allocs/op -BenchmarkRune_Mixed/mattn/go-runewidth-8 5308 ns/op 317.81 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3343 ns/op 504.67 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Mixed/mattn/go-runewidth-8 5414 ns/op 311.62 MB/s 0 B/op 0 allocs/op -BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3419 ns/op 493.49 MB/s 0 B/op 0 allocs/op -BenchmarkRune_EastAsian/mattn/go-runewidth-8 15321 ns/op 110.11 MB/s 0 B/op 0 allocs/op +BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3393 ns/op 497.17 MB/s 0 B/op 0 allocs/op +BenchmarkRune_EastAsian/mattn/go-runewidth-8 15312 ns/op 110.17 MB/s 0 B/op 0 allocs/op -BenchmarkRune_ASCII/clipperhouse/displaywidth-8 254.4 ns/op 503.19 MB/s 0 B/op 0 allocs/op -BenchmarkRune_ASCII/mattn/go-runewidth-8 264.3 ns/op 484.31 MB/s 0 B/op 0 allocs/op +BenchmarkRune_ASCII/clipperhouse/displaywidth-8 256.9 ns/op 498.32 MB/s 0 B/op 0 allocs/op +BenchmarkRune_ASCII/mattn/go-runewidth-8 265.7 ns/op 481.75 MB/s 0 B/op 0 allocs/op -BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1374 ns/op 527.02 MB/s 0 B/op 0 allocs/op -BenchmarkRune_Emoji/mattn/go-runewidth-8 2210 ns/op 327.66 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1336 ns/op 541.96 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Emoji/mattn/go-runewidth-8 2304 ns/op 314.23 MB/s 0 B/op 0 allocs/op ``` + +Here are some notes on [how to make Unicode things fast](https://clipperhouse.com/go-unicode/). diff --git a/vendor/github.com/clipperhouse/displaywidth/tables.go b/vendor/github.com/clipperhouse/displaywidth/tables.go deleted file mode 100644 index 40cf596680..0000000000 --- a/vendor/github.com/clipperhouse/displaywidth/tables.go +++ /dev/null @@ -1,91 +0,0 @@ -package displaywidth - -// propertyWidths is a jump table of sorts, instead of a switch -var propertyWidths = [5]int{ - _Default: 1, - _Zero_Width: 0, - _East_Asian_Wide: 2, - _East_Asian_Ambiguous: 1, - _Emoji: 2, -} - -// asciiWidths is a lookup table for single-byte character widths. Printable -// ASCII characters have width 1, control characters have width 0. -// -// It is intended for valid single-byte UTF-8, which means <128. -// -// If you look up an index >= 128, that is either: -// - invalid UTF-8, or -// - a multi-byte UTF-8 sequence, in which case you should be operating on -// the grapheme cluster, and not using this table -// -// We will return a default value of 1 in those cases, so as not to panic. -var asciiWidths = [256]int8{ - // Control characters (0x00-0x1F): width 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // Printable ASCII (0x20-0x7E): width 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - // DEL (0x7F): width 0 - 0, - // >= 128 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -} - -// asciiProperties is a lookup table for single-byte character properties. -// It is intended for valid single-byte UTF-8, which means <128. -// -// If you look up an index >= 128, that is either: -// - invalid UTF-8, or -// - a multi-byte UTF-8 sequence, in which case you should be operating on -// the grapheme cluster, and not using this table -// -// We will return a default value of _Default in those cases, so as not to -// panic. -var asciiProperties = [256]property{ - // Control characters (0x00-0x1F): _Zero_Width - _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, - _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, - _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, - _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, _Zero_Width, - // Printable ASCII (0x20-0x7E): _Default - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, - // DEL (0x7F): _Zero_Width - _Zero_Width, - // >= 128 - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, - _Default, _Default, _Default, _Default, _Default, _Default, _Default, _Default, -} diff --git a/vendor/github.com/clipperhouse/displaywidth/trie.go b/vendor/github.com/clipperhouse/displaywidth/trie.go index e98c3695c4..c63ed320ac 100644 --- a/vendor/github.com/clipperhouse/displaywidth/trie.go +++ b/vendor/github.com/clipperhouse/displaywidth/trie.go @@ -16,6 +16,8 @@ const ( _East_Asian_Ambiguous // Extended_Pictographic + Emoji_Presentation _Emoji + // Regional Indicator symbols (used in flag emoji pairs) + _Regional_Indicator ) // lookup returns the trie value for the first UTF-8 encoding in s and @@ -81,7 +83,7 @@ func lookup[T stringish.Interface](s T) (v uint8, sz int) { return 0, 1 } -// stringWidthTrie. Total size: 17728 bytes (17.31 KiB). Checksum: b4b51ae347944fdb. +// stringWidthTrie. Total size: 17792 bytes (17.38 KiB). Checksum: a03a02693a639d4a. // type stringWidthTrie struct { } // func newStringWidthTrie(i int) *stringWidthTrie { @@ -96,9 +98,9 @@ func lookupValue(n uint32, b byte) uint8 { } } -// stringWidthValues: 247 blocks, 15808 entries, 15808 bytes +// stringWidthValues: 248 blocks, 15872 entries, 15872 bytes // The third block is the zero block. -var stringWidthValues = [15808]uint8{ +var stringWidthValues = [15872]uint8{ // Block 0x0, offset 0x0 // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 @@ -1309,80 +1311,74 @@ var stringWidthValues = [15808]uint8{ 0x3764: 0x0003, 0x3765: 0x0003, 0x3766: 0x0003, 0x3767: 0x0003, 0x3768: 0x0003, 0x3769: 0x0003, 0x376a: 0x0003, 0x376b: 0x0003, 0x376c: 0x0003, // Block 0xde, offset 0x3780 - 0x3780: 0x0002, 0x3781: 0x0004, 0x3782: 0x0002, - 0x3790: 0x0002, 0x3791: 0x0002, - 0x3792: 0x0002, 0x3793: 0x0002, 0x3794: 0x0002, 0x3795: 0x0002, 0x3796: 0x0002, 0x3797: 0x0002, - 0x3798: 0x0002, 0x3799: 0x0002, 0x379a: 0x0004, 0x379b: 0x0002, 0x379c: 0x0002, 0x379d: 0x0002, - 0x379e: 0x0002, 0x379f: 0x0002, 0x37a0: 0x0002, 0x37a1: 0x0002, 0x37a2: 0x0002, 0x37a3: 0x0002, - 0x37a4: 0x0002, 0x37a5: 0x0002, 0x37a6: 0x0002, 0x37a7: 0x0002, 0x37a8: 0x0002, 0x37a9: 0x0002, - 0x37aa: 0x0002, 0x37ab: 0x0002, 0x37ac: 0x0002, 0x37ad: 0x0002, 0x37ae: 0x0002, 0x37af: 0x0004, - 0x37b0: 0x0002, 0x37b1: 0x0002, 0x37b2: 0x0004, 0x37b3: 0x0004, 0x37b4: 0x0004, 0x37b5: 0x0004, - 0x37b6: 0x0004, 0x37b7: 0x0002, 0x37b8: 0x0004, 0x37b9: 0x0004, 0x37ba: 0x0004, 0x37bb: 0x0002, + 0x37a6: 0x0005, 0x37a7: 0x0005, 0x37a8: 0x0005, 0x37a9: 0x0005, + 0x37aa: 0x0005, 0x37ab: 0x0005, 0x37ac: 0x0005, 0x37ad: 0x0005, 0x37ae: 0x0005, 0x37af: 0x0005, + 0x37b0: 0x0005, 0x37b1: 0x0005, 0x37b2: 0x0005, 0x37b3: 0x0005, 0x37b4: 0x0005, 0x37b5: 0x0005, + 0x37b6: 0x0005, 0x37b7: 0x0005, 0x37b8: 0x0005, 0x37b9: 0x0005, 0x37ba: 0x0005, 0x37bb: 0x0005, + 0x37bc: 0x0005, 0x37bd: 0x0005, 0x37be: 0x0005, 0x37bf: 0x0005, // Block 0xdf, offset 0x37c0 - 0x37c0: 0x0002, 0x37c1: 0x0002, 0x37c2: 0x0002, 0x37c3: 0x0002, 0x37c4: 0x0002, 0x37c5: 0x0002, - 0x37c6: 0x0002, 0x37c7: 0x0002, 0x37c8: 0x0002, - 0x37d0: 0x0004, 0x37d1: 0x0004, - 0x37e0: 0x0002, 0x37e1: 0x0002, 0x37e2: 0x0002, 0x37e3: 0x0002, - 0x37e4: 0x0002, 0x37e5: 0x0002, + 0x37c0: 0x0002, 0x37c1: 0x0004, 0x37c2: 0x0002, + 0x37d0: 0x0002, 0x37d1: 0x0002, + 0x37d2: 0x0002, 0x37d3: 0x0002, 0x37d4: 0x0002, 0x37d5: 0x0002, 0x37d6: 0x0002, 0x37d7: 0x0002, + 0x37d8: 0x0002, 0x37d9: 0x0002, 0x37da: 0x0004, 0x37db: 0x0002, 0x37dc: 0x0002, 0x37dd: 0x0002, + 0x37de: 0x0002, 0x37df: 0x0002, 0x37e0: 0x0002, 0x37e1: 0x0002, 0x37e2: 0x0002, 0x37e3: 0x0002, + 0x37e4: 0x0002, 0x37e5: 0x0002, 0x37e6: 0x0002, 0x37e7: 0x0002, 0x37e8: 0x0002, 0x37e9: 0x0002, + 0x37ea: 0x0002, 0x37eb: 0x0002, 0x37ec: 0x0002, 0x37ed: 0x0002, 0x37ee: 0x0002, 0x37ef: 0x0004, + 0x37f0: 0x0002, 0x37f1: 0x0002, 0x37f2: 0x0004, 0x37f3: 0x0004, 0x37f4: 0x0004, 0x37f5: 0x0004, + 0x37f6: 0x0004, 0x37f7: 0x0002, 0x37f8: 0x0004, 0x37f9: 0x0004, 0x37fa: 0x0004, 0x37fb: 0x0002, // Block 0xe0, offset 0x3800 - 0x3800: 0x0004, 0x3801: 0x0004, 0x3802: 0x0004, 0x3803: 0x0004, 0x3804: 0x0004, 0x3805: 0x0004, - 0x3806: 0x0004, 0x3807: 0x0004, 0x3808: 0x0004, 0x3809: 0x0004, 0x380a: 0x0004, 0x380b: 0x0004, - 0x380c: 0x0004, 0x380d: 0x0004, 0x380e: 0x0004, 0x380f: 0x0004, 0x3810: 0x0004, 0x3811: 0x0004, - 0x3812: 0x0004, 0x3813: 0x0004, 0x3814: 0x0004, 0x3815: 0x0004, 0x3816: 0x0004, 0x3817: 0x0004, - 0x3818: 0x0004, 0x3819: 0x0004, 0x381a: 0x0004, 0x381b: 0x0004, 0x381c: 0x0004, 0x381d: 0x0004, - 0x381e: 0x0004, 0x381f: 0x0004, 0x3820: 0x0004, - 0x382d: 0x0004, 0x382e: 0x0004, 0x382f: 0x0004, - 0x3830: 0x0004, 0x3831: 0x0004, 0x3832: 0x0004, 0x3833: 0x0004, 0x3834: 0x0004, 0x3835: 0x0004, - 0x3837: 0x0004, 0x3838: 0x0004, 0x3839: 0x0004, 0x383a: 0x0004, 0x383b: 0x0004, - 0x383c: 0x0004, 0x383d: 0x0004, 0x383e: 0x0004, 0x383f: 0x0004, + 0x3800: 0x0002, 0x3801: 0x0002, 0x3802: 0x0002, 0x3803: 0x0002, 0x3804: 0x0002, 0x3805: 0x0002, + 0x3806: 0x0002, 0x3807: 0x0002, 0x3808: 0x0002, + 0x3810: 0x0004, 0x3811: 0x0004, + 0x3820: 0x0002, 0x3821: 0x0002, 0x3822: 0x0002, 0x3823: 0x0002, + 0x3824: 0x0002, 0x3825: 0x0002, // Block 0xe1, offset 0x3840 0x3840: 0x0004, 0x3841: 0x0004, 0x3842: 0x0004, 0x3843: 0x0004, 0x3844: 0x0004, 0x3845: 0x0004, 0x3846: 0x0004, 0x3847: 0x0004, 0x3848: 0x0004, 0x3849: 0x0004, 0x384a: 0x0004, 0x384b: 0x0004, 0x384c: 0x0004, 0x384d: 0x0004, 0x384e: 0x0004, 0x384f: 0x0004, 0x3850: 0x0004, 0x3851: 0x0004, 0x3852: 0x0004, 0x3853: 0x0004, 0x3854: 0x0004, 0x3855: 0x0004, 0x3856: 0x0004, 0x3857: 0x0004, 0x3858: 0x0004, 0x3859: 0x0004, 0x385a: 0x0004, 0x385b: 0x0004, 0x385c: 0x0004, 0x385d: 0x0004, - 0x385e: 0x0004, 0x385f: 0x0004, 0x3860: 0x0004, 0x3861: 0x0004, 0x3862: 0x0004, 0x3863: 0x0004, - 0x3864: 0x0004, 0x3865: 0x0004, 0x3866: 0x0004, 0x3867: 0x0004, 0x3868: 0x0004, 0x3869: 0x0004, - 0x386a: 0x0004, 0x386b: 0x0004, 0x386c: 0x0004, 0x386d: 0x0004, 0x386e: 0x0004, 0x386f: 0x0004, + 0x385e: 0x0004, 0x385f: 0x0004, 0x3860: 0x0004, + 0x386d: 0x0004, 0x386e: 0x0004, 0x386f: 0x0004, 0x3870: 0x0004, 0x3871: 0x0004, 0x3872: 0x0004, 0x3873: 0x0004, 0x3874: 0x0004, 0x3875: 0x0004, - 0x3876: 0x0004, 0x3877: 0x0004, 0x3878: 0x0004, 0x3879: 0x0004, 0x387a: 0x0004, 0x387b: 0x0004, - 0x387c: 0x0004, 0x387e: 0x0004, 0x387f: 0x0004, + 0x3877: 0x0004, 0x3878: 0x0004, 0x3879: 0x0004, 0x387a: 0x0004, 0x387b: 0x0004, + 0x387c: 0x0004, 0x387d: 0x0004, 0x387e: 0x0004, 0x387f: 0x0004, // Block 0xe2, offset 0x3880 0x3880: 0x0004, 0x3881: 0x0004, 0x3882: 0x0004, 0x3883: 0x0004, 0x3884: 0x0004, 0x3885: 0x0004, 0x3886: 0x0004, 0x3887: 0x0004, 0x3888: 0x0004, 0x3889: 0x0004, 0x388a: 0x0004, 0x388b: 0x0004, 0x388c: 0x0004, 0x388d: 0x0004, 0x388e: 0x0004, 0x388f: 0x0004, 0x3890: 0x0004, 0x3891: 0x0004, - 0x3892: 0x0004, 0x3893: 0x0004, - 0x38a0: 0x0004, 0x38a1: 0x0004, 0x38a2: 0x0004, 0x38a3: 0x0004, + 0x3892: 0x0004, 0x3893: 0x0004, 0x3894: 0x0004, 0x3895: 0x0004, 0x3896: 0x0004, 0x3897: 0x0004, + 0x3898: 0x0004, 0x3899: 0x0004, 0x389a: 0x0004, 0x389b: 0x0004, 0x389c: 0x0004, 0x389d: 0x0004, + 0x389e: 0x0004, 0x389f: 0x0004, 0x38a0: 0x0004, 0x38a1: 0x0004, 0x38a2: 0x0004, 0x38a3: 0x0004, 0x38a4: 0x0004, 0x38a5: 0x0004, 0x38a6: 0x0004, 0x38a7: 0x0004, 0x38a8: 0x0004, 0x38a9: 0x0004, 0x38aa: 0x0004, 0x38ab: 0x0004, 0x38ac: 0x0004, 0x38ad: 0x0004, 0x38ae: 0x0004, 0x38af: 0x0004, 0x38b0: 0x0004, 0x38b1: 0x0004, 0x38b2: 0x0004, 0x38b3: 0x0004, 0x38b4: 0x0004, 0x38b5: 0x0004, 0x38b6: 0x0004, 0x38b7: 0x0004, 0x38b8: 0x0004, 0x38b9: 0x0004, 0x38ba: 0x0004, 0x38bb: 0x0004, - 0x38bc: 0x0004, 0x38bd: 0x0004, 0x38be: 0x0004, 0x38bf: 0x0004, + 0x38bc: 0x0004, 0x38be: 0x0004, 0x38bf: 0x0004, // Block 0xe3, offset 0x38c0 0x38c0: 0x0004, 0x38c1: 0x0004, 0x38c2: 0x0004, 0x38c3: 0x0004, 0x38c4: 0x0004, 0x38c5: 0x0004, - 0x38c6: 0x0004, 0x38c7: 0x0004, 0x38c8: 0x0004, 0x38c9: 0x0004, 0x38ca: 0x0004, - 0x38cf: 0x0004, 0x38d0: 0x0004, 0x38d1: 0x0004, + 0x38c6: 0x0004, 0x38c7: 0x0004, 0x38c8: 0x0004, 0x38c9: 0x0004, 0x38ca: 0x0004, 0x38cb: 0x0004, + 0x38cc: 0x0004, 0x38cd: 0x0004, 0x38ce: 0x0004, 0x38cf: 0x0004, 0x38d0: 0x0004, 0x38d1: 0x0004, 0x38d2: 0x0004, 0x38d3: 0x0004, 0x38e0: 0x0004, 0x38e1: 0x0004, 0x38e2: 0x0004, 0x38e3: 0x0004, 0x38e4: 0x0004, 0x38e5: 0x0004, 0x38e6: 0x0004, 0x38e7: 0x0004, 0x38e8: 0x0004, 0x38e9: 0x0004, 0x38ea: 0x0004, 0x38eb: 0x0004, 0x38ec: 0x0004, 0x38ed: 0x0004, 0x38ee: 0x0004, 0x38ef: 0x0004, - 0x38f0: 0x0004, 0x38f4: 0x0004, - 0x38f8: 0x0004, 0x38f9: 0x0004, 0x38fa: 0x0004, 0x38fb: 0x0002, - 0x38fc: 0x0002, 0x38fd: 0x0002, 0x38fe: 0x0002, 0x38ff: 0x0002, + 0x38f0: 0x0004, 0x38f1: 0x0004, 0x38f2: 0x0004, 0x38f3: 0x0004, 0x38f4: 0x0004, 0x38f5: 0x0004, + 0x38f6: 0x0004, 0x38f7: 0x0004, 0x38f8: 0x0004, 0x38f9: 0x0004, 0x38fa: 0x0004, 0x38fb: 0x0004, + 0x38fc: 0x0004, 0x38fd: 0x0004, 0x38fe: 0x0004, 0x38ff: 0x0004, // Block 0xe4, offset 0x3900 0x3900: 0x0004, 0x3901: 0x0004, 0x3902: 0x0004, 0x3903: 0x0004, 0x3904: 0x0004, 0x3905: 0x0004, - 0x3906: 0x0004, 0x3907: 0x0004, 0x3908: 0x0004, 0x3909: 0x0004, 0x390a: 0x0004, 0x390b: 0x0004, - 0x390c: 0x0004, 0x390d: 0x0004, 0x390e: 0x0004, 0x390f: 0x0004, 0x3910: 0x0004, 0x3911: 0x0004, - 0x3912: 0x0004, 0x3913: 0x0004, 0x3914: 0x0004, 0x3915: 0x0004, 0x3916: 0x0004, 0x3917: 0x0004, - 0x3918: 0x0004, 0x3919: 0x0004, 0x391a: 0x0004, 0x391b: 0x0004, 0x391c: 0x0004, 0x391d: 0x0004, - 0x391e: 0x0004, 0x391f: 0x0004, 0x3920: 0x0004, 0x3921: 0x0004, 0x3922: 0x0004, 0x3923: 0x0004, + 0x3906: 0x0004, 0x3907: 0x0004, 0x3908: 0x0004, 0x3909: 0x0004, 0x390a: 0x0004, + 0x390f: 0x0004, 0x3910: 0x0004, 0x3911: 0x0004, + 0x3912: 0x0004, 0x3913: 0x0004, + 0x3920: 0x0004, 0x3921: 0x0004, 0x3922: 0x0004, 0x3923: 0x0004, 0x3924: 0x0004, 0x3925: 0x0004, 0x3926: 0x0004, 0x3927: 0x0004, 0x3928: 0x0004, 0x3929: 0x0004, 0x392a: 0x0004, 0x392b: 0x0004, 0x392c: 0x0004, 0x392d: 0x0004, 0x392e: 0x0004, 0x392f: 0x0004, - 0x3930: 0x0004, 0x3931: 0x0004, 0x3932: 0x0004, 0x3933: 0x0004, 0x3934: 0x0004, 0x3935: 0x0004, - 0x3936: 0x0004, 0x3937: 0x0004, 0x3938: 0x0004, 0x3939: 0x0004, 0x393a: 0x0004, 0x393b: 0x0004, - 0x393c: 0x0004, 0x393d: 0x0004, 0x393e: 0x0004, + 0x3930: 0x0004, 0x3934: 0x0004, + 0x3938: 0x0004, 0x3939: 0x0004, 0x393a: 0x0004, 0x393b: 0x0002, + 0x393c: 0x0002, 0x393d: 0x0002, 0x393e: 0x0002, 0x393f: 0x0002, // Block 0xe5, offset 0x3940 - 0x3940: 0x0004, 0x3942: 0x0004, 0x3943: 0x0004, 0x3944: 0x0004, 0x3945: 0x0004, + 0x3940: 0x0004, 0x3941: 0x0004, 0x3942: 0x0004, 0x3943: 0x0004, 0x3944: 0x0004, 0x3945: 0x0004, 0x3946: 0x0004, 0x3947: 0x0004, 0x3948: 0x0004, 0x3949: 0x0004, 0x394a: 0x0004, 0x394b: 0x0004, 0x394c: 0x0004, 0x394d: 0x0004, 0x394e: 0x0004, 0x394f: 0x0004, 0x3950: 0x0004, 0x3951: 0x0004, 0x3952: 0x0004, 0x3953: 0x0004, 0x3954: 0x0004, 0x3955: 0x0004, 0x3956: 0x0004, 0x3957: 0x0004, @@ -1392,9 +1388,9 @@ var stringWidthValues = [15808]uint8{ 0x396a: 0x0004, 0x396b: 0x0004, 0x396c: 0x0004, 0x396d: 0x0004, 0x396e: 0x0004, 0x396f: 0x0004, 0x3970: 0x0004, 0x3971: 0x0004, 0x3972: 0x0004, 0x3973: 0x0004, 0x3974: 0x0004, 0x3975: 0x0004, 0x3976: 0x0004, 0x3977: 0x0004, 0x3978: 0x0004, 0x3979: 0x0004, 0x397a: 0x0004, 0x397b: 0x0004, - 0x397c: 0x0004, 0x397d: 0x0004, 0x397e: 0x0004, 0x397f: 0x0004, + 0x397c: 0x0004, 0x397d: 0x0004, 0x397e: 0x0004, // Block 0xe6, offset 0x3980 - 0x3980: 0x0004, 0x3981: 0x0004, 0x3982: 0x0004, 0x3983: 0x0004, 0x3984: 0x0004, 0x3985: 0x0004, + 0x3980: 0x0004, 0x3982: 0x0004, 0x3983: 0x0004, 0x3984: 0x0004, 0x3985: 0x0004, 0x3986: 0x0004, 0x3987: 0x0004, 0x3988: 0x0004, 0x3989: 0x0004, 0x398a: 0x0004, 0x398b: 0x0004, 0x398c: 0x0004, 0x398d: 0x0004, 0x398e: 0x0004, 0x398f: 0x0004, 0x3990: 0x0004, 0x3991: 0x0004, 0x3992: 0x0004, 0x3993: 0x0004, 0x3994: 0x0004, 0x3995: 0x0004, 0x3996: 0x0004, 0x3997: 0x0004, @@ -1416,7 +1412,7 @@ var stringWidthValues = [15808]uint8{ 0x39ea: 0x0004, 0x39eb: 0x0004, 0x39ec: 0x0004, 0x39ed: 0x0004, 0x39ee: 0x0004, 0x39ef: 0x0004, 0x39f0: 0x0004, 0x39f1: 0x0004, 0x39f2: 0x0004, 0x39f3: 0x0004, 0x39f4: 0x0004, 0x39f5: 0x0004, 0x39f6: 0x0004, 0x39f7: 0x0004, 0x39f8: 0x0004, 0x39f9: 0x0004, 0x39fa: 0x0004, 0x39fb: 0x0004, - 0x39fc: 0x0004, 0x39ff: 0x0004, + 0x39fc: 0x0004, 0x39fd: 0x0004, 0x39fe: 0x0004, 0x39ff: 0x0004, // Block 0xe8, offset 0x3a00 0x3a00: 0x0004, 0x3a01: 0x0004, 0x3a02: 0x0004, 0x3a03: 0x0004, 0x3a04: 0x0004, 0x3a05: 0x0004, 0x3a06: 0x0004, 0x3a07: 0x0004, 0x3a08: 0x0004, 0x3a09: 0x0004, 0x3a0a: 0x0004, 0x3a0b: 0x0004, @@ -1428,53 +1424,53 @@ var stringWidthValues = [15808]uint8{ 0x3a2a: 0x0004, 0x3a2b: 0x0004, 0x3a2c: 0x0004, 0x3a2d: 0x0004, 0x3a2e: 0x0004, 0x3a2f: 0x0004, 0x3a30: 0x0004, 0x3a31: 0x0004, 0x3a32: 0x0004, 0x3a33: 0x0004, 0x3a34: 0x0004, 0x3a35: 0x0004, 0x3a36: 0x0004, 0x3a37: 0x0004, 0x3a38: 0x0004, 0x3a39: 0x0004, 0x3a3a: 0x0004, 0x3a3b: 0x0004, - 0x3a3c: 0x0004, 0x3a3d: 0x0004, + 0x3a3c: 0x0004, 0x3a3f: 0x0004, // Block 0xe9, offset 0x3a40 - 0x3a4b: 0x0004, - 0x3a4c: 0x0004, 0x3a4d: 0x0004, 0x3a4e: 0x0004, 0x3a50: 0x0004, 0x3a51: 0x0004, + 0x3a40: 0x0004, 0x3a41: 0x0004, 0x3a42: 0x0004, 0x3a43: 0x0004, 0x3a44: 0x0004, 0x3a45: 0x0004, + 0x3a46: 0x0004, 0x3a47: 0x0004, 0x3a48: 0x0004, 0x3a49: 0x0004, 0x3a4a: 0x0004, 0x3a4b: 0x0004, + 0x3a4c: 0x0004, 0x3a4d: 0x0004, 0x3a4e: 0x0004, 0x3a4f: 0x0004, 0x3a50: 0x0004, 0x3a51: 0x0004, 0x3a52: 0x0004, 0x3a53: 0x0004, 0x3a54: 0x0004, 0x3a55: 0x0004, 0x3a56: 0x0004, 0x3a57: 0x0004, 0x3a58: 0x0004, 0x3a59: 0x0004, 0x3a5a: 0x0004, 0x3a5b: 0x0004, 0x3a5c: 0x0004, 0x3a5d: 0x0004, 0x3a5e: 0x0004, 0x3a5f: 0x0004, 0x3a60: 0x0004, 0x3a61: 0x0004, 0x3a62: 0x0004, 0x3a63: 0x0004, - 0x3a64: 0x0004, 0x3a65: 0x0004, 0x3a66: 0x0004, 0x3a67: 0x0004, - 0x3a7a: 0x0004, + 0x3a64: 0x0004, 0x3a65: 0x0004, 0x3a66: 0x0004, 0x3a67: 0x0004, 0x3a68: 0x0004, 0x3a69: 0x0004, + 0x3a6a: 0x0004, 0x3a6b: 0x0004, 0x3a6c: 0x0004, 0x3a6d: 0x0004, 0x3a6e: 0x0004, 0x3a6f: 0x0004, + 0x3a70: 0x0004, 0x3a71: 0x0004, 0x3a72: 0x0004, 0x3a73: 0x0004, 0x3a74: 0x0004, 0x3a75: 0x0004, + 0x3a76: 0x0004, 0x3a77: 0x0004, 0x3a78: 0x0004, 0x3a79: 0x0004, 0x3a7a: 0x0004, 0x3a7b: 0x0004, + 0x3a7c: 0x0004, 0x3a7d: 0x0004, // Block 0xea, offset 0x3a80 - 0x3a95: 0x0004, 0x3a96: 0x0004, - 0x3aa4: 0x0004, + 0x3a8b: 0x0004, + 0x3a8c: 0x0004, 0x3a8d: 0x0004, 0x3a8e: 0x0004, 0x3a90: 0x0004, 0x3a91: 0x0004, + 0x3a92: 0x0004, 0x3a93: 0x0004, 0x3a94: 0x0004, 0x3a95: 0x0004, 0x3a96: 0x0004, 0x3a97: 0x0004, + 0x3a98: 0x0004, 0x3a99: 0x0004, 0x3a9a: 0x0004, 0x3a9b: 0x0004, 0x3a9c: 0x0004, 0x3a9d: 0x0004, + 0x3a9e: 0x0004, 0x3a9f: 0x0004, 0x3aa0: 0x0004, 0x3aa1: 0x0004, 0x3aa2: 0x0004, 0x3aa3: 0x0004, + 0x3aa4: 0x0004, 0x3aa5: 0x0004, 0x3aa6: 0x0004, 0x3aa7: 0x0004, + 0x3aba: 0x0004, // Block 0xeb, offset 0x3ac0 - 0x3afb: 0x0004, - 0x3afc: 0x0004, 0x3afd: 0x0004, 0x3afe: 0x0004, 0x3aff: 0x0004, + 0x3ad5: 0x0004, 0x3ad6: 0x0004, + 0x3ae4: 0x0004, // Block 0xec, offset 0x3b00 - 0x3b00: 0x0004, 0x3b01: 0x0004, 0x3b02: 0x0004, 0x3b03: 0x0004, 0x3b04: 0x0004, 0x3b05: 0x0004, - 0x3b06: 0x0004, 0x3b07: 0x0004, 0x3b08: 0x0004, 0x3b09: 0x0004, 0x3b0a: 0x0004, 0x3b0b: 0x0004, - 0x3b0c: 0x0004, 0x3b0d: 0x0004, 0x3b0e: 0x0004, 0x3b0f: 0x0004, + 0x3b3b: 0x0004, + 0x3b3c: 0x0004, 0x3b3d: 0x0004, 0x3b3e: 0x0004, 0x3b3f: 0x0004, // Block 0xed, offset 0x3b40 0x3b40: 0x0004, 0x3b41: 0x0004, 0x3b42: 0x0004, 0x3b43: 0x0004, 0x3b44: 0x0004, 0x3b45: 0x0004, - 0x3b4c: 0x0004, 0x3b50: 0x0004, 0x3b51: 0x0004, - 0x3b52: 0x0004, 0x3b55: 0x0004, 0x3b56: 0x0004, 0x3b57: 0x0004, - 0x3b5c: 0x0004, 0x3b5d: 0x0004, - 0x3b5e: 0x0004, 0x3b5f: 0x0004, - 0x3b6b: 0x0004, 0x3b6c: 0x0004, - 0x3b74: 0x0004, 0x3b75: 0x0004, - 0x3b76: 0x0004, 0x3b77: 0x0004, 0x3b78: 0x0004, 0x3b79: 0x0004, 0x3b7a: 0x0004, 0x3b7b: 0x0004, - 0x3b7c: 0x0004, + 0x3b46: 0x0004, 0x3b47: 0x0004, 0x3b48: 0x0004, 0x3b49: 0x0004, 0x3b4a: 0x0004, 0x3b4b: 0x0004, + 0x3b4c: 0x0004, 0x3b4d: 0x0004, 0x3b4e: 0x0004, 0x3b4f: 0x0004, // Block 0xee, offset 0x3b80 - 0x3ba0: 0x0004, 0x3ba1: 0x0004, 0x3ba2: 0x0004, 0x3ba3: 0x0004, - 0x3ba4: 0x0004, 0x3ba5: 0x0004, 0x3ba6: 0x0004, 0x3ba7: 0x0004, 0x3ba8: 0x0004, 0x3ba9: 0x0004, - 0x3baa: 0x0004, 0x3bab: 0x0004, - 0x3bb0: 0x0004, + 0x3b80: 0x0004, 0x3b81: 0x0004, 0x3b82: 0x0004, 0x3b83: 0x0004, 0x3b84: 0x0004, 0x3b85: 0x0004, + 0x3b8c: 0x0004, 0x3b90: 0x0004, 0x3b91: 0x0004, + 0x3b92: 0x0004, 0x3b95: 0x0004, 0x3b96: 0x0004, 0x3b97: 0x0004, + 0x3b9c: 0x0004, 0x3b9d: 0x0004, + 0x3b9e: 0x0004, 0x3b9f: 0x0004, + 0x3bab: 0x0004, 0x3bac: 0x0004, + 0x3bb4: 0x0004, 0x3bb5: 0x0004, + 0x3bb6: 0x0004, 0x3bb7: 0x0004, 0x3bb8: 0x0004, 0x3bb9: 0x0004, 0x3bba: 0x0004, 0x3bbb: 0x0004, + 0x3bbc: 0x0004, // Block 0xef, offset 0x3bc0 - 0x3bcc: 0x0004, 0x3bcd: 0x0004, 0x3bce: 0x0004, 0x3bcf: 0x0004, 0x3bd0: 0x0004, 0x3bd1: 0x0004, - 0x3bd2: 0x0004, 0x3bd3: 0x0004, 0x3bd4: 0x0004, 0x3bd5: 0x0004, 0x3bd6: 0x0004, 0x3bd7: 0x0004, - 0x3bd8: 0x0004, 0x3bd9: 0x0004, 0x3bda: 0x0004, 0x3bdb: 0x0004, 0x3bdc: 0x0004, 0x3bdd: 0x0004, - 0x3bde: 0x0004, 0x3bdf: 0x0004, 0x3be0: 0x0004, 0x3be1: 0x0004, 0x3be2: 0x0004, 0x3be3: 0x0004, + 0x3be0: 0x0004, 0x3be1: 0x0004, 0x3be2: 0x0004, 0x3be3: 0x0004, 0x3be4: 0x0004, 0x3be5: 0x0004, 0x3be6: 0x0004, 0x3be7: 0x0004, 0x3be8: 0x0004, 0x3be9: 0x0004, - 0x3bea: 0x0004, 0x3beb: 0x0004, 0x3bec: 0x0004, 0x3bed: 0x0004, 0x3bee: 0x0004, 0x3bef: 0x0004, - 0x3bf0: 0x0004, 0x3bf1: 0x0004, 0x3bf2: 0x0004, 0x3bf3: 0x0004, 0x3bf4: 0x0004, 0x3bf5: 0x0004, - 0x3bf6: 0x0004, 0x3bf7: 0x0004, 0x3bf8: 0x0004, 0x3bf9: 0x0004, 0x3bfa: 0x0004, - 0x3bfc: 0x0004, 0x3bfd: 0x0004, 0x3bfe: 0x0004, 0x3bff: 0x0004, + 0x3bea: 0x0004, 0x3beb: 0x0004, + 0x3bf0: 0x0004, // Block 0xf0, offset 0x3c00 - 0x3c00: 0x0004, 0x3c01: 0x0004, 0x3c02: 0x0004, 0x3c03: 0x0004, 0x3c04: 0x0004, 0x3c05: 0x0004, - 0x3c07: 0x0004, 0x3c08: 0x0004, 0x3c09: 0x0004, 0x3c0a: 0x0004, 0x3c0b: 0x0004, 0x3c0c: 0x0004, 0x3c0d: 0x0004, 0x3c0e: 0x0004, 0x3c0f: 0x0004, 0x3c10: 0x0004, 0x3c11: 0x0004, 0x3c12: 0x0004, 0x3c13: 0x0004, 0x3c14: 0x0004, 0x3c15: 0x0004, 0x3c16: 0x0004, 0x3c17: 0x0004, 0x3c18: 0x0004, 0x3c19: 0x0004, 0x3c1a: 0x0004, 0x3c1b: 0x0004, 0x3c1c: 0x0004, 0x3c1d: 0x0004, @@ -1482,66 +1478,78 @@ var stringWidthValues = [15808]uint8{ 0x3c24: 0x0004, 0x3c25: 0x0004, 0x3c26: 0x0004, 0x3c27: 0x0004, 0x3c28: 0x0004, 0x3c29: 0x0004, 0x3c2a: 0x0004, 0x3c2b: 0x0004, 0x3c2c: 0x0004, 0x3c2d: 0x0004, 0x3c2e: 0x0004, 0x3c2f: 0x0004, 0x3c30: 0x0004, 0x3c31: 0x0004, 0x3c32: 0x0004, 0x3c33: 0x0004, 0x3c34: 0x0004, 0x3c35: 0x0004, - 0x3c36: 0x0004, 0x3c37: 0x0004, 0x3c38: 0x0004, 0x3c39: 0x0004, 0x3c3a: 0x0004, 0x3c3b: 0x0004, + 0x3c36: 0x0004, 0x3c37: 0x0004, 0x3c38: 0x0004, 0x3c39: 0x0004, 0x3c3a: 0x0004, 0x3c3c: 0x0004, 0x3c3d: 0x0004, 0x3c3e: 0x0004, 0x3c3f: 0x0004, // Block 0xf1, offset 0x3c40 + 0x3c40: 0x0004, 0x3c41: 0x0004, 0x3c42: 0x0004, 0x3c43: 0x0004, 0x3c44: 0x0004, 0x3c45: 0x0004, + 0x3c47: 0x0004, 0x3c48: 0x0004, 0x3c49: 0x0004, 0x3c4a: 0x0004, 0x3c4b: 0x0004, + 0x3c4c: 0x0004, 0x3c4d: 0x0004, 0x3c4e: 0x0004, 0x3c4f: 0x0004, 0x3c50: 0x0004, 0x3c51: 0x0004, + 0x3c52: 0x0004, 0x3c53: 0x0004, 0x3c54: 0x0004, 0x3c55: 0x0004, 0x3c56: 0x0004, 0x3c57: 0x0004, + 0x3c58: 0x0004, 0x3c59: 0x0004, 0x3c5a: 0x0004, 0x3c5b: 0x0004, 0x3c5c: 0x0004, 0x3c5d: 0x0004, + 0x3c5e: 0x0004, 0x3c5f: 0x0004, 0x3c60: 0x0004, 0x3c61: 0x0004, 0x3c62: 0x0004, 0x3c63: 0x0004, + 0x3c64: 0x0004, 0x3c65: 0x0004, 0x3c66: 0x0004, 0x3c67: 0x0004, 0x3c68: 0x0004, 0x3c69: 0x0004, + 0x3c6a: 0x0004, 0x3c6b: 0x0004, 0x3c6c: 0x0004, 0x3c6d: 0x0004, 0x3c6e: 0x0004, 0x3c6f: 0x0004, 0x3c70: 0x0004, 0x3c71: 0x0004, 0x3c72: 0x0004, 0x3c73: 0x0004, 0x3c74: 0x0004, 0x3c75: 0x0004, 0x3c76: 0x0004, 0x3c77: 0x0004, 0x3c78: 0x0004, 0x3c79: 0x0004, 0x3c7a: 0x0004, 0x3c7b: 0x0004, - 0x3c7c: 0x0004, + 0x3c7c: 0x0004, 0x3c7d: 0x0004, 0x3c7e: 0x0004, 0x3c7f: 0x0004, // Block 0xf2, offset 0x3c80 - 0x3c80: 0x0004, 0x3c81: 0x0004, 0x3c82: 0x0004, 0x3c83: 0x0004, 0x3c84: 0x0004, 0x3c85: 0x0004, - 0x3c86: 0x0004, 0x3c87: 0x0004, 0x3c88: 0x0004, 0x3c89: 0x0004, - 0x3c8f: 0x0004, 0x3c90: 0x0004, 0x3c91: 0x0004, - 0x3c92: 0x0004, 0x3c93: 0x0004, 0x3c94: 0x0004, 0x3c95: 0x0004, 0x3c96: 0x0004, 0x3c97: 0x0004, - 0x3c98: 0x0004, 0x3c99: 0x0004, 0x3c9a: 0x0004, 0x3c9b: 0x0004, 0x3c9c: 0x0004, 0x3c9d: 0x0004, - 0x3c9e: 0x0004, 0x3c9f: 0x0004, 0x3ca0: 0x0004, 0x3ca1: 0x0004, 0x3ca2: 0x0004, 0x3ca3: 0x0004, - 0x3ca4: 0x0004, 0x3ca5: 0x0004, 0x3ca6: 0x0004, 0x3ca7: 0x0004, 0x3ca8: 0x0004, 0x3ca9: 0x0004, - 0x3caa: 0x0004, 0x3cab: 0x0004, 0x3cac: 0x0004, 0x3cad: 0x0004, 0x3cae: 0x0004, 0x3caf: 0x0004, 0x3cb0: 0x0004, 0x3cb1: 0x0004, 0x3cb2: 0x0004, 0x3cb3: 0x0004, 0x3cb4: 0x0004, 0x3cb5: 0x0004, 0x3cb6: 0x0004, 0x3cb7: 0x0004, 0x3cb8: 0x0004, 0x3cb9: 0x0004, 0x3cba: 0x0004, 0x3cbb: 0x0004, - 0x3cbc: 0x0004, 0x3cbd: 0x0004, 0x3cbe: 0x0004, 0x3cbf: 0x0004, + 0x3cbc: 0x0004, // Block 0xf3, offset 0x3cc0 0x3cc0: 0x0004, 0x3cc1: 0x0004, 0x3cc2: 0x0004, 0x3cc3: 0x0004, 0x3cc4: 0x0004, 0x3cc5: 0x0004, - 0x3cc6: 0x0004, - 0x3cce: 0x0004, 0x3ccf: 0x0004, 0x3cd0: 0x0004, 0x3cd1: 0x0004, + 0x3cc6: 0x0004, 0x3cc7: 0x0004, 0x3cc8: 0x0004, 0x3cc9: 0x0004, + 0x3ccf: 0x0004, 0x3cd0: 0x0004, 0x3cd1: 0x0004, 0x3cd2: 0x0004, 0x3cd3: 0x0004, 0x3cd4: 0x0004, 0x3cd5: 0x0004, 0x3cd6: 0x0004, 0x3cd7: 0x0004, - 0x3cd8: 0x0004, 0x3cd9: 0x0004, 0x3cda: 0x0004, 0x3cdb: 0x0004, 0x3cdc: 0x0004, - 0x3cdf: 0x0004, 0x3ce0: 0x0004, 0x3ce1: 0x0004, 0x3ce2: 0x0004, 0x3ce3: 0x0004, + 0x3cd8: 0x0004, 0x3cd9: 0x0004, 0x3cda: 0x0004, 0x3cdb: 0x0004, 0x3cdc: 0x0004, 0x3cdd: 0x0004, + 0x3cde: 0x0004, 0x3cdf: 0x0004, 0x3ce0: 0x0004, 0x3ce1: 0x0004, 0x3ce2: 0x0004, 0x3ce3: 0x0004, 0x3ce4: 0x0004, 0x3ce5: 0x0004, 0x3ce6: 0x0004, 0x3ce7: 0x0004, 0x3ce8: 0x0004, 0x3ce9: 0x0004, + 0x3cea: 0x0004, 0x3ceb: 0x0004, 0x3cec: 0x0004, 0x3ced: 0x0004, 0x3cee: 0x0004, 0x3cef: 0x0004, 0x3cf0: 0x0004, 0x3cf1: 0x0004, 0x3cf2: 0x0004, 0x3cf3: 0x0004, 0x3cf4: 0x0004, 0x3cf5: 0x0004, - 0x3cf6: 0x0004, 0x3cf7: 0x0004, 0x3cf8: 0x0004, + 0x3cf6: 0x0004, 0x3cf7: 0x0004, 0x3cf8: 0x0004, 0x3cf9: 0x0004, 0x3cfa: 0x0004, 0x3cfb: 0x0004, + 0x3cfc: 0x0004, 0x3cfd: 0x0004, 0x3cfe: 0x0004, 0x3cff: 0x0004, // Block 0xf4, offset 0x3d00 - 0x3d00: 0x0002, 0x3d01: 0x0002, 0x3d02: 0x0002, 0x3d03: 0x0002, 0x3d04: 0x0002, 0x3d05: 0x0002, - 0x3d06: 0x0002, 0x3d07: 0x0002, 0x3d08: 0x0002, 0x3d09: 0x0002, 0x3d0a: 0x0002, 0x3d0b: 0x0002, - 0x3d0c: 0x0002, 0x3d0d: 0x0002, 0x3d0e: 0x0002, 0x3d0f: 0x0002, 0x3d10: 0x0002, 0x3d11: 0x0002, - 0x3d12: 0x0002, 0x3d13: 0x0002, 0x3d14: 0x0002, 0x3d15: 0x0002, 0x3d16: 0x0002, 0x3d17: 0x0002, - 0x3d18: 0x0002, 0x3d19: 0x0002, 0x3d1a: 0x0002, 0x3d1b: 0x0002, 0x3d1c: 0x0002, 0x3d1d: 0x0002, - 0x3d1e: 0x0002, 0x3d1f: 0x0002, 0x3d20: 0x0002, 0x3d21: 0x0002, 0x3d22: 0x0002, 0x3d23: 0x0002, - 0x3d24: 0x0002, 0x3d25: 0x0002, 0x3d26: 0x0002, 0x3d27: 0x0002, 0x3d28: 0x0002, 0x3d29: 0x0002, - 0x3d2a: 0x0002, 0x3d2b: 0x0002, 0x3d2c: 0x0002, 0x3d2d: 0x0002, 0x3d2e: 0x0002, 0x3d2f: 0x0002, - 0x3d30: 0x0002, 0x3d31: 0x0002, 0x3d32: 0x0002, 0x3d33: 0x0002, 0x3d34: 0x0002, 0x3d35: 0x0002, - 0x3d36: 0x0002, 0x3d37: 0x0002, 0x3d38: 0x0002, 0x3d39: 0x0002, 0x3d3a: 0x0002, 0x3d3b: 0x0002, - 0x3d3c: 0x0002, 0x3d3d: 0x0002, + 0x3d00: 0x0004, 0x3d01: 0x0004, 0x3d02: 0x0004, 0x3d03: 0x0004, 0x3d04: 0x0004, 0x3d05: 0x0004, + 0x3d06: 0x0004, + 0x3d0e: 0x0004, 0x3d0f: 0x0004, 0x3d10: 0x0004, 0x3d11: 0x0004, + 0x3d12: 0x0004, 0x3d13: 0x0004, 0x3d14: 0x0004, 0x3d15: 0x0004, 0x3d16: 0x0004, 0x3d17: 0x0004, + 0x3d18: 0x0004, 0x3d19: 0x0004, 0x3d1a: 0x0004, 0x3d1b: 0x0004, 0x3d1c: 0x0004, + 0x3d1f: 0x0004, 0x3d20: 0x0004, 0x3d21: 0x0004, 0x3d22: 0x0004, 0x3d23: 0x0004, + 0x3d24: 0x0004, 0x3d25: 0x0004, 0x3d26: 0x0004, 0x3d27: 0x0004, 0x3d28: 0x0004, 0x3d29: 0x0004, + 0x3d30: 0x0004, 0x3d31: 0x0004, 0x3d32: 0x0004, 0x3d33: 0x0004, 0x3d34: 0x0004, 0x3d35: 0x0004, + 0x3d36: 0x0004, 0x3d37: 0x0004, 0x3d38: 0x0004, // Block 0xf5, offset 0x3d40 - 0x3d41: 0x0001, - 0x3d60: 0x0001, 0x3d61: 0x0001, 0x3d62: 0x0001, 0x3d63: 0x0001, - 0x3d64: 0x0001, 0x3d65: 0x0001, 0x3d66: 0x0001, 0x3d67: 0x0001, 0x3d68: 0x0001, 0x3d69: 0x0001, - 0x3d6a: 0x0001, 0x3d6b: 0x0001, 0x3d6c: 0x0001, 0x3d6d: 0x0001, 0x3d6e: 0x0001, 0x3d6f: 0x0001, - 0x3d70: 0x0001, 0x3d71: 0x0001, 0x3d72: 0x0001, 0x3d73: 0x0001, 0x3d74: 0x0001, 0x3d75: 0x0001, - 0x3d76: 0x0001, 0x3d77: 0x0001, 0x3d78: 0x0001, 0x3d79: 0x0001, 0x3d7a: 0x0001, 0x3d7b: 0x0001, - 0x3d7c: 0x0001, 0x3d7d: 0x0001, 0x3d7e: 0x0001, 0x3d7f: 0x0001, + 0x3d40: 0x0002, 0x3d41: 0x0002, 0x3d42: 0x0002, 0x3d43: 0x0002, 0x3d44: 0x0002, 0x3d45: 0x0002, + 0x3d46: 0x0002, 0x3d47: 0x0002, 0x3d48: 0x0002, 0x3d49: 0x0002, 0x3d4a: 0x0002, 0x3d4b: 0x0002, + 0x3d4c: 0x0002, 0x3d4d: 0x0002, 0x3d4e: 0x0002, 0x3d4f: 0x0002, 0x3d50: 0x0002, 0x3d51: 0x0002, + 0x3d52: 0x0002, 0x3d53: 0x0002, 0x3d54: 0x0002, 0x3d55: 0x0002, 0x3d56: 0x0002, 0x3d57: 0x0002, + 0x3d58: 0x0002, 0x3d59: 0x0002, 0x3d5a: 0x0002, 0x3d5b: 0x0002, 0x3d5c: 0x0002, 0x3d5d: 0x0002, + 0x3d5e: 0x0002, 0x3d5f: 0x0002, 0x3d60: 0x0002, 0x3d61: 0x0002, 0x3d62: 0x0002, 0x3d63: 0x0002, + 0x3d64: 0x0002, 0x3d65: 0x0002, 0x3d66: 0x0002, 0x3d67: 0x0002, 0x3d68: 0x0002, 0x3d69: 0x0002, + 0x3d6a: 0x0002, 0x3d6b: 0x0002, 0x3d6c: 0x0002, 0x3d6d: 0x0002, 0x3d6e: 0x0002, 0x3d6f: 0x0002, + 0x3d70: 0x0002, 0x3d71: 0x0002, 0x3d72: 0x0002, 0x3d73: 0x0002, 0x3d74: 0x0002, 0x3d75: 0x0002, + 0x3d76: 0x0002, 0x3d77: 0x0002, 0x3d78: 0x0002, 0x3d79: 0x0002, 0x3d7a: 0x0002, 0x3d7b: 0x0002, + 0x3d7c: 0x0002, 0x3d7d: 0x0002, // Block 0xf6, offset 0x3d80 - 0x3d80: 0x0003, 0x3d81: 0x0003, 0x3d82: 0x0003, 0x3d83: 0x0003, 0x3d84: 0x0003, 0x3d85: 0x0003, - 0x3d86: 0x0003, 0x3d87: 0x0003, 0x3d88: 0x0003, 0x3d89: 0x0003, 0x3d8a: 0x0003, 0x3d8b: 0x0003, - 0x3d8c: 0x0003, 0x3d8d: 0x0003, 0x3d8e: 0x0003, 0x3d8f: 0x0003, 0x3d90: 0x0003, 0x3d91: 0x0003, - 0x3d92: 0x0003, 0x3d93: 0x0003, 0x3d94: 0x0003, 0x3d95: 0x0003, 0x3d96: 0x0003, 0x3d97: 0x0003, - 0x3d98: 0x0003, 0x3d99: 0x0003, 0x3d9a: 0x0003, 0x3d9b: 0x0003, 0x3d9c: 0x0003, 0x3d9d: 0x0003, - 0x3d9e: 0x0003, 0x3d9f: 0x0003, 0x3da0: 0x0003, 0x3da1: 0x0003, 0x3da2: 0x0003, 0x3da3: 0x0003, - 0x3da4: 0x0003, 0x3da5: 0x0003, 0x3da6: 0x0003, 0x3da7: 0x0003, 0x3da8: 0x0003, 0x3da9: 0x0003, - 0x3daa: 0x0003, 0x3dab: 0x0003, 0x3dac: 0x0003, 0x3dad: 0x0003, 0x3dae: 0x0003, 0x3daf: 0x0003, - 0x3db0: 0x0003, 0x3db1: 0x0003, 0x3db2: 0x0003, 0x3db3: 0x0003, 0x3db4: 0x0003, 0x3db5: 0x0003, - 0x3db6: 0x0003, 0x3db7: 0x0003, 0x3db8: 0x0003, 0x3db9: 0x0003, 0x3dba: 0x0003, 0x3dbb: 0x0003, - 0x3dbc: 0x0003, 0x3dbd: 0x0003, + 0x3d81: 0x0001, + 0x3da0: 0x0001, 0x3da1: 0x0001, 0x3da2: 0x0001, 0x3da3: 0x0001, + 0x3da4: 0x0001, 0x3da5: 0x0001, 0x3da6: 0x0001, 0x3da7: 0x0001, 0x3da8: 0x0001, 0x3da9: 0x0001, + 0x3daa: 0x0001, 0x3dab: 0x0001, 0x3dac: 0x0001, 0x3dad: 0x0001, 0x3dae: 0x0001, 0x3daf: 0x0001, + 0x3db0: 0x0001, 0x3db1: 0x0001, 0x3db2: 0x0001, 0x3db3: 0x0001, 0x3db4: 0x0001, 0x3db5: 0x0001, + 0x3db6: 0x0001, 0x3db7: 0x0001, 0x3db8: 0x0001, 0x3db9: 0x0001, 0x3dba: 0x0001, 0x3dbb: 0x0001, + 0x3dbc: 0x0001, 0x3dbd: 0x0001, 0x3dbe: 0x0001, 0x3dbf: 0x0001, + // Block 0xf7, offset 0x3dc0 + 0x3dc0: 0x0003, 0x3dc1: 0x0003, 0x3dc2: 0x0003, 0x3dc3: 0x0003, 0x3dc4: 0x0003, 0x3dc5: 0x0003, + 0x3dc6: 0x0003, 0x3dc7: 0x0003, 0x3dc8: 0x0003, 0x3dc9: 0x0003, 0x3dca: 0x0003, 0x3dcb: 0x0003, + 0x3dcc: 0x0003, 0x3dcd: 0x0003, 0x3dce: 0x0003, 0x3dcf: 0x0003, 0x3dd0: 0x0003, 0x3dd1: 0x0003, + 0x3dd2: 0x0003, 0x3dd3: 0x0003, 0x3dd4: 0x0003, 0x3dd5: 0x0003, 0x3dd6: 0x0003, 0x3dd7: 0x0003, + 0x3dd8: 0x0003, 0x3dd9: 0x0003, 0x3dda: 0x0003, 0x3ddb: 0x0003, 0x3ddc: 0x0003, 0x3ddd: 0x0003, + 0x3dde: 0x0003, 0x3ddf: 0x0003, 0x3de0: 0x0003, 0x3de1: 0x0003, 0x3de2: 0x0003, 0x3de3: 0x0003, + 0x3de4: 0x0003, 0x3de5: 0x0003, 0x3de6: 0x0003, 0x3de7: 0x0003, 0x3de8: 0x0003, 0x3de9: 0x0003, + 0x3dea: 0x0003, 0x3deb: 0x0003, 0x3dec: 0x0003, 0x3ded: 0x0003, 0x3dee: 0x0003, 0x3def: 0x0003, + 0x3df0: 0x0003, 0x3df1: 0x0003, 0x3df2: 0x0003, 0x3df3: 0x0003, 0x3df4: 0x0003, 0x3df5: 0x0003, + 0x3df6: 0x0003, 0x3df7: 0x0003, 0x3df8: 0x0003, 0x3df9: 0x0003, 0x3dfa: 0x0003, 0x3dfb: 0x0003, + 0x3dfc: 0x0003, 0x3dfd: 0x0003, } // stringWidthIndex: 30 blocks, 1920 entries, 1920 bytes @@ -1673,12 +1681,12 @@ var stringWidthIndex = [1920]uint8{ 0x593: 0xd4, 0x5a3: 0xd5, 0x5a5: 0xd6, // Block 0x17, offset 0x5c0 - 0x5c0: 0xd7, 0x5c3: 0xd8, 0x5c4: 0xd9, 0x5c5: 0xda, 0x5c6: 0xdb, - 0x5c8: 0xdc, 0x5c9: 0xdd, 0x5cc: 0xde, 0x5cd: 0xdf, 0x5ce: 0xe0, 0x5cf: 0xe1, - 0x5d0: 0xe2, 0x5d1: 0xe3, 0x5d2: 0xe4, 0x5d3: 0xe5, 0x5d4: 0xe6, 0x5d5: 0xe7, 0x5d6: 0xe8, 0x5d7: 0xe9, - 0x5d8: 0xe4, 0x5d9: 0xea, 0x5da: 0xe4, 0x5db: 0xeb, 0x5df: 0xec, - 0x5e4: 0xed, 0x5e5: 0xee, 0x5e6: 0xe4, 0x5e7: 0xe4, - 0x5e9: 0xef, 0x5ea: 0xf0, 0x5eb: 0xf1, + 0x5c0: 0xd7, 0x5c3: 0xd8, 0x5c4: 0xd9, 0x5c5: 0xda, 0x5c6: 0xdb, 0x5c7: 0xdc, + 0x5c8: 0xdd, 0x5c9: 0xde, 0x5cc: 0xdf, 0x5cd: 0xe0, 0x5ce: 0xe1, 0x5cf: 0xe2, + 0x5d0: 0xe3, 0x5d1: 0xe4, 0x5d2: 0xe5, 0x5d3: 0xe6, 0x5d4: 0xe7, 0x5d5: 0xe8, 0x5d6: 0xe9, 0x5d7: 0xea, + 0x5d8: 0xe5, 0x5d9: 0xeb, 0x5da: 0xe5, 0x5db: 0xec, 0x5df: 0xed, + 0x5e4: 0xee, 0x5e5: 0xef, 0x5e6: 0xe5, 0x5e7: 0xe5, + 0x5e9: 0xf0, 0x5ea: 0xf1, 0x5eb: 0xf2, // Block 0x18, offset 0x600 0x600: 0x39, 0x601: 0x39, 0x602: 0x39, 0x603: 0x39, 0x604: 0x39, 0x605: 0x39, 0x606: 0x39, 0x607: 0x39, 0x608: 0x39, 0x609: 0x39, 0x60a: 0x39, 0x60b: 0x39, 0x60c: 0x39, 0x60d: 0x39, 0x60e: 0x39, 0x60f: 0x39, @@ -1687,7 +1695,7 @@ var stringWidthIndex = [1920]uint8{ 0x620: 0x39, 0x621: 0x39, 0x622: 0x39, 0x623: 0x39, 0x624: 0x39, 0x625: 0x39, 0x626: 0x39, 0x627: 0x39, 0x628: 0x39, 0x629: 0x39, 0x62a: 0x39, 0x62b: 0x39, 0x62c: 0x39, 0x62d: 0x39, 0x62e: 0x39, 0x62f: 0x39, 0x630: 0x39, 0x631: 0x39, 0x632: 0x39, 0x633: 0x39, 0x634: 0x39, 0x635: 0x39, 0x636: 0x39, 0x637: 0x39, - 0x638: 0x39, 0x639: 0x39, 0x63a: 0x39, 0x63b: 0x39, 0x63c: 0x39, 0x63d: 0x39, 0x63e: 0x39, 0x63f: 0xf2, + 0x638: 0x39, 0x639: 0x39, 0x63a: 0x39, 0x63b: 0x39, 0x63c: 0x39, 0x63d: 0x39, 0x63e: 0x39, 0x63f: 0xf3, // Block 0x19, offset 0x640 0x650: 0x0b, 0x651: 0x0c, 0x653: 0x0d, 0x656: 0x0e, 0x657: 0x06, 0x658: 0x0f, 0x65a: 0x10, 0x65b: 0x11, 0x65c: 0x12, 0x65d: 0x13, 0x65e: 0x14, 0x65f: 0x15, @@ -1696,7 +1704,7 @@ var stringWidthIndex = [1920]uint8{ 0x670: 0x06, 0x671: 0x06, 0x672: 0x06, 0x673: 0x06, 0x674: 0x06, 0x675: 0x06, 0x676: 0x06, 0x677: 0x06, 0x678: 0x06, 0x679: 0x06, 0x67a: 0x06, 0x67b: 0x06, 0x67c: 0x06, 0x67d: 0x06, 0x67e: 0x06, 0x67f: 0x16, // Block 0x1a, offset 0x680 - 0x680: 0xf3, 0x681: 0x08, 0x684: 0x08, 0x685: 0x08, 0x686: 0x08, 0x687: 0x09, + 0x680: 0xf4, 0x681: 0x08, 0x684: 0x08, 0x685: 0x08, 0x686: 0x08, 0x687: 0x09, // Block 0x1b, offset 0x6c0 0x6c0: 0x5b, 0x6c1: 0x5b, 0x6c2: 0x5b, 0x6c3: 0x5b, 0x6c4: 0x5b, 0x6c5: 0x5b, 0x6c6: 0x5b, 0x6c7: 0x5b, 0x6c8: 0x5b, 0x6c9: 0x5b, 0x6ca: 0x5b, 0x6cb: 0x5b, 0x6cc: 0x5b, 0x6cd: 0x5b, 0x6ce: 0x5b, 0x6cf: 0x5b, @@ -1705,7 +1713,7 @@ var stringWidthIndex = [1920]uint8{ 0x6e0: 0x5b, 0x6e1: 0x5b, 0x6e2: 0x5b, 0x6e3: 0x5b, 0x6e4: 0x5b, 0x6e5: 0x5b, 0x6e6: 0x5b, 0x6e7: 0x5b, 0x6e8: 0x5b, 0x6e9: 0x5b, 0x6ea: 0x5b, 0x6eb: 0x5b, 0x6ec: 0x5b, 0x6ed: 0x5b, 0x6ee: 0x5b, 0x6ef: 0x5b, 0x6f0: 0x5b, 0x6f1: 0x5b, 0x6f2: 0x5b, 0x6f3: 0x5b, 0x6f4: 0x5b, 0x6f5: 0x5b, 0x6f6: 0x5b, 0x6f7: 0x5b, - 0x6f8: 0x5b, 0x6f9: 0x5b, 0x6fa: 0x5b, 0x6fb: 0x5b, 0x6fc: 0x5b, 0x6fd: 0x5b, 0x6fe: 0x5b, 0x6ff: 0xf4, + 0x6f8: 0x5b, 0x6f9: 0x5b, 0x6fa: 0x5b, 0x6fb: 0x5b, 0x6fc: 0x5b, 0x6fd: 0x5b, 0x6fe: 0x5b, 0x6ff: 0xf5, // Block 0x1c, offset 0x700 0x720: 0x18, 0x730: 0x09, 0x731: 0x09, 0x732: 0x09, 0x733: 0x09, 0x734: 0x09, 0x735: 0x09, 0x736: 0x09, 0x737: 0x09, diff --git a/vendor/github.com/clipperhouse/displaywidth/width.go b/vendor/github.com/clipperhouse/displaywidth/width.go index bd6b65f047..55dd4584c0 100644 --- a/vendor/github.com/clipperhouse/displaywidth/width.go +++ b/vendor/github.com/clipperhouse/displaywidth/width.go @@ -34,7 +34,7 @@ func (options Options) String(s string) int { case 0: return 0 case 1: - return int(asciiWidths[s[0]]) + return asciiWidth(s[0]) } width := 0 @@ -60,7 +60,7 @@ func (options Options) Bytes(s []byte) int { case 0: return 0 case 1: - return int(asciiWidths[s[0]]) + return asciiWidth(s[0]) } width := 0 @@ -90,7 +90,7 @@ func Rune(r rune) int { // Iterating over runes to measure width is incorrect in many cases. func (options Options) Rune(r rune) int { if r < utf8.RuneSelf { - return int(asciiWidths[byte(r)]) + return asciiWidth(byte(r)) } // Surrogates (U+D800-U+DFFF) are invalid UTF-8. @@ -102,9 +102,11 @@ func (options Options) Rune(r rune) int { n := utf8.EncodeRune(buf[:], r) // Skip the grapheme iterator - return lookupProperties(buf[:n]).width(options) + return graphemeWidth(buf[:n], options) } +const _Default property = 0 + // graphemeWidth returns the display width of a grapheme cluster. // The passed string must be a single grapheme cluster. func graphemeWidth[T stringish.Interface](s T, options Options) int { @@ -113,99 +115,65 @@ func graphemeWidth[T stringish.Interface](s T, options Options) int { case 0: return 0 case 1: - return int(asciiWidths[s[0]]) - } - - return lookupProperties(s).width(options) -} - -// isRIPrefix checks if the slice matches the Regional Indicator prefix -// (F0 9F 87). It assumes len(s) >= 3. -func isRIPrefix[T stringish.Interface](s T) bool { - return s[0] == 0xF0 && s[1] == 0x9F && s[2] == 0x87 -} - -// isVS16 checks if the slice matches VS16 (U+FE0F) UTF-8 encoding -// (EF B8 8F). It assumes len(s) >= 3. -func isVS16[T stringish.Interface](s T) bool { - return s[0] == 0xEF && s[1] == 0xB8 && s[2] == 0x8F -} - -// lookupProperties returns the properties for a grapheme. -// The passed string must be at least one byte long. -// -// Callers must handle zero and single-byte strings upstream, both as an -// optimization, and to reduce the scope of this function. -func lookupProperties[T stringish.Interface](s T) property { - l := len(s) - - if s[0] < utf8.RuneSelf { - // Check for variation selector after ASCII (e.g., keycap sequences like 1️⃣) - if l >= 4 { - // Subslice may help eliminate bounds checks - vs := s[1:4] - if isVS16(vs) { - // VS16 requests emoji presentation (width 2) - return _Emoji - } - // VS15 (0x8E) requests text presentation but does not affect width, - // in my reading of Unicode TR51. Falls through to _Default. - } - return asciiProperties[s[0]] - } - - // Regional indicator pair (flag) - if l >= 8 { - // Subslice may help eliminate bounds checks - ri := s[:8] - // First rune - if isRIPrefix(ri[0:3]) { - b3 := ri[3] - if b3 >= 0xA6 && b3 <= 0xBF { - // Second rune - if isRIPrefix(ri[4:7]) { - b7 := ri[7] - if b7 >= 0xA6 && b7 <= 0xBF { - return _Emoji - } - } - } - } + return asciiWidth(s[0]) } p, sz := lookup(s) + prop := property(p) - // Variation Selectors - if sz > 0 && l >= sz+3 { - // Subslice may help eliminate bounds checks + // Variation Selector 16 (VS16) requests emoji presentation + if sz > 0 && len(s) >= sz+3 { vs := s[sz : sz+3] if isVS16(vs) { - // VS16 requests emoji presentation (width 2) - return _Emoji + prop = _Emoji } // VS15 (0x8E) requests text presentation but does not affect width, // in my reading of Unicode TR51. Falls through to return the base // character's property. } - return property(p) -} + /* + Note: we previously had some regional indicator handling here, + intending to treat single RI's as width 1 and pairs as width 2. + We think that's what the Unicode #11 indicates? -const _Default property = 0 -const boundsCheck = property(len(propertyWidths) - 1) + Then we looked at what actual terminals do, and they seem to treat + single and paired RI's as width 2, regardless. See terminal-test/. + Looks like VS Code does the same FWIW. + */ -// width determines the display width of a character based on its properties, -// and configuration options -func (p property) width(options Options) int { - if options.EastAsianWidth && p == _East_Asian_Ambiguous { - return 2 + if options.EastAsianWidth && prop == _East_Asian_Ambiguous { + prop = _East_Asian_Wide } - // Bounds check may help the compiler eliminate its bounds check, - // and safety of course. - if p > boundsCheck { - return 1 // default width + if prop > upperBound { + prop = _Default } - return propertyWidths[p] + return propertyWidths[prop] } + +func asciiWidth(b byte) int { + if b <= 0x1F || b == 0x7F { + return 0 + } + return 1 +} + +// isVS16 checks if the slice matches VS16 (U+FE0F) UTF-8 encoding +// (EF B8 8F). It assumes len(s) >= 3. +func isVS16[T stringish.Interface](s T) bool { + return s[0] == 0xEF && s[1] == 0xB8 && s[2] == 0x8F +} + +// propertyWidths is a jump table of sorts, instead of a switch +var propertyWidths = [6]int{ + _Default: 1, + _Zero_Width: 0, + _East_Asian_Wide: 2, + _East_Asian_Ambiguous: 1, + _Emoji: 2, + _Regional_Indicator: 2, +} + +const upperBound = property(len(propertyWidths) - 1) diff --git a/vendor/github.com/dop251/goja/destruct.go b/vendor/github.com/dop251/goja/destruct.go index 66792dc3f6..5323dc58ff 100644 --- a/vendor/github.com/dop251/goja/destruct.go +++ b/vendor/github.com/dop251/goja/destruct.go @@ -1,14 +1,15 @@ package goja import ( - "github.com/dop251/goja/unistring" "reflect" + + "github.com/dop251/goja/unistring" ) type destructKeyedSource struct { r *Runtime wrapped Value - usedKeys map[Value]struct{} + usedKeys propNameSet } func newDestructKeyedSource(r *Runtime, wrapped Value) *destructKeyedSource { @@ -30,10 +31,7 @@ func (d *destructKeyedSource) w() objectImpl { } func (d *destructKeyedSource) recordKey(key Value) { - if d.usedKeys == nil { - d.usedKeys = make(map[Value]struct{}) - } - d.usedKeys[key] = struct{}{} + d.usedKeys.add(key) } func (d *destructKeyedSource) sortLen() int { @@ -202,7 +200,7 @@ func (i *destructKeyedSourceIter) next() (propIterItem, iterNextFunc) { return item, nil } i.wrapped = next - if _, exists := i.d.usedKeys[item.name]; !exists { + if !i.d.usedKeys.has(item.name) { return item, i.next } } @@ -268,7 +266,7 @@ func (d *destructKeyedSource) stringKeys(all bool, accum []Value) []Value { func (d *destructKeyedSource) filterUsedKeys(keys []Value) []Value { k := 0 for i, key := range keys { - if _, exists := d.usedKeys[key]; exists { + if d.usedKeys.has(key) { continue } if k != i { diff --git a/vendor/github.com/dop251/goja/object.go b/vendor/github.com/dop251/goja/object.go index 79bd67df42..9a02e084b1 100644 --- a/vendor/github.com/dop251/goja/object.go +++ b/vendor/github.com/dop251/goja/object.go @@ -1822,3 +1822,43 @@ func (i *privateId) String() string { func (i *privateId) string() unistring.String { return privateIdString(i.name) } + +type propNameSet struct { + stringProps map[unistring.String]struct{} + symbolProps map[*Symbol]struct{} +} + +func (s *propNameSet) add(prop Value) { + if sym, ok := prop.(*Symbol); ok { + if s.symbolProps == nil { + s.symbolProps = make(map[*Symbol]struct{}) + } + s.symbolProps[sym] = struct{}{} + } else { + if s.stringProps == nil { + s.stringProps = make(map[unistring.String]struct{}) + } + s.stringProps[prop.string()] = struct{}{} + } +} + +func (s *propNameSet) has(prop Value) bool { + if sym, ok := prop.(*Symbol); ok { + _, exists := s.symbolProps[sym] + return exists + } + _, exists := s.stringProps[prop.string()] + return exists +} + +func (s *propNameSet) delete(prop Value) { + if sym, ok := prop.(*Symbol); ok { + delete(s.symbolProps, sym) + } else { + delete(s.stringProps, prop.string()) + } +} + +func (s *propNameSet) size() int { + return len(s.stringProps) + len(s.symbolProps) +} diff --git a/vendor/github.com/dop251/goja/proxy.go b/vendor/github.com/dop251/goja/proxy.go index e9bd8c9675..8974ae1580 100644 --- a/vendor/github.com/dop251/goja/proxy.go +++ b/vendor/github.com/dop251/goja/proxy.go @@ -351,7 +351,7 @@ func (p *proxyObject) preventExtensions(throw bool) bool { p.val.runtime.typeErrorResult(throw, "'preventExtensions' on proxy: trap returned falsish") return false } - if te := target.self.isExtensible(); booleanTrapResult && te { + if target.self.isExtensible() { panic(p.val.runtime.NewTypeError("'preventExtensions' on proxy: trap returned truish but the proxy target is extensible")) } } @@ -791,7 +791,7 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) { if v, ok := p.checkHandler().ownKeys(target); ok { keys := p.val.runtime.toObject(v) var keyList []Value - keySet := make(map[Value]struct{}) + var keySet propNameSet l := toLength(keys.self.getStr("length", nil)) for k := int64(0); k < l; k++ { item := keys.self.getIdx(valueInt(k), nil) @@ -800,16 +800,16 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) { panic(p.val.runtime.NewTypeError("%s is not a valid property name", item.String())) } } - if _, exists := keySet[item]; exists { + if keySet.has(item) { panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned duplicate entries")) } keyList = append(keyList, item) - keySet[item] = struct{}{} + keySet.add(item) } ext := target.self.isExtensible() for item, next := target.self.iterateKeys()(); next != nil; item, next = next() { - if _, exists := keySet[item.name]; exists { - delete(keySet, item.name) + if keySet.has(item.name) { + keySet.delete(item.name) } else { if !ext { panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include '%s'", item.name.String())) @@ -825,7 +825,7 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) { } } } - if !ext && len(keyList) > 0 && len(keySet) > 0 { + if !ext && len(keyList) > 0 && keySet.size() > 0 { panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible")) } diff --git a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md index cc0d551a46..821d303e6f 100644 --- a/vendor/github.com/getsentry/sentry-go/CHANGELOG.md +++ b/vendor/github.com/getsentry/sentry-go/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.40.0 + +The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.40.0. + +### Bug Fixes + +- Disable `DisableTelemetryBuffer` flag and noop Telemetry Buffer, to prevent a panic at runtime ([#1149](https://github.com/getsentry/sentry-go/pull/1149)). + ## 0.39.0 The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.39.0. diff --git a/vendor/github.com/getsentry/sentry-go/client.go b/vendor/github.com/getsentry/sentry-go/client.go index b785b987d4..3aa267f706 100644 --- a/vendor/github.com/getsentry/sentry-go/client.go +++ b/vendor/github.com/getsentry/sentry-go/client.go @@ -380,9 +380,11 @@ func NewClient(options ClientOptions) (*Client, error) { client.setupTransport() - if !options.DisableTelemetryBuffer { - client.setupTelemetryBuffer() - } else if options.EnableLogs { + // noop Telemetry Buffers fow now + // if !options.DisableTelemetryBuffer { + // client.setupTelemetryBuffer() + // } else + if options.EnableLogs { client.batchLogger = NewBatchLogger(&client) client.batchLogger.Start() } @@ -408,7 +410,7 @@ func (client *Client) setupTransport() { client.Transport = transport } -func (client *Client) setupTelemetryBuffer() { +func (client *Client) setupTelemetryBuffer() { // nolint: unused if client.options.DisableTelemetryBuffer { return } diff --git a/vendor/github.com/getsentry/sentry-go/sentry.go b/vendor/github.com/getsentry/sentry-go/sentry.go index 2f1e362c91..4193bcd98d 100644 --- a/vendor/github.com/getsentry/sentry-go/sentry.go +++ b/vendor/github.com/getsentry/sentry-go/sentry.go @@ -6,7 +6,7 @@ import ( ) // The version of the SDK. -const SDKVersion = "0.39.0" +const SDKVersion = "0.40.0" // apiVersion is the minimum version of the Sentry API compatible with the // sentry-go SDK. diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 244ee19c4b..af2ef63953 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -27,6 +27,16 @@ Use the links above for more information on each. # changelog +* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) + * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079 + * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059 + * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080 + * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086 + * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090 + * flate: Faster load+store https://github.com/klauspost/compress/pull/1104 + * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101 + * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103 + * Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0) * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036 * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028 @@ -36,6 +46,9 @@ Use the links above for more information on each. * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049 * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050 +
+ See changes to v1.17.x + * Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11) * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017 * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014 @@ -102,7 +115,8 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839 * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837 * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860 - + +
See changes to v1.16.x @@ -669,3 +683,4 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv # license This code is licensed under the same conditions as the original Go code. See LICENSE file. + diff --git a/vendor/github.com/pion/ice/v4/.golangci.yml b/vendor/github.com/pion/ice/v4/.golangci.yml index 88cb4fbf9e..4b4025fbc8 100644 --- a/vendor/github.com/pion/ice/v4/.golangci.yml +++ b/vendor/github.com/pion/ice/v4/.golangci.yml @@ -1,43 +1,7 @@ # SPDX-FileCopyrightText: 2023 The Pion community # SPDX-License-Identifier: MIT -run: - timeout: 5m - -linters-settings: - govet: - enable: - - shadow - misspell: - locale: US - exhaustive: - default-signifies-exhaustive: true - gomodguard: - blocked: - modules: - - github.com/pkg/errors: - recommendations: - - errors - forbidigo: - forbid: - - ^fmt.Print(f|ln)?$ - - ^log.(Panic|Fatal|Print)(f|ln)?$ - - ^os.Exit$ - - ^panic$ - - ^print(ln)?$ - varnamelen: - max-distance: 12 - min-name-length: 2 - ignore-type-assert-ok: true - ignore-map-index-ok: true - ignore-chan-recv-ok: true - ignore-decls: - - i int - - n int - - w io.Writer - - r io.Reader - - b []byte - +version: "2" linters: enable: - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers @@ -56,10 +20,8 @@ linters: - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. - exhaustive # check exhaustiveness of enum switch statements - - exportloopref # checks for pointers to enclosing loop variables - forbidigo # Forbids identifiers - forcetypeassert # finds forced type assertions - - gci # Gci control golang package import order and make it always deterministic. - gochecknoglobals # Checks that no globals are present in Go code - gocognit # Computes and checks the cognitive complexity of functions - goconst # Finds repeated strings that could be replaced by a constant @@ -67,14 +29,10 @@ linters: - gocyclo # Computes and checks the cyclomatic complexity of functions - godot # Check if comments end in a period - godox # Tool for detection of FIXME, TODO and other comment keywords - - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification - - gofumpt # Gofumpt checks whether code was gofumpt-ed. - goheader # Checks is file header matches to pattern - - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - goprintffuncname # Checks that printf-like functions are named with `f` at the end - gosec # Inspects source code for security problems - - gosimple # Linter for Go source code that specializes in simplifying a code - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string - grouper # An analyzer to analyze expression groups. - importas # Enforces consistent import aliases @@ -92,11 +50,8 @@ linters: - predeclared # find code that shadows one of Go's predeclared identifiers - revive # golint replacement, finds style mistakes - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks - - stylecheck # Stylecheck is a replacement for golint - tagliatelle # Checks the struct tags. - - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code - unconvert # Remove unnecessary type conversions - unparam # Reports unused function parameters - unused # Checks Go code for unused constants, variables, functions and types @@ -121,18 +76,72 @@ linters: - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - wrapcheck # Checks that errors returned from external packages are wrapped - wsl # Whitespace Linter - Forces you to use empty lines! - -issues: - exclude-use-default: false - exclude-dirs-use-default: false - exclude-rules: - # Allow complex tests and examples, better to be self contained - - path: (examples|main\.go|_test\.go) - linters: - - forbidigo - - gocognit - - # Allow forbidden identifiers in CLI commands - - path: cmd - linters: - - forbidigo + settings: + staticcheck: + checks: + - all + - -QF1008 # "could remove embedded field", to keep it explicit! + - -QF1003 # "could use tagged switch on enum", Cases conflicts with exhaustive! + exhaustive: + default-signifies-exhaustive: true + forbidigo: + forbid: + - pattern: ^fmt.Print(f|ln)?$ + - pattern: ^log.(Panic|Fatal|Print)(f|ln)?$ + - pattern: ^os.Exit$ + - pattern: ^panic$ + - pattern: ^print(ln)?$ + - pattern: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$ + pkg: ^testing$ + msg: use testify/assert instead + analyze-types: true + gomodguard: + blocked: + modules: + - github.com/pkg/errors: + recommendations: + - errors + govet: + enable: + - shadow + revive: + rules: + # Prefer 'any' type alias over 'interface{}' for Go 1.18+ compatibility + - name: use-any + severity: warning + disabled: false + misspell: + locale: US + varnamelen: + max-distance: 12 + min-name-length: 2 + ignore-type-assert-ok: true + ignore-map-index-ok: true + ignore-chan-recv-ok: true + ignore-decls: + - i int + - n int + - w io.Writer + - r io.Reader + - b []byte + exclusions: + generated: lax + rules: + - linters: + - forbidigo + - gocognit + path: (examples|main\.go) + - linters: + - gocognit + path: _test\.go + - linters: + - forbidigo + path: cmd +formatters: + enable: + - gci # Gci control golang package import order and make it always deterministic. + - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification + - gofumpt # Gofumpt checks whether code was gofumpt-ed. + - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports + exclusions: + generated: lax diff --git a/vendor/github.com/pion/ice/v4/active_tcp.go b/vendor/github.com/pion/ice/v4/active_tcp.go index b55e650417..2fd466b29a 100644 --- a/vendor/github.com/pion/ice/v4/active_tcp.go +++ b/vendor/github.com/pion/ice/v4/active_tcp.go @@ -18,7 +18,7 @@ import ( type activeTCPConn struct { readBuffer, writeBuffer *packetio.Buffer localAddr, remoteAddr atomic.Value - closed int32 + closed atomic.Bool } func newActiveTCPConn( @@ -34,7 +34,7 @@ func newActiveTCPConn( laddr, err := getTCPAddrOnInterface(localAddress) if err != nil { - atomic.StoreInt32(&a.closed, 1) + a.closed.Store(true) log.Infof("Failed to dial TCP address %s: %v", remoteAddress, err) return a @@ -43,7 +43,7 @@ func newActiveTCPConn( go func() { defer func() { - atomic.StoreInt32(&a.closed, 1) + a.closed.Store(true) }() dialer := &net.Dialer{ @@ -60,7 +60,7 @@ func newActiveTCPConn( go func() { buff := make([]byte, receiveMTU) - for atomic.LoadInt32(&a.closed) == 0 { + for !a.closed.Load() { n, err := readStreamingPacket(conn, buff) if err != nil { log.Infof("Failed to read streaming packet: %s", err) @@ -78,7 +78,7 @@ func newActiveTCPConn( buff := make([]byte, receiveMTU) - for atomic.LoadInt32(&a.closed) == 0 { + for !a.closed.Load() { n, err := a.writeBuffer.Read(buff) if err != nil { log.Infof("Failed to read from buffer: %s", err) @@ -102,7 +102,7 @@ func newActiveTCPConn( } func (a *activeTCPConn) ReadFrom(buff []byte) (n int, srcAddr net.Addr, err error) { - if atomic.LoadInt32(&a.closed) == 1 { + if a.closed.Load() { return 0, nil, io.ErrClosedPipe } @@ -114,7 +114,7 @@ func (a *activeTCPConn) ReadFrom(buff []byte) (n int, srcAddr net.Addr, err erro } func (a *activeTCPConn) WriteTo(buff []byte, _ net.Addr) (n int, err error) { - if atomic.LoadInt32(&a.closed) == 1 { + if a.closed.Load() { return 0, io.ErrClosedPipe } @@ -122,7 +122,7 @@ func (a *activeTCPConn) WriteTo(buff []byte, _ net.Addr) (n int, err error) { } func (a *activeTCPConn) Close() error { - atomic.StoreInt32(&a.closed, 1) + a.closed.Store(true) _ = a.readBuffer.Close() _ = a.writeBuffer.Close() diff --git a/vendor/github.com/pion/ice/v4/agent.go b/vendor/github.com/pion/ice/v4/agent.go index 80c89d05bb..7fc3ce31e2 100644 --- a/vendor/github.com/pion/ice/v4/agent.go +++ b/vendor/github.com/pion/ice/v4/agent.go @@ -29,10 +29,11 @@ import ( ) type bindingRequest struct { - timestamp time.Time - transactionID [stun.TransactionIDSize]byte - destination net.Addr - isUseCandidate bool + timestamp time.Time + transactionID [stun.TransactionIDSize]byte + destination net.Addr + isUseCandidate bool + nominationValue *uint32 // Tracks nomination value for renomination requests } // Agent represents the ICE agent. @@ -62,7 +63,7 @@ type Agent struct { muHaveStarted sync.Mutex startedCh <-chan struct{} startedFn func() - isControlling bool + isControlling atomic.Bool maxBindingRequests uint16 @@ -104,12 +105,16 @@ type Agent struct { remoteCandidates map[NetworkType][]Candidate checklist []*CandidatePair - selector pairCandidateSelector + + selectorLock sync.RWMutex + selector pairCandidateSelector selectedPair atomic.Value // *CandidatePair - urls []*stun.URI - networkTypes []NetworkType + urls []*stun.URI + networkTypes []NetworkType + natCandidateType CandidateType + natIPs []string buf *packetio.Buffer @@ -147,29 +152,59 @@ type Agent struct { proxyDialer proxy.Dialer enableUseCandidateCheckPriority bool + + // Renomination support + enableRenomination bool + nominationValueGenerator func() uint32 + nominationAttribute stun.AttrType + + // Continual gathering support + continualGatheringPolicy ContinualGatheringPolicy + networkMonitorInterval time.Duration + lastKnownInterfaces map[string]netip.Addr // map[iface+ip] for deduplication + + // Automatic renomination + automaticRenomination bool + renominationInterval time.Duration + lastRenominationTime time.Time } // NewAgent creates a new Agent. -func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop - var err error - if config.PortMax < config.PortMin { - return nil, ErrPort +func NewAgent(config *AgentConfig) (*Agent, error) { + return newAgentFromConfig(config) +} + +// NewAgentWithOptions creates a new Agent with options only. +func NewAgentWithOptions(opts ...AgentOption) (*Agent, error) { + return newAgentFromConfig(&AgentConfig{}, opts...) +} + +func newAgentFromConfig(config *AgentConfig, opts ...AgentOption) (*Agent, error) { + if config == nil { + config = &AgentConfig{} } - mDNSName := config.MulticastDNSHostName - if mDNSName == "" { - if mDNSName, err = generateMulticastDNSName(); err != nil { - return nil, err - } + agent, err := createAgentBase(config) + if err != nil { + return nil, err } - if !strings.HasSuffix(mDNSName, ".local") || len(strings.Split(mDNSName, ".")) != 2 { - return nil, ErrInvalidMulticastDNSHostName + agent.localUfrag = config.LocalUfrag + agent.localPwd = config.LocalPwd + agent.natCandidateType = config.NAT1To1IPCandidateType + agent.natIPs = config.NAT1To1IPs + + return newAgentWithConfig(agent, opts...) +} + +func createAgentBase(config *AgentConfig) (*Agent, error) { + if config.PortMax < config.PortMin { + return nil, ErrPort } - mDNSMode := config.MulticastDNSMode - if mDNSMode == 0 { - mDNSMode = MulticastDNSModeQueryOnly + mDNSName, mDNSMode, err := setupMDNSConfig(config) + if err != nil { + return nil, err } loggerFactory := config.LoggerFactory @@ -181,49 +216,117 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop startedCtx, startedFn := context.WithCancel(context.Background()) agent := &Agent{ - tieBreaker: globalMathRandomGenerator.Uint64(), - lite: config.Lite, - gatheringState: GatheringStateNew, - connectionState: ConnectionStateNew, - localCandidates: make(map[NetworkType][]Candidate), - remoteCandidates: make(map[NetworkType][]Candidate), - urls: config.Urls, - networkTypes: config.NetworkTypes, - onConnected: make(chan struct{}), - buf: packetio.NewBuffer(), - startedCh: startedCtx.Done(), - startedFn: startedFn, - portMin: config.PortMin, - portMax: config.PortMax, - loggerFactory: loggerFactory, - log: log, - net: config.Net, - proxyDialer: config.ProxyDialer, - tcpMux: config.TCPMux, - udpMux: config.UDPMux, - udpMuxSrflx: config.UDPMuxSrflx, + tieBreaker: globalMathRandomGenerator.Uint64(), + lite: config.Lite, + gatheringState: GatheringStateNew, + connectionState: ConnectionStateNew, + localCandidates: make(map[NetworkType][]Candidate), + remoteCandidates: make(map[NetworkType][]Candidate), + urls: config.Urls, + networkTypes: config.NetworkTypes, + onConnected: make(chan struct{}), + buf: packetio.NewBuffer(), + startedCh: startedCtx.Done(), + startedFn: startedFn, + portMin: config.PortMin, + portMax: config.PortMax, + loggerFactory: loggerFactory, + log: log, + net: config.Net, + proxyDialer: config.ProxyDialer, + tcpMux: config.TCPMux, + udpMux: config.UDPMux, + udpMuxSrflx: config.UDPMuxSrflx, + mDNSMode: mDNSMode, + mDNSName: mDNSName, + gatherCandidateCancel: func() {}, + forceCandidateContact: make(chan bool, 1), + interfaceFilter: config.InterfaceFilter, + ipFilter: config.IPFilter, + insecureSkipVerify: config.InsecureSkipVerify, + includeLoopback: config.IncludeLoopback, + disableActiveTCP: config.DisableActiveTCP, + userBindingRequestHandler: config.BindingRequestHandler, + enableUseCandidateCheckPriority: config.EnableUseCandidateCheckPriority, + enableRenomination: false, + nominationValueGenerator: nil, + nominationAttribute: stun.AttrType(0x0030), // Default value + continualGatheringPolicy: GatherOnce, // Default to GatherOnce + networkMonitorInterval: 2 * time.Second, + lastKnownInterfaces: make(map[string]netip.Addr), + automaticRenomination: false, + renominationInterval: 3 * time.Second, // Default matching libwebrtc + } - mDNSMode: mDNSMode, - mDNSName: mDNSName, + config.initWithDefaults(agent) - gatherCandidateCancel: func() {}, + return agent, nil +} - forceCandidateContact: make(chan bool, 1), +func applyExternalIPMapping(agent *Agent, candidateType CandidateType, ips []string) error { + mapper, err := newExternalIPMapper(candidateType, ips) + if err != nil { + return err + } - interfaceFilter: config.InterfaceFilter, + agent.extIPMapper = mapper + if agent.extIPMapper == nil { + return nil + } - ipFilter: config.IPFilter, + switch agent.extIPMapper.candidateType { + case CandidateTypeHost: + if agent.mDNSMode == MulticastDNSModeQueryAndGather { + return ErrMulticastDNSWithNAT1To1IPMapping + } + if !containsCandidateType(CandidateTypeHost, agent.candidateTypes) { + return ErrIneffectiveNAT1To1IPMappingHost + } + case CandidateTypeServerReflexive: + if !containsCandidateType(CandidateTypeServerReflexive, agent.candidateTypes) { + return ErrIneffectiveNAT1To1IPMappingSrflx + } + default: + return nil + } - insecureSkipVerify: config.InsecureSkipVerify, + return nil +} - includeLoopback: config.IncludeLoopback, +// setupMDNSConfig validates and returns mDNS configuration. +func setupMDNSConfig(config *AgentConfig) (string, MulticastDNSMode, error) { + mDNSName := config.MulticastDNSHostName + if mDNSName == "" { + var err error + if mDNSName, err = generateMulticastDNSName(); err != nil { + return "", 0, err + } + } - disableActiveTCP: config.DisableActiveTCP, + if !strings.HasSuffix(mDNSName, ".local") || len(strings.Split(mDNSName, ".")) != 2 { + return "", 0, ErrInvalidMulticastDNSHostName + } - userBindingRequestHandler: config.BindingRequestHandler, + mDNSMode := config.MulticastDNSMode + if mDNSMode == 0 { + mDNSMode = MulticastDNSModeQueryOnly + } - enableUseCandidateCheckPriority: config.EnableUseCandidateCheckPriority, + return mDNSName, mDNSMode, nil +} + +// newAgentWithConfig finalizes a pre-configured agent with optional overrides. +// +//nolint:gocognit,cyclop +func newAgentWithConfig(agent *Agent, opts ...AgentOption) (*Agent, error) { + var err error + + for _, opt := range opts { + if err = opt(agent); err != nil { + return nil, err + } } + agent.connectionStateNotifier = &handlerNotifier{ connectionStateFunc: agent.onConnectionStateChange, done: make(chan struct{}), @@ -264,16 +367,14 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop agent.networkTypes, localIfcs, agent.includeLoopback, - mDNSMode, - mDNSName, - log, - loggerFactory, + agent.mDNSMode, + agent.mDNSName, + agent.log, + agent.loggerFactory, ); err != nil { - log.Warnf("Failed to initialize mDNS %s: %v", mDNSName, err) + agent.log.Warnf("Failed to initialize mDNS %s: %v", agent.mDNSName, err) } - config.initWithDefaults(agent) - // Make sure the buffer doesn't grow indefinitely. // NOTE: We actually won't get anywhere close to this limit. // SRTP will constantly read from the endpoint and drop packets if it's full. @@ -285,7 +386,7 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop return nil, ErrLiteUsingNonHostCandidates } - if len(config.Urls) > 0 && + if len(agent.urls) > 0 && !containsCandidateType(CandidateTypeServerReflexive, agent.candidateTypes) && !containsCandidateType(CandidateTypeRelay, agent.candidateTypes) { agent.closeMulticastConn() @@ -293,7 +394,7 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop return nil, ErrUselessUrlsProvided } - if err = config.initExtIPMapping(agent); err != nil { + if err = applyExternalIPMapping(agent, agent.natCandidateType, agent.natIPs); err != nil { agent.closeMulticastConn() return nil, err @@ -318,7 +419,7 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit,cyclop }) // Restart is also used to initialize the agent for the first time - if err := agent.Restart(config.LocalUfrag, config.LocalPwd); err != nil { + if err := agent.Restart(agent.localUfrag, agent.localPwd); err != nil { agent.closeMulticastConn() _ = agent.Close() @@ -343,21 +444,11 @@ func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remoteP a.log.Debugf("Started agent: isControlling? %t, remoteUfrag: %q, remotePwd: %q", isControlling, remoteUfrag, remotePwd) return a.loop.Run(a.loop, func(_ context.Context) { - a.isControlling = isControlling + a.isControlling.Store(isControlling) a.remoteUfrag = remoteUfrag a.remotePwd = remotePwd + a.setSelector() - if isControlling { - a.selector = &controllingSelector{agent: a, log: a.log} - } else { - a.selector = &controlledSelector{agent: a, log: a.log} - } - - if a.lite { - a.selector = &liteSelector{pairCandidateSelector: a.selector} - } - - a.selector.Start() a.startedFn() a.updateConnectionState(ConnectionStateChecking) @@ -397,7 +488,7 @@ func (a *Agent) connectivityChecks() { //nolint:cyclop default: } - a.selector.ContactCandidates() + a.getSelector().ContactCandidates() }); err != nil { a.log.Warnf("Failed to start connectivity checks: %v", err) } @@ -474,13 +565,14 @@ func (a *Agent) setSelectedPair(pair *CandidatePair) { a.selectedPair.Store(pair) a.log.Tracef("Set selected candidate pair: %s", pair) + // Signal connected: notify any Connect() calls waiting on onConnected + a.onConnectedOnce.Do(func() { close(a.onConnected) }) + + // Update connection state to Connected and notify state change handlers a.updateConnectionState(ConnectionStateConnected) - // Notify when the selected pair changes + // Notify when the selected candidate pair changes a.selectedCandidatePairNotifier.EnqueueSelectedCandidatePair(pair) - - // Signal connected - a.onConnectedOnce.Do(func() { close(a.onConnected) }) } func (a *Agent) pingAllCandidates() { @@ -501,12 +593,42 @@ func (a *Agent) pingAllCandidates() { a.log.Tracef("Maximum requests reached for pair %s, marking it as failed", p) p.state = CandidatePairStateFailed } else { - a.selector.PingCandidate(p.Local, p.Remote) + a.getSelector().PingCandidate(p.Local, p.Remote) p.bindingRequestCount++ } } } +// keepAliveCandidatesForRenomination pings all candidate pairs to keep them tested +// and ready for automatic renomination. Unlike pingAllCandidates, this: +// - Pings pairs in succeeded state to keep RTT measurements fresh +// - Ignores maxBindingRequests limit (we want to keep testing alternate paths) +// - Only pings pairs that are not failed. +func (a *Agent) keepAliveCandidatesForRenomination() { + a.log.Trace("Keep alive candidates for automatic renomination") + + if len(a.checklist) == 0 { + return + } + + for _, pair := range a.checklist { + switch pair.state { + case CandidatePairStateFailed: + // Skip failed pairs + continue + case CandidatePairStateWaiting: + // Transition waiting pairs to in-progress + pair.state = CandidatePairStateInProgress + case CandidatePairStateInProgress, CandidatePairStateSucceeded: + // Continue pinging in-progress and succeeded pairs + } + + // Ping all non-failed pairs (including succeeded ones) + // to keep RTT measurements fresh for renomination decisions + a.getSelector().PingCandidate(pair.Local, pair.Remote) + } +} + func (a *Agent) getBestAvailableCandidatePair() *CandidatePair { var best *CandidatePair for _, p := range a.checklist { @@ -542,7 +664,7 @@ func (a *Agent) getBestValidCandidatePair() *CandidatePair { } func (a *Agent) addPair(local, remote Candidate) *CandidatePair { - p := newCandidatePair(local, remote, a.isControlling) + p := newCandidatePair(local, remote, a.isControlling.Load()) a.checklist = append(a.checklist, p) return p @@ -598,7 +720,7 @@ func (a *Agent) checkKeepalive() { if a.keepaliveInterval != 0 { // We use binding request instead of indication to support refresh consent schemas // see https://tools.ietf.org/html/rfc7675 - a.selector.PingCandidate(selectedPair.Local, selectedPair.Remote) + a.getSelector().PingCandidate(selectedPair.Local, selectedPair.Remote) } } @@ -869,6 +991,19 @@ func (a *Agent) GetLocalCandidates() ([]Candidate, error) { return res, nil } +// GetGatheringState returns the current gathering state of the Agent. +func (a *Agent) GetGatheringState() (GatheringState, error) { + var state GatheringState + err := a.loop.Run(a.loop, func(_ context.Context) { + state = a.gatheringState + }) + if err != nil { + return GatheringStateUnknown, err + } + + return state, nil +} + // GetLocalUserCredentials returns the local user credentials. func (a *Agent) GetLocalUserCredentials() (frag string, pwd string, err error) { valSet := make(chan struct{}) @@ -982,12 +1117,20 @@ func (a *Agent) findRemoteCandidate(networkType NetworkType, addr net.Addr) Cand func (a *Agent) sendBindingRequest(msg *stun.Message, local, remote Candidate) { a.log.Tracef("Ping STUN from %s to %s", local, remote) + // Extract nomination value if present + var nominationValue *uint32 + var nomination NominationAttribute + if err := nomination.GetFromWithType(msg, a.nominationAttribute); err == nil { + nominationValue = &nomination.Value + } + a.invalidatePendingBindingRequests(time.Now()) a.pendingBindingRequests = append(a.pendingBindingRequests, bindingRequest{ - timestamp: time.Now(), - transactionID: msg.TransactionID, - destination: remote.addr(), - isUseCandidate: msg.Contains(stun.AttrUseCandidate), + timestamp: time.Now(), + transactionID: msg.TransactionID, + destination: remote.addr(), + isUseCandidate: msg.Contains(stun.AttrUseCandidate), + nominationValue: nominationValue, }) if pair := a.findPair(local, remote); pair != nil { @@ -1064,44 +1207,57 @@ func (a *Agent) handleInboundBindingSuccess(id [stun.TransactionIDSize]byte) (bo return false, nil, 0 } +func (a *Agent) handleRoleConflict(msg *stun.Message, local, remote Candidate, remoteTieBreaker *AttrControl) { + localIsGreaterOrEqual := a.tieBreaker >= remoteTieBreaker.Tiebreaker + a.log.Warnf("Role conflict local and remote same role(%s), localIsGreaterOrEqual(%t)", a.role(), localIsGreaterOrEqual) + + // https://datatracker.ietf.org/doc/html/rfc8445#section-7.3.1.1 + // An agent MUST examine the Binding request for either the ICE- + // CONTROLLING or ICE-CONTROLLED attribute. It MUST follow these + // procedures: + + // If the agent's tiebreaker value is larger than or equal to the contents of the ICE-CONTROLLING attribute + // If the agent's tiebreaker value is less than the contents of the ICE-CONTROLLED attribute + // the agent generates a Binding error response + if (a.isControlling.Load() && localIsGreaterOrEqual) || (!a.isControlling.Load() && !localIsGreaterOrEqual) { + if roleConflictMsg, err := stun.Build(msg, stun.BindingError, + stun.ErrorCodeAttribute{ + Code: stun.CodeRoleConflict, + Reason: []byte("Role Conflict"), + }, + stun.NewShortTermIntegrity(a.localPwd), + stun.Fingerprint, + ); err != nil { + a.log.Warnf("Failed to generate Role Conflict message from: %s to: %s error: %s", local, remote, err) + } else { + a.sendSTUN(roleConflictMsg, local, remote) + } + } else { + a.isControlling.Store(!a.isControlling.Load()) + a.setSelector() + } +} + // handleInbound processes STUN traffic from a remote candidate. func (a *Agent) handleInbound(msg *stun.Message, local Candidate, remote net.Addr) { //nolint:gocognit,cyclop - var err error if msg == nil || local == nil { return } if msg.Type.Method != stun.MethodBinding || - !(msg.Type.Class == stun.ClassSuccessResponse || - msg.Type.Class == stun.ClassRequest || - msg.Type.Class == stun.ClassIndication) { + (msg.Type.Class != stun.ClassSuccessResponse && + msg.Type.Class != stun.ClassRequest && + msg.Type.Class != stun.ClassIndication) { a.log.Tracef("Unhandled STUN from %s to %s class(%s) method(%s)", remote, local, msg.Type.Class, msg.Type.Method) return } - if a.isControlling { - if msg.Contains(stun.AttrICEControlling) { - a.log.Debug("Inbound STUN message: isControlling && a.isControlling == true") - - return - } else if msg.Contains(stun.AttrUseCandidate) { - a.log.Debug("Inbound STUN message: useCandidate && a.isControlling == true") - - return - } - } else { - if msg.Contains(stun.AttrICEControlled) { - a.log.Debug("Inbound STUN message: isControlled && a.isControlling == false") - - return - } - } - remoteCandidate := a.findRemoteCandidate(local.NetworkType(), remote) + if msg.Type.Class == stun.ClassSuccessResponse { //nolint:nestif - if err = stun.MessageIntegrity([]byte(a.remotePwd)).Check(msg); err != nil { - a.log.Warnf("Discard message from (%s), %v", remote, err) + if err := stun.MessageIntegrity([]byte(a.remotePwd)).Check(msg); err != nil { + a.log.Warnf("Discard success response with broken integrity from (%s), %v", remote, err) return } @@ -1112,7 +1268,7 @@ func (a *Agent) handleInbound(msg *stun.Message, local Candidate, remote net.Add return } - a.selector.HandleSuccessResponse(msg, local, remoteCandidate, remote) + a.getSelector().HandleSuccessResponse(msg, local, remoteCandidate, remote) } else if msg.Type.Class == stun.ClassRequest { a.log.Tracef( "Inbound STUN (Request) from %s to %s, useCandidate: %v", @@ -1121,12 +1277,12 @@ func (a *Agent) handleInbound(msg *stun.Message, local Candidate, remote net.Add msg.Contains(stun.AttrUseCandidate), ) - if err = stunx.AssertUsername(msg, a.localUfrag+":"+a.remoteUfrag); err != nil { - a.log.Warnf("Discard message from (%s), %v", remote, err) + if err := stunx.AssertUsername(msg, a.localUfrag+":"+a.remoteUfrag); err != nil { + a.log.Warnf("Discard request with wrong username from (%s), %v", remote, err) return - } else if err = stun.MessageIntegrity([]byte(a.localPwd)).Check(msg); err != nil { - a.log.Warnf("Discard message from (%s), %v", remote, err) + } else if err := stun.MessageIntegrity([]byte(a.localPwd)).Check(msg); err != nil { + a.log.Warnf("Discard request with broken integrity from (%s), %v", remote, err) return } @@ -1160,7 +1316,16 @@ func (a *Agent) handleInbound(msg *stun.Message, local Candidate, remote net.Add a.addRemoteCandidate(remoteCandidate) } - a.selector.HandleBindingRequest(msg, local, remoteCandidate) + // Support Remotes that don't set a TIE-BREAKER. Not standards compliant, but + // keeping to maintain backwards compat + remoteTieBreaker := &AttrControl{} + if err := remoteTieBreaker.GetFrom(msg); err == nil && remoteTieBreaker.Role == a.role() { + a.handleRoleConflict(msg, local, remoteCandidate, remoteTieBreaker) + + return + } + + a.getSelector().HandleBindingRequest(msg, local, remoteCandidate) } if remoteCandidate != nil { @@ -1282,9 +1447,7 @@ func (a *Agent) Restart(ufrag, pwd string) error { //nolint:cyclop a.pendingBindingRequests = make([]bindingRequest, 0) a.setSelectedPair(nil) a.deleteAllCandidates() - if a.selector != nil { - a.selector.Start() - } + a.setSelector() // Restart is used by NewAgent. Accept/Connect should be used to move to checking // for new Agents @@ -1319,3 +1482,241 @@ func (a *Agent) setGatheringState(newState GatheringState) error { func (a *Agent) needsToCheckPriorityOnNominated() bool { return !a.lite || a.enableUseCandidateCheckPriority } + +func (a *Agent) role() Role { + if a.isControlling.Load() { + return Controlling + } + + return Controlled +} + +func (a *Agent) setSelector() { + a.selectorLock.Lock() + defer a.selectorLock.Unlock() + + var s pairCandidateSelector + if a.isControlling.Load() { + s = &controllingSelector{agent: a, log: a.log} + } else { + s = &controlledSelector{agent: a, log: a.log} + } + if a.lite { + s = &liteSelector{pairCandidateSelector: s} + } + + s.Start() + a.selector = s +} + +func (a *Agent) getSelector() pairCandidateSelector { + a.selectorLock.Lock() + defer a.selectorLock.Unlock() + + return a.selector +} + +// getNominationValue returns a nomination value if generator is available, otherwise 0. +func (a *Agent) getNominationValue() uint32 { + if a.nominationValueGenerator != nil { + return a.nominationValueGenerator() + } + + return 0 +} + +// RenominateCandidate allows the controlling ICE agent to nominate a new candidate pair. +// This implements the continuous renomination feature from draft-thatcher-ice-renomination-01. +func (a *Agent) RenominateCandidate(local, remote Candidate) error { + if !a.isControlling.Load() { + return ErrOnlyControllingAgentCanRenominate + } + + if !a.enableRenomination { + return ErrRenominationNotEnabled + } + + // Find the candidate pair + pair := a.findPair(local, remote) + if pair == nil { + return ErrCandidatePairNotFound + } + + // Send nomination with custom attribute + return a.sendNominationRequest(pair, a.getNominationValue()) +} + +// sendNominationRequest sends a nomination request with custom nomination value. +func (a *Agent) sendNominationRequest(pair *CandidatePair, nominationValue uint32) error { + attributes := []stun.Setter{ + stun.TransactionID, + stun.NewUsername(a.remoteUfrag + ":" + a.localUfrag), + UseCandidate(), + AttrControlling(a.tieBreaker), + PriorityAttr(pair.Local.Priority()), + stun.NewShortTermIntegrity(a.remotePwd), + stun.Fingerprint, + } + + // Add nomination attribute if renomination is enabled and value > 0 + if a.enableRenomination && nominationValue > 0 { + attributes = append(attributes, NominationSetter{ + Value: nominationValue, + AttrType: a.nominationAttribute, + }) + a.log.Tracef("Sending renomination request from %s to %s with nomination value %d", + pair.Local, pair.Remote, nominationValue) + } + + msg, err := stun.Build(append([]stun.Setter{stun.BindingRequest}, attributes...)...) + if err != nil { + return fmt.Errorf("failed to build nomination request: %w", err) + } + + a.sendBindingRequest(msg, pair.Local, pair.Remote) + + return nil +} + +// evaluateCandidatePairQuality calculates a quality score for a candidate pair. +// Higher scores indicate better quality. The score considers: +// - Candidate types (host > srflx > relay) +// - RTT (lower is better) +// - Connection stability. +func (a *Agent) evaluateCandidatePairQuality(pair *CandidatePair) float64 { //nolint:cyclop + if pair == nil || pair.state != CandidatePairStateSucceeded { + return 0 + } + + score := float64(0) + + // Type preference scoring (host=100, srflx=50, prflx=30, relay=10) + localTypeScore := float64(0) + switch pair.Local.Type() { + case CandidateTypeHost: + localTypeScore = 100 + case CandidateTypeServerReflexive: + localTypeScore = 50 + case CandidateTypePeerReflexive: + localTypeScore = 30 + case CandidateTypeRelay: + localTypeScore = 10 + case CandidateTypeUnspecified: + localTypeScore = 0 + } + + remoteTypeScore := float64(0) + switch pair.Remote.Type() { + case CandidateTypeHost: + remoteTypeScore = 100 + case CandidateTypeServerReflexive: + remoteTypeScore = 50 + case CandidateTypePeerReflexive: + remoteTypeScore = 30 + case CandidateTypeRelay: + remoteTypeScore = 10 + case CandidateTypeUnspecified: + remoteTypeScore = 0 + } + + // Combined type score (average of local and remote) + score += (localTypeScore + remoteTypeScore) / 2 + + // RTT scoring (convert to penalty, lower RTT = higher score) + // Use current RTT if available, otherwise assume high latency + rtt := pair.CurrentRoundTripTime() + if rtt > 0 { + // Convert RTT to Duration for cleaner calculation + rttDuration := time.Duration(rtt * float64(time.Second)) + rttMs := float64(rttDuration / time.Millisecond) + if rttMs < 1 { + rttMs = 1 // Minimum 1ms to avoid log(0) + } + // Subtract RTT penalty (logarithmic to reduce impact of very high RTTs) + score -= math.Log10(rttMs) * 10 + } else { + // No RTT data available, apply moderate penalty + score -= 30 + } + + // Boost score if pair has been stable (received responses recently) + if pair.ResponsesReceived() > 0 { + lastResponse := pair.LastResponseReceivedAt() + if !lastResponse.IsZero() && time.Since(lastResponse) < 5*time.Second { + score += 20 // Stability bonus + } + } + + return score +} + +// shouldRenominate determines if automatic renomination should occur. +// It compares the current selected pair with a candidate pair and decides +// if switching would provide significant benefit. +func (a *Agent) shouldRenominate(current, candidate *CandidatePair) bool { //nolint:cyclop + if current == nil || candidate == nil || current.equal(candidate) || candidate.state != CandidatePairStateSucceeded { + return false + } + + // Type-based switching (always prefer direct over relay) + currentIsRelay := current.Local.Type() == CandidateTypeRelay || + current.Remote.Type() == CandidateTypeRelay + candidateIsDirect := candidate.Local.Type() == CandidateTypeHost && + candidate.Remote.Type() == CandidateTypeHost + + if currentIsRelay && candidateIsDirect { + a.log.Debugf("Should renominate: relay -> direct connection available") + + return true + } + + // RTT-based switching (must improve by at least 10ms) + currentRTT := current.CurrentRoundTripTime() + candidateRTT := candidate.CurrentRoundTripTime() + + // Only compare RTT if both values are valid + if currentRTT > 0 && candidateRTT > 0 { + currentRTTDuration := time.Duration(currentRTT * float64(time.Second)) + candidateRTTDuration := time.Duration(candidateRTT * float64(time.Second)) + rttImprovement := currentRTTDuration - candidateRTTDuration + + if rttImprovement > 10*time.Millisecond { + a.log.Debugf("Should renominate: RTT improvement of %v", rttImprovement) + + return true + } + } + + // Quality score comparison (must improve by at least 15%) + currentScore := a.evaluateCandidatePairQuality(current) + candidateScore := a.evaluateCandidatePairQuality(candidate) + + if candidateScore > currentScore*1.15 { + a.log.Debugf("Should renominate: quality score improved from %.2f to %.2f", + currentScore, candidateScore) + + return true + } + + return false +} + +// findBestCandidatePair finds the best available candidate pair based on quality assessment. +func (a *Agent) findBestCandidatePair() *CandidatePair { + var best *CandidatePair + bestScore := float64(-math.MaxFloat64) + + for _, pair := range a.checklist { + if pair.state != CandidatePairStateSucceeded { + continue + } + + score := a.evaluateCandidatePairQuality(pair) + if score > bestScore { + bestScore = score + best = pair + } + } + + return best +} diff --git a/vendor/github.com/pion/ice/v4/agent_config.go b/vendor/github.com/pion/ice/v4/agent_config.go index 708aab569e..151486edf1 100644 --- a/vendor/github.com/pion/ice/v4/agent_config.go +++ b/vendor/github.com/pion/ice/v4/agent_config.go @@ -38,6 +38,9 @@ const ( // defaultRelayAcceptanceMinWait is the wait time before nominating a relay candidate. defaultRelayAcceptanceMinWait = 2000 * time.Millisecond + // defaultRelayOnlyAcceptanceMinWait is the wait time before nominating with a relay only candidate. + defaultRelayOnlyAcceptanceMinWait = time.Duration(0) + // defaultSTUNGatherTimeout is the wait time for STUN responses. defaultSTUNGatherTimeout = 5 * time.Second @@ -59,6 +62,14 @@ func defaultCandidateTypes() []CandidateType { return []CandidateType{CandidateTypeHost, CandidateTypeServerReflexive, CandidateTypeRelay} } +func defaultRelayAcceptanceMinWaitFor(candidateTypes []CandidateType) time.Duration { + if len(candidateTypes) == 1 && candidateTypes[0] == CandidateTypeRelay { + return defaultRelayOnlyAcceptanceMinWait + } + + return defaultRelayAcceptanceMinWait +} + // AgentConfig collects the arguments to ice.Agent construction into // a single structure, for future-proofness of the interface. type AgentConfig struct { @@ -236,7 +247,7 @@ func (config *AgentConfig) initWithDefaults(agent *Agent) { //nolint:cyclop } if config.RelayAcceptanceMinWait == nil { - agent.relayAcceptanceMinWait = defaultRelayAcceptanceMinWait + agent.relayAcceptanceMinWait = defaultRelayAcceptanceMinWaitFor(config.CandidateTypes) } else { agent.relayAcceptanceMinWait = *config.RelayAcceptanceMinWait } @@ -283,44 +294,3 @@ func (config *AgentConfig) initWithDefaults(agent *Agent) { //nolint:cyclop agent.candidateTypes = config.CandidateTypes } } - -func (config *AgentConfig) initExtIPMapping(agent *Agent) error { //nolint:cyclop - var err error - agent.extIPMapper, err = newExternalIPMapper(config.NAT1To1IPCandidateType, config.NAT1To1IPs) - if err != nil { - return err - } - if agent.extIPMapper == nil { - return nil // This may happen when config.NAT1To1IPs is an empty array - } - if agent.extIPMapper.candidateType == CandidateTypeHost { //nolint:nestif - if agent.mDNSMode == MulticastDNSModeQueryAndGather { - return ErrMulticastDNSWithNAT1To1IPMapping - } - candiHostEnabled := false - for _, candiType := range agent.candidateTypes { - if candiType == CandidateTypeHost { - candiHostEnabled = true - - break - } - } - if !candiHostEnabled { - return ErrIneffectiveNAT1To1IPMappingHost - } - } else if agent.extIPMapper.candidateType == CandidateTypeServerReflexive { - candiSrflxEnabled := false - for _, candiType := range agent.candidateTypes { - if candiType == CandidateTypeServerReflexive { - candiSrflxEnabled = true - - break - } - } - if !candiSrflxEnabled { - return ErrIneffectiveNAT1To1IPMappingSrflx - } - } - - return nil -} diff --git a/vendor/github.com/pion/ice/v4/agent_options.go b/vendor/github.com/pion/ice/v4/agent_options.go new file mode 100644 index 0000000000..c9ab3b32dd --- /dev/null +++ b/vendor/github.com/pion/ice/v4/agent_options.go @@ -0,0 +1,525 @@ +// SPDX-FileCopyrightText: 2025 The Pion community +// SPDX-License-Identifier: MIT + +package ice + +import ( + "net" + "strings" + "sync/atomic" + "time" + + "github.com/pion/logging" + "github.com/pion/stun/v3" + "github.com/pion/transport/v3" + "golang.org/x/net/proxy" +) + +// AgentOption represents a function that can be used to configure an Agent. +type AgentOption func(*Agent) error + +// NominationValueGenerator is a function that generates nomination values for renomination. +type NominationValueGenerator func() uint32 + +// DefaultNominationValueGenerator returns a generator that starts at 1 and increments for each call. +// This provides a simple, monotonically increasing sequence suitable for renomination. +func DefaultNominationValueGenerator() NominationValueGenerator { + var counter atomic.Uint32 + + return func() uint32 { + return counter.Add(1) + } +} + +// WithICELite configures whether the agent operates in lite mode. +// Lite agents do not perform connectivity checks and only provide host candidates. +func WithICELite(lite bool) AgentOption { + return func(a *Agent) error { + a.lite = lite + + return nil + } +} + +// WithUrls sets the STUN/TURN server URLs used by the agent. +func WithUrls(urls []*stun.URI) AgentOption { + return func(a *Agent) error { + if len(urls) == 0 { + a.urls = nil + + return nil + } + + cloned := make([]*stun.URI, len(urls)) + copy(cloned, urls) + a.urls = cloned + + return nil + } +} + +// WithPortRange sets the UDP port range for host candidates. +func WithPortRange(portMin, portMax uint16) AgentOption { + return func(a *Agent) error { + if portMax < portMin { + return ErrPort + } + + a.portMin = portMin + a.portMax = portMax + + return nil + } +} + +// WithDisconnectedTimeout sets the duration before the agent transitions to disconnected state. +// A timeout of 0 disables the transition. +func WithDisconnectedTimeout(timeout time.Duration) AgentOption { + return func(a *Agent) error { + a.disconnectedTimeout = timeout + + return nil + } +} + +// WithFailedTimeout sets the duration before the agent transitions to failed state after disconnected. +// A timeout of 0 disables the transition. +func WithFailedTimeout(timeout time.Duration) AgentOption { + return func(a *Agent) error { + a.failedTimeout = timeout + + return nil + } +} + +// WithKeepaliveInterval sets how often ICE keepalive packets are sent. +// An interval of 0 disables keepalives. +func WithKeepaliveInterval(interval time.Duration) AgentOption { + return func(a *Agent) error { + a.keepaliveInterval = interval + + return nil + } +} + +// WithHostAcceptanceMinWait sets the minimum wait before selecting host candidates. +func WithHostAcceptanceMinWait(wait time.Duration) AgentOption { + return func(a *Agent) error { + a.hostAcceptanceMinWait = wait + + return nil + } +} + +// WithSrflxAcceptanceMinWait sets the minimum wait before selecting srflx candidates. +func WithSrflxAcceptanceMinWait(wait time.Duration) AgentOption { + return func(a *Agent) error { + a.srflxAcceptanceMinWait = wait + + return nil + } +} + +// WithPrflxAcceptanceMinWait sets the minimum wait before selecting prflx candidates. +func WithPrflxAcceptanceMinWait(wait time.Duration) AgentOption { + return func(a *Agent) error { + a.prflxAcceptanceMinWait = wait + + return nil + } +} + +// WithRelayAcceptanceMinWait sets the minimum wait before selecting relay candidates. +func WithRelayAcceptanceMinWait(wait time.Duration) AgentOption { + return func(a *Agent) error { + a.relayAcceptanceMinWait = wait + + return nil + } +} + +// WithSTUNGatherTimeout sets the STUN gather timeout. +func WithSTUNGatherTimeout(timeout time.Duration) AgentOption { + return func(a *Agent) error { + a.stunGatherTimeout = timeout + + return nil + } +} + +// WithIPFilter sets a filter for IP addresses used during candidate gathering. +func WithIPFilter(filter func(net.IP) bool) AgentOption { + return func(a *Agent) error { + a.ipFilter = filter + + return nil + } +} + +// WithNet sets the underlying network implementation for the agent. +func WithNet(net transport.Net) AgentOption { + return func(a *Agent) error { + a.net = net + + return nil + } +} + +// WithMulticastDNSMode configures mDNS behavior for the agent. +func WithMulticastDNSMode(mode MulticastDNSMode) AgentOption { + return func(a *Agent) error { + a.mDNSMode = mode + + return nil + } +} + +// WithMulticastDNSHostName sets the mDNS host name used by the agent. +func WithMulticastDNSHostName(hostName string) AgentOption { + return func(a *Agent) error { + if !strings.HasSuffix(hostName, ".local") || len(strings.Split(hostName, ".")) != 2 { + return ErrInvalidMulticastDNSHostName + } + + a.mDNSName = hostName + + return nil + } +} + +// WithLocalCredentials sets the local ICE username fragment and password used during Restart. +// If empty strings are provided, the agent will generate values during Restart. +func WithLocalCredentials(ufrag, pwd string) AgentOption { + return func(a *Agent) error { + if ufrag != "" && len([]rune(ufrag))*8 < 24 { + return ErrLocalUfragInsufficientBits + } + if pwd != "" && len([]rune(pwd))*8 < 128 { + return ErrLocalPwdInsufficientBits + } + + a.localUfrag = ufrag + a.localPwd = pwd + + return nil + } +} + +// WithTCPMux sets the TCP mux for ICE TCP multiplexing. +func WithTCPMux(tcpMux TCPMux) AgentOption { + return func(a *Agent) error { + a.tcpMux = tcpMux + + return nil + } +} + +// WithUDPMux sets the UDP mux used for multiplexing host candidates. +func WithUDPMux(udpMux UDPMux) AgentOption { + return func(a *Agent) error { + a.udpMux = udpMux + + return nil + } +} + +// WithUDPMuxSrflx sets the UDP mux for server reflexive candidates. +func WithUDPMuxSrflx(udpMuxSrflx UniversalUDPMux) AgentOption { + return func(a *Agent) error { + a.udpMuxSrflx = udpMuxSrflx + + return nil + } +} + +// WithProxyDialer sets the proxy dialer used for TURN over TCP/TLS/DTLS connections. +func WithProxyDialer(dialer proxy.Dialer) AgentOption { + return func(a *Agent) error { + a.proxyDialer = dialer + + return nil + } +} + +// WithMaxBindingRequests sets the maximum number of binding requests before considering a pair failed. +func WithMaxBindingRequests(limit uint16) AgentOption { + return func(a *Agent) error { + a.maxBindingRequests = limit + + return nil + } +} + +// WithCheckInterval sets how often the agent runs connectivity checks while connecting. +func WithCheckInterval(interval time.Duration) AgentOption { + return func(a *Agent) error { + a.checkInterval = interval + + return nil + } +} + +// WithRenomination enables ICE renomination as described in draft-thatcher-ice-renomination-01. +// When enabled, the controlling agent can renominate candidate pairs multiple times +// and the controlled agent follows "last nomination wins" rule. +// +// The generator parameter specifies how nomination values are generated. +// Use DefaultNominationValueGenerator() for a simple incrementing counter, +// or provide a custom generator for more complex scenarios. +// +// Example: +// +// agent, err := NewAgentWithOptions(config, WithRenomination(DefaultNominationValueGenerator())) +func WithRenomination(generator NominationValueGenerator) AgentOption { + return func(a *Agent) error { + if generator == nil { + return ErrInvalidNominationValueGenerator + } + a.enableRenomination = true + a.nominationValueGenerator = generator + + return nil + } +} + +// WithNominationAttribute sets the STUN attribute type to use for ICE renomination. +// The default value is 0x0030. This can be configured until the attribute is officially +// assigned by IANA for draft-thatcher-ice-renomination. +// +// This option returns an error if the provided attribute type is invalid. +// Currently, validation ensures the attribute is not 0x0000 (reserved). +// Additional validation may be added in the future. +func WithNominationAttribute(attrType uint16) AgentOption { + return func(a *Agent) error { + // Basic validation: ensure it's not the reserved 0x0000 + if attrType == 0x0000 { + return ErrInvalidNominationAttribute + } + + a.nominationAttribute = stun.AttrType(attrType) + + return nil + } +} + +// WithIncludeLoopback includes loopback addresses in the candidate list. +// By default, loopback addresses are excluded. +// +// Example: +// +// agent, err := NewAgentWithOptions(WithIncludeLoopback()) +func WithIncludeLoopback() AgentOption { + return func(a *Agent) error { + a.includeLoopback = true + + return nil + } +} + +// WithTCPPriorityOffset sets a number which is subtracted from the default (UDP) candidate type preference +// for host, srflx and prfx candidate types. It helps to configure relative preference of UDP candidates +// against TCP ones. Relay candidates for TCP and UDP are always 0 and not affected by this setting. +// When not set, defaultTCPPriorityOffset (27) is used. +// +// Example: +// +// agent, err := NewAgentWithOptions(WithTCPPriorityOffset(50)) +func WithTCPPriorityOffset(offset uint16) AgentOption { + return func(a *Agent) error { + a.tcpPriorityOffset = offset + + return nil + } +} + +// WithDisableActiveTCP disables Active TCP candidates. +// When TCP is enabled, Active TCP candidates will be created when a new passive TCP remote candidate is added +// unless this option is used. +// +// Example: +// +// agent, err := NewAgentWithOptions(WithDisableActiveTCP()) +func WithDisableActiveTCP() AgentOption { + return func(a *Agent) error { + a.disableActiveTCP = true + + return nil + } +} + +// WithBindingRequestHandler sets a handler to allow applications to perform logic on incoming STUN Binding Requests. +// This was implemented to allow users to: +// - Log incoming Binding Requests for debugging +// - Implement draft-thatcher-ice-renomination +// - Implement custom CandidatePair switching logic +// +// Example: +// +// handler := func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool { +// log.Printf("Binding request from %s to %s", remote.Address(), local.Address()) +// return true // Accept the request +// } +// agent, err := NewAgentWithOptions(WithBindingRequestHandler(handler)) +func WithBindingRequestHandler( + handler func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool, +) AgentOption { + return func(a *Agent) error { + a.userBindingRequestHandler = handler + + return nil + } +} + +// WithEnableUseCandidateCheckPriority enables checking for equal or higher priority when +// switching selected candidate pair if the peer requests USE-CANDIDATE and agent is a lite agent. +// This is disabled by default, i.e. when peer requests USE-CANDIDATE, the selected pair will be +// switched to that irrespective of relative priority between current selected pair +// and priority of the pair being switched to. +// +// Example: +// +// agent, err := NewAgentWithOptions(WithEnableUseCandidateCheckPriority()) +func WithEnableUseCandidateCheckPriority() AgentOption { + return func(a *Agent) error { + a.enableUseCandidateCheckPriority = true + + return nil + } +} + +// WithContinualGatheringPolicy sets the continual gathering policy for the agent. +// When set to GatherContinually, the agent will continuously monitor network interfaces +// and gather new candidates as they become available. +// When set to GatherOnce (default), gathering completes after the initial phase. +// +// Example: +// +// agent, err := NewAgentWithOptions(WithContinualGatheringPolicy(GatherContinually)) +func WithContinualGatheringPolicy(policy ContinualGatheringPolicy) AgentOption { + return func(a *Agent) error { + a.continualGatheringPolicy = policy + + return nil + } +} + +// WithNetworkMonitorInterval sets the interval at which the agent checks for network interface changes +// when using GatherContinually policy. This option only has effect when used with +// WithContinualGatheringPolicy(GatherContinually). +// Default is 2 seconds if not specified. +// +// Example: +// +// agent, err := NewAgentWithOptions( +// WithContinualGatheringPolicy(GatherContinually), +// WithNetworkMonitorInterval(5 * time.Second), +// ) +func WithNetworkMonitorInterval(interval time.Duration) AgentOption { + return func(a *Agent) error { + if interval <= 0 { + return ErrInvalidNetworkMonitorInterval + } + a.networkMonitorInterval = interval + + return nil + } +} + +// WithNetworkTypes sets the enabled network types for candidate gathering. +// By default, all network types are enabled. +// +// Example: +// +// agent, err := NewAgentWithOptions( +// WithNetworkTypes([]NetworkType{NetworkTypeUDP4, NetworkTypeUDP6}), +// ) +func WithNetworkTypes(networkTypes []NetworkType) AgentOption { + return func(a *Agent) error { + a.networkTypes = networkTypes + + return nil + } +} + +// WithCandidateTypes sets the enabled candidate types for gathering. +// By default, host, server reflexive, and relay candidates are enabled. +// +// Example: +// +// agent, err := NewAgentWithOptions( +// WithCandidateTypes([]CandidateType{CandidateTypeHost, CandidateTypeServerReflexive}), +// ) +func WithCandidateTypes(candidateTypes []CandidateType) AgentOption { + return func(a *Agent) error { + a.candidateTypes = candidateTypes + + return nil + } +} + +// WithAutomaticRenomination enables automatic renomination of candidate pairs +// when better pairs become available after initial connection establishment. +// This feature requires renomination to be enabled and both agents to support it. +// +// When enabled, the controlling agent will periodically evaluate candidate pairs +// and renominate if a significantly better pair is found (e.g., switching from +// relay to direct connection, or when RTT improves significantly). +// +// The interval parameter specifies the minimum time to wait after connection +// before considering automatic renomination. If set to 0, it defaults to 3 seconds. +// +// Example: +// +// agent, err := NewAgentWithOptions( +// WithRenomination(DefaultNominationValueGenerator()), +// WithAutomaticRenomination(3*time.Second), +// ) +func WithAutomaticRenomination(interval time.Duration) AgentOption { + return func(a *Agent) error { + a.automaticRenomination = true + if interval > 0 { + a.renominationInterval = interval + } + // Note: renomination must be enabled separately via WithRenomination + return nil + } +} + +// WithInterfaceFilter sets a filter function to whitelist or blacklist network interfaces +// for ICE candidate gathering. +// +// The filter function receives the interface name and should return true to keep the interface, +// or false to exclude it. +// +// Example: +// +// // Only use interfaces starting with "eth" +// agent, err := NewAgentWithOptions( +// WithInterfaceFilter(func(interfaceName string) bool { +// return len(interfaceName) >= 3 && interfaceName[:3] == "eth" +// }), +// ) +func WithInterfaceFilter(filter func(string) bool) AgentOption { + return func(a *Agent) error { + a.interfaceFilter = filter + + return nil + } +} + +// WithLoggerFactory sets the logger factory for the agent. +// +// Example: +// +// import "github.com/pion/logging" +// +// loggerFactory := logging.NewDefaultLoggerFactory() +// loggerFactory.DefaultLogLevel = logging.LogLevelDebug +// agent, err := NewAgentWithOptions(WithLoggerFactory(loggerFactory)) +func WithLoggerFactory(loggerFactory logging.LoggerFactory) AgentOption { + return func(a *Agent) error { + a.log = loggerFactory.NewLogger("ice") + + return nil + } +} diff --git a/vendor/github.com/pion/ice/v4/agent_stats.go b/vendor/github.com/pion/ice/v4/agent_stats.go index c6b21f57e5..f795e85044 100644 --- a/vendor/github.com/pion/ice/v4/agent_stats.go +++ b/vendor/github.com/pion/ice/v4/agent_stats.go @@ -15,20 +15,20 @@ func (a *Agent) GetCandidatePairsStats() []CandidatePairStats { result := make([]CandidatePairStats, 0, len(a.checklist)) for _, cp := range a.checklist { stat := CandidatePairStats{ - Timestamp: time.Now(), - LocalCandidateID: cp.Local.ID(), - RemoteCandidateID: cp.Remote.ID(), - State: cp.state, - Nominated: cp.nominated, - // PacketsSent uint32 - // PacketsReceived uint32 - // BytesSent uint64 - // BytesReceived uint64 - // LastPacketSentTimestamp time.Time - // LastPacketReceivedTimestamp time.Time + Timestamp: time.Now(), + LocalCandidateID: cp.Local.ID(), + RemoteCandidateID: cp.Remote.ID(), + State: cp.state, + Nominated: cp.nominated, + PacketsSent: cp.PacketsSent(), + PacketsReceived: cp.PacketsReceived(), + BytesSent: cp.BytesSent(), + BytesReceived: cp.BytesReceived(), + LastPacketSentTimestamp: cp.LastPacketSentAt(), + LastPacketReceivedTimestamp: cp.LastPacketReceivedAt(), FirstRequestTimestamp: cp.FirstRequestSentAt(), LastRequestTimestamp: cp.LastRequestSentAt(), - FirstResponseTimestamp: cp.FirstReponseReceivedAt(), + FirstResponseTimestamp: cp.FirstResponseReceivedAt(), LastResponseTimestamp: cp.LastResponseReceivedAt(), FirstRequestReceivedTimestamp: cp.FirstRequestReceivedAt(), LastRequestReceivedTimestamp: cp.LastRequestReceivedAt(), @@ -73,17 +73,17 @@ func (a *Agent) GetSelectedCandidatePairStats() (CandidatePairStats, bool) { isAvailable = true res = CandidatePairStats{ - Timestamp: time.Now(), - LocalCandidateID: sp.Local.ID(), - RemoteCandidateID: sp.Remote.ID(), - State: sp.state, - Nominated: sp.nominated, - // PacketsSent uint32 - // PacketsReceived uint32 - // BytesSent uint64 - // BytesReceived uint64 - // LastPacketSentTimestamp time.Time - // LastPacketReceivedTimestamp time.Time + Timestamp: time.Now(), + LocalCandidateID: sp.Local.ID(), + RemoteCandidateID: sp.Remote.ID(), + State: sp.state, + Nominated: sp.nominated, + PacketsSent: sp.PacketsSent(), + PacketsReceived: sp.PacketsReceived(), + BytesSent: sp.BytesSent(), + BytesReceived: sp.BytesReceived(), + LastPacketSentTimestamp: sp.LastPacketSentAt(), + LastPacketReceivedTimestamp: sp.LastPacketReceivedAt(), // FirstRequestTimestamp time.Time // LastRequestTimestamp time.Time // LastResponseTimestamp time.Time diff --git a/vendor/github.com/pion/ice/v4/candidate_base.go b/vendor/github.com/pion/ice/v4/candidate_base.go index 66fb776ee1..0e38d4cc93 100644 --- a/vendor/github.com/pion/ice/v4/candidate_base.go +++ b/vendor/github.com/pion/ice/v4/candidate_base.go @@ -69,7 +69,7 @@ func (c *candidateBase) Deadline() (deadline time.Time, ok bool) { } // Value implements context.Context. -func (c *candidateBase) Value(interface{}) interface{} { +func (c *candidateBase) Value(any) any { return nil } @@ -217,7 +217,7 @@ func (c *candidateBase) start(a *Agent, conn net.PacketConn, initializedCh <-cha } var bufferPool = sync.Pool{ // nolint:gochecknoglobals - New: func() interface{} { + New: func() any { return make([]byte, receiveMTU) }, } @@ -243,7 +243,7 @@ func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) { for { n, srcAddr, err := c.conn.ReadFrom(buf) if err != nil { - if !(errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed)) { + if !errors.Is(err, io.EOF) && !errors.Is(err, net.ErrClosed) { agent.log.Warnf("Failed to read from candidate %s: %v", c, err) } @@ -309,11 +309,19 @@ func (c *candidateBase) handleInboundPacket(buf []byte, srcAddr net.Addr) { } // Note: This will return packetio.ErrFull if the buffer ever manages to fill up. - if _, err := agent.buf.Write(buf); err != nil { + n, err := agent.buf.Write(buf) + if err != nil { agent.log.Warnf("Failed to write packet: %s", err) return } + + // Add received application bytes to the currently selected candidate pair. + if n > 0 { + if sp := agent.getSelectedPair(); sp != nil { + sp.UpdatePacketReceived(n) + } + } } // close stops the recvLoop. @@ -891,10 +899,10 @@ func readCandidateCharToken(raw string, start int, limit int) (string, int, erro return "", 0, fmt.Errorf("token too long: %s expected 1x%d", raw[start:start+i], limit) } - if !(char >= 'A' && char <= 'Z' || - char >= 'a' && char <= 'z' || - char >= '0' && char <= '9' || - char == '+' || char == '/') { + if (char < 'A' || char > 'Z') && + (char < 'a' || char > 'z') && + (char < '0' || char > '9') && + char != '+' && char != '/' { return "", 0, fmt.Errorf("invalid ice-char token: %c", char) //nolint: err113 // handled by caller } } @@ -928,7 +936,7 @@ func readCandidateDigitToken(raw string, start, limit int) (int, int, error) { return 0, 0, fmt.Errorf("token too long: %s expected 1x%d", raw[start:start+i], limit) } - if !(char >= '0' && char <= '9') { + if char < '0' || char > '9' { return 0, 0, fmt.Errorf("invalid digit token: %c", char) //nolint: err113 // handled by caller } @@ -962,9 +970,9 @@ func readCandidateByteString(raw string, start int) (string, int, error) { } // 1*(%x01-09/%x0B-0C/%x0E-FF) - if !(char >= 0x01 && char <= 0x09 || - char >= 0x0B && char <= 0x0C || - char >= 0x0E && char <= 0xFF) { + if (char < 0x01 || char > 0x09) && + (char < 0x0B || char > 0x0C) && + (char < 0x0E || char > 0xFF) { return "", 0, fmt.Errorf("invalid byte-string character: %c", char) //nolint: err113 // handled by caller } } diff --git a/vendor/github.com/pion/ice/v4/candidatepair.go b/vendor/github.com/pion/ice/v4/candidatepair.go index 82655aa5f0..31b8bf1934 100644 --- a/vendor/github.com/pion/ice/v4/candidatepair.go +++ b/vendor/github.com/pion/ice/v4/candidatepair.go @@ -34,17 +34,24 @@ type CandidatePair struct { currentRoundTripTime int64 // in ns totalRoundTripTime int64 // in ns + packetsSent uint32 + packetsReceived uint32 + bytesSent uint64 + bytesReceived uint64 + lastPacketSentAt atomic.Value // time.Time + lastPacketReceivedAt atomic.Value // time.Time + requestsReceived uint64 requestsSent uint64 responsesReceived uint64 responsesSent uint64 - firstRequestSentAt atomic.Value // time.Time - lastRequestSentAt atomic.Value // time.Time - firstReponseReceivedAt atomic.Value // time.Time - lastResponseReceivedAt atomic.Value // time.Time - firstRequestReceivedAt atomic.Value // time.Time - lastRequestReceivedAt atomic.Value // time.Time + firstRequestSentAt atomic.Value // time.Time + lastRequestSentAt atomic.Value // time.Time + firstResponseReceivedAt atomic.Value // time.Time + lastResponseReceivedAt atomic.Value // time.Time + firstRequestReceivedAt atomic.Value // time.Time + lastRequestReceivedAt atomic.Value // time.Time } func (p *CandidatePair) String() string { @@ -140,7 +147,7 @@ func (p *CandidatePair) UpdateRoundTripTime(rtt time.Duration) { atomic.AddUint64(&p.responsesReceived, 1) now := time.Now() - p.firstReponseReceivedAt.CompareAndSwap(nil, now) + p.firstResponseReceivedAt.CompareAndSwap(nil, now) p.lastResponseReceivedAt.Store(now) } @@ -180,6 +187,66 @@ func (p *CandidatePair) ResponsesSent() uint64 { return atomic.LoadUint64(&p.responsesSent) } +// PacketsSent returns total application (non-STUN) packets sent on this pair. +func (p *CandidatePair) PacketsSent() uint32 { + return atomic.LoadUint32(&p.packetsSent) +} + +// PacketsReceived returns total application (non-STUN) packets received on this pair. +func (p *CandidatePair) PacketsReceived() uint32 { + return atomic.LoadUint32(&p.packetsReceived) +} + +// BytesSent returns total application bytes sent on this pair. +func (p *CandidatePair) BytesSent() uint64 { + return atomic.LoadUint64(&p.bytesSent) +} + +// BytesReceived returns total application bytes received on this pair. +func (p *CandidatePair) BytesReceived() uint64 { + return atomic.LoadUint64(&p.bytesReceived) +} + +// LastPacketSentAt returns the timestamp of the last application packet sent. +func (p *CandidatePair) LastPacketSentAt() time.Time { + if v, ok := p.lastPacketSentAt.Load().(time.Time); ok { + return v + } + + return time.Time{} +} + +// LastPacketReceivedAt returns the timestamp of the last application packet received. +func (p *CandidatePair) LastPacketReceivedAt() time.Time { + if v, ok := p.lastPacketReceivedAt.Load().(time.Time); ok { + return v + } + + return time.Time{} +} + +// UpdatePacketSent increments packet/byte counters and updates timestamp for a sent application packet. +func (p *CandidatePair) UpdatePacketSent(n int) { + if n <= 0 { + return + } + + atomic.AddUint32(&p.packetsSent, 1) + atomic.AddUint64(&p.bytesSent, uint64(n)) // #nosec G115 -- n > 0 validated above + p.lastPacketSentAt.Store(time.Now()) +} + +// UpdatePacketReceived increments packet/byte counters and updates timestamp for a received application packet. +func (p *CandidatePair) UpdatePacketReceived(n int) { + if n <= 0 { + return + } + + atomic.AddUint32(&p.packetsReceived, 1) + atomic.AddUint64(&p.bytesReceived, uint64(n)) // #nosec G115 -- n > 0 validated above + p.lastPacketReceivedAt.Store(time.Now()) +} + // FirstRequestSentAt returns the timestamp of the first connectivity check sent. func (p *CandidatePair) FirstRequestSentAt() time.Time { if v, ok := p.firstRequestSentAt.Load().(time.Time); ok { @@ -198,9 +265,15 @@ func (p *CandidatePair) LastRequestSentAt() time.Time { return time.Time{} } +// Deprecated: use FirstResponseReceivedAt // FirstReponseReceivedAt returns the timestamp of the first connectivity response received. func (p *CandidatePair) FirstReponseReceivedAt() time.Time { - if v, ok := p.firstReponseReceivedAt.Load().(time.Time); ok { + return p.FirstResponseReceivedAt() +} + +// FirstResponseReceivedAt returns the timestamp of the first connectivity response received. +func (p *CandidatePair) FirstResponseReceivedAt() time.Time { + if v, ok := p.firstResponseReceivedAt.Load().(time.Time); ok { return v } diff --git a/vendor/github.com/pion/ice/v4/candidatetype.go b/vendor/github.com/pion/ice/v4/candidatetype.go index fef798b6ba..9ba7632aad 100644 --- a/vendor/github.com/pion/ice/v4/candidatetype.go +++ b/vendor/github.com/pion/ice/v4/candidatetype.go @@ -3,6 +3,8 @@ package ice +import "slices" + // CandidateType represents the type of candidate. type CandidateType byte @@ -58,11 +60,6 @@ func containsCandidateType(candidateType CandidateType, candidateTypeList []Cand if candidateTypeList == nil { return false } - for _, ct := range candidateTypeList { - if ct == candidateType { - return true - } - } - return false + return slices.Contains(candidateTypeList, candidateType) } diff --git a/vendor/github.com/pion/ice/v4/errors.go b/vendor/github.com/pion/ice/v4/errors.go index 39b22e5bd8..4249678a2e 100644 --- a/vendor/github.com/pion/ice/v4/errors.go +++ b/vendor/github.com/pion/ice/v4/errors.go @@ -120,6 +120,24 @@ var ( // ErrDetermineNetworkType indicates that the NetworkType was not able to be parsed. ErrDetermineNetworkType = errors.New("unable to determine networkType") + // ErrOnlyControllingAgentCanRenominate indicates that only controlling agent can renominate. + ErrOnlyControllingAgentCanRenominate = errors.New("only controlling agent can renominate") + + // ErrRenominationNotEnabled indicates that renomination is not enabled. + ErrRenominationNotEnabled = errors.New("renomination is not enabled") + + // ErrCandidatePairNotFound indicates that candidate pair was not found. + ErrCandidatePairNotFound = errors.New("candidate pair not found") + + // ErrInvalidNominationAttribute indicates an invalid nomination attribute type was provided. + ErrInvalidNominationAttribute = errors.New("invalid nomination attribute type") + + // ErrInvalidNominationValueGenerator indicates a nil nomination value generator was provided. + ErrInvalidNominationValueGenerator = errors.New("nomination value generator cannot be nil") + + // ErrInvalidNetworkMonitorInterval indicates an invalid network monitor interval was provided. + ErrInvalidNetworkMonitorInterval = errors.New("network monitor interval must be greater than 0") + errAttributeTooShortICECandidate = errors.New("attribute not long enough to be ICE candidate") errClosingConnection = errors.New("failed to close connection") errConnectionAddrAlreadyExist = errors.New("connection with same remote address already exists") @@ -136,7 +154,6 @@ var ( errParseRelatedAddr = errors.New("failed to parse related addresses") errParseExtension = errors.New("failed to parse extension") errParseTCPType = errors.New("failed to parse TCP type") - errRead = errors.New("failed to read") errUDPMuxDisabled = errors.New("UDPMux is not enabled") errUnknownRole = errors.New("unknown role") errWrite = errors.New("failed to write") diff --git a/vendor/github.com/pion/ice/v4/gather.go b/vendor/github.com/pion/ice/v4/gather.go index a1e0247160..fad9068483 100644 --- a/vendor/github.com/pion/ice/v4/gather.go +++ b/vendor/github.com/pion/ice/v4/gather.go @@ -12,17 +12,19 @@ import ( "net/netip" "reflect" "sync" + "time" "github.com/pion/dtls/v3" "github.com/pion/ice/v4/internal/fakenet" stunx "github.com/pion/ice/v4/internal/stun" "github.com/pion/logging" "github.com/pion/stun/v3" + "github.com/pion/transport/v3/stdnet" "github.com/pion/turn/v4" ) // Close a net.Conn and log if we have a failure. -func closeConnAndLog(c io.Closer, log logging.LeveledLogger, msg string, args ...interface{}) { +func closeConnAndLog(c io.Closer, log logging.LeveledLogger, msg string, args ...any) { if c == nil || (reflect.ValueOf(c).Kind() == reflect.Ptr && reflect.ValueOf(c).IsNil()) { log.Warnf("Connection is not allocated: "+msg, args...) @@ -72,6 +74,36 @@ func (a *Agent) gatherCandidates(ctx context.Context, done chan struct{}) { //no return } + a.gatherCandidatesInternal(ctx) + + switch a.continualGatheringPolicy { + case GatherOnce: + if err := a.setGatheringState(GatheringStateComplete); err != nil { //nolint:contextcheck + a.log.Warnf("Failed to set gatheringState to GatheringStateComplete: %v", err) + } + case GatherContinually: + // Initialize known interfaces before starting monitoring + _, addrs, err := localInterfaces( + a.net, + a.interfaceFilter, + a.ipFilter, + a.networkTypes, + a.includeLoopback, + ) + if err != nil { + a.log.Warnf("Failed to get initial interfaces for monitoring: %v", err) + } else { + for _, addr := range addrs { + a.lastKnownInterfaces[addr.String()] = addr + } + a.log.Infof("Initialized network monitoring with %d IP addresses", len(addrs)) + } + go a.startNetworkMonitoring(ctx) + } +} + +// gatherCandidatesInternal performs the actual candidate gathering for all configured types. +func (a *Agent) gatherCandidatesInternal(ctx context.Context) { var wg sync.WaitGroup for _, t := range a.candidateTypes { switch t { @@ -110,10 +142,6 @@ func (a *Agent) gatherCandidates(ctx context.Context, done chan struct{}) { //no // Block until all STUN and TURN URLs have been gathered (or timed out) wg.Wait() - - if err := a.setGatheringState(GatheringStateComplete); err != nil { //nolint:contextcheck - a.log.Warnf("Failed to set gatheringState to GatheringStateComplete: %v", err) - } } //nolint:gocognit,gocyclo,cyclop @@ -892,3 +920,63 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*stun.URI) { }(*urls[i]) } } + +// startNetworkMonitoring starts a goroutine that periodically checks for network changes +// and re-gathers candidates when changes are detected. This is only used with GatherContinually policy. +func (a *Agent) startNetworkMonitoring(ctx context.Context) { + ticker := time.NewTicker(a.networkMonitorInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + if a.detectNetworkChanges() { + a.gatherCandidatesInternal(ctx) + } + } + } +} + +// detectNetworkChanges checks if the network interfaces have changed since the last check. +func (a *Agent) detectNetworkChanges() bool { + // Try to refresh interfaces if using stdnet + if stdNet, ok := a.net.(*stdnet.Net); ok { + if err := stdNet.UpdateInterfaces(); err != nil { + a.log.Warnf("Failed to update interfaces: %v", err) + } + } + + _, currentAddrs, err := localInterfaces( + a.net, + a.interfaceFilter, + a.ipFilter, + a.networkTypes, + a.includeLoopback, + ) + if err != nil { + a.log.Warnf("Failed to get local interfaces during network monitoring: %v", err) + + return false + } + + currentInterfaces := make(map[string]netip.Addr) + for _, addr := range currentAddrs { + key := addr.String() + currentInterfaces[key] = addr + } + + hasAdditions := false + + for key, addr := range currentInterfaces { + if _, exists := a.lastKnownInterfaces[key]; !exists { + a.log.Infof("New IP address detected: %s", addr) + hasAdditions = true + } + } + + a.lastKnownInterfaces = currentInterfaces + + return hasAdditions +} diff --git a/vendor/github.com/pion/ice/v4/ice.go b/vendor/github.com/pion/ice/v4/ice.go index bd53702f5d..5de7b5cb1a 100644 --- a/vendor/github.com/pion/ice/v4/ice.go +++ b/vendor/github.com/pion/ice/v4/ice.go @@ -84,7 +84,27 @@ func (t GatheringState) String() string { } } +// ContinualGatheringPolicy defines the behavior for gathering ICE candidates. +type ContinualGatheringPolicy int + +const ( + GatherOnce ContinualGatheringPolicy = iota + GatherContinually +) + +func (c ContinualGatheringPolicy) String() string { + switch c { + case GatherOnce: + return "gather_once" + case GatherContinually: + return "gather_continually" + default: + return unknownStr + } +} + const ( + unknownStr = "unknown" relayProtocolDTLS = "dtls" relayProtocolTLS = "tls" ) diff --git a/vendor/github.com/pion/ice/v4/internal/taskloop/taskloop.go b/vendor/github.com/pion/ice/v4/internal/taskloop/taskloop.go index 15a2666545..4c8e43e504 100644 --- a/vendor/github.com/pion/ice/v4/internal/taskloop/taskloop.go +++ b/vendor/github.com/pion/ice/v4/internal/taskloop/taskloop.go @@ -85,6 +85,8 @@ func (l *Loop) Run(ctx context.Context, t func(context.Context)) error { select { case <-ctx.Done(): return ctx.Err() + case <-l.done: + return ErrClosed case l.tasks <- task{t, done}: <-done @@ -116,6 +118,6 @@ func (l *Loop) Deadline() (deadline time.Time, ok bool) { } // Value is not supported for task loops. -func (l *Loop) Value(interface{}) interface{} { +func (l *Loop) Value(any) any { return nil } diff --git a/vendor/github.com/pion/ice/v4/renomination.go b/vendor/github.com/pion/ice/v4/renomination.go new file mode 100644 index 0000000000..c1465ef0a0 --- /dev/null +++ b/vendor/github.com/pion/ice/v4/renomination.go @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2025 The Pion community +// SPDX-License-Identifier: MIT + +package ice + +import ( + "fmt" + + "github.com/pion/stun/v3" +) + +// Default STUN Nomination attribute type for ICE renomination. +// Following the specification draft-thatcher-ice-renomination-01. +const ( + // DefaultNominationAttribute represents the default STUN Nomination attribute. + // This is a custom attribute for ICE renomination support. + // This value can be overridden via AgentConfig.NominationAttribute. + DefaultNominationAttribute stun.AttrType = 0x0030 // Using a value in the reserved range +) + +// NominationAttribute represents a STUN Nomination attribute. +type NominationAttribute struct { + Value uint32 +} + +// GetFrom decodes a Nomination attribute from a STUN message. +func (a *NominationAttribute) GetFrom(m *stun.Message) error { + return a.GetFromWithType(m, DefaultNominationAttribute) +} + +// GetFromWithType decodes a Nomination attribute from a STUN message using a specific attribute type. +func (a *NominationAttribute) GetFromWithType(m *stun.Message, attrType stun.AttrType) error { + v, err := m.Get(attrType) + if err != nil { + return err + } + if len(v) < 4 { + return stun.ErrAttributeSizeInvalid + } + + // Extract 24-bit value from the last 3 bytes + a.Value = uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3]) + + return nil +} + +// AddTo adds a Nomination attribute to a STUN message. +func (a NominationAttribute) AddTo(m *stun.Message) error { + return a.AddToWithType(m, DefaultNominationAttribute) +} + +// AddToWithType adds a Nomination attribute to a STUN message using a specific attribute type. +func (a NominationAttribute) AddToWithType(m *stun.Message, attrType stun.AttrType) error { + // Store as 4 bytes with first byte as 0 + v := make([]byte, 4) + v[1] = byte(a.Value >> 16) + v[2] = byte(a.Value >> 8) + v[3] = byte(a.Value) + + m.Add(attrType, v) + + return nil +} + +// String returns string representation of the nomination attribute. +func (a NominationAttribute) String() string { + return fmt.Sprintf("NOMINATION: %d", a.Value) +} + +// Nomination creates a new STUN nomination attribute. +func Nomination(value uint32) NominationAttribute { + return NominationAttribute{Value: value} +} + +// NominationSetter is a STUN setter for nomination attribute with configurable type. +type NominationSetter struct { + Value uint32 + AttrType stun.AttrType +} + +// AddTo adds a Nomination attribute to a STUN message using the configured attribute type. +func (n NominationSetter) AddTo(m *stun.Message) error { + attr := NominationAttribute{Value: n.Value} + + return attr.AddToWithType(m, n.AttrType) +} diff --git a/vendor/github.com/pion/ice/v4/selection.go b/vendor/github.com/pion/ice/v4/selection.go index b67898dd79..533d566641 100644 --- a/vendor/github.com/pion/ice/v4/selection.go +++ b/vendor/github.com/pion/ice/v4/selection.go @@ -54,6 +54,14 @@ func (s *controllingSelector) ContactCandidates() { if s.agent.validateSelectedPair() { s.log.Trace("Checking keepalive") s.agent.checkKeepalive() + + // If automatic renomination is enabled, continuously ping all candidate pairs + // to keep them tested with fresh RTT measurements for switching decisions + if s.agent.automaticRenomination && s.agent.enableRenomination { + s.agent.keepAliveCandidatesForRenomination() + } + + s.checkForAutomaticRenomination() } case s.nominatedPair != nil: s.nominatePair(s.nominatedPair) @@ -132,7 +140,7 @@ func (s *controllingSelector) HandleBindingRequest(message *stun.Message, local, func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remote Candidate, remoteAddr net.Addr) { ok, pendingRequest, rtt := s.agent.handleInboundBindingSuccess(m.TransactionID) if !ok { - s.log.Warnf("Discard message from (%s), unknown TransactionID 0x%x", remote, m.TransactionID) + s.log.Warnf("Discard success response from (%s), unknown TransactionID 0x%x", remote, m.TransactionID) return } @@ -163,8 +171,20 @@ func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remo pair.state = CandidatePairStateSucceeded s.log.Tracef("Found valid candidate pair: %s", pair) - if pendingRequest.isUseCandidate && s.agent.getSelectedPair() == nil { - s.agent.setSelectedPair(pair) + + // Handle nomination/renomination + if pendingRequest.isUseCandidate { + selectedPair := s.agent.getSelectedPair() + + // If this is a renomination request (has nomination value), always update the selected pair + // If it's a standard nomination (no value), only set if no pair is selected yet + if pendingRequest.nominationValue != nil { + s.log.Infof("Renomination success response received for pair %s (nomination value: %d), switching to this pair", + pair, *pendingRequest.nominationValue) + s.agent.setSelectedPair(pair) + } else if selectedPair == nil { + s.agent.setSelectedPair(pair) + } } pair.UpdateRoundTripTime(rtt) @@ -187,12 +207,123 @@ func (s *controllingSelector) PingCandidate(local, remote Candidate) { s.agent.sendBindingRequest(msg, local, remote) } +// checkForAutomaticRenomination evaluates if automatic renomination should occur. +// This is called periodically when the agent is in connected state and automatic +// renomination is enabled. +func (s *controllingSelector) checkForAutomaticRenomination() { + if !s.agent.automaticRenomination || !s.agent.enableRenomination { + s.log.Tracef("Automatic renomination check skipped: automaticRenomination=%v, enableRenomination=%v", + s.agent.automaticRenomination, s.agent.enableRenomination) + + return + } + + timeSinceStart := time.Since(s.startTime) + if timeSinceStart < s.agent.renominationInterval { + s.log.Tracef("Automatic renomination check skipped: not enough time since start (%v < %v)", + timeSinceStart, s.agent.renominationInterval) + + return + } + + if !s.agent.lastRenominationTime.IsZero() { + timeSinceLastRenomination := time.Since(s.agent.lastRenominationTime) + if timeSinceLastRenomination < s.agent.renominationInterval { + s.log.Tracef("Automatic renomination check skipped: too soon since last renomination (%v < %v)", + timeSinceLastRenomination, s.agent.renominationInterval) + + return + } + } + + currentPair := s.agent.getSelectedPair() + if currentPair == nil { + s.log.Tracef("Automatic renomination check skipped: no current selected pair") + + return + } + + bestPair := s.agent.findBestCandidatePair() + if bestPair == nil { + s.log.Tracef("Automatic renomination check skipped: no best pair found") + + return + } + + s.log.Debugf("Evaluating automatic renomination: current=%s (RTT=%.2fms), best=%s (RTT=%.2fms)", + currentPair, currentPair.CurrentRoundTripTime()*1000, + bestPair, bestPair.CurrentRoundTripTime()*1000) + + if s.agent.shouldRenominate(currentPair, bestPair) { + s.log.Infof("Automatic renomination triggered: switching from %s to %s", + currentPair, bestPair) + + // Update last renomination time to prevent rapid renominations + s.agent.lastRenominationTime = time.Now() + + if err := s.agent.RenominateCandidate(bestPair.Local, bestPair.Remote); err != nil { + s.log.Errorf("Failed to trigger automatic renomination: %v", err) + } + } else { + s.log.Debugf("Automatic renomination not warranted") + } +} + type controlledSelector struct { - agent *Agent - log logging.LeveledLogger + agent *Agent + log logging.LeveledLogger + lastNomination *uint32 // For renomination: tracks highest nomination value seen } func (s *controlledSelector) Start() { + s.lastNomination = nil +} + +// shouldAcceptNomination checks if a nomination should be accepted based on renomination rules. +func (s *controlledSelector) shouldAcceptNomination(nominationValue *uint32) bool { + // If no nomination value, accept normally (standard ICE nomination) + if nominationValue == nil { + return true + } + + // If nomination value is present, controlling side is using renomination + // Apply "last nomination wins" rule + + if s.lastNomination == nil || *nominationValue > *s.lastNomination { + s.lastNomination = nominationValue + s.log.Tracef("Accepting nomination with value %d", *nominationValue) + + return true + } + + s.log.Tracef("Rejecting nomination value %d (current is %d)", *nominationValue, *s.lastNomination) + + return false +} + +// shouldSwitchSelectedPair determines if we should switch to a new nominated pair. +// Returns true if the switch should occur, false otherwise. +func (s *controlledSelector) shouldSwitchSelectedPair(pair, selectedPair *CandidatePair, nominationValue *uint32) bool { + switch { + case selectedPair == nil: + // No current selection, accept the nomination + return true + case selectedPair == pair: + // Same pair, no change needed + return false + case nominationValue != nil: + // Renomination is in use (nomination value present) + // Accept the switch based on nomination value alone, not priority + // The shouldAcceptNomination check already validated this is a valid renomination + s.log.Debugf("Accepting renomination to pair %s (nomination value: %d)", pair, *nominationValue) + + return true + } + + // Standard ICE nomination without renomination - apply priority rules + // Only switch if we don't check priority, OR new pair has strictly higher priority + return !s.agent.needsToCheckPriorityOnNominated() || + selectedPair.priority() < pair.priority() } func (s *controlledSelector) ContactCandidates() { @@ -288,18 +419,32 @@ func (s *controlledSelector) HandleBindingRequest(message *stun.Message, local, if message.Contains(stun.AttrUseCandidate) { //nolint:nestif // https://tools.ietf.org/html/rfc8445#section-7.3.1.5 + // Check for renomination attribute + var nominationValue *uint32 + var nomination NominationAttribute + if err := nomination.GetFromWithType(message, s.agent.nominationAttribute); err == nil { + nominationValue = &nomination.Value + s.log.Tracef("Received nomination with value %d", nomination.Value) + } + + // Check if we should accept this nomination based on renomination rules + if !s.shouldAcceptNomination(nominationValue) { + s.log.Tracef("Rejecting nomination request due to renomination rules") + s.agent.sendBindingSuccess(message, local, remote) + + return + } + if pair.state == CandidatePairStateSucceeded { // If the state of this pair is Succeeded, it means that the check // previously sent by this pair produced a successful response and // generated a valid pair (Section 7.2.5.3.2). The agent sets the // nominated flag value of the valid pair to true. selectedPair := s.agent.getSelectedPair() - if selectedPair == nil || - (selectedPair != pair && - (!s.agent.needsToCheckPriorityOnNominated() || - selectedPair.priority() <= pair.priority())) { + if s.shouldSwitchSelectedPair(pair, selectedPair, nominationValue) { + s.log.Tracef("Accepting nomination for pair %s", pair) s.agent.setSelectedPair(pair) - } else if selectedPair != pair { + } else { s.log.Tracef("Ignore nominate new pair %s, already nominated pair %s", pair, selectedPair) } } else { diff --git a/vendor/github.com/pion/ice/v4/tcp_packet_conn.go b/vendor/github.com/pion/ice/v4/tcp_packet_conn.go index 1d1dffcb8a..754078342f 100644 --- a/vendor/github.com/pion/ice/v4/tcp_packet_conn.go +++ b/vendor/github.com/pion/ice/v4/tcp_packet_conn.go @@ -190,7 +190,7 @@ func (t *tcpPacketConn) startReading(conn net.Conn) { t.params.Logger.Warnf("Failed to read streaming packet: %s", err) last := t.removeConn(conn) // Only propagate connection closure errors if no other open connection exists. - if last || !(errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed)) { + if last || (!errors.Is(err, io.EOF) && !errors.Is(err, net.ErrClosed)) { t.handleRecv(streamingPacket{nil, conn.RemoteAddr(), err}) } @@ -284,6 +284,11 @@ func (t *tcpPacketConn) removeConn(conn net.Conn) bool { t.closeAndLogError(conn) + // wait for some time to flush pending writes + _ = conn.SetWriteDeadline(time.Now().Add(5 * time.Second)) + // read deadline as well just in case + _ = conn.SetReadDeadline(time.Now().Add(5 * time.Second)) + delete(t.conns, conn.RemoteAddr().String()) return len(t.conns) == 0 @@ -303,6 +308,12 @@ func (t *tcpPacketConn) Close() error { for _, conn := range t.conns { t.closeAndLogError(conn) + + // wait for some time to flush pending writes + _ = conn.SetWriteDeadline(time.Now().Add(5 * time.Second)) + // read deadline as well just in case + _ = conn.SetReadDeadline(time.Now().Add(5 * time.Second)) + delete(t.conns, conn.RemoteAddr().String()) } diff --git a/vendor/github.com/pion/ice/v4/transport.go b/vendor/github.com/pion/ice/v4/transport.go index a28605dfe4..31e1286655 100644 --- a/vendor/github.com/pion/ice/v4/transport.go +++ b/vendor/github.com/pion/ice/v4/transport.go @@ -27,19 +27,19 @@ func (a *Agent) Accept(ctx context.Context, remoteUfrag, remotePwd string) (*Con // Conn represents the ICE connection. // At the moment the lifetime of the Conn is equal to the Agent. type Conn struct { - bytesReceived uint64 - bytesSent uint64 + bytesReceived atomic.Uint64 + bytesSent atomic.Uint64 agent *Agent } // BytesSent returns the number of bytes sent. func (c *Conn) BytesSent() uint64 { - return atomic.LoadUint64(&c.bytesSent) + return c.bytesSent.Load() } // BytesReceived returns the number of bytes received. func (c *Conn) BytesReceived() uint64 { - return atomic.LoadUint64(&c.bytesReceived) + return c.bytesReceived.Load() } func (a *Agent) connect(ctx context.Context, isControlling bool, remoteUfrag, remotePwd string) (*Conn, error) { @@ -74,7 +74,7 @@ func (c *Conn) Read(p []byte) (int, error) { } n, err := c.agent.buf.Read(p) - atomic.AddUint64(&c.bytesReceived, uint64(n)) //nolint:gosec // G115 + c.bytesReceived.Add(uint64(n)) //nolint:gosec // G115 return n, err } @@ -103,9 +103,14 @@ func (c *Conn) Write(packet []byte) (int, error) { } } - atomic.AddUint64(&c.bytesSent, uint64(len(packet))) + // Write application data via the selected pair and update stats with actual bytes written. + n, err := pair.Write(packet) + if n > 0 { + c.bytesSent.Add(uint64(n)) + pair.UpdatePacketSent(n) + } - return pair.Write(packet) + return n, err } // Close implements the Conn Close method. It is used to close diff --git a/vendor/github.com/pion/ice/v4/udp_mux.go b/vendor/github.com/pion/ice/v4/udp_mux.go index 3732b2685f..257ef5fa24 100644 --- a/vendor/github.com/pion/ice/v4/udp_mux.go +++ b/vendor/github.com/pion/ice/v4/udp_mux.go @@ -95,12 +95,13 @@ func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault { //nolint:cyclop _, addrs, err := localInterfaces(params.Net, nil, nil, networks, true) if err == nil { - for _, addr := range addrs { - localAddrsForUnspecified = append(localAddrsForUnspecified, &net.UDPAddr{ + localAddrsForUnspecified = make([]net.Addr, len(addrs)) + for i, addr := range addrs { + localAddrsForUnspecified[i] = &net.UDPAddr{ IP: addr.AsSlice(), Port: udpAddr.Port, Zone: addr.Zone(), - }) + } } } else { params.Logger.Errorf("Failed to get local interfaces for unspecified addr: %v", err) @@ -116,7 +117,7 @@ func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault { //nolint:cyclop connsIPv6: make(map[string]*udpMuxedConn), closedChan: make(chan struct{}, 1), pool: &sync.Pool{ - New: func() interface{} { + New: func() any { // Big enough buffer to fit both packet and address return newBufferHolder(receiveMTU) }, diff --git a/vendor/github.com/pion/ice/v4/udp_muxed_conn.go b/vendor/github.com/pion/ice/v4/udp_muxed_conn.go index e32cb30596..c9f4d2633c 100644 --- a/vendor/github.com/pion/ice/v4/udp_muxed_conn.go +++ b/vendor/github.com/pion/ice/v4/udp_muxed_conn.go @@ -6,6 +6,7 @@ package ice import ( "io" "net" + "slices" "sync" "time" @@ -102,8 +103,11 @@ func (c *udpMuxedConn) WriteTo(buf []byte, rAddr net.Addr) (n int, err error) { return 0, errFailedToCastUDPAddr } - //nolint:gosec // TODO add port validation G115 - ipAndPort, err := newIPPort(netUDPAddr.IP, netUDPAddr.Zone, uint16(netUDPAddr.Port)) + port := netUDPAddr.Port + if port < 0 || port > 0xFFFF { + return 0, ErrPort + } + ipAndPort, err := newIPPort(netUDPAddr.IP, netUDPAddr.Zone, uint16(port)) if err != nil { return 0, err } @@ -198,13 +202,8 @@ func (c *udpMuxedConn) removeAddress(addr ipPort) { func (c *udpMuxedConn) containsAddress(addr ipPort) bool { c.mu.Lock() defer c.mu.Unlock() - for _, a := range c.addresses { - if addr == a { - return true - } - } - return false + return slices.Contains(c.addresses, addr) } func (c *udpMuxedConn) writePacket(data []byte, addr *net.UDPAddr) error { diff --git a/vendor/github.com/pion/sctp/README.md b/vendor/github.com/pion/sctp/README.md index 18fa3f1641..ef33fb5b97 100644 --- a/vendor/github.com/pion/sctp/README.md +++ b/vendor/github.com/pion/sctp/README.md @@ -16,6 +16,36 @@


+### Implemented +- [RFC 6525](https://www.rfc-editor.org/rfc/rfc6525.html) — Stream Control Transmission Protocol (SCTP) Stream Reconfiguration +- [RFC 3758](https://www.rfc-editor.org/rfc/rfc3758.html) — Stream Control Transmission Protocol (SCTP) Partial Reliability Extension +- [RFC 5061](https://www.rfc-editor.org/rfc/rfc5061.html) — Stream Control Transmission Protocol (SCTP) Dynamic Address Reconfiguration +- [RFC 4895](https://www.rfc-editor.org/rfc/rfc4895.html) — Authenticated Chunks for the Stream Control Transmission Protocol (SCTP) +- [RFC 1982](https://www.rfc-editor.org/rfc/rfc1982.html) — Serial Number Arithmetic + +### Partial implementations +Pion only implements the subset of RFC 4960 that is required for WebRTC. + +- [RFC 4960](https://www.rfc-editor.org/rfc/rfc4960.html) — Stream Control Transmission Protocol [Obsoleted by 9260, above] +- [RFC 2960](https://www.rfc-editor.org/rfc/rfc2960.html) — Stream Control Transmission Protocol [Obsoleted by 4960, above] + +The update to [RFC 9260](https://www.rfc-editor.org/rfc/rfc9260) — Stream Control Transmission Protocol is currently a [work in progress](https://github.com/pion/sctp/issues/402). + +### Potential future implementations +Ideally, we would like to add the following features as part of a [v2 refresh](https://github.com/pion/sctp/issues/314): + +Feature | Reference | Progress +--- | --- | --- +RACK (tail loss probing) | [Paper](https://icnp20.cs.ucr.edu/proceedings/nipaa/RACK%20for%20SCTP.pdf), [Comment](https://github.com/pion/sctp/issues/206#issuecomment-968265853)| [In review](https://github.com/pion/sctp/pull/390) +Adaptive burst mitigation | [Paper, see section 5A](https://icnp20.cs.ucr.edu/proceedings/nipaa/RACK%20for%20SCTP.pdf)| [In review](https://github.com/pion/sctp/pull/394) +Update to RFC 9260 | [Parent issue](https://github.com/pion/sctp/issues/402) | [In progress](https://github.com/pion/sctp/issues/402) +Implement RFC 8260 | [Issue](https://github.com/pion/sctp/issues/435) | In progress (no PR available yet) +Blocking writes | [1](https://github.com/pion/sctp/issues/77), [2](https://github.com/pion/sctp/issues/357) | [Potentially in progress](https://github.com/pion/sctp/issues/357#issuecomment-3382050767) +association.listener (and better docs) | [1](https://github.com/pion/sctp/issues/74), [2](https://github.com/pion/sctp/issues/173) | Not started, [blocked by above](https://github.com/pion/sctp/issues/74#issuecomment-545550714) + +RFCs of interest: +- [RFC 9438](https://datatracker.ietf.org/doc/rfc9438/) as it addresses the low utilization problem of [RFC 4960](https://www.rfc-editor.org/rfc/rfc4960.html) in fast long-distance networks as mentioned [here](https://github.com/pion/sctp/issues/218#issuecomment-3329690797). + ### Roadmap The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones. diff --git a/vendor/github.com/pion/sctp/association.go b/vendor/github.com/pion/sctp/association.go index dc8b7bec2f..e47b3feeca 100644 --- a/vendor/github.com/pion/sctp/association.go +++ b/vendor/github.com/pion/sctp/association.go @@ -578,8 +578,14 @@ func (a *Association) Abort(reason string) { a.lock.Unlock() + // short bound for abort flush. + _ = a.netConn.SetWriteDeadline(time.Now().Add(200 * time.Millisecond)) a.awakeWriteLoop() + // unblock readLoop even if the underlying TCP connection is half-open. + // We want Abort to return promptly during shutdown. + _ = a.netConn.SetReadDeadline(time.Now()) + // Wait for readLoop to end <-a.readLoopCloseCh } diff --git a/vendor/github.com/pion/sctp/paramtype.go b/vendor/github.com/pion/sctp/paramtype.go index c82d2bf71e..b1cdacd3c4 100644 --- a/vendor/github.com/pion/sctp/paramtype.go +++ b/vendor/github.com/pion/sctp/paramtype.go @@ -13,14 +13,14 @@ import ( type paramType uint16 const ( - heartbeatInfo paramType = 1 // Heartbeat Info [RFC4960] - ipV4Addr paramType = 5 // IPv4 IP [RFC4960] - ipV6Addr paramType = 6 // IPv6 IP [RFC4960] - stateCookie paramType = 7 // State Cookie [RFC4960] - unrecognizedParam paramType = 8 // Unrecognized Parameters [RFC4960] - cookiePreservative paramType = 9 // Cookie Preservative [RFC4960] - hostNameAddr paramType = 11 // Host Name IP [RFC4960] - supportedAddrTypes paramType = 12 // Supported IP Types [RFC4960] + heartbeatInfo paramType = 1 // Heartbeat Info [RFC9260] + ipV4Addr paramType = 5 // IPv4 IP [RFC9260] + ipV6Addr paramType = 6 // IPv6 IP [RFC9260] + stateCookie paramType = 7 // State Cookie [RFC9260] + unrecognizedParam paramType = 8 // Unrecognized Parameters [RFC9260] + cookiePreservative paramType = 9 // Cookie Preservative [RFC9260] + hostNameAddr paramType = 11 // Host Name Address [RFC9260] + supportedAddrTypes paramType = 12 // Supported IP Types [RFC9260] outSSNResetReq paramType = 13 // Outgoing SSN Reset Request Parameter [RFC6525] incSSNResetReq paramType = 14 // Incoming SSN Reset Request Parameter [RFC6525] ssnTSNResetReq paramType = 15 // SSN/TSN Reset Request Parameter [RFC6525] @@ -29,14 +29,14 @@ const ( addIncStreamsReq paramType = 18 // Add Incoming Streams Request Parameter [RFC6525] ecnCapable paramType = 32768 // ECN Capable (0x8000) [RFC2960] zeroChecksumAcceptable paramType = 32769 // Zero Checksum Acceptable [draft-ietf-tsvwg-sctp-zero-checksum-00] - random paramType = 32770 // Random (0x8002) [RFC4805] + random paramType = 32770 // Random (0x8002) [RFC4895] chunkList paramType = 32771 // Chunk List (0x8003) [RFC4895] reqHMACAlgo paramType = 32772 // Requested HMAC Algorithm Parameter (0x8004) [RFC4895] padding paramType = 32773 // Padding (0x8005) supportedExt paramType = 32776 // Supported Extensions (0x8008) [RFC5061] forwardTSNSupp paramType = 49152 // Forward TSN supported (0xC000) [RFC3758] - addIPAddr paramType = 49153 // Add IP IP (0xC001) [RFC5061] - delIPAddr paramType = 49154 // Delete IP IP (0xC002) [RFC5061] + addIPAddr paramType = 49153 // Add IP Address (0xC001) [RFC5061] + delIPAddr paramType = 49154 // Delete IP Address (0xC002) [RFC5061] errClauseInd paramType = 49155 // Error Cause Indication (0xC003) [RFC5061] setPriAddr paramType = 49156 // Set Primary IP (0xC004) [RFC5061] successInd paramType = 49157 // Success Indication (0xC005) [RFC5061] @@ -45,7 +45,7 @@ const ( // Parameter packet errors. var ( - ErrParamPacketTooShort = errors.New("packet to short") + ErrParamPacketTooShort = errors.New("packet too short") ) func parseParamType(raw []byte) (paramType, error) { @@ -71,7 +71,7 @@ func (p paramType) String() string { //nolint:cyclop case cookiePreservative: return "Cookie Preservative" case hostNameAddr: - return "Host Name IP" + return "Host Name Address" case supportedAddrTypes: return "Supported IP Types" case outSSNResetReq: @@ -103,9 +103,9 @@ func (p paramType) String() string { //nolint:cyclop case forwardTSNSupp: return "Forward TSN supported" case addIPAddr: - return "Add IP IP" + return "Add IP Address" case delIPAddr: - return "Delete IP IP" + return "Delete IP Address" case errClauseInd: return "Error Cause Indication" case setPriAddr: diff --git a/vendor/github.com/pion/sctp/pending_queue.go b/vendor/github.com/pion/sctp/pending_queue.go index a9a1552b42..d3aeba86ad 100644 --- a/vendor/github.com/pion/sctp/pending_queue.go +++ b/vendor/github.com/pion/sctp/pending_queue.go @@ -25,8 +25,15 @@ func (q *pendingBaseQueue) pop() *chunkPayloadData { if len(q.queue) == 0 { return nil } + c := q.queue[0] - q.queue = q.queue[1:] + q.queue[0] = nil + + if len(q.queue) == 0 { + q.queue = nil + } else { + q.queue = q.queue[1:] + } return c } @@ -55,9 +62,14 @@ type pendingQueue struct { // Pending queue errors. var ( - ErrUnexpectedChuckPoppedUnordered = errors.New("unexpected chunk popped (unordered)") - ErrUnexpectedChuckPoppedOrdered = errors.New("unexpected chunk popped (ordered)") + ErrUnexpectedChunkPoppedUnordered = errors.New("unexpected chunk popped (unordered)") + ErrUnexpectedChunkPoppedOrdered = errors.New("unexpected chunk popped (ordered)") ErrUnexpectedQState = errors.New("unexpected q state (should've been selected)") + + // Deprecated: use ErrUnexpectedChunkPoppedUnordered. + ErrUnexpectedChuckPoppedUnordered = ErrUnexpectedChunkPoppedUnordered + // Deprecated: use ErrUnexpectedChunkPoppedOrdered. + ErrUnexpectedChuckPoppedOrdered = ErrUnexpectedChunkPoppedOrdered ) func newPendingQueue() *pendingQueue { @@ -98,12 +110,12 @@ func (q *pendingQueue) pop(chunkPayload *chunkPayloadData) error { //nolint:cycl if q.unorderedIsSelected { popped = q.unorderedQueue.pop() if popped != chunkPayload { - return ErrUnexpectedChuckPoppedUnordered + return ErrUnexpectedChunkPoppedUnordered } } else { popped = q.orderedQueue.pop() if popped != chunkPayload { - return ErrUnexpectedChuckPoppedOrdered + return ErrUnexpectedChunkPoppedOrdered } } if popped.endingFragment { @@ -116,7 +128,7 @@ func (q *pendingQueue) pop(chunkPayload *chunkPayloadData) error { //nolint:cycl if chunkPayload.unordered { popped := q.unorderedQueue.pop() if popped != chunkPayload { - return ErrUnexpectedChuckPoppedUnordered + return ErrUnexpectedChunkPoppedUnordered } if !popped.endingFragment { q.selected = true @@ -125,7 +137,7 @@ func (q *pendingQueue) pop(chunkPayload *chunkPayloadData) error { //nolint:cycl } else { popped := q.orderedQueue.pop() if popped != chunkPayload { - return ErrUnexpectedChuckPoppedOrdered + return ErrUnexpectedChunkPoppedOrdered } if !popped.endingFragment { q.selected = true @@ -133,7 +145,12 @@ func (q *pendingQueue) pop(chunkPayload *chunkPayloadData) error { //nolint:cycl } } } + + // guard against negative values (should never happen, but just in case). q.nBytes -= len(chunkPayload.userData) + if q.nBytes < 0 { + q.nBytes = 0 + } return nil } diff --git a/vendor/github.com/pion/sctp/receive_payload_queue.go b/vendor/github.com/pion/sctp/receive_payload_queue.go index 30c9109dc0..faa2377df6 100644 --- a/vendor/github.com/pion/sctp/receive_payload_queue.go +++ b/vendor/github.com/pion/sctp/receive_payload_queue.go @@ -102,7 +102,7 @@ func (q *receivePayloadQueue) pop(force bool) bool { return false } -// popDuplicates returns an array of TSN values that were found duplicate. +// popDuplicates returns an array of TSN values that were duplicated. func (q *receivePayloadQueue) popDuplicates() []uint32 { dups := q.dupTSN q.dupTSN = []uint32{} @@ -117,6 +117,8 @@ func (q *receivePayloadQueue) getGapAckBlocks() (gapAckBlocks []gapAckBlock) { return nil } + // RFC 9260 section 3.3.4: Gap Ack Blocks report received TSNs greater than + // the Cumulative TSN Ack and up to the highest TSN newly received. startTSN, endTSN := q.cumulativeTSN+1, q.tailTSN var findEnd bool for tsn := startTSN; sna32LTE(tsn, endTSN); { diff --git a/vendor/github.com/pion/srtp/v3/stream_srtp.go b/vendor/github.com/pion/srtp/v3/stream_srtp.go index 1b34266c13..be746a69a4 100644 --- a/vendor/github.com/pion/srtp/v3/stream_srtp.go +++ b/vendor/github.com/pion/srtp/v3/stream_srtp.go @@ -6,6 +6,7 @@ package srtp import ( "errors" "io" + "slices" "sync" "time" @@ -26,7 +27,8 @@ type ReadStreamSRTP struct { ssrc uint32 isInited bool - buffer io.ReadWriteCloser + buffer io.ReadWriteCloser + peekedPackets [][]byte } // Used by getOrCreateReadStream. @@ -74,8 +76,31 @@ func (r *ReadStreamSRTP) write(buf []byte) (n int, err error) { return n, err } +// Peek reads and decrypts full RTP packet from the nextConn. +// It is then buffered so that a call to `Read` will return it. +func (r *ReadStreamSRTP) Peek(buf []byte) (n int, err error) { + n, err = r.buffer.Read(buf) + if err == nil { + r.peekedPackets = append(r.peekedPackets, slices.Clone(buf[:n])) + } + + return +} + // Read reads and decrypts full RTP packet from the nextConn. func (r *ReadStreamSRTP) Read(buf []byte) (int, error) { + if len(r.peekedPackets) != 0 { + if len(r.peekedPackets[0]) > len(buf) { + return 0, io.ErrShortBuffer + } + + n := len(r.peekedPackets[0]) + copy(buf, r.peekedPackets[0]) + r.peekedPackets = r.peekedPackets[1:] + + return n, nil + } + return r.buffer.Read(buf) } diff --git a/vendor/modules.txt b/vendor/modules.txt index cb4330cf83..e75c576b9b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -61,7 +61,7 @@ github.com/CortexFoundation/robot/backend # github.com/CortexFoundation/statik v0.0.0-20210315012922-8bb8a7b5dc66 ## explicit; go 1.16 github.com/CortexFoundation/statik -# github.com/CortexFoundation/torrentfs v1.0.73-0.20251124184227-7b581860e3c0 +# github.com/CortexFoundation/torrentfs v1.0.73-0.20251202154802-316eb23b5a00 ## explicit; go 1.24.4 github.com/CortexFoundation/torrentfs github.com/CortexFoundation/torrentfs/backend @@ -91,13 +91,13 @@ github.com/RoaringBitmap/roaring/internal # github.com/VictoriaMetrics/fastcache v1.13.2 ## explicit; go 1.24.0 github.com/VictoriaMetrics/fastcache -# github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 => github.com/anacrolix/btree v0.0.0-20251103085645-fd1051eb0009 -## explicit; go 1.23 -github.com/ajwerner/btree -github.com/ajwerner/btree/internal/abstract # github.com/alecthomas/atomic v0.1.0-alpha2 ## explicit; go 1.18 github.com/alecthomas/atomic +# github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8 +## explicit; go 1.23 +github.com/anacrolix/btree +github.com/anacrolix/btree/internal/abstract # github.com/anacrolix/chansync v0.7.0 ## explicit; go 1.16 github.com/anacrolix/chansync @@ -117,7 +117,7 @@ github.com/anacrolix/dht/v2/types # github.com/anacrolix/envpprof v1.4.0 ## explicit; go 1.12 github.com/anacrolix/envpprof -# github.com/anacrolix/generics v0.1.0 +# github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b ## explicit; go 1.18 github.com/anacrolix/generics github.com/anacrolix/generics/heap @@ -164,8 +164,8 @@ github.com/anacrolix/stm/stmutil # github.com/anacrolix/sync v0.5.5-0.20251119100342-d78dd1f686f1 ## explicit; go 1.18 github.com/anacrolix/sync -# github.com/anacrolix/torrent v1.59.2-0.20251121022239-29ca7fdf5c63 -## explicit; go 1.24 +# github.com/anacrolix/torrent v1.59.2-0.20251201070025-62f62628d9b8 +## explicit; go 1.24.0 github.com/anacrolix/torrent github.com/anacrolix/torrent/analysis github.com/anacrolix/torrent/bencode @@ -248,10 +248,10 @@ github.com/aws/aws-sdk-go-v2/internal/shareddefaults github.com/aws/aws-sdk-go-v2/internal/strings github.com/aws/aws-sdk-go-v2/internal/sync/singleflight github.com/aws/aws-sdk-go-v2/internal/timeconv -# github.com/aws/aws-sdk-go-v2/config v1.32.1 +# github.com/aws/aws-sdk-go-v2/config v1.32.2 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/config -# github.com/aws/aws-sdk-go-v2/credentials v1.19.1 +# github.com/aws/aws-sdk-go-v2/credentials v1.19.2 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/credentials github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds @@ -280,33 +280,33 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding # github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url -# github.com/aws/aws-sdk-go-v2/service/route53 v1.60.1 +# github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/route53 github.com/aws/aws-sdk-go-v2/service/route53/internal/customizations github.com/aws/aws-sdk-go-v2/service/route53/internal/endpoints github.com/aws/aws-sdk-go-v2/service/route53/types -# github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 +# github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/signin github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints github.com/aws/aws-sdk-go-v2/service/signin/types -# github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 +# github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/sso github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints github.com/aws/aws-sdk-go-v2/service/sso/types -# github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 +# github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/ssooidc github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints github.com/aws/aws-sdk-go-v2/service/ssooidc/types -# github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 +# github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 ## explicit; go 1.23 github.com/aws/aws-sdk-go-v2/service/sts github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints github.com/aws/aws-sdk-go-v2/service/sts/types -# github.com/aws/smithy-go v1.23.2 +# github.com/aws/smithy-go v1.24.0 ## explicit; go 1.23 github.com/aws/smithy-go github.com/aws/smithy-go/auth @@ -318,6 +318,7 @@ github.com/aws/smithy-go/encoding/httpbinding github.com/aws/smithy-go/encoding/json github.com/aws/smithy-go/encoding/xml github.com/aws/smithy-go/endpoints +github.com/aws/smithy-go/endpoints/private/rulesfn github.com/aws/smithy-go/internal/sync/singleflight github.com/aws/smithy-go/io github.com/aws/smithy-go/logging @@ -370,7 +371,7 @@ github.com/charmbracelet/colorprofile # github.com/charmbracelet/lipgloss v1.1.0 ## explicit; go 1.18 github.com/charmbracelet/lipgloss -# github.com/charmbracelet/x/ansi v0.11.1 +# github.com/charmbracelet/x/ansi v0.11.2 ## explicit; go 1.24.2 github.com/charmbracelet/x/ansi github.com/charmbracelet/x/ansi/parser @@ -380,7 +381,7 @@ github.com/charmbracelet/x/cellbuf # github.com/charmbracelet/x/term v0.2.2 ## explicit; go 1.24.0 github.com/charmbracelet/x/term -# github.com/clipperhouse/displaywidth v0.6.0 +# github.com/clipperhouse/displaywidth v0.6.1 ## explicit; go 1.18 github.com/clipperhouse/displaywidth # github.com/clipperhouse/stringish v0.1.1 @@ -549,7 +550,7 @@ github.com/dgraph-io/ristretto/v2/z/simd ## explicit; go 1.13 github.com/dlclark/regexp2 github.com/dlclark/regexp2/syntax -# github.com/dop251/goja v0.0.0-20251121114222-56b1242a5f86 +# github.com/dop251/goja v0.0.0-20251201205617-2bb4c724c0f9 ## explicit; go 1.20 github.com/dop251/goja github.com/dop251/goja/ast @@ -603,7 +604,7 @@ github.com/garslo/gogen # github.com/gballet/go-libpcsclite v0.0.0-20250918194357-1ec6f2e601c6 ## explicit; go 1.19 github.com/gballet/go-libpcsclite -# github.com/getsentry/sentry-go v0.39.0 +# github.com/getsentry/sentry-go v0.40.0 ## explicit; go 1.23.0 github.com/getsentry/sentry-go github.com/getsentry/sentry-go/attribute @@ -755,7 +756,7 @@ github.com/jedib0t/go-pretty/v6/text # github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7 ## explicit; go 1.23.4 github.com/jedisct1/go-minisign -# github.com/klauspost/compress v1.18.1 +# github.com/klauspost/compress v1.18.2 ## explicit; go 1.23 github.com/klauspost/compress github.com/klauspost/compress/fse @@ -909,8 +910,8 @@ github.com/pion/dtls/v3/pkg/protocol/alert github.com/pion/dtls/v3/pkg/protocol/extension github.com/pion/dtls/v3/pkg/protocol/handshake github.com/pion/dtls/v3/pkg/protocol/recordlayer -# github.com/pion/ice/v4 v4.0.10 -## explicit; go 1.20 +# github.com/pion/ice/v4 v4.0.12 +## explicit; go 1.21 github.com/pion/ice/v4 github.com/pion/ice/v4/internal/atomic github.com/pion/ice/v4/internal/fakenet @@ -947,13 +948,13 @@ github.com/pion/rtp github.com/pion/rtp/codecs github.com/pion/rtp/codecs/av1/obu github.com/pion/rtp/codecs/vp9 -# github.com/pion/sctp v1.8.40 +# github.com/pion/sctp v1.8.41 ## explicit; go 1.21 github.com/pion/sctp # github.com/pion/sdp/v3 v3.0.16 ## explicit; go 1.21 github.com/pion/sdp/v3 -# github.com/pion/srtp/v3 v3.0.8 +# github.com/pion/srtp/v3 v3.0.9 ## explicit; go 1.21 github.com/pion/srtp/v3 # github.com/pion/stun/v2 v2.0.0 @@ -1104,7 +1105,7 @@ github.com/ucwong/filecache # github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb ## explicit; go 1.19 github.com/ucwong/go-ttlmap -# github.com/ucwong/golang-kv v1.0.24-0.20251109124133-d3b517c91775 +# github.com/ucwong/golang-kv v1.0.24-0.20251129161750-0c74710bc499 ## explicit; go 1.24.0 github.com/ucwong/golang-kv github.com/ucwong/golang-kv/badger @@ -1202,7 +1203,7 @@ golang.org/x/crypto/ripemd160 golang.org/x/crypto/scrypt golang.org/x/crypto/sha3 golang.org/x/crypto/ssh/terminal -# golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 +# golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 ## explicit; go 1.24.0 golang.org/x/exp/constraints golang.org/x/exp/rand @@ -1402,4 +1403,3 @@ modernc.org/sqlite/lib ## explicit; go 1.23.0 zombiezen.com/go/sqlite zombiezen.com/go/sqlite/sqlitex -# github.com/ajwerner/btree => github.com/anacrolix/btree v0.0.0-20251103085645-fd1051eb0009