chore_: bump go-waku (#5150)

This commit is contained in:
richΛrd 2024-05-15 19:15:00 -04:00 committed by GitHub
parent 5ca1cb0a0f
commit 9e0fb30f8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1131 changed files with 26101 additions and 26172 deletions

View File

@ -8,8 +8,8 @@ import (
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/waku-org/go-waku/waku/v2/protocol/store" "github.com/waku-org/go-waku/waku/v2/protocol/legacy_store"
storepb "github.com/waku-org/go-waku/waku/v2/protocol/store/pb" storepb "github.com/waku-org/go-waku/waku/v2/protocol/legacy_store/pb"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/connection" "github.com/status-im/status-go/connection"
@ -177,19 +177,19 @@ func (w *gethWakuV2Wrapper) SendMessagesRequest(peerID []byte, r types.MessagesR
} }
func (w *gethWakuV2Wrapper) RequestStoreMessages(ctx context.Context, peerID []byte, r types.MessagesRequest, processEnvelopes bool) (*types.StoreRequestCursor, int, error) { func (w *gethWakuV2Wrapper) RequestStoreMessages(ctx context.Context, peerID []byte, r types.MessagesRequest, processEnvelopes bool) (*types.StoreRequestCursor, int, error) {
var options []store.HistoryRequestOption var options []legacy_store.HistoryRequestOption
peer, err := peer.Decode(string(peerID)) peer, err := peer.Decode(string(peerID))
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
options = []store.HistoryRequestOption{ options = []legacy_store.HistoryRequestOption{
store.WithPaging(false, uint64(r.Limit)), legacy_store.WithPaging(false, uint64(r.Limit)),
} }
if r.StoreCursor != nil { if r.StoreCursor != nil {
options = append(options, store.WithCursor(&storepb.Index{ options = append(options, legacy_store.WithCursor(&storepb.Index{
Digest: r.StoreCursor.Digest, Digest: r.StoreCursor.Digest,
ReceiverTime: r.StoreCursor.ReceiverTime, ReceiverTime: r.StoreCursor.ReceiverTime,
SenderTime: r.StoreCursor.SenderTime, SenderTime: r.StoreCursor.SenderTime,

107
go.mod
View File

@ -33,11 +33,11 @@ require (
github.com/keighl/metabolize v0.0.0-20150915210303-97ab655d4034 github.com/keighl/metabolize v0.0.0-20150915210303-97ab655d4034
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f
github.com/lib/pq v1.10.4 github.com/lib/pq v1.10.4
github.com/libp2p/go-libp2p v0.29.2 github.com/libp2p/go-libp2p v0.32.2
github.com/libp2p/go-libp2p-pubsub v0.9.3 github.com/libp2p/go-libp2p-pubsub v0.10.1
github.com/lucasb-eyer/go-colorful v1.0.3 github.com/lucasb-eyer/go-colorful v1.0.3
github.com/mat/besticon v0.0.0-20210314201728-1579f269edb7 github.com/mat/besticon v0.0.0-20210314201728-1579f269edb7
github.com/multiformats/go-multiaddr v0.10.1 github.com/multiformats/go-multiaddr v0.12.3
github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-multibase v0.2.0
github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-multihash v0.2.3
github.com/multiformats/go-varint v0.0.7 github.com/multiformats/go-varint v0.0.7
@ -52,19 +52,19 @@ require (
github.com/status-im/markdown v0.0.0-20240404192634-b7e33c6ac3d4 github.com/status-im/markdown v0.0.0-20240404192634-b7e33c6ac3d4
github.com/status-im/migrate/v4 v4.6.2-status.3 github.com/status-im/migrate/v4 v4.6.2-status.3
github.com/status-im/mvds v0.0.27-0.20240111144448-92d364e4be82 github.com/status-im/mvds v0.0.27-0.20240111144448-92d364e4be82
github.com/status-im/rendezvous v1.3.7 github.com/status-im/rendezvous v1.3.8-0.20240110194857-cc5be22bf83e
github.com/status-im/status-go/extkeys v1.1.2 github.com/status-im/status-go/extkeys v1.1.2
github.com/status-im/tcp-shaker v1.1.1-status github.com/status-im/tcp-shaker v1.1.1-status
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857 github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.9.0
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9
github.com/wealdtech/go-ens/v3 v3.5.0 github.com/wealdtech/go-ens/v3 v3.5.0
github.com/wealdtech/go-multicodec v1.4.0 github.com/wealdtech/go-multicodec v1.4.0
github.com/xeipuuv/gojsonschema v1.2.0 github.com/xeipuuv/gojsonschema v1.2.0
github.com/zenthangplus/goccm v0.0.0-20211005163543-2f2e522aca15 github.com/zenthangplus/goccm v0.0.0-20211005163543-2f2e522aca15
go.uber.org/zap v1.24.0 go.uber.org/zap v1.27.0
golang.org/x/crypto v0.12.0 golang.org/x/crypto v0.18.0
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
@ -90,20 +90,20 @@ require (
github.com/mutecomm/go-sqlcipher/v4 v4.4.2 github.com/mutecomm/go-sqlcipher/v4 v4.4.2
github.com/schollz/peerdiscovery v1.7.0 github.com/schollz/peerdiscovery v1.7.0
github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7 github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7
github.com/urfave/cli/v2 v2.24.4 github.com/urfave/cli/v2 v2.27.2
github.com/waku-org/go-waku v0.8.1-0.20240415131212-6d889ca3e2fe github.com/waku-org/go-waku v0.8.1-0.20240507175626-19d27befd98b
github.com/wk8/go-ordered-map/v2 v2.1.7 github.com/wk8/go-ordered-map/v2 v2.1.7
github.com/yeqown/go-qrcode/v2 v2.2.1 github.com/yeqown/go-qrcode/v2 v2.2.1
github.com/yeqown/go-qrcode/writer/standard v1.2.1 github.com/yeqown/go-qrcode/writer/standard v1.2.1
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/net v0.14.0 golang.org/x/net v0.17.0
golang.org/x/text v0.12.0 golang.org/x/text v0.14.0
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af golang.org/x/time v0.0.0-20220922220347-f3bd1da661af
) )
require ( require (
github.com/BurntSushi/toml v1.2.1 // indirect github.com/BurntSushi/toml v1.3.2 // indirect
github.com/PuerkitoBio/goquery v1.6.1 // indirect github.com/PuerkitoBio/goquery v1.6.1 // indirect
github.com/RoaringBitmap/roaring v0.9.4 // indirect github.com/RoaringBitmap/roaring v0.9.4 // indirect
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
@ -137,7 +137,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
@ -163,21 +163,21 @@ require (
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.0.1 // indirect github.com/google/btree v1.0.1 // indirect
github.com/google/gopacket v1.1.19 // indirect github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect
github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.2.0 // indirect github.com/holiman/uint256 v1.2.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect
github.com/huin/goupnp v1.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect github.com/koron/go-ssdp v0.0.4 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
@ -187,19 +187,20 @@ require (
github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
github.com/libp2p/go-libp2p-mplex v0.9.0 // indirect
github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-reuseport v0.3.0 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.55 // indirect github.com/miekg/dns v1.1.56 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
@ -212,38 +213,36 @@ require (
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multistream v0.4.1 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pion/datachannel v1.5.2 // indirect github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.1.2 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/ice/v2 v2.1.20 // indirect github.com/pion/ice/v2 v2.3.6 // indirect
github.com/pion/interceptor v0.1.7 // indirect github.com/pion/interceptor v0.1.17 // indirect
github.com/pion/logging v0.2.2 // indirect github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect github.com/pion/mdns v0.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.9 // indirect github.com/pion/rtcp v1.2.10 // indirect
github.com/pion/rtp v1.7.4 // indirect github.com/pion/rtp v1.7.13 // indirect
github.com/pion/sctp v1.8.2 // indirect github.com/pion/sctp v1.8.7 // indirect
github.com/pion/sdp/v3 v3.0.4 // indirect github.com/pion/sdp/v3 v3.0.6 // indirect
github.com/pion/srtp/v2 v2.0.5 // indirect github.com/pion/srtp/v2 v2.0.15 // indirect
github.com/pion/stun v0.3.5 // indirect github.com/pion/stun v0.6.0 // indirect
github.com/pion/transport v0.13.0 // indirect github.com/pion/transport/v2 v2.2.1 // indirect
github.com/pion/turn/v2 v2.0.6 // indirect github.com/pion/turn/v2 v2.1.0 // indirect
github.com/pion/udp v0.1.1 // indirect github.com/pion/webrtc/v3 v3.2.9 // indirect
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect github.com/prometheus/procfs v0.10.1 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect github.com/prometheus/tsdb v0.10.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/quic-go/quic-go v0.39.4 // indirect
github.com/quic-go/quic-go v0.36.4 // indirect github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/quic-go/webtransport-go v0.5.3 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
@ -258,12 +257,12 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/status-im/go-multiaddr-ethv4 v1.2.5 // indirect github.com/status-im/go-multiaddr-ethv4 v1.2.5 // indirect
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3 // indirect github.com/waku-org/go-discover v0.0.0-20240506173252-4912704efdc5 // indirect
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 // indirect github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0 // indirect
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 // indirect github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect
@ -271,19 +270,19 @@ require (
github.com/wk8/go-ordered-map v1.0.0 // indirect github.com/wk8/go-ordered-map v1.0.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/bbolt v1.3.6 // indirect go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.0 // indirect go.uber.org/dig v1.17.1 // indirect
go.uber.org/fx v1.20.0 // indirect go.uber.org/fx v1.20.1 // indirect
golang.org/x/mod v0.12.0 // indirect go.uber.org/mock v0.3.0 // indirect
golang.org/x/sync v0.3.0 // indirect golang.org/x/mod v0.13.0 // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.18.0 // indirect golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.11.0 // indirect golang.org/x/term v0.16.0 // indirect
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 // indirect golang.org/x/tools v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect

237
go.sum
View File

@ -104,8 +104,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
@ -632,8 +632,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -1023,8 +1023,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -1112,8 +1112,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
@ -1135,8 +1135,8 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -1290,8 +1290,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@ -1348,12 +1348,14 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
github.com/libp2p/go-libp2p v0.29.2 h1:uPw/c8hOxoLP/KhFnzlc5Ejqf+OmAL1dwIsqE31WBtY= github.com/libp2p/go-libp2p v0.32.2 h1:s8GYN4YJzgUoyeYNPdW7JZeZ5Ee31iNaIBfGYMAY4FQ=
github.com/libp2p/go-libp2p v0.29.2/go.mod h1:OU7nSq0aEZMsV2wY8nXn1+XNNt9q2UiR8LjW3Kmp2UE= github.com/libp2p/go-libp2p v0.32.2/go.mod h1:E0LKe+diV/ZVJVnOJby8VC5xzHF0660osg71skcxJvk=
github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s=
github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w=
github.com/libp2p/go-libp2p-pubsub v0.9.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= github.com/libp2p/go-libp2p-mplex v0.9.0 h1:R58pDRAmuBXkYugbSSXR9wrTX3+1pFM1xP2bLuodIq8=
github.com/libp2p/go-libp2p-pubsub v0.9.3/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc= github.com/libp2p/go-libp2p-mplex v0.9.0/go.mod h1:ro1i4kuwiFT+uMPbIDIFkcLs1KRbNp0QwnUXM+P64Og=
github.com/libp2p/go-libp2p-pubsub v0.10.1 h1:/RqOZpEtAolsr8/9CC8KqROJSOZeu7lK7fPftn4MwNg=
github.com/libp2p/go-libp2p-pubsub v0.10.1/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw=
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=
github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY=
@ -1364,8 +1366,8 @@ github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
@ -1426,8 +1428,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@ -1458,8 +1460,8 @@ github.com/meirf/gopart v0.0.0-20180520194036-37e9492a85a8/go.mod h1:Uz8uoD6o+eQ
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
@ -1526,8 +1528,8 @@ github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
github.com/multiformats/go-multiaddr v0.3.2/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr v0.3.2/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0=
github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= github.com/multiformats/go-multiaddr v0.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8=
github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
@ -1543,8 +1545,8 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj
github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=
github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA=
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
@ -1602,8 +1604,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@ -1618,7 +1620,7 @@ github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQ
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -1643,8 +1645,9 @@ github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
@ -1684,34 +1687,39 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg= github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U= github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U=
github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I= github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I=
github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI= github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI=
github.com/pion/dtls/v2 v2.0.7/go.mod h1:QuDII+8FVvk9Dp5t5vYIMTo7hh7uBkra+8QIm7QGm10= github.com/pion/dtls/v2 v2.0.7/go.mod h1:QuDII+8FVvk9Dp5t5vYIMTo7hh7uBkra+8QIm7QGm10=
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho= github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
github.com/pion/dtls/v2 v2.1.1/go.mod h1:qG3gA7ZPZemBqpEFqRKyURYdKEwFZQCGb7gv9T3ON3Y= github.com/pion/dtls/v2 v2.1.1/go.mod h1:qG3gA7ZPZemBqpEFqRKyURYdKEwFZQCGb7gv9T3ON3Y=
github.com/pion/dtls/v2 v2.1.2 h1:22Q1Jk9L++Yo7BIf9130MonNPfPVb+YgdYLeyQotuAA=
github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus= github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/ice v0.7.18/go.mod h1:+Bvnm3nYC6Nnp7VV6glUkuOfToB/AtMRZpOU8ihuf4c= github.com/pion/ice v0.7.18/go.mod h1:+Bvnm3nYC6Nnp7VV6glUkuOfToB/AtMRZpOU8ihuf4c=
github.com/pion/ice/v2 v2.0.15/go.mod h1:ZIiVGevpgAxF/cXiIVmuIUtCb3Xs4gCzCbXB6+nFkSI= github.com/pion/ice/v2 v2.0.15/go.mod h1:ZIiVGevpgAxF/cXiIVmuIUtCb3Xs4gCzCbXB6+nFkSI=
github.com/pion/ice/v2 v2.1.7/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0= github.com/pion/ice/v2 v2.1.7/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0=
github.com/pion/ice/v2 v2.1.10/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0= github.com/pion/ice/v2 v2.1.10/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0=
github.com/pion/ice/v2 v2.1.12/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU= github.com/pion/ice/v2 v2.1.12/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
github.com/pion/ice/v2 v2.1.20 h1:xpxXyX5b4WjCh/D905gzBeW/hbJxMEPx2ptVfrhVE6M=
github.com/pion/ice/v2 v2.1.20/go.mod h1:hEAldRzBhTtAfvlU1V/2/nLCMvveQWFKPNCop+63/Iw= github.com/pion/ice/v2 v2.1.20/go.mod h1:hEAldRzBhTtAfvlU1V/2/nLCMvveQWFKPNCop+63/Iw=
github.com/pion/ice/v2 v2.3.6 h1:Jgqw36cAud47iD+N6rNX225uHvrgWtAlHfVyOQc3Heg=
github.com/pion/ice/v2 v2.3.6/go.mod h1:9/TzKDRwBVAPsC+YOrKH/e3xDrubeTRACU9/sHQarsU=
github.com/pion/interceptor v0.0.9/go.mod h1:dHgEP5dtxOTf21MObuBAjJeAayPxLUAZjerGH8Xr07c= github.com/pion/interceptor v0.0.9/go.mod h1:dHgEP5dtxOTf21MObuBAjJeAayPxLUAZjerGH8Xr07c=
github.com/pion/interceptor v0.0.12/go.mod h1:qzeuWuD/ZXvPqOnxNcnhWfkCZ2e1kwwslicyyPnhoK4= github.com/pion/interceptor v0.0.12/go.mod h1:qzeuWuD/ZXvPqOnxNcnhWfkCZ2e1kwwslicyyPnhoK4=
github.com/pion/interceptor v0.0.13/go.mod h1:svsW2QoLHLoGLUr4pDoSopGBEWk8FZwlfxId/OKRKzo= github.com/pion/interceptor v0.0.13/go.mod h1:svsW2QoLHLoGLUr4pDoSopGBEWk8FZwlfxId/OKRKzo=
github.com/pion/interceptor v0.0.15/go.mod h1:pg3J253eGi5bqyKzA74+ej5Y19ez2jkWANVnF+Z9Dfk= github.com/pion/interceptor v0.0.15/go.mod h1:pg3J253eGi5bqyKzA74+ej5Y19ez2jkWANVnF+Z9Dfk=
github.com/pion/interceptor v0.1.7 h1:HThW0tIIKT9RRoDWGURe8rlZVOx0fJHxBHpA0ej0+bo=
github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U= github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
github.com/pion/interceptor v0.1.17 h1:prJtgwFh/gB8zMqGZoOgJPHivOwVAp61i2aG61Du/1w=
github.com/pion/interceptor v0.1.17/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0= github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g= github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k= github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k=
github.com/pion/quic v0.1.4/go.mod h1:dBhNvkLoQqRwfi6h3Vqj3IcPLgiW7rkZxBbRdp7Vzvk= github.com/pion/quic v0.1.4/go.mod h1:dBhNvkLoQqRwfi6h3Vqj3IcPLgiW7rkZxBbRdp7Vzvk=
github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
@ -1720,33 +1728,41 @@ github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TB
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I= github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I=
github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo= github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI= github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI=
github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.6.5/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.6.5/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.7.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0= github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0= github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw=
github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU=
github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E= github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk= github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA= github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA=
github.com/pion/srtp v1.5.2/go.mod h1:NiBff/MSxUwMUwx/fRNyD/xGE+dVvf8BOCeXhjCXZ9U= github.com/pion/srtp v1.5.2/go.mod h1:NiBff/MSxUwMUwx/fRNyD/xGE+dVvf8BOCeXhjCXZ9U=
github.com/pion/srtp/v2 v2.0.1/go.mod h1:c8NWHhhkFf/drmHTAblkdu8++lsISEBBdAuiyxgqIsE= github.com/pion/srtp/v2 v2.0.1/go.mod h1:c8NWHhhkFf/drmHTAblkdu8++lsISEBBdAuiyxgqIsE=
github.com/pion/srtp/v2 v2.0.2/go.mod h1:VEyLv4CuxrwGY8cxM+Ng3bmVy8ckz/1t6A0q/msKOw0= github.com/pion/srtp/v2 v2.0.2/go.mod h1:VEyLv4CuxrwGY8cxM+Ng3bmVy8ckz/1t6A0q/msKOw0=
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A= github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= github.com/pion/srtp/v2 v2.0.15 h1:+tqRtXGsGwHC0G0IUIAzRmdkHvriF79IHVfZGfHrQoA=
github.com/pion/srtp/v2 v2.0.15/go.mod h1:b/pQOlDrbB0HEH5EUAQXzSYxikFbNcNuKmF8tM0hCtw=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/stun v0.4.0/go.mod h1:QPsh1/SbXASntw3zkkrIk3ZJVKz4saBY2G7S10P3wCw=
github.com/pion/stun v0.6.0 h1:JHT/2iyGDPrFWE8NNC15wnddBN8KifsEDw8swQmrEmU=
github.com/pion/stun v0.6.0/go.mod h1:HPqcfoeqQn9cuaet7AOmB5e5xkObu9DwBdurwLKO9oA=
github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE= github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE=
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8= github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE= github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
@ -1754,21 +1770,28 @@ github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+D
github.com/pion/transport v0.12.1/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= github.com/pion/transport v0.12.1/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g= github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
github.com/pion/transport/v2 v2.1.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
github.com/pion/transport/v2 v2.2.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog= github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw= github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pion/turn/v2 v2.0.6 h1:AsXjSPR6Im15DMTB39NlfdTY9BQfieANPBjdg/aVNwY=
github.com/pion/turn/v2 v2.0.6/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= github.com/pion/turn/v2 v2.0.6/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/turn/v2 v2.1.0 h1:5wGHSgGhJhP/RpabkUb/T9PdsAjkGLS6toYz5HNzoSI=
github.com/pion/turn/v2 v2.1.0/go.mod h1:yrT5XbXSGX1VFSF31A3c1kCNB5bBZgk/uu5LET162qs=
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths= github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v2 v2.2.26/go.mod h1:XMZbZRNHyPDe1gzTIHFcQu02283YO45CbiwFgKvXnmc= github.com/pion/webrtc/v2 v2.2.26/go.mod h1:XMZbZRNHyPDe1gzTIHFcQu02283YO45CbiwFgKvXnmc=
github.com/pion/webrtc/v3 v3.0.11/go.mod h1:WEvXneGTeqNmiR59v5jTsxMc4yXQyOQcRsrdAbNwSEU= github.com/pion/webrtc/v3 v3.0.11/go.mod h1:WEvXneGTeqNmiR59v5jTsxMc4yXQyOQcRsrdAbNwSEU=
github.com/pion/webrtc/v3 v3.0.27/go.mod h1:QpLDmsU5a/a05n230gRtxZRvfHhFzn9ukGUL2x4G5ic= github.com/pion/webrtc/v3 v3.0.27/go.mod h1:QpLDmsU5a/a05n230gRtxZRvfHhFzn9ukGUL2x4G5ic=
github.com/pion/webrtc/v3 v3.0.32/go.mod h1:wX3V5dQQUGCifhT1mYftC2kCrDQX6ZJ3B7Yad0R9JK0= github.com/pion/webrtc/v3 v3.0.32/go.mod h1:wX3V5dQQUGCifhT1mYftC2kCrDQX6ZJ3B7Yad0R9JK0=
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 h1:+IEql+S+YAj3S5e7Ftl/u4xPcZGG0WwLFsyFj6NRTz4=
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38/go.mod h1:L5S/oAhL0Fzt/rnftVQRrP80/j5jygY7XRZzWwFx6P4= github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38/go.mod h1:L5S/oAhL0Fzt/rnftVQRrP80/j5jygY7XRZzWwFx6P4=
github.com/pion/webrtc/v3 v3.2.9 h1:U8NSjQDlZZ+Iy/hg42Q/u6mhEVSXYvKrOIZiZwYTfLc=
github.com/pion/webrtc/v3 v3.2.9/go.mod h1:gjQLMZeyN3jXBGdxGmUYCyKjOuYX/c99BDjGqmadq0A=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@ -1847,14 +1870,12 @@ github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38i
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= github.com/quic-go/quic-go v0.39.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s=
github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
github.com/quic-go/quic-go v0.36.4 h1:CXn/ZLN5Vntlk53fjR+kUMC8Jt7flfQe+I5Ty5A+k0o= github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
github.com/quic-go/quic-go v0.36.4/go.mod h1:qxQumdeKw5GmWs1OsTZZnOxzSI+RJWuhf1O8FN35L2o= github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU=
github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -2007,8 +2028,8 @@ github.com/status-im/mvds v0.0.27-0.20240111144448-92d364e4be82 h1:A7jtwOlDMUGUP
github.com/status-im/mvds v0.0.27-0.20240111144448-92d364e4be82/go.mod h1:2fiAx0q9XYIPKYRq2B1oiO9zZESy/n4D32gWw6lMDsE= github.com/status-im/mvds v0.0.27-0.20240111144448-92d364e4be82/go.mod h1:2fiAx0q9XYIPKYRq2B1oiO9zZESy/n4D32gWw6lMDsE=
github.com/status-im/notify v1.0.2-status h1:x8wev0Sh8H8KAf4bVcv+L0dVHldBESOKUlqRqRY7uL8= github.com/status-im/notify v1.0.2-status h1:x8wev0Sh8H8KAf4bVcv+L0dVHldBESOKUlqRqRY7uL8=
github.com/status-im/notify v1.0.2-status/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/status-im/notify v1.0.2-status/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc=
github.com/status-im/rendezvous v1.3.7 h1:rZGWsFCjPV3MWeUkLkZSOGTAvyRf+rxx5hnEGLE4OHg= github.com/status-im/rendezvous v1.3.8-0.20240110194857-cc5be22bf83e h1:pCOHeAYmYttXQBCn+6u01bs5d/W3XslxmplFhru4X1Y=
github.com/status-im/rendezvous v1.3.7/go.mod h1:r0vCbQJByTteMajN0f+Mcet/Vd7uAXxFPfewNpI2iXQ= github.com/status-im/rendezvous v1.3.8-0.20240110194857-cc5be22bf83e/go.mod h1:LEPENTHDBGCxXVZx6FEKNKN+tfPaIK+lmiGv1DxkJW4=
github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088 h1:ClCAP2FPCvl8hGMhbUx/tq/sOu2wibztAa5jAvQEe4Q= github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088 h1:ClCAP2FPCvl8hGMhbUx/tq/sOu2wibztAa5jAvQEe4Q=
github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088/go.mod h1:+92j1tN27DypDeBFxkg0uzkqfh1bNHTZe3Bv2PjvxpM= github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088/go.mod h1:+92j1tN27DypDeBFxkg0uzkqfh1bNHTZe3Bv2PjvxpM=
github.com/status-im/status-go/extkeys v1.1.2 h1:FSjARgDathJ3rIapJt851LsIXP9Oyuu2M2jPJKuzloU= github.com/status-im/status-go/extkeys v1.1.2 h1:FSjARgDathJ3rIapJt851LsIXP9Oyuu2M2jPJKuzloU=
@ -2028,8 +2049,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -2043,8 +2065,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402eqvEIasMQOE8nFOxy7M= github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402eqvEIasMQOE8nFOxy7M=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -2084,8 +2110,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@ -2099,12 +2125,12 @@ github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmF
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3 h1:Kk0KYXZE/uNnARF2TbCQyvyZ/w4SgF8VhquNdOVVsNU= github.com/waku-org/go-discover v0.0.0-20240506173252-4912704efdc5 h1:4K3IS97JryAEV8pRXB//qPcg+8bPXl/O+AOLt3FeCKc=
github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw= github.com/waku-org/go-discover v0.0.0-20240506173252-4912704efdc5/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 h1:0e1h+p84yBp0IN7AqgbZlV7lgFBjm214lgSOE7CeJmE= github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0 h1:R4YYx2QamhBRl/moIxkDCNW+OP7AHbyWLBygDc/xIMo=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7/go.mod h1:pFvOZ9YTFsW0o5zJW7a0B5tr1owAijRWJctXJ2toL04= github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0/go.mod h1:EhZP9fee0DYjKH/IOQvoNSy1tSHp2iZadsHGphcAJgY=
github.com/waku-org/go-waku v0.8.1-0.20240415131212-6d889ca3e2fe h1:rJF7qKODzvWx03iaLbYyjvA62crnCaDqIN661aqCQ8c= github.com/waku-org/go-waku v0.8.1-0.20240507175626-19d27befd98b h1:2NR0UCjuuAFmnkhsvlCKn7PTs4JxUjSq4s7lSWaG0ek=
github.com/waku-org/go-waku v0.8.1-0.20240415131212-6d889ca3e2fe/go.mod h1:RjTvkTrIwpoT1cM9HeQqwa2Q7t7WOkb3hpuB/zuZ6SM= github.com/waku-org/go-waku v0.8.1-0.20240507175626-19d27befd98b/go.mod h1:yXnWChXRKTb+NhALbFysluxgSwuxeTF2rhanDJkIx+k=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA= github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E= github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE= github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE=
@ -2146,8 +2172,8 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8= github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8=
github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24= github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0= github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
@ -2226,14 +2252,16 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk=
go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@ -2246,8 +2274,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -2295,8 +2323,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -2311,8 +2341,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 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-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -2350,8 +2380,9 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -2441,9 +2472,15 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -2479,8 +2516,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -2636,9 +2674,14 @@ golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -2646,9 +2689,15 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -2658,9 +2707,14 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -2760,8 +2814,9 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60 h1:o4bs4seAAlSiZQAZbO6/RP5XBCZCooQS3Pgc0AUjWts= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.12.1-0.20230818130535-1517d1a3ba60/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -2769,8 +2824,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=

View File

@ -11,7 +11,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/waku-org/go-waku/waku/v2/protocol/store" "github.com/waku-org/go-waku/waku/v2/protocol/legacy_store"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -380,10 +380,10 @@ func (s *MessengerStoreNodeRequestSuite) ensureStoreNodeEnvelopes(contentTopic *
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Directly ensure profile is available on store node // Directly ensure profile is available on store node
queryOptions := []store.HistoryRequestOption{ queryOptions := []legacy_store.HistoryRequestOption{
store.WithLocalQuery(), legacy_store.WithLocalQuery(),
} }
query := store.Query{ query := legacy_store.Query{
PubsubTopic: "", PubsubTopic: "",
ContentTopics: []string{contentTopic.ContentTopic()}, ContentTopics: []string{contentTopic.ContentTopic()},
} }

View File

@ -37,7 +37,7 @@ func (m Mailserver) IDBytes() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return []byte(id.Pretty()), err return []byte(id.String()), err
} }
node, err := enode.ParseV4(m.Address) node, err := enode.ParseV4(m.Address)

View File

@ -62,7 +62,7 @@ func (c *Client) PushReceivedMessages(filter transport.Filter, sshMessage *types
func (c *Client) PushReceivedEnvelope(envelope *v2protocol.Envelope) { func (c *Client) PushReceivedEnvelope(envelope *v2protocol.Envelope) {
url := fmt.Sprintf("%s/received-envelope", c.serverURL) url := fmt.Sprintf("%s/received-envelope", c.serverURL)
postBody := map[string]interface{}{ postBody := map[string]interface{}{
"messageHash": types.EncodeHex(envelope.Hash()), "messageHash": envelope.Hash().String(),
"sentAt": uint32(envelope.Message().GetTimestamp() / int64(time.Second)), "sentAt": uint32(envelope.Message().GetTimestamp() / int64(time.Second)),
"pubsubTopic": envelope.PubsubTopic(), "pubsubTopic": envelope.PubsubTopic(),
"topic": envelope.Message().ContentTopic, "topic": envelope.Message().ContentTopic,

View File

@ -91,7 +91,7 @@ const (
// UnmarshalText method. See the Unmarshaler example for a demonstration with // UnmarshalText method. See the Unmarshaler example for a demonstration with
// email addresses. // email addresses.
// //
// ### Key mapping // # Key mapping
// //
// TOML keys can map to either keys in a Go map or field names in a Go struct. // TOML keys can map to either keys in a Go map or field names in a Go struct.
// The special `toml` struct tag can be used to map TOML keys to struct fields // The special `toml` struct tag can be used to map TOML keys to struct fields
@ -248,7 +248,7 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
case reflect.Bool: case reflect.Bool:
return md.unifyBool(data, rv) return md.unifyBool(data, rv)
case reflect.Interface: case reflect.Interface:
if rv.NumMethod() > 0 { // Only support empty interfaces are supported. if rv.NumMethod() > 0 { /// Only empty interfaces are supported.
return md.e("unsupported type %s", rv.Type()) return md.e("unsupported type %s", rv.Type())
} }
return md.unifyAnything(data, rv) return md.unifyAnything(data, rv)

View File

@ -5,17 +5,25 @@ import (
"io" "io"
) )
// TextMarshaler is an alias for encoding.TextMarshaler.
//
// Deprecated: use encoding.TextMarshaler // Deprecated: use encoding.TextMarshaler
type TextMarshaler encoding.TextMarshaler type TextMarshaler encoding.TextMarshaler
// TextUnmarshaler is an alias for encoding.TextUnmarshaler.
//
// Deprecated: use encoding.TextUnmarshaler // Deprecated: use encoding.TextUnmarshaler
type TextUnmarshaler encoding.TextUnmarshaler type TextUnmarshaler encoding.TextUnmarshaler
// PrimitiveDecode is an alias for MetaData.PrimitiveDecode().
//
// Deprecated: use MetaData.PrimitiveDecode. // Deprecated: use MetaData.PrimitiveDecode.
func PrimitiveDecode(primValue Primitive, v interface{}) error { func PrimitiveDecode(primValue Primitive, v interface{}) error {
md := MetaData{decoded: make(map[string]struct{})} md := MetaData{decoded: make(map[string]struct{})}
return md.unify(primValue.undecoded, rvalue(v)) return md.unify(primValue.undecoded, rvalue(v))
} }
// DecodeReader is an alias for NewDecoder(r).Decode(v).
//
// Deprecated: use NewDecoder(reader).Decode(&value). // Deprecated: use NewDecoder(reader).Decode(&value).
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) } func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) }

View File

@ -136,7 +136,8 @@ func NewEncoder(w io.Writer) *Encoder {
// document. // document.
func (enc *Encoder) Encode(v interface{}) error { func (enc *Encoder) Encode(v interface{}) error {
rv := eindirect(reflect.ValueOf(v)) rv := eindirect(reflect.ValueOf(v))
if err := enc.safeEncode(Key([]string{}), rv); err != nil { err := enc.safeEncode(Key([]string{}), rv)
if err != nil {
return err return err
} }
return enc.w.Flush() return enc.w.Flush()
@ -457,6 +458,16 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
frv := eindirect(rv.Field(i)) frv := eindirect(rv.Field(i))
if is32Bit {
// Copy so it works correct on 32bit archs; not clear why this
// is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
// This also works fine on 64bit, but 32bit archs are somewhat
// rare and this is a wee bit faster.
copyStart := make([]int, len(start))
copy(copyStart, start)
start = copyStart
}
// Treat anonymous struct fields with tag names as though they are // Treat anonymous struct fields with tag names as though they are
// not anonymous, like encoding/json does. // not anonymous, like encoding/json does.
// //
@ -471,17 +482,7 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
if typeIsTable(tomlTypeOfGo(frv)) { if typeIsTable(tomlTypeOfGo(frv)) {
fieldsSub = append(fieldsSub, append(start, f.Index...)) fieldsSub = append(fieldsSub, append(start, f.Index...))
} else { } else {
// Copy so it works correct on 32bit archs; not clear why this fieldsDirect = append(fieldsDirect, append(start, f.Index...))
// is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
// This also works fine on 64bit, but 32bit archs are somewhat
// rare and this is a wee bit faster.
if is32Bit {
copyStart := make([]int, len(start))
copy(copyStart, start)
fieldsDirect = append(fieldsDirect, append(copyStart, f.Index...))
} else {
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
}
} }
} }
} }
@ -490,24 +491,27 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
writeFields := func(fields [][]int) { writeFields := func(fields [][]int) {
for _, fieldIndex := range fields { for _, fieldIndex := range fields {
fieldType := rt.FieldByIndex(fieldIndex) fieldType := rt.FieldByIndex(fieldIndex)
fieldVal := eindirect(rv.FieldByIndex(fieldIndex)) fieldVal := rv.FieldByIndex(fieldIndex)
if isNil(fieldVal) { /// Don't write anything for nil fields.
continue
}
opts := getOptions(fieldType.Tag) opts := getOptions(fieldType.Tag)
if opts.skip { if opts.skip {
continue continue
} }
if opts.omitempty && isEmpty(fieldVal) {
continue
}
fieldVal = eindirect(fieldVal)
if isNil(fieldVal) { /// Don't write anything for nil fields.
continue
}
keyName := fieldType.Name keyName := fieldType.Name
if opts.name != "" { if opts.name != "" {
keyName = opts.name keyName = opts.name
} }
if opts.omitempty && enc.isEmpty(fieldVal) {
continue
}
if opts.omitzero && isZero(fieldVal) { if opts.omitzero && isZero(fieldVal) {
continue continue
} }
@ -649,7 +653,7 @@ func isZero(rv reflect.Value) bool {
return false return false
} }
func (enc *Encoder) isEmpty(rv reflect.Value) bool { func isEmpty(rv reflect.Value) bool {
switch rv.Kind() { switch rv.Kind() {
case reflect.Array, reflect.Slice, reflect.Map, reflect.String: case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
return rv.Len() == 0 return rv.Len() == 0
@ -664,13 +668,15 @@ func (enc *Encoder) isEmpty(rv reflect.Value) bool {
// type b struct{ s []string } // type b struct{ s []string }
// s := a{field: b{s: []string{"AAA"}}} // s := a{field: b{s: []string{"AAA"}}}
for i := 0; i < rv.NumField(); i++ { for i := 0; i < rv.NumField(); i++ {
if !enc.isEmpty(rv.Field(i)) { if !isEmpty(rv.Field(i)) {
return false return false
} }
} }
return true return true
case reflect.Bool: case reflect.Bool:
return !rv.Bool() return !rv.Bool()
case reflect.Ptr:
return rv.IsNil()
} }
return false return false
} }
@ -693,8 +699,11 @@ func (enc *Encoder) newline() {
// v v v v vv // v v v v vv
// key = {k = 1, k2 = 2} // key = {k = 1, k2 = 2}
func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
/// Marshaler used on top-level document; call eElement() to just call
/// Marshal{TOML,Text}.
if len(key) == 0 { if len(key) == 0 {
encPanic(errNoKey) enc.eElement(val)
return
} }
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
enc.eElement(val) enc.eElement(val)

View File

@ -84,7 +84,7 @@ func (pe ParseError) Error() string {
pe.Position.Line, pe.LastKey, msg) pe.Position.Line, pe.LastKey, msg)
} }
// ErrorWithUsage() returns the error with detailed location context. // ErrorWithPosition returns the error with detailed location context.
// //
// See the documentation on [ParseError]. // See the documentation on [ParseError].
func (pe ParseError) ErrorWithPosition() string { func (pe ParseError) ErrorWithPosition() string {
@ -124,7 +124,7 @@ func (pe ParseError) ErrorWithPosition() string {
return b.String() return b.String()
} }
// ErrorWithUsage() returns the error with detailed location context and usage // ErrorWithUsage returns the error with detailed location context and usage
// guidance. // guidance.
// //
// See the documentation on [ParseError]. // See the documentation on [ParseError].

View File

@ -46,12 +46,13 @@ func (p Position) String() string {
} }
type lexer struct { type lexer struct {
input string input string
start int start int
pos int pos int
line int line int
state stateFn state stateFn
items chan item items chan item
tomlNext bool
// Allow for backing up up to 4 runes. This is necessary because TOML // Allow for backing up up to 4 runes. This is necessary because TOML
// contains 3-rune tokens (""" and '''). // contains 3-rune tokens (""" and ''').
@ -87,13 +88,14 @@ func (lx *lexer) nextItem() item {
} }
} }
func lex(input string) *lexer { func lex(input string, tomlNext bool) *lexer {
lx := &lexer{ lx := &lexer{
input: input, input: input,
state: lexTop, state: lexTop,
items: make(chan item, 10), items: make(chan item, 10),
stack: make([]stateFn, 0, 10), stack: make([]stateFn, 0, 10),
line: 1, line: 1,
tomlNext: tomlNext,
} }
return lx return lx
} }
@ -408,7 +410,7 @@ func lexTableNameEnd(lx *lexer) stateFn {
// Lexes only one part, e.g. only 'a' inside 'a.b'. // Lexes only one part, e.g. only 'a' inside 'a.b'.
func lexBareName(lx *lexer) stateFn { func lexBareName(lx *lexer) stateFn {
r := lx.next() r := lx.next()
if isBareKeyChar(r) { if isBareKeyChar(r, lx.tomlNext) {
return lexBareName return lexBareName
} }
lx.backup() lx.backup()
@ -618,6 +620,9 @@ func lexInlineTableValue(lx *lexer) stateFn {
case isWhitespace(r): case isWhitespace(r):
return lexSkip(lx, lexInlineTableValue) return lexSkip(lx, lexInlineTableValue)
case isNL(r): case isNL(r):
if lx.tomlNext {
return lexSkip(lx, lexInlineTableValue)
}
return lx.errorPrevLine(errLexInlineTableNL{}) return lx.errorPrevLine(errLexInlineTableNL{})
case r == '#': case r == '#':
lx.push(lexInlineTableValue) lx.push(lexInlineTableValue)
@ -640,6 +645,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
case isWhitespace(r): case isWhitespace(r):
return lexSkip(lx, lexInlineTableValueEnd) return lexSkip(lx, lexInlineTableValueEnd)
case isNL(r): case isNL(r):
if lx.tomlNext {
return lexSkip(lx, lexInlineTableValueEnd)
}
return lx.errorPrevLine(errLexInlineTableNL{}) return lx.errorPrevLine(errLexInlineTableNL{})
case r == '#': case r == '#':
lx.push(lexInlineTableValueEnd) lx.push(lexInlineTableValueEnd)
@ -648,6 +656,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
lx.ignore() lx.ignore()
lx.skip(isWhitespace) lx.skip(isWhitespace)
if lx.peek() == '}' { if lx.peek() == '}' {
if lx.tomlNext {
return lexInlineTableValueEnd
}
return lx.errorf("trailing comma not allowed in inline tables") return lx.errorf("trailing comma not allowed in inline tables")
} }
return lexInlineTableValue return lexInlineTableValue
@ -770,8 +781,8 @@ func lexRawString(lx *lexer) stateFn {
} }
} }
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such // lexMultilineRawString consumes a raw string. Nothing can be escaped in such a
// a string. It assumes that the beginning ''' has already been consumed and // string. It assumes that the beginning triple-' has already been consumed and
// ignored. // ignored.
func lexMultilineRawString(lx *lexer) stateFn { func lexMultilineRawString(lx *lexer) stateFn {
r := lx.next() r := lx.next()
@ -828,6 +839,11 @@ func lexMultilineStringEscape(lx *lexer) stateFn {
func lexStringEscape(lx *lexer) stateFn { func lexStringEscape(lx *lexer) stateFn {
r := lx.next() r := lx.next()
switch r { switch r {
case 'e':
if !lx.tomlNext {
return lx.error(errLexEscape{r})
}
fallthrough
case 'b': case 'b':
fallthrough fallthrough
case 't': case 't':
@ -846,6 +862,11 @@ func lexStringEscape(lx *lexer) stateFn {
fallthrough fallthrough
case '\\': case '\\':
return lx.pop() return lx.pop()
case 'x':
if !lx.tomlNext {
return lx.error(errLexEscape{r})
}
return lexHexEscape
case 'u': case 'u':
return lexShortUnicodeEscape return lexShortUnicodeEscape
case 'U': case 'U':
@ -854,6 +875,19 @@ func lexStringEscape(lx *lexer) stateFn {
return lx.error(errLexEscape{r}) return lx.error(errLexEscape{r})
} }
func lexHexEscape(lx *lexer) stateFn {
var r rune
for i := 0; i < 2; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf(
`expected two hexadecimal digits after '\x', but got %q instead`,
lx.current())
}
}
return lx.pop()
}
func lexShortUnicodeEscape(lx *lexer) stateFn { func lexShortUnicodeEscape(lx *lexer) stateFn {
var r rune var r rune
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
@ -1225,7 +1259,23 @@ func isOctal(r rune) bool { return r >= '0' && r <= '7' }
func isHexadecimal(r rune) bool { func isHexadecimal(r rune) bool {
return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')
} }
func isBareKeyChar(r rune) bool {
func isBareKeyChar(r rune, tomlNext bool) bool {
if tomlNext {
return (r >= 'A' && r <= 'Z') ||
(r >= 'a' && r <= 'z') ||
(r >= '0' && r <= '9') ||
r == '_' || r == '-' ||
r == 0xb2 || r == 0xb3 || r == 0xb9 || (r >= 0xbc && r <= 0xbe) ||
(r >= 0xc0 && r <= 0xd6) || (r >= 0xd8 && r <= 0xf6) || (r >= 0xf8 && r <= 0x037d) ||
(r >= 0x037f && r <= 0x1fff) ||
(r >= 0x200c && r <= 0x200d) || (r >= 0x203f && r <= 0x2040) ||
(r >= 0x2070 && r <= 0x218f) || (r >= 0x2460 && r <= 0x24ff) ||
(r >= 0x2c00 && r <= 0x2fef) || (r >= 0x3001 && r <= 0xd7ff) ||
(r >= 0xf900 && r <= 0xfdcf) || (r >= 0xfdf0 && r <= 0xfffd) ||
(r >= 0x10000 && r <= 0xeffff)
}
return (r >= 'A' && r <= 'Z') || return (r >= 'A' && r <= 'Z') ||
(r >= 'a' && r <= 'z') || (r >= 'a' && r <= 'z') ||
(r >= '0' && r <= '9') || (r >= '0' && r <= '9') ||

View File

@ -106,7 +106,7 @@ func (k Key) maybeQuoted(i int) string {
return `""` return `""`
} }
for _, c := range k[i] { for _, c := range k[i] {
if !isBareKeyChar(c) { if !isBareKeyChar(c, false) {
return `"` + dblQuotedReplacer.Replace(k[i]) + `"` return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
} }
} }

View File

@ -2,6 +2,7 @@ package toml
import ( import (
"fmt" "fmt"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -15,6 +16,7 @@ type parser struct {
context Key // Full key for the current hash in scope. context Key // Full key for the current hash in scope.
currentKey string // Base key name for everything except hashes. currentKey string // Base key name for everything except hashes.
pos Position // Current position in the TOML file. pos Position // Current position in the TOML file.
tomlNext bool
ordered []Key // List of keys in the order that they appear in the TOML data. ordered []Key // List of keys in the order that they appear in the TOML data.
@ -29,6 +31,8 @@ type keyInfo struct {
} }
func parse(data string) (p *parser, err error) { func parse(data string) (p *parser, err error) {
_, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110")
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
if pErr, ok := r.(ParseError); ok { if pErr, ok := r.(ParseError); ok {
@ -41,9 +45,12 @@ func parse(data string) (p *parser, err error) {
}() }()
// Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString() // Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
// which mangles stuff. // which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add
if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // it anyway.
if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16
data = data[2:] data = data[2:]
} else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8
data = data[3:]
} }
// Examine first few bytes for NULL bytes; this probably means it's a UTF-16 // Examine first few bytes for NULL bytes; this probably means it's a UTF-16
@ -65,9 +72,10 @@ func parse(data string) (p *parser, err error) {
p = &parser{ p = &parser{
keyInfo: make(map[string]keyInfo), keyInfo: make(map[string]keyInfo),
mapping: make(map[string]interface{}), mapping: make(map[string]interface{}),
lx: lex(data), lx: lex(data, tomlNext),
ordered: make([]Key, 0), ordered: make([]Key, 0),
implicits: make(map[string]struct{}), implicits: make(map[string]struct{}),
tomlNext: tomlNext,
} }
for { for {
item := p.next() item := p.next()
@ -194,12 +202,12 @@ func (p *parser) topLevel(item item) {
for i := range context { for i := range context {
p.addImplicitContext(append(p.context, context[i:i+1]...)) p.addImplicitContext(append(p.context, context[i:i+1]...))
} }
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Set value. /// Set value.
vItem := p.next() vItem := p.next()
val, typ := p.value(vItem, false) val, typ := p.value(vItem, false)
p.set(p.currentKey, val, typ, vItem.pos) p.set(p.currentKey, val, typ, vItem.pos)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Remove the context we added (preserving any context from [tbl] lines). /// Remove the context we added (preserving any context from [tbl] lines).
p.context = outerContext p.context = outerContext
@ -236,7 +244,7 @@ func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) {
case itemString: case itemString:
return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it) return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
case itemMultilineString: case itemMultilineString:
return p.replaceEscapes(it, stripFirstNewline(p.stripEscapedNewlines(it.val))), p.typeOfPrimitive(it) return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it)
case itemRawString: case itemRawString:
return it.val, p.typeOfPrimitive(it) return it.val, p.typeOfPrimitive(it)
case itemRawMultilineString: case itemRawMultilineString:
@ -331,11 +339,17 @@ func (p *parser) valueFloat(it item) (interface{}, tomlType) {
var dtTypes = []struct { var dtTypes = []struct {
fmt string fmt string
zone *time.Location zone *time.Location
next bool
}{ }{
{time.RFC3339Nano, time.Local}, {time.RFC3339Nano, time.Local, false},
{"2006-01-02T15:04:05.999999999", internal.LocalDatetime}, {"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false},
{"2006-01-02", internal.LocalDate}, {"2006-01-02", internal.LocalDate, false},
{"15:04:05.999999999", internal.LocalTime}, {"15:04:05.999999999", internal.LocalTime, false},
// tomlNext
{"2006-01-02T15:04Z07:00", time.Local, true},
{"2006-01-02T15:04", internal.LocalDatetime, true},
{"15:04", internal.LocalTime, true},
} }
func (p *parser) valueDatetime(it item) (interface{}, tomlType) { func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
@ -346,6 +360,9 @@ func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
err error err error
) )
for _, dt := range dtTypes { for _, dt := range dtTypes {
if dt.next && !p.tomlNext {
continue
}
t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone) t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
if err == nil { if err == nil {
ok = true ok = true
@ -384,6 +401,7 @@ func (p *parser) valueArray(it item) (interface{}, tomlType) {
// //
// Not entirely sure how to best store this; could use "key[0]", // Not entirely sure how to best store this; could use "key[0]",
// "key[1]" notation, or maybe store it on the Array type? // "key[1]" notation, or maybe store it on the Array type?
_ = types
} }
return array, tomlArray return array, tomlArray
} }
@ -426,11 +444,11 @@ func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tom
for i := range context { for i := range context {
p.addImplicitContext(append(p.context, context[i:i+1]...)) p.addImplicitContext(append(p.context, context[i:i+1]...))
} }
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Set the value. /// Set the value.
val, typ := p.value(p.next(), false) val, typ := p.value(p.next(), false)
p.set(p.currentKey, val, typ, it.pos) p.set(p.currentKey, val, typ, it.pos)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
hash[p.currentKey] = val hash[p.currentKey] = val
/// Restore context. /// Restore context.
@ -551,7 +569,6 @@ func (p *parser) addContext(key Key, array bool) {
func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) { func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) {
p.setValue(key, val) p.setValue(key, val)
p.setType(key, typ, pos) p.setType(key, typ, pos)
} }
// setValue sets the given key to the given value in the current context. // setValue sets the given key to the given value in the current context.
@ -632,14 +649,11 @@ func (p *parser) setType(key string, typ tomlType, pos Position) {
// Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and // Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and
// "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly). // "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly).
func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} } func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} }
func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) } func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) }
func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok } func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok }
func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray } func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray }
func (p *parser) addImplicitContext(key Key) { func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) }
p.addImplicit(key)
p.addContext(key, false)
}
// current returns the full key name of the current context. // current returns the full key name of the current context.
func (p *parser) current() string { func (p *parser) current() string {
@ -662,49 +676,54 @@ func stripFirstNewline(s string) string {
return s return s
} }
// Remove newlines inside triple-quoted strings if a line ends with "\". // stripEscapedNewlines removes whitespace after line-ending backslashes in
// multiline strings.
//
// A line-ending backslash is an unescaped \ followed only by whitespace until
// the next newline. After a line-ending backslash, all whitespace is removed
// until the next non-whitespace character.
func (p *parser) stripEscapedNewlines(s string) string { func (p *parser) stripEscapedNewlines(s string) string {
split := strings.Split(s, "\n") var b strings.Builder
if len(split) < 1 { var i int
return s for {
} ix := strings.Index(s[i:], `\`)
if ix < 0 {
b.WriteString(s)
return b.String()
}
i += ix
escNL := false // Keep track of the last non-blank line was escaped. if len(s) > i+1 && s[i+1] == '\\' {
for i, line := range split { // Escaped backslash.
line = strings.TrimRight(line, " \t\r") i += 2
continue
if len(line) == 0 || line[len(line)-1] != '\\' { }
split[i] = strings.TrimRight(split[i], "\r") // Scan until the next non-whitespace.
if !escNL && i != len(split)-1 { j := i + 1
split[i] += "\n" whitespaceLoop:
for ; j < len(s); j++ {
switch s[j] {
case ' ', '\t', '\r', '\n':
default:
break whitespaceLoop
} }
}
if j == i+1 {
// Not a whitespace escape.
i++
continue continue
} }
if !strings.Contains(s[i:j], "\n") {
escBS := true // This is not a line-ending backslash.
for j := len(line) - 1; j >= 0 && line[j] == '\\'; j-- { // (It's a bad escape sequence, but we can let
escBS = !escBS // replaceEscapes catch it.)
} i++
if escNL {
line = strings.TrimLeft(line, " \t\r")
}
escNL = !escBS
if escBS {
split[i] += "\n"
continue continue
} }
b.WriteString(s[:i])
if i == len(split)-1 { s = s[j:]
p.panicf("invalid escape: '\\ '") i = 0
}
split[i] = line[:len(line)-1] // Remove \
if len(split)-1 > i {
split[i+1] = strings.TrimLeft(split[i+1], " \t\r")
}
} }
return strings.Join(split, "")
} }
func (p *parser) replaceEscapes(it item, str string) string { func (p *parser) replaceEscapes(it item, str string) string {
@ -743,12 +762,23 @@ func (p *parser) replaceEscapes(it item, str string) string {
case 'r': case 'r':
replaced = append(replaced, rune(0x000D)) replaced = append(replaced, rune(0x000D))
r += 1 r += 1
case 'e':
if p.tomlNext {
replaced = append(replaced, rune(0x001B))
r += 1
}
case '"': case '"':
replaced = append(replaced, rune(0x0022)) replaced = append(replaced, rune(0x0022))
r += 1 r += 1
case '\\': case '\\':
replaced = append(replaced, rune(0x005C)) replaced = append(replaced, rune(0x005C))
r += 1 r += 1
case 'x':
if p.tomlNext {
escaped := p.asciiEscapeToUnicode(it, s[r+1:r+3])
replaced = append(replaced, escaped)
r += 3
}
case 'u': case 'u':
// At this point, we know we have a Unicode escape of the form // At this point, we know we have a Unicode escape of the form
// `uXXXX` at [r, r+5). (Because the lexer guarantees this // `uXXXX` at [r, r+5). (Because the lexer guarantees this

View File

@ -9,6 +9,8 @@ func Render(doc []byte) []byte {
renderer := NewRoffRenderer() renderer := NewRoffRenderer()
return blackfriday.Run(doc, return blackfriday.Run(doc,
[]blackfriday.Option{blackfriday.WithRenderer(renderer), []blackfriday.Option{
blackfriday.WithExtensions(renderer.GetExtensions())}...) blackfriday.WithRenderer(renderer),
blackfriday.WithExtensions(renderer.GetExtensions()),
}...)
} }

View File

@ -1,6 +1,8 @@
package md2man package md2man
import ( import (
"bufio"
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -20,34 +22,35 @@ type roffRenderer struct {
} }
const ( const (
titleHeader = ".TH " titleHeader = ".TH "
topLevelHeader = "\n\n.SH " topLevelHeader = "\n\n.SH "
secondLevelHdr = "\n.SH " secondLevelHdr = "\n.SH "
otherHeader = "\n.SS " otherHeader = "\n.SS "
crTag = "\n" crTag = "\n"
emphTag = "\\fI" emphTag = "\\fI"
emphCloseTag = "\\fP" emphCloseTag = "\\fP"
strongTag = "\\fB" strongTag = "\\fB"
strongCloseTag = "\\fP" strongCloseTag = "\\fP"
breakTag = "\n.br\n" breakTag = "\n.br\n"
paraTag = "\n.PP\n" paraTag = "\n.PP\n"
hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n" hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n"
linkTag = "\n\\[la]" linkTag = "\n\\[la]"
linkCloseTag = "\\[ra]" linkCloseTag = "\\[ra]"
codespanTag = "\\fB\\fC" codespanTag = "\\fB"
codespanCloseTag = "\\fR" codespanCloseTag = "\\fR"
codeTag = "\n.PP\n.RS\n\n.nf\n" codeTag = "\n.EX\n"
codeCloseTag = "\n.fi\n.RE\n" codeCloseTag = ".EE\n" // Do not prepend a newline character since code blocks, by definition, include a newline already (or at least as how blackfriday gives us on).
quoteTag = "\n.PP\n.RS\n" quoteTag = "\n.PP\n.RS\n"
quoteCloseTag = "\n.RE\n" quoteCloseTag = "\n.RE\n"
listTag = "\n.RS\n" listTag = "\n.RS\n"
listCloseTag = "\n.RE\n" listCloseTag = "\n.RE\n"
dtTag = "\n.TP\n" dtTag = "\n.TP\n"
dd2Tag = "\n" dd2Tag = "\n"
tableStart = "\n.TS\nallbox;\n" tableStart = "\n.TS\nallbox;\n"
tableEnd = ".TE\n" tableEnd = ".TE\n"
tableCellStart = "T{\n" tableCellStart = "T{\n"
tableCellEnd = "\nT}\n" tableCellEnd = "\nT}\n"
tablePreprocessor = `'\" t`
) )
// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents // NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
@ -74,6 +77,16 @@ func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
// RenderHeader handles outputting the header at document start // RenderHeader handles outputting the header at document start
func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) { func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) {
// We need to walk the tree to check if there are any tables.
// If there are, we need to enable the roff table preprocessor.
ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
if node.Type == blackfriday.Table {
out(w, tablePreprocessor+"\n")
return blackfriday.Terminate
}
return blackfriday.GoToNext
})
// disable hyphenation // disable hyphenation
out(w, ".nh\n") out(w, ".nh\n")
} }
@ -86,8 +99,7 @@ func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) {
// RenderNode is called for each node in a markdown document; based on the node // RenderNode is called for each node in a markdown document; based on the node
// type the equivalent roff output is sent to the writer // type the equivalent roff output is sent to the writer
func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
walkAction := blackfriday.GoToNext
var walkAction = blackfriday.GoToNext
switch node.Type { switch node.Type {
case blackfriday.Text: case blackfriday.Text:
@ -109,9 +121,16 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
out(w, strongCloseTag) out(w, strongCloseTag)
} }
case blackfriday.Link: case blackfriday.Link:
if !entering { // Don't render the link text for automatic links, because this
out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag) // will only duplicate the URL in the roff output.
// See https://daringfireball.net/projects/markdown/syntax#autolink
if !bytes.Equal(node.LinkData.Destination, node.FirstChild.Literal) {
out(w, string(node.FirstChild.Literal))
} }
// Hyphens in a link must be escaped to avoid word-wrap in the rendered man page.
escapedLink := strings.ReplaceAll(string(node.LinkData.Destination), "-", "\\-")
out(w, linkTag+escapedLink+linkCloseTag)
walkAction = blackfriday.SkipChildren
case blackfriday.Image: case blackfriday.Image:
// ignore images // ignore images
walkAction = blackfriday.SkipChildren walkAction = blackfriday.SkipChildren
@ -160,6 +179,11 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
r.handleTableCell(w, node, entering) r.handleTableCell(w, node, entering)
case blackfriday.HTMLSpan: case blackfriday.HTMLSpan:
// ignore other HTML tags // ignore other HTML tags
case blackfriday.HTMLBlock:
if bytes.HasPrefix(node.Literal, []byte("<!--")) {
break // ignore comments, no warning
}
fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
default: default:
fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String()) fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
} }
@ -254,7 +278,7 @@ func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, ente
start = "\t" start = "\t"
} }
if node.IsHeader { if node.IsHeader {
start += codespanTag start += strongTag
} else if nodeLiteralSize(node) > 30 { } else if nodeLiteralSize(node) > 30 {
start += tableCellStart start += tableCellStart
} }
@ -262,7 +286,7 @@ func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, ente
} else { } else {
var end string var end string
if node.IsHeader { if node.IsHeader {
end = codespanCloseTag end = strongCloseTag
} else if nodeLiteralSize(node) > 30 { } else if nodeLiteralSize(node) > 30 {
end = tableCellEnd end = tableCellEnd
} }
@ -310,6 +334,28 @@ func out(w io.Writer, output string) {
} }
func escapeSpecialChars(w io.Writer, text []byte) { func escapeSpecialChars(w io.Writer, text []byte) {
scanner := bufio.NewScanner(bytes.NewReader(text))
// count the number of lines in the text
// we need to know this to avoid adding a newline after the last line
n := bytes.Count(text, []byte{'\n'})
idx := 0
for scanner.Scan() {
dt := scanner.Bytes()
if idx < n {
idx++
dt = append(dt, '\n')
}
escapeSpecialCharsLine(w, dt)
}
if err := scanner.Err(); err != nil {
panic(err)
}
}
func escapeSpecialCharsLine(w io.Writer, text []byte) {
for i := 0; i < len(text); i++ { for i := 0; i < len(text); i++ {
// escape initial apostrophe or period // escape initial apostrophe or period
if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {

View File

@ -1,26 +0,0 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.12
package main
import (
"log"
)
func printModuleVersion() {
log.Printf("No version information is available for Mockgen compiled with " +
"version 1.11")
}

View File

@ -2,12 +2,13 @@
# SPDX-License-Identifier: MPL-2.0 # SPDX-License-Identifier: MPL-2.0
linters: linters:
fast: false
disable-all: true
enable: enable:
- megacheck
- revive - revive
- megacheck
- govet - govet
- unconvert - unconvert
- megacheck
- gas - gas
- gocyclo - gocyclo
- dupl - dupl
@ -16,18 +17,30 @@ linters:
- unused - unused
- typecheck - typecheck
- ineffassign - ineffassign
- stylecheck # - stylecheck
- exportloopref - exportloopref
- gocritic - gocritic
- nakedret - nakedret
- gosimple - gosimple
- prealloc - prealloc
fast: false
disable-all: true # golangci-lint configuration file
linters-settings:
revive:
ignore-generated-header: true
severity: warning
rules:
- name: package-comments
severity: warning
disabled: true
- name: exported
severity: warning
disabled: false
arguments: ["checkPrivateReceivers", "disableStutteringCheck"]
issues: issues:
exclude-use-default: false
exclude-rules: exclude-rules:
- path: _test\.go - path: _test\.go
linters: linters:
- dupl - dupl
exclude-use-default: false

View File

@ -181,6 +181,16 @@ func (c *TwoQueueCache[K, V]) Keys() []K {
return append(k1, k2...) return append(k1, k2...)
} }
// Values returns a slice of the values in the cache.
// The frequently used values are first in the returned slice.
func (c *TwoQueueCache[K, V]) Values() []V {
c.lock.RLock()
defer c.lock.RUnlock()
v1 := c.frequent.Values()
v2 := c.recent.Values()
return append(v1, v2...)
}
// Remove removes the provided key from the cache. // Remove removes the provided key from the cache.
func (c *TwoQueueCache[K, V]) Remove(key K) { func (c *TwoQueueCache[K, V]) Remove(key K) {
c.lock.Lock() c.lock.Lock()

View File

@ -9,17 +9,71 @@ Documentation
Full docs are available on [Go Packages](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2) Full docs are available on [Go Packages](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2)
Example LRU cache example
======= =================
Using the LRU is very simple:
```go ```go
l, _ := New[int, interface{}](128) package main
for i := 0; i < 256; i++ {
l.Add(i, nil) import (
} "fmt"
if l.Len() != 128 { "github.com/hashicorp/golang-lru/v2"
panic(fmt.Sprintf("bad len: %v", l.Len())) )
func main() {
l, _ := lru.New[int, any](128)
for i := 0; i < 256; i++ {
l.Add(i, nil)
}
if l.Len() != 128 {
panic(fmt.Sprintf("bad len: %v", l.Len()))
}
}
```
Expirable LRU cache example
===========================
```go
package main
import (
"fmt"
"time"
"github.com/hashicorp/golang-lru/v2/expirable"
)
func main() {
// make cache with 10ms TTL and 5 max keys
cache := expirable.NewLRU[string, string](5, nil, time.Millisecond*10)
// set value under key1.
cache.Add("key1", "val1")
// get value under key1
r, ok := cache.Get("key1")
// check for OK value
if ok {
fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
}
// wait for cache to expire
time.Sleep(time.Millisecond * 12)
// get value under key1 after key expiration
r, ok = cache.Get("key1")
fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)
// set value under key2, would evict old entry because it is already expired.
cache.Add("key2", "val2")
fmt.Printf("Cache len: %d\n", cache.Len())
// Output:
// value before expiration is found: true, value: "val1"
// value after expiration is found: false, value: ""
// Cache len: 1
} }
``` ```

View File

@ -1,259 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package lru
import (
"sync"
"github.com/hashicorp/golang-lru/v2/simplelru"
)
// ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC).
// ARC is an enhancement over the standard LRU cache in that tracks both
// frequency and recency of use. This avoids a burst in access to new
// entries from evicting the frequently used older entries. It adds some
// additional tracking overhead to a standard LRU cache, computationally
// it is roughly 2x the cost, and the extra memory overhead is linear
// with the size of the cache. ARC has been patented by IBM, but is
// similar to the TwoQueueCache (2Q) which requires setting parameters.
type ARCCache[K comparable, V any] struct {
size int // Size is the total capacity of the cache
p int // P is the dynamic preference towards T1 or T2
t1 simplelru.LRUCache[K, V] // T1 is the LRU for recently accessed items
b1 simplelru.LRUCache[K, struct{}] // B1 is the LRU for evictions from t1
t2 simplelru.LRUCache[K, V] // T2 is the LRU for frequently accessed items
b2 simplelru.LRUCache[K, struct{}] // B2 is the LRU for evictions from t2
lock sync.RWMutex
}
// NewARC creates an ARC of the given size
func NewARC[K comparable, V any](size int) (*ARCCache[K, V], error) {
// Create the sub LRUs
b1, err := simplelru.NewLRU[K, struct{}](size, nil)
if err != nil {
return nil, err
}
b2, err := simplelru.NewLRU[K, struct{}](size, nil)
if err != nil {
return nil, err
}
t1, err := simplelru.NewLRU[K, V](size, nil)
if err != nil {
return nil, err
}
t2, err := simplelru.NewLRU[K, V](size, nil)
if err != nil {
return nil, err
}
// Initialize the ARC
c := &ARCCache[K, V]{
size: size,
p: 0,
t1: t1,
b1: b1,
t2: t2,
b2: b2,
}
return c, nil
}
// Get looks up a key's value from the cache.
func (c *ARCCache[K, V]) Get(key K) (value V, ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
// If the value is contained in T1 (recent), then
// promote it to T2 (frequent)
if val, ok := c.t1.Peek(key); ok {
c.t1.Remove(key)
c.t2.Add(key, val)
return val, ok
}
// Check if the value is contained in T2 (frequent)
if val, ok := c.t2.Get(key); ok {
return val, ok
}
// No hit
return
}
// Add adds a value to the cache.
func (c *ARCCache[K, V]) Add(key K, value V) {
c.lock.Lock()
defer c.lock.Unlock()
// Check if the value is contained in T1 (recent), and potentially
// promote it to frequent T2
if c.t1.Contains(key) {
c.t1.Remove(key)
c.t2.Add(key, value)
return
}
// Check if the value is already in T2 (frequent) and update it
if c.t2.Contains(key) {
c.t2.Add(key, value)
return
}
// Check if this value was recently evicted as part of the
// recently used list
if c.b1.Contains(key) {
// T1 set is too small, increase P appropriately
delta := 1
b1Len := c.b1.Len()
b2Len := c.b2.Len()
if b2Len > b1Len {
delta = b2Len / b1Len
}
if c.p+delta >= c.size {
c.p = c.size
} else {
c.p += delta
}
// Potentially need to make room in the cache
if c.t1.Len()+c.t2.Len() >= c.size {
c.replace(false)
}
// Remove from B1
c.b1.Remove(key)
// Add the key to the frequently used list
c.t2.Add(key, value)
return
}
// Check if this value was recently evicted as part of the
// frequently used list
if c.b2.Contains(key) {
// T2 set is too small, decrease P appropriately
delta := 1
b1Len := c.b1.Len()
b2Len := c.b2.Len()
if b1Len > b2Len {
delta = b1Len / b2Len
}
if delta >= c.p {
c.p = 0
} else {
c.p -= delta
}
// Potentially need to make room in the cache
if c.t1.Len()+c.t2.Len() >= c.size {
c.replace(true)
}
// Remove from B2
c.b2.Remove(key)
// Add the key to the frequently used list
c.t2.Add(key, value)
return
}
// Potentially need to make room in the cache
if c.t1.Len()+c.t2.Len() >= c.size {
c.replace(false)
}
// Keep the size of the ghost buffers trim
if c.b1.Len() > c.size-c.p {
c.b1.RemoveOldest()
}
if c.b2.Len() > c.p {
c.b2.RemoveOldest()
}
// Add to the recently seen list
c.t1.Add(key, value)
}
// replace is used to adaptively evict from either T1 or T2
// based on the current learned value of P
func (c *ARCCache[K, V]) replace(b2ContainsKey bool) {
t1Len := c.t1.Len()
if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) {
k, _, ok := c.t1.RemoveOldest()
if ok {
c.b1.Add(k, struct{}{})
}
} else {
k, _, ok := c.t2.RemoveOldest()
if ok {
c.b2.Add(k, struct{}{})
}
}
}
// Len returns the number of cached entries
func (c *ARCCache[K, V]) Len() int {
c.lock.RLock()
defer c.lock.RUnlock()
return c.t1.Len() + c.t2.Len()
}
// Keys returns all the cached keys
func (c *ARCCache[K, V]) Keys() []K {
c.lock.RLock()
defer c.lock.RUnlock()
k1 := c.t1.Keys()
k2 := c.t2.Keys()
return append(k1, k2...)
}
// Remove is used to purge a key from the cache
func (c *ARCCache[K, V]) Remove(key K) {
c.lock.Lock()
defer c.lock.Unlock()
if c.t1.Remove(key) {
return
}
if c.t2.Remove(key) {
return
}
if c.b1.Remove(key) {
return
}
if c.b2.Remove(key) {
return
}
}
// Purge is used to clear the cache
func (c *ARCCache[K, V]) Purge() {
c.lock.Lock()
defer c.lock.Unlock()
c.t1.Purge()
c.t2.Purge()
c.b1.Purge()
c.b2.Purge()
}
// Contains is used to check if the cache contains a key
// without updating recency or frequency.
func (c *ARCCache[K, V]) Contains(key K) bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.t1.Contains(key) || c.t2.Contains(key)
}
// Peek is used to inspect the cache value of a key
// without updating recency or frequency.
func (c *ARCCache[K, V]) Peek(key K) (value V, ok bool) {
c.lock.RLock()
defer c.lock.RUnlock()
if val, ok := c.t1.Peek(key); ok {
return val, ok
}
return c.t2.Peek(key)
}

View File

@ -3,21 +3,21 @@
// Package lru provides three different LRU caches of varying sophistication. // Package lru provides three different LRU caches of varying sophistication.
// //
// Cache is a simple LRU cache. It is based on the // Cache is a simple LRU cache. It is based on the LRU implementation in
// LRU implementation in groupcache: // groupcache: https://github.com/golang/groupcache/tree/master/lru
// https://github.com/golang/groupcache/tree/master/lru
// //
// TwoQueueCache tracks frequently used and recently used entries separately. // TwoQueueCache tracks frequently used and recently used entries separately.
// This avoids a burst of accesses from taking out frequently used entries, // This avoids a burst of accesses from taking out frequently used entries, at
// at the cost of about 2x computational overhead and some extra bookkeeping. // the cost of about 2x computational overhead and some extra bookkeeping.
// //
// ARCCache is an adaptive replacement cache. It tracks recent evictions as // ARCCache is an adaptive replacement cache. It tracks recent evictions as well
// well as recent usage in both the frequent and recent caches. Its // as recent usage in both the frequent and recent caches. Its computational
// computational overhead is comparable to TwoQueueCache, but the memory // overhead is comparable to TwoQueueCache, but the memory overhead is linear
// overhead is linear with the size of the cache. // with the size of the cache.
// //
// ARC has been patented by IBM, so do not use it if that is problematic for // ARC has been patented by IBM, so do not use it if that is problematic for
// your program. // your program. For this reason, it is in a separate go module contained within
// this repository.
// //
// All caches in this package take locks while operating, and are therefore // All caches in this package take locks while operating, and are therefore
// thread-safe for consumers. // thread-safe for consumers.

View File

@ -0,0 +1,142 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE_list file.
package internal
import "time"
// Entry is an LRU Entry
type Entry[K comparable, V any] struct {
// Next and previous pointers in the doubly-linked list of elements.
// To simplify the implementation, internally a list l is implemented
// as a ring, such that &l.root is both the next element of the last
// list element (l.Back()) and the previous element of the first list
// element (l.Front()).
next, prev *Entry[K, V]
// The list to which this element belongs.
list *LruList[K, V]
// The LRU Key of this element.
Key K
// The Value stored with this element.
Value V
// The time this element would be cleaned up, optional
ExpiresAt time.Time
// The expiry bucket item was put in, optional
ExpireBucket uint8
}
// PrevEntry returns the previous list element or nil.
func (e *Entry[K, V]) PrevEntry() *Entry[K, V] {
if p := e.prev; e.list != nil && p != &e.list.root {
return p
}
return nil
}
// LruList represents a doubly linked list.
// The zero Value for LruList is an empty list ready to use.
type LruList[K comparable, V any] struct {
root Entry[K, V] // sentinel list element, only &root, root.prev, and root.next are used
len int // current list Length excluding (this) sentinel element
}
// Init initializes or clears list l.
func (l *LruList[K, V]) Init() *LruList[K, V] {
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
// NewList returns an initialized list.
func NewList[K comparable, V any]() *LruList[K, V] { return new(LruList[K, V]).Init() }
// Length returns the number of elements of list l.
// The complexity is O(1).
func (l *LruList[K, V]) Length() int { return l.len }
// Back returns the last element of list l or nil if the list is empty.
func (l *LruList[K, V]) Back() *Entry[K, V] {
if l.len == 0 {
return nil
}
return l.root.prev
}
// lazyInit lazily initializes a zero List Value.
func (l *LruList[K, V]) lazyInit() {
if l.root.next == nil {
l.Init()
}
}
// insert inserts e after at, increments l.len, and returns e.
func (l *LruList[K, V]) insert(e, at *Entry[K, V]) *Entry[K, V] {
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
e.list = l
l.len++
return e
}
// insertValue is a convenience wrapper for insert(&Entry{Value: v, ExpiresAt: ExpiresAt}, at).
func (l *LruList[K, V]) insertValue(k K, v V, expiresAt time.Time, at *Entry[K, V]) *Entry[K, V] {
return l.insert(&Entry[K, V]{Value: v, Key: k, ExpiresAt: expiresAt}, at)
}
// Remove removes e from its list, decrements l.len
func (l *LruList[K, V]) Remove(e *Entry[K, V]) V {
e.prev.next = e.next
e.next.prev = e.prev
e.next = nil // avoid memory leaks
e.prev = nil // avoid memory leaks
e.list = nil
l.len--
return e.Value
}
// move moves e to next to at.
func (l *LruList[K, V]) move(e, at *Entry[K, V]) {
if e == at {
return
}
e.prev.next = e.next
e.next.prev = e.prev
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
}
// PushFront inserts a new element e with value v at the front of list l and returns e.
func (l *LruList[K, V]) PushFront(k K, v V) *Entry[K, V] {
l.lazyInit()
return l.insertValue(k, v, time.Time{}, &l.root)
}
// PushFrontExpirable inserts a new expirable element e with Value v at the front of list l and returns e.
func (l *LruList[K, V]) PushFrontExpirable(k K, v V, expiresAt time.Time) *Entry[K, V] {
l.lazyInit()
return l.insertValue(k, v, expiresAt, &l.root)
}
// MoveToFront moves element e to the front of list l.
// If e is not an element of l, the list is not modified.
// The element must not be nil.
func (l *LruList[K, V]) MoveToFront(e *Entry[K, V]) {
if e.list != l || l.root.next == e {
return
}
// see comment in List.Remove about initialization of l
l.move(e, &l.root)
}

View File

@ -233,6 +233,14 @@ func (c *Cache[K, V]) Keys() []K {
return keys return keys
} }
// Values returns a slice of the values in the cache, from oldest to newest.
func (c *Cache[K, V]) Values() []V {
c.lock.RLock()
values := c.lru.Values()
c.lock.RUnlock()
return values
}
// Len returns the number of items in the cache. // Len returns the number of items in the cache.
func (c *Cache[K, V]) Len() int { func (c *Cache[K, V]) Len() int {
c.lock.RLock() c.lock.RLock()

View File

@ -1,128 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE_list file.
package simplelru
// entry is an LRU entry
type entry[K comparable, V any] struct {
// Next and previous pointers in the doubly-linked list of elements.
// To simplify the implementation, internally a list l is implemented
// as a ring, such that &l.root is both the next element of the last
// list element (l.Back()) and the previous element of the first list
// element (l.Front()).
next, prev *entry[K, V]
// The list to which this element belongs.
list *lruList[K, V]
// The LRU key of this element.
key K
// The value stored with this element.
value V
}
// prevEntry returns the previous list element or nil.
func (e *entry[K, V]) prevEntry() *entry[K, V] {
if p := e.prev; e.list != nil && p != &e.list.root {
return p
}
return nil
}
// lruList represents a doubly linked list.
// The zero value for lruList is an empty list ready to use.
type lruList[K comparable, V any] struct {
root entry[K, V] // sentinel list element, only &root, root.prev, and root.next are used
len int // current list length excluding (this) sentinel element
}
// init initializes or clears list l.
func (l *lruList[K, V]) init() *lruList[K, V] {
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
// newList returns an initialized list.
func newList[K comparable, V any]() *lruList[K, V] { return new(lruList[K, V]).init() }
// length returns the number of elements of list l.
// The complexity is O(1).
func (l *lruList[K, V]) length() int { return l.len }
// back returns the last element of list l or nil if the list is empty.
func (l *lruList[K, V]) back() *entry[K, V] {
if l.len == 0 {
return nil
}
return l.root.prev
}
// lazyInit lazily initializes a zero List value.
func (l *lruList[K, V]) lazyInit() {
if l.root.next == nil {
l.init()
}
}
// insert inserts e after at, increments l.len, and returns e.
func (l *lruList[K, V]) insert(e, at *entry[K, V]) *entry[K, V] {
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
e.list = l
l.len++
return e
}
// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
func (l *lruList[K, V]) insertValue(k K, v V, at *entry[K, V]) *entry[K, V] {
return l.insert(&entry[K, V]{value: v, key: k}, at)
}
// remove removes e from its list, decrements l.len
func (l *lruList[K, V]) remove(e *entry[K, V]) V {
e.prev.next = e.next
e.next.prev = e.prev
e.next = nil // avoid memory leaks
e.prev = nil // avoid memory leaks
e.list = nil
l.len--
return e.value
}
// move moves e to next to at.
func (l *lruList[K, V]) move(e, at *entry[K, V]) {
if e == at {
return
}
e.prev.next = e.next
e.next.prev = e.prev
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
}
// pushFront inserts a new element e with value v at the front of list l and returns e.
func (l *lruList[K, V]) pushFront(k K, v V) *entry[K, V] {
l.lazyInit()
return l.insertValue(k, v, &l.root)
}
// moveToFront moves element e to the front of list l.
// If e is not an element of l, the list is not modified.
// The element must not be nil.
func (l *lruList[K, V]) moveToFront(e *entry[K, V]) {
if e.list != l || l.root.next == e {
return
}
// see comment in List.Remove about initialization of l
l.move(e, &l.root)
}

View File

@ -5,6 +5,8 @@ package simplelru
import ( import (
"errors" "errors"
"github.com/hashicorp/golang-lru/v2/internal"
) )
// EvictCallback is used to get a callback when a cache entry is evicted // EvictCallback is used to get a callback when a cache entry is evicted
@ -13,8 +15,8 @@ type EvictCallback[K comparable, V any] func(key K, value V)
// LRU implements a non-thread safe fixed size LRU cache // LRU implements a non-thread safe fixed size LRU cache
type LRU[K comparable, V any] struct { type LRU[K comparable, V any] struct {
size int size int
evictList *lruList[K, V] evictList *internal.LruList[K, V]
items map[K]*entry[K, V] items map[K]*internal.Entry[K, V]
onEvict EvictCallback[K, V] onEvict EvictCallback[K, V]
} }
@ -26,8 +28,8 @@ func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V]) (*LRU[K,
c := &LRU[K, V]{ c := &LRU[K, V]{
size: size, size: size,
evictList: newList[K, V](), evictList: internal.NewList[K, V](),
items: make(map[K]*entry[K, V]), items: make(map[K]*internal.Entry[K, V]),
onEvict: onEvict, onEvict: onEvict,
} }
return c, nil return c, nil
@ -37,27 +39,30 @@ func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V]) (*LRU[K,
func (c *LRU[K, V]) Purge() { func (c *LRU[K, V]) Purge() {
for k, v := range c.items { for k, v := range c.items {
if c.onEvict != nil { if c.onEvict != nil {
c.onEvict(k, v.value) c.onEvict(k, v.Value)
} }
delete(c.items, k) delete(c.items, k)
} }
c.evictList.init() c.evictList.Init()
} }
// Add adds a value to the cache. Returns true if an eviction occurred. // Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU[K, V]) Add(key K, value V) (evicted bool) { func (c *LRU[K, V]) Add(key K, value V) (evicted bool) {
// Check for existing item // Check for existing item
if ent, ok := c.items[key]; ok { if ent, ok := c.items[key]; ok {
c.evictList.moveToFront(ent) c.evictList.MoveToFront(ent)
ent.value = value if c.onEvict != nil {
c.onEvict(key, ent.Value)
}
ent.Value = value
return false return false
} }
// Add new item // Add new item
ent := c.evictList.pushFront(key, value) ent := c.evictList.PushFront(key, value)
c.items[key] = ent c.items[key] = ent
evict := c.evictList.length() > c.size evict := c.evictList.Length() > c.size
// Verify size not exceeded // Verify size not exceeded
if evict { if evict {
c.removeOldest() c.removeOldest()
@ -68,8 +73,8 @@ func (c *LRU[K, V]) Add(key K, value V) (evicted bool) {
// Get looks up a key's value from the cache. // Get looks up a key's value from the cache.
func (c *LRU[K, V]) Get(key K) (value V, ok bool) { func (c *LRU[K, V]) Get(key K) (value V, ok bool) {
if ent, ok := c.items[key]; ok { if ent, ok := c.items[key]; ok {
c.evictList.moveToFront(ent) c.evictList.MoveToFront(ent)
return ent.value, true return ent.Value, true
} }
return return
} }
@ -84,9 +89,9 @@ func (c *LRU[K, V]) Contains(key K) (ok bool) {
// Peek returns the key value (or undefined if not found) without updating // Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key. // the "recently used"-ness of the key.
func (c *LRU[K, V]) Peek(key K) (value V, ok bool) { func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
var ent *entry[K, V] var ent *internal.Entry[K, V]
if ent, ok = c.items[key]; ok { if ent, ok = c.items[key]; ok {
return ent.value, true return ent.Value, true
} }
return return
} }
@ -103,35 +108,46 @@ func (c *LRU[K, V]) Remove(key K) (present bool) {
// RemoveOldest removes the oldest item from the cache. // RemoveOldest removes the oldest item from the cache.
func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) { func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
if ent := c.evictList.back(); ent != nil { if ent := c.evictList.Back(); ent != nil {
c.removeElement(ent) c.removeElement(ent)
return ent.key, ent.value, true return ent.Key, ent.Value, true
} }
return return
} }
// GetOldest returns the oldest entry // GetOldest returns the oldest entry
func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) { func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) {
if ent := c.evictList.back(); ent != nil { if ent := c.evictList.Back(); ent != nil {
return ent.key, ent.value, true return ent.Key, ent.Value, true
} }
return return
} }
// Keys returns a slice of the keys in the cache, from oldest to newest. // Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *LRU[K, V]) Keys() []K { func (c *LRU[K, V]) Keys() []K {
keys := make([]K, c.evictList.length()) keys := make([]K, c.evictList.Length())
i := 0 i := 0
for ent := c.evictList.back(); ent != nil; ent = ent.prevEntry() { for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
keys[i] = ent.key keys[i] = ent.Key
i++ i++
} }
return keys return keys
} }
// Values returns a slice of the values in the cache, from oldest to newest.
func (c *LRU[K, V]) Values() []V {
values := make([]V, len(c.items))
i := 0
for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
values[i] = ent.Value
i++
}
return values
}
// Len returns the number of items in the cache. // Len returns the number of items in the cache.
func (c *LRU[K, V]) Len() int { func (c *LRU[K, V]) Len() int {
return c.evictList.length() return c.evictList.Length()
} }
// Resize changes the cache size. // Resize changes the cache size.
@ -149,16 +165,16 @@ func (c *LRU[K, V]) Resize(size int) (evicted int) {
// removeOldest removes the oldest item from the cache. // removeOldest removes the oldest item from the cache.
func (c *LRU[K, V]) removeOldest() { func (c *LRU[K, V]) removeOldest() {
if ent := c.evictList.back(); ent != nil { if ent := c.evictList.Back(); ent != nil {
c.removeElement(ent) c.removeElement(ent)
} }
} }
// removeElement is used to remove a given list element from the cache // removeElement is used to remove a given list element from the cache
func (c *LRU[K, V]) removeElement(e *entry[K, V]) { func (c *LRU[K, V]) removeElement(e *internal.Entry[K, V]) {
c.evictList.remove(e) c.evictList.Remove(e)
delete(c.items, e.key) delete(c.items, e.Key)
if c.onEvict != nil { if c.onEvict != nil {
c.onEvict(e.key, e.value) c.onEvict(e.Key, e.Value)
} }
} }

View File

@ -32,6 +32,9 @@ type LRUCache[K comparable, V any] interface {
// Returns a slice of the keys in the cache, from oldest to newest. // Returns a slice of the keys in the cache, from oldest to newest.
Keys() []K Keys() []K
// Values returns a slice of the values in the cache, from oldest to newest.
Values() []V
// Returns the number of items in the cache. // Returns the number of items in the cache.
Len() int Len() int

View File

@ -1,19 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package lru
import (
"crypto/rand"
"math"
"math/big"
"testing"
)
func getRand(tb testing.TB) int64 {
out, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
tb.Fatal(err)
}
return out.Int64()
}

View File

@ -85,7 +85,10 @@ func DiscoverDevicesCtx(ctx context.Context, searchTarget string) ([]MaybeRootDe
return nil, err return nil, err
} }
defer hcCleanup() defer hcCleanup()
responses, err := ssdp.SSDPRawSearchCtx(ctx, hc, string(searchTarget), 2, 3)
searchCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
responses, err := ssdp.RawSearch(searchCtx, hc, string(searchTarget), 3)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,6 +3,7 @@ package httpu
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@ -26,6 +27,27 @@ type ClientInterface interface {
) ([]*http.Response, error) ) ([]*http.Response, error)
} }
// ClientInterfaceCtx is the equivalent of ClientInterface, except with methods
// taking a context.Context parameter.
type ClientInterfaceCtx interface {
// DoWithContext performs a request. If the input request has a
// deadline, then that value will be used as the timeout for how long
// to wait before returning the responses that were received. If the
// request's context is canceled, this method will return immediately.
//
// If the request's context is never canceled, and does not have a
// deadline, then this function WILL NEVER RETURN. You MUST set an
// appropriate deadline on the context, or otherwise cancel it when you
// want to finish an operation.
//
// An error is only returned for failing to send the request. Failures
// in receipt simply do not add to the resulting responses.
DoWithContext(
req *http.Request,
numSends int,
) ([]*http.Response, error)
}
// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical // HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical
// function is for HTTPMU, and particularly SSDP. // function is for HTTPMU, and particularly SSDP.
type HTTPUClient struct { type HTTPUClient struct {
@ -34,6 +56,7 @@ type HTTPUClient struct {
} }
var _ ClientInterface = &HTTPUClient{} var _ ClientInterface = &HTTPUClient{}
var _ ClientInterfaceCtx = &HTTPUClient{}
// NewHTTPUClient creates a new HTTPUClient, opening up a new UDP socket for the // NewHTTPUClient creates a new HTTPUClient, opening up a new UDP socket for the
// purpose. // purpose.
@ -75,6 +98,25 @@ func (httpu *HTTPUClient) Do(
req *http.Request, req *http.Request,
timeout time.Duration, timeout time.Duration,
numSends int, numSends int,
) ([]*http.Response, error) {
ctx := req.Context()
if timeout > 0 {
var cancel func()
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
req = req.WithContext(ctx)
}
return httpu.DoWithContext(req, numSends)
}
// DoWithContext implements ClientInterfaceCtx.DoWithContext.
//
// Make sure to read the documentation on the ClientInterfaceCtx interface
// regarding cancellation!
func (httpu *HTTPUClient) DoWithContext(
req *http.Request,
numSends int,
) ([]*http.Response, error) { ) ([]*http.Response, error) {
httpu.connLock.Lock() httpu.connLock.Lock()
defer httpu.connLock.Unlock() defer httpu.connLock.Unlock()
@ -101,10 +143,28 @@ func (httpu *HTTPUClient) Do(
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = httpu.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
return nil, err // Handle context deadline/timeout
ctx := req.Context()
deadline, ok := ctx.Deadline()
if ok {
if err = httpu.conn.SetDeadline(deadline); err != nil {
return nil, err
}
} }
// Handle context cancelation
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-ctx.Done():
// if context is cancelled, stop any connections by setting time in the past.
httpu.conn.SetDeadline(time.Now().Add(-time.Second))
case <-done:
}
}()
// Send request. // Send request.
for i := 0; i < numSends; i++ { for i := 0; i < numSends; i++ {
if n, err := httpu.conn.WriteTo(requestBuf.Bytes(), destAddr); err != nil { if n, err := httpu.conn.WriteTo(requestBuf.Bytes(), destAddr); err != nil {

View File

@ -49,14 +49,14 @@ func (mc *MultiClient) Do(
} }
func (mc *MultiClient) sendRequests( func (mc *MultiClient) sendRequests(
results chan<-[]*http.Response, results chan<- []*http.Response,
req *http.Request, req *http.Request,
timeout time.Duration, timeout time.Duration,
numSends int, numSends int,
) error { ) error {
tasks := &errgroup.Group{} tasks := &errgroup.Group{}
for _, d := range mc.delegates { for _, d := range mc.delegates {
d := d // copy for closure d := d // copy for closure
tasks.Go(func() error { tasks.Go(func() error {
responses, err := d.Do(req, timeout, numSends) responses, err := d.Do(req, timeout, numSends)
if err != nil { if err != nil {
@ -68,3 +68,65 @@ func (mc *MultiClient) sendRequests(
} }
return tasks.Wait() return tasks.Wait()
} }
// MultiClientCtx dispatches requests out to all the delegated clients.
type MultiClientCtx struct {
// The HTTPU clients to delegate to.
delegates []ClientInterfaceCtx
}
var _ ClientInterfaceCtx = &MultiClientCtx{}
// NewMultiClient creates a new MultiClient that delegates to all the given
// clients.
func NewMultiClientCtx(delegates []ClientInterfaceCtx) *MultiClientCtx {
return &MultiClientCtx{
delegates: delegates,
}
}
// DoWithContext implements ClientInterfaceCtx.DoWithContext.
func (mc *MultiClientCtx) DoWithContext(
req *http.Request,
numSends int,
) ([]*http.Response, error) {
tasks, ctx := errgroup.WithContext(req.Context())
req = req.WithContext(ctx) // so we cancel if the errgroup errors
results := make(chan []*http.Response)
// For each client, send the request to it and collect results.
tasks.Go(func() error {
defer close(results)
return mc.sendRequestsCtx(results, req, numSends)
})
var responses []*http.Response
tasks.Go(func() error {
for rs := range results {
responses = append(responses, rs...)
}
return nil
})
return responses, tasks.Wait()
}
func (mc *MultiClientCtx) sendRequestsCtx(
results chan<- []*http.Response,
req *http.Request,
numSends int,
) error {
tasks := &errgroup.Group{}
for _, d := range mc.delegates {
d := d // copy for closure
tasks.Go(func() error {
responses, err := d.DoWithContext(req, numSends)
if err != nil {
return err
}
results <- responses
return nil
})
}
return tasks.Wait()
}

View File

@ -10,14 +10,14 @@ import (
// httpuClient creates a HTTPU client that multiplexes to all multicast-capable // httpuClient creates a HTTPU client that multiplexes to all multicast-capable
// IPv4 addresses on the host. Returns a function to clean up once the client is // IPv4 addresses on the host. Returns a function to clean up once the client is
// no longer required. // no longer required.
func httpuClient() (httpu.ClientInterface, func(), error) { func httpuClient() (httpu.ClientInterfaceCtx, func(), error) {
addrs, err := localIPv4MCastAddrs() addrs, err := localIPv4MCastAddrs()
if err != nil { if err != nil {
return nil, nil, ctxError(err, "requesting host IPv4 addresses") return nil, nil, ctxError(err, "requesting host IPv4 addresses")
} }
closers := make([]io.Closer, 0, len(addrs)) closers := make([]io.Closer, 0, len(addrs))
delegates := make([]httpu.ClientInterface, 0, len(addrs)) delegates := make([]httpu.ClientInterfaceCtx, 0, len(addrs))
for _, addr := range addrs { for _, addr := range addrs {
c, err := httpu.NewHTTPUClientAddr(addr) c, err := httpu.NewHTTPUClientAddr(addr)
if err != nil { if err != nil {
@ -34,7 +34,7 @@ func httpuClient() (httpu.ClientInterface, func(), error) {
} }
} }
return httpu.NewMultiClient(delegates), closer, nil return httpu.NewMultiClientCtx(delegates), closer, nil
} }
// localIPv2MCastAddrs returns the set of IPv4 addresses on multicast-able // localIPv2MCastAddrs returns the set of IPv4 addresses on multicast-able

View File

@ -35,6 +35,15 @@ type HTTPUClient interface {
) ([]*http.Response, error) ) ([]*http.Response, error)
} }
// HTTPUClientCtx is an optional interface that will be used to perform
// HTTP-over-UDP requests if the client implements it.
type HTTPUClientCtx interface {
DoWithContext(
req *http.Request,
numSends int,
) ([]*http.Response, error)
}
// SSDPRawSearchCtx performs a fairly raw SSDP search request, and returns the // SSDPRawSearchCtx performs a fairly raw SSDP search request, and returns the
// unique response(s) that it receives. Each response has the requested // unique response(s) that it receives. Each response has the requested
// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to // searchTarget, a USN, and a valid location. maxWaitSeconds states how long to
@ -49,8 +58,64 @@ func SSDPRawSearchCtx(
maxWaitSeconds int, maxWaitSeconds int,
numSends int, numSends int,
) ([]*http.Response, error) { ) ([]*http.Response, error) {
req, err := prepareRequest(ctx, searchTarget, maxWaitSeconds)
if err != nil {
return nil, err
}
allResponses, err := httpu.Do(req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends)
if err != nil {
return nil, err
}
return processSSDPResponses(searchTarget, allResponses)
}
// RawSearch performs a fairly raw SSDP search request, and returns the
// unique response(s) that it receives. Each response has the requested
// searchTarget, a USN, and a valid location. If the provided context times out
// or is canceled, the search will be aborted. numSends is the number of
// requests to send - 3 is a reasonable value for this.
//
// The provided context should have a deadline, since the SSDP protocol
// requires the max wait time be included in search requests. If the context
// has no deadline, then a default deadline of 3 seconds will be applied.
func RawSearch(
ctx context.Context,
httpu HTTPUClientCtx,
searchTarget string,
numSends int,
) ([]*http.Response, error) {
// We need a timeout value to include in the SSDP request; get it by
// checking the deadline on the context.
var maxWaitSeconds int
if deadline, ok := ctx.Deadline(); ok {
maxWaitSeconds = int(deadline.Sub(time.Now()) / time.Second)
} else {
// Pick a default timeout of 3 seconds if none was provided.
maxWaitSeconds = 3
var cancel func()
ctx, cancel = context.WithTimeout(ctx, time.Duration(maxWaitSeconds)*time.Second)
defer cancel()
}
req, err := prepareRequest(ctx, searchTarget, maxWaitSeconds)
if err != nil {
return nil, err
}
allResponses, err := httpu.DoWithContext(req, numSends)
if err != nil {
return nil, err
}
return processSSDPResponses(searchTarget, allResponses)
}
// prepareRequest checks the provided parameters and constructs a SSDP search
// request to be sent.
func prepareRequest(ctx context.Context, searchTarget string, maxWaitSeconds int) (*http.Request, error) {
if maxWaitSeconds < 1 { if maxWaitSeconds < 1 {
return nil, errors.New("ssdp: maxWaitSeconds must be >= 1") return nil, errors.New("ssdp: request timeout must be at least 1s")
} }
req := (&http.Request{ req := (&http.Request{
@ -67,11 +132,13 @@ func SSDPRawSearchCtx(
"ST": []string{searchTarget}, "ST": []string{searchTarget},
}, },
}).WithContext(ctx) }).WithContext(ctx)
allResponses, err := httpu.Do(req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends) return req, nil
if err != nil { }
return nil, err
}
func processSSDPResponses(
searchTarget string,
allResponses []*http.Response,
) ([]*http.Response, error) {
isExactSearch := searchTarget != SSDPAll && searchTarget != UPNPRootDevice isExactSearch := searchTarget != SSDPAll && searchTarget != UPNPRootDevice
seenIDs := make(map[string]bool) seenIDs := make(map[string]bool)

View File

@ -3,7 +3,7 @@
before: before:
hooks: hooks:
- ./gen.sh - ./gen.sh
- go install mvdan.cc/garble@v0.9.3 - go install mvdan.cc/garble@v0.10.1
builds: builds:
- -
@ -92,16 +92,7 @@ builds:
archives: archives:
- -
id: s2-binaries id: s2-binaries
name_template: "s2-{{ .Os }}_{{ .Arch }}_{{ .Version }}" name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
replacements:
aix: AIX
darwin: OSX
linux: Linux
windows: Windows
386: i386
amd64: x86_64
freebsd: FreeBSD
netbsd: NetBSD
format_overrides: format_overrides:
- goos: windows - goos: windows
format: zip format: zip
@ -125,7 +116,7 @@ changelog:
nfpms: nfpms:
- -
file_name_template: "s2_package_{{ .Version }}_{{ .Os }}_{{ .Arch }}" file_name_template: "s2_package__{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
vendor: Klaus Post vendor: Klaus Post
homepage: https://github.com/klauspost/compress homepage: https://github.com/klauspost/compress
maintainer: Klaus Post <klauspost@gmail.com> maintainer: Klaus Post <klauspost@gmail.com>
@ -134,8 +125,3 @@ nfpms:
formats: formats:
- deb - deb
- rpm - rpm
replacements:
darwin: Darwin
linux: Linux
freebsd: FreeBSD
amd64: x86_64

View File

@ -16,6 +16,18 @@ This package provides various compression algorithms.
# changelog # changelog
* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
* Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
* Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
* flate: Add limited window compression https://github.com/klauspost/compress/pull/843
* 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
* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
* zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
* s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6) * June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
* zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806 * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
* zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824 * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
@ -50,6 +62,9 @@ This package provides various compression algorithms.
* s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747 * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
* s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746 * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
<details>
<summary>See changes to v1.15.x</summary>
* Jan 21st, 2023 (v1.15.15) * Jan 21st, 2023 (v1.15.15)
* deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739 * deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739
* zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728 * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
@ -176,6 +191,8 @@ Stream decompression is now faster on asynchronous, since the goroutine allocati
While the release has been extensively tested, it is recommended to testing when upgrading. While the release has been extensively tested, it is recommended to testing when upgrading.
</details>
<details> <details>
<summary>See changes to v1.14.x</summary> <summary>See changes to v1.14.x</summary>
@ -636,6 +653,8 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv
* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer. * [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression. * [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression. * [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.
# license # license

View File

@ -152,12 +152,11 @@ func (b *bitWriter) flushAlign() {
// close will write the alignment bit and write the final byte(s) // close will write the alignment bit and write the final byte(s)
// to the output. // to the output.
func (b *bitWriter) close() error { func (b *bitWriter) close() {
// End mark // End mark
b.addBits16Clean(1, 1) b.addBits16Clean(1, 1)
// flush until next byte. // flush until next byte.
b.flushAlign() b.flushAlign()
return nil
} }
// reset and continue writing by appending to out. // reset and continue writing by appending to out.

View File

@ -199,7 +199,8 @@ func (s *Scratch) compress(src []byte) error {
c2.flush(s.actualTableLog) c2.flush(s.actualTableLog)
c1.flush(s.actualTableLog) c1.flush(s.actualTableLog)
return s.bw.close() s.bw.close()
return nil
} }
// writeCount will write the normalized histogram count to header. // writeCount will write the normalized histogram count to header.

View File

@ -94,10 +94,9 @@ func (b *bitWriter) flushAlign() {
// close will write the alignment bit and write the final byte(s) // close will write the alignment bit and write the final byte(s)
// to the output. // to the output.
func (b *bitWriter) close() error { func (b *bitWriter) close() {
// End mark // End mark
b.addBits16Clean(1, 1) b.addBits16Clean(1, 1)
// flush until next byte. // flush until next byte.
b.flushAlign() b.flushAlign()
return nil
} }

View File

@ -227,10 +227,10 @@ func EstimateSizes(in []byte, s *Scratch) (tableSz, dataSz, reuseSz int, err err
} }
func (s *Scratch) compress1X(src []byte) ([]byte, error) { func (s *Scratch) compress1X(src []byte) ([]byte, error) {
return s.compress1xDo(s.Out, src) return s.compress1xDo(s.Out, src), nil
} }
func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) { func (s *Scratch) compress1xDo(dst, src []byte) []byte {
var bw = bitWriter{out: dst} var bw = bitWriter{out: dst}
// N is length divisible by 4. // N is length divisible by 4.
@ -260,8 +260,8 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
bw.encTwoSymbols(cTable, tmp[1], tmp[0]) bw.encTwoSymbols(cTable, tmp[1], tmp[0])
} }
} }
err := bw.close() bw.close()
return bw.out, err return bw.out
} }
var sixZeros [6]byte var sixZeros [6]byte
@ -283,12 +283,8 @@ func (s *Scratch) compress4X(src []byte) ([]byte, error) {
} }
src = src[len(toDo):] src = src[len(toDo):]
var err error
idx := len(s.Out) idx := len(s.Out)
s.Out, err = s.compress1xDo(s.Out, toDo) s.Out = s.compress1xDo(s.Out, toDo)
if err != nil {
return nil, err
}
if len(s.Out)-idx > math.MaxUint16 { if len(s.Out)-idx > math.MaxUint16 {
// We cannot store the size in the jump table // We cannot store the size in the jump table
return nil, ErrIncompressible return nil, ErrIncompressible
@ -315,7 +311,6 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
segmentSize := (len(src) + 3) / 4 segmentSize := (len(src) + 3) / 4
var wg sync.WaitGroup var wg sync.WaitGroup
var errs [4]error
wg.Add(4) wg.Add(4)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
toDo := src toDo := src
@ -326,15 +321,12 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
// Separate goroutine for each block. // Separate goroutine for each block.
go func(i int) { go func(i int) {
s.tmpOut[i], errs[i] = s.compress1xDo(s.tmpOut[i][:0], toDo) s.tmpOut[i] = s.compress1xDo(s.tmpOut[i][:0], toDo)
wg.Done() wg.Done()
}(i) }(i)
} }
wg.Wait() wg.Wait()
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
if errs[i] != nil {
return nil, errs[i]
}
o := s.tmpOut[i] o := s.tmpOut[i]
if len(o) > math.MaxUint16 { if len(o) > math.MaxUint16 {
// We cannot store the size in the jump table // We cannot store the size in the jump table

View File

@ -17,7 +17,6 @@ import (
// for aligning the input. // for aligning the input.
type bitReader struct { type bitReader struct {
in []byte in []byte
off uint // next byte to read is at in[off - 1]
value uint64 // Maybe use [16]byte, but shifting is awkward. value uint64 // Maybe use [16]byte, but shifting is awkward.
bitsRead uint8 bitsRead uint8
} }
@ -28,7 +27,6 @@ func (b *bitReader) init(in []byte) error {
return errors.New("corrupt stream: too short") return errors.New("corrupt stream: too short")
} }
b.in = in b.in = in
b.off = uint(len(in))
// The highest bit of the last byte indicates where to start // The highest bit of the last byte indicates where to start
v := in[len(in)-1] v := in[len(in)-1]
if v == 0 { if v == 0 {
@ -69,21 +67,19 @@ func (b *bitReader) fillFast() {
if b.bitsRead < 32 { if b.bitsRead < 32 {
return return
} }
// 2 bounds checks. v := b.in[len(b.in)-4:]
v := b.in[b.off-4:] b.in = b.in[:len(b.in)-4]
v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low) b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32 b.bitsRead -= 32
b.off -= 4
} }
// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read. // fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
func (b *bitReader) fillFastStart() { func (b *bitReader) fillFastStart() {
// Do single re-slice to avoid bounds checks. v := b.in[len(b.in)-8:]
b.value = binary.LittleEndian.Uint64(b.in[b.off-8:]) b.in = b.in[:len(b.in)-8]
b.value = binary.LittleEndian.Uint64(v)
b.bitsRead = 0 b.bitsRead = 0
b.off -= 8
} }
// fill() will make sure at least 32 bits are available. // fill() will make sure at least 32 bits are available.
@ -91,25 +87,25 @@ func (b *bitReader) fill() {
if b.bitsRead < 32 { if b.bitsRead < 32 {
return return
} }
if b.off >= 4 { if len(b.in) >= 4 {
v := b.in[b.off-4:] v := b.in[len(b.in)-4:]
v = v[:4] b.in = b.in[:len(b.in)-4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low) b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32 b.bitsRead -= 32
b.off -= 4
return return
} }
for b.off > 0 {
b.value = (b.value << 8) | uint64(b.in[b.off-1]) b.bitsRead -= uint8(8 * len(b.in))
b.bitsRead -= 8 for len(b.in) > 0 {
b.off-- b.value = (b.value << 8) | uint64(b.in[len(b.in)-1])
b.in = b.in[:len(b.in)-1]
} }
} }
// finished returns true if all bits have been read from the bit stream. // finished returns true if all bits have been read from the bit stream.
func (b *bitReader) finished() bool { func (b *bitReader) finished() bool {
return b.off == 0 && b.bitsRead >= 64 return len(b.in) == 0 && b.bitsRead >= 64
} }
// overread returns true if more bits have been requested than is on the stream. // overread returns true if more bits have been requested than is on the stream.
@ -119,7 +115,7 @@ func (b *bitReader) overread() bool {
// remain returns the number of bits remaining. // remain returns the number of bits remaining.
func (b *bitReader) remain() uint { func (b *bitReader) remain() uint {
return b.off*8 + 64 - uint(b.bitsRead) return 8*uint(len(b.in)) + 64 - uint(b.bitsRead)
} }
// close the bitstream and returns an error if out-of-buffer reads occurred. // close the bitstream and returns an error if out-of-buffer reads occurred.

View File

@ -97,12 +97,11 @@ func (b *bitWriter) flushAlign() {
// close will write the alignment bit and write the final byte(s) // close will write the alignment bit and write the final byte(s)
// to the output. // to the output.
func (b *bitWriter) close() error { func (b *bitWriter) close() {
// End mark // End mark
b.addBits16Clean(1, 1) b.addBits16Clean(1, 1)
// flush until next byte. // flush until next byte.
b.flushAlign() b.flushAlign()
return nil
} }
// reset and continue writing by appending to out. // reset and continue writing by appending to out.

View File

@ -361,14 +361,21 @@ func (b *blockEnc) encodeLits(lits []byte, raw bool) error {
if len(lits) >= 1024 { if len(lits) >= 1024 {
// Use 4 Streams. // Use 4 Streams.
out, reUsed, err = huff0.Compress4X(lits, b.litEnc) out, reUsed, err = huff0.Compress4X(lits, b.litEnc)
} else if len(lits) > 32 { } else if len(lits) > 16 {
// Use 1 stream // Use 1 stream
single = true single = true
out, reUsed, err = huff0.Compress1X(lits, b.litEnc) out, reUsed, err = huff0.Compress1X(lits, b.litEnc)
} else { } else {
err = huff0.ErrIncompressible err = huff0.ErrIncompressible
} }
if err == nil && len(out)+5 > len(lits) {
// If we are close, we may still be worse or equal to raw.
var lh literalsHeader
lh.setSizes(len(out), len(lits), single)
if len(out)+lh.size() >= len(lits) {
err = huff0.ErrIncompressible
}
}
switch err { switch err {
case huff0.ErrIncompressible: case huff0.ErrIncompressible:
if debugEncoder { if debugEncoder {
@ -503,7 +510,7 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
if len(b.literals) >= 1024 && !raw { if len(b.literals) >= 1024 && !raw {
// Use 4 Streams. // Use 4 Streams.
out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc) out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
} else if len(b.literals) > 32 && !raw { } else if len(b.literals) > 16 && !raw {
// Use 1 stream // Use 1 stream
single = true single = true
out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc) out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
@ -511,6 +518,17 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
err = huff0.ErrIncompressible err = huff0.ErrIncompressible
} }
if err == nil && len(out)+5 > len(b.literals) {
// If we are close, we may still be worse or equal to raw.
var lh literalsHeader
lh.setSize(len(b.literals))
szRaw := lh.size()
lh.setSizes(len(out), len(b.literals), single)
szComp := lh.size()
if len(out)+szComp >= len(b.literals)+szRaw {
err = huff0.ErrIncompressible
}
}
switch err { switch err {
case huff0.ErrIncompressible: case huff0.ErrIncompressible:
lh.setType(literalsBlockRaw) lh.setType(literalsBlockRaw)
@ -773,10 +791,7 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
ml.flush(mlEnc.actualTableLog) ml.flush(mlEnc.actualTableLog)
of.flush(ofEnc.actualTableLog) of.flush(ofEnc.actualTableLog)
ll.flush(llEnc.actualTableLog) ll.flush(llEnc.actualTableLog)
err = wr.close() wr.close()
if err != nil {
return err
}
b.output = wr.out b.output = wr.out
// Maybe even add a bigger margin. // Maybe even add a bigger margin.

View File

@ -1,10 +1,13 @@
package zstd package zstd
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"sort"
"github.com/klauspost/compress/huff0" "github.com/klauspost/compress/huff0"
) )
@ -14,9 +17,8 @@ type dict struct {
litEnc *huff0.Scratch litEnc *huff0.Scratch
llDec, ofDec, mlDec sequenceDec llDec, ofDec, mlDec sequenceDec
//llEnc, ofEnc, mlEnc []*fseEncoder offsets [3]int
offsets [3]int content []byte
content []byte
} }
const dictMagic = "\x37\xa4\x30\xec" const dictMagic = "\x37\xa4\x30\xec"
@ -159,3 +161,374 @@ func InspectDictionary(b []byte) (interface {
d, err := loadDict(b) d, err := loadDict(b)
return d, err return d, err
} }
type BuildDictOptions struct {
// Dictionary ID.
ID uint32
// Content to use to create dictionary tables.
Contents [][]byte
// History to use for all blocks.
History []byte
// Offsets to use.
Offsets [3]int
// CompatV155 will make the dictionary compatible with Zstd v1.5.5 and earlier.
// See https://github.com/facebook/zstd/issues/3724
CompatV155 bool
// Use the specified encoder level.
// The dictionary will be built using the specified encoder level,
// which will reflect speed and make the dictionary tailored for that level.
// If not set SpeedBestCompression will be used.
Level EncoderLevel
// DebugOut will write stats and other details here if set.
DebugOut io.Writer
}
func BuildDict(o BuildDictOptions) ([]byte, error) {
initPredefined()
hist := o.History
contents := o.Contents
debug := o.DebugOut != nil
println := func(args ...interface{}) {
if o.DebugOut != nil {
fmt.Fprintln(o.DebugOut, args...)
}
}
printf := func(s string, args ...interface{}) {
if o.DebugOut != nil {
fmt.Fprintf(o.DebugOut, s, args...)
}
}
print := func(args ...interface{}) {
if o.DebugOut != nil {
fmt.Fprint(o.DebugOut, args...)
}
}
if int64(len(hist)) > dictMaxLength {
return nil, fmt.Errorf("dictionary of size %d > %d", len(hist), int64(dictMaxLength))
}
if len(hist) < 8 {
return nil, fmt.Errorf("dictionary of size %d < %d", len(hist), 8)
}
if len(contents) == 0 {
return nil, errors.New("no content provided")
}
d := dict{
id: o.ID,
litEnc: nil,
llDec: sequenceDec{},
ofDec: sequenceDec{},
mlDec: sequenceDec{},
offsets: o.Offsets,
content: hist,
}
block := blockEnc{lowMem: false}
block.init()
enc := encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}})
if o.Level != 0 {
eOpts := encoderOptions{
level: o.Level,
blockSize: maxMatchLen,
windowSize: maxMatchLen,
dict: &d,
lowMem: false,
}
enc = eOpts.encoder()
} else {
o.Level = SpeedBestCompression
}
var (
remain [256]int
ll [256]int
ml [256]int
of [256]int
)
addValues := func(dst *[256]int, src []byte) {
for _, v := range src {
dst[v]++
}
}
addHist := func(dst *[256]int, src *[256]uint32) {
for i, v := range src {
dst[i] += int(v)
}
}
seqs := 0
nUsed := 0
litTotal := 0
newOffsets := make(map[uint32]int, 1000)
for _, b := range contents {
block.reset(nil)
if len(b) < 8 {
continue
}
nUsed++
enc.Reset(&d, true)
enc.Encode(&block, b)
addValues(&remain, block.literals)
litTotal += len(block.literals)
seqs += len(block.sequences)
block.genCodes()
addHist(&ll, block.coders.llEnc.Histogram())
addHist(&ml, block.coders.mlEnc.Histogram())
addHist(&of, block.coders.ofEnc.Histogram())
for i, seq := range block.sequences {
if i > 3 {
break
}
offset := seq.offset
if offset == 0 {
continue
}
if offset > 3 {
newOffsets[offset-3]++
} else {
newOffsets[uint32(o.Offsets[offset-1])]++
}
}
}
// Find most used offsets.
var sortedOffsets []uint32
for k := range newOffsets {
sortedOffsets = append(sortedOffsets, k)
}
sort.Slice(sortedOffsets, func(i, j int) bool {
a, b := sortedOffsets[i], sortedOffsets[j]
if a == b {
// Prefer the longer offset
return sortedOffsets[i] > sortedOffsets[j]
}
return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]]
})
if len(sortedOffsets) > 3 {
if debug {
print("Offsets:")
for i, v := range sortedOffsets {
if i > 20 {
break
}
printf("[%d: %d],", v, newOffsets[v])
}
println("")
}
sortedOffsets = sortedOffsets[:3]
}
for i, v := range sortedOffsets {
o.Offsets[i] = int(v)
}
if debug {
println("New repeat offsets", o.Offsets)
}
if nUsed == 0 || seqs == 0 {
return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs)
}
if debug {
println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal)
}
if seqs/nUsed < 512 {
// Use 512 as minimum.
nUsed = seqs / 512
}
copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) {
hist := dst.Histogram()
var maxSym uint8
var maxCount int
var fakeLength int
for i, v := range src {
if v > 0 {
v = v / nUsed
if v == 0 {
v = 1
}
}
if v > maxCount {
maxCount = v
}
if v != 0 {
maxSym = uint8(i)
}
fakeLength += v
hist[i] = uint32(v)
}
dst.HistogramFinished(maxSym, maxCount)
dst.reUsed = false
dst.useRLE = false
err := dst.normalizeCount(fakeLength)
if err != nil {
return nil, err
}
if debug {
println("RAW:", dst.count[:maxSym+1], "NORM:", dst.norm[:maxSym+1], "LEN:", fakeLength)
}
return dst.writeCount(nil)
}
if debug {
print("Literal lengths: ")
}
llTable, err := copyHist(block.coders.llEnc, &ll)
if err != nil {
return nil, err
}
if debug {
print("Match lengths: ")
}
mlTable, err := copyHist(block.coders.mlEnc, &ml)
if err != nil {
return nil, err
}
if debug {
print("Offsets: ")
}
ofTable, err := copyHist(block.coders.ofEnc, &of)
if err != nil {
return nil, err
}
// Literal table
avgSize := litTotal
if avgSize > huff0.BlockSizeMax/2 {
avgSize = huff0.BlockSizeMax / 2
}
huffBuff := make([]byte, 0, avgSize)
// Target size
div := litTotal / avgSize
if div < 1 {
div = 1
}
if debug {
println("Huffman weights:")
}
for i, n := range remain[:] {
if n > 0 {
n = n / div
// Allow all entries to be represented.
if n == 0 {
n = 1
}
huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
if debug {
printf("[%d: %d], ", i, n)
}
}
}
if o.CompatV155 && remain[255]/div == 0 {
huffBuff = append(huffBuff, 255)
}
scratch := &huff0.Scratch{TableLog: 11}
for tries := 0; tries < 255; tries++ {
scratch = &huff0.Scratch{TableLog: 11}
_, _, err = huff0.Compress1X(huffBuff, scratch)
if err == nil {
break
}
if debug {
printf("Try %d: Huffman error: %v\n", tries+1, err)
}
huffBuff = huffBuff[:0]
if tries == 250 {
if debug {
println("Huffman: Bailing out with predefined table")
}
// Bail out.... Just generate something
huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...)
for i := 0; i < 128; i++ {
huffBuff = append(huffBuff, byte(i))
}
continue
}
if errors.Is(err, huff0.ErrIncompressible) {
// Try truncating least common.
for i, n := range remain[:] {
if n > 0 {
n = n / (div * (i + 1))
if n > 0 {
huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
}
}
}
if o.CompatV155 && len(huffBuff) > 0 && huffBuff[len(huffBuff)-1] != 255 {
huffBuff = append(huffBuff, 255)
}
if len(huffBuff) == 0 {
huffBuff = append(huffBuff, 0, 255)
}
}
if errors.Is(err, huff0.ErrUseRLE) {
for i, n := range remain[:] {
n = n / (div * (i + 1))
// Allow all entries to be represented.
if n == 0 {
n = 1
}
huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
}
}
}
var out bytes.Buffer
out.Write([]byte(dictMagic))
out.Write(binary.LittleEndian.AppendUint32(nil, o.ID))
out.Write(scratch.OutTable)
if debug {
println("huff table:", len(scratch.OutTable), "bytes")
println("of table:", len(ofTable), "bytes")
println("ml table:", len(mlTable), "bytes")
println("ll table:", len(llTable), "bytes")
}
out.Write(ofTable)
out.Write(mlTable)
out.Write(llTable)
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[0])))
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1])))
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2])))
out.Write(hist)
if debug {
_, err := loadDict(out.Bytes())
if err != nil {
panic(err)
}
i, err := InspectDictionary(out.Bytes())
if err != nil {
panic(err)
}
println("ID:", i.ID())
println("Content size:", i.ContentSize())
println("Encoder:", i.LitEncoder() != nil)
println("Offsets:", i.Offsets())
var totalSize int
for _, b := range contents {
totalSize += len(b)
}
encWith := func(opts ...EOption) int {
enc, err := NewWriter(nil, opts...)
if err != nil {
panic(err)
}
defer enc.Close()
var dst []byte
var totalSize int
for _, b := range contents {
dst = enc.EncodeAll(b, dst[:0])
totalSize += len(dst)
}
return totalSize
}
plain := encWith(WithEncoderLevel(o.Level))
withDict := encWith(WithEncoderLevel(o.Level), WithEncoderDict(out.Bytes()))
println("Input size:", totalSize)
println("Plain Compressed:", plain)
println("Dict Compressed:", withDict)
println("Saved:", plain-withDict, (plain-withDict)/len(contents), "bytes per input (rounded down)")
}
return out.Bytes(), nil
}

