diff --git a/go.mod b/go.mod index 35cc26b65c..733c6670f0 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 github.com/anacrolix/missinggo v1.3.0 github.com/anacrolix/missinggo/v2 v2.7.4 - github.com/anacrolix/multiless v0.3.0 + github.com/anacrolix/multiless v0.4.0 github.com/anacrolix/possum/go v0.1.1-0.20240321122240-a01f3a22f2d1 github.com/anacrolix/squirrel v0.6.4 github.com/anacrolix/sync v0.5.1 @@ -52,7 +52,6 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 go.opentelemetry.io/otel/sdk v1.11.1 go.opentelemetry.io/otel/trace v1.11.1 - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 golang.org/x/sync v0.8.0 golang.org/x/sys v0.18.0 golang.org/x/time v0.0.0-20220609170525-579cf78fd858 @@ -137,6 +136,7 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.21.0 // indirect + golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect golang.org/x/net v0.23.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect diff --git a/go.sum b/go.sum index 2de5eff7e5..0a98832a4e 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/anacrolix/missinggo/v2 v2.7.4/go.mod h1:vVO5FEziQm+NFmJesc7StpkquZk+W github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw= github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg= github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc= -github.com/anacrolix/multiless v0.3.0 h1:5Bu0DZncjE4e06b9r1Ap2tUY4Au0NToBP5RpuEngSis= -github.com/anacrolix/multiless v0.3.0/go.mod h1:TrCLEZfIDbMVfLoQt5tOoiBS/uq4y8+ojuEVVvTNPX4= +github.com/anacrolix/multiless v0.4.0 h1:lqSszHkliMsZd2hsyrDvHOw4AbYWa+ijQ66LzbjqWjM= +github.com/anacrolix/multiless v0.4.0/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM= github.com/anacrolix/possum/go v0.1.1-0.20240321122240-a01f3a22f2d1 h1:lINi1HW+PExnMJkECx30AZSt0XT0cng9dVo3Zz5rSRM= github.com/anacrolix/possum/go v0.1.1-0.20240321122240-a01f3a22f2d1/go.mod h1:pw5HEMBSiL+otYzHe4q5jGaVuy5unl+Mt4Bx6SDemW8= github.com/anacrolix/squirrel v0.6.4 h1:K6ABRMCms0xwpEIdY3kAaDBUqiUeUYCKLKI0yHTr9IQ= diff --git a/metainfo/file-tree.go b/metainfo/file-tree.go index 6401b1ed4b..85cbd73654 100644 --- a/metainfo/file-tree.go +++ b/metainfo/file-tree.go @@ -1,10 +1,10 @@ package metainfo import ( - "sort" + "maps" + "slices" g "github.com/anacrolix/generics" - "golang.org/x/exp/maps" "github.com/anacrolix/torrent/bencode" ) @@ -91,9 +91,7 @@ func (ft *FileTree) IsDir() bool { } func (ft *FileTree) orderedKeys() []string { - keys := maps.Keys(ft.Dir) - sort.Strings(keys) - return keys + return slices.Sorted(maps.Keys(ft.Dir)) } func (ft *FileTree) upvertedFiles(pieceLength int64, out func(fi FileInfo)) { diff --git a/misc.go b/misc.go index a76f216f50..16538b781e 100644 --- a/misc.go +++ b/misc.go @@ -111,8 +111,8 @@ func chunkIndexSpec(index, pieceLength, chunkSize pp.Integer) ChunkSpec { return ret } -func connLessTrusted(l, r *Peer) bool { - return l.trust().Less(r.trust()) +func comparePeerTrust(l, r *Peer) int { + return l.trust().Cmp(r.trust()) } func connIsIpv6(nc interface { diff --git a/mse/mse.go b/mse/mse.go index a4c31f537f..f566c63f79 100644 --- a/mse/mse.go +++ b/mse/mse.go @@ -12,12 +12,13 @@ import ( "errors" "expvar" "fmt" - "github.com/anacrolix/torrent/internal/ctxrw" "io" "math" "math/big" "strconv" "sync" + + "github.com/anacrolix/torrent/internal/ctxrw" ) const ( diff --git a/peer.go b/peer.go index e28b5afd69..4e49468f6d 100644 --- a/peer.go +++ b/peer.go @@ -854,8 +854,8 @@ type connectionTrust struct { NetGoodPiecesDirted int64 } -func (l connectionTrust) Less(r connectionTrust) bool { - return multiless.New().Bool(l.Implicit, r.Implicit).Int64(l.NetGoodPiecesDirted, r.NetGoodPiecesDirted).Less() +func (l connectionTrust) Cmp(r connectionTrust) int { + return multiless.New().Bool(l.Implicit, r.Implicit).Int64(l.NetGoodPiecesDirted, r.NetGoodPiecesDirted).OrderingInt() } // Returns a new Bitmap that includes bits for all pieces the peer could have based on their claims. diff --git a/peerconn.go b/peerconn.go index f12477fd6f..65800dd695 100644 --- a/peerconn.go +++ b/peerconn.go @@ -21,7 +21,6 @@ import ( "github.com/anacrolix/log" "github.com/anacrolix/missinggo/v2/bitmap" "github.com/anacrolix/multiless" - "golang.org/x/exp/maps" "golang.org/x/time/rate" "github.com/anacrolix/torrent/bencode" @@ -103,24 +102,11 @@ func (cn *PeerConn) pexStatus() string { if !cn.supportsExtension(pp.ExtensionNamePex) { return "unsupported" } - if true { - return fmt.Sprintf( - "%v conns, %v unsent events", - len(cn.pex.remoteLiveConns), - cn.pex.numPending(), - ) - } else { - // This alternative branch prints out the remote live conn addresses. - return fmt.Sprintf( - "%v conns, %v unsent events", - strings.Join(generics.SliceMap( - maps.Keys(cn.pex.remoteLiveConns), - func(from netip.AddrPort) string { - return from.String() - }), ","), - cn.pex.numPending(), - ) - } + return fmt.Sprintf( + "%v conns, %v unsent events", + len(cn.pex.remoteLiveConns), + cn.pex.numPending(), + ) } func (cn *PeerConn) peerImplStatusLines() []string { diff --git a/tests/peers-bootstrapping/main.go b/tests/peers-bootstrapping/main.go index 2e0b382220..f9f100f65a 100644 --- a/tests/peers-bootstrapping/main.go +++ b/tests/peers-bootstrapping/main.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "fmt" "io" + "log/slog" "net/http" "os" "path/filepath" @@ -13,7 +14,6 @@ import ( "github.com/anacrolix/log" "github.com/anacrolix/sync" "github.com/dustin/go-humanize" - "golang.org/x/exp/slog" "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/bencode" diff --git a/torrent.go b/torrent.go index 8fb3912789..1288606117 100644 --- a/torrent.go +++ b/torrent.go @@ -9,10 +9,12 @@ import ( "fmt" "hash" "io" + "iter" + "maps" "math/rand" "net/netip" "net/url" - "sort" + "slices" "strings" "text/tabwriter" "time" @@ -25,14 +27,12 @@ import ( . "github.com/anacrolix/generics" g "github.com/anacrolix/generics" "github.com/anacrolix/log" - "github.com/anacrolix/missinggo/slices" "github.com/anacrolix/missinggo/v2" "github.com/anacrolix/missinggo/v2/bitmap" "github.com/anacrolix/missinggo/v2/pubsub" "github.com/anacrolix/multiless" "github.com/anacrolix/sync" "github.com/pion/datachannel" - "golang.org/x/exp/maps" "golang.org/x/sync/errgroup" "github.com/anacrolix/torrent/bencode" @@ -865,24 +865,28 @@ func (t *Torrent) writeStatus(w io.Writer) { fmt.Fprintln(w) fmt.Fprintf(w, "Enabled trackers:\n") - func() { + { tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0) fmt.Fprintf(tw, " URL\tExtra\n") - for _, ta := range slices.Sort(slices.FromMapElems(t.trackerAnnouncers), func(l, r torrentTrackerAnnouncer) bool { - lu := l.URL() - ru := r.URL() - var luns, runs url.URL = *lu, *ru - luns.Scheme = "" - runs.Scheme = "" - var ml missinggo.MultiLess - ml.StrictNext(luns.String() == runs.String(), luns.String() < runs.String()) - ml.StrictNext(lu.String() == ru.String(), lu.String() < ru.String()) - return ml.Less() - }).([]torrentTrackerAnnouncer) { + sortedTrackerAnnouncers := slices.SortedFunc( + maps.Values(t.trackerAnnouncers), + func(l, r torrentTrackerAnnouncer) int { + lu := l.URL() + ru := r.URL() + var luns, runs url.URL = *lu, *ru + luns.Scheme = "" + runs.Scheme = "" + var ml multiless.Computation + ml = multiless.EagerOrdered(ml, luns.String(), runs.String()) + ml = multiless.EagerOrdered(ml, lu.String(), ru.String()) + return ml.OrderingInt() + }, + ) + for _, ta := range sortedTrackerAnnouncers { fmt.Fprintf(tw, " %q\t%v\n", ta.URL(), ta.statusLine()) } tw.Flush() - }() + } fmt.Fprintf(w, "DHT Announces: %d\n", t.numDHTAnnounces) @@ -891,29 +895,31 @@ func (t *Torrent) writeStatus(w io.Writer) { fmt.Fprintf(w, "webseeds:\n") t.writePeerStatuses(w, maps.Values(t.webSeeds)) - peerConns := maps.Keys(t.conns) // Peers without priorities first, then those with. I'm undecided about how to order peers // without priorities. - sort.Slice(peerConns, func(li, ri int) bool { - l := peerConns[li] - r := peerConns[ri] + peerConns := slices.SortedFunc(maps.Keys(t.conns), func(l, r *PeerConn) int { ml := multiless.New() lpp := g.ResultFromTuple(l.peerPriority()).ToOption() rpp := g.ResultFromTuple(r.peerPriority()).ToOption() ml = ml.Bool(lpp.Ok, rpp.Ok) ml = ml.Uint32(rpp.Value, lpp.Value) - return ml.Less() + return ml.OrderingInt() }) fmt.Fprintf(w, "%v peer conns:\n", len(peerConns)) - t.writePeerStatuses(w, g.SliceMap(peerConns, func(pc *PeerConn) *Peer { - return &pc.Peer - })) + var peerIter iter.Seq[*Peer] = func(yield func(*Peer) bool) { + for _, pc := range peerConns { + if !yield(&pc.Peer) { + return + } + } + } + t.writePeerStatuses(w, peerIter) } -func (t *Torrent) writePeerStatuses(w io.Writer, peers []*Peer) { +func (t *Torrent) writePeerStatuses(w io.Writer, peers iter.Seq[*Peer]) { var buf bytes.Buffer - for _, c := range peers { + for c := range peers { fmt.Fprintf(w, "- ") buf.Reset() c.writeStatus(&buf) @@ -2433,7 +2439,7 @@ func (t *Torrent) pieceHashed(piece pieceIndex, passed bool, hashIoErr error) { } } t.clearPieceTouchers(piece) - slices.Sort(bannableTouchers, connLessTrusted) + slices.SortFunc(bannableTouchers, comparePeerTrust) if t.cl.config.Debug { t.logger.Printf(