-
Notifications
You must be signed in to change notification settings - Fork 10
/
dht.js
65 lines (50 loc) · 1.8 KB
/
dht.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
module.exports = DHT
function DHT(peers, hash = djb){
this.ring = emitterify(new RBTree((a, b) => (a.hash - b.hash)))
this.vnodes = {}
this.hash = hash
this.peers = peers
peers.cache
.on('status', (status, peer) => status == 'connected'
? this.insert(peer)
: this.remove(peer)
)
if (peers.me)
this.insert(peers.me)
}
DHT.prototype.lookup = function(key){
return (this.ring.lowerBound({ hash: this.hash(key || '') }).next() || this.ring.min() || {}).peer
}
DHT.prototype.insert = function(peer){
if (peer.id in this.vnodes) return
this.vnodes[peer.id] = []
this.vnodes[peer.id].peer = peer
for (let i = 0, hash; i < this.peers.constants.dht.vnodes; i++) {
this.vnodes[peer.id].push(hash = this.hash(peer.id + '*' + i))
this.ring.insert({ peer, hash })
}
this.checksum = checksum(this.vnodes, this.hash)
this.peers.cache.emit('checksum', this.checksum)
deb('insert', peer.id, this.ring.size/this.peers.constants.dht.vnodes, this.checksum, peer.uuid.bgRed)
}
DHT.prototype.remove = function(peer) {
const vnodes = this.vnodes[peer.id]
if (!vnodes || vnodes.peer !== peer) return
for (let i = 0; i < vnodes.length; i++)
this.ring.remove({ hash: vnodes[i] })
delete this.vnodes[peer.id]
this.checksum = checksum(this.vnodes, this.hash)
this.peers.cache.emit('checksum', this.checksum)
deb('remove', peer.id, this.ring.size/this.peers.constants.dht.vnodes, this.checksum, peer.uuid.bgRed)
}
const checksum = (vnodes, hash) => hash(keys(vnodes).sort().join(';'))
const djb = str => {
let hash = 5381
, i = str.length
while (i)
hash = (hash * 33) ^ str.charCodeAt(--i)
return hash >>> 0
}
const { RBTree } = require('bintrees')
, { emitterify, keys } = require('utilise/pure')
, deb = require('./deb')('rin'.bgBlue.bold)