View File

@ -197,12 +197,13 @@ encodeLoop:
// Set m to a match at offset if it looks like that will improve compression. // Set m to a match at offset if it looks like that will improve compression.
improve := func(m *match, offset int32, s int32, first uint32, rep int32) { improve := func(m *match, offset int32, s int32, first uint32, rep int32) {
if s-offset >= e.maxMatchOff || load3232(src, offset) != first { delta := s - offset
if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first {
return return
} }
if debugAsserts { if debugAsserts {
if offset <= 0 { if offset >= s {
panic(offset) panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff))
} }
if !bytes.Equal(src[s:s+4], src[offset:offset+4]) { if !bytes.Equal(src[s:s+4], src[offset:offset+4]) {
panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first))
@ -343,8 +344,8 @@ encodeLoop:
if best.rep > 0 { if best.rep > 0 {
var seq seq var seq seq
seq.matchLen = uint32(best.length - zstdMinMatch) seq.matchLen = uint32(best.length - zstdMinMatch)
if debugAsserts && s <= nextEmit { if debugAsserts && s < nextEmit {
panic("s <= nextEmit") panic("s < nextEmit")
} }
addLiterals(&seq, best.s) addLiterals(&seq, best.s)

View File

@ -227,10 +227,7 @@ func (e *Encoder) nextBlock(final bool) error {
DictID: e.o.dict.ID(), DictID: e.o.dict.ID(),
} }
dst, err := fh.appendTo(tmp[:0]) dst := fh.appendTo(tmp[:0])
if err != nil {
return err
}
s.headerWritten = true s.headerWritten = true
s.wWg.Wait() s.wWg.Wait()
var n2 int var n2 int
@ -483,7 +480,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
Checksum: false, Checksum: false,
DictID: 0, DictID: 0,
} }
dst, _ = fh.appendTo(dst) dst = fh.appendTo(dst)
// Write raw block as last one only. // Write raw block as last one only.
var blk blockHeader var blk blockHeader
@ -518,10 +515,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
if len(dst) == 0 && cap(dst) == 0 && len(src) < 1<<20 && !e.o.lowMem { if len(dst) == 0 && cap(dst) == 0 && len(src) < 1<<20 && !e.o.lowMem {
dst = make([]byte, 0, len(src)) dst = make([]byte, 0, len(src))
} }
dst, err := fh.appendTo(dst) dst = fh.appendTo(dst)
if err != nil {
panic(err)
}
// If we can do everything in one block, prefer that. // If we can do everything in one block, prefer that.
if len(src) <= e.o.blockSize { if len(src) <= e.o.blockSize {
@ -581,6 +575,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
// Add padding with content from crypto/rand.Reader // Add padding with content from crypto/rand.Reader
if e.o.pad > 0 { if e.o.pad > 0 {
add := calcSkippableFrame(int64(len(dst)), int64(e.o.pad)) add := calcSkippableFrame(int64(len(dst)), int64(e.o.pad))
var err error
dst, err = skippableFrame(dst, add, rand.Reader) dst, err = skippableFrame(dst, add, rand.Reader)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -22,7 +22,7 @@ type frameHeader struct {
const maxHeaderSize = 14 const maxHeaderSize = 14
func (f frameHeader) appendTo(dst []byte) ([]byte, error) { func (f frameHeader) appendTo(dst []byte) []byte {
dst = append(dst, frameMagic...) dst = append(dst, frameMagic...)
var fhd uint8 var fhd uint8
if f.Checksum { if f.Checksum {
@ -88,7 +88,7 @@ func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
default: default:
panic("invalid fcs") panic("invalid fcs")
} }
return dst, nil return dst
} }
const skippableFrameHeader = 4 + 4 const skippableFrameHeader = 4 + 4

View File

@ -245,7 +245,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
var ll, mo, ml int var ll, mo, ml int
if br.off > 4+((maxOffsetBits+16+16)>>3) { if len(br.in) > 4+((maxOffsetBits+16+16)>>3) {
// inlined function: // inlined function:
// ll, mo, ml = s.nextFast(br, llState, mlState, ofState) // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
@ -452,18 +452,13 @@ func (s *sequenceDecs) next(br *bitReader, llState, mlState, ofState decSymbol)
// extra bits are stored in reverse order. // extra bits are stored in reverse order.
br.fill() br.fill()
if s.maxBits <= 32 { mo += br.getBits(moB)
mo += br.getBits(moB) if s.maxBits > 32 {
ml += br.getBits(mlB)
ll += br.getBits(llB)
} else {
mo += br.getBits(moB)
br.fill() br.fill()
// matchlength+literal length, max 32 bits
ml += br.getBits(mlB)
ll += br.getBits(llB)
} }
// matchlength+literal length, max 32 bits
ml += br.getBits(mlB)
ll += br.getBits(llB)
mo = s.adjustOffset(mo, ll, moB) mo = s.adjustOffset(mo, ll, moB)
return return
} }

View File

@ -5,11 +5,11 @@
// func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
// Requires: CMOV // Requires: CMOV
TEXT ·sequenceDecs_decode_amd64(SB), $8-32 TEXT ·sequenceDecs_decode_amd64(SB), $8-32
MOVQ br+8(FP), AX MOVQ br+8(FP), CX
MOVQ 32(AX), DX MOVQ 24(CX), DX
MOVBQZX 40(AX), BX MOVBQZX 32(CX), BX
MOVQ 24(AX), SI MOVQ (CX), AX
MOVQ (AX), AX MOVQ 8(CX), SI
ADDQ SI, AX ADDQ SI, AX
MOVQ AX, (SP) MOVQ AX, (SP)
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -301,9 +301,9 @@ sequenceDecs_decode_amd64_match_len_ofs_ok:
MOVQ R12, 152(AX) MOVQ R12, 152(AX)
MOVQ R13, 160(AX) MOVQ R13, 160(AX)
MOVQ br+8(FP), AX MOVQ br+8(FP), AX
MOVQ DX, 32(AX) MOVQ DX, 24(AX)
MOVB BL, 40(AX) MOVB BL, 32(AX)
MOVQ SI, 24(AX) MOVQ SI, 8(AX)
// Return success // Return success
MOVQ $0x00000000, ret+24(FP) MOVQ $0x00000000, ret+24(FP)
@ -336,11 +336,11 @@ error_overread:
// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
// Requires: CMOV // Requires: CMOV
TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32 TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32
MOVQ br+8(FP), AX MOVQ br+8(FP), CX
MOVQ 32(AX), DX MOVQ 24(CX), DX
MOVBQZX 40(AX), BX MOVBQZX 32(CX), BX
MOVQ 24(AX), SI MOVQ (CX), AX
MOVQ (AX), AX MOVQ 8(CX), SI
ADDQ SI, AX ADDQ SI, AX
MOVQ AX, (SP) MOVQ AX, (SP)
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -603,9 +603,9 @@ sequenceDecs_decode_56_amd64_match_len_ofs_ok:
MOVQ R12, 152(AX) MOVQ R12, 152(AX)
MOVQ R13, 160(AX) MOVQ R13, 160(AX)
MOVQ br+8(FP), AX MOVQ br+8(FP), AX
MOVQ DX, 32(AX) MOVQ DX, 24(AX)
MOVB BL, 40(AX) MOVB BL, 32(AX)
MOVQ SI, 24(AX) MOVQ SI, 8(AX)
// Return success // Return success
MOVQ $0x00000000, ret+24(FP) MOVQ $0x00000000, ret+24(FP)
@ -638,11 +638,11 @@ error_overread:
// func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
// Requires: BMI, BMI2, CMOV // Requires: BMI, BMI2, CMOV
TEXT ·sequenceDecs_decode_bmi2(SB), $8-32 TEXT ·sequenceDecs_decode_bmi2(SB), $8-32
MOVQ br+8(FP), CX MOVQ br+8(FP), BX
MOVQ 32(CX), AX MOVQ 24(BX), AX
MOVBQZX 40(CX), DX MOVBQZX 32(BX), DX
MOVQ 24(CX), BX MOVQ (BX), CX
MOVQ (CX), CX MOVQ 8(BX), BX
ADDQ BX, CX ADDQ BX, CX
MOVQ CX, (SP) MOVQ CX, (SP)
MOVQ ctx+16(FP), CX MOVQ ctx+16(FP), CX
@ -892,9 +892,9 @@ sequenceDecs_decode_bmi2_match_len_ofs_ok:
MOVQ R11, 152(CX) MOVQ R11, 152(CX)
MOVQ R12, 160(CX) MOVQ R12, 160(CX)
MOVQ br+8(FP), CX MOVQ br+8(FP), CX
MOVQ AX, 32(CX) MOVQ AX, 24(CX)
MOVB DL, 40(CX) MOVB DL, 32(CX)
MOVQ BX, 24(CX) MOVQ BX, 8(CX)
// Return success // Return success
MOVQ $0x00000000, ret+24(FP) MOVQ $0x00000000, ret+24(FP)
@ -927,11 +927,11 @@ error_overread:
// func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
// Requires: BMI, BMI2, CMOV // Requires: BMI, BMI2, CMOV
TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32 TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32
MOVQ br+8(FP), CX MOVQ br+8(FP), BX
MOVQ 32(CX), AX MOVQ 24(BX), AX
MOVBQZX 40(CX), DX MOVBQZX 32(BX), DX
MOVQ 24(CX), BX MOVQ (BX), CX
MOVQ (CX), CX MOVQ 8(BX), BX
ADDQ BX, CX ADDQ BX, CX
MOVQ CX, (SP) MOVQ CX, (SP)
MOVQ ctx+16(FP), CX MOVQ ctx+16(FP), CX
@ -1152,9 +1152,9 @@ sequenceDecs_decode_56_bmi2_match_len_ofs_ok:
MOVQ R11, 152(CX) MOVQ R11, 152(CX)
MOVQ R12, 160(CX) MOVQ R12, 160(CX)
MOVQ br+8(FP), CX MOVQ br+8(FP), CX
MOVQ AX, 32(CX) MOVQ AX, 24(CX)
MOVB DL, 40(CX) MOVB DL, 32(CX)
MOVQ BX, 24(CX) MOVQ BX, 8(CX)
// Return success // Return success
MOVQ $0x00000000, ret+24(FP) MOVQ $0x00000000, ret+24(FP)
@ -1797,11 +1797,11 @@ empty_seqs:
// func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
// Requires: CMOV, SSE // Requires: CMOV, SSE
TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32 TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32
MOVQ br+8(FP), AX MOVQ br+8(FP), CX
MOVQ 32(AX), DX MOVQ 24(CX), DX
MOVBQZX 40(AX), BX MOVBQZX 32(CX), BX
MOVQ 24(AX), SI MOVQ (CX), AX
MOVQ (AX), AX MOVQ 8(CX), SI
ADDQ SI, AX ADDQ SI, AX
MOVQ AX, (SP) MOVQ AX, (SP)
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -2295,9 +2295,9 @@ handle_loop:
loop_finished: loop_finished:
MOVQ br+8(FP), AX MOVQ br+8(FP), AX
MOVQ DX, 32(AX) MOVQ DX, 24(AX)
MOVB BL, 40(AX) MOVB BL, 32(AX)
MOVQ SI, 24(AX) MOVQ SI, 8(AX)
// Update the context // Update the context
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -2362,11 +2362,11 @@ error_not_enough_space:
// func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
// Requires: BMI, BMI2, CMOV, SSE // Requires: BMI, BMI2, CMOV, SSE
TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32 TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32
MOVQ br+8(FP), CX MOVQ br+8(FP), BX
MOVQ 32(CX), AX MOVQ 24(BX), AX
MOVBQZX 40(CX), DX MOVBQZX 32(BX), DX
MOVQ 24(CX), BX MOVQ (BX), CX
MOVQ (CX), CX MOVQ 8(BX), BX
ADDQ BX, CX ADDQ BX, CX
MOVQ CX, (SP) MOVQ CX, (SP)
MOVQ ctx+16(FP), CX MOVQ ctx+16(FP), CX
@ -2818,9 +2818,9 @@ handle_loop:
loop_finished: loop_finished:
MOVQ br+8(FP), CX MOVQ br+8(FP), CX
MOVQ AX, 32(CX) MOVQ AX, 24(CX)
MOVB DL, 40(CX) MOVB DL, 32(CX)
MOVQ BX, 24(CX) MOVQ BX, 8(CX)
// Update the context // Update the context
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -2885,11 +2885,11 @@ error_not_enough_space:
// func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
// Requires: CMOV, SSE // Requires: CMOV, SSE
TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32 TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32
MOVQ br+8(FP), AX MOVQ br+8(FP), CX
MOVQ 32(AX), DX MOVQ 24(CX), DX
MOVBQZX 40(AX), BX MOVBQZX 32(CX), BX
MOVQ 24(AX), SI MOVQ (CX), AX
MOVQ (AX), AX MOVQ 8(CX), SI
ADDQ SI, AX ADDQ SI, AX
MOVQ AX, (SP) MOVQ AX, (SP)
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -3485,9 +3485,9 @@ handle_loop:
loop_finished: loop_finished:
MOVQ br+8(FP), AX MOVQ br+8(FP), AX
MOVQ DX, 32(AX) MOVQ DX, 24(AX)
MOVB BL, 40(AX) MOVB BL, 32(AX)
MOVQ SI, 24(AX) MOVQ SI, 8(AX)
// Update the context // Update the context
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX
@ -3552,11 +3552,11 @@ error_not_enough_space:
// func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
// Requires: BMI, BMI2, CMOV, SSE // Requires: BMI, BMI2, CMOV, SSE
TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32 TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32
MOVQ br+8(FP), CX MOVQ br+8(FP), BX
MOVQ 32(CX), AX MOVQ 24(BX), AX
MOVBQZX 40(CX), DX MOVBQZX 32(BX), DX
MOVQ 24(CX), BX MOVQ (BX), CX
MOVQ (CX), CX MOVQ 8(BX), BX
ADDQ BX, CX ADDQ BX, CX
MOVQ CX, (SP) MOVQ CX, (SP)
MOVQ ctx+16(FP), CX MOVQ ctx+16(FP), CX
@ -4110,9 +4110,9 @@ handle_loop:
loop_finished: loop_finished:
MOVQ br+8(FP), CX MOVQ br+8(FP), CX
MOVQ AX, 32(CX) MOVQ AX, 24(CX)
MOVB DL, 40(CX) MOVB DL, 32(CX)
MOVQ BX, 24(CX) MOVQ BX, 8(CX)
// Update the context // Update the context
MOVQ ctx+16(FP), AX MOVQ ctx+16(FP), AX

View File

@ -29,7 +29,7 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
} }
for i := range seqs { for i := range seqs {
var ll, mo, ml int var ll, mo, ml int
if br.off > 4+((maxOffsetBits+16+16)>>3) { if len(br.in) > 4+((maxOffsetBits+16+16)>>3) {
// inlined function: // inlined function:
// ll, mo, ml = s.nextFast(br, llState, mlState, ofState) // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)

View File

@ -95,10 +95,9 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
var written int64 var written int64
var readHeader bool var readHeader bool
{ {
var header []byte header := frameHeader{WindowSize: snappyMaxBlockSize}.appendTo(r.buf[:0])
var n int
header, r.err = frameHeader{WindowSize: snappyMaxBlockSize}.appendTo(r.buf[:0])
var n int
n, r.err = w.Write(header) n, r.err = w.Write(header)
if r.err != nil { if r.err != nil {
return written, r.err return written, r.err

1
vendor/github.com/libp2p/go-libp2p-mplex/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
*.swp

View File

@ -1,6 +1,6 @@
MIT License The MIT License (MIT)
Copyright (c) 2018 Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in
copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
SOFTWARE. THE SOFTWARE.

11
vendor/github.com/libp2p/go-libp2p-mplex/README.md generated vendored Normal file
View File

@ -0,0 +1,11 @@
# DEPRECATION NOTICE
mplex has been deprecated.
see https://github.com/libp2p/specs/issues/553 for details
# go-libp2p-mplex - a go-stream-muxer shim for multiplex
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) ![](https://raw.githubusercontent.com/libp2p/go-stream-muxer/master/img/badge.png)
This is an implementation of the [go-libp2p muxer](https://pkg.go.dev/github.com/libp2p/go-libp2p@v0.30.0/core/network#Multiplexer) interface for [multiplex](https://github.com/libp2p/go-mplex). For more information, see that repo.

View File

@ -1,3 +1,5 @@
// DEPRECATED: mplex has been deprecated. Users should prefer Yamux over mplex. see https://github.com/libp2p/specs/issues/553
// for details
package mplex package mplex
import ( import (

View File

@ -0,0 +1,3 @@
{
"version": "v0.9.0"
}

View File

@ -77,6 +77,9 @@ func (p *PubSub) handleNewStream(s network.Stream) {
return return
} }
if len(msgbytes) == 0 {
continue
}
rpc := new(RPC) rpc := new(RPC)
err = rpc.Unmarshal(msgbytes) err = rpc.Unmarshal(msgbytes)

View File

@ -1170,20 +1170,20 @@ func (gs *GossipSubRouter) sendRPC(p peer.ID, out *RPC) {
return return
} }
// If we're too big, fragment into multiple RPCs and send each sequentially // Potentially split the RPC into multiple RPCs that are below the max message size
outRPCs, err := fragmentRPC(out, gs.p.maxMessageSize) outRPCs := appendOrMergeRPC(nil, gs.p.maxMessageSize, *out)
if err != nil {
gs.doDropRPC(out, p, fmt.Sprintf("unable to fragment RPC: %s", err))
return
}
for _, rpc := range outRPCs { for _, rpc := range outRPCs {
if rpc.Size() > gs.p.maxMessageSize {
// This should only happen if a single message/control is above the maxMessageSize.
gs.doDropRPC(out, p, fmt.Sprintf("Dropping oversized RPC. Size: %d, limit: %d. (Over by %d bytes)", rpc.Size(), gs.p.maxMessageSize, rpc.Size()-gs.p.maxMessageSize))
continue
}
gs.doSendRPC(rpc, p, mch) gs.doSendRPC(rpc, p, mch)
} }
} }
func (gs *GossipSubRouter) doDropRPC(rpc *RPC, p peer.ID, reason string) { func (gs *GossipSubRouter) doDropRPC(rpc *RPC, p peer.ID, reason string) {
log.Debugf("dropping message to peer %s: %s", p.Pretty(), reason) log.Debugf("dropping message to peer %s: %s", p, reason)
gs.tracer.DropRPC(rpc, p) gs.tracer.DropRPC(rpc, p)
// push control messages that need to be retried // push control messages that need to be retried
ctl := rpc.GetControl() ctl := rpc.GetControl()
@ -1201,119 +1201,134 @@ func (gs *GossipSubRouter) doSendRPC(rpc *RPC, p peer.ID, mch chan *RPC) {
} }
} }
func fragmentRPC(rpc *RPC, limit int) ([]*RPC, error) { // appendOrMergeRPC appends the given RPCs to the slice, merging them if possible.
if rpc.Size() < limit { // If any elem is too large to fit in a single RPC, it will be split into multiple RPCs.
return []*RPC{rpc}, nil // If an RPC is too large and can't be split further (e.g. Message data is
// bigger than the RPC limit), then it will be returned as an oversized RPC.
// The caller should filter out oversized RPCs.
func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC {
if len(elems) == 0 {
return slice
} }
c := (rpc.Size() / limit) + 1 if len(slice) == 0 && len(elems) == 1 && elems[0].Size() < limit {
rpcs := make([]*RPC, 1, c) // Fast path: no merging needed and only one element
rpcs[0] = &RPC{RPC: pb.RPC{}, from: rpc.from} return append(slice, &elems[0])
}
// outRPC returns the current RPC message if it will fit sizeToAdd more bytes out := slice
// otherwise, it will create a new RPC message and add it to the list. if len(out) == 0 {
// if withCtl is true, the returned message will have a non-nil empty Control message. out = append(out, &RPC{RPC: pb.RPC{}})
outRPC := func(sizeToAdd int, withCtl bool) *RPC { out[0].from = elems[0].from
current := rpcs[len(rpcs)-1] }
// check if we can fit the new data, plus an extra byte for the protobuf field tag
if current.Size()+sizeToAdd+1 < limit { for _, elem := range elems {
if withCtl && current.Control == nil { lastRPC := out[len(out)-1]
current.Control = &pb.ControlMessage{}
// Merge/Append publish messages
// TODO: Never merge messages. The current behavior is the same as the
// old behavior. In the future let's not merge messages. Since,
// it may increase message latency.
for _, msg := range elem.GetPublish() {
if lastRPC.Publish = append(lastRPC.Publish, msg); lastRPC.Size() > limit {
lastRPC.Publish = lastRPC.Publish[:len(lastRPC.Publish)-1]
lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from}
lastRPC.Publish = append(lastRPC.Publish, msg)
out = append(out, lastRPC)
} }
return current
} }
var ctl *pb.ControlMessage
if withCtl { // Merge/Append Subscriptions
ctl = &pb.ControlMessage{} for _, sub := range elem.GetSubscriptions() {
if lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub); lastRPC.Size() > limit {
lastRPC.Subscriptions = lastRPC.Subscriptions[:len(lastRPC.Subscriptions)-1]
lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from}
lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub)
out = append(out, lastRPC)
}
} }
next := &RPC{RPC: pb.RPC{Control: ctl}, from: rpc.from}
rpcs = append(rpcs, next)
return next
}
for _, msg := range rpc.GetPublish() { // Merge/Append Control messages
s := msg.Size() if ctl := elem.GetControl(); ctl != nil {
// if an individual message is too large, we can't fragment it and have to fail entirely if lastRPC.Control == nil {
if s > limit { lastRPC.Control = &pb.ControlMessage{}
return nil, fmt.Errorf("message with len=%d exceeds limit %d", s, limit) if lastRPC.Size() > limit {
} lastRPC.Control = nil
out := outRPC(s, false) lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
out.Publish = append(out.Publish, msg) out = append(out, lastRPC)
} }
}
for _, sub := range rpc.GetSubscriptions() { for _, graft := range ctl.GetGraft() {
out := outRPC(sub.Size(), false) if lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft); lastRPC.Size() > limit {
out.Subscriptions = append(out.Subscriptions, sub) lastRPC.Control.Graft = lastRPC.Control.Graft[:len(lastRPC.Control.Graft)-1]
} lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft)
out = append(out, lastRPC)
}
}
ctl := rpc.GetControl() for _, prune := range ctl.GetPrune() {
if ctl == nil { if lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune); lastRPC.Size() > limit {
// if there were no control messages, we're done lastRPC.Control.Prune = lastRPC.Control.Prune[:len(lastRPC.Control.Prune)-1]
return rpcs, nil lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from}
} lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune)
// if all the control messages fit into one RPC, we just add it to the end and return out = append(out, lastRPC)
ctlOut := &RPC{RPC: pb.RPC{Control: ctl}, from: rpc.from} }
if ctlOut.Size() < limit { }
rpcs = append(rpcs, ctlOut)
return rpcs, nil
}
// we need to split up the control messages into multiple RPCs for _, iwant := range ctl.GetIwant() {
for _, graft := range ctl.Graft { if len(lastRPC.Control.Iwant) == 0 {
out := outRPC(graft.Size(), true) // Initialize with a single IWANT.
out.Control.Graft = append(out.Control.Graft, graft) // For IWANTs we don't need more than a single one,
} // since there are no topic IDs here.
for _, prune := range ctl.Prune { newIWant := &pb.ControlIWant{}
out := outRPC(prune.Size(), true) if lastRPC.Control.Iwant = append(lastRPC.Control.Iwant, newIWant); lastRPC.Size() > limit {
out.Control.Prune = append(out.Control.Prune, prune) lastRPC.Control.Iwant = lastRPC.Control.Iwant[:len(lastRPC.Control.Iwant)-1]
} lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
Iwant: []*pb.ControlIWant{newIWant},
}}, from: elem.from}
out = append(out, lastRPC)
}
}
for _, msgID := range iwant.GetMessageIDs() {
if lastRPC.Control.Iwant[0].MessageIDs = append(lastRPC.Control.Iwant[0].MessageIDs, msgID); lastRPC.Size() > limit {
lastRPC.Control.Iwant[0].MessageIDs = lastRPC.Control.Iwant[0].MessageIDs[:len(lastRPC.Control.Iwant[0].MessageIDs)-1]
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
Iwant: []*pb.ControlIWant{{MessageIDs: []string{msgID}}},
}}, from: elem.from}
out = append(out, lastRPC)
}
}
}
// An individual IWANT or IHAVE message could be larger than the limit if we have for _, ihave := range ctl.GetIhave() {
// a lot of message IDs. fragmentMessageIds will split them into buckets that if len(lastRPC.Control.Ihave) == 0 ||
// fit within the limit, with some overhead for the control messages themselves lastRPC.Control.Ihave[len(lastRPC.Control.Ihave)-1].TopicID != ihave.TopicID {
for _, iwant := range ctl.Iwant { // Start a new IHAVE if we are referencing a new topic ID
const protobufOverhead = 6 newIhave := &pb.ControlIHave{TopicID: ihave.TopicID}
idBuckets := fragmentMessageIds(iwant.MessageIDs, limit-protobufOverhead) if lastRPC.Control.Ihave = append(lastRPC.Control.Ihave, newIhave); lastRPC.Size() > limit {
for _, ids := range idBuckets { lastRPC.Control.Ihave = lastRPC.Control.Ihave[:len(lastRPC.Control.Ihave)-1]
iwant := &pb.ControlIWant{MessageIDs: ids} lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
out := outRPC(iwant.Size(), true) Ihave: []*pb.ControlIHave{newIhave},
out.Control.Iwant = append(out.Control.Iwant, iwant) }}, from: elem.from}
out = append(out, lastRPC)
}
}
for _, msgID := range ihave.GetMessageIDs() {
lastIHave := lastRPC.Control.Ihave[len(lastRPC.Control.Ihave)-1]
if lastIHave.MessageIDs = append(lastIHave.MessageIDs, msgID); lastRPC.Size() > limit {
lastIHave.MessageIDs = lastIHave.MessageIDs[:len(lastIHave.MessageIDs)-1]
lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{
Ihave: []*pb.ControlIHave{{TopicID: ihave.TopicID, MessageIDs: []string{msgID}}},
}}, from: elem.from}
out = append(out, lastRPC)
}
}
}
} }
} }
for _, ihave := range ctl.Ihave {
const protobufOverhead = 6
idBuckets := fragmentMessageIds(ihave.MessageIDs, limit-protobufOverhead)
for _, ids := range idBuckets {
ihave := &pb.ControlIHave{MessageIDs: ids}
out := outRPC(ihave.Size(), true)
out.Control.Ihave = append(out.Control.Ihave, ihave)
}
}
return rpcs, nil
}
func fragmentMessageIds(msgIds []string, limit int) [][]string {
// account for two bytes of protobuf overhead per array element
const protobufOverhead = 2
out := [][]string{{}}
var currentBucket int
var bucketLen int
for i := 0; i < len(msgIds); i++ {
size := len(msgIds[i]) + protobufOverhead
if size > limit {
// pathological case where a single message ID exceeds the limit.
log.Warnf("message ID length %d exceeds limit %d, removing from outgoing gossip", size, limit)
continue
}
bucketLen += size
if bucketLen > limit {
out = append(out, []string{})
currentBucket++
bucketLen = size
}
out[currentBucket] = append(out[currentBucket], msgIds[i])
}
return out return out
} }

