diff --git a/torrent.go b/torrent.go index e53b6bef..f18fc252 100644 --- a/torrent.go +++ b/torrent.go @@ -61,6 +61,7 @@ type Torrent struct { userOnWriteChunkErr func(error) closed chansync.SetOnce + onClose []func() infoHash metainfo.Hash pieces []Piece @@ -865,6 +866,9 @@ func (t *Torrent) close(wg *sync.WaitGroup) (err error) { err = errors.New("already closed") return } + for _, f := range t.onClose { + f() + } if t.storage != nil { wg.Add(1) go func() { @@ -1614,11 +1618,10 @@ func (t *Torrent) runHandshookConnLoggingErr(pc *PeerConn) { } func (t *Torrent) startWebsocketAnnouncer(u url.URL) torrentTrackerAnnouncer { - wtc, release := t.cl.websocketTrackers.Get(u.String()) - go func() { - <-t.closed.Done() - release() - }() + wtc, release := t.cl.websocketTrackers.Get(u.String(), t.infoHash) + // This needs to run before the Torrent is dropped from the Client, to prevent a new webtorrent.TrackerClient for + // the same info hash before the old one is cleaned up. + t.onClose = append(t.onClose, release) wst := websocketTrackerStatus{u, wtc} go func() { err := wtc.Announce(tracker.Started, t.infoHash) diff --git a/webtorrent/tracker-client.go b/webtorrent/tracker-client.go index 1ec4b9d9..3b8c6a6b 100644 --- a/webtorrent/tracker-client.go +++ b/webtorrent/tracker-client.go @@ -187,6 +187,17 @@ func (tc *TrackerClient) closeUnusedOffers() { tc.outboundOffers = nil } +func (tc *TrackerClient) CloseOffersForInfohash(infoHash [20]byte) { + tc.mu.Lock() + defer tc.mu.Unlock() + for key, offer := range tc.outboundOffers { + if offer.infoHash == infoHash { + offer.peerConnection.Close() + delete(tc.outboundOffers, key) + } + } +} + func (tc *TrackerClient) Announce(event tracker.AnnounceEvent, infoHash [20]byte) error { metrics.Add("outbound announces", 1) var randOfferId [20]byte diff --git a/wstracker.go b/wstracker.go index 5338ceb9..e8bde8c3 100644 --- a/wstracker.go +++ b/wstracker.go @@ -42,7 +42,7 @@ type websocketTrackers struct { Proxy http.ProxyFunc } -func (me *websocketTrackers) Get(url string) (*webtorrent.TrackerClient, func()) { +func (me *websocketTrackers) Get(url string, infoHash [20]byte) (*webtorrent.TrackerClient, func()) { me.mu.Lock() defer me.mu.Unlock() value, ok := me.clients[url] @@ -74,6 +74,7 @@ func (me *websocketTrackers) Get(url string) (*webtorrent.TrackerClient, func()) return &value.TrackerClient, func() { me.mu.Lock() defer me.mu.Unlock() + value.TrackerClient.CloseOffersForInfohash(infoHash) value.refCount-- if value.refCount == 0 { value.TrackerClient.Close()