@libp2p/utils 5.3.2 → 5.4.0-43046b9ae
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/src/abort-options.d.ts +7 -0
- package/dist/src/abort-options.d.ts.map +1 -0
- package/dist/src/abort-options.js +14 -0
- package/dist/src/abort-options.js.map +1 -0
- package/dist/src/adaptive-timeout.d.ts +35 -0
- package/dist/src/adaptive-timeout.d.ts.map +1 -0
- package/dist/src/adaptive-timeout.js +63 -0
- package/dist/src/adaptive-timeout.js.map +1 -0
- package/dist/src/close.d.ts +21 -0
- package/dist/src/close.d.ts.map +1 -0
- package/dist/src/close.js +49 -0
- package/dist/src/close.js.map +1 -0
- package/dist/src/filters/bloom-filter.d.ts +34 -0
- package/dist/src/filters/bloom-filter.d.ts.map +1 -0
- package/dist/src/filters/bloom-filter.js +113 -0
- package/dist/src/filters/bloom-filter.js.map +1 -0
- package/dist/src/filters/bucket.d.ts +10 -0
- package/dist/src/filters/bucket.d.ts.map +1 -0
- package/dist/src/filters/bucket.js +53 -0
- package/dist/src/filters/bucket.js.map +1 -0
- package/dist/src/filters/cuckoo-filter.d.ts +41 -0
- package/dist/src/filters/cuckoo-filter.d.ts.map +1 -0
- package/dist/src/filters/cuckoo-filter.js +134 -0
- package/dist/src/filters/cuckoo-filter.js.map +1 -0
- package/dist/src/filters/fingerprint.d.ts +11 -0
- package/dist/src/filters/fingerprint.d.ts.map +1 -0
- package/dist/src/filters/fingerprint.js +34 -0
- package/dist/src/filters/fingerprint.js.map +1 -0
- package/dist/src/filters/hashes.d.ts +8 -0
- package/dist/src/filters/hashes.d.ts.map +1 -0
- package/dist/src/filters/hashes.js +29 -0
- package/dist/src/filters/hashes.js.map +1 -0
- package/dist/src/filters/index.d.ts +9 -0
- package/dist/src/filters/index.d.ts.map +1 -0
- package/dist/src/filters/index.js +4 -0
- package/dist/src/filters/index.js.map +1 -0
- package/dist/src/filters/scalable-cuckoo-filter.d.ts +24 -0
- package/dist/src/filters/scalable-cuckoo-filter.d.ts.map +1 -0
- package/dist/src/filters/scalable-cuckoo-filter.js +87 -0
- package/dist/src/filters/scalable-cuckoo-filter.js.map +1 -0
- package/dist/src/filters/utils.d.ts +2 -0
- package/dist/src/filters/utils.d.ts.map +1 -0
- package/dist/src/filters/utils.js +4 -0
- package/dist/src/filters/utils.js.map +1 -0
- package/dist/src/moving-average.d.ts +18 -0
- package/dist/src/moving-average.d.ts.map +1 -0
- package/dist/src/moving-average.js +43 -0
- package/dist/src/moving-average.js.map +1 -0
- package/dist/src/peer-queue.d.ts +3 -3
- package/dist/src/peer-queue.d.ts.map +1 -1
- package/dist/src/peer-queue.js +0 -1
- package/dist/src/peer-queue.js.map +1 -1
- package/dist/src/priority-queue.d.ts +10 -0
- package/dist/src/priority-queue.d.ts.map +1 -0
- package/dist/src/priority-queue.js +18 -0
- package/dist/src/priority-queue.js.map +1 -0
- package/dist/src/queue/index.d.ts +14 -14
- package/dist/src/queue/index.d.ts.map +1 -1
- package/dist/src/queue/index.js +6 -24
- package/dist/src/queue/index.js.map +1 -1
- package/dist/src/queue/job.d.ts +1 -2
- package/dist/src/queue/job.d.ts.map +1 -1
- package/dist/src/queue/job.js +1 -3
- package/dist/src/queue/job.js.map +1 -1
- package/package.json +36 -7
- package/src/abort-options.ts +20 -0
- package/src/adaptive-timeout.ts +94 -0
- package/src/close.ts +65 -0
- package/src/filters/bloom-filter.ts +142 -0
- package/src/filters/bucket.ts +64 -0
- package/src/filters/cuckoo-filter.ts +197 -0
- package/src/filters/fingerprint.ts +44 -0
- package/src/filters/hashes.ts +38 -0
- package/src/filters/index.ts +9 -0
- package/src/filters/scalable-cuckoo-filter.ts +111 -0
- package/src/filters/utils.ts +3 -0
- package/src/moving-average.ts +45 -0
- package/src/peer-queue.ts +3 -5
- package/src/priority-queue.ts +26 -0
- package/src/queue/index.ts +21 -45
- package/src/queue/job.ts +1 -3
- package/dist/typedoc-urls.json +0 -76
package/dist/src/queue/job.js
CHANGED
|
@@ -11,16 +11,14 @@ export class Job {
|
|
|
11
11
|
id;
|
|
12
12
|
fn;
|
|
13
13
|
options;
|
|
14
|
-
priority;
|
|
15
14
|
recipients;
|
|
16
15
|
status;
|
|
17
16
|
timeline;
|
|
18
17
|
controller;
|
|
19
|
-
constructor(fn, options
|
|
18
|
+
constructor(fn, options) {
|
|
20
19
|
this.id = randomId();
|
|
21
20
|
this.status = 'queued';
|
|
22
21
|
this.fn = fn;
|
|
23
|
-
this.priority = priority;
|
|
24
22
|
this.options = options;
|
|
25
23
|
this.recipients = [];
|
|
26
24
|
this.timeline = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job.js","sourceRoot":"","sources":["../../../src/queue/job.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAI7C;;GAEG;AACH,SAAS,QAAQ;IACf,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;AACjF,CAAC;AAQD,MAAM,OAAO,GAAG;IACP,EAAE,CAAQ;IACV,EAAE,CAAiD;IACnD,OAAO,CAAY;IACnB,
|
|
1
|
+
{"version":3,"file":"job.js","sourceRoot":"","sources":["../../../src/queue/job.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0-43046b9ae",
|
|
4
4
|
"description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/utils#readme",
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"types": "./src/index.d.ts",
|
|
45
45
|
"import": "./dist/src/index.js"
|
|
46
46
|
},
|
|
47
|
+
"./abort-options": {
|
|
48
|
+
"types": "./dist/src/abort-options.d.ts",
|
|
49
|
+
"import": "./dist/src/abort-options.js"
|
|
50
|
+
},
|
|
47
51
|
"./abstract-stream": {
|
|
48
52
|
"types": "./dist/src/abstract-stream.d.ts",
|
|
49
53
|
"import": "./dist/src/abstract-stream.js"
|
|
@@ -52,6 +56,10 @@
|
|
|
52
56
|
"types": "./dist/src/address-sort.d.ts",
|
|
53
57
|
"import": "./dist/src/address-sort.js"
|
|
54
58
|
},
|
|
59
|
+
"./adaptive-timeout": {
|
|
60
|
+
"types": "./dist/src/adaptive-timeout.d.ts",
|
|
61
|
+
"import": "./dist/src/adaptive-timeout.js"
|
|
62
|
+
},
|
|
55
63
|
"./array-equals": {
|
|
56
64
|
"types": "./dist/src/array-equals.d.ts",
|
|
57
65
|
"import": "./dist/src/array-equals.js"
|
|
@@ -60,6 +68,14 @@
|
|
|
60
68
|
"types": "./dist/src/close-source.d.ts",
|
|
61
69
|
"import": "./dist/src/close-source.js"
|
|
62
70
|
},
|
|
71
|
+
"./close": {
|
|
72
|
+
"types": "./dist/src/close.d.ts",
|
|
73
|
+
"import": "./dist/src/close.js"
|
|
74
|
+
},
|
|
75
|
+
"./filters": {
|
|
76
|
+
"types": "./dist/src/filters/index.d.ts",
|
|
77
|
+
"import": "./dist/src/filters/index.js"
|
|
78
|
+
},
|
|
63
79
|
"./ip-port-to-multiaddr": {
|
|
64
80
|
"types": "./dist/src/ip-port-to-multiaddr.d.ts",
|
|
65
81
|
"import": "./dist/src/ip-port-to-multiaddr.js"
|
|
@@ -68,6 +84,10 @@
|
|
|
68
84
|
"types": "./dist/src/is-promise.d.ts",
|
|
69
85
|
"import": "./dist/src/is-promise.js"
|
|
70
86
|
},
|
|
87
|
+
"./moving-average": {
|
|
88
|
+
"types": "./dist/src/moving-average.d.ts",
|
|
89
|
+
"import": "./dist/src/moving-average.js"
|
|
90
|
+
},
|
|
71
91
|
"./multiaddr/is-loopback": {
|
|
72
92
|
"types": "./dist/src/multiaddr/is-loopback.d.ts",
|
|
73
93
|
"import": "./dist/src/multiaddr/is-loopback.js"
|
|
@@ -80,6 +100,10 @@
|
|
|
80
100
|
"types": "./dist/src/peer-queue.d.ts",
|
|
81
101
|
"import": "./dist/src/peer-queue.js"
|
|
82
102
|
},
|
|
103
|
+
"./priority-queue": {
|
|
104
|
+
"types": "./dist/src/priority-queue.d.ts",
|
|
105
|
+
"import": "./dist/src/priority-queue.js"
|
|
106
|
+
},
|
|
83
107
|
"./private-ip": {
|
|
84
108
|
"types": "./dist/src/private-ip.d.ts",
|
|
85
109
|
"import": "./dist/src/private-ip.js"
|
|
@@ -128,23 +152,29 @@
|
|
|
128
152
|
},
|
|
129
153
|
"dependencies": {
|
|
130
154
|
"@chainsafe/is-ip": "^2.0.2",
|
|
131
|
-
"@libp2p/
|
|
132
|
-
"@libp2p/
|
|
155
|
+
"@libp2p/crypto": "4.1.1-43046b9ae",
|
|
156
|
+
"@libp2p/interface": "1.3.1-43046b9ae",
|
|
157
|
+
"@libp2p/logger": "4.0.12-43046b9ae",
|
|
133
158
|
"@multiformats/multiaddr": "^12.2.1",
|
|
134
159
|
"@multiformats/multiaddr-matcher": "^1.2.0",
|
|
160
|
+
"@sindresorhus/fnv1a": "^3.1.0",
|
|
161
|
+
"@types/murmurhash3js-revisited": "^3.0.3",
|
|
162
|
+
"any-signal": "^4.1.1",
|
|
135
163
|
"delay": "^6.0.0",
|
|
136
164
|
"get-iterator": "^2.0.1",
|
|
137
165
|
"is-loopback-addr": "^2.0.2",
|
|
138
166
|
"it-pushable": "^3.2.3",
|
|
139
167
|
"it-stream-types": "^2.0.1",
|
|
168
|
+
"murmurhash3js-revisited": "^3.0.0",
|
|
140
169
|
"netmask": "^2.0.2",
|
|
141
170
|
"p-defer": "^4.0.1",
|
|
142
171
|
"race-event": "^1.2.0",
|
|
143
172
|
"race-signal": "^1.0.2",
|
|
144
|
-
"uint8arraylist": "^2.4.8"
|
|
173
|
+
"uint8arraylist": "^2.4.8",
|
|
174
|
+
"uint8arrays": "^5.0.3"
|
|
145
175
|
},
|
|
146
176
|
"devDependencies": {
|
|
147
|
-
"@libp2p/peer-id-factory": "
|
|
177
|
+
"@libp2p/peer-id-factory": "4.1.1-43046b9ae",
|
|
148
178
|
"@types/netmask": "^2.0.5",
|
|
149
179
|
"aegir": "^42.2.5",
|
|
150
180
|
"delay": "^6.0.0",
|
|
@@ -153,8 +183,7 @@
|
|
|
153
183
|
"it-pair": "^2.0.6",
|
|
154
184
|
"it-pipe": "^3.0.1",
|
|
155
185
|
"sinon": "^17.0.1",
|
|
156
|
-
"sinon-ts": "^2.0.0"
|
|
157
|
-
"uint8arrays": "^5.0.3"
|
|
186
|
+
"sinon-ts": "^2.0.0"
|
|
158
187
|
},
|
|
159
188
|
"sideEffects": false
|
|
160
189
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { setMaxListeners } from '@libp2p/interface'
|
|
2
|
+
import { anySignal } from 'any-signal'
|
|
3
|
+
import type { AbortOptions } from '@libp2p/interface'
|
|
4
|
+
import type { ClearableSignal } from 'any-signal'
|
|
5
|
+
|
|
6
|
+
export function createTimeoutOptions (timeout: number): AbortOptions
|
|
7
|
+
export function createTimeoutOptions (timeout: number, ...existingSignals: AbortSignal[]): { signal: ClearableSignal }
|
|
8
|
+
export function createTimeoutOptions (timeout: number, ...existingSignals: AbortSignal[]): AbortOptions {
|
|
9
|
+
let signal = AbortSignal.timeout(timeout)
|
|
10
|
+
setMaxListeners(Infinity, signal)
|
|
11
|
+
|
|
12
|
+
if (existingSignals.length > 0) {
|
|
13
|
+
signal = anySignal([signal, ...existingSignals])
|
|
14
|
+
setMaxListeners(Infinity, signal)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
signal
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { setMaxListeners } from '@libp2p/interface'
|
|
2
|
+
import { anySignal, type ClearableSignal } from 'any-signal'
|
|
3
|
+
import { MovingAverage } from './moving-average.js'
|
|
4
|
+
import type { MetricGroup, Metrics } from '@libp2p/interface'
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_TIMEOUT_MULTIPLIER = 1.2
|
|
7
|
+
export const DEFAULT_FAILURE_MULTIPLIER = 2
|
|
8
|
+
export const DEFAULT_MIN_TIMEOUT = 2000
|
|
9
|
+
|
|
10
|
+
export interface AdaptiveTimeoutSignal extends ClearableSignal {
|
|
11
|
+
start: number
|
|
12
|
+
timeout: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AdaptiveTimeoutInit {
|
|
16
|
+
metricName?: string
|
|
17
|
+
metrics?: Metrics
|
|
18
|
+
interval?: number
|
|
19
|
+
initialValue?: number
|
|
20
|
+
timeoutMultiplier?: number
|
|
21
|
+
failureMultiplier?: number
|
|
22
|
+
minTimeout?: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface GetTimeoutSignalOptions {
|
|
26
|
+
timeoutFactor?: number
|
|
27
|
+
signal?: AbortSignal
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class AdaptiveTimeout {
|
|
31
|
+
private readonly success: MovingAverage
|
|
32
|
+
private readonly failure: MovingAverage
|
|
33
|
+
private readonly next: MovingAverage
|
|
34
|
+
private readonly metric?: MetricGroup
|
|
35
|
+
private readonly timeoutMultiplier: number
|
|
36
|
+
private readonly failureMultiplier: number
|
|
37
|
+
private readonly minTimeout: number
|
|
38
|
+
|
|
39
|
+
constructor (init: AdaptiveTimeoutInit = {}) {
|
|
40
|
+
this.success = new MovingAverage(init.interval ?? 5000)
|
|
41
|
+
this.failure = new MovingAverage(init.interval ?? 5000)
|
|
42
|
+
this.next = new MovingAverage(init.interval ?? 5000)
|
|
43
|
+
this.failureMultiplier = init.failureMultiplier ?? DEFAULT_FAILURE_MULTIPLIER
|
|
44
|
+
this.timeoutMultiplier = init.timeoutMultiplier ?? DEFAULT_TIMEOUT_MULTIPLIER
|
|
45
|
+
this.minTimeout = init.minTimeout ?? DEFAULT_MIN_TIMEOUT
|
|
46
|
+
|
|
47
|
+
if (init.metricName != null) {
|
|
48
|
+
this.metric = init.metrics?.registerMetricGroup(init.metricName)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getTimeoutSignal (options: GetTimeoutSignalOptions = {}): AdaptiveTimeoutSignal {
|
|
53
|
+
// calculate timeout for individual peers based on moving average of
|
|
54
|
+
// previous successful requests
|
|
55
|
+
const timeout = Math.max(
|
|
56
|
+
Math.round(this.next.movingAverage * (options.timeoutFactor ?? this.timeoutMultiplier)),
|
|
57
|
+
this.minTimeout
|
|
58
|
+
)
|
|
59
|
+
const sendTimeout = AbortSignal.timeout(timeout)
|
|
60
|
+
const timeoutSignal = anySignal([options.signal, sendTimeout]) as AdaptiveTimeoutSignal
|
|
61
|
+
setMaxListeners(Infinity, timeoutSignal, sendTimeout)
|
|
62
|
+
|
|
63
|
+
timeoutSignal.start = Date.now()
|
|
64
|
+
timeoutSignal.timeout = timeout
|
|
65
|
+
|
|
66
|
+
return timeoutSignal
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cleanUp (signal: AdaptiveTimeoutSignal): void {
|
|
70
|
+
const time = Date.now() - signal.start
|
|
71
|
+
|
|
72
|
+
if (signal.aborted) {
|
|
73
|
+
this.failure.push(time)
|
|
74
|
+
this.next.push(time * this.failureMultiplier)
|
|
75
|
+
this.metric?.update({
|
|
76
|
+
failureMovingAverage: this.failure.movingAverage,
|
|
77
|
+
failureDeviation: this.failure.deviation,
|
|
78
|
+
failureForecast: this.failure.forecast,
|
|
79
|
+
failureVariance: this.failure.variance,
|
|
80
|
+
failure: time
|
|
81
|
+
})
|
|
82
|
+
} else {
|
|
83
|
+
this.success.push(time)
|
|
84
|
+
this.next.push(time)
|
|
85
|
+
this.metric?.update({
|
|
86
|
+
successMovingAverage: this.success.movingAverage,
|
|
87
|
+
successDeviation: this.success.deviation,
|
|
88
|
+
successForecast: this.success.forecast,
|
|
89
|
+
successVariance: this.success.variance,
|
|
90
|
+
success: time
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/close.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Connection, Stream, AbortOptions } from '@libp2p/interface'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Close the passed stream, falling back to aborting the stream if closing
|
|
5
|
+
* cleanly fails.
|
|
6
|
+
*/
|
|
7
|
+
export async function safelyCloseStream (stream?: Stream, options?: AbortOptions): Promise<void> {
|
|
8
|
+
try {
|
|
9
|
+
await stream?.close(options)
|
|
10
|
+
} catch (err: any) {
|
|
11
|
+
stream?.abort(err)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* These are speculative protocols that are run automatically on connection open
|
|
17
|
+
* so are usually not the reason the connection was opened.
|
|
18
|
+
*
|
|
19
|
+
* Consequently when requested it should be safe to close connections that only
|
|
20
|
+
* have these protocol streams open.
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_CLOSABLE_PROTOCOLS = [
|
|
23
|
+
// identify
|
|
24
|
+
'/ipfs/id/1.0.0',
|
|
25
|
+
|
|
26
|
+
// identify-push
|
|
27
|
+
'/ipfs/id/push/1.0.0',
|
|
28
|
+
|
|
29
|
+
// autonat
|
|
30
|
+
'/libp2p/autonat/1.0.0',
|
|
31
|
+
|
|
32
|
+
// dcutr
|
|
33
|
+
'/libp2p/dcutr'
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
export interface SafelyCloseConnectionOptions extends AbortOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Only close the stream if it either has no protocol streams open or only
|
|
39
|
+
* ones in this list.
|
|
40
|
+
*
|
|
41
|
+
* @default ['/ipfs/id/1.0.0']
|
|
42
|
+
*/
|
|
43
|
+
closableProtocols?: string[]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Close the passed connection if it has no streams, or only closable protocol
|
|
48
|
+
* streams, falling back to aborting the connection if closing it cleanly fails.
|
|
49
|
+
*/
|
|
50
|
+
export async function safelyCloseConnectionIfUnused (connection?: Connection, options?: SafelyCloseConnectionOptions): Promise<void> {
|
|
51
|
+
const streamProtocols = connection?.streams?.map(stream => stream.protocol) ?? []
|
|
52
|
+
const closableProtocols = options?.closableProtocols ?? DEFAULT_CLOSABLE_PROTOCOLS
|
|
53
|
+
|
|
54
|
+
// if the connection has protocols not in the closable protocols list, do not
|
|
55
|
+
// close the connection
|
|
56
|
+
if (streamProtocols.filter(proto => proto != null && !closableProtocols.includes(proto)).length > 0) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
await connection?.close(options)
|
|
62
|
+
} catch (err: any) {
|
|
63
|
+
connection?.abort(err)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// ported from xxbloom - https://github.com/ceejbot/xxbloom/blob/master/LICENSE
|
|
2
|
+
import { randomBytes } from '@libp2p/crypto'
|
|
3
|
+
import mur from 'murmurhash3js-revisited'
|
|
4
|
+
import { Uint8ArrayList } from 'uint8arraylist'
|
|
5
|
+
import { alloc } from 'uint8arrays/alloc'
|
|
6
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
7
|
+
import type { Filter } from './index.js'
|
|
8
|
+
|
|
9
|
+
const LN2_SQUARED = Math.LN2 * Math.LN2
|
|
10
|
+
|
|
11
|
+
export interface BloomFilterOptions {
|
|
12
|
+
seeds?: number[]
|
|
13
|
+
hashes?: number
|
|
14
|
+
bits?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class BloomFilter implements Filter {
|
|
18
|
+
public readonly seeds: number[]
|
|
19
|
+
public readonly bits: number
|
|
20
|
+
public buffer: Uint8Array
|
|
21
|
+
|
|
22
|
+
constructor (options: BloomFilterOptions = {}) {
|
|
23
|
+
if (options.seeds != null) {
|
|
24
|
+
this.seeds = options.seeds
|
|
25
|
+
} else {
|
|
26
|
+
this.seeds = generateSeeds(options.hashes ?? 8)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.bits = options.bits ?? 1024
|
|
30
|
+
this.buffer = alloc(Math.ceil(this.bits / 8))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Add an item to the filter
|
|
35
|
+
*/
|
|
36
|
+
add (item: Uint8Array | string): void {
|
|
37
|
+
if (typeof item === 'string') {
|
|
38
|
+
item = uint8ArrayFromString(item)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
42
|
+
const hash = mur.x86.hash32(item, this.seeds[i])
|
|
43
|
+
const bit = hash % this.bits
|
|
44
|
+
|
|
45
|
+
this.setbit(bit)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Test if the filter has an item. If it returns false it definitely does not
|
|
51
|
+
* have the item. If it returns true, it probably has the item but there's
|
|
52
|
+
* an `errorRate` chance it doesn't.
|
|
53
|
+
*/
|
|
54
|
+
has (item: Uint8Array | string): boolean {
|
|
55
|
+
if (typeof item === 'string') {
|
|
56
|
+
item = uint8ArrayFromString(item)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
60
|
+
const hash = mur.x86.hash32(item, this.seeds[i])
|
|
61
|
+
const bit = hash % this.bits
|
|
62
|
+
|
|
63
|
+
const isSet = this.getbit(bit)
|
|
64
|
+
|
|
65
|
+
if (!isSet) {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reset the filter
|
|
75
|
+
*/
|
|
76
|
+
clear (): void {
|
|
77
|
+
this.buffer.fill(0)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setbit (bit: number): void {
|
|
81
|
+
let pos = 0
|
|
82
|
+
let shift = bit
|
|
83
|
+
while (shift > 7) {
|
|
84
|
+
pos++
|
|
85
|
+
shift -= 8
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let bitfield = this.buffer[pos]
|
|
89
|
+
bitfield |= (0x1 << shift)
|
|
90
|
+
this.buffer[pos] = bitfield
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getbit (bit: number): boolean {
|
|
94
|
+
let pos = 0
|
|
95
|
+
let shift = bit
|
|
96
|
+
while (shift > 7) {
|
|
97
|
+
pos++
|
|
98
|
+
shift -= 8
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const bitfield = this.buffer[pos]
|
|
102
|
+
return (bitfield & (0x1 << shift)) !== 0
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create a `BloomFilter` with the smallest `bits` and `hashes` value for the
|
|
108
|
+
* specified item count and error rate.
|
|
109
|
+
*/
|
|
110
|
+
export function createBloomFilter (itemcount: number, errorRate: number = 0.005): Filter {
|
|
111
|
+
const opts = optimize(itemcount, errorRate)
|
|
112
|
+
return new BloomFilter(opts)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function optimize (itemCount: number, errorRate: number = 0.005): { bits: number, hashes: number } {
|
|
116
|
+
const bits = Math.round(-1 * itemCount * Math.log(errorRate) / LN2_SQUARED)
|
|
117
|
+
const hashes = Math.round((bits / itemCount) * Math.LN2)
|
|
118
|
+
|
|
119
|
+
return { bits, hashes }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function generateSeeds (count: number): number[] {
|
|
123
|
+
let buf: Uint8ArrayList
|
|
124
|
+
let j: number
|
|
125
|
+
const seeds = []
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < count; i++) {
|
|
128
|
+
buf = new Uint8ArrayList(randomBytes(4))
|
|
129
|
+
seeds[i] = buf.getUint32(0, true)
|
|
130
|
+
|
|
131
|
+
// Make sure we don't end up with two identical seeds,
|
|
132
|
+
// which is unlikely but possible.
|
|
133
|
+
for (j = 0; j < i; j++) {
|
|
134
|
+
if (seeds[i] === seeds[j]) {
|
|
135
|
+
i--
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return seeds
|
|
142
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Fingerprint } from './fingerprint.js'
|
|
2
|
+
import { getRandomInt } from './utils.js'
|
|
3
|
+
|
|
4
|
+
export class Bucket {
|
|
5
|
+
private readonly contents: Array<Fingerprint | null>
|
|
6
|
+
|
|
7
|
+
constructor (size: number) {
|
|
8
|
+
this.contents = new Array(size).fill(null)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
has (fingerprint: Fingerprint): boolean {
|
|
12
|
+
if (!(fingerprint instanceof Fingerprint)) {
|
|
13
|
+
throw new TypeError('Invalid Fingerprint')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return this.contents.some((fp) => {
|
|
17
|
+
return fingerprint.equals(fp)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
add (fingerprint: Fingerprint): boolean {
|
|
22
|
+
if (!(fingerprint instanceof Fingerprint)) {
|
|
23
|
+
throw new TypeError('Invalid Fingerprint')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < this.contents.length; i++) {
|
|
27
|
+
if (this.contents[i] == null) {
|
|
28
|
+
this.contents[i] = fingerprint
|
|
29
|
+
return true
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
swap (fingerprint: Fingerprint): Fingerprint | null {
|
|
37
|
+
if (!(fingerprint instanceof Fingerprint)) {
|
|
38
|
+
throw new TypeError('Invalid Fingerprint')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const i = getRandomInt(0, this.contents.length - 1)
|
|
42
|
+
const current = this.contents[i]
|
|
43
|
+
this.contents[i] = fingerprint
|
|
44
|
+
|
|
45
|
+
return current
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
remove (fingerprint: Fingerprint): boolean {
|
|
49
|
+
if (!(fingerprint instanceof Fingerprint)) {
|
|
50
|
+
throw new TypeError('Invalid Fingerprint')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const found = this.contents.findIndex((fp) => {
|
|
54
|
+
return fingerprint.equals(fp)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if (found > -1) {
|
|
58
|
+
this.contents[found] = null
|
|
59
|
+
return true
|
|
60
|
+
} else {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|