fix eslint
This commit is contained in:
@ -11,88 +11,88 @@ const config = require('../config')
|
||||
|
||||
class Client extends Emiter
|
||||
{
|
||||
constructor(options) {
|
||||
super();
|
||||
this.timeout = config.downloader.timeout;
|
||||
this.maxConnections = config.downloader.maxConnections;
|
||||
debug('timeout', this.timeout)
|
||||
debug('maxConnections', this.maxConnections)
|
||||
this.activeConnections = 0;
|
||||
this.peers = new PeerQueue(this.maxConnections);
|
||||
this.on('download', this._download);
|
||||
constructor(options) {
|
||||
super();
|
||||
this.timeout = config.downloader.timeout;
|
||||
this.maxConnections = config.downloader.maxConnections;
|
||||
debug('timeout', this.timeout)
|
||||
debug('maxConnections', this.maxConnections)
|
||||
this.activeConnections = 0;
|
||||
this.peers = new PeerQueue(this.maxConnections);
|
||||
this.on('download', this._download);
|
||||
|
||||
// if (typeof options.ignore === 'function') {
|
||||
// this.ignore = options.ignore;
|
||||
//}
|
||||
//else {
|
||||
this.ignore = function (infohash, rinfo, ignore) {
|
||||
ignore(false);
|
||||
};
|
||||
// }
|
||||
}
|
||||
// if (typeof options.ignore === 'function') {
|
||||
// this.ignore = options.ignore;
|
||||
//}
|
||||
//else {
|
||||
this.ignore = function (infohash, rinfo, ignore) {
|
||||
ignore(false);
|
||||
};
|
||||
// }
|
||||
}
|
||||
|
||||
_next(infohash, successful) {
|
||||
var req = this.peers.shift(infohash, successful);
|
||||
if (req) {
|
||||
this.ignore(req.infohash.toString('hex'), req.rinfo, (drop) => {
|
||||
if (!drop) {
|
||||
this.emit('download', req.rinfo, req.infohash);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
_next(infohash, successful) {
|
||||
var req = this.peers.shift(infohash, successful);
|
||||
if (req) {
|
||||
this.ignore(req.infohash.toString('hex'), req.rinfo, (drop) => {
|
||||
if (!drop) {
|
||||
this.emit('download', req.rinfo, req.infohash);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_download(rinfo, infohash)
|
||||
{
|
||||
debug('start download', infohash.toString('hex'), 'connections', this.activeConnections);
|
||||
this.activeConnections++;
|
||||
_download(rinfo, infohash)
|
||||
{
|
||||
debug('start download', infohash.toString('hex'), 'connections', this.activeConnections);
|
||||
this.activeConnections++;
|
||||
|
||||
var successful = false;
|
||||
var socket = new net.Socket();
|
||||
var successful = false;
|
||||
var socket = new net.Socket();
|
||||
|
||||
socket.setTimeout(this.timeout || 5000);
|
||||
socket.connect(rinfo.port, rinfo.address, () => {
|
||||
var wire = new Wire(infohash);
|
||||
socket.pipe(wire).pipe(socket);
|
||||
socket.setTimeout(this.timeout || 5000);
|
||||
socket.connect(rinfo.port, rinfo.address, () => {
|
||||
var wire = new Wire(infohash);
|
||||
socket.pipe(wire).pipe(socket);
|
||||
|
||||
wire.on('metadata', (metadata, infoHash) => {
|
||||
successful = true;
|
||||
debug('successfuly downloader', infoHash, rinfo);
|
||||
this.emit('complete', metadata, infoHash, rinfo);
|
||||
socket.destroy();
|
||||
});
|
||||
wire.on('metadata', (metadata, infoHash) => {
|
||||
successful = true;
|
||||
debug('successfuly downloader', infoHash, rinfo);
|
||||
this.emit('complete', metadata, infoHash, rinfo);
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
wire.on('fail', () => {
|
||||
socket.destroy();
|
||||
});
|
||||
wire.on('fail', () => {
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
wire.sendHandshake();
|
||||
});
|
||||
wire.sendHandshake();
|
||||
});
|
||||
|
||||
socket.on('error', (err) => {
|
||||
socket.destroy();
|
||||
});
|
||||
socket.on('error', (err) => {
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
socket.on('timeout', (err) => {
|
||||
socket.destroy();
|
||||
});
|
||||
socket.on('timeout', (err) => {
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
socket.once('close', () => {
|
||||
this.activeConnections--;
|
||||
this._next(infohash, successful);
|
||||
});
|
||||
}
|
||||
socket.once('close', () => {
|
||||
this.activeConnections--;
|
||||
this._next(infohash, successful);
|
||||
});
|
||||
}
|
||||
|
||||
add(rinfo, infohash) {
|
||||
this.peers.push({infohash: infohash, rinfo: rinfo});
|
||||
if (this.activeConnections < this.maxConnections && this.peers.length() > 0) {
|
||||
this._next();
|
||||
}
|
||||
}
|
||||
add(rinfo, infohash) {
|
||||
this.peers.push({infohash: infohash, rinfo: rinfo});
|
||||
if (this.activeConnections < this.maxConnections && this.peers.length() > 0) {
|
||||
this._next();
|
||||
}
|
||||
}
|
||||
|
||||
isIdle() {
|
||||
return this.peers.length() === 0;
|
||||
}
|
||||
isIdle() {
|
||||
return this.peers.length() === 0;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
@ -8,28 +8,28 @@ let sw = false
|
||||
const cpuTimer = setInterval(() => {
|
||||
if(!sw) {
|
||||
keepTime = process.hrtime();
|
||||
keepUsage = process.cpuUsage();
|
||||
sw = true;
|
||||
keepUsage = process.cpuUsage();
|
||||
sw = true;
|
||||
} else {
|
||||
startTime = keepTime;
|
||||
startUsage = keepUsage;
|
||||
sw = false;
|
||||
}
|
||||
}
|
||||
}, 500)
|
||||
|
||||
cpuTimer.unref()
|
||||
|
||||
module.exports = () => {
|
||||
function secNSec2ms (secNSec) {
|
||||
return secNSec[0] * 1000 + secNSec[1] / 1000000
|
||||
}
|
||||
function secNSec2ms (secNSec) {
|
||||
return secNSec[0] * 1000 + secNSec[1] / 1000000
|
||||
}
|
||||
|
||||
var elapTime = process.hrtime(startTime)
|
||||
var elapUsage = process.cpuUsage(startUsage)
|
||||
var elapTime = process.hrtime(startTime)
|
||||
var elapUsage = process.cpuUsage(startUsage)
|
||||
|
||||
var elapTimeMS = secNSec2ms(elapTime)
|
||||
var elapUserMS = elapUsage.user
|
||||
var elapSystMS = elapUsage.system
|
||||
var elapTimeMS = secNSec2ms(elapTime)
|
||||
var elapUserMS = elapUsage.user
|
||||
var elapSystMS = elapUsage.system
|
||||
|
||||
return Math.round(100 * ((elapUserMS + elapSystMS) / 1000) / elapTimeMS)
|
||||
return Math.round(100 * ((elapUserMS + elapSystMS) / 1000) / elapTimeMS)
|
||||
}
|
@ -1,55 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
var PeerQueue = function (maxSize, perLimit) {
|
||||
this.maxSize = maxSize || 200;
|
||||
this.perLimit = perLimit || 10;
|
||||
this.peers = {};
|
||||
this.reqs = [];
|
||||
this.maxSize = maxSize || 200;
|
||||
this.perLimit = perLimit || 10;
|
||||
this.peers = {};
|
||||
this.reqs = [];
|
||||
};
|
||||
|
||||
PeerQueue.prototype._shift = function () {
|
||||
if (this.length() > 0) {
|
||||
var req = this.reqs.shift();
|
||||
this.peers[req.infohash.toString('hex')] = [];
|
||||
return req;
|
||||
}
|
||||
if (this.length() > 0) {
|
||||
var req = this.reqs.shift();
|
||||
this.peers[req.infohash.toString('hex')] = [];
|
||||
return req;
|
||||
}
|
||||
};
|
||||
|
||||
PeerQueue.prototype.push = function (peer) {
|
||||
var infohashHex = peer.infohash.toString('hex');
|
||||
var peers = this.peers[infohashHex];
|
||||
var infohashHex = peer.infohash.toString('hex');
|
||||
var peers = this.peers[infohashHex];
|
||||
|
||||
if (peers && peers.length < this.perLimit) {
|
||||
peers.push(peer);
|
||||
}
|
||||
else if (this.length() < this.maxSize) {
|
||||
this.reqs.push(peer);
|
||||
}
|
||||
if (peers && peers.length < this.perLimit) {
|
||||
peers.push(peer);
|
||||
}
|
||||
else if (this.length() < this.maxSize) {
|
||||
this.reqs.push(peer);
|
||||
}
|
||||
};
|
||||
|
||||
PeerQueue.prototype.shift = function (infohash, successful) {
|
||||
if (infohash) {
|
||||
var infohashHex = infohash.toString('hex');
|
||||
if (successful === true) {
|
||||
delete this.peers[infohashHex];
|
||||
}
|
||||
else {
|
||||
var peers = this.peers[infohashHex];
|
||||
if (peers) {
|
||||
if (peers.length > 0) {
|
||||
return peers.shift();
|
||||
}
|
||||
else {
|
||||
delete this.peers[infohashHex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._shift();
|
||||
if (infohash) {
|
||||
var infohashHex = infohash.toString('hex');
|
||||
if (successful === true) {
|
||||
delete this.peers[infohashHex];
|
||||
}
|
||||
else {
|
||||
var peers = this.peers[infohashHex];
|
||||
if (peers) {
|
||||
if (peers.length > 0) {
|
||||
return peers.shift();
|
||||
}
|
||||
else {
|
||||
delete this.peers[infohashHex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._shift();
|
||||
};
|
||||
|
||||
PeerQueue.prototype.length = function () {
|
||||
return this.reqs.length;
|
||||
return this.reqs.length;
|
||||
};
|
||||
|
||||
module.exports = PeerQueue;
|
@ -9,312 +9,312 @@ const config = require('../config')
|
||||
const fs = require('fs')
|
||||
|
||||
const bootstraps = [{
|
||||
address: 'router.bittorrent.com',
|
||||
port: 6881
|
||||
address: 'router.bittorrent.com',
|
||||
port: 6881
|
||||
}, {
|
||||
address: 'router.utorrent.com',
|
||||
port: 6881
|
||||
address: 'router.utorrent.com',
|
||||
port: 6881
|
||||
}, {
|
||||
address: 'dht.transmissionbt.com',
|
||||
port: 6881
|
||||
address: 'dht.transmissionbt.com',
|
||||
port: 6881
|
||||
}, {
|
||||
address: 'dht.aelitis.com',
|
||||
port: 6881
|
||||
address: 'dht.aelitis.com',
|
||||
port: 6881
|
||||
}]
|
||||
|
||||
function isValidPort(port) {
|
||||
return port > 0 && port < (1 << 16)
|
||||
return port > 0 && port < (1 << 16)
|
||||
}
|
||||
|
||||
function generateTid() {
|
||||
return parseInt(Math.random() * 99).toString()
|
||||
return parseInt(Math.random() * 99).toString()
|
||||
}
|
||||
|
||||
class Spider extends Emiter {
|
||||
constructor(client) {
|
||||
super()
|
||||
const options = arguments.length? arguments[0]: {}
|
||||
this.table = new Table(options.tableCaption || 1000)
|
||||
this.bootstraps = options.bootstraps || bootstraps
|
||||
this.token = new Token()
|
||||
this.client = client
|
||||
this.ignore = false; // ignore all requests
|
||||
this.initialized = false;
|
||||
constructor(client) {
|
||||
super()
|
||||
const options = arguments.length? arguments[0]: {}
|
||||
this.table = new Table(options.tableCaption || 1000)
|
||||
this.bootstraps = options.bootstraps || bootstraps
|
||||
this.token = new Token()
|
||||
this.client = client
|
||||
this.ignore = false; // ignore all requests
|
||||
this.initialized = false;
|
||||
|
||||
this.walkInterval = config.spider.walkInterval;
|
||||
this.foundSpeed = 0;
|
||||
this.foundCounter = 0;
|
||||
setInterval(() => {
|
||||
this.foundSpeed = this.foundCounter;
|
||||
this.foundCounter = 0;
|
||||
}, 1000)
|
||||
this.walkInterval = config.spider.walkInterval;
|
||||
this.foundSpeed = 0;
|
||||
this.foundCounter = 0;
|
||||
setInterval(() => {
|
||||
this.foundSpeed = this.foundCounter;
|
||||
this.foundCounter = 0;
|
||||
}, 1000)
|
||||
|
||||
this.announceHashes = []
|
||||
}
|
||||
this.announceHashes = []
|
||||
}
|
||||
|
||||
send(message, address) {
|
||||
const data = bencode.encode(message)
|
||||
this.udp.send(data, 0, data.length, address.port, address.address)
|
||||
}
|
||||
send(message, address) {
|
||||
const data = bencode.encode(message)
|
||||
this.udp.send(data, 0, data.length, address.port, address.address)
|
||||
}
|
||||
|
||||
findNode(id, address) {
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'find_node',
|
||||
a: {
|
||||
id: id,
|
||||
target: Node.generateID()
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
findNode(id, address) {
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'find_node',
|
||||
a: {
|
||||
id: id,
|
||||
target: Node.generateID()
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
|
||||
getPeersRequest(infoHash, address) {
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'get_peers',
|
||||
a: {
|
||||
id: this.table.id,
|
||||
info_hash: infoHash
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
getPeersRequest(infoHash, address) {
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'get_peers',
|
||||
a: {
|
||||
id: this.table.id,
|
||||
info_hash: infoHash
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
|
||||
announcePeer(infoHash, token, address, port)
|
||||
{
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'announce_peer',
|
||||
a: {
|
||||
id: this.table.id,
|
||||
token: token,
|
||||
info_hash: infoHash,
|
||||
port: port,
|
||||
implied_port: port ? 0 : 1
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
announcePeer(infoHash, token, address, port)
|
||||
{
|
||||
const message = {
|
||||
t: generateTid(),
|
||||
y: 'q',
|
||||
q: 'announce_peer',
|
||||
a: {
|
||||
id: this.table.id,
|
||||
token: token,
|
||||
info_hash: infoHash,
|
||||
port: port,
|
||||
implied_port: port ? 0 : 1
|
||||
}
|
||||
}
|
||||
this.send(message, address)
|
||||
}
|
||||
|
||||
join() {
|
||||
this.bootstraps.forEach((bootstrap) => {
|
||||
this.findNode(this.table.id, bootstrap)
|
||||
})
|
||||
}
|
||||
join() {
|
||||
this.bootstraps.forEach((bootstrap) => {
|
||||
this.findNode(this.table.id, bootstrap)
|
||||
})
|
||||
}
|
||||
|
||||
walk() {
|
||||
if(this.closing)
|
||||
return
|
||||
walk() {
|
||||
if(this.closing)
|
||||
return
|
||||
|
||||
if(!this.client || this.client.isIdle()) {
|
||||
if(!this.ignore)
|
||||
{
|
||||
const node = this.table.shift()
|
||||
if (node && (config.spider.nodesUsage === 0 || parseInt(Math.random() * this.table.nodes.length / config.spider.nodesUsage) === 0)) {
|
||||
this.findNode(Node.neighbor(node.id, this.table.id), {address: node.address, port: node.port})
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(()=>this.walk(), this.walkInterval)
|
||||
}
|
||||
if(!this.client || this.client.isIdle()) {
|
||||
if(!this.ignore)
|
||||
{
|
||||
const node = this.table.shift()
|
||||
if (node && (config.spider.nodesUsage === 0 || parseInt(Math.random() * this.table.nodes.length / config.spider.nodesUsage) === 0)) {
|
||||
this.findNode(Node.neighbor(node.id, this.table.id), {address: node.address, port: node.port})
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(()=>this.walk(), this.walkInterval)
|
||||
}
|
||||
|
||||
onFoundNodes(data, token, address) {
|
||||
const nodes = Node.decodeNodes(data)
|
||||
nodes.forEach((node) => {
|
||||
if (node.id != this.table.id && isValidPort(node.port)) {
|
||||
this.table.add(node)
|
||||
}
|
||||
})
|
||||
this.emit('nodes', nodes)
|
||||
onFoundNodes(data, token, address) {
|
||||
const nodes = Node.decodeNodes(data)
|
||||
nodes.forEach((node) => {
|
||||
if (node.id != this.table.id && isValidPort(node.port)) {
|
||||
this.table.add(node)
|
||||
}
|
||||
})
|
||||
this.emit('nodes', nodes)
|
||||
|
||||
// announce torrents
|
||||
if(token)
|
||||
{
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.announcePeer(hash, token, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
// announce torrents
|
||||
if(token)
|
||||
{
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.announcePeer(hash, token, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFoundPeers(peers, token, address) {
|
||||
if(token)
|
||||
{
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.announcePeer(hash, token, address)
|
||||
}
|
||||
}
|
||||
onFoundPeers(peers, token, address) {
|
||||
if(token)
|
||||
{
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.announcePeer(hash, token, address)
|
||||
}
|
||||
}
|
||||
|
||||
if(!peers || peers.length == 0)
|
||||
return;
|
||||
if(!peers || peers.length == 0)
|
||||
return;
|
||||
|
||||
const ips = Node.decodeCompactIP(peers)
|
||||
this.emit('peer', ips)
|
||||
}
|
||||
const ips = Node.decodeCompactIP(peers)
|
||||
this.emit('peer', ips)
|
||||
}
|
||||
|
||||
onFindNodeRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
onFindNodeRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
const {t: tid, a: {id: nid, target: infohash}} = message
|
||||
const {t: tid, a: {id: nid, target: infohash}} = message
|
||||
|
||||
if (tid === undefined || target.length != 20 || nid.length != 20) {
|
||||
return
|
||||
}
|
||||
if (tid === undefined || target.length != 20 || nid.length != 20) {
|
||||
return
|
||||
}
|
||||
|
||||
this.send({
|
||||
t: tid,
|
||||
y: 'r',
|
||||
r: {
|
||||
id: Node.neighbor(nid, this.table.id),
|
||||
nodes: Node.encodeNodes(this.table.first())
|
||||
}
|
||||
}, address)
|
||||
this.send({
|
||||
t: tid,
|
||||
y: 'r',
|
||||
r: {
|
||||
id: Node.neighbor(nid, this.table.id),
|
||||
nodes: Node.encodeNodes(this.table.first())
|
||||
}
|
||||
}, address)
|
||||
|
||||
// also check hashes of alive ones
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.getPeersRequest(hash, address)
|
||||
}
|
||||
}
|
||||
// also check hashes of alive ones
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.getPeersRequest(hash, address)
|
||||
}
|
||||
}
|
||||
|
||||
onGetPeersRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
onGetPeersRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
const {t: tid, a: {id: nid, info_hash: infohash}} = message
|
||||
const {t: tid, a: {id: nid, info_hash: infohash}} = message
|
||||
|
||||
if (tid === undefined || infohash.length != 20 || nid.length != 20) {
|
||||
return
|
||||
}
|
||||
if (tid === undefined || infohash.length != 20 || nid.length != 20) {
|
||||
return
|
||||
}
|
||||
|
||||
this.send({
|
||||
t: tid,
|
||||
y: 'r',
|
||||
r: {
|
||||
id: Node.neighbor(nid, this.table.id),
|
||||
nodes: Node.encodeNodes(this.table.first()),
|
||||
token: this.token.token
|
||||
}
|
||||
}, address)
|
||||
this.send({
|
||||
t: tid,
|
||||
y: 'r',
|
||||
r: {
|
||||
id: Node.neighbor(nid, this.table.id),
|
||||
nodes: Node.encodeNodes(this.table.first()),
|
||||
token: this.token.token
|
||||
}
|
||||
}, address)
|
||||
|
||||
this.emit('unensureHash', infohash.toString('hex').toUpperCase())
|
||||
this.emit('unensureHash', infohash.toString('hex').toUpperCase())
|
||||
|
||||
// also check hashes of alive ones
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.getPeersRequest(hash, address)
|
||||
}
|
||||
}
|
||||
// also check hashes of alive ones
|
||||
for(const hash of this.announceHashes)
|
||||
{
|
||||
this.getPeersRequest(hash, address)
|
||||
}
|
||||
}
|
||||
|
||||
onAnnouncePeerRequest(message, address) {
|
||||
let {t: tid, a: {info_hash: infohash, token: token, id: id, implied_port: implied, port: port}} = message
|
||||
if (!tid) return
|
||||
onAnnouncePeerRequest(message, address) {
|
||||
let {t: tid, a: {info_hash: infohash, token: token, id: id, implied_port: implied, port: port}} = message
|
||||
if (!tid) return
|
||||
|
||||
if (!this.token.isValid(token)) return
|
||||
if (!this.token.isValid(token)) return
|
||||
|
||||
port = (implied != undefined && implied != 0) ? address.port : (port || 0)
|
||||
if (!isValidPort(port)) return
|
||||
port = (implied != undefined && implied != 0) ? address.port : (port || 0)
|
||||
if (!isValidPort(port)) return
|
||||
|
||||
this.send({ t: tid, y: 'r', r: { id: Node.neighbor(id, this.table.id) } }, address)
|
||||
this.send({ t: tid, y: 'r', r: { id: Node.neighbor(id, this.table.id) } }, address)
|
||||
|
||||
let addressPair = {
|
||||
address: address.address,
|
||||
port: port
|
||||
};
|
||||
this.emit('ensureHash', infohash.toString('hex').toUpperCase(), addressPair)
|
||||
if(this.client && !this.ignore) {
|
||||
this.client.add(addressPair, infohash);
|
||||
}
|
||||
}
|
||||
let addressPair = {
|
||||
address: address.address,
|
||||
port: port
|
||||
};
|
||||
this.emit('ensureHash', infohash.toString('hex').toUpperCase(), addressPair)
|
||||
if(this.client && !this.ignore) {
|
||||
this.client.add(addressPair, infohash);
|
||||
}
|
||||
}
|
||||
|
||||
onPingRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
onPingRequest(message, address) {
|
||||
if(config.spider.packagesLimit !== 0 && this.foundSpeed > config.spider.packagesLimit)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
this.send({ t: message.t, y: 'r', r: { id: Node.neighbor(message.a.id, this.table.id) } }, address)
|
||||
}
|
||||
this.send({ t: message.t, y: 'r', r: { id: Node.neighbor(message.a.id, this.table.id) } }, address)
|
||||
}
|
||||
|
||||
parse(data, address) {
|
||||
try {
|
||||
const message = bencode.decode(data)
|
||||
if (message.y.toString() == 'r') {
|
||||
if(message.r.nodes) {
|
||||
this.foundCounter++;
|
||||
this.onFoundNodes(message.r.nodes, message.r.token, address)
|
||||
} else if(message.r.values) {
|
||||
this.onFoundPeers(message.r.values, message.r.token, address)
|
||||
}
|
||||
} else if (message.y.toString() == 'q') {
|
||||
this.foundCounter++;
|
||||
switch(message.q.toString()) {
|
||||
case 'get_peers':
|
||||
this.onGetPeersRequest(message, address)
|
||||
break
|
||||
case 'announce_peer':
|
||||
this.onAnnouncePeerRequest(message, address)
|
||||
break
|
||||
case 'find_node':
|
||||
this.onFindNodeRequest(message, address)
|
||||
break
|
||||
case 'ping':
|
||||
this.onPingRequest(message, address)
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
parse(data, address) {
|
||||
try {
|
||||
const message = bencode.decode(data)
|
||||
if (message.y.toString() == 'r') {
|
||||
if(message.r.nodes) {
|
||||
this.foundCounter++;
|
||||
this.onFoundNodes(message.r.nodes, message.r.token, address)
|
||||
} else if(message.r.values) {
|
||||
this.onFoundPeers(message.r.values, message.r.token, address)
|
||||
}
|
||||
} else if (message.y.toString() == 'q') {
|
||||
this.foundCounter++;
|
||||
switch(message.q.toString()) {
|
||||
case 'get_peers':
|
||||
this.onGetPeersRequest(message, address)
|
||||
break
|
||||
case 'announce_peer':
|
||||
this.onAnnouncePeerRequest(message, address)
|
||||
break
|
||||
case 'find_node':
|
||||
this.onFindNodeRequest(message, address)
|
||||
break
|
||||
case 'ping':
|
||||
this.onPingRequest(message, address)
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
listen(port) {
|
||||
if(this.initialized)
|
||||
return
|
||||
this.initialized = true
|
||||
listen(port) {
|
||||
if(this.initialized)
|
||||
return
|
||||
this.initialized = true
|
||||
|
||||
this.closing = false
|
||||
this.udp = dgram.createSocket('udp4')
|
||||
this.udp.bind(port)
|
||||
this.udp.on('listening', () => {
|
||||
console.log(`Listen DHT protocol on ${this.udp.address().address}:${this.udp.address().port}`)
|
||||
})
|
||||
this.udp.on('message', (data, addr) => {
|
||||
this.parse(data, addr)
|
||||
})
|
||||
this.udp.on('error', (err) => {})
|
||||
this.joinInterval = setInterval(() => {
|
||||
if(!this.client || this.client.isIdle()) {
|
||||
this.join()
|
||||
}
|
||||
}, 3000)
|
||||
this.join()
|
||||
this.walk()
|
||||
}
|
||||
this.closing = false
|
||||
this.udp = dgram.createSocket('udp4')
|
||||
this.udp.bind(port)
|
||||
this.udp.on('listening', () => {
|
||||
console.log(`Listen DHT protocol on ${this.udp.address().address}:${this.udp.address().port}`)
|
||||
})
|
||||
this.udp.on('message', (data, addr) => {
|
||||
this.parse(data, addr)
|
||||
})
|
||||
this.udp.on('error', (err) => {})
|
||||
this.joinInterval = setInterval(() => {
|
||||
if(!this.client || this.client.isIdle()) {
|
||||
this.join()
|
||||
}
|
||||
}, 3000)
|
||||
this.join()
|
||||
this.walk()
|
||||
}
|
||||
|
||||
close(callback)
|
||||
{
|
||||
if(!this.initialized) {
|
||||
if(callback)
|
||||
callback()
|
||||
return
|
||||
}
|
||||
clearInterval(this.joinInterval)
|
||||
this.closing = true
|
||||
this.udp.close(() => {
|
||||
this.initialized = false
|
||||
if(callback)
|
||||
callback()
|
||||
})
|
||||
}
|
||||
close(callback)
|
||||
{
|
||||
if(!this.initialized) {
|
||||
if(callback)
|
||||
callback()
|
||||
return
|
||||
}
|
||||
clearInterval(this.joinInterval)
|
||||
this.closing = true
|
||||
this.udp.close(() => {
|
||||
this.initialized = false
|
||||
if(callback)
|
||||
callback()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Spider
|
@ -13,119 +13,119 @@ const connectionIdLow = 0x27101980
|
||||
const requests = {};
|
||||
|
||||
let message = function (buf, host, port) {
|
||||
server.send(buf, 0, buf.length, port, host, function(err, bytes) {
|
||||
if (err) {
|
||||
console.log(err.message);
|
||||
}
|
||||
});
|
||||
server.send(buf, 0, buf.length, port, host, function(err, bytes) {
|
||||
if (err) {
|
||||
console.log(err.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let connectTracker = function(connection) {
|
||||
debug('start screape connection');
|
||||
let buffer = new Buffer(16);
|
||||
debug('start screape connection');
|
||||
let buffer = new Buffer(16);
|
||||
|
||||
const transactionId = Math.floor((Math.random()*100000)+1);
|
||||
const transactionId = Math.floor((Math.random()*100000)+1);
|
||||
|
||||
buffer.fill(0);
|
||||
buffer.fill(0);
|
||||
|
||||
buffer.writeUInt32BE(connectionIdHigh, 0);
|
||||
buffer.writeUInt32BE(connectionIdLow, 4);
|
||||
buffer.writeUInt32BE(ACTION_CONNECT, 8);
|
||||
buffer.writeUInt32BE(transactionId, 12);
|
||||
buffer.writeUInt32BE(connectionIdHigh, 0);
|
||||
buffer.writeUInt32BE(connectionIdLow, 4);
|
||||
buffer.writeUInt32BE(ACTION_CONNECT, 8);
|
||||
buffer.writeUInt32BE(transactionId, 12);
|
||||
|
||||
// очистка старых соединений
|
||||
for(const transaction in requests) {
|
||||
if((new Date).getTime() - requests[transaction].date.getTime() > config.udpTrackersTimeout) {
|
||||
delete requests[transaction];
|
||||
}
|
||||
}
|
||||
// очистка старых соединений
|
||||
for(const transaction in requests) {
|
||||
if((new Date).getTime() - requests[transaction].date.getTime() > config.udpTrackersTimeout) {
|
||||
delete requests[transaction];
|
||||
}
|
||||
}
|
||||
|
||||
requests[transactionId] = connection;
|
||||
message(buffer, connection.host, connection.port);
|
||||
requests[transactionId] = connection;
|
||||
message(buffer, connection.host, connection.port);
|
||||
};
|
||||
|
||||
let scrapeTorrent = function (connectionIdHigh, connectionIdLow, transactionId) {
|
||||
let connection = requests[transactionId];
|
||||
if(!connection)
|
||||
return;
|
||||
let connection = requests[transactionId];
|
||||
if(!connection)
|
||||
return;
|
||||
|
||||
if(!connection.hash || connection.hash.length != 40)
|
||||
return
|
||||
if(!connection.hash || connection.hash.length != 40)
|
||||
return
|
||||
|
||||
debug('start scrape');
|
||||
let buffer = new Buffer(56)
|
||||
debug('start scrape');
|
||||
let buffer = new Buffer(56)
|
||||
|
||||
buffer.fill(0);
|
||||
buffer.fill(0);
|
||||
|
||||
buffer.writeUInt32BE(connectionIdHigh, 0);
|
||||
buffer.writeUInt32BE(connectionIdLow, 4);
|
||||
buffer.writeUInt32BE(ACTION_SCRAPE, 8);
|
||||
buffer.writeUInt32BE(transactionId, 12);
|
||||
buffer.writeUInt32BE(connectionIdHigh, 0);
|
||||
buffer.writeUInt32BE(connectionIdLow, 4);
|
||||
buffer.writeUInt32BE(ACTION_SCRAPE, 8);
|
||||
buffer.writeUInt32BE(transactionId, 12);
|
||||
|
||||
try
|
||||
{
|
||||
buffer.write(connection.hash, 16, buffer.length, 'hex');
|
||||
// do scrape
|
||||
message(buffer, connection.host, connection.port);
|
||||
} catch(error)
|
||||
{
|
||||
console.log('ERROR on scrape', error)
|
||||
}
|
||||
try
|
||||
{
|
||||
buffer.write(connection.hash, 16, buffer.length, 'hex');
|
||||
// do scrape
|
||||
message(buffer, connection.host, connection.port);
|
||||
} catch(error)
|
||||
{
|
||||
console.log('ERROR on scrape', error)
|
||||
}
|
||||
};
|
||||
|
||||
server.on("message", function (msg, rinfo) {
|
||||
let buffer = new Buffer(msg)
|
||||
let buffer = new Buffer(msg)
|
||||
|
||||
const action = buffer.readUInt32BE(0, 4);
|
||||
const transactionId = buffer.readUInt32BE(4, 4);
|
||||
const action = buffer.readUInt32BE(0, 4);
|
||||
const transactionId = buffer.readUInt32BE(4, 4);
|
||||
|
||||
if(!(transactionId in requests))
|
||||
return;
|
||||
if(!(transactionId in requests))
|
||||
return;
|
||||
|
||||
debug("returned action: " + action);
|
||||
debug("returned transactionId: " + transactionId);
|
||||
debug("returned action: " + action);
|
||||
debug("returned transactionId: " + transactionId);
|
||||
|
||||
if (action === ACTION_CONNECT) {
|
||||
debug("connect response");
|
||||
if (action === ACTION_CONNECT) {
|
||||
debug("connect response");
|
||||
|
||||
let connectionIdHigh = buffer.readUInt32BE(8, 4);
|
||||
let connectionIdLow = buffer.readUInt32BE(12, 4);
|
||||
let connectionIdHigh = buffer.readUInt32BE(8, 4);
|
||||
let connectionIdLow = buffer.readUInt32BE(12, 4);
|
||||
|
||||
scrapeTorrent(connectionIdHigh, connectionIdLow, transactionId);
|
||||
scrapeTorrent(connectionIdHigh, connectionIdLow, transactionId);
|
||||
|
||||
} else if (action === ACTION_SCRAPE) {
|
||||
debug("scrape response");
|
||||
} else if (action === ACTION_SCRAPE) {
|
||||
debug("scrape response");
|
||||
|
||||
let seeders = buffer.readUInt32BE(8, 4);
|
||||
let completed = buffer.readUInt32BE(12, 4);
|
||||
let leechers = buffer.readUInt32BE(16, 4);
|
||||
let seeders = buffer.readUInt32BE(8, 4);
|
||||
let completed = buffer.readUInt32BE(12, 4);
|
||||
let leechers = buffer.readUInt32BE(16, 4);
|
||||
|
||||
let connection = requests[transactionId];
|
||||
connection.callback({
|
||||
host: connection.host,
|
||||
port: connection.port,
|
||||
hash: connection.hash,
|
||||
seeders,
|
||||
completed,
|
||||
leechers
|
||||
})
|
||||
delete requests[transactionId];
|
||||
} else if (action === ACTION_ERROR) {
|
||||
delete requests[transactionId];
|
||||
console.log("error in scrape response");
|
||||
}
|
||||
let connection = requests[transactionId];
|
||||
connection.callback({
|
||||
host: connection.host,
|
||||
port: connection.port,
|
||||
hash: connection.hash,
|
||||
seeders,
|
||||
completed,
|
||||
leechers
|
||||
})
|
||||
delete requests[transactionId];
|
||||
} else if (action === ACTION_ERROR) {
|
||||
delete requests[transactionId];
|
||||
console.log("error in scrape response");
|
||||
}
|
||||
});
|
||||
|
||||
let getPeersStatistic = (host, port, hash, callback) => {
|
||||
let connection = {
|
||||
host, port, hash, callback, date: new Date()
|
||||
}
|
||||
connectTracker(connection);
|
||||
let connection = {
|
||||
host, port, hash, callback, date: new Date()
|
||||
}
|
||||
connectTracker(connection);
|
||||
}
|
||||
|
||||
server.on("listening", function () {
|
||||
var address = server.address();
|
||||
console.log("listening udp tracker respose on " + address.address + ":" + address.port);
|
||||
var address = server.address();
|
||||
console.log("listening udp tracker respose on " + address.address + ":" + address.port);
|
||||
});
|
||||
|
||||
server.bind(config.udpTrackersPort);
|
||||
|
@ -18,230 +18,230 @@ var EXT_HANDSHAKE_ID = 0;
|
||||
var BT_MSG_ID = 20;
|
||||
|
||||
var Wire = function(infohash) {
|
||||
stream.Duplex.call(this);
|
||||
stream.Duplex.call(this);
|
||||
|
||||
this._bitfield = new BitField(0, { grow: BITFIELD_GROW });
|
||||
this._infohash = infohash;
|
||||
this._bitfield = new BitField(0, { grow: BITFIELD_GROW });
|
||||
this._infohash = infohash;
|
||||
|
||||
this._buffer = [];
|
||||
this._bufferSize = 0;
|
||||
this._buffer = [];
|
||||
this._bufferSize = 0;
|
||||
|
||||
this._next = null;
|
||||
this._nextSize = 0;
|
||||
this._next = null;
|
||||
this._nextSize = 0;
|
||||
|
||||
this._metadata = null;
|
||||
this._metadataSize = null;
|
||||
this._numPieces = 0;
|
||||
this._ut_metadata = null;
|
||||
this._metadata = null;
|
||||
this._metadataSize = null;
|
||||
this._numPieces = 0;
|
||||
this._ut_metadata = null;
|
||||
|
||||
this._onHandshake();
|
||||
this._onHandshake();
|
||||
}
|
||||
|
||||
util.inherits(Wire, stream.Duplex);
|
||||
|
||||
Wire.prototype._onMessageLength = function (buffer) {
|
||||
if (buffer.length >= 4) {
|
||||
var length = buffer.readUInt32BE(0);
|
||||
if (length > 0) {
|
||||
this._register(length, this._onMessage)
|
||||
}
|
||||
}
|
||||
if (buffer.length >= 4) {
|
||||
var length = buffer.readUInt32BE(0);
|
||||
if (length > 0) {
|
||||
this._register(length, this._onMessage)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Wire.prototype._onMessage = function (buffer) {
|
||||
this._register(4, this._onMessageLength)
|
||||
if (buffer[0] == BT_MSG_ID) {
|
||||
this._onExtended(buffer.readUInt8(1), buffer.slice(2));
|
||||
}
|
||||
this._register(4, this._onMessageLength)
|
||||
if (buffer[0] == BT_MSG_ID) {
|
||||
this._onExtended(buffer.readUInt8(1), buffer.slice(2));
|
||||
}
|
||||
};
|
||||
|
||||
Wire.prototype._onExtended = function(ext, buf) {
|
||||
if (ext === 0) {
|
||||
try {
|
||||
this._onExtHandshake(bencode.decode(buf));
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._onPiece(buf);
|
||||
}
|
||||
if (ext === 0) {
|
||||
try {
|
||||
this._onExtHandshake(bencode.decode(buf));
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._onPiece(buf);
|
||||
}
|
||||
};
|
||||
|
||||
Wire.prototype._register = function (size, next) {
|
||||
this._nextSize = size;
|
||||
this._next = next;
|
||||
this._nextSize = size;
|
||||
this._next = next;
|
||||
};
|
||||
|
||||
Wire.prototype.end = function() {
|
||||
stream.Duplex.prototype.end.apply(this, arguments);
|
||||
stream.Duplex.prototype.end.apply(this, arguments);
|
||||
};
|
||||
|
||||
Wire.prototype._onHandshake = function() {
|
||||
this._register(1, function(buffer) {
|
||||
if (buffer.length == 0) {
|
||||
this.end();
|
||||
return this._fail();
|
||||
}
|
||||
var pstrlen = buffer.readUInt8(0);
|
||||
this._register(pstrlen + 48, function(handshake) {
|
||||
var protocol = handshake.slice(0, pstrlen);
|
||||
if (protocol.toString() !== BT_PROTOCOL.toString()) {
|
||||
this.end();
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
handshake = handshake.slice(pstrlen);
|
||||
if ( !!(handshake[5] & 0x10) ) {
|
||||
this._register(4, this._onMessageLength);
|
||||
this._sendExtHandshake();
|
||||
}
|
||||
else {
|
||||
this._fail();
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
this._register(1, function(buffer) {
|
||||
if (buffer.length == 0) {
|
||||
this.end();
|
||||
return this._fail();
|
||||
}
|
||||
var pstrlen = buffer.readUInt8(0);
|
||||
this._register(pstrlen + 48, function(handshake) {
|
||||
var protocol = handshake.slice(0, pstrlen);
|
||||
if (protocol.toString() !== BT_PROTOCOL.toString()) {
|
||||
this.end();
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
handshake = handshake.slice(pstrlen);
|
||||
if ( !!(handshake[5] & 0x10) ) {
|
||||
this._register(4, this._onMessageLength);
|
||||
this._sendExtHandshake();
|
||||
}
|
||||
else {
|
||||
this._fail();
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Wire.prototype._onExtHandshake = function(extHandshake) {
|
||||
if (!extHandshake.metadata_size || !extHandshake.m.ut_metadata
|
||||
if (!extHandshake.metadata_size || !extHandshake.m.ut_metadata
|
||||
|| extHandshake.metadata_size > MAX_METADATA_SIZE) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
|
||||
this._metadataSize = extHandshake.metadata_size;
|
||||
this._numPieces = Math.ceil(this._metadataSize / PIECE_LENGTH);
|
||||
this._ut_metadata = extHandshake.m.ut_metadata;
|
||||
this._metadataSize = extHandshake.metadata_size;
|
||||
this._numPieces = Math.ceil(this._metadataSize / PIECE_LENGTH);
|
||||
this._ut_metadata = extHandshake.m.ut_metadata;
|
||||
|
||||
this._requestPieces();
|
||||
this._requestPieces();
|
||||
}
|
||||
|
||||
Wire.prototype._requestPieces = function() {
|
||||
this._metadata = new Buffer(this._metadataSize);
|
||||
for (var piece = 0; piece < this._numPieces; piece++) {
|
||||
this._requestPiece(piece);
|
||||
}
|
||||
this._metadata = new Buffer(this._metadataSize);
|
||||
for (var piece = 0; piece < this._numPieces; piece++) {
|
||||
this._requestPiece(piece);
|
||||
}
|
||||
};
|
||||
|
||||
Wire.prototype._requestPiece = function(piece) {
|
||||
var msg = Buffer.concat([
|
||||
new Buffer([BT_MSG_ID]),
|
||||
new Buffer([this._ut_metadata]),
|
||||
bencode.encode({msg_type: 0, piece: piece})
|
||||
]);
|
||||
this._sendMessage(msg);
|
||||
var msg = Buffer.concat([
|
||||
new Buffer([BT_MSG_ID]),
|
||||
new Buffer([this._ut_metadata]),
|
||||
bencode.encode({msg_type: 0, piece: piece})
|
||||
]);
|
||||
this._sendMessage(msg);
|
||||
};
|
||||
|
||||
Wire.prototype._sendPacket = function(packet) {
|
||||
this.push(packet);
|
||||
this.push(packet);
|
||||
};
|
||||
|
||||
Wire.prototype._sendMessage = function(msg) {
|
||||
var buf = new Buffer(4);
|
||||
buf.writeUInt32BE(msg.length, 0);
|
||||
this._sendPacket(Buffer.concat([buf, msg]));
|
||||
var buf = new Buffer(4);
|
||||
buf.writeUInt32BE(msg.length, 0);
|
||||
this._sendPacket(Buffer.concat([buf, msg]));
|
||||
};
|
||||
|
||||
Wire.prototype.sendHandshake = function() {
|
||||
var peerID = Node.generateID();
|
||||
var packet = Buffer.concat([
|
||||
new Buffer([BT_PROTOCOL.length]),
|
||||
BT_PROTOCOL, BT_RESERVED, this._infohash, peerID
|
||||
]);
|
||||
this._sendPacket(packet);
|
||||
var peerID = Node.generateID();
|
||||
var packet = Buffer.concat([
|
||||
new Buffer([BT_PROTOCOL.length]),
|
||||
BT_PROTOCOL, BT_RESERVED, this._infohash, peerID
|
||||
]);
|
||||
this._sendPacket(packet);
|
||||
};
|
||||
|
||||
Wire.prototype._sendExtHandshake = function() {
|
||||
var msg = Buffer.concat([
|
||||
new Buffer([BT_MSG_ID]),
|
||||
new Buffer([EXT_HANDSHAKE_ID]),
|
||||
bencode.encode({m: {ut_metadata: 1}})
|
||||
]);
|
||||
this._sendMessage(msg);
|
||||
var msg = Buffer.concat([
|
||||
new Buffer([BT_MSG_ID]),
|
||||
new Buffer([EXT_HANDSHAKE_ID]),
|
||||
bencode.encode({m: {ut_metadata: 1}})
|
||||
]);
|
||||
this._sendMessage(msg);
|
||||
};
|
||||
|
||||
Wire.prototype._onPiece = function(piece) {
|
||||
var dict, trailer;
|
||||
try {
|
||||
var str = piece.toString();
|
||||
var trailerIndex = str.indexOf('ee') + 2;
|
||||
dict = bencode.decode(str.substring(0, trailerIndex));
|
||||
trailer = piece.slice(trailerIndex);
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
if (dict.msg_type != 1) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
if (trailer.length > PIECE_LENGTH) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
trailer.copy(this._metadata, dict.piece * PIECE_LENGTH);
|
||||
this._bitfield.set(dict.piece);
|
||||
this._checkDone();
|
||||
var dict, trailer;
|
||||
try {
|
||||
var str = piece.toString();
|
||||
var trailerIndex = str.indexOf('ee') + 2;
|
||||
dict = bencode.decode(str.substring(0, trailerIndex));
|
||||
trailer = piece.slice(trailerIndex);
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
if (dict.msg_type != 1) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
if (trailer.length > PIECE_LENGTH) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
trailer.copy(this._metadata, dict.piece * PIECE_LENGTH);
|
||||
this._bitfield.set(dict.piece);
|
||||
this._checkDone();
|
||||
};
|
||||
|
||||
Wire.prototype._checkDone = function () {
|
||||
var done = true;
|
||||
for (var piece = 0; piece < this._numPieces; piece++) {
|
||||
if (!this._bitfield.get(piece)) {
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
return
|
||||
}
|
||||
this._onDone(this._metadata);
|
||||
var done = true;
|
||||
for (var piece = 0; piece < this._numPieces; piece++) {
|
||||
if (!this._bitfield.get(piece)) {
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
return
|
||||
}
|
||||
this._onDone(this._metadata);
|
||||
};
|
||||
|
||||
Wire.prototype._onDone = function(metadata) {
|
||||
try {
|
||||
var info = bencode.decode(metadata).info;
|
||||
if (info) {
|
||||
metadata = bencode.encode(info);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
var infohash = crypto.createHash('sha1').update(metadata).digest('hex');
|
||||
if (this._infohash.toString('hex') != infohash ) {
|
||||
this._fail();
|
||||
return false;
|
||||
}
|
||||
this.emit('metadata', {info: bencode.decode(metadata, 'utf8')}, this._infohash);
|
||||
try {
|
||||
var info = bencode.decode(metadata).info;
|
||||
if (info) {
|
||||
metadata = bencode.encode(info);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this._fail();
|
||||
return;
|
||||
}
|
||||
var infohash = crypto.createHash('sha1').update(metadata).digest('hex');
|
||||
if (this._infohash.toString('hex') != infohash ) {
|
||||
this._fail();
|
||||
return false;
|
||||
}
|
||||
this.emit('metadata', {info: bencode.decode(metadata, 'utf8')}, this._infohash);
|
||||
};
|
||||
|
||||
Wire.prototype._fail = function() {
|
||||
this.emit('fail');
|
||||
this.emit('fail');
|
||||
};
|
||||
|
||||
Wire.prototype._write = function (buf, encoding, next) {
|
||||
this._bufferSize += buf.length;
|
||||
this._buffer.push(buf);
|
||||
this._bufferSize += buf.length;
|
||||
this._buffer.push(buf);
|
||||
|
||||
while (this._bufferSize >= this._nextSize) {
|
||||
var buffer = Buffer.concat(this._buffer);
|
||||
this._bufferSize -= this._nextSize;
|
||||
this._buffer = this._bufferSize
|
||||
? [buffer.slice(this._nextSize)]
|
||||
: [];
|
||||
this._next(buffer.slice(0, this._nextSize));
|
||||
}
|
||||
while (this._bufferSize >= this._nextSize) {
|
||||
var buffer = Buffer.concat(this._buffer);
|
||||
this._bufferSize -= this._nextSize;
|
||||
this._buffer = this._bufferSize
|
||||
? [buffer.slice(this._nextSize)]
|
||||
: [];
|
||||
this._next(buffer.slice(0, this._nextSize));
|
||||
}
|
||||
|
||||
next(null);
|
||||
next(null);
|
||||
}
|
||||
|
||||
Wire.prototype._read = function() {
|
||||
// do nothing
|
||||
// do nothing
|
||||
};
|
||||
|
||||
module.exports = Wire;
|
||||
|
Reference in New Issue
Block a user