Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize lib/peer.js #1495

Merged
merged 2 commits into from Aug 30, 2018
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Next

Modernize lib/peer.js

  • Loading branch information
DiegoRBaquero committed Aug 30, 2018
commit 12f3833cf6b3ab59b675ba77edf6c012e2f8824e
@@ -1,28 +1,28 @@
var arrayRemove = require('unordered-array-remove')
var debug = require('debug')('webtorrent:peer')
var Wire = require('bittorrent-protocol')
const arrayRemove = require('unordered-array-remove');
const debug = require('debug')('webtorrent:peer');
const Wire = require('bittorrent-protocol');

var WebConn = require('./webconn')
const WebConn = require('./webconn');

var CONNECT_TIMEOUT_TCP = 5000
var CONNECT_TIMEOUT_WEBRTC = 25000
var HANDSHAKE_TIMEOUT = 25000
const CONNECT_TIMEOUT_TCP = 5000;
const CONNECT_TIMEOUT_WEBRTC = 25000;
const HANDSHAKE_TIMEOUT = 25000;

/**
* WebRTC peer connections start out connected, because WebRTC peers require an
* "introduction" (i.e. WebRTC signaling), and there's no equivalent to an IP address
* that lets you refer to a WebRTC endpoint.
*/
exports.createWebRTCPeer = function (conn, swarm) {
var peer = new Peer(conn.id, 'webrtc')
exports.createWebRTCPeer = (conn, swarm) => {
const peer = new Peer(conn.id, 'webrtc');
peer.conn = conn
peer.swarm = swarm

if (peer.conn.connected) {
peer.onConnect()
} else {
peer.conn.once('connect', function () { peer.onConnect() })
peer.conn.once('error', function (err) { peer.destroy(err) })
peer.conn.once('connect', () => { peer.onConnect() })
peer.conn.once('error', err => { peer.destroy(err) })
peer.startConnectTimeout()
}

@@ -34,9 +34,9 @@ exports.createWebRTCPeer = function (conn, swarm) {
* listening port of the TCP server. Until the remote peer sends a handshake, we don't
* know what swarm the connection is intended for.
*/
exports.createTCPIncomingPeer = function (conn) {
var addr = conn.remoteAddress + ':' + conn.remotePort
var peer = new Peer(addr, 'tcpIncoming')
exports.createTCPIncomingPeer = conn => {
const addr = `${conn.remoteAddress}:${conn.remotePort}`;
const peer = new Peer(addr, 'tcpIncoming');
peer.conn = conn
peer.addr = addr

@@ -49,8 +49,8 @@ exports.createTCPIncomingPeer = function (conn) {
* Outgoing TCP peers start out with just an IP address. At some point (when there is an
* available connection), the client can attempt to connect to the address.
*/
exports.createTCPOutgoingPeer = function (addr, swarm) {
var peer = new Peer(addr, 'tcpOutgoing')
exports.createTCPOutgoingPeer = (addr, swarm) => {
const peer = new Peer(addr, 'tcpOutgoing');
peer.addr = addr
peer.swarm = swarm

@@ -60,8 +60,8 @@ exports.createTCPOutgoingPeer = function (addr, swarm) {
/**
* Peer that represents a Web Seed (BEP17 / BEP19).
*/
exports.createWebSeedPeer = function (url, swarm) {
var peer = new Peer(url, 'webSeed')
exports.createWebSeedPeer = (url, swarm) => {
const peer = new Peer(url, 'webSeed');
peer.swarm = swarm
peer.conn = new WebConn(url, swarm)

@@ -76,170 +76,163 @@ exports.createWebSeedPeer = function (url, swarm) {
* @param {string} id "ip:port" string, peer id (for WebRTC peers), or url (for Web Seeds)
* @param {string} type the type of the peer
*/
function Peer (id, type) {
var self = this
self.id = id
self.type = type
class Peer {
constructor(id, type) {
this.id = id
this.type = type

debug('new %s Peer %s', type, id)
debug('new %s Peer %s', type, id)

self.addr = null
self.conn = null
self.swarm = null
self.wire = null
this.addr = null
this.conn = null
this.swarm = null
this.wire = null

self.connected = false
self.destroyed = false
self.timeout = null // handshake timeout
self.retries = 0 // outgoing TCP connection retry count
this.connected = false
this.destroyed = false
this.timeout = null // handshake timeout
this.retries = 0 // outgoing TCP connection retry count

self.sentHandshake = false
}

/**
* Called once the peer is connected (i.e. fired 'connect' event)
* @param {Socket} conn
*/
Peer.prototype.onConnect = function () {
var self = this
if (self.destroyed) return
self.connected = true

debug('Peer %s connected', self.id)

clearTimeout(self.connectTimeout)

var conn = self.conn
conn.once('end', function () {
self.destroy()
})
conn.once('close', function () {
self.destroy()
})
conn.once('finish', function () {
self.destroy()
})
conn.once('error', function (err) {
self.destroy(err)
})

var wire = self.wire = new Wire()
wire.type = self.type
wire.once('end', function () {
self.destroy()
})
wire.once('close', function () {
self.destroy()
})
wire.once('finish', function () {
self.destroy()
})
wire.once('error', function (err) {
self.destroy(err)
})

wire.once('handshake', function (infoHash, peerId) {
self.onHandshake(infoHash, peerId)
})
self.startHandshakeTimeout()

conn.pipe(wire).pipe(conn)
if (self.swarm && !self.sentHandshake) self.handshake()
}

/**
* Called when handshake is received from remote peer.
* @param {string} infoHash
* @param {string} peerId
*/
Peer.prototype.onHandshake = function (infoHash, peerId) {
var self = this
if (!self.swarm) return // `self.swarm` not set yet, so do nothing
if (self.destroyed) return

if (self.swarm.destroyed) {
return self.destroy(new Error('swarm already destroyed'))
}
if (infoHash !== self.swarm.infoHash) {
return self.destroy(new Error('unexpected handshake info hash for this swarm'))
this.sentHandshake = false
}
if (peerId === self.swarm.peerId) {
return self.destroy(new Error('refusing to connect to ourselves'))
}

debug('Peer %s got handshake %s', self.id, infoHash)

clearTimeout(self.handshakeTimeout)

self.retries = 0

var addr = self.addr
if (!addr && self.conn.remoteAddress && self.conn.remotePort) {
addr = self.conn.remoteAddress + ':' + self.conn.remotePort
/**
* Called once the peer is connected (i.e. fired 'connect' event)
* @param {Socket} conn
*/
onConnect() {
if (this.destroyed) return
this.connected = true

debug('Peer %s connected', this.id)

clearTimeout(this.connectTimeout)

const conn = this.conn;
conn.once('end', () => {
this.destroy()
})
conn.once('close', () => {
this.destroy()
})
conn.once('finish', () => {
this.destroy()
})
conn.once('error', err => {
this.destroy(err)
})

const wire = this.wire = new Wire();
wire.type = this.type
wire.once('end', () => {
this.destroy()
})
wire.once('close', () => {
this.destroy()
})
wire.once('finish', () => {
this.destroy()
})
wire.once('error', err => {
this.destroy(err)
})

wire.once('handshake', (infoHash, peerId) => {
this.onHandshake(infoHash, peerId)
})
this.startHandshakeTimeout()

conn.pipe(wire).pipe(conn)
if (this.swarm && !this.sentHandshake) this.handshake()
}
self.swarm._onWire(self.wire, addr)

// swarm could be destroyed in user's 'wire' event handler
if (!self.swarm || self.swarm.destroyed) return

if (!self.sentHandshake) self.handshake()
}

Peer.prototype.handshake = function () {
var self = this
var opts = {
dht: self.swarm.private ? false : !!self.swarm.client.dht
/**
* Called when handshake is received from remote peer.
* @param {string} infoHash
* @param {string} peerId
*/
onHandshake(infoHash, peerId) {
if (!this.swarm) return // `this.swarm` not set yet, so do nothing
if (this.destroyed) return

if (this.swarm.destroyed) {
return this.destroy(new Error('swarm already destroyed'))
}
if (infoHash !== this.swarm.infoHash) {
return this.destroy(new Error('unexpected handshake info hash for this swarm'))
}
if (peerId === this.swarm.peerId) {
return this.destroy(new Error('refusing to connect to ourselves'))
}

debug('Peer %s got handshake %s', this.id, infoHash)

clearTimeout(this.handshakeTimeout)

this.retries = 0

let addr = this.addr;
if (!addr && this.conn.remoteAddress && this.conn.remotePort) {
addr = `${this.conn.remoteAddress}:${this.conn.remotePort}`
}
this.swarm._onWire(this.wire, addr)

// swarm could be destroyed in user's 'wire' event handler
if (!this.swarm || this.swarm.destroyed) return

if (!this.sentHandshake) this.handshake()
}
self.wire.handshake(self.swarm.infoHash, self.swarm.client.peerId, opts)
self.sentHandshake = true
}

Peer.prototype.startConnectTimeout = function () {
var self = this
clearTimeout(self.connectTimeout)
self.connectTimeout = setTimeout(function () {
self.destroy(new Error('connect timeout'))
}, self.type === 'webrtc' ? CONNECT_TIMEOUT_WEBRTC : CONNECT_TIMEOUT_TCP)
if (self.connectTimeout.unref) self.connectTimeout.unref()
}

Peer.prototype.startHandshakeTimeout = function () {
var self = this
clearTimeout(self.handshakeTimeout)
self.handshakeTimeout = setTimeout(function () {
self.destroy(new Error('handshake timeout'))
}, HANDSHAKE_TIMEOUT)
if (self.handshakeTimeout.unref) self.handshakeTimeout.unref()
}

Peer.prototype.destroy = function (err) {
var self = this
if (self.destroyed) return
self.destroyed = true
self.connected = false

debug('destroy %s (error: %s)', self.id, err && (err.message || err))

clearTimeout(self.connectTimeout)
clearTimeout(self.handshakeTimeout)

var swarm = self.swarm
var conn = self.conn
var wire = self.wire
handshake() {
const opts = {
dht: this.swarm.private ? false : !!this.swarm.client.dht
};
this.wire.handshake(this.swarm.infoHash, this.swarm.client.peerId, opts)
this.sentHandshake = true
}

self.swarm = null
self.conn = null
self.wire = null
startConnectTimeout() {
clearTimeout(this.connectTimeout)
this.connectTimeout = setTimeout(() => {
this.destroy(new Error('connect timeout'))
}, this.type === 'webrtc' ? CONNECT_TIMEOUT_WEBRTC : CONNECT_TIMEOUT_TCP)
if (this.connectTimeout.unref) this.connectTimeout.unref()
}

if (swarm && wire) {
arrayRemove(swarm.wires, swarm.wires.indexOf(wire))
startHandshakeTimeout() {
clearTimeout(this.handshakeTimeout)
this.handshakeTimeout = setTimeout(() => {
this.destroy(new Error('handshake timeout'))
}, HANDSHAKE_TIMEOUT)
if (this.handshakeTimeout.unref) this.handshakeTimeout.unref()
}
if (conn) {
conn.on('error', noop)
conn.destroy()

destroy(err) {
if (this.destroyed) return
this.destroyed = true
this.connected = false

debug('destroy %s (error: %s)', this.id, err && (err.message || err))

clearTimeout(this.connectTimeout)
clearTimeout(this.handshakeTimeout)

const swarm = this.swarm;
const conn = this.conn;
const wire = this.wire;

this.swarm = null
this.conn = null
this.wire = null

if (swarm && wire) {
arrayRemove(swarm.wires, swarm.wires.indexOf(wire))
}
if (conn) {
conn.on('error', () => {})
conn.destroy()
}
if (wire) wire.destroy()
if (swarm) swarm.removePeer(this.id)
}
if (wire) wire.destroy()
if (swarm) swarm.removePeer(self.id)
}

function noop () {}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.