diff --git a/server.js b/server.js index 1ec53da4..8d39ca99 100644 --- a/server.js +++ b/server.js @@ -136,147 +136,148 @@ class Server extends EventEmitter { } // Http handler for '/stats' route - this.http.on('request', (req, res) => { - if (res.headersSent) return + this.http.on('request', this.onStats); + } + + let num = !!this.http + !!this.udp4 + !!this.udp6 + const self = this + function onListening () { + num -= 1 + if (num === 0) { + self.listening = true + debug('listening') + self.emit('listening') + } + } + } - const infoHashes = Object.keys(this.torrents) - let activeTorrents = 0 - const allPeers = {} + onStats = (req, res) => { + if (res.headersSent) return - function countPeers (filterFunction) { - let count = 0 - let key + const infoHashes = Object.keys(this.torrents) + let activeTorrents = 0 + const allPeers = {} - for (key in allPeers) { - if (hasOwnProperty.call(allPeers, key) && filterFunction(allPeers[key])) { - count++ - } - } + function countPeers (filterFunction) { + let count = 0 + let key - return count + for (key in allPeers) { + if (hasOwnProperty.call(allPeers, key) && filterFunction(allPeers[key])) { + count++ } + } - function groupByClient () { - const clients = {} - for (const key in allPeers) { - if (hasOwnProperty.call(allPeers, key)) { - const peer = allPeers[key] - - if (!clients[peer.client.client]) { - clients[peer.client.client] = {} - } - const client = clients[peer.client.client] - // If the client is not known show 8 chars from peerId as version - const version = peer.client.version || Buffer.from(peer.peerId, 'hex').toString().substring(0, 8) - if (!client[version]) { - client[version] = 0 - } - client[version]++ - } + return count + } + + function groupByClient () { + const clients = {} + for (const key in allPeers) { + if (hasOwnProperty.call(allPeers, key)) { + const peer = allPeers[key] + + if (!clients[peer.client.client]) { + clients[peer.client.client] = {} + } + const client = clients[peer.client.client] + // If the client is not known show 8 chars from peerId as version + const version = peer.client.version || Buffer.from(peer.peerId, 'hex').toString().substring(0, 8) + if (!client[version]) { + client[version] = 0 } - return clients + client[version]++ } + } + return clients + } - function printClients (clients) { - let html = '' + return html + } - if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) { - infoHashes.forEach(infoHash => { - const peers = this.torrents[infoHash].peers - const keys = peers.keys - if (keys.length > 0) activeTorrents++ - - keys.forEach(peerId => { - // Don't mark the peer as most recently used for stats - const peer = peers.peek(peerId) - if (peer == null) return // peers.peek() can evict the peer - - if (!hasOwnProperty.call(allPeers, peerId)) { - allPeers[peerId] = { - ipv4: false, - ipv6: false, - seeder: false, - leecher: false - } - } - - if (peer.ip.includes(':')) { - allPeers[peerId].ipv6 = true - } else { - allPeers[peerId].ipv4 = true - } - - if (peer.complete) { - allPeers[peerId].seeder = true - } else { - allPeers[peerId].leecher = true - } - - allPeers[peerId].peerId = peer.peerId - allPeers[peerId].client = peerid(peer.peerId) - }) - }) + if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) { + infoHashes.forEach(infoHash => { + const peers = this.torrents[infoHash].peers + const keys = peers.keys + if (keys.length > 0) activeTorrents++ + + keys.forEach(peerId => { + // Don't mark the peer as most recently used for stats + const peer = peers.peek(peerId) + if (peer == null) return // peers.peek() can evict the peer + + if (!hasOwnProperty.call(allPeers, peerId)) { + allPeers[peerId] = { + ipv4: false, + ipv6: false, + seeder: false, + leecher: false + } + } - const isSeederOnly = peer => { return peer.seeder && peer.leecher === false } - const isLeecherOnly = peer => { return peer.leecher && peer.seeder === false } - const isSeederAndLeecher = peer => { return peer.seeder && peer.leecher } - const isIPv4 = peer => { return peer.ipv4 } - const isIPv6 = peer => { return peer.ipv6 } - - const stats = { - torrents: infoHashes.length, - activeTorrents, - peersAll: Object.keys(allPeers).length, - peersSeederOnly: countPeers(isSeederOnly), - peersLeecherOnly: countPeers(isLeecherOnly), - peersSeederAndLeecher: countPeers(isSeederAndLeecher), - peersIPv4: countPeers(isIPv4), - peersIPv6: countPeers(isIPv6), - clients: groupByClient() + if (peer.ip.includes(':')) { + allPeers[peerId].ipv6 = true + } else { + allPeers[peerId].ipv4 = true } - if (req.url === '/stats.json' || req.headers.accept === 'application/json') { - res.setHeader('Content-Type', 'application/json') - res.end(JSON.stringify(stats)) - } else if (req.url === '/stats') { - res.setHeader('Content-Type', 'text/html') - res.end(` -