View File

@ -13,18 +13,17 @@
<a href="https://marcopolo.github.io/FlakyTests/"><img src="https://marcopolo.github.io/FlakyTests/current-score.svg"/></a> <a href="https://marcopolo.github.io/FlakyTests/"><img src="https://marcopolo.github.io/FlakyTests/current-score.svg"/></a>
</p> </p>
# Table of Contents # Table of Contents <!-- omit in toc -->
- [Background](#background) - [Background](#background)
- [Roadmap](#roadmap) - [Roadmap](#roadmap)
- [Usage](#usage) - [Usage](#usage)
- [Examples](#examples) - [Examples](#examples)
- [Development](#development) - [Dashboards](#dashboards)
- [Tests](#tests)
- [Contribute](#contribute) - [Contribute](#contribute)
- [Supported Go Versions](#supported-go-versions) - [Supported Go Versions](#supported-go-versions)
- [Notable Users](#notable-users)
## Background # Background
[libp2p](https://github.com/libp2p/specs) is a networking stack and library modularized out of [The IPFS Project](https://github.com/ipfs/ipfs), and bundled separately for other tools to use. [libp2p](https://github.com/libp2p/specs) is a networking stack and library modularized out of [The IPFS Project](https://github.com/ipfs/ipfs), and bundled separately for other tools to use.
> >
@ -37,12 +36,12 @@ To learn more, check out the following resources:
- [**js-libp2p implementation**](https://github.com/libp2p/js-libp2p) - [**js-libp2p implementation**](https://github.com/libp2p/js-libp2p)
- [**rust-libp2p implementation**](https://github.com/libp2p/rust-libp2p) - [**rust-libp2p implementation**](https://github.com/libp2p/rust-libp2p)
## Roadmap # Roadmap
Our roadmap for go-libp2p can be found here: https://github.com/libp2p/go-libp2p/blob/master/ROADMAP.md Our roadmap for go-libp2p can be found here: https://github.com/libp2p/go-libp2p/blob/master/ROADMAP.md
This document represents current projects the go-libp2p team is focused on and provides an estimation of completion targets. It is a completementary roadmap to the overarching libp2p project roadmap: https://github.com/libp2p/specs/blob/master/ROADMAP.md This document represents current projects the go-libp2p team is focused on and provides an estimation of completion targets. It is a complementary roadmap to the overarching libp2p project roadmap: https://github.com/libp2p/specs/blob/master/ROADMAP.md
## Usage # Usage
This repository (`go-libp2p`) serves as the entrypoint to the universe of packages that compose the Go implementation of the libp2p stack. This repository (`go-libp2p`) serves as the entrypoint to the universe of packages that compose the Go implementation of the libp2p stack.
@ -52,10 +51,17 @@ You can start using go-libp2p in your Go application simply by adding imports fr
import "github.com/libp2p/go-libp2p" import "github.com/libp2p/go-libp2p"
``` ```
### Examples ## Examples
Examples can be found in the [examples folder](examples). Examples can be found in the [examples folder](examples).
## Dashboards
We provide prebuilt Grafana dashboards so that applications can better monitor libp2p in production.
You can find the [dashboard JSON files here](https://github.com/libp2p/go-libp2p/tree/master/dashboards).
We also have live [Public Dashboards](https://github.com/libp2p/go-libp2p/tree/master/dashboards/README.md#public-dashboards) that you can check out to see real time monitoring in action.
# Contribute # Contribute
@ -70,7 +76,7 @@ Guidelines:
- have fun! - have fun!
There's a few things you can do right now to help out: There's a few things you can do right now to help out:
- Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrasture behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically. - Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
- **Perform code reviews**. - **Perform code reviews**.
- **Add tests**. There can never be enough tests. - **Add tests**. There can never be enough tests.
@ -99,4 +105,4 @@ Some notable users of go-libp2p are:
- [Kairos](https://github.com/kairos-io/kairos) - A Kubernetes-focused, Cloud Native Linux meta-distribution. - [Kairos](https://github.com/kairos-io/kairos) - A Kubernetes-focused, Cloud Native Linux meta-distribution.
- [Oasis Core](https://github.com/oasisprotocol/oasis-core) - The consensus and runtime layers of the [Oasis protocol](https://oasisprotocol.org/). - [Oasis Core](https://github.com/oasisprotocol/oasis-core) - The consensus and runtime layers of the [Oasis protocol](https://oasisprotocol.org/).
Please open a pull request if you want your project to be added here. Please open a pull request if you want your project (min. 250 GitHub stars) to be added here.

View File

@ -261,6 +261,7 @@ func (cfg *Config) addTransports(h host.Host) error {
} }
fxopts = append(fxopts, fx.Provide(PrivKeyToStatelessResetKey)) fxopts = append(fxopts, fx.Provide(PrivKeyToStatelessResetKey))
fxopts = append(fxopts, fx.Provide(PrivKeyToTokenGeneratorKey))
if cfg.QUICReuse != nil { if cfg.QUICReuse != nil {
fxopts = append(fxopts, cfg.QUICReuse...) fxopts = append(fxopts, cfg.QUICReuse...)
} else { } else {
@ -295,6 +296,15 @@ func (cfg *Config) addTransports(h host.Host) error {
// //
// This function consumes the config. Do not reuse it (really!). // This function consumes the config. Do not reuse it (really!).
func (cfg *Config) NewNode() (host.Host, error) { func (cfg *Config) NewNode() (host.Host, error) {
// If possible check that the resource manager conn limit is higher than the
// limit set in the conn manager.
if l, ok := cfg.ResourceManager.(connmgr.GetConnLimiter); ok {
err := cfg.ConnManager.CheckLimit(l)
if err != nil {
log.Warn(fmt.Sprintf("rcmgr limit conflicts with connmgr limit: %v", err))
}
}
eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer)))) eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer))))
swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics) swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics)
if err != nil { if err != nil {
@ -419,6 +429,11 @@ func (cfg *Config) NewNode() (host.Host, error) {
PeerKey: autonatPrivKey, PeerKey: autonatPrivKey,
Peerstore: ps, Peerstore: ps,
DialRanker: swarm.NoDelayDialRanker, DialRanker: swarm.NoDelayDialRanker,
SwarmOpts: []swarm.Option{
// It is better to disable black hole detection and just attempt a dial for autonat
swarm.WithUDPBlackHoleConfig(false, 0, 0),
swarm.WithIPv6BlackHoleConfig(false, 0, 0),
},
} }
dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false) dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false)

View File

@ -11,7 +11,10 @@ import (
"github.com/quic-go/quic-go" "github.com/quic-go/quic-go"
) )
const statelessResetKeyInfo = "libp2p quic stateless reset key" const (
statelessResetKeyInfo = "libp2p quic stateless reset key"
tokenGeneratorKeyInfo = "libp2p quic token generator key"
)
func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, error) { func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, error) {
var statelessResetKey quic.StatelessResetKey var statelessResetKey quic.StatelessResetKey
@ -25,3 +28,16 @@ func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, err
} }
return statelessResetKey, nil return statelessResetKey, nil
} }
func PrivKeyToTokenGeneratorKey(key crypto.PrivKey) (quic.TokenGeneratorKey, error) {
var tokenKey quic.TokenGeneratorKey
keyBytes, err := key.Raw()
if err != nil {
return tokenKey, err
}
keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(tokenGeneratorKeyInfo))
if _, err := io.ReadFull(keyReader, tokenKey[:]); err != nil {
return tokenKey, err
}
return tokenKey, nil
}

View File

@ -74,6 +74,10 @@ type ConnManager interface {
// then it will return true if the peer is protected for any tag // then it will return true if the peer is protected for any tag
IsProtected(id peer.ID, tag string) (protected bool) IsProtected(id peer.ID, tag string) (protected bool)
// CheckLimit will return an error if the connection manager's internal
// connection limit exceeds the provided system limit.
CheckLimit(l GetConnLimiter) error
// Close closes the connection manager and stops background processes. // Close closes the connection manager and stops background processes.
Close() error Close() error
} }
@ -89,3 +93,9 @@ type TagInfo struct {
// Conns maps connection ids (such as remote multiaddr) to their creation time. // Conns maps connection ids (such as remote multiaddr) to their creation time.
Conns map[string]time.Time Conns map[string]time.Time
} }
// GetConnLimiter provides access to a component's total connection limit.
type GetConnLimiter interface {
// GetConnLimit returns the total connection limit of the implementing component.
GetConnLimit() int
}

View File

@ -21,4 +21,5 @@ func (NullConnMgr) Notifee() network.Notifiee { return network.Gl
func (NullConnMgr) Protect(peer.ID, string) {} func (NullConnMgr) Protect(peer.ID, string) {}
func (NullConnMgr) Unprotect(peer.ID, string) bool { return false } func (NullConnMgr) Unprotect(peer.ID, string) bool { return false }
func (NullConnMgr) IsProtected(peer.ID, string) bool { return false } func (NullConnMgr) IsProtected(peer.ID, string) bool { return false }
func (NullConnMgr) CheckLimit(l GetConnLimiter) error { return nil }
func (NullConnMgr) Close() error { return nil } func (NullConnMgr) Close() error { return nil }

View File

@ -12,8 +12,7 @@ import (
pb "github.com/libp2p/go-libp2p/core/crypto/pb" pb "github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/libp2p/go-libp2p/core/internal/catch" "github.com/libp2p/go-libp2p/core/internal/catch"
"github.com/libp2p/go-libp2p/internal/sha256"
"github.com/minio/sha256-simd"
) )
// ECDSAPrivateKey is an implementation of an ECDSA private key // ECDSAPrivateKey is an implementation of an ECDSA private key

View File

@ -10,8 +10,7 @@ import (
pb "github.com/libp2p/go-libp2p/core/crypto/pb" pb "github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/libp2p/go-libp2p/core/internal/catch" "github.com/libp2p/go-libp2p/core/internal/catch"
"github.com/libp2p/go-libp2p/internal/sha256"
"github.com/minio/sha256-simd"
) )
// RsaPrivateKey is a rsa private key // RsaPrivateKey is a rsa private key

