mirror of
https://github.com/webtorrent/bittorrent-tracker.git
synced 2025-01-18 12:11:36 +00:00
Scrape implementation for websocket. Issue #116
This commit is contained in:
parent
eb3cefec35
commit
39507bf8be
@ -47,6 +47,7 @@ WebSocketTracker.prototype.announce = function (opts) {
|
||||
|
||||
self._generateOffers(numwant, function (offers) {
|
||||
var params = extend(opts, {
|
||||
action: 'announce',
|
||||
numwant: numwant,
|
||||
info_hash: self.client._infoHashBinary,
|
||||
peer_id: self.client._peerIdBinary,
|
||||
@ -61,7 +62,21 @@ WebSocketTracker.prototype.announce = function (opts) {
|
||||
WebSocketTracker.prototype.scrape = function (opts) {
|
||||
var self = this
|
||||
if (self.destroyed || self.reconnecting) return
|
||||
self._onSocketError(new Error('scrape not supported ' + self.announceUrl))
|
||||
if (!self.socket.connected) {
|
||||
return self.socket.once('connect', self.scrape.bind(self, opts))
|
||||
}
|
||||
|
||||
var infoHashes = (Array.isArray(opts.infoHash) && opts.infoHash.length > 0)
|
||||
? opts.infoHash.map(function (infoHash) {
|
||||
return infoHash.toString('binary')
|
||||
})
|
||||
: (opts.infoHash && opts.infoHash.toString('binary')) || self.client._infoHashBinary
|
||||
var params = {
|
||||
action: 'scrape',
|
||||
info_hash: infoHashes
|
||||
}
|
||||
|
||||
self._send(params)
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype.destroy = function (onclose) {
|
||||
@ -133,6 +148,18 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
return
|
||||
}
|
||||
|
||||
if (data.action === common.ACTIONS.ANNOUNCE || data.offer || data.answer) {
|
||||
self._onAnnounceResponse(data)
|
||||
} else if (data.action === common.ACTIONS.SCRAPE) {
|
||||
self._onScrapeResponse(data)
|
||||
} else {
|
||||
throw new Error('invalid action in WS response: ' + data.action)
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._onAnnounceResponse = function (data) {
|
||||
var self = this
|
||||
|
||||
if (data.info_hash !== self.client._infoHashBinary) {
|
||||
debug(
|
||||
'ignoring websocket data from %s for %s (looking for %s: reused socket)',
|
||||
@ -215,6 +242,32 @@ WebSocketTracker.prototype._onSocketData = function (data) {
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._onScrapeResponse = function (data) {
|
||||
var self = this
|
||||
// NOTE: the unofficial spec says to use the 'files' key, 'host' has been
|
||||
// seen in practice
|
||||
data = data.files || data.host || {}
|
||||
|
||||
var keys = Object.keys(data)
|
||||
if (keys.length === 0) {
|
||||
self.client.emit('warning', new Error('invalid scrape response'))
|
||||
return
|
||||
}
|
||||
|
||||
keys.forEach(function (infoHash) {
|
||||
var response = data[infoHash]
|
||||
// TODO: optionally handle data.flags.min_request_interval
|
||||
// (separate from announce interval)
|
||||
self.client.emit('scrape', {
|
||||
announce: self.announceUrl,
|
||||
infoHash: common.binaryToHex(infoHash),
|
||||
complete: response.complete,
|
||||
incomplete: response.incomplete,
|
||||
downloaded: response.downloaded
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
WebSocketTracker.prototype._onSocketClose = function () {
|
||||
var self = this
|
||||
if (self.destroyed) return
|
||||
|
@ -6,33 +6,51 @@ function parseWebSocketRequest (socket, opts, params) {
|
||||
if (!opts) opts = {}
|
||||
params = JSON.parse(params) // may throw
|
||||
|
||||
params.action = common.ACTIONS.ANNOUNCE
|
||||
params.type = 'ws'
|
||||
params.socket = socket
|
||||
if (params.action === 'announce' || params.answer || params.offers) {
|
||||
params.action = common.ACTIONS.ANNOUNCE
|
||||
|
||||
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
||||
throw new Error('invalid info_hash')
|
||||
}
|
||||
params.info_hash = common.binaryToHex(params.info_hash)
|
||||
|
||||
if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) {
|
||||
throw new Error('invalid peer_id')
|
||||
}
|
||||
params.peer_id = common.binaryToHex(params.peer_id)
|
||||
|
||||
if (params.answer) {
|
||||
if (typeof params.to_peer_id !== 'string' || params.to_peer_id.length !== 20) {
|
||||
throw new Error('invalid `to_peer_id` (required with `answer`)')
|
||||
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
||||
throw new Error('invalid info_hash')
|
||||
}
|
||||
params.to_peer_id = common.binaryToHex(params.to_peer_id)
|
||||
}
|
||||
params.info_hash = common.binaryToHex(params.info_hash)
|
||||
|
||||
params.left = Number(params.left) || Infinity
|
||||
params.numwant = Math.min(
|
||||
Number(params.offers && params.offers.length) || 0, // no default - explicit only
|
||||
common.MAX_ANNOUNCE_PEERS
|
||||
)
|
||||
params.compact = -1 // return full peer objects (used for websocket responses)
|
||||
if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) {
|
||||
throw new Error('invalid peer_id')
|
||||
}
|
||||
params.peer_id = common.binaryToHex(params.peer_id)
|
||||
|
||||
if (params.answer) {
|
||||
if (typeof params.to_peer_id !== 'string' || params.to_peer_id.length !== 20) {
|
||||
throw new Error('invalid `to_peer_id` (required with `answer`)')
|
||||
}
|
||||
params.to_peer_id = common.binaryToHex(params.to_peer_id)
|
||||
}
|
||||
|
||||
params.left = Number(params.left) || Infinity
|
||||
params.numwant = Math.min(
|
||||
Number(params.offers && params.offers.length) || 0, // no default - explicit only
|
||||
common.MAX_ANNOUNCE_PEERS
|
||||
)
|
||||
params.compact = -1 // return full peer objects (used for websocket responses)
|
||||
} else if (params.action === 'scrape') {
|
||||
params.action = common.ACTIONS.SCRAPE
|
||||
|
||||
if (typeof params.info_hash === 'string') params.info_hash = [ params.info_hash ]
|
||||
if (Array.isArray(params.info_hash)) {
|
||||
params.info_hash = params.info_hash.map(function (binaryInfoHash) {
|
||||
if (typeof binaryInfoHash !== 'string' || binaryInfoHash.length !== 20) {
|
||||
throw new Error('invalid info_hash')
|
||||
}
|
||||
return common.binaryToHex(binaryInfoHash)
|
||||
})
|
||||
} else {
|
||||
params.info_hash = common.binaryToHex(params.info_hash)
|
||||
}
|
||||
} else {
|
||||
throw new Error('invalid action in WS request: ' + params.action)
|
||||
}
|
||||
|
||||
params.ip = opts.trustProxy
|
||||
? socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress
|
||||
|
12
server.js
12
server.js
@ -327,6 +327,7 @@ Server.prototype._onWebSocketRequest = function (socket, opts, params) {
|
||||
self._onRequest(params, function (err, response) {
|
||||
if (err) {
|
||||
socket.send(JSON.stringify({
|
||||
action: params.action,
|
||||
'failure reason': err.message,
|
||||
info_hash: common.hexToBinary(params.info_hash)
|
||||
}), socket.onSend)
|
||||
@ -336,9 +337,14 @@ Server.prototype._onWebSocketRequest = function (socket, opts, params) {
|
||||
}
|
||||
if (self.destroyed) return
|
||||
|
||||
if (socket.infoHashes.indexOf(params.info_hash) === -1) {
|
||||
socket.infoHashes.push(params.info_hash)
|
||||
}
|
||||
var hashes
|
||||
if (typeof params.info_hash === 'string') hashes = [ params.info_hash ]
|
||||
else hashes = params.info_hash
|
||||
hashes.forEach(function (info_hash) {
|
||||
if (socket.infoHashes.indexOf(info_hash) === -1) {
|
||||
socket.infoHashes.push(info_hash)
|
||||
}
|
||||
})
|
||||
|
||||
var peers = response.peers
|
||||
delete response.peers
|
||||
|
Loading…
Reference in New Issue
Block a user