${stats.torrents} torrents (${stats.activeTorrents} active)

-

Connected Peers: ${stats.peersAll}

-

Peers Seeding Only: ${stats.peersSeederOnly}

-

Peers Leeching Only: ${stats.peersLeecherOnly}

-

Peers Seeding & Leeching: ${stats.peersSeederAndLeecher}

-

IPv4 Peers: ${stats.peersIPv4}

-

IPv6 Peers: ${stats.peersIPv6}

-

Clients:

- ${printClients(stats.clients)} - `.replace(/^\s+/gm, '')) // trim left + if (peer.complete) { + allPeers[peerId].seeder = true + } else { + allPeers[peerId].leecher = true } - } + + allPeers[peerId].peerId = peer.peerId + allPeers[peerId].client = peerid(peer.peerId) + }) }) - } - let num = !!this.http + !!this.udp4 + !!this.udp6 - const self = this - function onListening () { - num -= 1 - if (num === 0) { - self.listening = true - debug('listening') - self.emit('listening') + const isSeederOnly = peer => { return peer.seeder && peer.leecher === false } + const isLeecherOnly = peer => { return peer.leecher && peer.seeder === false } + const isSeederAndLeecher = peer => { return peer.seeder && peer.leecher } + const isIPv4 = peer => { return peer.ipv4 } + const isIPv6 = peer => { return peer.ipv6 } + + const stats = { + torrents: infoHashes.length, + activeTorrents, + peersAll: Object.keys(allPeers).length, + peersSeederOnly: countPeers(isSeederOnly), + peersLeecherOnly: countPeers(isLeecherOnly), + peersSeederAndLeecher: countPeers(isSeederAndLeecher), + peersIPv4: countPeers(isIPv4), + peersIPv6: countPeers(isIPv6), + clients: groupByClient() + } + + if (req.url === '/stats.json' || req.headers.accept === 'application/json') { + res.write(JSON.stringify(stats)) + res.end() + } else if (req.url === '/stats') { + res.end(` +

${stats.torrents} torrents (${stats.activeTorrents} active)

+

Connected Peers: ${stats.peersAll}

+

Peers Seeding Only: ${stats.peersSeederOnly}

+

Peers Leeching Only: ${stats.peersLeecherOnly}

+

Peers Seeding & Leeching: ${stats.peersSeederAndLeecher}

+

IPv4 Peers: ${stats.peersIPv4}

+

IPv6 Peers: ${stats.peersIPv6}

+

Clients:

+ ${printClients(stats.clients)} + `.replace(/^\s+/gm, '')) // trim left } } } @@ -363,6 +364,10 @@ class Server extends EventEmitter { onHttpRequest (req, res, opts = {}) { opts.trustProxy = opts.trustProxy || this._trustProxy + if (req.originalUrl === "/stats" || req.originalUrl === "/stats.json") { + return this.onStats(req, res); + } + let params try { params = parseHttpRequest(req, opts)