View File

@ -9,7 +9,7 @@ import (
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
"github.com/minio/sha256-simd" "github.com/libp2p/go-libp2p/internal/sha256"
) )
// Secp256k1PrivateKey is a Secp256k1 private key // Secp256k1PrivateKey is a Secp256k1 private key

View File

@ -86,7 +86,7 @@ func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs. // AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs.
func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
p2ppart, err := ma.NewComponent("p2p", Encode(pi.ID)) p2ppart, err := ma.NewComponent("p2p", pi.ID.String())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -102,7 +102,7 @@ func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
func (pi *AddrInfo) Loggable() map[string]interface{} { func (pi *AddrInfo) Loggable() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"peerID": pi.ID.Pretty(), "peerID": pi.ID.String(),
"addrs": pi.Addrs, "addrs": pi.Addrs,
} }
} }

View File

@ -41,12 +41,6 @@ const maxInlineKeyLength = 42
// hash output as a multihash. See IDFromPublicKey for details. // hash output as a multihash. See IDFromPublicKey for details.
type ID string type ID string
// Pretty returns a base58-encoded string representation of the ID.
// Deprecated: use String() instead.
func (id ID) Pretty() string {
return id.String()
}
// Loggable returns a pretty peer ID string in loggable JSON format. // Loggable returns a pretty peer ID string in loggable JSON format.
func (id ID) Loggable() map[string]interface{} { func (id ID) Loggable() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
@ -145,16 +139,6 @@ func Decode(s string) (ID, error) {
return FromCid(c) return FromCid(c)
} }
// Encode encodes a peer ID as a string.
//
// At the moment, it base58 encodes the peer ID but, in the future, it will
// switch to encoding it as a CID by default.
//
// Deprecated: use id.String instead.
func Encode(id ID) string {
return id.String()
}
// FromCid converts a CID to a peer ID, if possible. // FromCid converts a CID to a peer ID, if possible.
func FromCid(c cid.Cid) (ID, error) { func FromCid(c cid.Cid) (ID, error) {
code := mc.Code(c.Type()) code := mc.Code(c.Type())

View File

@ -45,7 +45,7 @@ func (id ID) Size() int {
} }
func (id ID) MarshalJSON() ([]byte, error) { func (id ID) MarshalJSON() ([]byte, error) {
return json.Marshal(Encode(id)) return json.Marshal(id.String())
} }
func (id *ID) UnmarshalJSON(data []byte) (err error) { func (id *ID) UnmarshalJSON(data []byte) (err error) {
@ -59,7 +59,7 @@ func (id *ID) UnmarshalJSON(data []byte) (err error) {
// MarshalText returns the text encoding of the ID. // MarshalText returns the text encoding of the ID.
func (id ID) MarshalText() ([]byte, error) { func (id ID) MarshalText() ([]byte, error) {
return []byte(Encode(id)), nil return []byte(id.String()), nil
} }
// UnmarshalText restores the ID from its text encoding. // UnmarshalText restores the ID from its text encoding.

View File

@ -3,6 +3,7 @@ package sec
import ( import (
"context" "context"
"fmt"
"net" "net"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
@ -29,3 +30,14 @@ type SecureTransport interface {
// ID is the protocol ID of the security protocol. // ID is the protocol ID of the security protocol.
ID() protocol.ID ID() protocol.ID
} }
type ErrPeerIDMismatch struct {
Expected peer.ID
Actual peer.ID
}
func (e ErrPeerIDMismatch) Error() string {
return fmt.Sprintf("peer id mismatch: expected %s, but remote key matches %s", e.Expected, e.Actual)
}
var _ error = (*ErrPeerIDMismatch)(nil)

View File

@ -5,6 +5,7 @@ package transport
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net" "net"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
@ -124,3 +125,47 @@ type Upgrader interface {
// Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection. // Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection.
Upgrade(ctx context.Context, t Transport, maconn manet.Conn, dir network.Direction, p peer.ID, scope network.ConnManagementScope) (CapableConn, error) Upgrade(ctx context.Context, t Transport, maconn manet.Conn, dir network.Direction, p peer.ID, scope network.ConnManagementScope) (CapableConn, error)
} }
// DialUpdater provides updates on in progress dials.
type DialUpdater interface {
// DialWithUpdates dials a remote peer and provides updates on the passed channel.
DialWithUpdates(context.Context, ma.Multiaddr, peer.ID, chan<- DialUpdate) (CapableConn, error)
}
// DialUpdateKind indicates the type of DialUpdate event.
type DialUpdateKind int
const (
// UpdateKindDialFailed indicates dial failed.
UpdateKindDialFailed DialUpdateKind = iota
// UpdateKindDialSuccessful indicates dial succeeded.
UpdateKindDialSuccessful
// UpdateKindHandshakeProgressed indicates successful completion of the TCP 3-way
// handshake
UpdateKindHandshakeProgressed
)
func (k DialUpdateKind) String() string {
switch k {
case UpdateKindDialFailed:
return "DialFailed"
case UpdateKindDialSuccessful:
return "DialSuccessful"
case UpdateKindHandshakeProgressed:
return "UpdateKindHandshakeProgressed"
default:
return fmt.Sprintf("DialUpdateKind<Unknown-%d>", k)
}
}
// DialUpdate is used by DialUpdater to provide dial updates.
type DialUpdate struct {
// Kind is the kind of update event.
Kind DialUpdateKind
// Addr is the peer's address.
Addr ma.Multiaddr
// Conn is the resulting connection on success.
Conn CapableConn
// Err is the reason for dial failure.
Err error
}

View File

@ -79,11 +79,9 @@ var RandomIdentity = func(cfg *Config) error {
var DefaultListenAddrs = func(cfg *Config) error { var DefaultListenAddrs = func(cfg *Config) error {
addrs := []string{ addrs := []string{
"/ip4/0.0.0.0/tcp/0", "/ip4/0.0.0.0/tcp/0",
"/ip4/0.0.0.0/udp/0/quic",
"/ip4/0.0.0.0/udp/0/quic-v1", "/ip4/0.0.0.0/udp/0/quic-v1",
"/ip4/0.0.0.0/udp/0/quic-v1/webtransport", "/ip4/0.0.0.0/udp/0/quic-v1/webtransport",
"/ip6/::/tcp/0", "/ip6/::/tcp/0",
"/ip6/::/udp/0/quic",
"/ip6/::/udp/0/quic-v1", "/ip6/::/udp/0/quic-v1",
"/ip6/::/udp/0/quic-v1/webtransport", "/ip6/::/udp/0/quic-v1/webtransport",
} }

View File

@ -0,0 +1,23 @@
//go:build go1.21
// This package use build tags to select between github.com/minio/sha256-simd
// for go1.20 and bellow and crypto/sha256 for go1.21 and above.
// This is used because a fast SHANI implementation of sha256 is only avaiable
// in the std for go1.21 and above. See https://go.dev/issue/50543.
// TODO: Once go1.22 releases remove this package and replace all uses
// with crypto/sha256 because the two supported version of go will have the fast
// implementation.
package sha256
import (
"crypto/sha256"
"hash"
)
func Sum256(b []byte) [sha256.Size]byte {
return sha256.Sum256(b)
}
func New() hash.Hash {
return sha256.New()
}

View File

@ -0,0 +1,24 @@
//go:build !go1.21
// This package use build tags to select between github.com/minio/sha256-simd
// for go1.20 and bellow and crypto/sha256 for go1.21 and above.
// This is used because a fast SHANI implementation of sha256 is only avaiable
// in the std for go1.21 and above. See https://go.dev/issue/50543.
// TODO: Once go1.22 releases remove this package and replace all uses
// with crypto/sha256 because the two supported version of go will have the fast
// implementation.
package sha256
import (
"hash"
"github.com/minio/sha256-simd"
)
func Sum256(b []byte) [sha256.Size]byte {
return sha256.Sum256(b)
}
func New() hash.Hash {
return sha256.New()
}

View File

@ -579,6 +579,7 @@ func PrometheusRegisterer(reg prometheus.Registerer) Option {
// DialRanker configures libp2p to use d as the dial ranker. To enable smart // DialRanker configures libp2p to use d as the dial ranker. To enable smart
// dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to // dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to
// disable smart dialing. // disable smart dialing.
//
// Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead // Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead
func DialRanker(d network.DialRanker) Option { func DialRanker(d network.DialRanker) Option {
return func(cfg *Config) error { return func(cfg *Config) error {

View File

@ -68,7 +68,7 @@ func (as *autoNATService) handleStream(s network.Stream) {
defer s.Close() defer s.Close()
pid := s.Conn().RemotePeer() pid := s.Conn().RemotePeer()
log.Debugf("New stream from %s", pid.Pretty()) log.Debugf("New stream from %s", pid)
r := pbio.NewDelimitedReader(s, maxMsgSize) r := pbio.NewDelimitedReader(s, maxMsgSize)
w := pbio.NewDelimitedWriter(s) w := pbio.NewDelimitedWriter(s)
@ -78,14 +78,14 @@ func (as *autoNATService) handleStream(s network.Stream) {
err := r.ReadMsg(&req) err := r.ReadMsg(&req)
if err != nil { if err != nil {
log.Debugf("Error reading message from %s: %s", pid.Pretty(), err.Error()) log.Debugf("Error reading message from %s: %s", pid, err.Error())
s.Reset() s.Reset()
return return
} }
t := req.GetType() t := req.GetType()
if t != pb.Message_DIAL { if t != pb.Message_DIAL {
log.Debugf("Unexpected message from %s: %s (%d)", pid.Pretty(), t.String(), t) log.Debugf("Unexpected message from %s: %s (%d)", pid, t.String(), t)
s.Reset() s.Reset()
return return
} }
@ -96,7 +96,7 @@ func (as *autoNATService) handleStream(s network.Stream) {
err = w.WriteMsg(&res) err = w.WriteMsg(&res)
if err != nil { if err != nil {
log.Debugf("Error writing response to %s: %s", pid.Pretty(), err.Error()) log.Debugf("Error writing response to %s: %s", pid, err.Error())
s.Reset() s.Reset()
return return
} }
@ -234,7 +234,7 @@ func (as *autoNATService) doDial(pi peer.AddrInfo) *pb.Message_DialResponse {
conn, err := as.config.dialer.DialPeer(ctx, pi.ID) conn, err := as.config.dialer.DialPeer(ctx, pi.ID)
if err != nil { if err != nil {
log.Debugf("error dialing %s: %s", pi.ID.Pretty(), err.Error()) log.Debugf("error dialing %s: %s", pi.ID, err.Error())
// wait for the context to timeout to avoid leaking timing information // wait for the context to timeout to avoid leaking timing information
// this renders the service ineffective as a port scanner // this renders the service ineffective as a port scanner
<-ctx.Done() <-ctx.Done()

View File

@ -736,7 +736,7 @@ func (rf *relayFinder) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
for p := range rf.relays { for p := range rf.relays {
addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p)) addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p))
relayAddrCnt += len(addrs) relayAddrCnt += len(addrs)
circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p.Pretty())) circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p))
for _, addr := range addrs { for _, addr := range addrs {
pub := addr.Encapsulate(circuit) pub := addr.Encapsulate(circuit)
raddrs = append(raddrs, pub) raddrs = append(raddrs, pub)

View File

@ -437,7 +437,7 @@ func (h *BasicHost) newStreamHandler(s network.Stream) {
log.Debugf("negotiated: %s (took %s)", protoID, took) log.Debugf("negotiated: %s (took %s)", protoID, took)
go handle(protoID, s) handle(protoID, s)
} }
// SignalAddressChange signals to the host that it needs to determine whether our listen addresses have recently // SignalAddressChange signals to the host that it needs to determine whether our listen addresses have recently
@ -629,9 +629,6 @@ func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) {
// to create one. If ProtocolID is "", writes no header. // to create one. If ProtocolID is "", writes no header.
// (Thread-safe) // (Thread-safe)
func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error) { func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error) {
// Ensure we have a connection, with peer addresses resolved by the routing system (#207)
// It is not sufficient to let the underlying host connect, it will most likely not have
// any addresses for the peer without any prior connections.
// If the caller wants to prevent the host from dialing, it should use the NoDial option. // If the caller wants to prevent the host from dialing, it should use the NoDial option.
if nodial, _ := network.GetNoDial(ctx); !nodial { if nodial, _ := network.GetNoDial(ctx); !nodial {
err := h.Connect(ctx, peer.AddrInfo{ID: p}) err := h.Connect(ctx, peer.AddrInfo{ID: p})
@ -669,7 +666,9 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I
} }
if pref != "" { if pref != "" {
s.SetProtocol(pref) if err := s.SetProtocol(pref); err != nil {
return nil, err
}
lzcon := msmux.NewMSSelect(s, pref) lzcon := msmux.NewMSSelect(s, pref)
return &streamWrapper{ return &streamWrapper{
Stream: s, Stream: s,
@ -795,10 +794,11 @@ func (h *BasicHost) Addrs() []ma.Multiaddr {
continue continue
} }
addrWithCerthash, added := tpt.AddCertHashes(addr) addrWithCerthash, added := tpt.AddCertHashes(addr)
addrs[i] = addrWithCerthash
if !added { if !added {
log.Debug("Couldn't add certhashes to webtransport multiaddr because we aren't listening on webtransport") log.Debug("Couldn't add certhashes to webtransport multiaddr because we aren't listening on webtransport")
continue
} }
addrs[i] = addrWithCerthash
} }
} }
return addrs return addrs
@ -945,17 +945,17 @@ func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr {
// Remove certhashes // Remove certhashes
addr, _ = ma.SplitLast(addr) addr, _ = ma.SplitLast(addr)
} }
webtransportAddrs[addr.String()] = struct{}{} webtransportAddrs[string(addr.Bytes())] = struct{}{}
// Remove webtransport component, now it's a multiaddr that ends in /quic-v1 // Remove webtransport component, now it's a multiaddr that ends in /quic-v1
addr, _ = ma.SplitLast(addr) addr, _ = ma.SplitLast(addr)
} }
if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 { if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 {
addrStr := addr.String() bytes := addr.Bytes()
if _, ok := quicOrWebtransportAddrs[addrStr]; ok { if _, ok := quicOrWebtransportAddrs[string(bytes)]; ok {
foundSameListeningAddr = true foundSameListeningAddr = true
} else { } else {
quicOrWebtransportAddrs[addrStr] = struct{}{} quicOrWebtransportAddrs[string(bytes)] = struct{}{}
} }
} }
} }
@ -977,7 +977,7 @@ func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr {
if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 { if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 {
// Convert quic to webtransport // Convert quic to webtransport
addr = addr.Encapsulate(wtComponent) addr = addr.Encapsulate(wtComponent)
if _, ok := webtransportAddrs[addr.String()]; ok { if _, ok := webtransportAddrs[string(addr.Bytes())]; ok {
// We already have this address // We already have this address
continue continue
} }

View File

@ -2,5 +2,5 @@
package basichost package basichost
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT" //go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT"
type NAT nat type NAT nat

View File

@ -210,7 +210,7 @@ func (bh *BlankHost) newStreamHandler(s network.Stream) {
s.SetProtocol(protoID) s.SetProtocol(protoID)
go handle(protoID, s) handle(protoID, s)
} }
// TODO: i'm not sure this really needs to be here // TODO: i'm not sure this really needs to be here

View File

@ -541,7 +541,7 @@ works best.
## Examples ## Examples
Here we consider some concrete examples that can ellucidate the abstract Here we consider some concrete examples that can elucidate the abstract
design as described so far. design as described so far.
### Stream Lifetime ### Stream Lifetime
@ -578,7 +578,7 @@ More specifically the following constraints apply:
- the peer scope, where the limits for the peer at the other end of the stream - the peer scope, where the limits for the peer at the other end of the stream
apply. apply.
- the service scope, where the limits of the specific service owning the stream apply. - the service scope, where the limits of the specific service owning the stream apply.
- the protcol scope, where the limits of the specific protocol for the stream apply. - the protocol scope, where the limits of the specific protocol for the stream apply.
The resource transfer that happens in the `SetProtocol` and `SetService` The resource transfer that happens in the `SetProtocol` and `SetService`

View File

@ -145,3 +145,7 @@ func (r *resourceManager) Stat() (result ResourceManagerStat) {
return result return result
} }
func (r *resourceManager) GetConnLimit() int {
return r.limits.GetConnLimits().GetConnTotalLimit()
}

View File

@ -2,7 +2,7 @@ package metricshelper
import ma "github.com/multiformats/go-multiaddr" import ma "github.com/multiformats/go-multiaddr"
var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP} var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBRTC_DIRECT, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP}
func GetTransport(a ma.Multiaddr) string { func GetTransport(a ma.Multiaddr) string {
for _, t := range transports { for _, t := range transports {

View File

@ -2,6 +2,7 @@ package connmgr
import ( import (
"context" "context"
"fmt"
"sort" "sort"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -239,6 +240,17 @@ func (cm *BasicConnMgr) IsProtected(id peer.ID, tag string) (protected bool) {
return protected return protected
} }
func (cm *BasicConnMgr) CheckLimit(systemLimit connmgr.GetConnLimiter) error {
if cm.cfg.highWater > systemLimit.GetConnLimit() {
return fmt.Errorf(
"conn manager high watermark limit: %d, exceeds the system connection limit of: %d",
cm.cfg.highWater,
systemLimit.GetConnLimit(),
)
}
return nil
}
// peerInfo stores metadata for a given peer. // peerInfo stores metadata for a given peer.
type peerInfo struct { type peerInfo struct {
id peer.ID id peer.ID

View File

@ -320,7 +320,7 @@ func (t *decayingTag) Bump(p peer.ID, delta int) error {
default: default:
return fmt.Errorf( return fmt.Errorf(
"unable to bump decaying tag for peer %s, tag %s, delta %d; queue full (len=%d)", "unable to bump decaying tag for peer %s, tag %s, delta %d; queue full (len=%d)",
p.Pretty(), t.name, delta, len(t.trkr.bumpTagCh)) p, t.name, delta, len(t.trkr.bumpTagCh))
} }
} }
@ -337,7 +337,7 @@ func (t *decayingTag) Remove(p peer.ID) error {
default: default:
return fmt.Errorf( return fmt.Errorf(
"unable to remove decaying tag for peer %s, tag %s; queue full (len=%d)", "unable to remove decaying tag for peer %s, tag %s; queue full (len=%d)",
p.Pretty(), t.name, len(t.trkr.removeTagCh)) p, t.name, len(t.trkr.removeTagCh))
} }
} }

View File

@ -1,39 +0,0 @@
package swarm
import (
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
var lowTimeoutFilters = ma.NewFilters()
func init() {
for _, p := range []string{
"/ip4/10.0.0.0/ipcidr/8",
"/ip4/100.64.0.0/ipcidr/10",
"/ip4/169.254.0.0/ipcidr/16",
"/ip4/172.16.0.0/ipcidr/12",
"/ip4/192.0.0.0/ipcidr/24",
"/ip4/192.0.0.0/ipcidr/29",
"/ip4/192.0.0.8/ipcidr/32",
"/ip4/192.0.0.170/ipcidr/32",
"/ip4/192.0.0.171/ipcidr/32",
"/ip4/192.0.2.0/ipcidr/24",
"/ip4/192.168.0.0/ipcidr/16",
"/ip4/198.18.0.0/ipcidr/15",
"/ip4/198.51.100.0/ipcidr/24",
"/ip4/203.0.113.0/ipcidr/24",
"/ip4/240.0.0.0/ipcidr/4",
} {
f, err := ma.NewMultiaddr(p)
if err != nil {
panic("error in lowTimeoutFilters init: " + err.Error())
}
ipnet, err := manet.MultiaddrToIPNet(f)
if err != nil {
panic("error in lowTimeoutFilters init: " + err.Error())
}
lowTimeoutFilters.AddFilter(*ipnet, ma.ActionDeny)
}
}

View File

@ -178,7 +178,7 @@ type blackHoleDetector struct {
} }
// FilterAddrs filters the peer's addresses removing black holed addresses // FilterAddrs filters the peer's addresses removing black holed addresses
func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) (valid []ma.Multiaddr, blackHoled []ma.Multiaddr) {
hasUDP, hasIPv6 := false, false hasUDP, hasIPv6 := false, false
for _, a := range addrs { for _, a := range addrs {
if !manet.IsPublicAddr(a) { if !manet.IsPublicAddr(a) {
@ -202,6 +202,7 @@ func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
ipv6Res = d.ipv6.HandleRequest() ipv6Res = d.ipv6.HandleRequest()
} }
blackHoled = make([]ma.Multiaddr, 0, len(addrs))
return ma.FilterAddrs( return ma.FilterAddrs(
addrs, addrs,
func(a ma.Multiaddr) bool { func(a ma.Multiaddr) bool {
@ -218,14 +219,16 @@ func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
} }
if udpRes == blackHoleResultBlocked && isProtocolAddr(a, ma.P_UDP) { if udpRes == blackHoleResultBlocked && isProtocolAddr(a, ma.P_UDP) {
blackHoled = append(blackHoled, a)
return false return false
} }
if ipv6Res == blackHoleResultBlocked && isProtocolAddr(a, ma.P_IP6) { if ipv6Res == blackHoleResultBlocked && isProtocolAddr(a, ma.P_IP6) {
blackHoled = append(blackHoled, a)
return false return false
} }
return true return true
}, },
) ), blackHoled
} }
// RecordResult updates the state of the relevant `blackHoleFilter`s for addr // RecordResult updates the state of the relevant `blackHoleFilter`s for addr

View File

@ -30,10 +30,7 @@ func (e *DialError) recordErr(addr ma.Multiaddr, err error) {
e.Skipped++ e.Skipped++
return return
} }
e.DialErrors = append(e.DialErrors, TransportError{ e.DialErrors = append(e.DialErrors, TransportError{Address: addr, Cause: err})
Address: addr,
Cause: err,
})
} }
func (e *DialError) Error() string { func (e *DialError) Error() string {
@ -51,9 +48,19 @@ func (e *DialError) Error() string {
return builder.String() return builder.String()
} }
// Unwrap implements https://godoc.org/golang.org/x/xerrors#Wrapper. func (e *DialError) Unwrap() []error {
func (e *DialError) Unwrap() error { if e == nil {
return e.Cause return nil
}
errs := make([]error, len(e.DialErrors)+1)
if e.Cause != nil {
errs = append(errs, e.Cause)
}
for i := 0; i < len(e.DialErrors); i++ {
errs = append(errs, &e.DialErrors[i])
}
return errs
} }
var _ error = (*DialError)(nil) var _ error = (*DialError)(nil)
@ -68,4 +75,8 @@ func (e *TransportError) Error() string {
return fmt.Sprintf("failed to dial %s: %s", e.Address, e.Cause) return fmt.Sprintf("failed to dial %s: %s", e.Address, e.Cause)
} }
func (e *TransportError) Unwrap() error {
return e.Cause
}
var _ error = (*TransportError)(nil) var _ error = (*TransportError)(nil)

View File

@ -58,8 +58,19 @@ func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay {
// 3. If a QUIC or WebTransport address is present, TCP addresses dials are delayed relative to the last QUIC dial: // 3. If a QUIC or WebTransport address is present, TCP addresses dials are delayed relative to the last QUIC dial:
// We prefer to end up with a QUIC connection. For public addresses, the delay introduced is 250ms (PublicTCPDelay), // We prefer to end up with a QUIC connection. For public addresses, the delay introduced is 250ms (PublicTCPDelay),
// and for private addresses 30ms (PrivateTCPDelay). // and for private addresses 30ms (PrivateTCPDelay).
// 4. For the TCP addresses we follow a strategy similar to QUIC with an optimisation for handling the long TCP
// handshake time described in 6. If both IPv6 TCP and IPv4 TCP addresses are present, we do a Happy Eyeballs
// style ranking. First dial the IPv6 TCP address with the lowest port. After this, dial the IPv4 TCP address
// with the lowest port delayed by 250ms (PublicTCPDelay) for public addresses, and 30ms (PrivateTCPDelay)
// for local addresses. After this we dial all the rest of the addresses delayed by 250ms (PublicTCPDelay) for
// public addresses, and 30ms (PrivateTCPDelay) for local addresses.
// 5. If only one of TCP IPv6 or TCP IPv4 addresses are present, dial the TCP address with the lowest port
// first. After this we dial the rest of the TCP addresses delayed by 250ms (PublicTCPDelay) for public
// addresses, and 30ms (PrivateTCPDelay) for local addresses.
// 6. When a TCP socket is connected and awaiting security and muxer upgrade, we stop new dials for 2*PrivateTCPDelay
// to allow for the upgrade to complete.
// //
// We dial lowest ports first for QUIC addresses as they are more likely to be the listen port. // We dial lowest ports first as they are more likely to be the listen port.
func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay {
relay, addrs := filterAddrs(addrs, isRelayAddr) relay, addrs := filterAddrs(addrs, isRelayAddr)
pvt, addrs := filterAddrs(addrs, manet.IsPrivateAddr) pvt, addrs := filterAddrs(addrs, manet.IsPrivateAddr)
@ -88,22 +99,57 @@ func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay {
// addresses relative to direct addresses. // addresses relative to direct addresses.
func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.Duration, func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.Duration,
offset time.Duration) []network.AddrDelay { offset time.Duration) []network.AddrDelay {
if len(addrs) == 0 {
return nil
}
sort.Slice(addrs, func(i, j int) bool { return score(addrs[i]) < score(addrs[j]) }) sort.Slice(addrs, func(i, j int) bool { return score(addrs[i]) < score(addrs[j]) })
// If the first address is (QUIC, IPv6), make the second address (QUIC, IPv4). // addrs is now sorted by (Transport, IPVersion). Reorder addrs for happy eyeballs dialing.
happyEyeballs := false // For QUIC and TCP, if we have both IPv6 and IPv4 addresses, move the
if len(addrs) > 0 { // highest priority IPv4 address to the second position.
happyEyeballsQUIC := false
happyEyeballsTCP := false
// tcpStartIdx is the index of the first TCP Address
var tcpStartIdx int
{
i := 0
// If the first QUIC address is IPv6 move the first QUIC IPv4 address to second position
if isQUICAddr(addrs[0]) && isProtocolAddr(addrs[0], ma.P_IP6) { if isQUICAddr(addrs[0]) && isProtocolAddr(addrs[0], ma.P_IP6) {
for i := 1; i < len(addrs); i++ { for j := 1; j < len(addrs); j++ {
if isQUICAddr(addrs[i]) && isProtocolAddr(addrs[i], ma.P_IP4) { if isQUICAddr(addrs[j]) && isProtocolAddr(addrs[j], ma.P_IP4) {
// make IPv4 address the second element // The first IPv4 address is at position j
if i > 1 { // Move the jth element at position 1 shifting the affected elements
a := addrs[i] if j > 1 {
copy(addrs[2:], addrs[1:i]) a := addrs[j]
copy(addrs[2:], addrs[1:j])
addrs[1] = a addrs[1] = a
} }
happyEyeballs = true happyEyeballsQUIC = true
i = j + 1
break
}
}
}
for tcpStartIdx = i; tcpStartIdx < len(addrs); tcpStartIdx++ {
if isProtocolAddr(addrs[tcpStartIdx], ma.P_TCP) {
break
}
}
// If the first TCP address is IPv6 move the first TCP IPv4 address to second position
if tcpStartIdx < len(addrs) && isProtocolAddr(addrs[tcpStartIdx], ma.P_IP6) {
for j := tcpStartIdx + 1; j < len(addrs); j++ {
if isProtocolAddr(addrs[j], ma.P_TCP) && isProtocolAddr(addrs[j], ma.P_IP4) {
// First TCP IPv4 address is at position j, move it to position tcpStartIdx+1
// which is the second priority TCP address
if j > tcpStartIdx+1 {
a := addrs[j]
copy(addrs[tcpStartIdx+2:], addrs[tcpStartIdx+1:j])
addrs[tcpStartIdx+1] = a
}
happyEyeballsTCP = true
break break
} }
} }
@ -111,25 +157,42 @@ func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.D
} }
res := make([]network.AddrDelay, 0, len(addrs)) res := make([]network.AddrDelay, 0, len(addrs))
var tcpFirstDialDelay time.Duration
var totalTCPDelay time.Duration
for i, addr := range addrs { for i, addr := range addrs {
var delay time.Duration var delay time.Duration
switch { switch {
case isQUICAddr(addr): case isQUICAddr(addr):
// For QUIC addresses we dial an IPv6 address, then after quicDelay an IPv4 // We dial an IPv6 address, then after quicDelay an IPv4
// address, then after quicDelay we dial rest of the addresses. // address, then after a further quicDelay we dial the rest of the addresses.
if i == 1 { if i == 1 {
delay = quicDelay delay = quicDelay
} }
if i > 1 && happyEyeballs { if i > 1 {
delay = 2 * quicDelay // If we have happy eyeballs for QUIC, dials after the second position
} else if i > 1 { // will be delayed by 2*quicDelay
delay = quicDelay if happyEyeballsQUIC {
delay = 2 * quicDelay
} else {
delay = quicDelay
}
} }
totalTCPDelay = delay + tcpDelay tcpFirstDialDelay = delay + tcpDelay
case isProtocolAddr(addr, ma.P_TCP): case isProtocolAddr(addr, ma.P_TCP):
delay = totalTCPDelay // We dial an IPv6 address, then after tcpDelay an IPv4
// address, then after a further tcpDelay we dial the rest of the addresses.
if i == tcpStartIdx+1 {
delay = tcpDelay
}
if i > tcpStartIdx+1 {
// If we have happy eyeballs for TCP, dials after the second position
// will be delayed by 2*tcpDelay
if happyEyeballsTCP {
delay = 2 * tcpDelay
} else {
delay = tcpDelay
}
}
delay += tcpFirstDialDelay
} }
res = append(res, network.AddrDelay{Addr: addr, Delay: offset + delay}) res = append(res, network.AddrDelay{Addr: addr, Delay: offset + delay})
} }

View File

@ -2,6 +2,7 @@ package swarm
import ( import (
"context" "context"
"errors"
"sync" "sync"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
@ -11,6 +12,9 @@ import (
// dialWorkerFunc is used by dialSync to spawn a new dial worker // dialWorkerFunc is used by dialSync to spawn a new dial worker
type dialWorkerFunc func(peer.ID, <-chan dialRequest) type dialWorkerFunc func(peer.ID, <-chan dialRequest)
// errConcurrentDialSuccessful is used to signal that a concurrent dial succeeded
var errConcurrentDialSuccessful = errors.New("concurrent dial successful")
// newDialSync constructs a new dialSync // newDialSync constructs a new dialSync
func newDialSync(worker dialWorkerFunc) *dialSync { func newDialSync(worker dialWorkerFunc) *dialSync {
return &dialSync{ return &dialSync{
@ -30,17 +34,12 @@ type dialSync struct {
type activeDial struct { type activeDial struct {
refCnt int refCnt int
ctx context.Context ctx context.Context
cancel func() cancelCause func(error)
reqch chan dialRequest reqch chan dialRequest
} }
func (ad *activeDial) close() {
ad.cancel()
close(ad.reqch)
}
func (ad *activeDial) dial(ctx context.Context) (*Conn, error) { func (ad *activeDial) dial(ctx context.Context) (*Conn, error) {
dialCtx := ad.ctx dialCtx := ad.ctx
@ -74,11 +73,11 @@ func (ds *dialSync) getActiveDial(p peer.ID) (*activeDial, error) {
if !ok { if !ok {
// This code intentionally uses the background context. Otherwise, if the first call // This code intentionally uses the background context. Otherwise, if the first call
// to Dial is canceled, subsequent dial calls will also be canceled. // to Dial is canceled, subsequent dial calls will also be canceled.
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancelCause(context.Background())
actd = &activeDial{ actd = &activeDial{
ctx: ctx, ctx: ctx,
cancel: cancel, cancelCause: cancel,
reqch: make(chan dialRequest), reqch: make(chan dialRequest),
} }
go ds.dialWorker(p, actd.reqch) go ds.dialWorker(p, actd.reqch)
ds.dials[p] = actd ds.dials[p] = actd
@ -96,14 +95,21 @@ func (ds *dialSync) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
return nil, err return nil, err
} }
defer func() { conn, err := ad.dial(ctx)
ds.mutex.Lock()
defer ds.mutex.Unlock() ds.mutex.Lock()
ad.refCnt-- defer ds.mutex.Unlock()
if ad.refCnt == 0 {
ad.close() ad.refCnt--
delete(ds.dials, p) if ad.refCnt == 0 {
if err == nil {
ad.cancelCause(errConcurrentDialSuccessful)
} else {
ad.cancelCause(err)
} }
}() close(ad.reqch)
return ad.dial(ctx) delete(ds.dials, p)
}
return conn, err
} }

View File

@ -8,15 +8,12 @@ import (
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
tpt "github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
) )
// /////////////////////////////////////////////////////////////////////////////////
// lo and behold, The Dialer
// TODO explain how all this works
// ////////////////////////////////////////////////////////////////////////////////
// dialRequest is structure used to request dials to the peer associated with a // dialRequest is structure used to request dials to the peer associated with a
// worker loop // worker loop
type dialRequest struct { type dialRequest struct {
@ -61,15 +58,14 @@ type addrDial struct {
conn *Conn conn *Conn
// err is the err on dialing the address // err is the err on dialing the address
err error err error
// requests is the list of pendRequests interested in this dial
// the value in the slice is the request number assigned to this request by the dialWorker
requests []int
// dialed indicates whether we have triggered the dial to the address // dialed indicates whether we have triggered the dial to the address
dialed bool dialed bool
// createdAt is the time this struct was created // createdAt is the time this struct was created
createdAt time.Time createdAt time.Time
// dialRankingDelay is the delay in dialing this address introduced by the ranking logic // dialRankingDelay is the delay in dialing this address introduced by the ranking logic
dialRankingDelay time.Duration dialRankingDelay time.Duration
// expectedTCPUpgradeTime is the expected time by which security upgrade will complete
expectedTCPUpgradeTime time.Time
} }
// dialWorker synchronises concurrent dials to a peer. It ensures that we make at most one dial to a // dialWorker synchronises concurrent dials to a peer. It ensures that we make at most one dial to a
@ -79,17 +75,13 @@ type dialWorker struct {
peer peer.ID peer peer.ID
// reqch is used to send dial requests to the worker. close reqch to end the worker loop // reqch is used to send dial requests to the worker. close reqch to end the worker loop
reqch <-chan dialRequest reqch <-chan dialRequest
// reqno is the request number used to track different dialRequests for a peer. // pendingRequests is the set of pendingRequests
// Each incoming request is assigned a reqno. This reqno is used in pendingRequests and in pendingRequests map[*pendRequest]struct{}
// addrDial objects in trackedDials to track this request // trackedDials tracks dials to the peer's addresses. An entry here is used to ensure that
reqno int
// pendingRequests maps reqno to the pendRequest object for a dialRequest
pendingRequests map[int]*pendRequest
// trackedDials tracks dials to the peers addresses. An entry here is used to ensure that
// we dial an address at most once // we dial an address at most once
trackedDials map[string]*addrDial trackedDials map[string]*addrDial
// resch is used to receive response for dials to the peers addresses. // resch is used to receive response for dials to the peers addresses.
resch chan dialResult resch chan tpt.DialUpdate
connected bool // true when a connection has been successfully established connected bool // true when a connection has been successfully established
@ -106,9 +98,9 @@ func newDialWorker(s *Swarm, p peer.ID, reqch <-chan dialRequest, cl Clock) *dia
s: s, s: s,
peer: p, peer: p,
reqch: reqch, reqch: reqch,
pendingRequests: make(map[int]*pendRequest), pendingRequests: make(map[*pendRequest]struct{}),
trackedDials: make(map[string]*addrDial), trackedDials: make(map[string]*addrDial),
resch: make(chan dialResult), resch: make(chan tpt.DialUpdate),
cl: cl, cl: cl,
} }
} }
@ -128,6 +120,8 @@ func (w *dialWorker) loop() {
startTime := w.cl.Now() startTime := w.cl.Now()
// dialTimer is the dialTimer used to trigger dials // dialTimer is the dialTimer used to trigger dials
dialTimer := w.cl.InstantTimer(startTime.Add(math.MaxInt64)) dialTimer := w.cl.InstantTimer(startTime.Add(math.MaxInt64))
defer dialTimer.Stop()
timerRunning := true timerRunning := true
// scheduleNextDial updates timer for triggering the next dial // scheduleNextDial updates timer for triggering the next dial
scheduleNextDial := func() { scheduleNextDial := func() {
@ -135,12 +129,18 @@ func (w *dialWorker) loop() {
<-dialTimer.Ch() <-dialTimer.Ch()
} }
timerRunning = false timerRunning = false
if dq.len() > 0 { if dq.Len() > 0 {
if dialsInFlight == 0 && !w.connected { if dialsInFlight == 0 && !w.connected {
// if there are no dials in flight, trigger the next dials immediately // if there are no dials in flight, trigger the next dials immediately
dialTimer.Reset(startTime) dialTimer.Reset(startTime)
} else { } else {
dialTimer.Reset(startTime.Add(dq.top().Delay)) resetTime := startTime.Add(dq.top().Delay)
for _, ad := range w.trackedDials {
if !ad.expectedTCPUpgradeTime.IsZero() && ad.expectedTCPUpgradeTime.After(resetTime) {
resetTime = ad.expectedTCPUpgradeTime
}
}
dialTimer.Reset(resetTime)
} }
timerRunning = true timerRunning = true
} }
@ -171,15 +171,20 @@ loop:
// Enqueue the peer's addresses relevant to this request in dq and // Enqueue the peer's addresses relevant to this request in dq and
// track dials to the addresses relevant to this request. // track dials to the addresses relevant to this request.
c, err := w.s.bestAcceptableConnToPeer(req.ctx, w.peer) c := w.s.bestAcceptableConnToPeer(req.ctx, w.peer)
if c != nil || err != nil { if c != nil {
req.resch <- dialResponse{conn: c, err: err} req.resch <- dialResponse{conn: c}
continue loop continue loop
} }
addrs, err := w.s.addrsForDial(req.ctx, w.peer) addrs, addrErrs, err := w.s.addrsForDial(req.ctx, w.peer)
if err != nil { if err != nil {
req.resch <- dialResponse{err: err} req.resch <- dialResponse{
err: &DialError{
Peer: w.peer,
DialErrors: addrErrs,
Cause: err,
}}
continue loop continue loop
} }
@ -191,8 +196,8 @@ loop:
// create the pending request object // create the pending request object
pr := &pendRequest{ pr := &pendRequest{
req: req, req: req,
err: &DialError{Peer: w.peer},
addrs: make(map[string]struct{}, len(addrRanking)), addrs: make(map[string]struct{}, len(addrRanking)),
err: &DialError{Peer: w.peer, DialErrors: addrErrs},
} }
for _, adelay := range addrRanking { for _, adelay := range addrRanking {
pr.addrs[string(adelay.Addr.Bytes())] = struct{}{} pr.addrs[string(adelay.Addr.Bytes())] = struct{}{}
@ -233,14 +238,13 @@ loop:
if len(todial) == 0 && len(tojoin) == 0 { if len(todial) == 0 && len(tojoin) == 0 {
// all request applicable addrs have been dialed, we must have errored // all request applicable addrs have been dialed, we must have errored
pr.err.Cause = ErrAllDialsFailed
req.resch <- dialResponse{err: pr.err} req.resch <- dialResponse{err: pr.err}
continue loop continue loop
} }
// The request has some pending or new dials. We assign this request a request number. // The request has some pending or new dials
// This value of w.reqno is used to track this request in all the structures w.pendingRequests[pr] = struct{}{}
w.reqno++
w.pendingRequests[w.reqno] = pr
for _, ad := range tojoin { for _, ad := range tojoin {
if !ad.dialed { if !ad.dialed {
@ -258,7 +262,6 @@ loop:
} }
} }
// add the request to the addrDial // add the request to the addrDial
ad.requests = append(ad.requests, w.reqno)
} }
if len(todial) > 0 { if len(todial) > 0 {
@ -268,7 +271,6 @@ loop:
w.trackedDials[string(a.Bytes())] = &addrDial{ w.trackedDials[string(a.Bytes())] = &addrDial{
addr: a, addr: a,
ctx: req.ctx, ctx: req.ctx,
requests: []int{w.reqno},
createdAt: now, createdAt: now,
} }
dq.Add(network.AddrDelay{Addr: a, Delay: addrDelay[string(a.Bytes())]}) dq.Add(network.AddrDelay{Addr: a, Delay: addrDelay[string(a.Bytes())]})
@ -313,16 +315,29 @@ loop:
// Update all requests waiting on this address. On success, complete the request. // Update all requests waiting on this address. On success, complete the request.
// On error, record the error // On error, record the error
dialsInFlight--
ad, ok := w.trackedDials[string(res.Addr.Bytes())] ad, ok := w.trackedDials[string(res.Addr.Bytes())]
if !ok { if !ok {
log.Errorf("SWARM BUG: no entry for address %s in trackedDials", res.Addr) log.Errorf("SWARM BUG: no entry for address %s in trackedDials", res.Addr)
if res.Conn != nil { if res.Conn != nil {
res.Conn.Close() res.Conn.Close()
} }
dialsInFlight--
continue continue
} }
// TCP Connection has been established. Wait for connection upgrade on this address
// before making new dials.
if res.Kind == tpt.UpdateKindHandshakeProgressed {
// Only wait for public addresses to complete dialing since private dials
// are quick any way
if manet.IsPublicAddr(res.Addr) {
ad.expectedTCPUpgradeTime = w.cl.Now().Add(PublicTCPDelay)
}
scheduleNextDial()
continue
}
dialsInFlight--
ad.expectedTCPUpgradeTime = time.Time{}
if res.Conn != nil { if res.Conn != nil {
// we got a connection, add it to the swarm // we got a connection, add it to the swarm
conn, err := w.s.addConn(res.Conn, network.DirOutbound) conn, err := w.s.addConn(res.Conn, network.DirOutbound)
@ -333,20 +348,14 @@ loop:
continue loop continue loop
} }
// request succeeded, respond to all pending requests for pr := range w.pendingRequests {
for _, reqno := range ad.requests { if _, ok := pr.addrs[string(ad.addr.Bytes())]; ok {
pr, ok := w.pendingRequests[reqno] pr.req.resch <- dialResponse{conn: conn}
if !ok { delete(w.pendingRequests, pr)
// some other dial for this request succeeded before this one
continue
} }
pr.req.resch <- dialResponse{conn: conn}
delete(w.pendingRequests, reqno)
} }
ad.conn = conn ad.conn = conn
ad.requests = nil
if !w.connected { if !w.connected {
w.connected = true w.connected = true
if w.s.metricsTracer != nil { if w.s.metricsTracer != nil {
@ -380,33 +389,27 @@ loop:
// dispatches an error to a specific addr dial // dispatches an error to a specific addr dial
func (w *dialWorker) dispatchError(ad *addrDial, err error) { func (w *dialWorker) dispatchError(ad *addrDial, err error) {
ad.err = err ad.err = err
for _, reqno := range ad.requests { for pr := range w.pendingRequests {
pr, ok := w.pendingRequests[reqno]
if !ok {
// some other dial for this request succeeded before this one
continue
}
// accumulate the error // accumulate the error
pr.err.recordErr(ad.addr, err) if _, ok := pr.addrs[string(ad.addr.Bytes())]; ok {
pr.err.recordErr(ad.addr, err)
delete(pr.addrs, string(ad.addr.Bytes())) delete(pr.addrs, string(ad.addr.Bytes()))
if len(pr.addrs) == 0 { if len(pr.addrs) == 0 {
// all addrs have erred, dispatch dial error // all addrs have erred, dispatch dial error
// but first do a last one check in case an acceptable connection has landed from // but first do a last one check in case an acceptable connection has landed from
// a simultaneous dial that started later and added new acceptable addrs // a simultaneous dial that started later and added new acceptable addrs
c, _ := w.s.bestAcceptableConnToPeer(pr.req.ctx, w.peer) c := w.s.bestAcceptableConnToPeer(pr.req.ctx, w.peer)
if c != nil { if c != nil {
pr.req.resch <- dialResponse{conn: c} pr.req.resch <- dialResponse{conn: c}
} else { } else {
pr.req.resch <- dialResponse{err: pr.err} pr.err.Cause = ErrAllDialsFailed
pr.req.resch <- dialResponse{err: pr.err}
}
delete(w.pendingRequests, pr)
} }
delete(w.pendingRequests, reqno)
} }
} }
ad.requests = nil
// if it was a backoff, clear the address dial so that it doesn't inhibit new dial requests. // if it was a backoff, clear the address dial so that it doesn't inhibit new dial requests.
// this is necessary to support active listen scenarios, where a new dial comes in while // this is necessary to support active listen scenarios, where a new dial comes in while
// another dial is in progress, and needs to do a direct connection without inhibitions from // another dial is in progress, and needs to do a direct connection without inhibitions from
@ -439,7 +442,7 @@ func newDialQueue() *dialQueue {
// Add adds adelay to the queue. If another element exists in the queue with // Add adds adelay to the queue. If another element exists in the queue with
// the same address, it replaces that element. // the same address, it replaces that element.
func (dq *dialQueue) Add(adelay network.AddrDelay) { func (dq *dialQueue) Add(adelay network.AddrDelay) {
for i := 0; i < dq.len(); i++ { for i := 0; i < dq.Len(); i++ {
if dq.q[i].Addr.Equal(adelay.Addr) { if dq.q[i].Addr.Equal(adelay.Addr) {
if dq.q[i].Delay == adelay.Delay { if dq.q[i].Delay == adelay.Delay {
// existing element is the same. nothing to do // existing element is the same. nothing to do
@ -452,7 +455,7 @@ func (dq *dialQueue) Add(adelay network.AddrDelay) {
} }
} }
for i := 0; i < dq.len(); i++ { for i := 0; i < dq.Len(); i++ {
if dq.q[i].Delay > adelay.Delay { if dq.q[i].Delay > adelay.Delay {
dq.q = append(dq.q, network.AddrDelay{}) // extend the slice dq.q = append(dq.q, network.AddrDelay{}) // extend the slice
copy(dq.q[i+1:], dq.q[i:]) copy(dq.q[i+1:], dq.q[i:])
@ -465,13 +468,13 @@ func (dq *dialQueue) Add(adelay network.AddrDelay) {
// NextBatch returns all the elements in the queue with the highest priority // NextBatch returns all the elements in the queue with the highest priority
func (dq *dialQueue) NextBatch() []network.AddrDelay { func (dq *dialQueue) NextBatch() []network.AddrDelay {
if dq.len() == 0 { if dq.Len() == 0 {
return nil return nil
} }
// i is the index of the second highest priority element // i is the index of the second highest priority element
var i int var i int
for i = 0; i < dq.len(); i++ { for i = 0; i < dq.Len(); i++ {
if dq.q[i].Delay != dq.q[0].Delay { if dq.q[i].Delay != dq.q[0].Delay {
break break
} }
@ -486,7 +489,7 @@ func (dq *dialQueue) top() network.AddrDelay {
return dq.q[0] return dq.q[0]
} }
// len returns the number of elements in the queue // Len returns the number of elements in the queue
func (dq *dialQueue) len() int { func (dq *dialQueue) Len() int {
return len(dq.q) return len(dq.q)
} }

View File

@ -13,17 +13,11 @@ import (
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
type dialResult struct {
Conn transport.CapableConn
Addr ma.Multiaddr
Err error
}
type dialJob struct { type dialJob struct {
addr ma.Multiaddr addr ma.Multiaddr
peer peer.ID peer peer.ID
ctx context.Context ctx context.Context
resp chan dialResult resp chan transport.DialUpdate
timeout time.Duration timeout time.Duration
} }
@ -45,7 +39,7 @@ type dialLimiter struct {
waitingOnPeerLimit map[peer.ID][]*dialJob waitingOnPeerLimit map[peer.ID][]*dialJob
} }
type dialfunc func(context.Context, peer.ID, ma.Multiaddr) (transport.CapableConn, error) type dialfunc func(context.Context, peer.ID, ma.Multiaddr, chan<- transport.DialUpdate) (transport.CapableConn, error)
func newDialLimiter(df dialfunc) *dialLimiter { func newDialLimiter(df dialfunc) *dialLimiter {
fd := ConcurrentFdDials fd := ConcurrentFdDials
@ -216,9 +210,13 @@ func (dl *dialLimiter) executeDial(j *dialJob) {
dctx, cancel := context.WithTimeout(j.ctx, j.timeout) dctx, cancel := context.WithTimeout(j.ctx, j.timeout)
defer cancel() defer cancel()
con, err := dl.dialFunc(dctx, j.peer, j.addr) con, err := dl.dialFunc(dctx, j.peer, j.addr, j.resp)
kind := transport.UpdateKindDialSuccessful
if err != nil {
kind = transport.UpdateKindDialFailed
}
select { select {
case j.resp <- dialResult{Conn: con, Addr: j.addr, Err: err}: case j.resp <- transport.DialUpdate{Kind: kind, Conn: con, Addr: j.addr, Err: err}:
case <-j.ctx.Done(): case <-j.ctx.Done():
if con != nil { if con != nil {
con.Close() con.Close()

View File

@ -17,6 +17,7 @@ import (
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/core/transport"
"golang.org/x/exp/slices"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
@ -136,8 +137,8 @@ func WithIPv6BlackHoleConfig(enabled bool, n, min int) Option {
// communication. The Chan sends/receives Messages, which note the // communication. The Chan sends/receives Messages, which note the
// destination or source Peer. // destination or source Peer.
type Swarm struct { type Swarm struct {
nextConnID uint64 // guarded by atomic nextConnID atomic.Uint64
nextStreamID uint64 // guarded by atomic nextStreamID atomic.Uint64
// Close refcount. This allows us to fully wait for the swarm to be torn // Close refcount. This allows us to fully wait for the swarm to be torn
// down before continuing. // down before continuing.
@ -172,6 +173,11 @@ type Swarm struct {
m map[network.Notifiee]struct{} m map[network.Notifiee]struct{}
} }
directConnNotifs struct {
sync.Mutex
m map[peer.ID][]chan struct{}
}
transports struct { transports struct {
sync.RWMutex sync.RWMutex
m map[int]transport.Transport m map[int]transport.Transport
@ -231,6 +237,7 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts
s.listeners.m = make(map[transport.Listener]struct{}) s.listeners.m = make(map[transport.Listener]struct{})
s.transports.m = make(map[int]transport.Transport) s.transports.m = make(map[int]transport.Transport)
s.notifs.m = make(map[network.Notifiee]struct{}) s.notifs.m = make(map[network.Notifiee]struct{})
s.directConnNotifs.m = make(map[peer.ID][]chan struct{})
for _, opt := range opts { for _, opt := range opts {
if err := opt(s); err != nil { if err := opt(s); err != nil {
@ -343,7 +350,7 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn,
conn: tc, conn: tc,
swarm: s, swarm: s,
stat: stat, stat: stat,
id: atomic.AddUint64(&s.nextConnID, 1), id: s.nextConnID.Add(1),
} }
// we ONLY check upgraded connections here so we can send them a Disconnect message. // we ONLY check upgraded connections here so we can send them a Disconnect message.
@ -353,7 +360,7 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn,
// TODO Send disconnect with reason here // TODO Send disconnect with reason here
err := tc.Close() err := tc.Close()
if err != nil { if err != nil {
log.Warnf("failed to close connection with peer %s and addr %s; err: %s", p.Pretty(), addr, err) log.Warnf("failed to close connection with peer %s and addr %s; err: %s", p, addr, err)
} }
return nil, ErrGaterDisallowedConnection return nil, ErrGaterDisallowedConnection
} }
@ -390,6 +397,19 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn,
c.notifyLk.Lock() c.notifyLk.Lock()
s.conns.Unlock() s.conns.Unlock()
// Notify goroutines waiting for a direct connection
if !c.Stat().Transient {
// Go routines interested in waiting for direct connection first acquire this lock
// and then acquire s.conns.RLock. Do not acquire this lock before conns.Unlock to
// prevent deadlock.
s.directConnNotifs.Lock()
for _, ch := range s.directConnNotifs.m[p] {
close(ch)
}
delete(s.directConnNotifs.m, p)
s.directConnNotifs.Unlock()
}
// Emit event after releasing `s.conns` lock so that a consumer can still // Emit event after releasing `s.conns` lock so that a consumer can still
// use swarm methods that need the `s.conns` lock. // use swarm methods that need the `s.conns` lock.
if isFirstConnection { if isFirstConnection {
@ -429,54 +449,110 @@ func (s *Swarm) StreamHandler() network.StreamHandler {
// NewStream creates a new stream on any available connection to peer, dialing // NewStream creates a new stream on any available connection to peer, dialing
// if necessary. // if necessary.
// Use network.WithUseTransient to open a stream over a transient(relayed)
// connection.
func (s *Swarm) NewStream(ctx context.Context, p peer.ID) (network.Stream, error) { func (s *Swarm) NewStream(ctx context.Context, p peer.ID) (network.Stream, error) {
log.Debugf("[%s] opening stream to peer [%s]", s.local, p) log.Debugf("[%s] opening stream to peer [%s]", s.local, p)
// Algorithm: // Algorithm:
// 1. Find the best connection, otherwise, dial. // 1. Find the best connection, otherwise, dial.
// 2. Try opening a stream. // 2. If the best connection is transient, wait for a direct conn via conn
// 3. If the underlying connection is, in fact, closed, close the outer // reversal or hole punching.
// 3. Try opening a stream.
// 4. If the underlying connection is, in fact, closed, close the outer
// connection and try again. We do this in case we have a closed // connection and try again. We do this in case we have a closed
// connection but don't notice it until we actually try to open a // connection but don't notice it until we actually try to open a
// stream. // stream.
// //
// Note: We only dial once.
//
// TODO: Try all connections even if we get an error opening a stream on // TODO: Try all connections even if we get an error opening a stream on
// a non-closed connection. // a non-closed connection.
dials := 0 numDials := 0
for { for {
// will prefer direct connections over relayed connections for opening streams c := s.bestConnToPeer(p)
c, err := s.bestAcceptableConnToPeer(ctx, p)
if err != nil {
return nil, err
}
if c == nil { if c == nil {
if nodial, _ := network.GetNoDial(ctx); nodial { if nodial, _ := network.GetNoDial(ctx); !nodial {
numDials++
if numDials > DialAttempts {
return nil, errors.New("max dial attempts exceeded")
}
var err error
c, err = s.dialPeer(ctx, p)
if err != nil {
return nil, err
}
} else {
return nil, network.ErrNoConn return nil, network.ErrNoConn
} }
}
if dials >= DialAttempts { useTransient, _ := network.GetUseTransient(ctx)
return nil, errors.New("max dial attempts exceeded") if !useTransient && c.Stat().Transient {
}
dials++
var err error var err error
c, err = s.dialPeer(ctx, p) c, err = s.waitForDirectConn(ctx, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
s, err := c.NewStream(ctx) str, err := c.NewStream(ctx)
if err != nil { if err != nil {
if c.conn.IsClosed() { if c.conn.IsClosed() {
continue continue
} }
return nil, err return nil, err
} }
return s, nil return str, nil
}
}
// waitForDirectConn waits for a direct connection established through hole punching or connection reversal.
func (s *Swarm) waitForDirectConn(ctx context.Context, p peer.ID) (*Conn, error) {
s.directConnNotifs.Lock()
c := s.bestConnToPeer(p)
if c == nil {
s.directConnNotifs.Unlock()
return nil, network.ErrNoConn
} else if !c.Stat().Transient {
s.directConnNotifs.Unlock()
return c, nil
}
// Wait for transient connection to upgrade to a direct connection either by
// connection reversal or hole punching.
ch := make(chan struct{})
s.directConnNotifs.m[p] = append(s.directConnNotifs.m[p], ch)
s.directConnNotifs.Unlock()
// apply the DialPeer timeout
ctx, cancel := context.WithTimeout(ctx, network.GetDialPeerTimeout(ctx))
defer cancel()
// Wait for notification.
select {
case <-ctx.Done():
// Remove ourselves from the notification list
s.directConnNotifs.Lock()
defer s.directConnNotifs.Unlock()
s.directConnNotifs.m[p] = slices.DeleteFunc(
s.directConnNotifs.m[p],
func(c chan struct{}) bool { return c == ch },
)
if len(s.directConnNotifs.m[p]) == 0 {
delete(s.directConnNotifs.m, p)
}
return nil, ctx.Err()
case <-ch:
// We do not need to remove ourselves from the list here as the notifier
// clears the map entry
c := s.bestConnToPeer(p)
if c == nil {
return nil, network.ErrNoConn
}
if c.Stat().Transient {
return nil, network.ErrTransientConn
}
return c, nil
} }
} }
@ -548,26 +624,17 @@ func (s *Swarm) bestConnToPeer(p peer.ID) *Conn {
return best return best
} }
// - Returns the best "acceptable" connection, if available. // bestAcceptableConnToPeer returns the best acceptable connection, considering the passed in ctx.
// - Returns nothing if no such connection exists, but if we should try dialing anyways. // If network.WithForceDirectDial is used, it only returns a direct connections, ignoring
// - Returns an error if no such connection exists, but we should not try dialing. // any transient (relayed) connections to the peer.
func (s *Swarm) bestAcceptableConnToPeer(ctx context.Context, p peer.ID) (*Conn, error) { func (s *Swarm) bestAcceptableConnToPeer(ctx context.Context, p peer.ID) *Conn {
conn := s.bestConnToPeer(p) conn := s.bestConnToPeer(p)
if conn == nil {
return nil, nil
}
forceDirect, _ := network.GetForceDirectDial(ctx) forceDirect, _ := network.GetForceDirectDial(ctx)
if forceDirect && !isDirectConn(conn) { if forceDirect && !isDirectConn(conn) {
return nil, nil return nil
} }
return conn
useTransient, _ := network.GetUseTransient(ctx)
if useTransient || !conn.Stat().Transient {
return conn, nil
}
return nil, network.ErrTransientConn
} }
func isDirectConn(c *Conn) bool { func isDirectConn(c *Conn) bool {

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"time" "time"
ic "github.com/libp2p/go-libp2p/core/crypto" ic "github.com/libp2p/go-libp2p/core/crypto"
@ -49,7 +48,7 @@ func (c *Conn) IsClosed() bool {
func (c *Conn) ID() string { func (c *Conn) ID() string {
// format: <first 10 chars of peer id>-<global conn ordinal> // format: <first 10 chars of peer id>-<global conn ordinal>
return fmt.Sprintf("%s-%d", c.RemotePeer().Pretty()[0:10], c.id) return fmt.Sprintf("%s-%d", c.RemotePeer().String()[:10], c.id)
} }
// Close closes this connection. // Close closes this connection.
@ -137,6 +136,7 @@ func (c *Conn) start() {
if h := c.swarm.StreamHandler(); h != nil { if h := c.swarm.StreamHandler(); h != nil {
h(s) h(s)
} }
s.completeAcceptStreamGoroutine()
}() }()
} }
}() }()
@ -147,9 +147,9 @@ func (c *Conn) String() string {
"<swarm.Conn[%T] %s (%s) <-> %s (%s)>", "<swarm.Conn[%T] %s (%s) <-> %s (%s)>",
c.conn.Transport(), c.conn.Transport(),
c.conn.LocalMultiaddr(), c.conn.LocalMultiaddr(),
c.conn.LocalPeer().Pretty(), c.conn.LocalPeer(),
c.conn.RemoteMultiaddr(), c.conn.RemoteMultiaddr(),
c.conn.RemotePeer().Pretty(), c.conn.RemotePeer(),
) )
} }
@ -238,7 +238,8 @@ func (c *Conn) addStream(ts network.MuxedStream, dir network.Direction, scope ne
Direction: dir, Direction: dir,
Opened: time.Now(), Opened: time.Now(),
}, },
id: atomic.AddUint64(&c.swarm.nextStreamID, 1), id: c.swarm.nextStreamID.Add(1),
acceptStreamGoroutineCompleted: dir != network.DirInbound,
} }
c.stat.NumStreams++ c.stat.NumStreams++
c.streams.m[s] = struct{}{} c.streams.m[s] = struct{}{}

View File

@ -14,8 +14,10 @@ import (
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns" madns "github.com/multiformats/go-multiaddr-dns"
mafmt "github.com/multiformats/go-multiaddr-fmt"
manet "github.com/multiformats/go-multiaddr/net" manet "github.com/multiformats/go-multiaddr/net"
) )
@ -65,6 +67,19 @@ var (
ErrGaterDisallowedConnection = errors.New("gater disallows connection to peer") ErrGaterDisallowedConnection = errors.New("gater disallows connection to peer")
) )
// ErrQUICDraft29 wraps ErrNoTransport and provide a more meaningful error message
var ErrQUICDraft29 errQUICDraft29
type errQUICDraft29 struct{}
func (errQUICDraft29) Error() string {
return "QUIC draft-29 has been removed, QUIC (RFC 9000) is accessible with /quic-v1"
}
func (errQUICDraft29) Unwrap() error {
return ErrNoTransport
}
// DialAttempts governs how many times a goroutine will try to dial a given peer. // DialAttempts governs how many times a goroutine will try to dial a given peer.
// Note: this is down to one, as we have _too many dials_ atm. To add back in, // Note: this is down to one, as we have _too many dials_ atm. To add back in,
// add loop back in Dial(.) // add loop back in Dial(.)
@ -201,7 +216,8 @@ func (db *DialBackoff) cleanup() {
} }
} }
// DialPeer connects to a peer. // DialPeer connects to a peer. Use network.WithForceDirectDial to force a
// direct connection.
// //
// The idea is that the client of Swarm does not need to know what network // The idea is that the client of Swarm does not need to know what network
// the connection will happen over. Swarm can use whichever it choses. // the connection will happen over. Swarm can use whichever it choses.
@ -231,15 +247,14 @@ func (s *Swarm) dialPeer(ctx context.Context, p peer.ID) (*Conn, error) {
return nil, ErrDialToSelf return nil, ErrDialToSelf
} }
// check if we already have an open (usable) connection first, or can't have a usable // check if we already have an open (usable) connection.
// connection. conn := s.bestAcceptableConnToPeer(ctx, p)
conn, err := s.bestAcceptableConnToPeer(ctx, p) if conn != nil {
if conn != nil || err != nil { return conn, nil
return conn, err
} }
if s.gater != nil && !s.gater.InterceptPeerDial(p) { if s.gater != nil && !s.gater.InterceptPeerDial(p) {
log.Debugf("gater disallowed outbound connection to peer %s", p.Pretty()) log.Debugf("gater disallowed outbound connection to peer %s", p)
return nil, &DialError{Peer: p, Cause: ErrGaterDisallowedConnection} return nil, &DialError{Peer: p, Cause: ErrGaterDisallowedConnection}
} }
@ -280,68 +295,47 @@ func (s *Swarm) dialWorkerLoop(p peer.ID, reqch <-chan dialRequest) {
w.loop() w.loop()
} }
func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) ([]ma.Multiaddr, error) { func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) (goodAddrs []ma.Multiaddr, addrErrs []TransportError, err error) {
peerAddrs := s.peers.Addrs(p) peerAddrs := s.peers.Addrs(p)
if len(peerAddrs) == 0 { if len(peerAddrs) == 0 {
return nil, ErrNoAddresses return nil, nil, ErrNoAddresses
}
peerAddrsAfterTransportResolved := make([]ma.Multiaddr, 0, len(peerAddrs))
for _, a := range peerAddrs {
tpt := s.TransportForDialing(a)
resolver, ok := tpt.(transport.Resolver)
if ok {
resolvedAddrs, err := resolver.Resolve(ctx, a)
if err != nil {
log.Warnf("Failed to resolve multiaddr %s by transport %v: %v", a, tpt, err)
continue
}
peerAddrsAfterTransportResolved = append(peerAddrsAfterTransportResolved, resolvedAddrs...)
} else {
peerAddrsAfterTransportResolved = append(peerAddrsAfterTransportResolved, a)
}
} }
// Resolve dns or dnsaddrs // Resolve dns or dnsaddrs
resolved, err := s.resolveAddrs(ctx, peer.AddrInfo{ resolved, err := s.resolveAddrs(ctx, peer.AddrInfo{ID: p, Addrs: peerAddrs})
ID: p,
Addrs: peerAddrsAfterTransportResolved,
})
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
goodAddrs := s.filterKnownUndialables(p, resolved) goodAddrs = ma.Unique(resolved)
goodAddrs, addrErrs = s.filterKnownUndialables(p, goodAddrs)
if forceDirect, _ := network.GetForceDirectDial(ctx); forceDirect { if forceDirect, _ := network.GetForceDirectDial(ctx); forceDirect {
goodAddrs = ma.FilterAddrs(goodAddrs, s.nonProxyAddr) goodAddrs = ma.FilterAddrs(goodAddrs, s.nonProxyAddr)
} }
goodAddrs = ma.Unique(goodAddrs)
if len(goodAddrs) == 0 { if len(goodAddrs) == 0 {
return nil, ErrNoGoodAddresses return nil, addrErrs, ErrNoGoodAddresses
} }
s.peers.AddAddrs(p, goodAddrs, peerstore.TempAddrTTL) s.peers.AddAddrs(p, goodAddrs, peerstore.TempAddrTTL)
return goodAddrs, nil return goodAddrs, addrErrs, nil
} }
func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multiaddr, error) { func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multiaddr, error) {
proto := ma.ProtocolWithCode(ma.P_P2P).Name p2paddr, err := ma.NewMultiaddr("/" + ma.ProtocolWithCode(ma.P_P2P).Name + "/" + pi.ID.String())
p2paddr, err := ma.NewMultiaddr("/" + proto + "/" + pi.ID.Pretty())
if err != nil { if err != nil {
return nil, err return nil, err
} }
resolveSteps := 0 var resolveSteps int
// Recursively resolve all addrs. // Recursively resolve all addrs.
// //
// While the toResolve list is non-empty: // While the toResolve list is non-empty:
// * Pop an address off. // * Pop an address off.
// * If the address is fully resolved, add it to the resolved list. // * If the address is fully resolved, add it to the resolved list.
// * Otherwise, resolve it and add the results to the "to resolve" list. // * Otherwise, resolve it and add the results to the "to resolve" list.
toResolve := append(([]ma.Multiaddr)(nil), pi.Addrs...) toResolve := append([]ma.Multiaddr{}, pi.Addrs...)
resolved := make([]ma.Multiaddr, 0, len(pi.Addrs)) resolved := make([]ma.Multiaddr, 0, len(pi.Addrs))
for len(toResolve) > 0 { for len(toResolve) > 0 {
// pop the last addr off. // pop the last addr off.
@ -368,6 +362,26 @@ func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multia
continue continue
} }
tpt := s.TransportForDialing(addr)
resolver, ok := tpt.(transport.Resolver)
if ok {
resolvedAddrs, err := resolver.Resolve(ctx, addr)
if err != nil {
log.Warnf("Failed to resolve multiaddr %s by transport %v: %v", addr, tpt, err)
continue
}
var added bool
for _, a := range resolvedAddrs {
if !addr.Equal(a) {
toResolve = append(toResolve, a)
added = true
}
}
if added {
continue
}
}
// otherwise, resolve it // otherwise, resolve it
reqaddr := addr.Encapsulate(p2paddr) reqaddr := addr.Encapsulate(p2paddr)
resaddrs, err := s.maResolver.Resolve(ctx, reqaddr) resaddrs, err := s.maResolver.Resolve(ctx, reqaddr)
@ -388,7 +402,7 @@ func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multia
return resolved, nil return resolved, nil
} }
func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, resch chan dialResult) error { func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, resch chan transport.DialUpdate) error {
// check the dial backoff // check the dial backoff
if forceDirect, _ := network.GetForceDirectDial(ctx); !forceDirect { if forceDirect, _ := network.GetForceDirectDial(ctx); !forceDirect {
if s.backf.Backoff(p, addr) { if s.backf.Backoff(p, addr) {
@ -402,23 +416,20 @@ func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr,
return nil return nil
} }
func (s *Swarm) canDial(addr ma.Multiaddr) bool {
t := s.TransportForDialing(addr)
return t != nil && t.CanDial(addr)
}
func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool { func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool {
t := s.TransportForDialing(addr) t := s.TransportForDialing(addr)
return !t.Proxy() return !t.Proxy()
} }
var quicDraft29DialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC))
// filterKnownUndialables takes a list of multiaddrs, and removes those // filterKnownUndialables takes a list of multiaddrs, and removes those
// that we definitely don't want to dial: addresses configured to be blocked, // that we definitely don't want to dial: addresses configured to be blocked,
// IPv6 link-local addresses, addresses without a dial-capable transport, // IPv6 link-local addresses, addresses without a dial-capable transport,
// addresses that we know to be our own, and addresses with a better tranport // addresses that we know to be our own, and addresses with a better tranport
// available. This is an optimization to avoid wasting time on dials that we // available. This is an optimization to avoid wasting time on dials that we
// know are going to fail or for which we have a better alternative. // know are going to fail or for which we have a better alternative.
func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) []ma.Multiaddr { func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAddrs []ma.Multiaddr, addrErrs []TransportError) {
lisAddrs, _ := s.InterfaceListenAddresses() lisAddrs, _ := s.InterfaceListenAddresses()
var ourAddrs []ma.Multiaddr var ourAddrs []ma.Multiaddr
for _, addr := range lisAddrs { for _, addr := range lisAddrs {
@ -431,35 +442,71 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) []ma.Mul
}) })
} }
// The order of these two filters is important. If we can only dial /webtransport, addrErrs = make([]TransportError, 0, len(addrs))
// we don't want to filter /webtransport addresses out because the peer had a /quic-v1
// address
// filter addresses we cannot dial // The order of checking for transport and filtering low priority addrs is important. If we
addrs = ma.FilterAddrs(addrs, s.canDial) // can only dial /webtransport, we don't want to filter /webtransport addresses out because
// the peer had a /quic-v1 address
// filter addresses with no transport
addrs = ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool {
if s.TransportForDialing(a) == nil {
e := ErrNoTransport
// We used to support QUIC draft-29 for a long time.
// Provide a more useful error when attempting to dial a QUIC draft-29 address.
if quicDraft29DialMatcher.Matches(a) {
e = ErrQUICDraft29
}
addrErrs = append(addrErrs, TransportError{Address: a, Cause: e})
return false
}
return true
})
// filter low priority addresses among the addresses we can dial // filter low priority addresses among the addresses we can dial
// We don't return an error for these addresses
addrs = filterLowPriorityAddresses(addrs) addrs = filterLowPriorityAddresses(addrs)
// remove black holed addrs // remove black holed addrs
addrs = s.bhd.FilterAddrs(addrs) addrs, blackHoledAddrs := s.bhd.FilterAddrs(addrs)
for _, a := range blackHoledAddrs {
addrErrs = append(addrErrs, TransportError{Address: a, Cause: ErrDialRefusedBlackHole})
}
return ma.FilterAddrs(addrs, return ma.FilterAddrs(addrs,
func(addr ma.Multiaddr) bool { return !ma.Contains(ourAddrs, addr) }, // Linux and BSD treat an unspecified address when dialing as a localhost address.
// Windows doesn't support this. We filter all such addresses out because peers
// listening on unspecified addresses will advertise more specific addresses.
// https://unix.stackexchange.com/a/419881
// https://superuser.com/a/1755455
func(addr ma.Multiaddr) bool {
return !manet.IsIPUnspecified(addr)
},
func(addr ma.Multiaddr) bool {
if ma.Contains(ourAddrs, addr) {
addrErrs = append(addrErrs, TransportError{Address: addr, Cause: ErrDialToSelf})
return false
}
return true
},
// TODO: Consider allowing link-local addresses // TODO: Consider allowing link-local addresses
func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) }, func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) },
func(addr ma.Multiaddr) bool { func(addr ma.Multiaddr) bool {
return s.gater == nil || s.gater.InterceptAddrDial(p, addr) if s.gater != nil && !s.gater.InterceptAddrDial(p, addr) {
addrErrs = append(addrErrs, TransportError{Address: addr, Cause: ErrGaterDisallowedConnection})
return false
}
return true
}, },
) ), addrErrs
} }
// limitedDial will start a dial to the given peer when // limitedDial will start a dial to the given peer when
// it is able, respecting the various different types of rate // it is able, respecting the various different types of rate
// limiting that occur without using extra goroutines per addr // limiting that occur without using extra goroutines per addr
func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp chan dialResult) { func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp chan transport.DialUpdate) {
timeout := s.dialTimeout timeout := s.dialTimeout
if lowTimeoutFilters.AddrBlocked(a) && s.dialTimeoutLocal < s.dialTimeout { if manet.IsPrivateAddr(a) && s.dialTimeoutLocal < s.dialTimeout {
timeout = s.dialTimeoutLocal timeout = s.dialTimeoutLocal
} }
s.limiter.AddDialJob(&dialJob{ s.limiter.AddDialJob(&dialJob{
@ -472,7 +519,7 @@ func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp
} }
// dialAddr is the actual dial for an addr, indirectly invoked through the limiter // dialAddr is the actual dial for an addr, indirectly invoked through the limiter
func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (transport.CapableConn, error) { func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, updCh chan<- transport.DialUpdate) (transport.CapableConn, error) {
// Just to double check. Costs nothing. // Just to double check. Costs nothing.
if s.local == p { if s.local == p {
return nil, ErrDialToSelf return nil, ErrDialToSelf
@ -490,7 +537,13 @@ func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (tra
} }
start := time.Now() start := time.Now()
connC, err := tpt.Dial(ctx, addr, p) var connC transport.CapableConn
var err error
if du, ok := tpt.(transport.DialUpdater); ok {
connC, err = du.DialWithUpdates(ctx, addr, p, updCh)
} else {
connC, err = tpt.Dial(ctx, addr, p)
}
// We're recording any error as a failure here. // We're recording any error as a failure here.
// Notably, this also applies to cancelations (i.e. if another dial attempt was faster). // Notably, this also applies to cancelations (i.e. if another dial attempt was faster).
@ -499,7 +552,7 @@ func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (tra
if err != nil { if err != nil {
if s.metricsTracer != nil { if s.metricsTracer != nil {
s.metricsTracer.FailedDialing(addr, err) s.metricsTracer.FailedDialing(addr, err, context.Cause(ctx))
} }
return nil, err return nil, err
} }

View File

@ -128,7 +128,7 @@ type MetricsTracer interface {
OpenedConnection(network.Direction, crypto.PubKey, network.ConnectionState, ma.Multiaddr) OpenedConnection(network.Direction, crypto.PubKey, network.ConnectionState, ma.Multiaddr)
ClosedConnection(network.Direction, time.Duration, network.ConnectionState, ma.Multiaddr) ClosedConnection(network.Direction, time.Duration, network.ConnectionState, ma.Multiaddr)
CompletedHandshake(time.Duration, network.ConnectionState, ma.Multiaddr) CompletedHandshake(time.Duration, network.ConnectionState, ma.Multiaddr)
FailedDialing(ma.Multiaddr, error) FailedDialing(ma.Multiaddr, error, error)
DialCompleted(success bool, totalDials int) DialCompleted(success bool, totalDials int)
DialRankingDelay(d time.Duration) DialRankingDelay(d time.Duration)
UpdatedBlackHoleFilterState(name string, state blackHoleState, nextProbeAfter int, successFraction float64) UpdatedBlackHoleFilterState(name string, state blackHoleState, nextProbeAfter int, successFraction float64)
@ -216,18 +216,28 @@ func (m *metricsTracer) CompletedHandshake(t time.Duration, cs network.Connectio
connHandshakeLatency.WithLabelValues(*tags...).Observe(t.Seconds()) connHandshakeLatency.WithLabelValues(*tags...).Observe(t.Seconds())
} }
func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, err error) { func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, dialErr error, cause error) {
transport := metricshelper.GetTransport(addr) transport := metricshelper.GetTransport(addr)
e := "other" e := "other"
if errors.Is(err, context.Canceled) { // dial deadline exceeded or the the parent contexts deadline exceeded
e = "canceled" if errors.Is(dialErr, context.DeadlineExceeded) || errors.Is(cause, context.DeadlineExceeded) {
} else if errors.Is(err, context.DeadlineExceeded) {
e = "deadline" e = "deadline"
} else if errors.Is(dialErr, context.Canceled) {
// dial was cancelled.
if errors.Is(cause, context.Canceled) {
// parent context was canceled
e = "application canceled"
} else if errors.Is(cause, errConcurrentDialSuccessful) {
e = "canceled: concurrent dial successful"
} else {
// something else
e = "canceled: other"
}
} else { } else {
nerr, ok := err.(net.Error) nerr, ok := dialErr.(net.Error)
if ok && nerr.Timeout() { if ok && nerr.Timeout() {
e = "timeout" e = "timeout"
} else if strings.Contains(err.Error(), "connect: connection refused") { } else if strings.Contains(dialErr.Error(), "connect: connection refused") {
e = "connection refused" e = "connection refused"
} }
} }

View File

@ -22,7 +22,10 @@ type Stream struct {
conn *Conn conn *Conn
scope network.StreamManagementScope scope network.StreamManagementScope
closeOnce sync.Once closeMx sync.Mutex
isClosed bool
// acceptStreamGoroutineCompleted indicates whether the goroutine handling the incoming stream has exited
acceptStreamGoroutineCompleted bool
protocol atomic.Pointer[protocol.ID] protocol atomic.Pointer[protocol.ID]
@ -76,7 +79,7 @@ func (s *Stream) Write(p []byte) (int, error) {
// resources. // resources.
func (s *Stream) Close() error { func (s *Stream) Close() error {
err := s.stream.Close() err := s.stream.Close()
s.closeOnce.Do(s.remove) s.closeAndRemoveStream()
return err return err
} }
@ -84,10 +87,25 @@ func (s *Stream) Close() error {
// associated resources. // associated resources.
func (s *Stream) Reset() error { func (s *Stream) Reset() error {
err := s.stream.Reset() err := s.stream.Reset()
s.closeOnce.Do(s.remove) s.closeAndRemoveStream()
return err return err
} }
func (s *Stream) closeAndRemoveStream() {
s.closeMx.Lock()
defer s.closeMx.Unlock()
if s.isClosed {
return
}
s.isClosed = true
// We don't want to keep swarm from closing till the stream handler has exited
s.conn.swarm.refs.Done()
// Cleanup the stream from connection only after the stream handler has completed
if s.acceptStreamGoroutineCompleted {
s.conn.removeStream(s)
}
}
// CloseWrite closes the stream for writing, flushing all data and sending an EOF. // CloseWrite closes the stream for writing, flushing all data and sending an EOF.
// This function does not free resources, call Close or Reset when done with the // This function does not free resources, call Close or Reset when done with the
// stream. // stream.
@ -101,9 +119,16 @@ func (s *Stream) CloseRead() error {
return s.stream.CloseRead() return s.stream.CloseRead()
} }
func (s *Stream) remove() { func (s *Stream) completeAcceptStreamGoroutine() {
s.conn.removeStream(s) s.closeMx.Lock()
s.conn.swarm.refs.Done() defer s.closeMx.Unlock()
if s.acceptStreamGoroutineCompleted {
return
}
s.acceptStreamGoroutineCompleted = true
if s.isClosed {
s.conn.removeStream(s)
}
} }
// Protocol returns the protocol negotiated on this stream (if set). // Protocol returns the protocol negotiated on this stream (if set).

View File

@ -152,7 +152,8 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma
return nil, ipnet.ErrNotInPrivateNetwork return nil, ipnet.ErrNotInPrivateNetwork
} }
sconn, security, server, err := u.setupSecurity(ctx, conn, p, dir) isServer := dir == network.DirInbound
sconn, security, err := u.setupSecurity(ctx, conn, p, isServer)
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, fmt.Errorf("failed to negotiate security protocol: %w", err) return nil, fmt.Errorf("failed to negotiate security protocol: %w", err)
@ -179,7 +180,7 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma
} }
} }
muxer, smconn, err := u.setupMuxer(ctx, sconn, server, connScope.PeerScope()) muxer, smconn, err := u.setupMuxer(ctx, sconn, isServer, connScope.PeerScope())
if err != nil { if err != nil {
sconn.Close() sconn.Close()
return nil, fmt.Errorf("failed to negotiate stream multiplexer: %w", err) return nil, fmt.Errorf("failed to negotiate stream multiplexer: %w", err)
@ -199,20 +200,17 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma
return tc, nil return tc, nil
} }
func (u *upgrader) setupSecurity(ctx context.Context, conn net.Conn, p peer.ID, dir network.Direction) (sec.SecureConn, protocol.ID, bool, error) { func (u *upgrader) setupSecurity(ctx context.Context, conn net.Conn, p peer.ID, isServer bool) (sec.SecureConn, protocol.ID, error) {
isServer := dir == network.DirInbound st, err := u.negotiateSecurity(ctx, conn, isServer)
var st sec.SecureTransport
var err error
st, isServer, err = u.negotiateSecurity(ctx, conn, isServer)
if err != nil { if err != nil {
return nil, "", false, err return nil, "", err
} }
if isServer { if isServer {
sconn, err := st.SecureInbound(ctx, conn, p) sconn, err := st.SecureInbound(ctx, conn, p)
return sconn, st.ID(), true, err return sconn, st.ID(), err
} }
sconn, err := st.SecureOutbound(ctx, conn, p) sconn, err := st.SecureOutbound(ctx, conn, p)
return sconn, st.ID(), false, err return sconn, st.ID(), err
} }
func (u *upgrader) negotiateMuxer(nc net.Conn, isServer bool) (*StreamMuxer, error) { func (u *upgrader) negotiateMuxer(nc net.Conn, isServer bool) (*StreamMuxer, error) {
@ -308,41 +306,38 @@ func (u *upgrader) getSecurityByID(id protocol.ID) sec.SecureTransport {
return nil return nil
} }
func (u *upgrader) negotiateSecurity(ctx context.Context, insecure net.Conn, server bool) (sec.SecureTransport, bool, error) { func (u *upgrader) negotiateSecurity(ctx context.Context, insecure net.Conn, server bool) (sec.SecureTransport, error) {
type result struct { type result struct {
proto protocol.ID proto protocol.ID
iamserver bool err error
err error
} }
done := make(chan result, 1) done := make(chan result, 1)
go func() { go func() {
if server { if server {
var r result var r result
r.iamserver = true
r.proto, _, r.err = u.securityMuxer.Negotiate(insecure) r.proto, _, r.err = u.securityMuxer.Negotiate(insecure)
done <- r done <- r
return return
} }
var r result var r result
r.proto, r.iamserver, r.err = mss.SelectWithSimopenOrFail(u.securityIDs, insecure) r.proto, r.err = mss.SelectOneOf(u.securityIDs, insecure)
done <- r done <- r
}() }()
select { select {
case r := <-done: case r := <-done:
if r.err != nil { if r.err != nil {
return nil, false, r.err return nil, r.err
} }
if s := u.getSecurityByID(r.proto); s != nil { if s := u.getSecurityByID(r.proto); s != nil {
return s, r.iamserver, nil return s, nil
} }
return nil, false, fmt.Errorf("selected unknown security transport: %s", r.proto) return nil, fmt.Errorf("selected unknown security transport: %s", r.proto)
case <-ctx.Done(): case <-ctx.Done():
// We *must* do this. We have outstanding work on the connection // We *must* do this. We have outstanding work on the connection, and it's no longer safe to use.
// and it's no longer safe to use.
insecure.Close() insecure.Close()
<-done // wait to stop using the connection. <-done // wait to stop using the connection.
return nil, false, ctx.Err() return nil, ctx.Err()
} }
} }

View File

@ -74,7 +74,10 @@ func (c *constraints) AddReservation(p peer.ID, a ma.Multiaddr) error {
var asnReservations []time.Time var asnReservations []time.Time
var asn string var asn string
if ip.To4() == nil { // Only public addresses have an ASN. Skip checking ASN for private addresses as
// initialising the ASN store is a costly operation. Skipping this check reduces a lot of
// flakiness in tests
if ip.To4() == nil && manet.IsPublicAddr(a) {
asn, _ = asnutil.Store.AsnForIPv6(ip) asn, _ = asnutil.Store.AsnForIPv6(ip)
if asn != "" { if asn != "" {
asnReservations = c.asns[asn] asnReservations = c.asns[asn]

View File

@ -556,7 +556,7 @@ func readAllIDMessages(r pbio.Reader, finalMsg proto.Message) error {
func (ids *idService) updateSnapshot() (updated bool) { func (ids *idService) updateSnapshot() (updated bool) {
addrs := ids.Host.Addrs() addrs := ids.Host.Addrs()
slices.SortFunc(addrs, func(a, b ma.Multiaddr) bool { return bytes.Compare(a.Bytes(), b.Bytes()) == -1 }) slices.SortFunc(addrs, func(a, b ma.Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) })
protos := ids.Host.Mux().Protocols() protos := ids.Host.Mux().Protocols()
slices.Sort(protos) slices.Sort(protos)
snapshot := identifySnapshot{ snapshot := identifySnapshot{

Some files were not shown because too many files have changed in this diff Show More