From 4d51a74503b6261832f37da67e9c2d7856032da1 Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Tue, 2 Jul 2024 16:28:45 +0200 Subject: [PATCH 1/4] Code cleanup Co-authored-by: Zach Xion XioZ@users.noreply.github.com --- mino/mino.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mino/mino.go b/mino/mino.go index a935fa074..537bf01d9 100644 --- a/mino/mino.go +++ b/mino/mino.go @@ -150,8 +150,8 @@ type Sender interface { // Receiver is an abstraction to receive messages from a stream in the context // of a distributed RPC. type Receiver interface { - // Recv waits for a message to send received from the stream. It returns the - // address of the original sender and the message, or a message if the + // Recv waits for a message to be received from the stream. It returns the + // address of the original sender and the message, or an error if the // stream is closed or the context is done. Recv(context.Context) (Address, serde.Message, error) } From e9eaa22292d30628e87e1d2c8522035e43590a9a Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Tue, 2 Jul 2024 16:31:26 +0200 Subject: [PATCH 2/4] MinoWS implementation Co-authored-by: Zach Xion XioZ@users.noreply.github.com This commit implements a new Mino handler using libp2p with websockets. Contrary to MinoGRPC it doesn't use any locks and uses a 1-level tree to handle messages. It is at least as performant as the MinoGRPC implementation, and works with d-voting. --- go.mod | 99 ++++++- go.sum | 496 +++++++++++++++++++++++++++++++-- mino/mino.go | 2 + mino/minows/README.md | 18 ++ mino/minows/address.go | 156 +++++++++++ mino/minows/address_test.go | 320 +++++++++++++++++++++ mino/minows/controller.go | 111 ++++++++ mino/minows/controller_test.go | 127 +++++++++ mino/minows/key/mod.go | 63 +++++ mino/minows/mod.go | 127 +++++++++ mino/minows/mod_test.go | 237 ++++++++++++++++ mino/minows/rpc.go | 422 ++++++++++++++++++++++++++++ mino/minows/rpc_test.go | 278 ++++++++++++++++++ mino/minows/session.go | 250 +++++++++++++++++ mino/minows/session_test.go | 315 +++++++++++++++++++++ 15 files changed, 2996 insertions(+), 25 deletions(-) create mode 100644 mino/minows/README.md create mode 100644 mino/minows/address.go create mode 100644 mino/minows/address_test.go create mode 100644 mino/minows/controller.go create mode 100644 mino/minows/controller_test.go create mode 100644 mino/minows/key/mod.go create mode 100644 mino/minows/mod.go create mode 100644 mino/minows/mod_test.go create mode 100644 mino/minows/rpc.go create mode 100644 mino/minows/rpc_test.go create mode 100644 mino/minows/session.go create mode 100644 mino/minows/session_test.go diff --git a/go.mod b/go.mod index a4536b4be..cf4166011 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,11 @@ go 1.21 require ( github.com/golang/protobuf v1.5.4 + github.com/libp2p/go-libp2p v0.35.2 + github.com/multiformats/go-multiaddr v0.13.0 github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_golang v1.19.1 github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.32.0 github.com/stretchr/testify v1.9.0 @@ -15,9 +17,9 @@ require ( go.dedis.ch/debugtools v0.1.1 go.dedis.ch/kyber/v3 v3.1.0 go.etcd.io/bbolt v1.3.9 - golang.org/x/crypto v0.22.0 - golang.org/x/net v0.24.0 - golang.org/x/tools v0.20.0 + golang.org/x/crypto v0.23.0 + golang.org/x/net v0.25.0 + golang.org/x/tools v0.21.0 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/grpc v1.63.0 gopkg.in/yaml.v2 v2.4.0 @@ -25,28 +27,107 @@ require ( require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/elastic/gosigar v0.14.2 // indirect + github.com/flynn/noise v1.1.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect + github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // 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-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pion/datachannel v1.5.6 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/ice/v2 v2.3.25 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.40 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect + github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.dedis.ch/protobuf v1.0.11 // indirect go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.22.1 // indirect + go.uber.org/mock v0.4.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index a251da256..f11d501d3 100644 --- a/go.sum +++ b/go.sum @@ -1,91 +1,383 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= +github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= +github.com/libp2p/go-libp2p v0.35.2 h1:287oHbuplkrLdAF+syB0n/qDgd50AUBtEODqS0e0HDs= +github.com/libp2p/go-libp2p v0.35.2/go.mod h1:RKCDNt30IkFipGL0tl8wQW/3zVWEGFUZo8g2gAKxwjU= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= +github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= +github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= +github.com/libp2p/go-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-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= +github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= +github.com/multiformats/go-multiaddr v0.13.0/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/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/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +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.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs= +github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +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/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +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/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= +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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/debugtools v0.1.1 h1:p/arQ7o9QLZ0JI0soA4CdQh9i3Enphr+O2bs5pWLqLA= go.dedis.ch/debugtools v0.1.1/go.mod h1:Yp+5sHo3/Pfvl1cq70nhbZs8sv1WlUyk1LWph7xFntg= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= @@ -100,56 +392,200 @@ go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +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/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys= +go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +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.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +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.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= @@ -158,24 +594,52 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/mino/mino.go b/mino/mino.go index 537bf01d9..ebcf31602 100644 --- a/mino/mino.go +++ b/mino/mino.go @@ -48,6 +48,8 @@ const ( ACTgRPCS // ACThttps is a publicly signed TLS secured grpc connection ACThttps + // ACTws is a WebSocket connection + ACTws ) // Address is a representation of a node's address. diff --git a/mino/minows/README.md b/mino/minows/README.md new file mode 100644 index 000000000..48a4bd3d0 --- /dev/null +++ b/mino/minows/README.md @@ -0,0 +1,18 @@ +# `minows` +This package implements `Mino` interface using `go-libp2p`. More info is to be added as development progresses. + +## Connection Types +`minows` supports 2 types of connections between nodes: +- WebSocket (WS): plaintext exchange without encryption, primarily used for local testing and development +- WebSocket Secure (WSS): encrypted WebSocket connections, used in production environments + +## Architecture +`minows` provides a minimalistic network overlay using WebSocket (Secure) connections. It assumes the following network environment, as illustrated by the diagram: + +- nodes are running in local networks with private addresses (e.g. 172.24.0.6) +- nodes listen on port 8080 for HTTP connections (:8080) +- Traefik is configured on each node to listen on port 443 for connections to the public hostname (e.g. p2p-1.dela-1.c4dt.org:443) +- Traefik accepts incoming HTTP connections from client nodes and establishes corresponding HTTP connections to server nodes +- the same connections then upgrade to WebSocket Secure (WSS) or WebSocket (WS) between the client node and Traefik, and WebSocket (WS) between Traefik and the server node + +![](./architecture.png) diff --git a/mino/minows/address.go b/mino/minows/address.go new file mode 100644 index 000000000..d23f5cbcb --- /dev/null +++ b/mino/minows/address.go @@ -0,0 +1,156 @@ +package minows + +import ( + "go.dedis.ch/dela" + "strings" + + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "golang.org/x/xerrors" +) + +const protocolP2P = "/p2p/" + +// address represents a publicly reachable network address that can be used +// to establish communication with a remote player through libp2p and, +// therefore, must have both `location` and `identity` components. +// - implements mino.Address +type address struct { + location ma.Multiaddr + identity peer.ID +} + +// newAddress creates a new address from a publicly reachable location with a +// peer identity. +func newAddress(location ma.Multiaddr, identity peer.ID) (address, error) { + if location == nil || identity.String() == "" { + return address{}, xerrors.New("address must have location and identity") + } + return address{ + location: location, + identity: identity, + }, nil +} + +// Equal implements mino.Address. +func (a address) Equal(other mino.Address) bool { + switch o := other.(type) { + case address: + return equalOrBothNil(a.location, o.location) && a.identity == o.identity + case orchestratorAddr: + return o.Equal(a) + } + return false +} + +// String implements fmt.Stringer. +func (a address) String() string { + var sb strings.Builder + + if a.location != nil { + sb.WriteString(a.location.String()) + } + + if a.identity.String() != "" { + sb.WriteString(protocolP2P) + sb.WriteString(a.identity.String()) + } + + return sb.String() +} + +// ConnectionType implements mino.Address +// Not used by minows +func (a address) ConnectionType() mino.AddressConnectionType { + return mino.ACTws +} + +// MarshalText implements encoding.TextMarshaler. +func (a address) MarshalText() ([]byte, error) { + location := "" + if a.location != nil { + location = a.location.String() + } + identity := a.identity.String() + return []byte(strings.Join([]string{location, identity}, ":")), nil +} + +// - implements mino.Address +type orchestratorAddr struct { + address +} + +func newOrchestratorAddr(location ma.Multiaddr, + identity peer.ID) (orchestratorAddr, error) { + addr, err := newAddress(location, identity) + if err != nil { + return orchestratorAddr{}, err + } + return orchestratorAddr{addr}, nil +} + +func (a orchestratorAddr) Equal(other mino.Address) bool { + switch o := other.(type) { + case orchestratorAddr: + return equalOrBothNil(a.location, o.location) && a.identity == o.identity + case address: + // Allows orchestrator to match its participant public address + return equalOrBothNil(a.location, o.location) + } + return false +} + +func (a orchestratorAddr) MarshalText() ([]byte, error) { + data, _ := a.address.MarshalText() + return append(data, []byte(":o")...), nil +} + +func equalOrBothNil(a, b ma.Multiaddr) bool { + if a != nil && b != nil { + return a.Equal(b) + } + return a == b +} + +// addressFactory is a factory to deserialize Minows addresses. +// - implements mino.AddressFactory +type addressFactory struct { + serde.Factory +} + +// FromText returns an instance of an address +// from a byte slice or nil if anything fails. +// - implements mino.AddressFactory +func (f addressFactory) FromText(text []byte) mino.Address { + parts := strings.Split(string(text), ":") + if len(parts) < 2 { + return nil + } + + location, err := ma.NewMultiaddr(parts[0]) + if err != nil { + dela.Logger.Error().Err(err). + Msgf("could not parse multiaddress %q", parts[0]) + return nil + } + identity, err := peer.Decode(parts[1]) + if err != nil { + dela.Logger.Error().Err(err). + Msgf("could not decode peer ID %q", parts[1]) + return nil + } + + var addr mino.Address + if len(parts) == 2 { + addr, err = newAddress(location, identity) + } else if parts[2] == "o" { + addr, err = newOrchestratorAddr(location, identity) + } + if err != nil { + dela.Logger.Error().Err(err).Msgf("could not create address") + return nil + } + return addr +} diff --git a/mino/minows/address_test.go b/mino/minows/address_test.go new file mode 100644 index 000000000..5cccd7adb --- /dev/null +++ b/mino/minows/address_test.go @@ -0,0 +1,320 @@ +package minows + +import ( + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/mino" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_newAddress(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const pid2 = "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv" + const addrAllInterface = "/ip4/0.0.0.0/tcp/80" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + type args struct { + location string + identity string + } + tests := map[string]struct { + args args + }{ + "all interface": { + args: args{addrAllInterface, pid1}, + }, + "localhost": { + args: args{addrLocalhost, pid2}, + }, + "hostname": { + args: args{addrHostname, pid1}, + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + location := mustCreateMultiaddress(t, tt.args.location) + identity := mustCreatePeerID(t, tt.args.identity) + + _, err := newAddress(location, identity) + require.NoError(t, err) + }) + } +} + +func Test_newAddress_Invalid(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const addrAllInterface = "/ip4/0.0.0.0/tcp/80" + + tests := map[string]struct { + location ma.Multiaddr + identity peer.ID + }{ + "missing location": { + location: nil, + identity: mustCreatePeerID(t, pid1), + }, + "missing identity": { + location: mustCreateMultiaddress(t, addrAllInterface), + identity: "", + }} + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + _, err := newAddress(tt.location, tt.identity) + require.Error(t, err) + }) + } +} + +func Test_address_Equal(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const pid2 = "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + reference := mustCreateAddress(t, addrHostname, pid1) + tests := map[string]struct { + self address + other mino.Address + out bool + }{ + "self": { + self: reference, + other: reference, + out: true, + }, + "copy": { + self: reference, + other: mustCreateAddress(t, addrHostname, pid1), + out: true, + }, + "diff location": { + self: reference, + other: mustCreateAddress(t, addrLocalhost, pid1), + out: false, + }, + "diff identity": { + self: reference, + other: mustCreateAddress(t, addrHostname, pid2), + out: false, + }, + "nil": { + self: reference, + other: nil, + out: false, + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result := tt.self.Equal(tt.other) + + require.Equal(t, tt.out, result) + }) + } +} + +func Test_address_String(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const pid2 = "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv" + const addrAllInterface = "/ip4/0.0.0.0/tcp/80" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + tests := map[string]struct { + a address + want string + }{ + "all interface": { + a: mustCreateAddress(t, addrAllInterface, pid1), + want: "/ip4/0.0.0.0/tcp/80/p2p/QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU", + }, + "localhost": { + a: mustCreateAddress(t, addrLocalhost, pid2), + want: "/ip4/127.0.0.1/tcp/80/p2p/QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv", + }, + "hostname": { + a: mustCreateAddress(t, addrHostname, pid1), + want: "/dns4/example.com/tcp/80/p2p/QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU", + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result := tt.a.String() + + require.Equal(t, tt.want, result) + }) + } +} + +func Test_address_MarshalText(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const pid2 = "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv" + const addrAllInterface = "/ip4/0.0.0.0/tcp/80" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + tests := map[string]struct { + a address + want []byte + }{ + "all interface": { + a: mustCreateAddress(t, addrAllInterface, pid1), + want: []byte("/ip4/0.0.0.0/tcp/80" + + ":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU"), + }, + "localhost": { + a: mustCreateAddress(t, addrLocalhost, pid2), + want: []byte("/ip4/127.0.0.1/tcp/80" + + ":QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv"), + }, + "hostname": { + a: mustCreateAddress(t, addrHostname, pid1), + want: []byte("/dns4/example.com/tcp/80" + + ":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU"), + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result, err := tt.a.MarshalText() + + require.NoError(t, err) + require.Equal(t, tt.want, result) + }) + } +} + +func Test_orchestratorAddr_MarshalText(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + tests := map[string]struct { + a orchestratorAddr + want []byte + }{ + "localhost": { + a: mustCreateOrchestratorAddr(t, addrLocalhost, pid1), + want: []byte("/ip4/127.0.0.1/tcp/80" + + ":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU:o"), + }, + "hostname": { + a: mustCreateOrchestratorAddr(t, addrHostname, pid1), + want: []byte("/dns4/example.com/tcp/80" + + ":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU:o"), + }, + } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result, err := tt.a.MarshalText() + + require.NoError(t, err) + require.Equal(t, tt.want, result) + }) + } +} + +func Test_addressFactory_FromText(t *testing.T) { + const pid1 = "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU" + const pid2 = "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv" + const addrAllInterface = "/ip4/0.0.0.0/tcp/80" + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + const addrHostname = "/dns4/example.com/tcp/80" + tests := map[string]struct { + args []byte + want mino.Address + }{ + "all interface": { + args: []byte("/ip4/0.0.0.0/tcp/80:" + + "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU"), + want: mustCreateAddress(t, addrAllInterface, pid1), + }, + "localhost": { + args: []byte("/ip4/127.0.0.1/tcp/80:" + + "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv"), + want: mustCreateAddress(t, addrLocalhost, pid2), + }, + "hostname": { + args: []byte("/dns4/example.com/tcp/80:" + + "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU"), + want: mustCreateAddress(t, addrHostname, pid1), + }, + "orchestrator - localhost": { + args: []byte("/ip4/127.0.0.1/tcp/80:" + + "QmVt9t5Tk2uEoA4CDbKNCVxqrut8UXmWHXvFZ8wFZ3ghhv"), + want: mustCreateAddress(t, addrLocalhost, pid2), + }, + "orchestrator - hostname": { + args: []byte("/dns4/example.com/tcp/80" + + ":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU:o"), + want: mustCreateOrchestratorAddr(t, addrHostname, pid1), + }, + } + factory := addressFactory{} + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result := factory.FromText(tt.args) + + require.Equal(t, tt.want, result) + }) + } +} + +func Test_addressFactory_FromText_Invalid(t *testing.T) { + const addrLocalhost = "/ip4/127.0.0.1/tcp/80" + tests := map[string]struct { + args []byte + }{ + "invalid text": { + args: []byte("invalid"), + }, + "missing location": { + args: []byte(":QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU"), + }, + "missing identity": { + args: []byte(addrLocalhost), + }, + } + + factory := addressFactory{} + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + result := factory.FromText(tt.args) + + require.Nil(t, result) + }) + } +} + +func mustCreateOrchestratorAddr(t *testing.T, location, identity string) orchestratorAddr { + addr, err := newOrchestratorAddr(mustCreateMultiaddress(t, location), + mustCreatePeerID(t, identity)) + require.NoError(t, err) + return addr +} + +func mustCreateAddress(t *testing.T, location, identity string) address { + addr, err := newAddress(mustCreateMultiaddress(t, location), + mustCreatePeerID(t, identity)) + require.NoError(t, err) + return addr +} + +func mustCreateMultiaddress(t *testing.T, address string) ma.Multiaddr { + if address == "" { + return nil + } + multiaddr, err := ma.NewMultiaddr(address) + require.NoError(t, err) + return multiaddr +} + +func mustCreatePeerID(t *testing.T, id string) peer.ID { + pid, err := peer.Decode(id) + require.NoError(t, err) + return pid +} diff --git a/mino/minows/controller.go b/mino/minows/controller.go new file mode 100644 index 000000000..edb5f6b3d --- /dev/null +++ b/mino/minows/controller.go @@ -0,0 +1,111 @@ +package minows + +import ( + "fmt" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/cli" + "go.dedis.ch/dela/cli/node" + "go.dedis.ch/dela/core/store/kv" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/mino/minows/key" + "golang.org/x/xerrors" +) + +// controller +// - implements node.Initializer +type controller struct{} + +// NewController creates a CLI app to start a Minows instance. +func NewController() node.Initializer { + return controller{} +} + +const flagListen = "listen" +const flagPublic = "public" + +func (c controller) SetCommands(builder node.Builder) { + builder.SetStartFlags( + cli.StringFlag{ + Name: flagListen, + Usage: "Set the address to listen on (default all interfaces, " + + "random port)", + Required: false, + Value: "/ip4/0.0.0.0/tcp/0", + }, + cli.StringFlag{ + Name: flagPublic, + Usage: "Set the publicly reachable address (" + + "default listen address)", + Required: false, + Value: "", + }, + ) + + cmd := builder.SetCommand("list") + sub := cmd.SetSubCommand("address") + sub.SetDescription("Print this node's full dialable address") + sub.SetAction(builder.MakeAction(addressAction{})) +} + +func (c controller) OnStart(flags cli.Flags, inj node.Injector) error { + listen, err := ma.NewMultiaddr(flags.String(flagListen)) + if err != nil { + return xerrors.Errorf("could not parse listen addr: %v", err) + } + + var db kv.DB + err = inj.Resolve(&db) + if err != nil { + return xerrors.Errorf("could not resolve db: %v", err) + } + storage := key.NewStorage(db) + key, err := storage.LoadOrCreate() + if err != nil { + return xerrors.Errorf("could not load key: %v", err) + } + + var public ma.Multiaddr + p := flags.String(flagPublic) + if p != "" { + public, err = ma.NewMultiaddr(p) + if err != nil { + return xerrors.Errorf("could not parse public addr: %v", err) + } + } + + m, err := NewMinows(listen, public, key) + if err != nil { + return xerrors.Errorf("could not start mino: %v", err) + } + inj.Inject(m) + return nil +} + +func (c controller) OnStop(inj node.Injector) error { + var m *minows + err := inj.Resolve(&m) + if err != nil { + return xerrors.Errorf("could not resolve mino: %v", err) + } + err = m.stop() + if err != nil { + return xerrors.Errorf("could not stop mino: %v", err) + } + return nil +} + +// - implements node.ActionTemplate +type addressAction struct{} + +func (a addressAction) Execute(req node.Context) error { + var m mino.Mino + err := req.Injector.Resolve(&m) + if err != nil { + return xerrors.Errorf("could not resolve: %v", err) + } + _, err = fmt.Fprint(req.Out, m.GetAddress()) + if err != nil { + return err + } + return nil +} diff --git a/mino/minows/controller_test.go b/mino/minows/controller_test.go new file mode 100644 index 000000000..c074485eb --- /dev/null +++ b/mino/minows/controller_test.go @@ -0,0 +1,127 @@ +package minows + +import ( + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.dedis.ch/dela/cli" + "go.dedis.ch/dela/cli/node" + "go.dedis.ch/dela/testing/fake" + "testing" + "time" +) + +func TestController_OnStart(t *testing.T) { + flags, inj, ctrl, stop := setUp(t, "/ip4/0.0.0.0/tcp/8000/ws", + "/dns4/p2p-1.c4dt.dela.org/tcp/443/wss") + defer stop() + + err := ctrl.OnStart(flags, inj) + require.NoError(t, err) + var m *minows + err = inj.Resolve(&m) + require.NoError(t, err) +} + +func TestController_OptionalPublic(t *testing.T) { + flags, inj, ctrl, stop := setUp(t, "/ip4/0.0.0.0/tcp/8000/ws", "") + defer stop() + + err := ctrl.OnStart(flags, inj) + require.NoError(t, err) + var m *minows + err = inj.Resolve(&m) + require.NoError(t, err) +} + +func TestController_InvalidListen(t *testing.T) { + flags, inj, ctrl, _ := setUp(t, "invalid", + "/dns4/p2p-1.c4dt.dela.org/tcp/443/wss") + + err := ctrl.OnStart(flags, inj) + require.Error(t, err) +} + +func TestController_InvalidPublic(t *testing.T) { + flags, inj, ctrl, _ := setUp(t, "/ip4/0.0.0.0/tcp/8000/ws", + "invalid") + + err := ctrl.OnStart(flags, inj) + require.Error(t, err) +} + +func TestController_OnStop(t *testing.T) { + flags, inj, ctrl, _ := setUp(t, "/ip4/0.0.0.0/tcp/8000/ws", + "/dns4/p2p-1.c4dt.dela.org/tcp/443/wss") + err := ctrl.OnStart(flags, inj) + require.NoError(t, err) + + err = ctrl.OnStop(inj) + require.NoError(t, err) +} + +func TestController_MissingDependency(t *testing.T) { + flags, inj, ctrl, _ := setUp(t, "/ip4/0.0.0.0/tcp/8000/ws", + "/dns4/p2p-1.c4dt.dela.org/tcp/443/wss") + err := ctrl.OnStart(flags, inj) + require.NoError(t, err) + + err = ctrl.OnStop(node.NewInjector()) + require.Error(t, err) +} + +func mustCreateController(t *testing.T, inj node.Injector) (node.Initializer, func()) { + ctrl := NewController() + stop := func() { + require.NoError(t, ctrl.OnStop(inj)) + } + return ctrl, stop +} + +func setUp(t *testing.T, listen string, public string) ( + cli.Flags, node.Injector, node.Initializer, func()) { + flags := new(mockFlags) + flags.On("String", "listen").Return(listen) + flags.On("String", "public").Return(public) + inj := node.NewInjector() + inj.Inject(fake.NewInMemoryDB()) + + ctrl, stop := mustCreateController(t, inj) + + return flags, inj, ctrl, stop +} + +// mockFlags +// - implements cli.Flags +type mockFlags struct { + mock.Mock +} + +func (m *mockFlags) String(name string) string { + args := m.Called(name) + return args.String(0) +} + +func (m *mockFlags) StringSlice(name string) []string { + args := m.Called(name) + return args.Get(0).([]string) +} + +func (m *mockFlags) Duration(name string) time.Duration { + args := m.Called(name) + return args.Get(0).(time.Duration) +} + +func (m *mockFlags) Path(name string) string { + args := m.Called(name) + return args.String(0) +} + +func (m *mockFlags) Int(name string) int { + args := m.Called(name) + return args.Int(0) +} + +func (m *mockFlags) Bool(name string) bool { + args := m.Called(name) + return args.Bool(0) +} diff --git a/mino/minows/key/mod.go b/mino/minows/key/mod.go new file mode 100644 index 000000000..2a07a0aab --- /dev/null +++ b/mino/minows/key/mod.go @@ -0,0 +1,63 @@ +package key + +import ( + "crypto/rand" + "github.com/libp2p/go-libp2p/core/crypto" + "go.dedis.ch/dela/core/store/kv" + "golang.org/x/xerrors" +) + +// Storage provides persistent Storage for private keys. +type Storage struct { + bucket []byte + db kv.DB +} + +// NewStorage creates a new Storage for private keys. +func NewStorage(db kv.DB) *Storage { + return &Storage{ + bucket: []byte("keys"), + db: db, + } +} + +// LoadOrCreate loads the private key from Storage or +// creates a new one if none exists. +func (s *Storage) LoadOrCreate() (crypto.PrivKey, error) { + key := []byte("private_key") + var buffer []byte + err := s.db.Update(func(tx kv.WritableTx) error { + bucket, err := tx.GetBucketOrCreate(s.bucket) + if err != nil { + return xerrors.Errorf("could not get bucket: %v", err) + } + + bytes := bucket.Get(key) + if bytes == nil { + private, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return xerrors.Errorf("could not generate key: %v", err) + } + bytes, err = crypto.MarshalPrivateKey(private) + if err != nil { + return xerrors.Errorf("could not marshal key: %v", err) + } + err = bucket.Set(key, bytes) + if err != nil { + return xerrors.Errorf("could not store key: %v", err) + } + } + buffer = make([]byte, len(bytes)) + copy(buffer, bytes) + return nil + }) + if err != nil { + return nil, xerrors.Errorf("could not update db: %v", err) + } + + private, err := crypto.UnmarshalPrivateKey(buffer) + if err != nil { + return nil, xerrors.Errorf("could not unmarshal key: %v", err) + } + return private, nil +} diff --git a/mino/minows/mod.go b/mino/minows/mod.go new file mode 100644 index 000000000..bdea00c4e --- /dev/null +++ b/mino/minows/mod.go @@ -0,0 +1,127 @@ +package minows + +import ( + "github.com/rs/zerolog" + "go.dedis.ch/dela" + "go.dedis.ch/dela/serde/json" + "regexp" + "strings" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/protocol" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "golang.org/x/xerrors" +) + +var pattern = regexp.MustCompile("^[a-zA-Z0-9]+$") + +// Minows +// - implements mino.Mino +type minows struct { + logger zerolog.Logger + + myAddr address + host host.Host + segments []string + rpcs map[string]any + factory addressFactory +} + +// NewMinows creates a new Minows instance that starts listening. +// listen: listening address in multiaddress format, +// e.g. /ip4/127.0.0.1/tcp/80/ws +// public: public dial-able address in multiaddress format, +// e.g. /dns4/p2p-1.c4dt.dela.org/tcp/443/wss +// `public` can be nil and will be determined +// by the listening address and the port the host has bound to. +// key: private key representing this mino instance's identity +func NewMinows(listen, public ma.Multiaddr, key crypto.PrivKey) (mino.Mino, + error) { + h, err := libp2p.New(libp2p.ListenAddrs(listen), libp2p.Identity(key)) + if err != nil { + return nil, xerrors.Errorf("could not start host: %v", err) + } + + if public == nil { + public = h.Addrs()[0] + } + myAddr, err := newAddress(public, h.ID()) + if err != nil { + return nil, xerrors.Errorf("could not create address: %v", err) + } + + return &minows{ + logger: dela.Logger.With().Str("mino", myAddr.String()).Logger(), + myAddr: myAddr, + segments: nil, + host: h, + rpcs: make(map[string]any), + factory: addressFactory{}, + }, nil +} + +func (m *minows) GetAddressFactory() mino.AddressFactory { + return m.factory +} + +func (m *minows) GetAddress() mino.Address { + return m.myAddr +} + +func (m *minows) WithSegment(segment string) mino.Mino { + if segment == "" { + return m + } + + return &minows{ + logger: m.logger, + myAddr: m.myAddr, + segments: append(m.segments, segment), + host: m.host, + rpcs: make(map[string]any), + factory: addressFactory{}, + } +} + +func (m *minows) CreateRPC(name string, h mino.Handler, f serde.Factory) (mino.RPC, error) { + if len(m.rpcs) == 0 { + for _, seg := range m.segments { + if !pattern.MatchString(seg) { + return nil, xerrors.Errorf("invalid segment: %s", seg) + } + } + } + + if !pattern.MatchString(name) { + return nil, xerrors.Errorf("invalid name: %s", name) + } + _, found := m.rpcs[name] + if found { + return nil, xerrors.Errorf("already exists rpc: %s", name) + } + + uri := strings.Join(append(m.segments, name), "/") + + r := &rpc{ + logger: m.logger.With().Str("rpc", uri).Logger(), + uri: uri, + handler: h, + mino: m, + factory: f, + context: json.NewContext(), + } + + m.host.SetStreamHandler(protocol.ID(uri+pathCall), r.handleCall) + m.host.SetStreamHandler(protocol.ID(uri+pathStream), r.handleStream) + m.rpcs[name] = nil + + return r, nil +} + +func (m *minows) stop() error { + return m.host.Close() +} diff --git a/mino/minows/mod_test.go b/mino/minows/mod_test.go new file mode 100644 index 000000000..53f5726cd --- /dev/null +++ b/mino/minows/mod_test.go @@ -0,0 +1,237 @@ +package minows + +import ( + "crypto/rand" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + "testing" +) + +func TestNewMinows(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452/ws" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + const wss = "/ip4/127.0.0.1/tcp/443/wss" + var tests = map[string]struct { + listen string + public string + }{ + "ws": {listen: listen, public: ws}, + "wss": {listen: listen, public: wss}, + } + key := mustCreateKey(t) + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + listen := mustCreateMultiaddress(t, tt.listen) + public := mustCreateMultiaddress(t, tt.public) + + m, err := NewMinows(listen, public, key) + require.NoError(t, err) + require.NotNil(t, m) + require.IsType(t, &minows{}, m) + require.NoError(t, m.(*minows).stop()) + }) + } +} + +func TestNewMinows_OptionalPublic(t *testing.T) { + listen := mustCreateMultiaddress(t, "/ip4/0.0.0.0/tcp/7452/ws") + random := mustCreateMultiaddress(t, "/ip4/127.0.0.1/tcp/0/ws") + tests := map[string]ma.Multiaddr{ + "no public": listen, + "random listen": random, + } + key := mustCreateKey(t) + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + m, err := NewMinows(tt, nil, key) + require.NoError(t, err) + require.NotNil(t, m) + require.IsType(t, &minows{}, m) + require.NoError(t, m.(*minows).stop()) + }) + + } +} + +func Test_minows_GetAddressFactory(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + const wss = "/ip4/127.0.0.1/tcp/443/wss" + type m struct { + listen string + public string + } + tests := map[string]struct { + m m + }{ + "ws": {m{listen, ws}}, + "wss": {m{listen, wss}}, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + m, stop := mustCreateMinows(t, tt.m.listen, tt.m.public) + defer stop() + + factory := m.GetAddressFactory() + require.NotNil(t, factory) + require.IsType(t, addressFactory{}, factory) + }) + } +} + +func Test_minows_GetAddress(t *testing.T) { + const listen = "/ip4/127.0.0.1/tcp/7452" + const publicWS = "/ip4/127.0.0.1/tcp/80/ws" + const wss = "/ip4/127.0.0.1/tcp/443/wss" + key := mustCreateKey(t) + id := mustDerivePeerID(t, key).String() + type m struct { + listen string + public string + key crypto.PrivKey + } + type want struct { + location string + identity string + } + tests := map[string]struct { + m m + want want + }{ + "ws": {m{listen, publicWS, key}, want{publicWS, id}}, + "wss": {m{listen, wss, key}, want{wss, id}}, + "no public": {m{listen, "", key}, want{listen, id}}, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + m, err := NewMinows(mustCreateMultiaddress(t, tt.m.listen), + mustCreateMultiaddress(t, tt.m.public), tt.m.key) + require.NoError(t, err) + defer require.NoError(t, m.(*minows).stop()) + want := mustCreateAddress(t, tt.want.location, tt.want.identity) + + got := m.GetAddress() + require.Equal(t, want, got) + }) + } +} + +func Test_minows_GetAddress_Random(t *testing.T) { + random := "/ip4/127.0.0.1/tcp/0/ws" + listen := mustCreateMultiaddress(t, random) + key := mustCreateKey(t) + m, err := NewMinows(listen, nil, key) + require.NoError(t, err) + defer require.NoError(t, m.(*minows).stop()) + + got := m.GetAddress().(address) + port, err := got.location.ValueForProtocol(ma.P_TCP) + require.NoError(t, err) + require.NotEqual(t, 0, port) +} + +func Test_minows_WithSegment_Empty(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + + got := m.WithSegment("") + require.Equal(t, m, got) +} + +func Test_minows_WithSegment(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + + got := m.WithSegment("test") + require.NotEqual(t, m, got) + + got2 := m.WithSegment("test").WithSegment("test") + require.NotEqual(t, m, got2) + require.NotEqual(t, got, got2) +} + +func Test_minows_CreateRPC_InvalidName(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + + _, err := m.CreateRPC("invalid name", nil, nil) + require.Error(t, err) +} + +func Test_minows_CreateRPC_AlreadyExists(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + + _, err := m.CreateRPC("test", nil, nil) + require.NoError(t, err) + _, err = m.CreateRPC("test", nil, nil) + require.Error(t, err) +} + +func Test_minows_CreateRPC_InvalidSegment(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + m = m.WithSegment("invalid segment").(*minows) + + _, err := m.CreateRPC("test", nil, nil) + require.Error(t, err) +} + +func Test_minows_CreateRPC(t *testing.T) { + const listen = "/ip4/0.0.0.0/tcp/7452" + const ws = "/ip4/127.0.0.1/tcp/7452/ws" + m, stop := mustCreateMinows(t, listen, ws) + defer stop() + + r1, err := m.CreateRPC("test", nil, nil) + require.NoError(t, err) + require.NotNil(t, r1) + r2, err := m.CreateRPC("Test", nil, nil) + require.NoError(t, err) + require.NotNil(t, r2) + + m = m.WithSegment("segment").(*minows) + r3, err := m.CreateRPC("test", nil, nil) + require.NoError(t, err) + require.NotNil(t, r3) + r4, err := m.CreateRPC("Test", nil, nil) + require.NoError(t, err) + require.NotNil(t, r4) +} + +func mustCreateMinows(t *testing.T, listen string, public string) (*minows, + func()) { + key := mustCreateKey(t) + lis := mustCreateMultiaddress(t, listen) + pub := mustCreateMultiaddress(t, public) + m, err := NewMinows(lis, pub, key) + require.NoError(t, err) + ws := m.(*minows) + stop := func() { require.NoError(t, ws.stop()) } + return ws, stop +} + +func mustCreateKey(t *testing.T) crypto.PrivKey { + key, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + return key +} + +func mustDerivePeerID(t *testing.T, key crypto.PrivKey) peer.ID { + pid, err := peer.IDFromPrivateKey(key) + require.NoError(t, err) + return pid +} diff --git a/mino/minows/rpc.go b/mino/minows/rpc.go new file mode 100644 index 000000000..52a72ca33 --- /dev/null +++ b/mino/minows/rpc.go @@ -0,0 +1,422 @@ +package minows + +import ( + "context" + "encoding/gob" + "errors" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/core/protocol" + ma "github.com/multiformats/go-multiaddr" + "github.com/rs/xid" + "github.com/rs/zerolog" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "golang.org/x/xerrors" + "strings" + "sync" + "time" +) + +const pathCall = "/call" +const pathStream = "/stream" + +// Packet encapsulates a message sent over the network streams. +type Packet struct { + Source []byte + Payload []byte +} + +type envelope struct { + author mino.Address + msg serde.Message + err error +} + +// RPC +// - implements mino.RPC +type rpc struct { + logger zerolog.Logger + + uri string + handler mino.Handler + mino *minows + factory serde.Factory + context serde.Context +} + +func (r rpc) Call(ctx context.Context, req serde.Message, + players mino.Players) (<-chan mino.Response, error) { + if players == nil || players.Len() == 0 { + resp := make(chan mino.Response) + close(resp) + return resp, nil + } + + addrs, err := toAddresses(players) + if err != nil { + return nil, err + } + + r.addPeers(addrs) + + result := make(chan envelope, len(addrs)) + for _, addr := range addrs { + if r.mino.myAddr.Equal(addr) { + request := mino.Request{Address: r.mino.myAddr, Message: req} + reply, err := r.handler.Process(request) + result <- envelope{r.mino.myAddr, reply, err} + } else { + go func(addr address) { + reply, err := r.unicast(ctx, addr, req) + result <- envelope{addr, reply, err} + }(addr) + } + } + + responses := make(chan mino.Response, len(addrs)) + go func() { + defer close(responses) + for i := 0; i < len(addrs); i++ { + select { + case <-ctx.Done(): + return + case env := <-result: + if env.err != nil { + responses <- mino.NewResponseWithError(env.author, env.err) + } else { + responses <- mino.NewResponse(env.author, env.msg) + } + } + } + }() + return responses, nil +} + +func (r rpc) Stream(ctx context.Context, players mino.Players) (mino.Sender, mino.Receiver, error) { + if players == nil || players.Len() == 0 { + return nil, nil, xerrors.New("no players") + } + + initiator, err := libp2p.New(libp2p.NoListenAddrs) + if err != nil { + return nil, nil, xerrors.Errorf("could not start host: %v", err) + } + + go func() { + <-ctx.Done() + err := initiator.Close() + if err != nil { + r.logger.Error().Err(err).Msg("could not close host") + } + }() + + errs := make(chan error, players.Len()) + streams := make(chan network.Stream, players.Len()) + var wg sync.WaitGroup + wg.Add(players.Len()) + for iter := players.AddressIterator(); iter.HasNext(); { + player := iter.GetNext() + addr, ok := player.(address) + if !ok { + return nil, nil, xerrors.Errorf("%v: %T", + ErrWrongAddressType, player) + } + go func(addr address) { + defer wg.Done() + initiator.Peerstore().AddAddr(addr.identity, addr.location, + peerstore.PermanentAddrTTL) + + stream, err := initiator.NewStream(ctx, addr.identity, + protocol.ID(r.uri+pathStream)) + if err != nil { + errs <- xerrors.Errorf("could not open stream: %v", err) + return + } + streams <- stream + go func() { + <-ctx.Done() + err = stream.Reset() + if err != nil { + r.logger.Error().Err(err).Msg("could not reset stream") + } + }() + }(addr) + } + + wg.Wait() + close(errs) + close(streams) + for err := range errs { + return nil, nil, err + } + + opened := make([]network.Stream, 0, players.Len()) + for stream := range streams { + opened = append(opened, stream) + } + o, err := r.createOrchestrator(ctx, initiator, opened) + if err != nil { + return nil, nil, xerrors.Errorf("could not create orchestrator: %v", err) + } + return o, o, nil +} + +func (r rpc) handleCall(stream network.Stream) { + handle := func() error { + dec := gob.NewDecoder(stream) + from, req, err := r.receive(dec) + if err != nil { + return xerrors.Errorf("could not receive: %v", err) + } + + id := stream.Conn().RemotePeer() + author := address{location: from, identity: id} + reply, err := r.handler.Process(mino.Request{Address: author, Message: req}) + if err != nil { + return xerrors.Errorf("could not process: %v", err) + } + + enc := gob.NewEncoder(stream) + err = r.send(enc, reply) + if err != nil { + return xerrors.Errorf("could not reply: %v", err) + } + return nil + } + + err := handle() + if err != nil { + r.logger.Error().Err(err).Msg("could not handle call") + } +} + +func (r rpc) handleStream(stream network.Stream) { + p := r.createParticipant(stream) + + go func() { + err := r.handler.Stream(p, p) + if err != nil { + r.logger.Error().Err(err).Msg("could not handle stream") + } + }() +} + +func toAddresses(players mino.Players) ([]address, error) { + addrs := make([]address, 0, players.Len()) + iter := players.AddressIterator() + for iter.HasNext() { + player := iter.GetNext() + addr, ok := player.(address) + if !ok { + return nil, xerrors.Errorf("wrong address type: %T", player) + } + addrs = append(addrs, addr) + } + return addrs, nil +} + +func (r rpc) addPeers(addrs []address) { + for _, addr := range addrs { + r.mino.host.Peerstore().AddAddr(addr.identity, addr.location, + peerstore.PermanentAddrTTL) + } +} + +func (r rpc) unicast(ctx context.Context, dest address, req serde.Message) ( + serde.Message, error) { + stream, err := r.openStream(ctx, dest, pathCall) + if err != nil { + return nil, xerrors.Errorf("could not open stream: %v", err) + } + + dec := gob.NewEncoder(stream) + err = r.send(dec, req) + if err != nil { + return nil, xerrors.Errorf("could not send request: %v", err) + } + + enc := gob.NewDecoder(stream) + _, reply, err := r.receive(enc) + if err != nil { + return nil, xerrors.Errorf("could not receive reply: %v", err) + } + return reply, nil +} + +func (r rpc) openStream(ctx context.Context, dest address, + path string) (network.Stream, error) { + pid := protocol.ID(r.uri + path) + stream, err := r.mino.host.NewStream(ctx, dest.identity, pid) + if err != nil { + return nil, xerrors.Errorf("could not open stream: %v", err) + } + + go func() { + <-ctx.Done() + err := stream.Reset() + if err != nil { + r.logger.Error().Err(err).Msg("could not reset stream") + } + }() + + return stream, nil +} + +func (r rpc) send(enc *gob.Encoder, msg serde.Message) error { + from := r.mino.myAddr.location.Bytes() + + var payload []byte + if msg != nil { + bytes, err := msg.Serialize(r.context) + if err != nil { + return xerrors.Errorf("could not serialize message: %v", err) + } + payload = bytes + } + + err := enc.Encode(&Packet{Source: from, Payload: payload}) + if errors.Is(err, network.ErrReset) { + return err + } + if err != nil { + return xerrors.Errorf("could not encode packet: %v", err) + } + return nil +} + +func (r rpc) receive(dec *gob.Decoder) (ma.Multiaddr, serde.Message, error) { + var packet Packet + err := dec.Decode(&packet) + if errors.Is(err, network.ErrReset) { + return nil, nil, err + } + if err != nil { + return nil, nil, xerrors.Errorf("could not decode packet: %v", err) + } + + from, err := ma.NewMultiaddrBytes(packet.Source) + if err != nil { + return nil, nil, xerrors.Errorf("could not unmarshal address: %v", + packet.Source) + } + + if packet.Payload == nil { + return from, nil, nil + } + msg, err := r.factory.Deserialize(r.context, packet.Payload) + if err != nil { + return from, nil, xerrors.Errorf( + "could not deserialize message: %v", + err) + } + return from, msg, nil +} + +func (r rpc) createOrchestrator(ctx context.Context, + initiator host.Host, streams []network.Stream) (*orchestrator, error) { + participant := r.mino.GetAddress().(address).location + myAddr, err := newOrchestratorAddr(participant, initiator.ID()) + if err != nil { + return nil, xerrors.Errorf("could not create address: %v", err) + } + + encoders := make(map[peer.ID]*gob.Encoder) + for _, stream := range streams { + encoders[stream.Conn().RemotePeer()] = gob.NewEncoder(stream) + } + + o := &orchestrator{ + logger: r.logger.With().Stringer("mino", myAddr). + Stringer("orchestrator", xid.New()).Logger(), + myAddr: myAddr, + rpc: r, + outs: encoders, + in: make(chan Packet, MaxUnreadAllowed), + } + + var wg sync.WaitGroup + wg.Add(len(streams)) + for _, stream := range streams { + go func(stream network.Stream) { + defer wg.Done() + decoder := gob.NewDecoder(stream) + for { + packet, err := o.listen(decoder) + if err != nil { + if strings.Contains(err.Error(), network.ErrReset.Error()) { + return + } + r.logger.Error().Err(err).Msg("message dropped") + continue + } + select { + case <-ctx.Done(): + return + case o.in <- packet: + } + } + }(stream) + } + + go func() { + wg.Wait() + close(o.in) + }() + + return o, nil +} + +func (r rpc) createParticipant(stream network.Stream) participant { + encoder := gob.NewEncoder(stream) + decoder := gob.NewDecoder(stream) + + p := participant{ + logger: r.logger.With().Stringer("participant", xid.New()).Logger(), + myAddr: r.mino.myAddr, + rpc: r, + out: encoder, + in: make(chan Packet), + } + + done := make(chan any) + go func() { + hasReset := func() bool { + for _, s := range stream.Conn().GetStreams() { + if s.ID() == stream.ID() { + return false + } + } + return true + } + + for !hasReset() { + time.Sleep(2 * time.Second) + } + close(done) + }() + + go func() { + for { + packet, err := p.listen(decoder) + if err != nil { + if strings.Contains(err.Error(), network.ErrReset.Error()) { + close(p.in) + return + } + r.logger.Error().Err(err).Msg("message dropped") + continue + } + select { + case <-done: + return + case p.in <- packet: + } + } + }() + + return p +} diff --git a/mino/minows/rpc_test.go b/mino/minows/rpc_test.go new file mode 100644 index 000000000..1fa842a80 --- /dev/null +++ b/mino/minows/rpc_test.go @@ -0,0 +1,278 @@ +package minows + +import ( + "context" + "github.com/stretchr/testify/require" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "go.dedis.ch/dela/testing/fake" + "testing" +) + +func Test_rpc_Call(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := fake.Message{} + players := mino.NewAddresses(player.GetAddress()) + + responses, err := r.Call(ctx, req, players) + require.NoError(t, err) + resp := <-responses + from := resp.GetFrom().(address) + require.Equal(t, player.GetAddress(), from) + msg, err := resp.GetMessageOrError() + require.NoError(t, err) + require.Equal(t, fake.Message{}, msg) + _, ok := <-responses + require.False(t, ok) + require.Equal(t, []mino.Address{initiator.GetAddress()}, handler.from) +} + +func Test_rpc_Call_ToSelf(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := fake.Message{} + players := mino.NewAddresses(initiator.GetAddress()) + + responses, err := r.Call(ctx, req, players) + require.NoError(t, err) + resp := <-responses + from := resp.GetFrom().(address) + require.Equal(t, initiator.GetAddress(), from) + msg, err := resp.GetMessageOrError() + require.NoError(t, err) + require.Equal(t, fake.Message{}, msg) + _, ok := <-responses + require.False(t, ok) +} + +func Test_rpc_Call_NoPlayers(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := fake.Message{} + players := mino.NewAddresses() + + _, err := r.Call(ctx, req, players) + require.Nil(t, err) +} + +func Test_rpc_Call_WrongAddressType(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := fake.Message{} + players := mino.NewAddresses(fake.Address{}) + + _, err := r.Call(ctx, req, players) + require.ErrorContains(t, err, "wrong address type") +} + +func Test_rpc_Call_DiffNamespace(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player.WithSegment("segment"), "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := fake.Message{} + players := mino.NewAddresses(player.GetAddress()) + + responses, err := r.Call(ctx, req, players) + require.NoError(t, err) + resp := <-responses + from := resp.GetFrom().(address) + require.Equal(t, player.GetAddress(), from) + _, err = resp.GetMessageOrError() + require.ErrorContains(t, err, "protocols not supported") + _, open := <-responses + require.False(t, open) +} + +func Test_rpc_Call_ContextCancelled(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + req := fake.Message{} + players := mino.NewAddresses(player.GetAddress()) + + cancel() + responses, _ := r.Call(ctx, req, players) + <-responses + _, ok := <-responses + require.False(t, ok) +} + +func Test_rpc_Stream(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + players := mino.NewAddresses(player.GetAddress()) + + sender, receiver, err := r.Stream(ctx, players) + require.NoError(t, err) + require.NotNil(t, sender) + require.NotNil(t, receiver) +} + +func Test_rpc_Stream_ToSelf(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + players := mino.NewAddresses(initiator.GetAddress()) + + sender, receiver, err := r.Stream(ctx, players) + require.NoError(t, err) + require.NotNil(t, sender) + require.NotNil(t, receiver) +} + +func Test_rpc_Stream_NoPlayers(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + players := mino.NewAddresses() + + _, _, err := r.Stream(ctx, players) + require.ErrorContains(t, err, "no players") +} + +func Test_rpc_Stream_WrongAddressType(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + players := mino.NewAddresses(fake.Address{}) + + _, _, err := r.Stream(ctx, players) + require.ErrorContains(t, err, "wrong address type") +} + +func Test_rpc_Stream_ContextCancelled(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + ctx, cancel := context.WithCancel(context.Background()) + players := mino.NewAddresses(player.GetAddress()) + + cancel() + _, _, err := r.Stream(ctx, players) + require.Error(t, err) +} + +// echoHandler implements mino.Handler +// Captures senders of received messages for test assertions and +// echos back the same message +// - implements mino.Handler +type echoHandler struct { + from []mino.Address + messages []serde.Message +} + +func (h *echoHandler) Process(req mino.Request) (resp serde.Message, + err error) { + h.from = append(h.from, req.Address) + h.messages = append(h.messages, req.Message) + return req.Message, nil +} + +func (h *echoHandler) Stream(out mino.Sender, in mino.Receiver) error { + for { + from, msg, err := in.Recv(context.Background()) + if err != nil { + return err + } + h.from = append(h.from, from) + h.messages = append(h.messages, msg) + err = <-out.Send(msg, from) + if err != nil { + return err + } + } +} + +func mustCreateRPC(t *testing.T, m mino.Mino, name string, + h mino.Handler) mino.RPC { + r, err := m.CreateRPC(name, h, fake.MessageFactory{}) + require.NoError(t, err) + return r +} diff --git a/mino/minows/session.go b/mino/minows/session.go new file mode 100644 index 000000000..e82841180 --- /dev/null +++ b/mino/minows/session.go @@ -0,0 +1,250 @@ +package minows + +import ( + "context" + "encoding/gob" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/rs/zerolog" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "golang.org/x/xerrors" + "io" + "sync" +) + +var ErrWrongAddressType = xerrors.New("wrong address type") +var ErrNotPlayer = xerrors.New("not player") + +// MaxUnreadAllowed Maximum number of unread messages allowed +// in orchestrator's incoming message buffer before pausing relaying +const MaxUnreadAllowed = 1e3 + +type Forward struct { + Packet + Destination []byte +} + +type orchestrator struct { + logger zerolog.Logger + + myAddr orchestratorAddr + rpc rpc + // Connects to the participants + outs map[peer.ID]*gob.Encoder + in chan Packet +} + +func (o orchestrator) Send(msg serde.Message, addrs ...mino.Address) <-chan error { + return doSend(addrs, msg, o.send, o.logger) +} + +func (o orchestrator) Recv(ctx context.Context) (mino.Address, serde.Message, error) { + unpack := unpacker(o.rpc.mino.GetAddressFactory(), o.rpc.factory, o.rpc.context) + return doReceive(ctx, o.in, unpack, o.logger) +} + +func (o orchestrator) send(addr mino.Address, msg serde.Message) error { + var unwrapped address + switch a := addr.(type) { + case address: + unwrapped = a + case orchestratorAddr: + unwrapped = a.address + default: + return xerrors.Errorf("%v: %T", ErrWrongAddressType, addr) + } + + encoder, ok := o.outs[unwrapped.identity] + if !ok { + return xerrors.Errorf("%v: %v", ErrNotPlayer, addr) + } + src, err := o.myAddr.MarshalText() + if err != nil { + return xerrors.Errorf("could not marshal address: %v", err) + } + payload, err := msg.Serialize(o.rpc.context) + if err != nil { + return xerrors.Errorf("could not serialize message: %v", err) + } + + err = encoder.Encode(&Packet{Source: src, Payload: payload}) + if err != nil { + return xerrors.Errorf("could not encode packet: %v", err) + } + return nil +} + +func (o orchestrator) fetch(decoder *gob.Decoder) (Packet, mino.Address, + error) { + var forward Forward + err := decoder.Decode(&forward) + if err != nil { + return Packet{}, nil, + xerrors.Errorf("could not decode packet: %v", err) + } + dest := o.rpc.mino.GetAddressFactory(). + FromText(forward.Destination) + if dest == nil { + return Packet{}, nil, + xerrors.New("could not unmarshal address") + } + return forward.Packet, dest, nil +} + +func (o orchestrator) relay(packet Packet, dest address) error { + encoder, ok := o.outs[dest.identity] + if !ok { + return xerrors.Errorf("%v: %v", ErrNotPlayer, dest) + } + err := encoder.Encode(packet) + if err != nil { + return xerrors.Errorf("could not encode packet: %v", err) + } + o.logger.Debug().Stringer("to", dest).Msgf("relayed packet") + return nil +} + +func (o orchestrator) listen(decoder *gob.Decoder) (Packet, error) { + for { + packet, dest, err := o.fetch(decoder) + if err != nil { + return Packet{}, xerrors.Errorf("could not receive: %v", err) + } + switch to := dest.(type) { + case orchestratorAddr: + if o.myAddr.Equal(to) { + return packet, nil + } + case address: + err := o.relay(packet, to) + if err != nil { + return Packet{}, xerrors.Errorf("could not relay: %v", err) + } + } + } +} + +type participant struct { + logger zerolog.Logger + + myAddr address + rpc rpc + // Connects to the orchestrator + out *gob.Encoder + in chan Packet +} + +func (p participant) Send(msg serde.Message, addrs ...mino.Address) <-chan error { + return doSend(addrs, msg, p.send, p.logger) +} + +func (p participant) Recv(ctx context.Context) (mino.Address, serde.Message, error) { + unpack := unpacker(p.rpc.mino.GetAddressFactory(), p.rpc.factory, p.rpc.context) + return doReceive(ctx, p.in, unpack, p.logger) +} + +func (p participant) send(addr mino.Address, msg serde.Message) error { + switch addr.(type) { + case address: + case orchestratorAddr: + default: + return xerrors.Errorf("%v: %T", ErrWrongAddressType, addr) + } + + src, err := p.myAddr.MarshalText() + if err != nil { + return xerrors.Errorf("could not marshal address: %v", err) + } + payload, err := msg.Serialize(p.rpc.context) + if err != nil { + return xerrors.Errorf("could not serialize message: %v", err) + } + dest, err := addr.MarshalText() + if err != nil { + return xerrors.Errorf("could not marshal address: %v", err) + } + + // Send to orchestrator to relay to the destination participant + forward := Forward{ + Packet: Packet{Source: src, Payload: payload}, + Destination: dest, + } + err = p.out.Encode(&forward) + if err != nil { + return xerrors.Errorf("could not encode packet: %v", err) + } + return nil +} + +func (p participant) listen(decoder *gob.Decoder) (Packet, error) { + var packet Packet + err := decoder.Decode(&packet) + if err != nil { + return Packet{}, xerrors.Errorf("could not decode packet: %v", err) + } + return packet, nil +} + +type sendFn func(addr mino.Address, msg serde.Message) error + +func doSend(addrs []mino.Address, msg serde.Message, send sendFn, + logger zerolog.Logger) chan error { + errs := make(chan error, len(addrs)) + var wg sync.WaitGroup + wg.Add(len(addrs)) + for _, addr := range addrs { + go func(addr mino.Address) { + defer wg.Done() + err := send(addr, msg) + if err != nil { + errs <- xerrors.Errorf("could not send to %v: %v", addr, err) + logger.Warn().Err(err).Msgf("could not send %T to %v", msg, addr) + return + } + logger.Debug().Msgf("sent %T to %v", msg, addr) + }(addr) + } + + go func() { + wg.Wait() + close(errs) + }() + return errs +} + +type unpackFn func(packet Packet) (mino.Address, serde.Message, error) + +func unpacker(af mino.AddressFactory, f serde.Factory, + c serde.Context) unpackFn { + return func(packet Packet) (mino.Address, serde.Message, error) { + src := af.FromText(packet.Source) + if src == nil { + return nil, nil, xerrors.New("could not unmarshal address") + } + msg, err := f.Deserialize(c, packet.Payload) + if err != nil { + return src, nil, xerrors.Errorf("could not deserialize message: %v", err) + } + return src, msg, nil + } +} + +func doReceive(ctx context.Context, in chan Packet, + unpack unpackFn, logger zerolog.Logger) (mino.Address, serde.Message, error) { + select { + case <-ctx.Done(): + return nil, nil, ctx.Err() + case packet, open := <-in: + if !open { + return nil, nil, io.EOF + } + origin, msg, err := unpack(packet) + if err != nil { + logger.Warn().Err(err).Msg("could not receive") + return nil, nil, xerrors.Errorf("could not receive from %v: %v", + origin, err) + } + logger.Debug().Msgf("received %T from %v", msg, origin) + return origin, msg, nil + } +} diff --git a/mino/minows/session_test.go b/mino/minows/session_test.go new file mode 100644 index 000000000..c2d9f43a5 --- /dev/null +++ b/mino/minows/session_test.go @@ -0,0 +1,315 @@ +package minows + +import ( + "context" + "github.com/libp2p/go-libp2p/core/network" + "github.com/stretchr/testify/require" + "go.dedis.ch/dela/mino" + "go.dedis.ch/dela/serde" + "go.dedis.ch/dela/testing/fake" + "io" + "testing" + "time" +) + +func Test_session_Send(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer1 = "/ip4/127.0.0.1/tcp/6002/ws" + player1, stop := mustCreateMinows(t, addrPlayer1, addrPlayer1) + defer stop() + mustCreateRPC(t, player1, "test", handler) + + const addrPlayer2 = "/ip4/127.0.0.1/tcp/6003/ws" + player2, stop := mustCreateMinows(t, addrPlayer2, addrPlayer2) + defer stop() + mustCreateRPC(t, player2, "test", handler) + + s, _, stop := mustStream(t, r, player1, player2) + defer stop() + + errs := s.Send(fake.Message{}, player1.GetAddress()) + err, open := <-errs + require.NoError(t, err) + require.False(t, open) + + errs = s.Send(fake.Message{}, player1.GetAddress(), player2.GetAddress()) + err, open = <-errs + require.NoError(t, err) + require.False(t, open) + + wait() + require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, + s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) + require.Equal(t, []serde.Message{fake.Message{}, + fake.Message{}, fake.Message{}}, handler.messages) +} + +func Test_session_Send_ToSelf(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer1 = "/ip4/127.0.0.1/tcp/6002/ws" + player1, stop := mustCreateMinows(t, addrPlayer1, addrPlayer1) + defer stop() + mustCreateRPC(t, player1, "test", handler) + + s, _, stop := mustStream(t, r, initiator, player1) + defer stop() + + errs := s.Send(fake.Message{}, initiator.GetAddress()) + err, open := <-errs + require.NoError(t, err) + require.False(t, open) + + errs = s.Send(fake.Message{}, initiator.GetAddress(), player1.GetAddress()) + err, open = <-errs + require.NoError(t, err) + require.False(t, open) + + wait() + require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, + s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) + require.Equal(t, []serde.Message{fake.Message{}, + fake.Message{}, fake.Message{}}, handler.messages) + require.NotEqual(t, s.(*orchestrator).myAddr, initiator.GetAddress()) +} + +func Test_session_Send_WrongAddressType(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + s, _, stop := mustStream(t, r, player) + defer stop() + + errs := s.Send(fake.Message{}, fake.Address{}) + require.ErrorContains(t, <-errs, "wrong address type") +} + +func Test_session_Send_AddressNotPlayer(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + s, _, stop := mustStream(t, r, player) + defer stop() + notPlayer := mustCreateAddress(t, "/ip4/127.0.0.1/tcp/6003/ws", + "QmaD31nEzFGwD8dK96UFWHtTYTqYJgHLMYSFz4W4Hm2WCU") + + errs := s.Send(fake.Message{}, notPlayer) + require.ErrorContains(t, <-errs, "not player") +} + +func Test_session_Send_SessionEnded(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + rpc := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + s, _, stop := mustStream(t, rpc, initiator, player) + stop() + wait() + + errs := s.Send(fake.Message{}, initiator.GetAddress(), player.GetAddress()) + require.ErrorContains(t, <-errs, network.ErrReset.Error()) + require.ErrorContains(t, <-errs, network.ErrReset.Error()) + _, open := <-errs + require.False(t, open) + require.Nil(t, handler.messages) +} + +func Test_session_Recv(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer1 = "/ip4/127.0.0.1/tcp/6002/ws" + player1, stop := mustCreateMinows(t, addrPlayer1, addrPlayer1) + defer stop() + mustCreateRPC(t, player1, "test", handler) + + const addrPlayer2 = "/ip4/127.0.0.1/tcp/6003/ws" + player2, stop := mustCreateMinows(t, addrPlayer2, addrPlayer2) + defer stop() + mustCreateRPC(t, player2, "test", handler) + + sender, receiver, stop := mustStream(t, r, player1, player2) + defer stop() + + errs := sender.Send(fake.Message{}, player1.GetAddress()) + require.NoError(t, <-errs) + ctx, cancel := setTimeout() + defer cancel() + + from, msg, err := receiver.Recv(ctx) + require.NoError(t, err) + require.Equal(t, player1.GetAddress(), from) + require.Equal(t, fake.Message{}, msg) + + errs = sender.Send(fake.Message{}, + player1.GetAddress(), player2.GetAddress()) + require.NoError(t, <-errs) + + from1, msg, err := receiver.Recv(ctx) + require.NoError(t, err) + require.True(t, from1.Equal(player1.GetAddress()) || + from1.Equal(player2.GetAddress())) + require.Equal(t, fake.Message{}, msg) + + from2, msg, err := receiver.Recv(ctx) + require.NoError(t, err) + require.True(t, from2.Equal(player1.GetAddress()) || + from2.Equal(player2.GetAddress())) + require.Equal(t, fake.Message{}, msg) + + require.NotEqual(t, from1, from2) +} + +func Test_session_Recv_FromSelf(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + rpc := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer1 = "/ip4/127.0.0.1/tcp/6002/ws" + player1, stop := mustCreateMinows(t, addrPlayer1, addrPlayer1) + defer stop() + mustCreateRPC(t, player1, "test", handler) + + s, r, stop := mustStream(t, rpc, initiator, player1) + defer stop() + + errs := s.Send(fake.Message{}, initiator.GetAddress()) + require.NoError(t, <-errs) + + ctx, cancel := setTimeout() + defer cancel() + + from, msg, err := r.Recv(ctx) + require.NoError(t, err) + require.Equal(t, initiator.GetAddress(), from) + require.Equal(t, fake.Message{}, msg) + + errs = s.Send(fake.Message{}, initiator.GetAddress(), player1.GetAddress()) + require.NoError(t, <-errs) + + from1, msg, err := r.Recv(ctx) + require.NoError(t, err) + require.True(t, from1.Equal(initiator.GetAddress()) || + from1.Equal(player1.GetAddress())) + require.Equal(t, fake.Message{}, msg) + + from2, msg, err := r.Recv(ctx) + require.NoError(t, err) + require.True(t, from2.Equal(initiator.GetAddress()) || + from2.Equal(player1.GetAddress())) + require.Equal(t, fake.Message{}, msg) + + require.NotEqual(t, from1, from2) + require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, + s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) + require.NotEqual(t, s.(*orchestrator).myAddr, initiator.GetAddress()) +} + +func Test_session_Recv_SessionEnded(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + rpc := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + s, r, end := mustStream(t, rpc, initiator, player) + + errs := s.Send(fake.Message{}, initiator.GetAddress(), player.GetAddress()) + _, open := <-errs + require.False(t, open) + + end() + + ctx, cancel := setTimeout() + defer cancel() + _, _, err := r.Recv(ctx) + require.ErrorIs(t, err, io.EOF) +} + +func Test_session_Recv_ContextCancelled(t *testing.T) { + handler := &echoHandler{} + const addrInitiator = "/ip4/127.0.0.1/tcp/6001/ws" + initiator, stop := mustCreateMinows(t, addrInitiator, addrInitiator) + defer stop() + r := mustCreateRPC(t, initiator, "test", handler) + + const addrPlayer = "/ip4/127.0.0.1/tcp/6002/ws" + player, stop := mustCreateMinows(t, addrPlayer, addrPlayer) + defer stop() + mustCreateRPC(t, player, "test", handler) + + _, receiver, stop := mustStream(t, r, player) + defer stop() + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + _, _, err := receiver.Recv(ctx) + require.ErrorIs(t, err, context.Canceled) +} + +func setTimeout() (context.Context, context.CancelFunc) { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + return ctx, cancel +} + +func wait() { + time.Sleep(2 * time.Second) +} + +func mustStream(t *testing.T, rpc mino.RPC, + minos ...mino.Mino) (mino.Sender, mino.Receiver, func()) { + ctx, cancel := context.WithCancel(context.Background()) + var addrs []mino.Address + for _, m := range minos { + addrs = append(addrs, m.GetAddress()) + } + players := mino.NewAddresses(addrs...) + end := func() { + cancel() + } + s, r, err := rpc.Stream(ctx, players) + require.NoError(t, err) + return s, r, end +} From 0d1740aa1d51d2156b363a00fd8fa0f7e6b0e60f Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Tue, 2 Jul 2024 16:32:13 +0200 Subject: [PATCH 3/4] Integration tests for MinoWS Co-authored-by: Zach Xion XioZ@users.noreply.github.com --- test/cosidela_test.go | 92 ++++++++++++++++++++++++---------------- test/dela_test.go | 2 +- test/integration_test.go | 19 ++++++--- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/test/cosidela_test.go b/test/cosidela_test.go index d45d0928d..9279638cf 100644 --- a/test/cosidela_test.go +++ b/test/cosidela_test.go @@ -5,6 +5,9 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/x509" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/mino/minows" + "go.dedis.ch/dela/mino/minows/key" "io" "math/rand" "net/url" @@ -46,6 +49,9 @@ import ( "golang.org/x/xerrors" ) +const minoGRPC = "grpc" +const minoWS = "ws" + const certKeyName = "cert.key" const privateKeyFile = "private.key" @@ -74,7 +80,7 @@ type cosiDelaNode struct { tree hashtree.Tree } -func newDelaNode(t require.TestingT, path string, port int) dela { +func newDelaNode(t require.TestingT, path string, port int, kind string) dela { err := os.MkdirAll(path, 0700) require.NoError(t, err) @@ -83,31 +89,43 @@ func newDelaNode(t require.TestingT, path string, port int) dela { require.NoError(t, err) // mino - router := tree.NewRouter(minogrpc.NewAddressFactory()) - addr := minogrpc.ParseAddress("127.0.0.1", uint16(port)) - - certs := certs.NewDiskStore(db, session.AddressFactory{}) - - fload := loader.NewFileLoader(filepath.Join(path, certKeyName)) - - keydata, err := fload.LoadOrCreate(newCertGenerator(rand.New(rand.NewSource(0)), - elliptic.P521())) - require.NoError(t, err) - - key, err := x509.ParseECPrivateKey(keydata) - require.NoError(t, err) - - opts := []minogrpc.Option{ - minogrpc.WithStorage(certs), - minogrpc.WithCertificateKey(key, key.Public()), + var onet mino.Mino + switch kind { + case minoGRPC: + router := tree.NewRouter(minogrpc.NewAddressFactory()) + addr := minogrpc.ParseAddress("127.0.0.1", uint16(port)) + + certs := certs.NewDiskStore(db, session.AddressFactory{}) + + fload := loader.NewFileLoader(filepath.Join(path, certKeyName)) + keydata, err := fload.LoadOrCreate(newCertGenerator(rand.New(rand.NewSource(0)), + elliptic.P521())) + require.NoError(t, err) + + key, err := x509.ParseECPrivateKey(keydata) + require.NoError(t, err) + + opts := []minogrpc.Option{ + minogrpc.WithStorage(certs), + minogrpc.WithCertificateKey(key, key.Public()), + } + + onet, err = minogrpc.NewMinogrpc(addr, nil, router, opts...) + require.NoError(t, err) + case minoWS: + listen, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0/ws") + require.NoError(t, err) + + storage := key.NewStorage(db) + key, _ := storage.LoadOrCreate() + + onet, err = minows.NewMinows(listen, nil, key) + require.NoError(t, err) } - - onet, err := minogrpc.NewMinogrpc(addr, nil, router, opts...) - require.NoError(t, err) onet.GetAddress() // ordering + validation + execution - fload = loader.NewFileLoader(filepath.Join(path, privateKeyFile)) + fload := loader.NewFileLoader(filepath.Join(path, privateKeyFile)) signerdata, err := fload.LoadOrCreate(newKeyGenerator()) require.NoError(t, err) @@ -193,25 +211,27 @@ func newDelaNode(t require.TestingT, path string, port int) dela { // Setup implements dela. It creates the roster, shares the certificate, and // create an new chain. -func (c cosiDelaNode) Setup(delas ...dela) { +func (c cosiDelaNode) Setup(kind string, delas ...dela) { // share the certificates - joinable, ok := c.onet.(minogrpc.Joinable) - require.True(c.t, ok) + if kind == minoGRPC { + joinable, ok := c.onet.(minogrpc.Joinable) + require.True(c.t, ok) - addrURL, err := url.Parse(c.onet.GetAddress().String()) - require.NoError(c.t, err, addrURL) + addrURL, err := url.Parse(c.onet.GetAddress().String()) + require.NoError(c.t, err, addrURL) - token := joinable.GenerateToken(time.Hour) + token := joinable.GenerateToken(time.Hour) - certHash, err := joinable.GetCertificateStore().Hash(joinable.GetCertificateChain()) - require.NoError(c.t, err) + certHash, err := joinable.GetCertificateStore().Hash(joinable.GetCertificateChain()) + require.NoError(c.t, err) - for _, dela := range delas { - otherJoinable, ok := dela.GetMino().(minogrpc.Joinable) - require.True(c.t, ok) + for _, dela := range delas { + otherJoinable, ok := dela.GetMino().(minogrpc.Joinable) + require.True(c.t, ok) - err = otherJoinable.Join(addrURL, token, certHash) - require.NoError(c.t, err) + err = otherJoinable.Join(addrURL, token, certHash) + require.NoError(c.t, err) + } } type extendedService interface { @@ -244,7 +264,7 @@ func (c cosiDelaNode) Setup(delas ...dela) { roster := authority.New(minoAddrs, pubKeys) // create chain - err = extended.Setup(context.Background(), roster) + err := extended.Setup(context.Background(), roster) require.NoError(c.t, err) } diff --git a/test/dela_test.go b/test/dela_test.go index 9d9c8f69b..466ff8c73 100644 --- a/test/dela_test.go +++ b/test/dela_test.go @@ -9,7 +9,7 @@ import ( // dela defines the common interface for a Dela node. type dela interface { - Setup(...dela) + Setup(string, ...dela) GetMino() mino.Mino GetOrdering() ordering.Service GetTxManager() txn.Manager diff --git a/test/integration_test.go b/test/integration_test.go index da6df36b2..b62932b70 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -33,14 +33,22 @@ func init() { // Use the value contract // Check the state func TestIntegration_Value_Simple(t *testing.T) { - t.Run("3 nodes", getTest[*testing.T](3, 2)) + t.Run("3 nodes: grpc", getTest[*testing.T](3, 2, minoGRPC)) + t.Run("3 nodes: ws", getTest[*testing.T](3, 2, minoWS)) } func BenchmarkValue(b *testing.B) { - getTest[*testing.B](5, b.N)(b) + testGRPC := func(b *testing.B) { + getTest[*testing.B](5, b.N, minoGRPC)(b) + } + testWS := func(b *testing.B) { + getTest[*testing.B](5, b.N, minoWS)(b) + } + b.Run("5 nodes: grpc", testGRPC) + b.Run("5 nodes: ws", testWS) } -func getTest[T require.TestingT](numNode, numTx int) func(t T) { +func getTest[T require.TestingT](numNode, numTx int, kind string) func(t T) { return func(t T) { dir, err := os.MkdirTemp(os.TempDir(), "dela-integration-test") require.NoError(t, err) @@ -52,11 +60,12 @@ func getTest[T require.TestingT](numNode, numTx int) func(t T) { nodes := make([]dela, numNode) for i := range nodes { - node := newDelaNode(t, filepath.Join(dir, "node"+strconv.Itoa(i)), 0) + node := newDelaNode(t, filepath.Join(dir, + "node"+strconv.Itoa(i)), 0, kind) nodes[i] = node } - nodes[0].Setup(nodes[1:]...) + nodes[0].Setup(kind, nodes[1:]...) l := loader.NewFileLoader(filepath.Join(dir, "private.key")) From 684c54a317dd3760c115eb756207a37c6b66625f Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Thu, 4 Jul 2024 10:16:46 +0200 Subject: [PATCH 4/4] @pierluca's comments - Adding new version of libp2p - Re-enabling failing test and remove goverall - Use peer.ID.Validate - Don't export Packet and Forward - Merging participant and orchestrator --- .github/workflows/go_test.yml | 1 + Makefile | 4 +- go.mod | 62 +++---- go.sum | 149 ++++++++-------- mino/minows/address.go | 10 +- mino/minows/key/mod.go | 3 +- mino/minows/rpc.go | 167 ++++++------------ mino/minows/session.go | 319 ++++++++++++++++------------------ mino/minows/session_test.go | 33 ++-- test/cosidela_test.go | 36 ++-- 10 files changed, 356 insertions(+), 428 deletions(-) diff --git a/.github/workflows/go_test.yml b/.github/workflows/go_test.yml index 4ed35d3d5..f5f85d6e3 100644 --- a/.github/workflows/go_test.yml +++ b/.github/workflows/go_test.yml @@ -62,6 +62,7 @@ jobs: # notifies that all test jobs are finished. finish: + if: github.repository == 'dedis/dela' needs: test runs-on: ubuntu-latest steps: diff --git a/Makefile b/Makefile index b317bcc3b..1364f4c5f 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ generate: tidy # Some packages are excluded from staticcheck due to deprecated warnings: #208. lint: tidy # Coding style static check. - @go install honnef.co/go/tools/cmd/staticcheck@latest + @go install honnef.co/go/tools/cmd/staticcheck@v0.4.7 staticcheck `go list ./... | grep -Ev "(go\.dedis\.ch/dela/internal/testing|go\.dedis\.ch/dela/mino/minogrpc/ptypes)"` vet: tidy @@ -54,4 +54,4 @@ coverage: tidy pushdoc: @echo "Requesting the proxy..." @curl "https://proxy.golang.org/go.dedis.ch/dela/@v/$(shell git log origin/master -1 --format=format:%H).info" - @echo "\nDone." \ No newline at end of file + @echo "\nDone." diff --git a/go.mod b/go.mod index cf4166011..67e1249d9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,8 @@ go 1.21 require ( github.com/golang/protobuf v1.5.4 - github.com/libp2p/go-libp2p v0.35.2 + github.com/libp2p/go-libp2p v0.36.1 + github.com/libp2p/go-yamux/v4 v4.0.1 github.com/multiformats/go-multiaddr v0.13.0 github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e github.com/opentracing/opentracing-go v1.2.0 @@ -17,9 +18,9 @@ require ( go.dedis.ch/debugtools v0.1.1 go.dedis.ch/kyber/v3 v3.1.0 go.etcd.io/bbolt v1.3.9 - golang.org/x/crypto v0.23.0 - golang.org/x/net v0.25.0 - golang.org/x/tools v0.21.0 + golang.org/x/crypto v0.25.0 + golang.org/x/net v0.27.0 + golang.org/x/tools v0.23.0 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/grpc v1.63.0 gopkg.in/yaml.v2 v2.4.0 @@ -29,7 +30,7 @@ require ( github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect @@ -37,14 +38,14 @@ require ( github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/elastic/gosigar v0.14.2 // indirect + github.com/elastic/gosigar v0.14.3 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -52,8 +53,8 @@ require ( github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect @@ -62,11 +63,10 @@ require ( github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.58 // indirect + github.com/miekg/dns v1.1.61 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -80,38 +80,40 @@ require ( github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo/v2 v2.19.1 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pion/datachannel v1.5.6 // indirect - github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.25 // indirect + github.com/pion/datachannel v1.5.8 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/ice/v2 v2.3.32 // indirect github.com/pion/interceptor v0.1.29 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.6 // indirect - github.com/pion/sctp v1.8.16 // indirect + github.com/pion/rtp v1.8.8 // indirect + github.com/pion/sctp v1.8.20 // indirect github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/srtp/v2 v2.0.20 // indirect github.com/pion/stun v0.6.1 // indirect - github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/transport/v2 v2.2.9 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.40 // indirect + github.com/pion/webrtc/v3 v3.2.50 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/quic-go v0.45.2 // indirect github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/wlynxg/anet v0.0.3 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.dedis.ch/protobuf v1.0.11 // indirect @@ -121,13 +123,13 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index f11d501d3..037b69d6f 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= @@ -53,8 +53,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= -github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= +github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -66,10 +66,10 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -100,8 +100,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -130,10 +130,10 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -149,8 +149,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 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-libp2p v0.35.2 h1:287oHbuplkrLdAF+syB0n/qDgd50AUBtEODqS0e0HDs= -github.com/libp2p/go-libp2p v0.35.2/go.mod h1:RKCDNt30IkFipGL0tl8wQW/3zVWEGFUZo8g2gAKxwjU= +github.com/libp2p/go-libp2p v0.36.1 h1:piAHesy0/8ifBEBUS8HF2m7ywR5vnktUFv00dTsVKcs= +github.com/libp2p/go-libp2p v0.36.1/go.mod h1:vHzel3CpRB+vS11fIjZSJAU4ALvieKV9VZHC9VerHj8= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -179,8 +179,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -220,13 +220,15 @@ github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dy github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -238,13 +240,13 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= -github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= +github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= -github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs= -github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.32 h1:VwE/uEeqiMm0zUWpdt1DJtnqEkj3UjEbhX92/CurtWI= +github.com/pion/ice/v2 v2.3.32/go.mod h1:8fac0+qftclGy1tYd/nfwfHC729BLaxtVqMdMVCAVPU= github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -257,31 +259,30 @@ github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9 github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= -github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= -github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= -github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/rtp v1.8.8 h1:EtYFHI0rpUEjT/RMnGfb1vdJhbYmPG77szD72uUnSxs= +github.com/pion/rtp v1.8.8/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.20 h1:sOc3lkV/tQaP57ZUEXIMdM2V92IIB2ia5v/ygnBxaEg= +github.com/pion/sctp v1.8.20/go.mod h1:oTxw8i5m+WbDHZJL/xUpe6CPIn1Y0GIKKwTLF4h53H8= github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= -github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= +github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= -github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.8/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v2 v2.2.9 h1:WEDygVovkJlV2CCunM9KS2kds+kcl7zdIefQA5y/nkE= +github.com/pion/transport/v2 v2.2.9/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= -github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/transport/v3 v3.0.6 h1:k1mQU06bmmX143qSWgXFqSH1KUJceQvIUuVH/K5ELWw= +github.com/pion/transport/v3 v3.0.6/go.mod h1:HvJr2N/JwNJAfipsRleqwFoR3t/pWyHeZUs89v3+t5s= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= -github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= +github.com/pion/webrtc/v3 v3.2.50 h1:C/rwL2mBfCxHv6tlLzDAO3krJpQXfVx8A8WHnGJ2j34= +github.com/pion/webrtc/v3 v3.2.50/go.mod h1:dytYYoSBy7ZUWhJMbndx9UckgYvzNAfL7xgVnrIKxqo= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -294,15 +295,15 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/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/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= -github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/quic-go v0.45.2 h1:DfqBmqjb4ExSdxRIb/+qXhPC+7k6+DUNZha4oeiC9fY= +github.com/quic-go/quic-go v0.45.2/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -354,7 +355,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -372,6 +372,8 @@ github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -425,21 +427,18 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= 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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -457,8 +456,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -480,13 +479,10 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -531,35 +527,28 @@ 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.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 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.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -582,8 +571,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -615,8 +604,8 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -638,8 +627,8 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/mino/minows/address.go b/mino/minows/address.go index d23f5cbcb..1d1a0cc62 100644 --- a/mino/minows/address.go +++ b/mino/minows/address.go @@ -25,9 +25,15 @@ type address struct { // newAddress creates a new address from a publicly reachable location with a // peer identity. func newAddress(location ma.Multiaddr, identity peer.ID) (address, error) { - if location == nil || identity.String() == "" { - return address{}, xerrors.New("address must have location and identity") + if location == nil { + return address{}, xerrors.New("address must have a location") } + + err := identity.Validate() + if err != nil { + return address{}, xerrors.Errorf("address must have a valid identity: %v", err) + } + return address{ location: location, identity: identity, diff --git a/mino/minows/key/mod.go b/mino/minows/key/mod.go index 2a07a0aab..6e10c4a3e 100644 --- a/mino/minows/key/mod.go +++ b/mino/minows/key/mod.go @@ -2,6 +2,7 @@ package key import ( "crypto/rand" + "github.com/libp2p/go-libp2p/core/crypto" "go.dedis.ch/dela/core/store/kv" "golang.org/x/xerrors" @@ -16,7 +17,7 @@ type Storage struct { // NewStorage creates a new Storage for private keys. func NewStorage(db kv.DB) *Storage { return &Storage{ - bucket: []byte("keys"), + bucket: []byte("minows_keys"), db: db, } } diff --git a/mino/minows/rpc.go b/mino/minows/rpc.go index 52a72ca33..37431c6df 100644 --- a/mino/minows/rpc.go +++ b/mino/minows/rpc.go @@ -16,18 +16,17 @@ import ( "go.dedis.ch/dela/mino" "go.dedis.ch/dela/serde" "golang.org/x/xerrors" - "strings" "sync" - "time" ) const pathCall = "/call" const pathStream = "/stream" -// Packet encapsulates a message sent over the network streams. -type Packet struct { - Source []byte - Payload []byte +// packet encapsulates a message sent over the network streams. +type packet struct { + Source []byte + Payload []byte + ForwardDest *[]byte } type envelope struct { @@ -81,6 +80,7 @@ func (r rpc) Call(ctx context.Context, req serde.Message, go func() { defer close(responses) for i := 0; i < len(addrs); i++ { + select { case <-ctx.Done(): return @@ -125,6 +125,7 @@ func (r rpc) Stream(ctx context.Context, players mino.Players) (mino.Sender, min return nil, nil, xerrors.Errorf("%v: %T", ErrWrongAddressType, player) } + go func(addr address) { defer wg.Done() initiator.Peerstore().AddAddr(addr.identity, addr.location, @@ -137,6 +138,7 @@ func (r rpc) Stream(ctx context.Context, players mino.Players) (mino.Sender, min return } streams <- stream + go func() { <-ctx.Done() err = stream.Reset() @@ -166,31 +168,23 @@ func (r rpc) Stream(ctx context.Context, players mino.Players) (mino.Sender, min } func (r rpc) handleCall(stream network.Stream) { - handle := func() error { - dec := gob.NewDecoder(stream) - from, req, err := r.receive(dec) - if err != nil { - return xerrors.Errorf("could not receive: %v", err) - } - - id := stream.Conn().RemotePeer() - author := address{location: from, identity: id} - reply, err := r.handler.Process(mino.Request{Address: author, Message: req}) - if err != nil { - return xerrors.Errorf("could not process: %v", err) - } + dec := gob.NewDecoder(stream) + from, req, err := r.receive(dec) + if err != nil { + r.logger.Error().Err(err).Msg("could not receive") + } - enc := gob.NewEncoder(stream) - err = r.send(enc, reply) - if err != nil { - return xerrors.Errorf("could not reply: %v", err) - } - return nil + id := stream.Conn().RemotePeer() + author := address{location: from, identity: id} + reply, err := r.handler.Process(mino.Request{Address: author, Message: req}) + if err != nil { + r.logger.Error().Err(err).Msg("could not process") } - err := handle() + enc := gob.NewEncoder(stream) + err = r.send(enc, reply) if err != nil { - r.logger.Error().Err(err).Msg("could not handle call") + r.logger.Error().Err(err).Msg("could not reply") } } @@ -278,7 +272,7 @@ func (r rpc) send(enc *gob.Encoder, msg serde.Message) error { payload = bytes } - err := enc.Encode(&Packet{Source: from, Payload: payload}) + err := enc.Encode(&packet{Source: from, Payload: payload}) if errors.Is(err, network.ErrReset) { return err } @@ -289,8 +283,8 @@ func (r rpc) send(enc *gob.Encoder, msg serde.Message) error { } func (r rpc) receive(dec *gob.Decoder) (ma.Multiaddr, serde.Message, error) { - var packet Packet - err := dec.Decode(&packet) + var pkt packet + err := dec.Decode(&pkt) if errors.Is(err, network.ErrReset) { return nil, nil, err } @@ -298,16 +292,16 @@ func (r rpc) receive(dec *gob.Decoder) (ma.Multiaddr, serde.Message, error) { return nil, nil, xerrors.Errorf("could not decode packet: %v", err) } - from, err := ma.NewMultiaddrBytes(packet.Source) + from, err := ma.NewMultiaddrBytes(pkt.Source) if err != nil { return nil, nil, xerrors.Errorf("could not unmarshal address: %v", - packet.Source) + pkt.Source) } - if packet.Payload == nil { + if pkt.Payload == nil { return from, nil, nil } - msg, err := r.factory.Deserialize(r.context, packet.Payload) + msg, err := r.factory.Deserialize(r.context, pkt.Payload) if err != nil { return from, nil, xerrors.Errorf( "could not deserialize message: %v", @@ -317,7 +311,7 @@ func (r rpc) receive(dec *gob.Decoder) (ma.Multiaddr, serde.Message, error) { } func (r rpc) createOrchestrator(ctx context.Context, - initiator host.Host, streams []network.Stream) (*orchestrator, error) { + initiator host.Host, streams []network.Stream) (*messageHandler, error) { participant := r.mino.GetAddress().(address).location myAddr, err := newOrchestratorAddr(participant, initiator.ID()) if err != nil { @@ -329,94 +323,35 @@ func (r rpc) createOrchestrator(ctx context.Context, encoders[stream.Conn().RemotePeer()] = gob.NewEncoder(stream) } - o := &orchestrator{ + m := &messageHandler{ logger: r.logger.With().Stringer("mino", myAddr). Stringer("orchestrator", xid.New()).Logger(), - myAddr: myAddr, - rpc: r, - outs: encoders, - in: make(chan Packet, MaxUnreadAllowed), - } - - var wg sync.WaitGroup - wg.Add(len(streams)) - for _, stream := range streams { - go func(stream network.Stream) { - defer wg.Done() - decoder := gob.NewDecoder(stream) - for { - packet, err := o.listen(decoder) - if err != nil { - if strings.Contains(err.Error(), network.ErrReset.Error()) { - return - } - r.logger.Error().Err(err).Msg("message dropped") - continue - } - select { - case <-ctx.Done(): - return - case o.in <- packet: - } - } - }(stream) + myAddr: myAddr, + rpc: r, + streams: streams, + outs: encoders, + in: make(chan packet, MaxUnreadAllowed), } - go func() { - wg.Wait() - close(o.in) - }() - - return o, nil + m.loop(ctx) + return m, nil } -func (r rpc) createParticipant(stream network.Stream) participant { - encoder := gob.NewEncoder(stream) - decoder := gob.NewDecoder(stream) - - p := participant{ - logger: r.logger.With().Stringer("participant", xid.New()).Logger(), - myAddr: r.mino.myAddr, - rpc: r, - out: encoder, - in: make(chan Packet), +func (r rpc) createParticipant(stream network.Stream) messageHandler { + out := gob.NewEncoder(stream) + + ctx, cancel := context.WithCancel(context.Background()) + m := messageHandler{ + logger: r.logger.With().Stringer("participant", xid.New()).Logger(), + myAddr: r.mino.myAddr, + rpc: r, + cancel: cancel, + streams: []network.Stream{stream}, + outs: map[peer.ID]*gob.Encoder{stream.Conn().RemotePeer(): out}, + in: make(chan packet), } - done := make(chan any) - go func() { - hasReset := func() bool { - for _, s := range stream.Conn().GetStreams() { - if s.ID() == stream.ID() { - return false - } - } - return true - } - - for !hasReset() { - time.Sleep(2 * time.Second) - } - close(done) - }() - - go func() { - for { - packet, err := p.listen(decoder) - if err != nil { - if strings.Contains(err.Error(), network.ErrReset.Error()) { - close(p.in) - return - } - r.logger.Error().Err(err).Msg("message dropped") - continue - } - select { - case <-done: - return - case p.in <- packet: - } - } - }() + m.loop(ctx) - return p + return m } diff --git a/mino/minows/session.go b/mino/minows/session.go index e82841180..35808f9f8 100644 --- a/mino/minows/session.go +++ b/mino/minows/session.go @@ -3,13 +3,17 @@ package minows import ( "context" "encoding/gob" + "fmt" + "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/rs/zerolog" "go.dedis.ch/dela/mino" "go.dedis.ch/dela/serde" "golang.org/x/xerrors" "io" + "strings" "sync" + "time" ) var ErrWrongAddressType = xerrors.New("wrong address type") @@ -19,31 +23,117 @@ var ErrNotPlayer = xerrors.New("not player") // in orchestrator's incoming message buffer before pausing relaying const MaxUnreadAllowed = 1e3 -type Forward struct { - Packet - Destination []byte -} - -type orchestrator struct { +type messageHandler struct { logger zerolog.Logger - myAddr orchestratorAddr - rpc rpc + myAddr mino.Address + rpc rpc + streams []network.Stream // Connects to the participants outs map[peer.ID]*gob.Encoder - in chan Packet + in chan packet + // Only used for the participant + cancel context.CancelFunc } -func (o orchestrator) Send(msg serde.Message, addrs ...mino.Address) <-chan error { - return doSend(addrs, msg, o.send, o.logger) +func (m messageHandler) Send(msg serde.Message, addrs ...mino.Address) <-chan error { + errs := make(chan error, len(addrs)) + var wg sync.WaitGroup + wg.Add(len(addrs)) + for _, addr := range addrs { + go func(addr mino.Address) { + defer wg.Done() + err := m.send(addr, msg) + if err != nil { + errs <- xerrors.Errorf("could not send %T to %v: %v", msg, addr, err) + return + } + m.logger.Debug().Msgf("sent %T to %v", msg, addr) + }(addr) + } + + go func() { + wg.Wait() + close(errs) + }() + return errs } -func (o orchestrator) Recv(ctx context.Context) (mino.Address, serde.Message, error) { - unpack := unpacker(o.rpc.mino.GetAddressFactory(), o.rpc.factory, o.rpc.context) - return doReceive(ctx, o.in, unpack, o.logger) +func (m messageHandler) Recv(ctx context.Context) (mino.Address, serde.Message, error) { + select { + case <-ctx.Done(): + return nil, nil, ctx.Err() + case packet, open := <-m.in: + if !open { + return nil, nil, io.EOF + } + + origin := m.rpc.mino.GetAddressFactory().FromText(packet.Source) + if origin == nil { + return nil, nil, xerrors.New("could not unmarshal address") + } + msg, err := m.rpc.factory.Deserialize(m.rpc.context, packet.Payload) + if err != nil { + return origin, nil, xerrors.Errorf("could not deserialize message: %v", err) + } + + m.logger.Debug().Msgf("received %T from %v", msg, origin) + return origin, msg, nil + } } -func (o orchestrator) send(addr mino.Address, msg serde.Message) error { +func (m messageHandler) loop(ctx context.Context) { + if m.isParticipant() { + go m.waitAllClosed() + } + + var wg sync.WaitGroup + wg.Add(len(m.streams)) + for _, stream := range m.streams { + go m.passMessages(ctx, stream, &wg) + } + + go func() { + wg.Wait() + close(m.in) + }() +} + +func (m messageHandler) passMessages(ctx context.Context, stream network.Stream, wg *sync.WaitGroup) { + defer wg.Done() + decoder := gob.NewDecoder(stream) + for { + pkt, err := m.listen(decoder) + if err != nil { + if strings.Contains(err.Error(), network.ErrReset.Error()) { + return + } + m.logger.Error().Err(err).Msg("message dropped") + continue + } + select { + case <-ctx.Done(): + fmt.Println("messageHandler done:", m.isOrchestrator()) + return + case m.in <- pkt: + } + } +} + +func (m messageHandler) waitAllClosed() { + for { + for _, s := range m.streams[0].Conn().GetStreams() { + if s.ID() == m.streams[0].ID() { + time.Sleep(2 * time.Second) + continue + } + } + break + } + m.cancel() +} + +func (m messageHandler) send(addr mino.Address, msg serde.Message) error { var unwrapped address switch a := addr.(type) { case address: @@ -54,45 +144,38 @@ func (o orchestrator) send(addr mino.Address, msg serde.Message) error { return xerrors.Errorf("%v: %T", ErrWrongAddressType, addr) } - encoder, ok := o.outs[unwrapped.identity] + encoder, ok := m.outs[unwrapped.identity] if !ok { return xerrors.Errorf("%v: %v", ErrNotPlayer, addr) } - src, err := o.myAddr.MarshalText() + src, err := m.myAddr.MarshalText() if err != nil { return xerrors.Errorf("could not marshal address: %v", err) } - payload, err := msg.Serialize(o.rpc.context) + payload, err := msg.Serialize(m.rpc.context) if err != nil { return xerrors.Errorf("could not serialize message: %v", err) } + pkt := packet{Source: src, Payload: payload} - err = encoder.Encode(&Packet{Source: src, Payload: payload}) - if err != nil { - return xerrors.Errorf("could not encode packet: %v", err) + if m.isParticipant() { + // Send to orchestrator to relay to the destination participant + dest, err := addr.MarshalText() + if err != nil { + return xerrors.Errorf("could not marshal address: %v", err) + } + pkt.ForwardDest = &dest } - return nil -} -func (o orchestrator) fetch(decoder *gob.Decoder) (Packet, mino.Address, - error) { - var forward Forward - err := decoder.Decode(&forward) + err = encoder.Encode(&pkt) if err != nil { - return Packet{}, nil, - xerrors.Errorf("could not decode packet: %v", err) - } - dest := o.rpc.mino.GetAddressFactory(). - FromText(forward.Destination) - if dest == nil { - return Packet{}, nil, - xerrors.New("could not unmarshal address") + return xerrors.Errorf("could not encode packet: %v", err) } - return forward.Packet, dest, nil + return nil } -func (o orchestrator) relay(packet Packet, dest address) error { - encoder, ok := o.outs[dest.identity] +func (m messageHandler) relay(packet packet, dest address) error { + encoder, ok := m.outs[dest.identity] if !ok { return xerrors.Errorf("%v: %v", ErrNotPlayer, dest) } @@ -100,151 +183,53 @@ func (o orchestrator) relay(packet Packet, dest address) error { if err != nil { return xerrors.Errorf("could not encode packet: %v", err) } - o.logger.Debug().Stringer("to", dest).Msgf("relayed packet") + m.logger.Debug().Stringer("to", dest).Msgf("relayed packet") return nil } -func (o orchestrator) listen(decoder *gob.Decoder) (Packet, error) { +func (m messageHandler) listen(decoder *gob.Decoder) (packet, error) { for { - packet, dest, err := o.fetch(decoder) + var pkt packet + err := decoder.Decode(&pkt) if err != nil { - return Packet{}, xerrors.Errorf("could not receive: %v", err) + return packet{}, xerrors.Errorf("could not decode packet: %v", err) + } + + if m.isParticipant() { + return pkt, nil + } + + // An orchestrator needs to distinguish between packets for itself and packets + // only forwarded to itself, which need to be relayed. + if pkt.ForwardDest == nil { + return packet{}, xerrors.Errorf("no forward found in packet for orchestrator") + } + + dest := m.rpc.mino.GetAddressFactory(). + FromText(*pkt.ForwardDest) + if dest == nil { + return packet{}, xerrors.Errorf("invalid forward destination") } + switch to := dest.(type) { case orchestratorAddr: - if o.myAddr.Equal(to) { - return packet, nil + if m.myAddr.Equal(to) { + return pkt, nil } case address: - err := o.relay(packet, to) + err := m.relay(pkt, to) if err != nil { - return Packet{}, xerrors.Errorf("could not relay: %v", err) + return packet{}, xerrors.Errorf("could not relay: %v", err) } } } } -type participant struct { - logger zerolog.Logger - - myAddr address - rpc rpc - // Connects to the orchestrator - out *gob.Encoder - in chan Packet -} - -func (p participant) Send(msg serde.Message, addrs ...mino.Address) <-chan error { - return doSend(addrs, msg, p.send, p.logger) -} - -func (p participant) Recv(ctx context.Context) (mino.Address, serde.Message, error) { - unpack := unpacker(p.rpc.mino.GetAddressFactory(), p.rpc.factory, p.rpc.context) - return doReceive(ctx, p.in, unpack, p.logger) -} - -func (p participant) send(addr mino.Address, msg serde.Message) error { - switch addr.(type) { - case address: - case orchestratorAddr: - default: - return xerrors.Errorf("%v: %T", ErrWrongAddressType, addr) - } - - src, err := p.myAddr.MarshalText() - if err != nil { - return xerrors.Errorf("could not marshal address: %v", err) - } - payload, err := msg.Serialize(p.rpc.context) - if err != nil { - return xerrors.Errorf("could not serialize message: %v", err) - } - dest, err := addr.MarshalText() - if err != nil { - return xerrors.Errorf("could not marshal address: %v", err) - } - - // Send to orchestrator to relay to the destination participant - forward := Forward{ - Packet: Packet{Source: src, Payload: payload}, - Destination: dest, - } - err = p.out.Encode(&forward) - if err != nil { - return xerrors.Errorf("could not encode packet: %v", err) - } - return nil -} - -func (p participant) listen(decoder *gob.Decoder) (Packet, error) { - var packet Packet - err := decoder.Decode(&packet) - if err != nil { - return Packet{}, xerrors.Errorf("could not decode packet: %v", err) - } - return packet, nil -} - -type sendFn func(addr mino.Address, msg serde.Message) error - -func doSend(addrs []mino.Address, msg serde.Message, send sendFn, - logger zerolog.Logger) chan error { - errs := make(chan error, len(addrs)) - var wg sync.WaitGroup - wg.Add(len(addrs)) - for _, addr := range addrs { - go func(addr mino.Address) { - defer wg.Done() - err := send(addr, msg) - if err != nil { - errs <- xerrors.Errorf("could not send to %v: %v", addr, err) - logger.Warn().Err(err).Msgf("could not send %T to %v", msg, addr) - return - } - logger.Debug().Msgf("sent %T to %v", msg, addr) - }(addr) - } - - go func() { - wg.Wait() - close(errs) - }() - return errs +func (m messageHandler) isOrchestrator() bool { + _, o := m.myAddr.(orchestratorAddr) + return o } -type unpackFn func(packet Packet) (mino.Address, serde.Message, error) - -func unpacker(af mino.AddressFactory, f serde.Factory, - c serde.Context) unpackFn { - return func(packet Packet) (mino.Address, serde.Message, error) { - src := af.FromText(packet.Source) - if src == nil { - return nil, nil, xerrors.New("could not unmarshal address") - } - msg, err := f.Deserialize(c, packet.Payload) - if err != nil { - return src, nil, xerrors.Errorf("could not deserialize message: %v", err) - } - return src, msg, nil - } -} - -func doReceive(ctx context.Context, in chan Packet, - unpack unpackFn, logger zerolog.Logger) (mino.Address, serde.Message, error) { - select { - case <-ctx.Done(): - return nil, nil, ctx.Err() - case packet, open := <-in: - if !open { - return nil, nil, io.EOF - } - origin, msg, err := unpack(packet) - if err != nil { - logger.Warn().Err(err).Msg("could not receive") - return nil, nil, xerrors.Errorf("could not receive from %v: %v", - origin, err) - } - logger.Debug().Msgf("received %T from %v", msg, origin) - return origin, msg, nil - } +func (m messageHandler) isParticipant() bool { + return !m.isOrchestrator() } diff --git a/mino/minows/session_test.go b/mino/minows/session_test.go index c2d9f43a5..d6c1bef22 100644 --- a/mino/minows/session_test.go +++ b/mino/minows/session_test.go @@ -2,14 +2,17 @@ package minows import ( "context" + "io" + "strings" + "testing" + "time" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-yamux/v4" "github.com/stretchr/testify/require" "go.dedis.ch/dela/mino" "go.dedis.ch/dela/serde" "go.dedis.ch/dela/testing/fake" - "io" - "testing" - "time" ) func Test_session_Send(t *testing.T) { @@ -43,8 +46,8 @@ func Test_session_Send(t *testing.T) { require.False(t, open) wait() - require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, - s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) + require.Equal(t, []mino.Address{s.(*messageHandler).myAddr, + s.(*messageHandler).myAddr, s.(*messageHandler).myAddr}, handler.from) require.Equal(t, []serde.Message{fake.Message{}, fake.Message{}, fake.Message{}}, handler.messages) } @@ -75,11 +78,11 @@ func Test_session_Send_ToSelf(t *testing.T) { require.False(t, open) wait() - require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, - s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) + require.Equal(t, []mino.Address{s.(*messageHandler).myAddr, + s.(*messageHandler).myAddr, s.(*messageHandler).myAddr}, handler.from) require.Equal(t, []serde.Message{fake.Message{}, fake.Message{}, fake.Message{}}, handler.messages) - require.NotEqual(t, s.(*orchestrator).myAddr, initiator.GetAddress()) + require.NotEqual(t, s.(*messageHandler).myAddr, initiator.GetAddress()) } func Test_session_Send_WrongAddressType(t *testing.T) { @@ -139,8 +142,12 @@ func Test_session_Send_SessionEnded(t *testing.T) { wait() errs := s.Send(fake.Message{}, initiator.GetAddress(), player.GetAddress()) - require.ErrorContains(t, <-errs, network.ErrReset.Error()) - require.ErrorContains(t, <-errs, network.ErrReset.Error()) + for i := 0; i < 2; i++ { + err := (<-errs).Error() + require.True(t, strings.Contains(err, network.ErrReset.Error()) || + strings.Contains(err, yamux.ErrSessionShutdown.Error())) + } + _, open := <-errs require.False(t, open) require.Nil(t, handler.messages) @@ -237,9 +244,9 @@ func Test_session_Recv_FromSelf(t *testing.T) { require.Equal(t, fake.Message{}, msg) require.NotEqual(t, from1, from2) - require.Equal(t, []mino.Address{s.(*orchestrator).myAddr, - s.(*orchestrator).myAddr, s.(*orchestrator).myAddr}, handler.from) - require.NotEqual(t, s.(*orchestrator).myAddr, initiator.GetAddress()) + require.Equal(t, []mino.Address{s.(*messageHandler).myAddr, + s.(*messageHandler).myAddr, s.(*messageHandler).myAddr}, handler.from) + require.NotEqual(t, s.(*messageHandler).myAddr, initiator.GetAddress()) } func Test_session_Recv_SessionEnded(t *testing.T) { diff --git a/test/cosidela_test.go b/test/cosidela_test.go index 9279638cf..c8b48e1fc 100644 --- a/test/cosidela_test.go +++ b/test/cosidela_test.go @@ -5,9 +5,7 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/x509" - ma "github.com/multiformats/go-multiaddr" - "go.dedis.ch/dela/mino/minows" - "go.dedis.ch/dela/mino/minows/key" + "fmt" "io" "math/rand" "net/url" @@ -15,6 +13,10 @@ import ( "path/filepath" "time" + ma "github.com/multiformats/go-multiaddr" + "go.dedis.ch/dela/mino/minows" + "go.dedis.ch/dela/mino/minows/key" + "github.com/stretchr/testify/require" accessContract "go.dedis.ch/dela/contracts/access" "go.dedis.ch/dela/contracts/value" @@ -95,31 +97,31 @@ func newDelaNode(t require.TestingT, path string, port int, kind string) dela { router := tree.NewRouter(minogrpc.NewAddressFactory()) addr := minogrpc.ParseAddress("127.0.0.1", uint16(port)) - certs := certs.NewDiskStore(db, session.AddressFactory{}) + delaCerts := certs.NewDiskStore(db, session.AddressFactory{}) fload := loader.NewFileLoader(filepath.Join(path, certKeyName)) keydata, err := fload.LoadOrCreate(newCertGenerator(rand.New(rand.NewSource(0)), elliptic.P521())) require.NoError(t, err) - key, err := x509.ParseECPrivateKey(keydata) + privateKey, err := x509.ParseECPrivateKey(keydata) require.NoError(t, err) opts := []minogrpc.Option{ - minogrpc.WithStorage(certs), - minogrpc.WithCertificateKey(key, key.Public()), + minogrpc.WithStorage(delaCerts), + minogrpc.WithCertificateKey(privateKey, privateKey.Public()), } onet, err = minogrpc.NewMinogrpc(addr, nil, router, opts...) require.NoError(t, err) case minoWS: - listen, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0/ws") + listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ws", port)) require.NoError(t, err) storage := key.NewStorage(db) - key, _ := storage.LoadOrCreate() + privKey, _ := storage.LoadOrCreate() - onet, err = minows.NewMinows(listen, nil, key) + onet, err = minows.NewMinows(listen, nil, privKey) require.NoError(t, err) } onet.GetAddress() @@ -147,22 +149,22 @@ func newDelaNode(t require.TestingT, path string, port int, kind string) dela { txFac := signed.NewTransactionFactory() vs := simple.NewService(exec, txFac) - pool, err := poolimpl.NewPool(gossip.NewFlat(onet.WithSegment("pool"), txFac)) + newPool, err := poolimpl.NewPool(gossip.NewFlat(onet.WithSegment("pool"), txFac)) require.NoError(t, err) - tree := binprefix.NewMerkleTree(db, binprefix.Nonce{}) + newTree := binprefix.NewMerkleTree(db, binprefix.Nonce{}) param := cosipbft.ServiceParam{ Mino: onet, Cosi: cosi, Validation: vs, Access: accessService, - Pool: pool, + Pool: newPool, DB: db, - Tree: tree, + Tree: newTree, } - err = tree.Load() + err = newTree.Load() require.NoError(t, err) genstore := blockstore.NewGenesisDiskStore(db, types.NewGenesisFactory(rosterFac)) @@ -202,10 +204,10 @@ func newDelaNode(t require.TestingT, path string, port int, kind string) dela { ordering: srvc, cosi: cosi, txManager: mgr, - pool: pool, + pool: newPool, accessService: accessService, accessStore: accessStore, - tree: tree, + tree: newTree, } }