-
-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support dht.unannounce (do not merge yet) #184
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -394,21 +394,30 @@ DHT.prototype.announce = function (infoHash, port, cb) { | |
if (typeof port === 'function') return this.announce(infoHash, 0, port) | ||
infoHash = toBuffer(infoHash) | ||
if (!cb) cb = noop | ||
this._updatePeer(true, infoHash, port, cb) | ||
} | ||
|
||
DHT.prototype.unannounce = function (infoHash, port, cb) { | ||
if (typeof port === 'function') return this.unannounce(infoHash, 0, port) | ||
infoHash = toBuffer(infoHash) | ||
if (!cb) cb = noop | ||
this._updatePeer(false, infoHash, port, cb) | ||
} | ||
|
||
DHT.prototype._updatePeer = function (announcing, infoHash, port, cb) { | ||
var table = this._tables.get(infoHash.toString('hex')) | ||
if (!table) return this._preannounce(infoHash, port, cb) | ||
if (!table) return this._preUpdatePeer(announcing, infoHash, port, cb) | ||
|
||
if (this._host) { | ||
var dhtPort = this.listening ? this.address().port : 0 | ||
this._addPeer( | ||
{host: this._host, port: port || dhtPort}, | ||
infoHash, | ||
{host: this._host, port: dhtPort} | ||
) | ||
var peer = {host: this._host, port: port || dhtPort} | ||
var from = {host: this._host, port: dhtPort} | ||
if (announcing) this._addPeer(peer, infoHash, from) | ||
else this._removePeer(peer, infoHash, from) | ||
} | ||
|
||
var message = { | ||
q: 'announce_peer', | ||
q: announcing ? 'announce_peer' : 'unannounce_peer', | ||
a: { | ||
id: this._rpc.id, | ||
token: null, // queryAll sets this | ||
|
@@ -418,17 +427,17 @@ DHT.prototype.announce = function (infoHash, port, cb) { | |
} | ||
} | ||
|
||
this._debug('announce %s %d', infoHash, port) | ||
this._debug(announcing ? 'announce %s %d' : 'unannounce %s %d', infoHash, port) | ||
this._rpc.queryAll(table.closest(infoHash), message, null, cb) | ||
} | ||
|
||
DHT.prototype._preannounce = function (infoHash, port, cb) { | ||
DHT.prototype._preUpdatePeer = function (announcing, infoHash, port, cb) { | ||
var self = this | ||
|
||
this.lookup(infoHash, function (err) { | ||
if (self.destroyed) return cb(new Error('dht is destroyed')) | ||
if (err) return cb(err) | ||
self.announce(infoHash, port, cb) | ||
self._updatePeer(announcing, infoHash, port, cb) | ||
}) | ||
} | ||
|
||
|
@@ -510,6 +519,9 @@ DHT.prototype._onquery = function (query, peer) { | |
case 'announce_peer': | ||
return this._onannouncepeer(query, peer) | ||
|
||
case 'unannounce_peer': | ||
return this._onunannouncepeer(query, peer) | ||
|
||
case 'get': | ||
return this._onget(query, peer) | ||
|
||
|
@@ -547,21 +559,51 @@ DHT.prototype._ongetpeers = function (query, peer) { | |
} | ||
|
||
DHT.prototype._onannouncepeer = function (query, peer) { | ||
var req = this._validatePeerUpdate(query, peer) | ||
|
||
if (!req) { | ||
return this._rpc.error(peer, query, [203, 'cannot `announce_peer` with bad token']) | ||
} | ||
|
||
var from = {host: req.host, port: peer.port} | ||
var infoHash = query.a.info_hash | ||
|
||
this.emit('announce_peer', infoHash, from) | ||
this._addPeer(req, infoHash, from) | ||
this._rpc.response(peer, query, {id: this._rpc.id}) | ||
} | ||
|
||
DHT.prototype._onunannouncepeer = function (query, peer) { | ||
var req = this._validatePeerUpdate(query, peer) | ||
|
||
if (!req) { | ||
return this._rpc.error(peer, query, [203, 'cannot `unannounce_peer` with bad token']) | ||
} | ||
|
||
var from = {host: req.host, port: peer.port} | ||
var infoHash = query.a.info_hash | ||
|
||
this.emit('unannounce_peer', infoHash, from) | ||
this._removePeer(req, infoHash, from) | ||
this._rpc.response(peer, query, {id: this._rpc.id}) | ||
} | ||
|
||
DHT.prototype._validatePeerUpdate = function (query, peer) { | ||
var host = peer.address || peer.host | ||
var port = query.a.implied_port ? peer.port : query.a.port | ||
if (!port || typeof port !== 'number' || port <= 0 || port > 65535) return | ||
var infoHash = query.a.info_hash | ||
var token = query.a.token | ||
if (!infoHash || !token) return | ||
|
||
if (!this._validateToken(host, token)) { | ||
return this._rpc.error(peer, query, [203, 'cannot `announce_peer` with bad token']) | ||
} | ||
if (!this._validateToken(host, token)) return null | ||
|
||
this.emit('announce_peer', infoHash, {host: host, port: peer.port}) | ||
return {host: host, port: port} | ||
} | ||
|
||
this._addPeer({host: host, port: port}, infoHash, {host: host, port: peer.port}) | ||
this._rpc.response(peer, query, {id: this._rpc.id}) | ||
DHT.prototype._removePeer = function (peer, infoHash, from) { | ||
this._peers.remove(infoHash.toString('hex'), encodePeer(peer.host, peer.port)) | ||
this.emit('unannounce', peer, infoHash, from) | ||
} | ||
|
||
DHT.prototype._addPeer = function (peer, infoHash, from) { | ||
|
@@ -813,6 +855,18 @@ PeerStore.prototype.add = function (key, peer) { | |
if (++this.used > this.max) this._evict() | ||
} | ||
|
||
PeerStore.prototype.remove = function (key, peer) { | ||
var peers = this.peers.peek(key) | ||
if (!peers) return false | ||
var removed = peers.map.remove(peer.toString('hex')) | ||
if (!removed) return false | ||
this.used-- | ||
swap(peers.values, peers.values.length - 1, removed.index) | ||
peers.values.pop() | ||
if (!peers.values.length) this.peers.remove(key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code looks similar to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ended up writing a new simple module that encapsulates this instead. https://github.com/mafintosh/record-cache. Wanna use this here and get rid of peer store in general |
||
return true | ||
} | ||
|
||
PeerStore.prototype._evict = function () { | ||
var a = this.peers.peek(this.peers.tail) | ||
var b = a.map.remove(a.map.tail) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop
null
to match code above?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It still does the same. Kinda hard to see from the diff. Returning null in here triggers the .error handler in the caller