@libp2p/kad-dht 9.3.4 → 9.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +23 -23
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +4 -4
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/query-self.d.ts +9 -6
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +31 -47
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +6 -1
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +7 -3
- package/dist/src/routing-table/index.js.map +1 -1
- package/package.json +3 -2
- package/src/kad-dht.ts +6 -4
- package/src/query-self.ts +67 -85
- package/src/routing-table/index.ts +15 -3
package/src/query-self.ts
CHANGED
|
@@ -4,10 +4,12 @@ import { anySignal } from 'any-signal'
|
|
|
4
4
|
import length from 'it-length'
|
|
5
5
|
import { pipe } from 'it-pipe'
|
|
6
6
|
import take from 'it-take'
|
|
7
|
+
import pDefer from 'p-defer'
|
|
8
|
+
import { pEvent } from 'p-event'
|
|
7
9
|
import { QUERY_SELF_INTERVAL, QUERY_SELF_TIMEOUT, K, QUERY_SELF_INITIAL_INTERVAL } from './constants.js'
|
|
8
|
-
import type { KadDHTComponents } from './index.js'
|
|
9
10
|
import type { PeerRouting } from './peer-routing/index.js'
|
|
10
11
|
import type { RoutingTable } from './routing-table/index.js'
|
|
12
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
11
13
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
12
14
|
import type { DeferredPromise } from 'p-defer'
|
|
13
15
|
|
|
@@ -22,18 +24,8 @@ export interface QuerySelfInit {
|
|
|
22
24
|
initialQuerySelfHasRun: DeferredPromise<void>
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return function () {
|
|
29
|
-
const later = function (): void {
|
|
30
|
-
timeout = undefined
|
|
31
|
-
func()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
clearTimeout(timeout)
|
|
35
|
-
timeout = setTimeout(later, wait)
|
|
36
|
-
}
|
|
27
|
+
export interface QuerySelfComponents {
|
|
28
|
+
peerId: PeerId
|
|
37
29
|
}
|
|
38
30
|
|
|
39
31
|
/**
|
|
@@ -41,7 +33,7 @@ function debounce (func: () => void, wait: number): () => void {
|
|
|
41
33
|
*/
|
|
42
34
|
export class QuerySelf implements Startable {
|
|
43
35
|
private readonly log: Logger
|
|
44
|
-
private readonly components:
|
|
36
|
+
private readonly components: QuerySelfComponents
|
|
45
37
|
private readonly peerRouting: PeerRouting
|
|
46
38
|
private readonly routingTable: RoutingTable
|
|
47
39
|
private readonly count: number
|
|
@@ -49,17 +41,16 @@ export class QuerySelf implements Startable {
|
|
|
49
41
|
private readonly initialInterval: number
|
|
50
42
|
private readonly queryTimeout: number
|
|
51
43
|
private started: boolean
|
|
52
|
-
private running: boolean
|
|
53
44
|
private timeoutId?: NodeJS.Timer
|
|
54
45
|
private controller?: AbortController
|
|
55
46
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
47
|
+
private querySelfPromise?: DeferredPromise<void>
|
|
56
48
|
|
|
57
|
-
constructor (components:
|
|
49
|
+
constructor (components: QuerySelfComponents, init: QuerySelfInit) {
|
|
58
50
|
const { peerRouting, lan, count, interval, queryTimeout, routingTable } = init
|
|
59
51
|
|
|
60
52
|
this.components = components
|
|
61
53
|
this.log = logger(`libp2p:kad-dht:${lan ? 'lan' : 'wan'}:query-self`)
|
|
62
|
-
this.running = false
|
|
63
54
|
this.started = false
|
|
64
55
|
this.peerRouting = peerRouting
|
|
65
56
|
this.routingTable = routingTable
|
|
@@ -68,25 +59,28 @@ export class QuerySelf implements Startable {
|
|
|
68
59
|
this.initialInterval = init.initialInterval ?? QUERY_SELF_INITIAL_INTERVAL
|
|
69
60
|
this.queryTimeout = queryTimeout ?? QUERY_SELF_TIMEOUT
|
|
70
61
|
this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
|
|
71
|
-
|
|
72
|
-
this.querySelf = debounce(this.querySelf.bind(this), 100)
|
|
73
62
|
}
|
|
74
63
|
|
|
75
64
|
isStarted (): boolean {
|
|
76
65
|
return this.started
|
|
77
66
|
}
|
|
78
67
|
|
|
79
|
-
|
|
68
|
+
start (): void {
|
|
80
69
|
if (this.started) {
|
|
81
70
|
return
|
|
82
71
|
}
|
|
83
72
|
|
|
84
73
|
this.started = true
|
|
85
74
|
clearTimeout(this.timeoutId)
|
|
86
|
-
this.timeoutId = setTimeout(
|
|
75
|
+
this.timeoutId = setTimeout(() => {
|
|
76
|
+
this.querySelf()
|
|
77
|
+
.catch(err => {
|
|
78
|
+
this.log.error('error running self-query', err)
|
|
79
|
+
})
|
|
80
|
+
}, this.initialInterval)
|
|
87
81
|
}
|
|
88
82
|
|
|
89
|
-
|
|
83
|
+
stop (): void {
|
|
90
84
|
this.started = false
|
|
91
85
|
|
|
92
86
|
if (this.timeoutId != null) {
|
|
@@ -98,84 +92,72 @@ export class QuerySelf implements Startable {
|
|
|
98
92
|
}
|
|
99
93
|
}
|
|
100
94
|
|
|
101
|
-
querySelf (): void {
|
|
95
|
+
async querySelf (): Promise<void> {
|
|
102
96
|
if (!this.started) {
|
|
103
97
|
this.log('skip self-query because we are not started')
|
|
104
98
|
return
|
|
105
99
|
}
|
|
106
100
|
|
|
107
|
-
if (this.
|
|
108
|
-
this.log('
|
|
109
|
-
return
|
|
101
|
+
if (this.querySelfPromise != null) {
|
|
102
|
+
this.log('joining existing self query')
|
|
103
|
+
return this.querySelfPromise.promise
|
|
110
104
|
}
|
|
111
105
|
|
|
112
|
-
|
|
113
|
-
let nextInterval = this.interval
|
|
114
|
-
|
|
115
|
-
if (this.initialQuerySelfHasRun != null) {
|
|
116
|
-
// if we've not yet run the first self query, shorten the interval until we try again
|
|
117
|
-
nextInterval = this.initialInterval
|
|
118
|
-
}
|
|
106
|
+
this.querySelfPromise = pDefer()
|
|
119
107
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return
|
|
108
|
+
if (this.routingTable.size === 0) {
|
|
109
|
+
// wait to discover at least one DHT peer
|
|
110
|
+
await pEvent(this.routingTable, 'peer:add')
|
|
124
111
|
}
|
|
125
112
|
|
|
126
|
-
this.
|
|
113
|
+
if (this.started) {
|
|
114
|
+
this.controller = new AbortController()
|
|
115
|
+
const signal = anySignal([this.controller.signal, AbortSignal.timeout(this.queryTimeout)])
|
|
127
116
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
return
|
|
117
|
+
// this controller will get used for lots of dial attempts so make sure we don't cause warnings to be logged
|
|
118
|
+
try {
|
|
119
|
+
if (setMaxListeners != null) {
|
|
120
|
+
setMaxListeners(Infinity, signal)
|
|
133
121
|
}
|
|
122
|
+
} catch {} // fails on node < 15.4
|
|
134
123
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
|
|
147
|
-
|
|
148
|
-
const found = await pipe(
|
|
149
|
-
this.peerRouting.getClosestPeers(this.components.peerId.toBytes(), {
|
|
150
|
-
signal,
|
|
151
|
-
isSelfQuery: true
|
|
152
|
-
}),
|
|
153
|
-
(source) => take(source, this.count),
|
|
154
|
-
async (source) => length(source)
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
this.log('self-query ran successfully - found %d peers', found)
|
|
158
|
-
|
|
159
|
-
if (this.initialQuerySelfHasRun != null) {
|
|
160
|
-
this.initialQuerySelfHasRun.resolve()
|
|
161
|
-
this.initialQuerySelfHasRun = undefined
|
|
162
|
-
}
|
|
163
|
-
} catch (err: any) {
|
|
164
|
-
this.log.error('self-query error', err)
|
|
165
|
-
} finally {
|
|
166
|
-
signal.clear()
|
|
167
|
-
}
|
|
168
|
-
}).catch(err => {
|
|
169
|
-
this.log('self-query error', err)
|
|
170
|
-
}).finally(() => {
|
|
171
|
-
this.running = false
|
|
124
|
+
try {
|
|
125
|
+
this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
|
|
126
|
+
|
|
127
|
+
const found = await pipe(
|
|
128
|
+
this.peerRouting.getClosestPeers(this.components.peerId.toBytes(), {
|
|
129
|
+
signal,
|
|
130
|
+
isSelfQuery: true
|
|
131
|
+
}),
|
|
132
|
+
(source) => take(source, this.count),
|
|
133
|
+
async (source) => length(source)
|
|
134
|
+
)
|
|
172
135
|
|
|
173
|
-
|
|
136
|
+
this.log('self-query ran successfully - found %d peers', found)
|
|
174
137
|
|
|
175
|
-
if (this.
|
|
176
|
-
this.
|
|
177
|
-
this.
|
|
138
|
+
if (this.initialQuerySelfHasRun != null) {
|
|
139
|
+
this.initialQuerySelfHasRun.resolve()
|
|
140
|
+
this.initialQuerySelfHasRun = undefined
|
|
178
141
|
}
|
|
179
|
-
})
|
|
142
|
+
} catch (err: any) {
|
|
143
|
+
this.log.error('self-query error', err)
|
|
144
|
+
} finally {
|
|
145
|
+
signal.clear()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.querySelfPromise.resolve()
|
|
150
|
+
this.querySelfPromise = undefined
|
|
151
|
+
|
|
152
|
+
if (!this.started) {
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.timeoutId = setTimeout(() => {
|
|
157
|
+
this.querySelf()
|
|
158
|
+
.catch(err => {
|
|
159
|
+
this.log.error('error running self-query', err)
|
|
160
|
+
})
|
|
161
|
+
}, this.interval)
|
|
180
162
|
}
|
|
181
163
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from '@libp2p/interfaces/events'
|
|
1
2
|
import { logger } from '@libp2p/logger'
|
|
2
3
|
import { PeerSet } from '@libp2p/peer-collections'
|
|
3
4
|
import Queue from 'p-queue'
|
|
@@ -33,11 +34,16 @@ export interface RoutingTableComponents {
|
|
|
33
34
|
metrics?: Metrics
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
export interface RoutingTableEvents {
|
|
38
|
+
'peer:add': CustomEvent<PeerId>
|
|
39
|
+
'peer:remove': CustomEvent<PeerId>
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
/**
|
|
37
43
|
* A wrapper around `k-bucket`, to provide easy store and
|
|
38
44
|
* retrieval for peers.
|
|
39
45
|
*/
|
|
40
|
-
export class RoutingTable implements Startable {
|
|
46
|
+
export class RoutingTable extends EventEmitter<RoutingTableEvents> implements Startable {
|
|
41
47
|
public kBucketSize: number
|
|
42
48
|
public kb?: KBucket
|
|
43
49
|
public pingQueue: Queue
|
|
@@ -58,6 +64,8 @@ export class RoutingTable implements Startable {
|
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
constructor (components: RoutingTableComponents, init: RoutingTableInit) {
|
|
67
|
+
super()
|
|
68
|
+
|
|
61
69
|
const { kBucketSize, pingTimeout, lan, pingConcurrency, protocol, tagName, tagValue } = init
|
|
62
70
|
|
|
63
71
|
this.components = components
|
|
@@ -160,11 +168,15 @@ export class RoutingTable implements Startable {
|
|
|
160
168
|
kClosest = newClosest
|
|
161
169
|
})
|
|
162
170
|
|
|
163
|
-
kBuck.addEventListener('added', () => {
|
|
171
|
+
kBuck.addEventListener('added', (evt) => {
|
|
164
172
|
updatePeerTags()
|
|
173
|
+
|
|
174
|
+
this.safeDispatchEvent('peer:add', { detail: evt.detail.peer })
|
|
165
175
|
})
|
|
166
|
-
kBuck.addEventListener('removed', () => {
|
|
176
|
+
kBuck.addEventListener('removed', (evt) => {
|
|
167
177
|
updatePeerTags()
|
|
178
|
+
|
|
179
|
+
this.safeDispatchEvent('peer:remove', { detail: evt.detail.peer })
|
|
168
180
|
})
|
|
169
181
|
}
|
|
170
182
|
|