@libp2p/kad-dht 0.28.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/LICENSE +4 -0
- package/README.md +105 -0
- package/dist/src/constants.d.ts +20 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +34 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/content-fetching/index.d.ts +55 -0
- package/dist/src/content-fetching/index.d.ts.map +1 -0
- package/dist/src/content-fetching/index.js +190 -0
- package/dist/src/content-fetching/index.js.map +1 -0
- package/dist/src/content-routing/index.d.ts +42 -0
- package/dist/src/content-routing/index.d.ts.map +1 -0
- package/dist/src/content-routing/index.js +129 -0
- package/dist/src/content-routing/index.js.map +1 -0
- package/dist/src/dual-kad-dht.d.ts +65 -0
- package/dist/src/dual-kad-dht.d.ts.map +1 -0
- package/dist/src/dual-kad-dht.js +191 -0
- package/dist/src/dual-kad-dht.js.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/kad-dht.d.ts +131 -0
- package/dist/src/kad-dht.d.ts.map +1 -0
- package/dist/src/kad-dht.js +268 -0
- package/dist/src/kad-dht.js.map +1 -0
- package/dist/src/message/dht.d.ts +297 -0
- package/dist/src/message/dht.js +921 -0
- package/dist/src/message/index.d.ts +32 -0
- package/dist/src/message/index.d.ts.map +1 -0
- package/dist/src/message/index.js +81 -0
- package/dist/src/message/index.js.map +1 -0
- package/dist/src/network.d.ts +60 -0
- package/dist/src/network.d.ts.map +1 -0
- package/dist/src/network.js +124 -0
- package/dist/src/network.js.map +1 -0
- package/dist/src/peer-list/index.d.ts +29 -0
- package/dist/src/peer-list/index.d.ts.map +1 -0
- package/dist/src/peer-list/index.js +44 -0
- package/dist/src/peer-list/index.js.map +1 -0
- package/dist/src/peer-list/peer-distance-list.d.ts +34 -0
- package/dist/src/peer-list/peer-distance-list.d.ts.map +1 -0
- package/dist/src/peer-list/peer-distance-list.js +64 -0
- package/dist/src/peer-list/peer-distance-list.js.map +1 -0
- package/dist/src/peer-routing/index.d.ts +71 -0
- package/dist/src/peer-routing/index.d.ts.map +1 -0
- package/dist/src/peer-routing/index.js +256 -0
- package/dist/src/peer-routing/index.js.map +1 -0
- package/dist/src/providers.d.ts +64 -0
- package/dist/src/providers.d.ts.map +1 -0
- package/dist/src/providers.js +208 -0
- package/dist/src/providers.js.map +1 -0
- package/dist/src/query/events.d.ts +46 -0
- package/dist/src/query/events.d.ts.map +1 -0
- package/dist/src/query/events.js +73 -0
- package/dist/src/query/events.js.map +1 -0
- package/dist/src/query/manager.d.ts +40 -0
- package/dist/src/query/manager.d.ts.map +1 -0
- package/dist/src/query/manager.js +140 -0
- package/dist/src/query/manager.js.map +1 -0
- package/dist/src/query/query-path.d.ts +58 -0
- package/dist/src/query/query-path.d.ts.map +1 -0
- package/dist/src/query/query-path.js +171 -0
- package/dist/src/query/query-path.js.map +1 -0
- package/dist/src/query/types.d.ts +16 -0
- package/dist/src/query/types.d.ts.map +1 -0
- package/dist/src/query/types.js +2 -0
- package/dist/src/query/types.js.map +1 -0
- package/dist/src/query-self.d.ts +31 -0
- package/dist/src/query-self.d.ts.map +1 -0
- package/dist/src/query-self.js +73 -0
- package/dist/src/query-self.js.map +1 -0
- package/dist/src/routing-table/generated-prefix-list-browser.d.ts +3 -0
- package/dist/src/routing-table/generated-prefix-list-browser.d.ts.map +1 -0
- package/dist/src/routing-table/generated-prefix-list-browser.js +1027 -0
- package/dist/src/routing-table/generated-prefix-list-browser.js.map +1 -0
- package/dist/src/routing-table/generated-prefix-list.d.ts +3 -0
- package/dist/src/routing-table/generated-prefix-list.d.ts.map +1 -0
- package/dist/src/routing-table/generated-prefix-list.js +4099 -0
- package/dist/src/routing-table/generated-prefix-list.js.map +1 -0
- package/dist/src/routing-table/index.d.ts +91 -0
- package/dist/src/routing-table/index.d.ts.map +1 -0
- package/dist/src/routing-table/index.js +183 -0
- package/dist/src/routing-table/index.js.map +1 -0
- package/dist/src/routing-table/refresh.d.ts +50 -0
- package/dist/src/routing-table/refresh.d.ts.map +1 -0
- package/dist/src/routing-table/refresh.js +204 -0
- package/dist/src/routing-table/refresh.js.map +1 -0
- package/dist/src/routing-table/types.d.ts +24 -0
- package/dist/src/routing-table/types.d.ts.map +1 -0
- package/dist/src/rpc/handlers/add-provider.d.ts +13 -0
- package/dist/src/rpc/handlers/add-provider.d.ts.map +1 -0
- package/dist/src/rpc/handlers/add-provider.js +42 -0
- package/dist/src/rpc/handlers/add-provider.js.map +1 -0
- package/dist/src/rpc/handlers/find-node.d.ts +18 -0
- package/dist/src/rpc/handlers/find-node.d.ts.map +1 -0
- package/dist/src/rpc/handlers/find-node.js +32 -0
- package/dist/src/rpc/handlers/find-node.js.map +1 -0
- package/dist/src/rpc/handlers/get-providers.d.ts +24 -0
- package/dist/src/rpc/handlers/get-providers.d.ts.map +1 -0
- package/dist/src/rpc/handlers/get-providers.js +60 -0
- package/dist/src/rpc/handlers/get-providers.js.map +1 -0
- package/dist/src/rpc/handlers/get-value.d.ts +27 -0
- package/dist/src/rpc/handlers/get-value.d.ts.map +1 -0
- package/dist/src/rpc/handlers/get-value.js +94 -0
- package/dist/src/rpc/handlers/get-value.js.map +1 -0
- package/dist/src/rpc/handlers/index.d.ts +13 -0
- package/dist/src/rpc/handlers/index.d.ts.map +1 -0
- package/dist/src/rpc/handlers/ping.d.ts +7 -0
- package/dist/src/rpc/handlers/ping.d.ts.map +1 -0
- package/dist/src/rpc/handlers/ping.js +9 -0
- package/dist/src/rpc/handlers/ping.js.map +1 -0
- package/dist/src/rpc/handlers/put-value.d.ts +18 -0
- package/dist/src/rpc/handlers/put-value.d.ts.map +1 -0
- package/dist/src/rpc/handlers/put-value.js +35 -0
- package/dist/src/rpc/handlers/put-value.js.map +1 -0
- package/dist/src/rpc/index.d.ts +38 -0
- package/dist/src/rpc/index.d.ts.map +1 -0
- package/dist/src/rpc/index.js +75 -0
- package/dist/src/rpc/index.js.map +1 -0
- package/dist/src/rpc/types.d.ts +6 -0
- package/dist/src/rpc/types.d.ts.map +1 -0
- package/dist/src/topology-listener.d.ts +33 -0
- package/dist/src/topology-listener.d.ts.map +1 -0
- package/dist/src/topology-listener.js +50 -0
- package/dist/src/topology-listener.js.map +1 -0
- package/dist/src/types.d.ts +143 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +33 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +89 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +200 -0
- package/src/constants.ts +50 -0
- package/src/content-fetching/index.ts +276 -0
- package/src/content-routing/index.ts +202 -0
- package/src/dual-kad-dht.ts +257 -0
- package/src/index.ts +21 -0
- package/src/kad-dht.ts +396 -0
- package/src/message/dht.d.ts +297 -0
- package/src/message/dht.js +921 -0
- package/src/message/dht.proto +75 -0
- package/src/message/index.ts +111 -0
- package/src/network.ts +185 -0
- package/src/peer-list/index.ts +54 -0
- package/src/peer-list/peer-distance-list.ts +93 -0
- package/src/peer-routing/index.ts +332 -0
- package/src/providers.ts +278 -0
- package/src/query/events.ts +126 -0
- package/src/query/manager.ts +188 -0
- package/src/query/query-path.ts +263 -0
- package/src/query/types.ts +22 -0
- package/src/query-self.ts +106 -0
- package/src/routing-table/generated-prefix-list-browser.ts +1026 -0
- package/src/routing-table/generated-prefix-list.ts +4098 -0
- package/src/routing-table/index.ts +265 -0
- package/src/routing-table/refresh.ts +263 -0
- package/src/rpc/handlers/add-provider.ts +63 -0
- package/src/rpc/handlers/find-node.ts +57 -0
- package/src/rpc/handlers/get-providers.ts +95 -0
- package/src/rpc/handlers/get-value.ts +130 -0
- package/src/rpc/handlers/ping.ts +13 -0
- package/src/rpc/handlers/put-value.ts +58 -0
- package/src/rpc/index.ts +118 -0
- package/src/topology-listener.ts +78 -0
- package/src/utils.ts +108 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
// can't use, because protocol-buffers doesn't support imports
|
|
3
|
+
// so we have to duplicate for now :(
|
|
4
|
+
// import "record.proto";
|
|
5
|
+
|
|
6
|
+
message Record {
|
|
7
|
+
// adjusted for javascript
|
|
8
|
+
optional bytes key = 1;
|
|
9
|
+
optional bytes value = 2;
|
|
10
|
+
optional bytes author = 3;
|
|
11
|
+
optional bytes signature = 4;
|
|
12
|
+
optional string timeReceived = 5;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
message Message {
|
|
16
|
+
enum MessageType {
|
|
17
|
+
PUT_VALUE = 0;
|
|
18
|
+
GET_VALUE = 1;
|
|
19
|
+
ADD_PROVIDER = 2;
|
|
20
|
+
GET_PROVIDERS = 3;
|
|
21
|
+
FIND_NODE = 4;
|
|
22
|
+
PING = 5;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum ConnectionType {
|
|
26
|
+
// sender does not have a connection to peer, and no extra information (default)
|
|
27
|
+
NOT_CONNECTED = 0;
|
|
28
|
+
|
|
29
|
+
// sender has a live connection to peer
|
|
30
|
+
CONNECTED = 1;
|
|
31
|
+
|
|
32
|
+
// sender recently connected to peer
|
|
33
|
+
CAN_CONNECT = 2;
|
|
34
|
+
|
|
35
|
+
// sender recently tried to connect to peer repeatedly but failed to connect
|
|
36
|
+
// ("try" here is loose, but this should signal "made strong effort, failed")
|
|
37
|
+
CANNOT_CONNECT = 3;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
message Peer {
|
|
41
|
+
// ID of a given peer.
|
|
42
|
+
optional bytes id = 1;
|
|
43
|
+
|
|
44
|
+
// multiaddrs for a given peer
|
|
45
|
+
repeated bytes addrs = 2;
|
|
46
|
+
|
|
47
|
+
// used to signal the sender's connection capabilities to the peer
|
|
48
|
+
optional ConnectionType connection = 3;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// defines what type of message it is.
|
|
52
|
+
optional MessageType type = 1;
|
|
53
|
+
|
|
54
|
+
// defines what coral cluster level this query/response belongs to.
|
|
55
|
+
// in case we want to implement coral's cluster rings in the future.
|
|
56
|
+
optional int32 clusterLevelRaw = 10;
|
|
57
|
+
|
|
58
|
+
// Used to specify the key associated with this message.
|
|
59
|
+
// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
|
|
60
|
+
// adjusted for javascript
|
|
61
|
+
optional bytes key = 2;
|
|
62
|
+
|
|
63
|
+
// Used to return a value
|
|
64
|
+
// PUT_VALUE, GET_VALUE
|
|
65
|
+
// adjusted Record to bytes for js
|
|
66
|
+
optional bytes record = 3;
|
|
67
|
+
|
|
68
|
+
// Used to return peers closer to a key in a query
|
|
69
|
+
// GET_VALUE, GET_PROVIDERS, FIND_NODE
|
|
70
|
+
repeated Peer closerPeers = 8;
|
|
71
|
+
|
|
72
|
+
// Used to return Providers
|
|
73
|
+
// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
|
|
74
|
+
repeated Peer providerPeers = 9;
|
|
75
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { peerIdFromBytes } from '@libp2p/peer-id'
|
|
2
|
+
import { Multiaddr } from '@multiformats/multiaddr'
|
|
3
|
+
import { Libp2pRecord } from '@libp2p/record'
|
|
4
|
+
import Proto from './dht.js'
|
|
5
|
+
import type { PeerData } from '@libp2p/interfaces/peer-data'
|
|
6
|
+
|
|
7
|
+
export const MESSAGE_TYPE = Proto.Message.MessageType
|
|
8
|
+
export const CONNECTION_TYPE = Proto.Message.ConnectionType
|
|
9
|
+
export const MESSAGE_TYPE_LOOKUP = Object.keys(MESSAGE_TYPE)
|
|
10
|
+
|
|
11
|
+
type ConnectionType = 0|1|2|3|4
|
|
12
|
+
|
|
13
|
+
interface PBPeer {
|
|
14
|
+
id: Uint8Array
|
|
15
|
+
addrs: Uint8Array[]
|
|
16
|
+
connection: ConnectionType
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents a single DHT control message.
|
|
21
|
+
*/
|
|
22
|
+
export class Message {
|
|
23
|
+
public type: Proto.Message.MessageType
|
|
24
|
+
public key: Uint8Array
|
|
25
|
+
private clusterLevelRaw: number
|
|
26
|
+
public closerPeers: PeerData[]
|
|
27
|
+
public providerPeers: PeerData[]
|
|
28
|
+
public record?: Libp2pRecord
|
|
29
|
+
|
|
30
|
+
constructor (type: Proto.Message.MessageType, key: Uint8Array, level: number) {
|
|
31
|
+
if (!(key instanceof Uint8Array)) {
|
|
32
|
+
throw new Error('Key must be a Uint8Array')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.type = type
|
|
36
|
+
this.key = key
|
|
37
|
+
this.clusterLevelRaw = level
|
|
38
|
+
this.closerPeers = []
|
|
39
|
+
this.providerPeers = []
|
|
40
|
+
this.record = undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
get clusterLevel () {
|
|
47
|
+
const level = this.clusterLevelRaw - 1
|
|
48
|
+
if (level < 0) {
|
|
49
|
+
return 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return level
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set clusterLevel (level) {
|
|
56
|
+
this.clusterLevelRaw = level
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Encode into protobuf
|
|
61
|
+
*/
|
|
62
|
+
serialize () {
|
|
63
|
+
return Proto.Message.encode({
|
|
64
|
+
key: this.key,
|
|
65
|
+
type: this.type,
|
|
66
|
+
clusterLevelRaw: this.clusterLevelRaw,
|
|
67
|
+
closerPeers: this.closerPeers.map(toPbPeer),
|
|
68
|
+
providerPeers: this.providerPeers.map(toPbPeer),
|
|
69
|
+
record: this.record == null ? undefined : this.record.serialize()
|
|
70
|
+
}).finish()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Decode from protobuf
|
|
75
|
+
*/
|
|
76
|
+
static deserialize (raw: Uint8Array) {
|
|
77
|
+
const dec = Proto.Message.decode(raw)
|
|
78
|
+
|
|
79
|
+
const msg = new Message(dec.type ?? 0, dec.key ?? Uint8Array.from([]), dec.clusterLevelRaw ?? 0)
|
|
80
|
+
msg.closerPeers = dec.closerPeers.map(fromPbPeer)
|
|
81
|
+
msg.providerPeers = dec.providerPeers.map(fromPbPeer)
|
|
82
|
+
|
|
83
|
+
if (dec.record?.length != null) {
|
|
84
|
+
msg.record = Libp2pRecord.deserialize(dec.record)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return msg
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function toPbPeer (peer: PeerData) {
|
|
92
|
+
const output: PBPeer = {
|
|
93
|
+
id: peer.id.toBytes(),
|
|
94
|
+
addrs: (peer.multiaddrs ?? []).map((m) => m.bytes),
|
|
95
|
+
connection: CONNECTION_TYPE.CONNECTED
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return output
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function fromPbPeer (peer: Proto.Message.IPeer) {
|
|
102
|
+
if (peer.id == null) {
|
|
103
|
+
throw new Error('Invalid peer in message')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
id: peerIdFromBytes(peer.id),
|
|
108
|
+
multiaddrs: (peer.addrs ?? []).map((a) => new Multiaddr(a)),
|
|
109
|
+
protocols: []
|
|
110
|
+
}
|
|
111
|
+
}
|
package/src/network.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import errcode from 'err-code'
|
|
2
|
+
import { pipe } from 'it-pipe'
|
|
3
|
+
import * as lp from 'it-length-prefixed'
|
|
4
|
+
import drain from 'it-drain'
|
|
5
|
+
import first from 'it-first'
|
|
6
|
+
import { Message, MESSAGE_TYPE_LOOKUP } from './message/index.js'
|
|
7
|
+
import { EventEmitter, CustomEvent } from '@libp2p/interfaces'
|
|
8
|
+
import {
|
|
9
|
+
dialingPeerEvent,
|
|
10
|
+
sendingQueryEvent,
|
|
11
|
+
peerResponseEvent,
|
|
12
|
+
queryErrorEvent
|
|
13
|
+
} from './query/events.js'
|
|
14
|
+
import { logger } from '@libp2p/logger'
|
|
15
|
+
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
|
16
|
+
import type { AbortOptions, Dialer, Startable } from '@libp2p/interfaces'
|
|
17
|
+
import type { Logger } from '@libp2p/logger'
|
|
18
|
+
import type { Duplex } from 'it-stream-types'
|
|
19
|
+
import type { PeerData } from '@libp2p/interfaces/peer-data'
|
|
20
|
+
|
|
21
|
+
export interface NetworkOptions {
|
|
22
|
+
dialer: Dialer
|
|
23
|
+
protocol: string
|
|
24
|
+
lan: boolean
|
|
25
|
+
peerId: PeerId
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface NetworkEvents {
|
|
29
|
+
'peer': CustomEvent<PeerData>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Handle network operations for the dht
|
|
34
|
+
*/
|
|
35
|
+
export class Network extends EventEmitter<NetworkEvents> implements Startable {
|
|
36
|
+
private readonly log: Logger
|
|
37
|
+
public dialer: Dialer
|
|
38
|
+
private readonly protocol: string
|
|
39
|
+
private running: boolean
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a new network
|
|
43
|
+
*/
|
|
44
|
+
constructor (options: NetworkOptions) {
|
|
45
|
+
super()
|
|
46
|
+
|
|
47
|
+
const { dialer, protocol, lan, peerId } = options
|
|
48
|
+
this.log = logger(`libp2p:kad-dht:${lan ? 'lan' : 'wan'}:network:${peerId.toString()}`)
|
|
49
|
+
this.running = false
|
|
50
|
+
this.dialer = dialer
|
|
51
|
+
this.protocol = protocol
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Start the network
|
|
56
|
+
*/
|
|
57
|
+
async start () {
|
|
58
|
+
if (this.running) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.running = true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Stop all network activity
|
|
67
|
+
*/
|
|
68
|
+
async stop () {
|
|
69
|
+
this.running = false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Is the network online?
|
|
74
|
+
*/
|
|
75
|
+
isStarted () {
|
|
76
|
+
return this.running
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Send a request and record RTT for latency measurements
|
|
81
|
+
*/
|
|
82
|
+
async * sendRequest (to: PeerId, msg: Message, options: AbortOptions = {}) {
|
|
83
|
+
if (!this.running) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.log('sending %s to %p', MESSAGE_TYPE_LOOKUP[msg.type], to)
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
yield dialingPeerEvent({ peer: to })
|
|
91
|
+
|
|
92
|
+
const { stream } = await this.dialer.dialProtocol(to, this.protocol, options)
|
|
93
|
+
|
|
94
|
+
yield sendingQueryEvent({ to, type: msg.type })
|
|
95
|
+
|
|
96
|
+
const response = await this._writeReadMessage(stream, msg.serialize())
|
|
97
|
+
|
|
98
|
+
yield peerResponseEvent({
|
|
99
|
+
from: to,
|
|
100
|
+
messageType: response.type,
|
|
101
|
+
closer: response.closerPeers,
|
|
102
|
+
providers: response.providerPeers,
|
|
103
|
+
record: response.record
|
|
104
|
+
})
|
|
105
|
+
} catch (err: any) {
|
|
106
|
+
yield queryErrorEvent({ from: to, error: err })
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sends a message without expecting an answer
|
|
112
|
+
*/
|
|
113
|
+
async * sendMessage (to: PeerId, msg: Message, options: AbortOptions = {}) {
|
|
114
|
+
if (!this.running) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.log('sending %s to %p', MESSAGE_TYPE_LOOKUP[msg.type], to)
|
|
119
|
+
|
|
120
|
+
yield dialingPeerEvent({ peer: to })
|
|
121
|
+
|
|
122
|
+
const { stream } = await this.dialer.dialProtocol(to, this.protocol, options)
|
|
123
|
+
|
|
124
|
+
yield sendingQueryEvent({ to, type: msg.type })
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await this._writeMessage(stream, msg.serialize())
|
|
128
|
+
|
|
129
|
+
yield peerResponseEvent({ from: to, messageType: msg.type })
|
|
130
|
+
} catch (err: any) {
|
|
131
|
+
yield queryErrorEvent({ from: to, error: err })
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Write a message to the given stream
|
|
137
|
+
*/
|
|
138
|
+
async _writeMessage (stream: Duplex<Uint8Array>, msg: Uint8Array) {
|
|
139
|
+
await pipe(
|
|
140
|
+
[msg],
|
|
141
|
+
lp.encode(),
|
|
142
|
+
stream,
|
|
143
|
+
drain
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Write a message and read its response.
|
|
149
|
+
* If no response is received after the specified timeout
|
|
150
|
+
* this will error out.
|
|
151
|
+
*/
|
|
152
|
+
async _writeReadMessage (stream: Duplex<Uint8Array>, msg: Uint8Array) {
|
|
153
|
+
const res = await pipe(
|
|
154
|
+
[msg],
|
|
155
|
+
lp.encode(),
|
|
156
|
+
stream,
|
|
157
|
+
lp.decode(),
|
|
158
|
+
async source => {
|
|
159
|
+
const buf = await first(source)
|
|
160
|
+
|
|
161
|
+
if (buf != null) {
|
|
162
|
+
return buf
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
throw errcode(new Error('No message received'), 'ERR_NO_MESSAGE_RECEIVED')
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
const message = Message.deserialize(res)
|
|
170
|
+
|
|
171
|
+
// tell any listeners about new peers we've seen
|
|
172
|
+
message.closerPeers.forEach(peerData => {
|
|
173
|
+
this.dispatchEvent(new CustomEvent('peer', {
|
|
174
|
+
detail: peerData
|
|
175
|
+
}))
|
|
176
|
+
})
|
|
177
|
+
message.providerPeers.forEach(peerData => {
|
|
178
|
+
this.dispatchEvent(new CustomEvent('peer', {
|
|
179
|
+
detail: peerData
|
|
180
|
+
}))
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
return message
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A list of unique peers.
|
|
5
|
+
*/
|
|
6
|
+
export class PeerList {
|
|
7
|
+
private readonly list: PeerId[]
|
|
8
|
+
|
|
9
|
+
constructor () {
|
|
10
|
+
this.list = []
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Add a new peer. Returns `true` if it was a new one
|
|
15
|
+
*/
|
|
16
|
+
push (peerId: PeerId) {
|
|
17
|
+
if (!this.has(peerId)) {
|
|
18
|
+
this.list.push(peerId)
|
|
19
|
+
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if this PeerData is already in here
|
|
28
|
+
*/
|
|
29
|
+
has (peerId: PeerId) {
|
|
30
|
+
const match = this.list.find((i) => i.equals(peerId))
|
|
31
|
+
return Boolean(match)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get the list as an array
|
|
36
|
+
*/
|
|
37
|
+
toArray () {
|
|
38
|
+
return this.list.slice()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Remove the last element
|
|
43
|
+
*/
|
|
44
|
+
pop () {
|
|
45
|
+
return this.list.pop()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The length of the list
|
|
50
|
+
*/
|
|
51
|
+
get length () {
|
|
52
|
+
return this.list.length
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as utils from '../utils.js'
|
|
2
|
+
import pMap from 'p-map'
|
|
3
|
+
import { compare as uint8ArrayCompare } from 'uint8arrays/compare'
|
|
4
|
+
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
5
|
+
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
|
6
|
+
|
|
7
|
+
interface PeerDistance {
|
|
8
|
+
peerId: PeerId
|
|
9
|
+
distance: Uint8Array
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Maintains a list of peerIds sorted by distance from a DHT key.
|
|
14
|
+
*/
|
|
15
|
+
export class PeerDistanceList {
|
|
16
|
+
/**
|
|
17
|
+
* The DHT key from which distance is calculated
|
|
18
|
+
*/
|
|
19
|
+
private readonly originDhtKey: Uint8Array
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The maximum size of the list
|
|
23
|
+
*/
|
|
24
|
+
private readonly capacity: number
|
|
25
|
+
|
|
26
|
+
private peerDistances: PeerDistance[]
|
|
27
|
+
|
|
28
|
+
constructor (originDhtKey: Uint8Array, capacity: number) {
|
|
29
|
+
this.originDhtKey = originDhtKey
|
|
30
|
+
this.capacity = capacity
|
|
31
|
+
this.peerDistances = []
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The length of the list
|
|
36
|
+
*/
|
|
37
|
+
get length () {
|
|
38
|
+
return this.peerDistances.length
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The peerIds in the list, in order of distance from the origin key
|
|
43
|
+
*/
|
|
44
|
+
get peers () {
|
|
45
|
+
return this.peerDistances.map(pd => pd.peerId)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Add a peerId to the list.
|
|
50
|
+
*/
|
|
51
|
+
async add (peerId: PeerId) {
|
|
52
|
+
if (this.peerDistances.find(pd => pd.peerId.equals(peerId)) != null) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const dhtKey = await utils.convertPeerId(peerId)
|
|
57
|
+
const el = {
|
|
58
|
+
peerId,
|
|
59
|
+
distance: uint8ArrayXor(this.originDhtKey, dhtKey)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.peerDistances.push(el)
|
|
63
|
+
this.peerDistances.sort((a, b) => uint8ArrayCompare(a.distance, b.distance))
|
|
64
|
+
this.peerDistances = this.peerDistances.slice(0, this.capacity)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Indicates whether any of the peerIds passed as a parameter are closer
|
|
69
|
+
* to the origin key than the furthest peerId in the PeerDistanceList.
|
|
70
|
+
*/
|
|
71
|
+
async anyCloser (peerIds: PeerId[]) {
|
|
72
|
+
if (peerIds.length === 0) {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (this.length === 0) {
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const dhtKeys = await pMap(peerIds, async (peerId) => await utils.convertPeerId(peerId))
|
|
81
|
+
const furthestDistance = this.peerDistances[this.peerDistances.length - 1].distance
|
|
82
|
+
|
|
83
|
+
for (const dhtKey of dhtKeys) {
|
|
84
|
+
const keyDistance = uint8ArrayXor(this.originDhtKey, dhtKey)
|
|
85
|
+
|
|
86
|
+
if (uint8ArrayCompare(keyDistance, furthestDistance) < 0) {
|
|
87
|
+
return true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
}
|