#2919·webtorrent

PeX never sends it's own local peers, only receives from remote.

Author: gdbortonCreated Jan 28, 2025Updated Oct 11, 2025
Labelsarea/nodeaccepted

What version of this package are you using? Latest

What operating system, Node.js, and npm version? N/A

What happened? I'm looking into adding i2p support and have it working locally. While looking into this, I started down the path of adding support for PeX. I've gotten it to mostly work, but spotted two issues along the way.

  1. The ut_pex instance is never passed peers from the torrent class.
  2. The ut_pex instance calls reset() in it's constructor, which stops the message sending timer, and Torrent.js never calls start().

I spotted this super old PR that removes the call to .start(), but it seems this was never implemented : https://github.com/webtorrent/webtorrent/commit/e2ed17c571a7bc9879725fa9b4f5e152b4f019d0

What I think needs to be happening is:

  1. call ut_pex.start() after wire.use(utPex);
  2. iterate over already connected wires on the torrent, and for each, call ut_pex.addPeer(wire) to add the existing wires to the ut_pex instance (and also, for each wire add this new wire to their own ut_pex instance)
javascript
// torrent.js
if (this.client.utPex && typeof utPex === 'function' && !this.private) {
      wire.use(utPex())
      wire.ut_pex.start(); // <-- start pex message timer
     
      this.wires.forEach(existingWire => {
        const existingAddress = `${existingWire.remoteAddress}:${existingWire.remotePort}`;
        const newAddress = `${wire.remoteAddress}:${wire.remotePort}`;
        if (existingAddress === newAddress) return; // bail early if we're adding a peer to itself
        wire.ut_pex.addPeer(existingAddress)); // <-- add existing wires to this new one
        existingWire.ut_pex?.addPeer(newAddress); // <-- add the new wire being instantiated to the existing wires.
      });

      wire.ut_pex.on('peer', peer => {
        // Only add potential new peers when we're not seeding
        if (this.done) return
        this._debug('ut_pex: got peer: %s (from %s)', peer, addr)
        this.addPeer(peer, Peer.SOURCE_UT_PEX)
      })

      wire.ut_pex.on('dropped', peer => {
        // the remote peer believes a given peer has been dropped from the torrent swarm.
        // if we're not currently connected to it, then remove it from the queue.
        const peerObj = this._peers[peer]
        if (peerObj && !peerObj.connected) {
          this._debug('ut_pex: dropped peer: %s (from %s)', peer, addr)
          this.removePeer(peer)
        }
      })

      wire.once('close', () => {
        // Stop sending updates to remote peer
        wire.ut_pex.reset()
      })
    }

What did you expect to happen?

Are you willing to submit a pull request to fix this bug? Yeah probably