-
Notifications
You must be signed in to change notification settings - Fork 772
/
kbucket.ts
79 lines (64 loc) · 2.25 KB
/
kbucket.ts
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { bytesToUnprefixedHex } from '@ethereumjs/util'
import { EventEmitter } from 'eventemitter3'
import { KBucket as _KBucket } from '../ext/index.js'
import type { PeerInfo } from '../types.js'
const KBUCKET_SIZE = 16
const KBUCKET_CONCURRENCY = 3
export class KBucket {
public events: EventEmitter
protected _peers: Map<string, PeerInfo> = new Map()
protected _kbucket: _KBucket
constructor(localNodeId: Uint8Array) {
this.events = new EventEmitter()
this._kbucket = new _KBucket({
localNodeId,
numberOfNodesPerKBucket: KBUCKET_SIZE,
numberOfNodesToPing: KBUCKET_CONCURRENCY,
})
this._kbucket.events.on('added', (peer: PeerInfo) => {
for (const key of KBucket.getKeys(peer)) {
this._peers.set(key, peer)
}
this.events.emit('added', peer)
})
this._kbucket.events.on('removed', (peer: PeerInfo) => {
for (const key of KBucket.getKeys(peer)) {
this._peers.delete(key)
}
this.events.emit('removed', peer)
})
this._kbucket.events.on('ping', (oldPeers: PeerInfo[], newPeer: PeerInfo | undefined) => {
this.events.emit('ping', oldPeers, newPeer)
})
}
static getKeys(obj: Uint8Array | string | PeerInfo): string[] {
if (obj instanceof Uint8Array) return [bytesToUnprefixedHex(obj)]
if (typeof obj === 'string') return [obj]
const keys = []
if (obj.id instanceof Uint8Array) keys.push(bytesToUnprefixedHex(obj.id))
if (obj.address !== undefined && typeof obj.tcpPort === 'number')
keys.push(`${obj.address}:${obj.tcpPort}`)
return keys
}
add(peer: PeerInfo): _KBucket | void {
const isExists = KBucket.getKeys(peer).some((key) => this._peers.has(key))
if (!isExists) this._kbucket.add(peer)
}
get(obj: Uint8Array | string | PeerInfo): PeerInfo | null {
for (const key of KBucket.getKeys(obj)) {
const peer = this._peers.get(key)
if (peer !== undefined) return peer
}
return null
}
getAll(): Array<PeerInfo> {
return this._kbucket.toArray()
}
closest(id: Uint8Array): PeerInfo[] {
return this._kbucket.closest(id, KBUCKET_SIZE)
}
remove(obj: Uint8Array | string | PeerInfo) {
const peer = this.get(obj)
if (peer?.id !== undefined) this._kbucket.remove(peer.id)
}
}