From f8c7de521300a42cea005262f34e358b52e85900 Mon Sep 17 00:00:00 2001 From: Yoann Ciabaud Date: Tue, 7 Jun 2016 14:34:38 +0200 Subject: [PATCH] Add stats on clients based on peerIds --- package.json | 1 + server.js | 48 +++++++++++++++++++++++++++++++++++++++++++++-- test/stats.js | 52 +++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0e2da31..ffcc060 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "bencode": "^0.10.0", + "bittorrent-peerid": "^1.0.2", "bn.js": "^4.4.0", "compact2string": "^1.2.0", "debug": "^2.0.0", diff --git a/server.js b/server.js index 62ca7be..8376635 100644 --- a/server.js +++ b/server.js @@ -7,6 +7,7 @@ var dgram = require('dgram') var EventEmitter = require('events').EventEmitter var http = require('http') var inherits = require('inherits') +var peerid = require('bittorrent-peerid') var series = require('run-series') var string2compact = require('string2compact') var WebSocketServer = require('ws').Server @@ -150,6 +151,43 @@ function Server (opts) { return count } + function groupByClient () { + var clients = {} + for (var key in allPeers) { + if (allPeers.hasOwnProperty(key)) { + var peer = allPeers[key] + + if (!clients[peer.client.client]) { + clients[peer.client.client] = {} + } + var client = clients[peer.client.client] + // If the client is not known show 8 chars from peerId as version + var version = peer.client.version || new Buffer(peer.peerId, 'hex').toString().substring(0, 8) + if (!client[version]) { + client[version] = 0 + } + client[version]++ + } + } + return clients + } + + function printClients (clients) { + var html = '' + return html + } + if (req.method === 'GET' && (req.url === '/stats' || req.url === '/stats.json')) { infoHashes.forEach(function (infoHash) { var peers = self.torrents[infoHash].peers @@ -176,6 +214,8 @@ function Server (opts) { } else { allPeers[peerId].leecher = true } + allPeers[peerId].peerId = peer.peerId + allPeers[peerId].client = peerid(peer.peerId) }) }) @@ -193,7 +233,8 @@ function Server (opts) { peersLeecherOnly: countPeers(isLeecherOnly), peersSeederAndLeecher: countPeers(isSeederAndLeecher), peersIPv4: countPeers(isIPv4), - peersIPv6: countPeers(isIPv6) + peersIPv6: countPeers(isIPv6), + clients: groupByClient() } if (req.url === '/stats.json' || req.headers['content-type'] === 'application/json') { @@ -206,7 +247,10 @@ function Server (opts) { '

Peers Leeching Only: ' + stats.peersLeecherOnly + '

\n' + '

Peers Seeding & Leeching: ' + stats.peersSeederAndLeecher + '

\n' + '

IPv4 Peers: ' + stats.peersIPv4 + '

\n' + - '

IPv6 Peers: ' + stats.peersIPv6 + '

\n') + '

IPv6 Peers: ' + stats.peersIPv6 + '

\n' + + '

Clients:

\n' + + printClients(stats.clients) + ) } } }) diff --git a/test/stats.js b/test/stats.js index 8971cd6..32edcb1 100644 --- a/test/stats.js +++ b/test/stats.js @@ -5,7 +5,8 @@ var fixtures = require('webtorrent-fixtures') var get = require('simple-get') var test = require('tape') -var peerId = Buffer.from('01234567890123456789') +var peerId = Buffer.from('-WW0091-4ea5886ce160') +var unknownPeerId = Buffer.from('01234567890123456789') function parseHtml (html) { var extractValue = new RegExp('[^v^h](\\d+)') @@ -13,7 +14,9 @@ function parseHtml (html) { return line && line.trim().length > 0 }).map(function (line) { var a = extractValue.exec(line) - return parseInt(a[1]) + if (a) { + return parseInt(a[1]) + } }) var i = 0 return { @@ -111,7 +114,7 @@ test('server: get empty stats on stats.json', function (t) { }) test('server: get leecher stats.json', function (t) { - t.plan(10) + t.plan(11) commonTest.createServer(t, 'http', function (server, announceUrl) { // announce a torrent to the tracker @@ -134,7 +137,6 @@ test('server: get leecher stats.json', function (t) { get.concat(opts, function (err, res, stats) { t.error(err) - console.log(stats) t.equal(res.statusCode, 200) t.equal(stats.torrents, 1) @@ -143,6 +145,48 @@ test('server: get leecher stats.json', function (t) { t.equal(stats.peersSeederOnly, 0) t.equal(stats.peersLeecherOnly, 1) t.equal(stats.peersSeederAndLeecher, 0) + t.equal(stats.clients['WebTorrent']['0.0.9.1'], 1) + + client.destroy(function () { t.pass('client destroyed') }) + server.close(function () { t.pass('server closed') }) + }) + }) + }) +}) + +test('server: get leecher stats.json (unknown peerId)', function (t) { + t.plan(11) + + commonTest.createServer(t, 'http', function (server, announceUrl) { + // announce a torrent to the tracker + var client = new Client({ + infoHash: fixtures.leaves.parsedTorrent.infoHash, + announce: announceUrl, + peerId: unknownPeerId, + port: 6881 + }) + client.on('error', function (err) { t.error(err) }) + client.on('warning', function (err) { t.error(err) }) + + client.start() + + server.once('start', function () { + var opts = { + url: announceUrl.replace('/announce', '/stats.json'), + json: true + } + + get.concat(opts, function (err, res, stats) { + t.error(err) + + t.equal(res.statusCode, 200) + t.equal(stats.torrents, 1) + t.equal(stats.activeTorrents, 1) + t.equal(stats.peersAll, 1) + t.equal(stats.peersSeederOnly, 0) + t.equal(stats.peersLeecherOnly, 1) + t.equal(stats.peersSeederAndLeecher, 0) + t.equal(stats.clients['unknown']['01234567'], 1) client.destroy(function () { t.pass('client destroyed') }) server.close(function () { t.pass('server closed') })