Skip to content

Commit 9d89de5

Browse files
authored
Allow HTTP Request to /stats and /stats.json route (#1)
1 parent 938db35 commit 9d89de5

File tree

1 file changed

+127
-122
lines changed

1 file changed

+127
-122
lines changed

server.js

Lines changed: 127 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -136,147 +136,148 @@ class Server extends EventEmitter {
136136
}
137137

138138
// Http handler for '/stats' route
139-
this.http.on('request', (req, res) => {
140-
if (res.headersSent) return
139+
this.http.on('request', this.onStats);
140+
}
141+
142+
let num = !!this.http + !!this.udp4 + !!this.udp6
143+
const self = this
144+
function onListening () {
145+
num -= 1
146+
if (num === 0) {
147+
self.listening = true
148+
debug('listening')
149+
self.emit('listening')
150+
}
151+
}
152+
}
141153

142-
const infoHashes = Object.keys(this.torrents)
143-
let activeTorrents = 0
144-
const allPeers = {}
154+
onStats = (req, res) => {
155+
if (res.headersSent) return
145156

146-
function countPeers (filterFunction) {
147-
let count = 0
148-
let key
157+
const infoHashes = Object.keys(this.torrents)
158+
let activeTorrents = 0
159+
const allPeers = {}
149160

150-
for (key in allPeers) {
151-
if (hasOwnProperty.call(allPeers, key) && filterFunction(allPeers[key])) {
152-
count++
153-
}
154-
}
161+
function countPeers (filterFunction) {
162+
let count = 0
163+
let key
155164

156-
return count
165+
for (key in allPeers) {
166+
if (hasOwnProperty.call(allPeers, key) && filterFunction(allPeers[key])) {
167+
count++
157168
}
169+
}
158170

159-
function groupByClient () {
160-
const clients = {}
161-
for (const key in allPeers) {
162-
if (hasOwnProperty.call(allPeers, key)) {
163-
const peer = allPeers[key]
164-
165-
if (!clients[peer.client.client]) {
166-
clients[peer.client.client] = {}
167-
}
168-
const client = clients[peer.client.client]
169-
// If the client is not known show 8 chars from peerId as version
170-
const version = peer.client.version || Buffer.from(peer.peerId, 'hex').toString().substring(0, 8)
171-
if (!client[version]) {
172-
client[version] = 0
173-
}
174-
client[version]++
175-
}
171+
return count
172+
}
173+
174+
function groupByClient () {
175+
const clients = {}
176+
for (const key in allPeers) {
177+
if (hasOwnProperty.call(allPeers, key)) {
178+
const peer = allPeers[key]
179+
180+
if (!clients[peer.client.client]) {
181+
clients[peer.client.client] = {}
182+
}
183+
const client = clients[peer.client.client]
184+
// If the client is not known show 8 chars from peerId as version
185+
const version = peer.client.version || Buffer.from(peer.peerId, 'hex').toString().substring(0, 8)
186+
if (!client[version]) {
187+
client[version] = 0
176188
}
177-
return clients
189+
client[version]++
178190
}
191+
}
192+
return clients
193+
}
179194

180-
function printClients (clients) {
181-
let html = '<ul>\n'
182-
for (const name in clients) {
183-
if (hasOwnProperty.call(clients, name)) {
184-
const client = clients[name]
185-
for (const version in client) {
186-
if (hasOwnProperty.call(client, version)) {
187-
html += `<li><strong>${name}</strong> ${version} : ${client[version]}</li>\n`
188-
}
189-
}
195+
function printClients (clients) {
196+
let html = '<ul>\n'
197+
for (const name in clients) {
198+
if (hasOwnProperty.call(clients, name)) {
199+
const client = clients[name]
200+
for (const version in client) {
201+
if (hasOwnProperty.call(client, version)) {
202+
html += `<li><strong>${name}</strong> ${version} : ${client[version]}</li>\n`
190203
}
191204
}
192-
html += '</ul>'
193-
return html
194205
}
206+
}
207+
html += '</ul>'
208+
return html
209+
}
195210

196-
if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) {
197-
infoHashes.forEach(infoHash => {
198-
const peers = this.torrents[infoHash].peers
199-
const keys = peers.keys
200-
if (keys.length > 0) activeTorrents++
201-
202-
keys.forEach(peerId => {
203-
// Don't mark the peer as most recently used for stats
204-
const peer = peers.peek(peerId)
205-
if (peer == null) return // peers.peek() can evict the peer
206-
207-
if (!hasOwnProperty.call(allPeers, peerId)) {
208-
allPeers[peerId] = {
209-
ipv4: false,
210-
ipv6: false,
211-
seeder: false,
212-
leecher: false
213-
}
214-
}
215-
216-
if (peer.ip.includes(':')) {
217-
allPeers[peerId].ipv6 = true
218-
} else {
219-
allPeers[peerId].ipv4 = true
220-
}
221-
222-
if (peer.complete) {
223-
allPeers[peerId].seeder = true
224-
} else {
225-
allPeers[peerId].leecher = true
226-
}
227-
228-
allPeers[peerId].peerId = peer.peerId
229-
allPeers[peerId].client = peerid(peer.peerId)
230-
})
231-
})
211+
if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) {
212+
infoHashes.forEach(infoHash => {
213+
const peers = this.torrents[infoHash].peers
214+
const keys = peers.keys
215+
if (keys.length > 0) activeTorrents++
216+
217+
keys.forEach(peerId => {
218+
// Don't mark the peer as most recently used for stats
219+
const peer = peers.peek(peerId)
220+
if (peer == null) return // peers.peek() can evict the peer
221+
222+
if (!hasOwnProperty.call(allPeers, peerId)) {
223+
allPeers[peerId] = {
224+
ipv4: false,
225+
ipv6: false,
226+
seeder: false,
227+
leecher: false
228+
}
229+
}
232230

233-
const isSeederOnly = peer => { return peer.seeder && peer.leecher === false }
234-
const isLeecherOnly = peer => { return peer.leecher && peer.seeder === false }
235-
const isSeederAndLeecher = peer => { return peer.seeder && peer.leecher }
236-
const isIPv4 = peer => { return peer.ipv4 }
237-
const isIPv6 = peer => { return peer.ipv6 }
238-
239-
const stats = {
240-
torrents: infoHashes.length,
241-
activeTorrents,
242-
peersAll: Object.keys(allPeers).length,
243-
peersSeederOnly: countPeers(isSeederOnly),
244-
peersLeecherOnly: countPeers(isLeecherOnly),
245-
peersSeederAndLeecher: countPeers(isSeederAndLeecher),
246-
peersIPv4: countPeers(isIPv4),
247-
peersIPv6: countPeers(isIPv6),
248-
clients: groupByClient()
231+
if (peer.ip.includes(':')) {
232+
allPeers[peerId].ipv6 = true
233+
} else {
234+
allPeers[peerId].ipv4 = true
249235
}
250236

251-
if (req.url === '/stats.json' || req.headers.accept === 'application/json') {
252-
res.setHeader('Content-Type', 'application/json')
253-
res.end(JSON.stringify(stats))
254-
} else if (req.url === '/stats') {
255-
res.setHeader('Content-Type', 'text/html')
256-
res.end(`
257-
<h1>${stats.torrents} torrents (${stats.activeTorrents} active)</h1>
258-
<h2>Connected Peers: ${stats.peersAll}</h2>
259-
<h3>Peers Seeding Only: ${stats.peersSeederOnly}</h3>
260-
<h3>Peers Leeching Only: ${stats.peersLeecherOnly}</h3>
261-
<h3>Peers Seeding & Leeching: ${stats.peersSeederAndLeecher}</h3>
262-
<h3>IPv4 Peers: ${stats.peersIPv4}</h3>
263-
<h3>IPv6 Peers: ${stats.peersIPv6}</h3>
264-
<h3>Clients:</h3>
265-
${printClients(stats.clients)}
266-
`.replace(/^\s+/gm, '')) // trim left
237+
if (peer.complete) {
238+
allPeers[peerId].seeder = true
239+
} else {
240+
allPeers[peerId].leecher = true
267241
}
268-
}
242+
243+
allPeers[peerId].peerId = peer.peerId
244+
allPeers[peerId].client = peerid(peer.peerId)
245+
})
269246
})
270-
}
271247

272-
let num = !!this.http + !!this.udp4 + !!this.udp6
273-
const self = this
274-
function onListening () {
275-
num -= 1
276-
if (num === 0) {
277-
self.listening = true
278-
debug('listening')
279-
self.emit('listening')
248+
const isSeederOnly = peer => { return peer.seeder && peer.leecher === false }
249+
const isLeecherOnly = peer => { return peer.leecher && peer.seeder === false }
250+
const isSeederAndLeecher = peer => { return peer.seeder && peer.leecher }
251+
const isIPv4 = peer => { return peer.ipv4 }
252+
const isIPv6 = peer => { return peer.ipv6 }
253+
254+
const stats = {
255+
torrents: infoHashes.length,
256+
activeTorrents,
257+
peersAll: Object.keys(allPeers).length,
258+
peersSeederOnly: countPeers(isSeederOnly),
259+
peersLeecherOnly: countPeers(isLeecherOnly),
260+
peersSeederAndLeecher: countPeers(isSeederAndLeecher),
261+
peersIPv4: countPeers(isIPv4),
262+
peersIPv6: countPeers(isIPv6),
263+
clients: groupByClient()
264+
}
265+
266+
if (req.url === '/stats.json' || req.headers.accept === 'application/json') {
267+
res.write(JSON.stringify(stats))
268+
res.end()
269+
} else if (req.url === '/stats') {
270+
res.end(`
271+
<h1>${stats.torrents} torrents (${stats.activeTorrents} active)</h1>
272+
<h2>Connected Peers: ${stats.peersAll}</h2>
273+
<h3>Peers Seeding Only: ${stats.peersSeederOnly}</h3>
274+
<h3>Peers Leeching Only: ${stats.peersLeecherOnly}</h3>
275+
<h3>Peers Seeding & Leeching: ${stats.peersSeederAndLeecher}</h3>
276+
<h3>IPv4 Peers: ${stats.peersIPv4}</h3>
277+
<h3>IPv6 Peers: ${stats.peersIPv6}</h3>
278+
<h3>Clients:</h3>
279+
${printClients(stats.clients)}
280+
`.replace(/^\s+/gm, '')) // trim left
280281
}
281282
}
282283
}
@@ -363,6 +364,10 @@ class Server extends EventEmitter {
363364
onHttpRequest (req, res, opts = {}) {
364365
opts.trustProxy = opts.trustProxy || this._trustProxy
365366

367+
if (req.originalUrl === "/stats" || req.originalUrl === "/stats.json") {
368+
return this.onStats(req, res);
369+
}
370+
366371
let params
367372
try {
368373
params = parseHttpRequest(req, opts)

0 commit comments

Comments
 (0)