@libp2p/peer-store 7.0.2 → 8.0.0
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/README.md +0 -170
- package/dist/index.min.js +14 -14
- package/dist/src/errors.d.ts +0 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +1 -2
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +23 -25
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +86 -88
- package/dist/src/index.js.map +1 -1
- package/dist/src/pb/peer.d.ts +28 -9
- package/dist/src/pb/peer.d.ts.map +1 -1
- package/dist/src/pb/peer.js +147 -31
- package/dist/src/pb/peer.js.map +1 -1
- package/dist/src/store.d.ts +18 -28
- package/dist/src/store.d.ts.map +1 -1
- package/dist/src/store.js +77 -147
- package/dist/src/store.js.map +1 -1
- package/dist/src/utils/bytes-to-peer.d.ts +4 -0
- package/dist/src/utils/bytes-to-peer.d.ts.map +1 -0
- package/dist/src/utils/bytes-to-peer.js +33 -0
- package/dist/src/utils/bytes-to-peer.js.map +1 -0
- package/dist/src/utils/dedupe-addresses.d.ts +6 -0
- package/dist/src/utils/dedupe-addresses.d.ts.map +1 -0
- package/dist/src/utils/dedupe-addresses.js +41 -0
- package/dist/src/utils/dedupe-addresses.js.map +1 -0
- package/dist/src/utils/peer-data-to-datastore-peer.d.ts +5 -0
- package/dist/src/utils/peer-data-to-datastore-peer.d.ts.map +1 -0
- package/dist/src/utils/peer-data-to-datastore-peer.js +92 -0
- package/dist/src/utils/peer-data-to-datastore-peer.js.map +1 -0
- package/dist/src/utils/peer-id-to-datastore-key.d.ts +5 -0
- package/dist/src/utils/peer-id-to-datastore-key.d.ts.map +1 -0
- package/dist/src/utils/peer-id-to-datastore-key.js +13 -0
- package/dist/src/utils/peer-id-to-datastore-key.js.map +1 -0
- package/dist/src/utils/to-peer-pb.d.ts +10 -0
- package/dist/src/utils/to-peer-pb.d.ts.map +1 -0
- package/dist/src/utils/to-peer-pb.js +182 -0
- package/dist/src/utils/to-peer-pb.js.map +1 -0
- package/dist/typedoc-urls.json +13 -2
- package/package.json +8 -10
- package/src/errors.ts +1 -2
- package/src/index.ts +97 -103
- package/src/pb/peer.proto +10 -7
- package/src/pb/peer.ts +187 -37
- package/src/store.ts +102 -189
- package/src/utils/bytes-to-peer.ts +41 -0
- package/src/utils/dedupe-addresses.ts +51 -0
- package/src/utils/peer-data-to-datastore-peer.ts +116 -0
- package/src/utils/peer-id-to-datastore-key.ts +15 -0
- package/src/utils/to-peer-pb.ts +237 -0
- package/dist/src/address-book.d.ts +0 -29
- package/dist/src/address-book.d.ts.map +0 -1
- package/dist/src/address-book.js +0 -304
- package/dist/src/address-book.js.map +0 -1
- package/dist/src/key-book.d.ts +0 -21
- package/dist/src/key-book.d.ts.map +0 -1
- package/dist/src/key-book.js +0 -121
- package/dist/src/key-book.js.map +0 -1
- package/dist/src/metadata-book.d.ts +0 -28
- package/dist/src/metadata-book.d.ts.map +0 -1
- package/dist/src/metadata-book.js +0 -211
- package/dist/src/metadata-book.js.map +0 -1
- package/dist/src/pb/tags.d.ts +0 -21
- package/dist/src/pb/tags.d.ts.map +0 -1
- package/dist/src/pb/tags.js +0 -111
- package/dist/src/pb/tags.js.map +0 -1
- package/dist/src/proto-book.d.ts +0 -18
- package/dist/src/proto-book.d.ts.map +0 -1
- package/dist/src/proto-book.js +0 -199
- package/dist/src/proto-book.js.map +0 -1
- package/src/address-book.ts +0 -367
- package/src/key-book.ts +0 -140
- package/src/metadata-book.ts +0 -244
- package/src/pb/tags.proto +0 -11
- package/src/pb/tags.ts +0 -145
- package/src/proto-book.ts +0 -234
package/src/store.ts
CHANGED
|
@@ -1,241 +1,154 @@
|
|
|
1
|
-
import { logger } from '@libp2p/logger'
|
|
2
1
|
import { peerIdFromBytes } from '@libp2p/peer-id'
|
|
3
|
-
import { CodeError } from '@libp2p/interfaces/errors'
|
|
4
|
-
import { codes } from './errors.js'
|
|
5
|
-
import { Key } from 'interface-datastore/key'
|
|
6
2
|
import { base32 } from 'multiformats/bases/base32'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import mortice from 'mortice'
|
|
10
|
-
import { equals as uint8arrayEquals } from 'uint8arrays/equals'
|
|
11
|
-
import type { Peer } from '@libp2p/interface-peer-store'
|
|
3
|
+
import { Peer as PeerPB } from './pb/peer.js'
|
|
4
|
+
import type { Peer, PeerData } from '@libp2p/interface-peer-store'
|
|
12
5
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
13
|
-
import type { PersistentPeerStoreComponents } from './index.js'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
lock: {
|
|
31
|
-
readLock: () => Promise<() => void>
|
|
32
|
-
writeLock: () => Promise<() => void>
|
|
33
|
-
}
|
|
6
|
+
import type { AddressFilter, PersistentPeerStoreComponents, PersistentPeerStoreInit } from './index.js'
|
|
7
|
+
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
8
|
+
import { NAMESPACE_COMMON, peerIdToDatastoreKey } from './utils/peer-id-to-datastore-key.js'
|
|
9
|
+
import { bytesToPeer } from './utils/bytes-to-peer.js'
|
|
10
|
+
import { CodeError } from '@libp2p/interfaces/errors'
|
|
11
|
+
import { codes } from './errors.js'
|
|
12
|
+
import type { Datastore } from 'interface-datastore'
|
|
13
|
+
import type { PeerUpdate as PeerUpdateExternal } from '@libp2p/interface-libp2p'
|
|
14
|
+
import mortice, { Mortice } from 'mortice'
|
|
15
|
+
import { toPeerPB } from './utils/to-peer-pb.js'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Event detail emitted when peer data changes
|
|
19
|
+
*/
|
|
20
|
+
export interface PeerUpdate extends PeerUpdateExternal {
|
|
21
|
+
updated: boolean
|
|
34
22
|
}
|
|
35
23
|
|
|
36
24
|
export class PersistentStore {
|
|
37
|
-
private readonly
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
private readonly peerId: PeerId
|
|
26
|
+
private readonly datastore: Datastore
|
|
27
|
+
public readonly lock: Mortice
|
|
28
|
+
private readonly addressFilter?: AddressFilter
|
|
29
|
+
|
|
30
|
+
constructor (components: PersistentPeerStoreComponents, init: PersistentPeerStoreInit = {}) {
|
|
31
|
+
this.peerId = components.peerId
|
|
32
|
+
this.datastore = components.datastore
|
|
33
|
+
this.addressFilter = init.addressFilter
|
|
42
34
|
this.lock = mortice({
|
|
43
35
|
name: 'peer-store',
|
|
44
36
|
singleProcess: true
|
|
45
37
|
})
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
_peerIdToDatastoreKey (peerId: PeerId): Key {
|
|
49
|
-
if (peerId.type == null) {
|
|
50
|
-
log.error('peerId must be an instance of peer-id to store data')
|
|
51
|
-
throw new CodeError('peerId must be an instance of peer-id', codes.ERR_INVALID_PARAMETERS)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const b32key = peerId.toCID().toString()
|
|
55
|
-
return new Key(`${NAMESPACE_COMMON}${b32key}`)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
40
|
async has (peerId: PeerId): Promise<boolean> {
|
|
59
|
-
return await this.
|
|
41
|
+
return await this.datastore.has(peerIdToDatastoreKey(peerId))
|
|
60
42
|
}
|
|
61
43
|
|
|
62
44
|
async delete (peerId: PeerId): Promise<void> {
|
|
63
|
-
|
|
45
|
+
if (this.peerId.equals(peerId)) {
|
|
46
|
+
throw new CodeError('Cannot delete self peer', codes.ERR_INVALID_PARAMETERS)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await this.datastore.delete(peerIdToDatastoreKey(peerId))
|
|
64
50
|
}
|
|
65
51
|
|
|
66
52
|
async load (peerId: PeerId): Promise<Peer> {
|
|
67
|
-
const buf = await this.
|
|
68
|
-
const peer = PeerPB.decode(buf)
|
|
69
|
-
const metadata = new Map()
|
|
53
|
+
const buf = await this.datastore.get(peerIdToDatastoreKey(peerId))
|
|
70
54
|
|
|
71
|
-
|
|
72
|
-
metadata.set(meta.key, meta.value)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
...peer,
|
|
77
|
-
id: peerId,
|
|
78
|
-
addresses: peer.addresses.map(({ multiaddr: ma, isCertified }) => {
|
|
79
|
-
return {
|
|
80
|
-
multiaddr: multiaddr(ma),
|
|
81
|
-
isCertified: isCertified ?? false
|
|
82
|
-
}
|
|
83
|
-
}),
|
|
84
|
-
metadata,
|
|
85
|
-
pubKey: peer.pubKey ?? undefined,
|
|
86
|
-
peerRecordEnvelope: peer.peerRecordEnvelope ?? undefined
|
|
87
|
-
}
|
|
55
|
+
return await bytesToPeer(peerId, buf)
|
|
88
56
|
}
|
|
89
57
|
|
|
90
|
-
async save (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// dedupe addresses
|
|
97
|
-
const addressSet = new Set()
|
|
98
|
-
const addresses = peer.addresses
|
|
99
|
-
.filter(address => {
|
|
100
|
-
if (addressSet.has(address.multiaddr.toString())) {
|
|
101
|
-
return false
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
addressSet.add(address.multiaddr.toString())
|
|
105
|
-
return true
|
|
106
|
-
})
|
|
107
|
-
.sort((a, b) => {
|
|
108
|
-
return a.multiaddr.toString().localeCompare(b.multiaddr.toString())
|
|
109
|
-
})
|
|
110
|
-
.map(({ multiaddr, isCertified }) => ({
|
|
111
|
-
multiaddr: multiaddr.bytes,
|
|
112
|
-
isCertified
|
|
113
|
-
}))
|
|
114
|
-
|
|
115
|
-
const metadata: Metadata[] = []
|
|
116
|
-
|
|
117
|
-
;[...peer.metadata.keys()].sort().forEach(key => {
|
|
118
|
-
const value = peer.metadata.get(key)
|
|
119
|
-
|
|
120
|
-
if (value != null) {
|
|
121
|
-
metadata.push({ key, value })
|
|
122
|
-
}
|
|
123
|
-
})
|
|
58
|
+
async save (peerId: PeerId, data: PeerData): Promise<PeerUpdate> {
|
|
59
|
+
const {
|
|
60
|
+
existingBuf,
|
|
61
|
+
existingPeer
|
|
62
|
+
} = await this.#findExistingPeer(peerId)
|
|
124
63
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
protocols: peer.protocols.sort(),
|
|
128
|
-
pubKey: peer.pubKey,
|
|
129
|
-
metadata,
|
|
130
|
-
peerRecordEnvelope: peer.peerRecordEnvelope
|
|
64
|
+
const peerPb: PeerPB = await toPeerPB(peerId, data, 'patch', {
|
|
65
|
+
addressFilter: this.addressFilter
|
|
131
66
|
})
|
|
132
67
|
|
|
133
|
-
await this
|
|
134
|
-
|
|
135
|
-
return await this.load(peer.id)
|
|
68
|
+
return await this.#saveIfDifferent(peerId, peerPb, existingBuf, existingPeer)
|
|
136
69
|
}
|
|
137
70
|
|
|
138
|
-
async patch (peerId: PeerId, data: Partial<
|
|
139
|
-
const
|
|
71
|
+
async patch (peerId: PeerId, data: Partial<PeerData>): Promise<PeerUpdate> {
|
|
72
|
+
const {
|
|
73
|
+
existingBuf,
|
|
74
|
+
existingPeer
|
|
75
|
+
} = await this.#findExistingPeer(peerId)
|
|
76
|
+
|
|
77
|
+
const peerPb: PeerPB = await toPeerPB(peerId, data, 'patch', {
|
|
78
|
+
addressFilter: this.addressFilter,
|
|
79
|
+
existingPeer
|
|
80
|
+
})
|
|
140
81
|
|
|
141
|
-
return await this
|
|
82
|
+
return await this.#saveIfDifferent(peerId, peerPb, existingBuf, existingPeer)
|
|
142
83
|
}
|
|
143
84
|
|
|
144
|
-
async
|
|
145
|
-
|
|
85
|
+
async merge (peerId: PeerId, data: PeerData): Promise<PeerUpdate> {
|
|
86
|
+
const {
|
|
87
|
+
existingBuf,
|
|
88
|
+
existingPeer
|
|
89
|
+
} = await this.#findExistingPeer(peerId)
|
|
146
90
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
throw err
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
peer = { id: peerId, addresses: [], protocols: [], metadata: new Map() }
|
|
155
|
-
}
|
|
91
|
+
const peerPb: PeerPB = await toPeerPB(peerId, data, 'merge', {
|
|
92
|
+
addressFilter: this.addressFilter,
|
|
93
|
+
existingPeer
|
|
94
|
+
})
|
|
156
95
|
|
|
157
|
-
return await this
|
|
96
|
+
return await this.#saveIfDifferent(peerId, peerPb, existingBuf, existingPeer)
|
|
158
97
|
}
|
|
159
98
|
|
|
160
|
-
async
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
id
|
|
165
|
-
|
|
166
|
-
|
|
99
|
+
async * all (): AsyncGenerator<Peer, void, unknown> {
|
|
100
|
+
for await (const { key, value } of this.datastore.query({
|
|
101
|
+
prefix: NAMESPACE_COMMON
|
|
102
|
+
})) {
|
|
103
|
+
// /peers/${peer-id-as-libp2p-key-cid-string-in-base-32}
|
|
104
|
+
const base32Str = key.toString().split('/')[2]
|
|
105
|
+
const buf = base32.decode(base32Str)
|
|
106
|
+
const peerId = peerIdFromBytes(buf)
|
|
167
107
|
|
|
168
|
-
|
|
169
|
-
|
|
108
|
+
if (peerId.equals(this.peerId)) {
|
|
109
|
+
// Skip self peer if present
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
170
112
|
|
|
171
|
-
|
|
113
|
+
yield bytesToPeer(peerId, value)
|
|
114
|
+
}
|
|
172
115
|
}
|
|
173
116
|
|
|
174
|
-
async
|
|
175
|
-
/** @type {Peer} */
|
|
176
|
-
let peer
|
|
177
|
-
|
|
117
|
+
async #findExistingPeer (peerId: PeerId): Promise<{ existingBuf?: Uint8Array, existingPeer?: Peer }> {
|
|
178
118
|
try {
|
|
179
|
-
|
|
119
|
+
const existingBuf = await this.datastore.get(peerIdToDatastoreKey(peerId))
|
|
120
|
+
const existingPeer = await bytesToPeer(peerId, existingBuf)
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
existingBuf,
|
|
124
|
+
existingPeer
|
|
125
|
+
}
|
|
180
126
|
} catch (err: any) {
|
|
181
|
-
if (err.code !==
|
|
127
|
+
if (err.code !== 'ERR_NOT_FOUND') {
|
|
182
128
|
throw err
|
|
183
129
|
}
|
|
184
|
-
|
|
185
|
-
peer = { id: peerId, addresses: [], protocols: [], metadata: new Map() }
|
|
186
130
|
}
|
|
187
131
|
|
|
188
|
-
return
|
|
132
|
+
return {}
|
|
189
133
|
}
|
|
190
134
|
|
|
191
|
-
async
|
|
192
|
-
|
|
193
|
-
// favour of the supplied versions
|
|
194
|
-
const addresses = new Map<string, boolean>()
|
|
195
|
-
|
|
196
|
-
peer.addresses.forEach((addr) => {
|
|
197
|
-
addresses.set(addr.multiaddr.toString(), addr.isCertified)
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
;(data.addresses ?? []).forEach(addr => {
|
|
201
|
-
const addrString = addr.multiaddr.toString()
|
|
202
|
-
const isAlreadyCertified = Boolean(addresses.get(addrString))
|
|
203
|
-
|
|
204
|
-
const isCertified = isAlreadyCertified || addr.isCertified
|
|
135
|
+
async #saveIfDifferent (peerId: PeerId, peer: PeerPB, existingBuf?: Uint8Array, existingPeer?: Peer): Promise<PeerUpdate> {
|
|
136
|
+
const buf = PeerPB.encode(peer)
|
|
205
137
|
|
|
206
|
-
|
|
207
|
-
|
|
138
|
+
if (existingBuf != null && uint8ArrayEquals(buf, existingBuf)) {
|
|
139
|
+
return {
|
|
140
|
+
peer: await bytesToPeer(peerId, buf),
|
|
141
|
+
previous: existingPeer,
|
|
142
|
+
updated: false
|
|
143
|
+
}
|
|
144
|
+
}
|
|
208
145
|
|
|
209
|
-
|
|
210
|
-
id: peerId,
|
|
211
|
-
addresses: Array.from(addresses.entries()).map(([addrStr, isCertified]) => {
|
|
212
|
-
return {
|
|
213
|
-
multiaddr: multiaddr(addrStr),
|
|
214
|
-
isCertified
|
|
215
|
-
}
|
|
216
|
-
}),
|
|
217
|
-
protocols: Array.from(new Set([
|
|
218
|
-
...(peer.protocols ?? []),
|
|
219
|
-
...(data.protocols ?? [])
|
|
220
|
-
])),
|
|
221
|
-
metadata: new Map([
|
|
222
|
-
...(peer.metadata?.entries() ?? []),
|
|
223
|
-
...(data.metadata?.entries() ?? [])
|
|
224
|
-
]),
|
|
225
|
-
pubKey: data.pubKey ?? (peer != null ? peer.pubKey : undefined),
|
|
226
|
-
peerRecordEnvelope: data.peerRecordEnvelope ?? (peer != null ? peer.peerRecordEnvelope : undefined)
|
|
227
|
-
})
|
|
228
|
-
}
|
|
146
|
+
await this.datastore.put(peerIdToDatastoreKey(peerId), buf)
|
|
229
147
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
// /peers/${peer-id-as-libp2p-key-cid-string-in-base-32}
|
|
235
|
-
const base32Str = key.toString().split('/')[2]
|
|
236
|
-
const buf = base32.decode(base32Str)
|
|
237
|
-
|
|
238
|
-
yield this.load(peerIdFromBytes(buf))
|
|
148
|
+
return {
|
|
149
|
+
peer: await bytesToPeer(peerId, buf),
|
|
150
|
+
previous: existingPeer,
|
|
151
|
+
updated: true
|
|
239
152
|
}
|
|
240
153
|
}
|
|
241
154
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { multiaddr } from '@multiformats/multiaddr'
|
|
2
|
+
import { Peer as PeerPB } from '../pb/peer.js'
|
|
3
|
+
import type { Peer, Tag } from '@libp2p/interface-peer-store'
|
|
4
|
+
import { createFromPubKey } from '@libp2p/peer-id-factory'
|
|
5
|
+
import { unmarshalPublicKey } from '@libp2p/crypto/keys'
|
|
6
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
7
|
+
|
|
8
|
+
export async function bytesToPeer (peerId: PeerId, buf: Uint8Array): Promise<Peer> {
|
|
9
|
+
const peer = PeerPB.decode(buf)
|
|
10
|
+
|
|
11
|
+
if (peer.publicKey != null && peerId.publicKey == null) {
|
|
12
|
+
peerId = await createFromPubKey(unmarshalPublicKey(peer.publicKey))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const tags = new Map<string, Tag>()
|
|
16
|
+
|
|
17
|
+
// remove any expired tags
|
|
18
|
+
const now = BigInt(Date.now())
|
|
19
|
+
|
|
20
|
+
for (const [key, tag] of peer.tags.entries()) {
|
|
21
|
+
if (tag.expiry != null && tag.expiry < now) {
|
|
22
|
+
continue
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
tags.set(key, tag)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
...peer,
|
|
30
|
+
id: peerId,
|
|
31
|
+
addresses: peer.addresses.map(({ multiaddr: ma, isCertified }) => {
|
|
32
|
+
return {
|
|
33
|
+
multiaddr: multiaddr(ma),
|
|
34
|
+
isCertified: isCertified ?? false
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
37
|
+
metadata: peer.metadata,
|
|
38
|
+
peerRecordEnvelope: peer.peerRecordEnvelope ?? undefined,
|
|
39
|
+
tags
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { isMultiaddr, multiaddr } from '@multiformats/multiaddr'
|
|
2
|
+
import type { Address as AddressPB } from '../pb/peer.js'
|
|
3
|
+
import type { Address } from '@libp2p/interface-peer-store'
|
|
4
|
+
import type { AddressFilter } from '../index.js'
|
|
5
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
6
|
+
import { CodeError } from '@libp2p/interfaces/errors'
|
|
7
|
+
import { codes } from '../errors.js'
|
|
8
|
+
|
|
9
|
+
export async function dedupeFilterAndSortAddresses (peerId: PeerId, filter: AddressFilter, addresses: Array<Address | AddressPB | undefined>): Promise<AddressPB[]> {
|
|
10
|
+
const addressMap = new Map<string, Address>()
|
|
11
|
+
|
|
12
|
+
for (const addr of addresses) {
|
|
13
|
+
if (addr == null) {
|
|
14
|
+
continue
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (addr.multiaddr instanceof Uint8Array) {
|
|
18
|
+
addr.multiaddr = multiaddr(addr.multiaddr)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!isMultiaddr(addr.multiaddr)) {
|
|
22
|
+
throw new CodeError('Multiaddr was invalid', codes.ERR_INVALID_PARAMETERS)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!(await filter(peerId, addr.multiaddr))) {
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isCertified = addr.isCertified ?? false
|
|
30
|
+
const maStr = addr.multiaddr.toString()
|
|
31
|
+
const existingAddr = addressMap.get(maStr)
|
|
32
|
+
|
|
33
|
+
if (existingAddr != null) {
|
|
34
|
+
addr.isCertified = existingAddr.isCertified || isCertified
|
|
35
|
+
} else {
|
|
36
|
+
addressMap.set(maStr, {
|
|
37
|
+
multiaddr: addr.multiaddr,
|
|
38
|
+
isCertified
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return [...addressMap.values()]
|
|
44
|
+
.sort((a, b) => {
|
|
45
|
+
return a.multiaddr.toString().localeCompare(b.multiaddr.toString())
|
|
46
|
+
})
|
|
47
|
+
.map(({ isCertified, multiaddr }) => ({
|
|
48
|
+
isCertified,
|
|
49
|
+
multiaddr: multiaddr.bytes
|
|
50
|
+
}))
|
|
51
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
|
|
2
|
+
import { CodeError } from '@libp2p/interfaces/errors'
|
|
3
|
+
import { codes } from '../errors.js'
|
|
4
|
+
import { isMultiaddr } from '@multiformats/multiaddr'
|
|
5
|
+
import type { Peer as PeerPB } from '../pb/peer.js'
|
|
6
|
+
import { equals as uint8arrayEquals } from 'uint8arrays/equals'
|
|
7
|
+
import type { PeerData } from '@libp2p/interface-peer-store'
|
|
8
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
9
|
+
|
|
10
|
+
export function toDatastorePeer (peerId: PeerId, data: PeerData): PeerPB {
|
|
11
|
+
if (data == null) {
|
|
12
|
+
throw new CodeError('Invalid PeerData', codes.ERR_INVALID_PARAMETERS)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (data.publicKey != null && peerId.publicKey != null && !uint8arrayEquals(data.publicKey, peerId.publicKey)) {
|
|
16
|
+
throw new CodeError('publicKey bytes do not match peer id publicKey bytes', codes.ERR_INVALID_PARAMETERS)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// merge addresses and multiaddrs, and dedupe
|
|
20
|
+
const addressSet = new Set()
|
|
21
|
+
|
|
22
|
+
const output: PeerPB = {
|
|
23
|
+
addresses: (data.addresses ?? [])
|
|
24
|
+
.concat((data.multiaddrs ?? []).map(multiaddr => ({ multiaddr, isCertified: false })))
|
|
25
|
+
.filter(address => {
|
|
26
|
+
if (!isMultiaddr(address.multiaddr)) {
|
|
27
|
+
throw new CodeError('Invalid mulitaddr', codes.ERR_INVALID_PARAMETERS)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (addressSet.has(address.multiaddr.toString())) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
addressSet.add(address.multiaddr.toString())
|
|
35
|
+
return true
|
|
36
|
+
})
|
|
37
|
+
.sort((a, b) => {
|
|
38
|
+
return a.multiaddr.toString().localeCompare(b.multiaddr.toString())
|
|
39
|
+
})
|
|
40
|
+
.map(({ multiaddr, isCertified }) => ({
|
|
41
|
+
multiaddr: multiaddr.bytes,
|
|
42
|
+
isCertified
|
|
43
|
+
})),
|
|
44
|
+
protocols: (data.protocols ?? []).sort(),
|
|
45
|
+
metadata: new Map(),
|
|
46
|
+
tags: new Map(),
|
|
47
|
+
publicKey: data.publicKey,
|
|
48
|
+
peerRecordEnvelope: data.peerRecordEnvelope
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// remove invalid metadata
|
|
52
|
+
if (data.metadata != null) {
|
|
53
|
+
const metadataEntries = data.metadata instanceof Map ? data.metadata.entries() : Object.entries(data.metadata)
|
|
54
|
+
|
|
55
|
+
for (const [key, value] of metadataEntries) {
|
|
56
|
+
if (typeof key !== 'string') {
|
|
57
|
+
throw new CodeError('Peer metadata keys must be strings', codes.ERR_INVALID_PARAMETERS)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (value == null) {
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!(value instanceof Uint8Array)) {
|
|
65
|
+
throw new CodeError('Peer metadata values must be Uint8Arrays', codes.ERR_INVALID_PARAMETERS)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
output.metadata.set(key, value)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (data.tags != null) {
|
|
73
|
+
const tagsEntries = data.tags instanceof Map ? data.tags.entries() : Object.entries(data.tags)
|
|
74
|
+
|
|
75
|
+
for (const [key, value] of tagsEntries) {
|
|
76
|
+
if (typeof key !== 'string') {
|
|
77
|
+
throw new CodeError('Peer tag keys must be strings', codes.ERR_INVALID_PARAMETERS)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (value == null) {
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tag = {
|
|
85
|
+
name: key,
|
|
86
|
+
ttl: value.ttl,
|
|
87
|
+
value: value.value ?? 0
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (tag.value < 0 || tag.value > 100) {
|
|
91
|
+
throw new CodeError('Tag value must be between 0-100', codes.ERR_INVALID_PARAMETERS)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (parseInt(`${tag.value}`, 10) !== tag.value) {
|
|
95
|
+
throw new CodeError('Tag value must be an integer', codes.ERR_INVALID_PARAMETERS)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (tag.ttl != null) {
|
|
99
|
+
if (tag.ttl < 0) {
|
|
100
|
+
throw new CodeError('Tag ttl must be between greater than 0', codes.ERR_INVALID_PARAMETERS)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (parseInt(`${tag.ttl}`, 10) !== tag.ttl) {
|
|
104
|
+
throw new CodeError('Tag ttl must be an integer', codes.ERR_INVALID_PARAMETERS)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
output.tags.set(tag.name, {
|
|
109
|
+
value: tag.value,
|
|
110
|
+
expiry: tag.ttl == null ? undefined : BigInt(Date.now() + tag.ttl)
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return output
|
|
116
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CodeError } from '@libp2p/interfaces/errors'
|
|
2
|
+
import { codes } from '../errors.js'
|
|
3
|
+
import { Key } from 'interface-datastore/key'
|
|
4
|
+
import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
|
|
5
|
+
|
|
6
|
+
export const NAMESPACE_COMMON = '/peers/'
|
|
7
|
+
|
|
8
|
+
export function peerIdToDatastoreKey (peerId: PeerId): Key {
|
|
9
|
+
if (!isPeerId(peerId) || peerId.type == null) {
|
|
10
|
+
throw new CodeError('Invalid PeerId', codes.ERR_INVALID_PARAMETERS)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const b32key = peerId.toCID().toString()
|
|
14
|
+
return new Key(`${NAMESPACE_COMMON}${b32key}`)
|
|
15
|
+
}
|