webpeerjs 0.0.1

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.
@@ -0,0 +1,1600 @@
1
+ import { Peer } from '#/pubsub-peer-discovery/peer.js';
2
+ import { Key } from 'interface-datastore';
3
+ import { sha256 } from 'multiformats/hashes/sha2';
4
+ import { createLibp2p } from 'libp2p';
5
+ import { IDBDatastore } from 'datastore-idb';
6
+ import { webTransport } from '@libp2p/webtransport';
7
+ import { noise } from '@chainsafe/libp2p-noise';
8
+ import { yamux } from '@chainsafe/libp2p-yamux';
9
+ import { pubsubPeerDiscovery } from '@libp2p/pubsub-peer-discovery';
10
+ import { circuitRelayTransport } from '@libp2p/circuit-relay-v2';
11
+ import { gossipsub } from '@chainsafe/libp2p-gossipsub';
12
+ import { identify, identifyPush } from '@libp2p/identify';
13
+ import { multiaddr } from '@multiformats/multiaddr';
14
+ import { kadDHT, removePrivateAddressesMapper } from '@libp2p/kad-dht';
15
+ import { simpleMetrics } from '@libp2p/simple-metrics';
16
+
17
+ const prefix$1 = 'webpeerjs';
18
+ const CONFIG_PREFIX = prefix$1;
19
+ const CONFIG_DBSTORE_PATH = prefix$1+'-dbstore';
20
+ const CONFIG_MAX_CONNECTIONS = 50;
21
+ const CONFIG_MIN_CONNECTIONS = 0;
22
+ const CONFIG_DISCOVER_RELAYS = 2;
23
+ const CONFIG_PEER_DISCOVERY_UNIVERSAL_CONNECTIVITY = 'universal-connectivity-browser-peer-discovery';
24
+ const CONFIG_PUBSUB_PEER_DISCOVERY = ['_peer-discovery._p2p._pubsub',CONFIG_PEER_DISCOVERY_UNIVERSAL_CONNECTIVITY,prefix$1+'-peer-discovery'];
25
+
26
+ const CONFIG_KNOWN_BOOTSTRAP_PEERS_ADDRS = [
27
+ {
28
+ "Peers": [
29
+ {
30
+ "Addrs": [
31
+ "/ip4/147.28.186.157/udp/9091/quic-v1",
32
+ "/ip4/147.28.186.157/udp/9090/webrtc-direct/certhash/uEiBbC9bbdvraVWDvcvCEdJAWDymmUqiJQ964FuyEq0hELw"
33
+ ],
34
+ "ID": "12D3KooWGahRw3ZnM4gAyd9FK75v4Bp5keFYTvkcAwhpEm28wbV3",
35
+ "Schema": "peer"
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "Peers": [
41
+ {
42
+ "Addrs": [
43
+ "/ip6/2604:1380:4642:6600::3/udp/9095/quic-v1/webtransport/certhash/uEiCU6MjDlUhqtik_vc8Ps5_MJtGhJKn-XSqvuzn8SJGL9A/certhash/uEiDlk15VyYoXwTaB608Y80ch3OptpMiKFblYdduSVLy2sQ",
44
+ "/ip4/147.28.186.157/udp/9095/quic-v1",
45
+ "/ip6/2604:1380:4642:6600::3/udp/9095/quic-v1",
46
+ "/ip4/147.28.186.157/udp/9095/quic-v1/webtransport/certhash/uEiCU6MjDlUhqtik_vc8Ps5_MJtGhJKn-XSqvuzn8SJGL9A/certhash/uEiDlk15VyYoXwTaB608Y80ch3OptpMiKFblYdduSVLy2sQ"
47
+ ],
48
+ "ID": "12D3KooWFhXabKDwALpzqMbto94sB7rvmZ6M28hs9Y9xSopDKwQr",
49
+ "Schema": "peer"
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ "Peers": [
55
+ {
56
+ "Addrs": [
57
+ "/ip6/2607:f2f8:a880:0:5054:ff:fe9f:4913/udp/4001/quic-v1/webtransport/certhash/uEiD84ZvAnGWTQx_WlOAqreebO036a5RRB5zfJBo9QJfDBA/certhash/uEiAOMkIVxeNye76-f5ADnLCSNqNlnhOYdkwyRlqLFbhIkQ",
58
+ "/ip6/2607:f2f8:a880::70/udp/4001/quic-v1/webtransport/certhash/uEiD84ZvAnGWTQx_WlOAqreebO036a5RRB5zfJBo9QJfDBA/certhash/uEiAOMkIVxeNye76-f5ADnLCSNqNlnhOYdkwyRlqLFbhIkQ",
59
+ "/ip6/2607:f2f8:a880:0:5054:ff:fe9f:4913/tcp/4001",
60
+ "/ip6/2607:f2f8:a880:0:5054:ff:fe9f:4913/udp/4001/quic-v1",
61
+ "/ip4/174.136.97.180/udp/4001/quic-v1/webtransport/certhash/uEiD84ZvAnGWTQx_WlOAqreebO036a5RRB5zfJBo9QJfDBA/certhash/uEiAOMkIVxeNye76-f5ADnLCSNqNlnhOYdkwyRlqLFbhIkQ",
62
+ "/ip4/174.136.97.180/udp/4001/quic-v1",
63
+ "/ip6/2607:f2f8:a880::70/udp/4001/quic-v1",
64
+ "/ip4/174.136.97.180/tcp/4001"
65
+ ],
66
+ "ID": "12D3KooWPEDBmt7vm6FNNYuqaA4n2qMUZ6wPK5NcRc8t6KpqgRkV",
67
+ "Schema": "peer"
68
+ }
69
+ ]
70
+ },
71
+ {
72
+ "Peers": [
73
+ {
74
+ "Addrs": [
75
+ "/ip4/174.136.97.179/udp/4001/quic-v1",
76
+ "/ip6/2607:f2f8:a880::50/udp/4002/quic-v1/webtransport/certhash/uEiBF7KOka9hhb2IjhUd-OkfgTFOf-VpgV7fwvMkKOkMrdQ/certhash/uEiDxVhDwzFlnorujU_rjTnO_TTLRMlXxzPLEgaG-1xOPkA",
77
+ "/ip4/174.136.97.179/udp/4001/quic-v1/webtransport/certhash/uEiBF7KOka9hhb2IjhUd-OkfgTFOf-VpgV7fwvMkKOkMrdQ/certhash/uEiDxVhDwzFlnorujU_rjTnO_TTLRMlXxzPLEgaG-1xOPkA",
78
+ "/ip6/2607:f2f8:a880::50/udp/4001/quic-v1",
79
+ "/ip4/174.136.97.179/udp/4002/quic-v1/webtransport/certhash/uEiBF7KOka9hhb2IjhUd-OkfgTFOf-VpgV7fwvMkKOkMrdQ/certhash/uEiDxVhDwzFlnorujU_rjTnO_TTLRMlXxzPLEgaG-1xOPkA",
80
+ "/ip6/2607:f2f8:a880::50/tcp/4001",
81
+ "/ip6/2607:f2f8:a880::50/udp/4001/quic-v1/webtransport/certhash/uEiBF7KOka9hhb2IjhUd-OkfgTFOf-VpgV7fwvMkKOkMrdQ/certhash/uEiDxVhDwzFlnorujU_rjTnO_TTLRMlXxzPLEgaG-1xOPkA",
82
+ "/ip4/174.136.97.179/tcp/4001"
83
+ ],
84
+ "ID": "12D3KooWSHbugDEQeWm2LjtRRMpNgLu6oZ8zkX8XcTwYMAewVekP",
85
+ "Schema": "peer"
86
+ }
87
+ ]
88
+ },
89
+ {
90
+ "Peers": [
91
+ {
92
+ "Addrs": [
93
+ "/ip6/2a03:4000:46:26e::c17/udp/443/quic-v1/webtransport/certhash/uEiAortGu7HNi8-pV9onPFkTwykrnWuJEqYf7zbQVE1FEtg/certhash/uEiB5Z8j3pdTJU_TDYoJ-GgUQSaXOmvKIGmASL9s-p3VHQA",
94
+ "/ip4/45.83.104.156/udp/443/quic-v1",
95
+ "/ip4/45.83.104.156/udp/443/quic-v1/webtransport/certhash/uEiAortGu7HNi8-pV9onPFkTwykrnWuJEqYf7zbQVE1FEtg/certhash/uEiB5Z8j3pdTJU_TDYoJ-GgUQSaXOmvKIGmASL9s-p3VHQA",
96
+ "/ip6/2a03:4000:46:26e::c17/tcp/443",
97
+ "/ip6/2a03:4000:46:26e::c17/udp/443/quic-v1",
98
+ "/ip4/45.83.104.156/tcp/443"
99
+ ],
100
+ "ID": "12D3KooWASoxFpwwy8JDdu4Tm57mhESsnbFPogam9VVmhR95FGXr",
101
+ "Schema": "peer"
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "Peers": [
107
+ {
108
+ "Addrs": [
109
+ "/ip4/139.178.91.71/udp/4001/quic-v1",
110
+ "/ip6/2604:1380:45e3:6e00::1/tcp/4001",
111
+ "/ip4/139.178.91.71/tcp/4001",
112
+ "/ip4/139.178.91.71/udp/4001/quic-v1/webtransport/certhash/uEiDYGZMqjz8wsz59DHA4iJin4nqTUfuJhq9AeAZlHBrmvg/certhash/uEiBXLv0dkEqbhmcinRbwj8b_3vWs0kWwf1-fiaz5wS-tew",
113
+ "/ip6/2604:1380:45e3:6e00::1/udp/4001/quic-v1/webtransport/certhash/uEiDYGZMqjz8wsz59DHA4iJin4nqTUfuJhq9AeAZlHBrmvg/certhash/uEiBXLv0dkEqbhmcinRbwj8b_3vWs0kWwf1-fiaz5wS-tew",
114
+ "/dnsaddr/bootstrap.libp2p.io",
115
+ "/dns6/sv15.bootstrap.libp2p.io/tcp/443/wss",
116
+ "/ip6/2604:1380:45e3:6e00::1/udp/4001/quic-v1",
117
+ "/ip4/139.178.91.71/tcp/443/tls/sni/sv15.bootstrap.libp2p.io/ws",
118
+ "/ip6/2604:1380:45e3:6e00::1/tcp/443/tls/sni/sv15.bootstrap.libp2p.io/ws",
119
+ "/dns4/sv15.bootstrap.libp2p.io/tcp/443/wss"
120
+ ],
121
+ "ID": "QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
122
+ "Schema": "peer"
123
+ }
124
+ ]
125
+ },
126
+ {
127
+ "Peers": [
128
+ {
129
+ "Addrs": [
130
+ "/ip4/139.178.65.157/udp/4001/quic-v1",
131
+ "/dns6/ny5.bootstrap.libp2p.io/tcp/443/wss",
132
+ "/ip6/2604:1380:45d2:8100::1/tcp/4001",
133
+ "/dns4/ny5.bootstrap.libp2p.io/tcp/443/wss",
134
+ "/ip4/139.178.65.157/tcp/4001",
135
+ "/ip6/2604:1380:45d2:8100::1/udp/4001/quic-v1"
136
+ ],
137
+ "ID": "QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
138
+ "Schema": "peer"
139
+ }
140
+ ]
141
+ },
142
+ {
143
+ "Peers": [
144
+ {
145
+ "Addrs": [
146
+ "/dns4/am6.bootstrap.libp2p.io/tcp/443/wss",
147
+ "/ip6/2604:1380:4602:5c00::3/udp/4001/quic-v1/webtransport/certhash/uEiD3Q2mfd5EYt6Y2M9rsge_nna4hVyCgUVlfSz3IjAK8ew/certhash/uEiAHt8JR08mlUCCGnN8VpqG9G4sfvdjAd0v5ZM5W1lqntw",
148
+ "/ip6/2604:1380:4602:5c00::3/tcp/4001",
149
+ "/ip4/147.75.87.27/udp/4001/quic-v1",
150
+ "/ip6/2604:1380:4602:5c00::3/udp/4001/quic-v1",
151
+ "/ip4/147.75.87.27/tcp/4001",
152
+ "/dns6/am6.bootstrap.libp2p.io/tcp/443/wss",
153
+ "/ip4/147.75.87.27/udp/4001/quic-v1/webtransport/certhash/uEiD3Q2mfd5EYt6Y2M9rsge_nna4hVyCgUVlfSz3IjAK8ew/certhash/uEiAHt8JR08mlUCCGnN8VpqG9G4sfvdjAd0v5ZM5W1lqntw"
154
+ ],
155
+ "ID": "QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
156
+ "Schema": "peer"
157
+ }
158
+ ]
159
+ },
160
+ {
161
+ "Peers": [
162
+ {
163
+ "Addrs": [
164
+ "/ip6/2604:1380:40e1:9c00::1/udp/4001/quic-v1/webtransport/certhash/uEiBENNd9IIPnU1cTGoVATo6cly-O2fQAjKpIyFi0msoJew/certhash/uEiD8N0sSnHOUIsKxz4pDuVqx4szt-huTZWafW_EY19H7MQ",
165
+ "/ip6/2604:1380:40e1:9c00::1/tcp/4001",
166
+ "/dnsaddr/bootstrap.libp2p.io",
167
+ "/ip4/145.40.118.135/udp/4001/quic-v1/webtransport/certhash/uEiBENNd9IIPnU1cTGoVATo6cly-O2fQAjKpIyFi0msoJew/certhash/uEiD8N0sSnHOUIsKxz4pDuVqx4szt-huTZWafW_EY19H7MQ",
168
+ "/ip4/145.40.118.135/udp/4001/quic-v1",
169
+ "/dns4/sg1.bootstrap.libp2p.io/tcp/443/wss",
170
+ "/ip6/2604:1380:40e1:9c00::1/udp/4001/quic-v1",
171
+ "/ip4/145.40.118.135/tcp/4001",
172
+ "/dns6/sg1.bootstrap.libp2p.io/tcp/443/wss",
173
+ "/ip4/145.40.118.135/tcp/443/tls/sni/sg1.bootstrap.libp2p.io/ws",
174
+ "/ip6/2604:1380:40e1:9c00::1/tcp/443/tls/sni/sg1.bootstrap.libp2p.io/ws"
175
+ ],
176
+ "ID": "QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
177
+ "Schema": "peer"
178
+ }
179
+ ]
180
+ },
181
+ {
182
+ "Peers": [
183
+ {
184
+ "Addrs": [
185
+ "/ip4/104.131.131.82/udp/4001/quic-v1/webtransport/certhash/uEiCIMEw_vvBwFLEqWbOj_wx7I90HmfMabSyVZ9Vn5srjPA/certhash/uEiBy22YtYUPU8T3aJ4rL3jC0lLR8MFZZNkFP-rWRxMrqQA",
186
+ "/ip4/104.131.131.82/udp/4001/quic-v1",
187
+ "/ip4/104.131.131.82/tcp/4001",
188
+ "/ip4/104.131.131.82/udp/4001/quic"
189
+ ],
190
+ "ID": "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
191
+ "Schema": "peer"
192
+ }
193
+ ]
194
+ },
195
+ {
196
+ "Peers": [
197
+ {
198
+ "Addrs": [
199
+ "/ip4/16.170.214.173/udp/4001/quic-v1/webtransport/certhash/uEiAKAeeOxU7ExDc81y7d53D96nFaRmmXwSFj0429Ij9T9A/certhash/uEiB4ttGGuaUzqF84q5RFhUTVArF4mb9t_UN_kcsfd4qYEQ",
200
+ "/ip4/16.170.214.173/tcp/4001",
201
+ "/ip4/16.170.214.173/udp/4001/quic-v1"
202
+ ],
203
+ "ID": "12D3KooWHh98YpAkJsn3ULjMjK1n9QVkXmi8Sb3gTDMatHxCmDP5",
204
+ "Schema": "peer"
205
+ }
206
+ ]
207
+ },
208
+ {
209
+ "Peers": [
210
+ {
211
+ "Addrs": [
212
+ "/ip4/18.119.248.24/udp/4001/quic-v1",
213
+ "/ip4/18.119.248.24/tcp/4001",
214
+ "/ip4/18.119.248.24/udp/4001/quic-v1/webtransport/certhash/uEiDwG2YnjoUpoKqmUMX-aYJeLi1UNEsqa8EFhpHFUVs0AQ/certhash/uEiCqy6-Pk3S2iYS0puQ0UhtTZ1s_nw-sIsoB-bX0Le6lFA"
215
+ ],
216
+ "ID": "12D3KooWS79EhkPU7ESUwgG4vyHHzW9FDNZLoWVth9b5N5NSrvaj",
217
+ "Schema": "peer"
218
+ }
219
+ ]
220
+ },
221
+ {
222
+ "Peers": [
223
+ {
224
+ "Addrs": [
225
+ "/ip4/83.173.236.99/udp/4001/quic-v1/webtransport/certhash/uEiD8mhYDW_6kgJAb07RlZnA-YSScG38df5wb9IxFtZmQwQ/certhash/uEiACG9e-sG_ild6y5t-jvb_dfsNi_gPgZ7nn7Qa5ctT-Wg",
226
+ "/ip6/2a02:121e:21e:1:546f:18ff:fea8:8e/tcp/4001",
227
+ "/ip4/83.173.236.99/tcp/10201",
228
+ "/dns4/ipfs-ws.neaweb.ch/tcp/443/wss",
229
+ "/ip4/89.251.251.195/udp/4001/quic-v1",
230
+ "/ip4/89.251.251.195/udp/4001/quic-v1/webtransport/certhash/uEiD8mhYDW_6kgJAb07RlZnA-YSScG38df5wb9IxFtZmQwQ/certhash/uEiACG9e-sG_ild6y5t-jvb_dfsNi_gPgZ7nn7Qa5ctT-Wg",
231
+ "/ip6/2a02:121e:21e:1:546f:18ff:fea8:8e/udp/4001/quic-v1",
232
+ "/ip4/89.251.251.195/tcp/4001/quic-v1/webtransport",
233
+ "/ip6/2a02:121e:21e:1:546f:18ff:fea8:8e/tcp/4011/ws",
234
+ "/ip4/89.251.251.195/tcp/4001",
235
+ "/dns4/ipfs-ws.neaweb.tech/tcp/443/wss",
236
+ "/ip4/89.251.251.195/tcp/4001/quic-v1",
237
+ "/ip4/83.173.236.99/tcp/4001",
238
+ "/ip6/2a02:121e:21e:1:546f:18ff:fea8:8e/udp/4001/quic-v1/webtransport/certhash/uEiD8mhYDW_6kgJAb07RlZnA-YSScG38df5wb9IxFtZmQwQ/certhash/uEiACG9e-sG_ild6y5t-jvb_dfsNi_gPgZ7nn7Qa5ctT-Wg",
239
+ "/ip4/83.173.236.99/udp/4001/quic-v1",
240
+ "/ip4/83.173.236.99/udp/19707/quic-v1",
241
+ "/ip4/83.173.236.99/udp/19707/quic-v1/webtransport/certhash/uEiD8mhYDW_6kgJAb07RlZnA-YSScG38df5wb9IxFtZmQwQ/certhash/uEiACG9e-sG_ild6y5t-jvb_dfsNi_gPgZ7nn7Qa5ctT-Wg"
242
+ ],
243
+ "ID": "12D3KooWBbkCD5MpJhMc1mfPAVGEyVkQnyxPKGS7AHwDqQM2JUsk",
244
+ "Schema": "peer"
245
+ }
246
+ ]
247
+ },
248
+ {
249
+ "Peers": [
250
+ {
251
+ "Addrs": [
252
+ "/ip4/89.58.11.155/udp/4001/quic-v1/webtransport/certhash/uEiDDgTBtcIstrvU4MRSfcD7tYDIsQrnGAxW6Oh5AoLm4Ig/certhash/uEiAXHXsg1wBb-sPvpBw8BVpRFxso1milPa801TxjPNYQ3w",
253
+ "/ip4/89.58.11.155/udp/4001/quic",
254
+ "/ip6/64:ff9b::593a:b9b/udp/4001/quic-v1/webtransport/certhash/uEiDDgTBtcIstrvU4MRSfcD7tYDIsQrnGAxW6Oh5AoLm4Ig/certhash/uEiAXHXsg1wBb-sPvpBw8BVpRFxso1milPa801TxjPNYQ3w",
255
+ "/ip6/64:ff9b::593a:b9b/udp/4001/quic-v1",
256
+ "/ip4/89.58.11.155/udp/4001/quic-v1",
257
+ "/ip4/89.58.11.155/tcp/4001"
258
+ ],
259
+ "ID": "12D3KooWKLdecs31Zmo2pLBjR9HY2vWo3VwM4eBm21Czeucbe6FL",
260
+ "Schema": "peer"
261
+ }
262
+ ]
263
+ },
264
+ {
265
+ "Peers": [
266
+ {
267
+ "Addrs": [
268
+ "/ip4/205.198.64.76/tcp/4001",
269
+ "/ip4/205.198.64.76/udp/4001/quic-v1",
270
+ "/ip4/205.198.64.76/udp/4001/quic-v1/webtransport/certhash/uEiCT4khDdgvF2NHCw-fu3qUk2qRqx0AgTEt0PHZct8jq5g/certhash/uEiA2RYkSCyOOtJmrpm_Dn8jJr-LLwS0S7K3HX3dbJJlN_w"
271
+ ],
272
+ "ID": "12D3KooWBdF3g6vSJFRPoZQo7BNnkNzaWb59gpyaVzsgtNTVeu8H",
273
+ "Schema": "peer"
274
+ }
275
+ ]
276
+ },
277
+ ];
278
+
279
+ const CONFIG_KNOWN_BOOTSTRAP_PEER_IDS = [
280
+ '12D3KooWFhXabKDwALpzqMbto94sB7rvmZ6M28hs9Y9xSopDKwQr',
281
+ '12D3KooWGahRw3ZnM4gAyd9FK75v4Bp5keFYTvkcAwhpEm28wbV3',
282
+ '12D3KooWPEDBmt7vm6FNNYuqaA4n2qMUZ6wPK5NcRc8t6KpqgRkV',
283
+ '12D3KooWSHbugDEQeWm2LjtRRMpNgLu6oZ8zkX8XcTwYMAewVekP',
284
+ '12D3KooWASoxFpwwy8JDdu4Tm57mhESsnbFPogam9VVmhR95FGXr',
285
+ 'QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
286
+ 'QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
287
+ 'QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
288
+ 'QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
289
+ 'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
290
+ '12D3KooWHh98YpAkJsn3ULjMjK1n9QVkXmi8Sb3gTDMatHxCmDP5',
291
+ '12D3KooWS79EhkPU7ESUwgG4vyHHzW9FDNZLoWVth9b5N5NSrvaj',
292
+ '12D3KooWBbkCD5MpJhMc1mfPAVGEyVkQnyxPKGS7AHwDqQM2JUsk',
293
+ '12D3KooWKLdecs31Zmo2pLBjR9HY2vWo3VwM4eBm21Czeucbe6FL',
294
+ '12D3KooWBdF3g6vSJFRPoZQo7BNnkNzaWb59gpyaVzsgtNTVeu8H'
295
+ ];
296
+
297
+ const prefix = CONFIG_PREFIX;
298
+
299
+ const mkErr = msg => new Error(`${prefix}: ${msg}`);
300
+
301
+ function uint8ArrayToString(uint8Array){
302
+ const string = new TextDecoder().decode(uint8Array);
303
+ return string
304
+ }
305
+
306
+ function uint8ArrayFromString(string){
307
+ const uint8Array = new TextEncoder().encode(string);
308
+ return uint8Array
309
+ }
310
+
311
+ //Add id to pupsub message
312
+ async function msgIdFnStrictNoSign(msg){
313
+ var enc = new TextEncoder();
314
+ const signedMessage = msg;
315
+ const encodedSeqNum = enc.encode(signedMessage.sequenceNumber.toString());
316
+ return await sha256.encode(encodedSeqNum)
317
+ }
318
+
319
+ let totals = {
320
+ readyErrored: 0,
321
+ noiseErrored: 0,
322
+ upgradeErrored: 0,
323
+ readyTimedout: 0,
324
+ noiseTimedout: 0,
325
+ success: 0
326
+ };
327
+
328
+ let stats = {
329
+ pending: 0,
330
+ open: 0,
331
+
332
+ ready_error: 0,
333
+ noise_error: 0,
334
+ upgrade_error: 0,
335
+
336
+ ready_timeout: 0,
337
+ noise_timeout: 0,
338
+
339
+ close: 0,
340
+ abort: 0,
341
+ remote_close: 0,
342
+ };
343
+
344
+ let lastStats = {
345
+ pending: 0,
346
+ ready_error: 0,
347
+ noise_error: 0,
348
+ upgrade_error: 0,
349
+ close: 0,
350
+ remote_close: 0,
351
+ ready: 0,
352
+ abort: 0,
353
+ ready_timeout: 0,
354
+ noise_timeout: 0,
355
+ open: 0
356
+ };
357
+
358
+ let isDialEnabled = true;
359
+ let lastfailtreshold = 0;
360
+
361
+ function metrics(data){
362
+ try{
363
+ const webTransportEvents = data.libp2p_webtransport_dialer_events_total;
364
+
365
+ const newPending = (webTransportEvents.pending ?? 0) - (lastStats.pending ?? 0);
366
+ const newReadyError = (webTransportEvents.ready_error ?? 0) - (lastStats.ready_error ?? 0);
367
+ const newNoiseError = (webTransportEvents.noise_error ?? 0) - (lastStats.noise_error ?? 0);
368
+ const newUpgradeError = (webTransportEvents.upgrade_error ?? 0) - (lastStats.upgrade_error ?? 0);
369
+ const newClose = (webTransportEvents.close ?? 0) - (lastStats.close ?? 0);
370
+ const newReady = (webTransportEvents.ready ?? 0) - (lastStats.ready ?? 0);
371
+ const newAbort = (webTransportEvents.abort ?? 0) - (lastStats.abort ?? 0);
372
+ const newReadyTimeout = (webTransportEvents.ready_timeout ?? 0) - (lastStats.ready_timeout ?? 0);
373
+ const newNoiseTimeout = (webTransportEvents.noise_timeout ?? 0) - (lastStats.noise_timeout ?? 0);
374
+ const newOpen = (webTransportEvents.open ?? 0) - (lastStats.open ?? 0);
375
+ const newRemoteClose = (webTransportEvents.remote_close ?? 0) - (lastStats.remote_close ?? 0);
376
+
377
+ stats.pending += newPending;
378
+ stats.pending -= newReadyTimeout;
379
+ stats.pending -= newNoiseTimeout;
380
+ stats.pending -= newReadyError;
381
+ stats.pending -= newNoiseError;
382
+ stats.pending -= newUpgradeError;
383
+ stats.pending -= newOpen;
384
+
385
+ stats.open += newOpen;
386
+ stats.open -= newClose;
387
+ stats.open -= newRemoteClose;
388
+ stats.open -= newAbort;
389
+
390
+ stats.ready_error = newReadyError;
391
+ stats.noise_error = newNoiseError;
392
+ stats.upgrade_error = newUpgradeError;
393
+ stats.ready_timeout = newReadyTimeout;
394
+ stats.noise_timeout = newNoiseTimeout;
395
+ stats.close = newClose;
396
+ stats.abort = newAbort;
397
+ stats.remote_close = newRemoteClose;
398
+
399
+ totals.success += newReady;
400
+ totals.readyErrored += newReadyError;
401
+ totals.noiseErrored += newNoiseError;
402
+ totals.upgradeErrored += newUpgradeError;
403
+ totals.readyTimedout += newReadyTimeout;
404
+ totals.noiseTimedout += newNoiseTimeout;
405
+
406
+ const errors = totals.readyErrored + totals.noiseErrored + totals.upgradeErrored;
407
+ const timeouts = totals.readyTimedout + totals.noiseTimedout;
408
+ //const failureRate = ((errors + timeouts) / (errors + timeouts + totals.success) * 100).toFixed(2)
409
+
410
+ lastStats = webTransportEvents;
411
+
412
+ const fail = errors+timeouts;
413
+ const treshold = errors+timeouts+stats.open+stats.pending;
414
+
415
+ if(treshold>50){
416
+ //console.log(`Treeshold hit : ${treshold}`)
417
+ }
418
+
419
+ if(fail>50){
420
+ //console.log(`Open : ${stats.open} , Pending : ${stats.pending} , Succes : ${totals.success} , Fail : ${fail} `)
421
+
422
+ }
423
+
424
+ if ((fail-lastfailtreshold)>50){
425
+ if(isDialEnabled){
426
+ isDialEnabled = false;
427
+ //const str = JSON.stringify({isDialEnabled,fail,lastfailtreshold})
428
+ //console.warn(str)
429
+ setTimeout(()=>{
430
+ if(!isDialEnabled){
431
+ isDialEnabled = true;
432
+ lastfailtreshold = fail;
433
+ //const str = JSON.stringify({isDialEnabled,fail,lastfailtreshold})
434
+ //console.warn(str)
435
+ }
436
+ },6*60*1000);
437
+ }
438
+ }
439
+
440
+ return isDialEnabled
441
+
442
+ }
443
+ catch{
444
+ console.debug('Metrics error');
445
+ }
446
+ }
447
+
448
+ /*
449
+ onunhandledrejection = function(evt) {
450
+ console.warn(evt.reason);
451
+ return
452
+ }
453
+ */
454
+
455
+ class webpeerjs{
456
+
457
+ //libp2p instance
458
+ #libp2p
459
+
460
+ //map [id,addrs] of discovered peers (addrs is array of address)
461
+ #discoveredPeers
462
+
463
+ //array of all webpeers id has been found
464
+ #webPeersId
465
+
466
+ //map [id,addrs]
467
+ #webPeersAddrs
468
+
469
+ //database of best peers has been found
470
+ #dbstore
471
+ #dbstoreData
472
+
473
+ //map of [id,number_of_dialed] of good peers on #connectionTracker
474
+ #dialedGoodPeers
475
+
476
+ //boolean is dial websocket
477
+ #isDialWebsocket
478
+
479
+ //map [id,mddrs] of dialed bootstrap address
480
+ #dialedKnownBootstrap
481
+
482
+ //array of dialed discovered peers id
483
+ //#dialedDiscoveredPeers
484
+
485
+ //object from joinRoom()
486
+ #rooms
487
+
488
+ //map [id,addrs] of webpeers currently connected (addrs is array of address)
489
+ #connectedPeers
490
+
491
+ //array of we peers id proxy of #connectedPeers
492
+ #connectedPeersArr
493
+
494
+ //map [id,number_of_dialed] of #connectionTracker object store
495
+ #connectionTrackerStore
496
+
497
+ //map [id,addr] of all peers connections (addr is string of address)
498
+ #connections
499
+
500
+ //track disconnect event
501
+ #trackDisconnect
502
+
503
+ //list of dial multiaddress queue
504
+ #dialQueue
505
+
506
+ //is dial enabled
507
+ #isDialEnabled
508
+
509
+ id
510
+ status
511
+ IPFS
512
+ address
513
+ peers
514
+
515
+ constructor(libp2p,dbstore,onMetrics){
516
+
517
+ this.#libp2p = libp2p;
518
+ this.#dbstore = dbstore;
519
+ this.#dbstoreData = new Map();
520
+ this.#discoveredPeers = new Map();
521
+ this.#webPeersId = [];
522
+ this.#webPeersAddrs = new Map();
523
+ this.#dialedGoodPeers = new Map();
524
+ this.#isDialWebsocket = false;
525
+ this.#dialedKnownBootstrap = new Map();
526
+ //this.#dialedDiscoveredPeers = []
527
+ this.address = [];
528
+ this.#rooms = {};
529
+ this.#connectedPeers = new Map();
530
+ this.#connectedPeersArr = [];
531
+ this.#connectionTrackerStore = new Map();
532
+ this.#connections = new Map();
533
+ this.#trackDisconnect = new Map();
534
+ this.#dialQueue = [];
535
+ this.#isDialEnabled = true;
536
+
537
+ this.peers = (function(f) {
538
+ return f
539
+ })(this.#connectedPeersArr);
540
+
541
+ this.status = (function(libp2p) {
542
+ return libp2p.status
543
+ })(this.#libp2p);
544
+
545
+ this.IPFS = (function(libp2p,discoveredPeers) {
546
+ const obj = {libp2p,discoveredPeers};
547
+ return obj
548
+ })(this.#libp2p,this.#discoveredPeers);
549
+
550
+ this.id = this.#libp2p.peerId.toString();
551
+
552
+
553
+ //listen to peer connect event
554
+ this.#libp2p.addEventListener("peer:connect", (evt) => {
555
+
556
+ //console.log(`Connected to ${connection.toString()}`);
557
+
558
+ const connection = evt.detail;
559
+ const id = evt.detail.toString();
560
+
561
+ const connections = this.#libp2p.getConnections().map((con)=>{return {id:con.remotePeer.toString(),addr:con.remoteAddr.toString()}});
562
+ const connect = connections.find((con)=>con.id == id);
563
+ const addr = connect.addr;
564
+ this.#connections.set(id,addr);
565
+
566
+ //required by joinRoom version 1 to announce via universal connectivity
567
+ if(connection.toString() === CONFIG_KNOWN_BOOTSTRAP_PEER_IDS[0]){
568
+ setTimeout(()=>{
569
+ this.#announce();
570
+ },1000);
571
+ }
572
+
573
+ });
574
+
575
+
576
+ //listen message from subscribed pupsub topic
577
+ this.#libp2p.services.pubsub.addEventListener('message', event => {
578
+
579
+ //console.log('on:'+event.detail.topic,event.detail.data)
580
+ //console.log('from '+event.detail.from.toString(),event)
581
+
582
+ if (event.detail.type !== 'signed') {
583
+ return
584
+ }
585
+ {
586
+ const topic = event.detail.topic;
587
+ const senderPeerId = event.detail.from.toString();
588
+ if(CONFIG_PUBSUB_PEER_DISCOVERY.includes(topic)){
589
+ try{
590
+
591
+ //if it is webpeer
592
+ if(this.#webPeersId.includes(senderPeerId)){
593
+
594
+ if(this.#connectedPeers.has(senderPeerId)){
595
+ //reset this last seen
596
+ const address = this.#connectedPeers.get(senderPeerId).addrs;
597
+ const now = new Date().getTime();
598
+ const metadata = {addrs:address,last:now};
599
+ this.#connectedPeers.set(senderPeerId,metadata);
600
+ }
601
+ else {
602
+ //add to connected webpeers
603
+ this.#onConnectFn(senderPeerId);
604
+ const address = this.#webPeersAddrs.get(senderPeerId);
605
+ const now = new Date().getTime();
606
+ const metadata = {addrs:address,last:now};
607
+ this.#connectedPeers.set(senderPeerId,metadata);
608
+ }
609
+
610
+ //dial if not connected
611
+ if(!this.#isConnected(senderPeerId)){
612
+ if(this.#connections.has(senderPeerId)){
613
+ let mddrs = [];
614
+ const addr = this.#connections.get(senderPeerId);
615
+ const mddr = multiaddr(addr);
616
+ mddrs.push(mddr);
617
+ this.#dialMultiaddress(mddrs);
618
+ }
619
+ else if(this.#discoveredPeers.has(senderPeerId)){
620
+ const addrs = this.#discoveredPeers.get(senderPeerId);
621
+ let mddrs = [];
622
+ for(const addr of addrs){
623
+ const mddr = multiaddr(addr);
624
+ mddrs.push(mddr);
625
+ }
626
+ this.#dialMultiaddress(mddrs);
627
+ }
628
+ else {
629
+ const addrs = this.#connectedPeers.get(senderPeerId).addrs;
630
+ let mddrs = [];
631
+ for(const addr of addrs){
632
+ const mddr = multiaddr(addr);
633
+ mddrs.push(mddr);
634
+ }
635
+ this.#dialMultiaddress(mddrs);
636
+ }
637
+ }
638
+
639
+
640
+ }
641
+
642
+ //parse the message over pupsub peer discovery
643
+ const peer = Peer.decode(event.detail.data);
644
+ const msg = uint8ArrayToString(peer.addrs[0]);
645
+ const json = JSON.parse(msg);
646
+ const prefix = json.prefix;
647
+ const room = json.room;
648
+ const message = json.message;
649
+ const signal = json.signal;
650
+ const id = json.id;
651
+ //console.log(`from ${id}:${signal} = ${message}`)
652
+ if(id != senderPeerId)return
653
+ let address = json.address;
654
+
655
+ //detect special webpeer identity
656
+ if(prefix === CONFIG_PREFIX){
657
+
658
+ //add to webpeers id
659
+ if(!this.#webPeersId.includes(id))this.#webPeersId.push(id);
660
+
661
+ //add to connected webpeers
662
+ if(!this.#connectedPeers.has(id)){
663
+ this.#onConnectFn(id);
664
+ address = [];
665
+ const now = new Date().getTime();
666
+ const metadata = {addrs:address,last:now};
667
+ this.#connectedPeers.set(id,metadata);
668
+ this.#webPeersAddrs.set(id,address);
669
+ this.#connectedPeersArr.length = 0;
670
+ for(const peer of this.#connectedPeers){
671
+ const item = {id:peer[0],address:peer[1].addrs};
672
+ this.#connectedPeersArr.push(item);
673
+ }
674
+ }
675
+
676
+
677
+ if(room){
678
+ if(this.#rooms[room]){
679
+
680
+ //inbound message
681
+ this.#rooms[room].onMessage(message,id);
682
+
683
+ //update room members
684
+ if(!this.#rooms[room].members.includes(id)){
685
+ this.#rooms[room].members.push(id);
686
+ this.#rooms[room].onMembers(this.#rooms[room].members);
687
+ }
688
+ }
689
+ }
690
+
691
+ if(signal){
692
+
693
+ //repply announce with ping
694
+ if(signal == 'announce'){
695
+ setTimeout(()=>{this.#ping();},1000);
696
+ }
697
+
698
+ if(signal == 'ping'){
699
+ //do nothing
700
+ }
701
+
702
+ //update connected webpeers
703
+ const now = new Date().getTime();
704
+ const metadata = {addrs:address,last:now};
705
+ this.#connectedPeers.set(id,metadata);
706
+ this.#webPeersAddrs.set(id,address);
707
+ this.#connectedPeersArr.length = 0;
708
+ for(const peer of this.#connectedPeers){
709
+ const item = {id:peer[0],address:peer[1].addrs};
710
+ this.#connectedPeersArr.push(item);
711
+ }
712
+
713
+ }
714
+ }
715
+
716
+ }catch(err){
717
+ //console.log('from '+event.detail.from.toString())
718
+ console.debug(err);
719
+ }
720
+ }else {
721
+ const json = JSON.parse(topic);
722
+ const room = json.room;
723
+ const message = new TextDecoder().decode(event.detail.data);
724
+ this.#rooms[room].onMessage(message);
725
+ }
726
+ }
727
+
728
+ });
729
+
730
+
731
+ //listen to peer discovery event
732
+ this.#libp2p.addEventListener('peer:discovery', (evt) => {
733
+
734
+ //console.log('Discovered:', evt.detail.id.toString())
735
+ //console.log('Discovered: '+evt.detail.id.toString(), evt.detail.multiaddrs.toString())
736
+
737
+ //save peer discover
738
+
739
+ const multiaddrs = evt.detail.multiaddrs;
740
+ const id = evt.detail.id;
741
+
742
+ if(multiaddrs.length != 0){
743
+ let addrs = [];
744
+ for(const addr of multiaddrs){
745
+ let peeraddr;
746
+ if(multiaddrs.toString().includes(evt.detail.id.toString())){
747
+ //console.log('Discovered:', evt.detail.multiaddrs.toString())
748
+ //peer from pupsub peer discovery already has included self id
749
+ peeraddr = addr.toString();
750
+ }
751
+ else {
752
+ //other need to add Id
753
+ peeraddr = addr.toString()+'/p2p/'+id;
754
+ }
755
+ addrs.push(peeraddr);
756
+ }
757
+ //save the new format multiaddrs
758
+ this.#discoveredPeers.set(id.toString(), addrs);
759
+
760
+ //track if peer come from relay then dial it because there is a chance it is from other browser node
761
+ if(multiaddrs.toString().includes('certhash')&& multiaddrs.toString().includes('webtransport') && multiaddrs.toString().includes('p2p-circuit')){
762
+ //console.log(addrs)
763
+ if(!this.#connections.has(id)){
764
+ for(const addr of addrs){
765
+ multiaddr(addr);
766
+ }
767
+ //this.#dialMultiaddress(mddrs)
768
+ }
769
+ }
770
+ }
771
+
772
+ });
773
+
774
+
775
+ //listen to peer disconnect event
776
+ this.#libp2p.addEventListener("peer:disconnect",async (evt) => {
777
+
778
+ //const connection = evt.detail;
779
+ //console.log(`Disconnected from ${connection.toCID().toString()}`);
780
+ const id = evt.detail.string;
781
+
782
+ //track disconnect event
783
+ if(this.#trackDisconnect.has(id)){
784
+ let count = this.#trackDisconnect.get(id);
785
+ count++;
786
+ this.#trackDisconnect.set(id,count);
787
+ //console.log(this.#trackDisconnect)
788
+ if(count>5){
789
+ if(this.#dbstoreData.has(id)){
790
+ //await this.#dbstore.delete(new Key(id))
791
+ this.#dbstoreData.delete(id);
792
+ }
793
+
794
+ if(!this.#webPeersId.includes(id) && !this.#dialedKnownBootstrap.has(id)){
795
+ return
796
+ }
797
+ }
798
+ }
799
+ else {
800
+ this.#trackDisconnect.set(id,0);
801
+ }
802
+
803
+ //if this disconnected peer is web peer redial it
804
+ if(this.#webPeersId.includes(id)){
805
+ const addr = this.#connections.get(id);
806
+ let mddrs = [];
807
+ const mddr = multiaddr(addr);
808
+ mddrs.push(mddr);
809
+ this.#dialMultiaddress(mddrs);
810
+ }
811
+
812
+ //if this disconnected peer is known bootstrap redial it
813
+ else if(this.#dialedKnownBootstrap.has(id)){
814
+ const addr = this.#connections.get(id);
815
+ let mddrs = [];
816
+ const addrs = multiaddr(addr);
817
+ mddrs.push(addrs);
818
+ this.#dialMultiaddress(mddrs);
819
+ }
820
+
821
+ //redial if this disconnected peer is regular peer
822
+ else {
823
+ const addr = this.#connections.get(id);
824
+ let mddrs = [];
825
+ const addrs = multiaddr(addr);
826
+ mddrs.push(addrs);
827
+ this.#dialMultiaddress(mddrs);
828
+ }
829
+ });
830
+
831
+
832
+ //listen to self peer update
833
+ this.#libp2p.addEventListener('self:peer:update', ({ detail: { peer } }) => {
834
+ //const multiaddrs = peer.addresses.map(({ multiaddr }) => multiaddr)
835
+ //console.log(`changed multiaddrs: peer ${peer.id.toString()} multiaddrs: ${multiaddrs}`)
836
+ const id = peer.id.toString();
837
+ const mddrs = [];
838
+ peer.addresses.forEach((addr)=>{
839
+ const maddr = addr.multiaddr.toString()+'/p2p/'+id;
840
+ if(maddr.includes('webtransport') && maddr.includes('certhash')){
841
+ mddrs.push(maddr);
842
+ }
843
+ });
844
+ //this.#ListenAddressChange(mddrs)
845
+ this.address = mddrs;
846
+ this.#ping();
847
+ });
848
+
849
+ //dial known peers from configuration
850
+ this.#dialKnownPeers();
851
+
852
+ //watch connection every 30s if none dial known peers again from configuration
853
+ this.#watchConnection();
854
+
855
+ //if found good peers save to storage and reconnect if disconnect
856
+ this.#connectionTracker();
857
+
858
+ //periodically dial saved bootstrap address if disconnect
859
+ this.#dialRandomBootstrap();
860
+
861
+ //dial random discovered peers
862
+ //this.#dialdiscoveredpeers()
863
+
864
+ onMetrics((data)=>{
865
+ const signal = metrics(data);
866
+ this.#isDialEnabled = signal;
867
+
868
+ });
869
+
870
+ setInterval(()=>{
871
+ this.#dialQueueList();
872
+ },5e3);
873
+
874
+ setInterval(()=>{
875
+ this.#trackLastSeen();
876
+ },5e3);
877
+
878
+ }
879
+
880
+
881
+
882
+
883
+ /*
884
+ PUBLIC FUNCTION
885
+ */
886
+
887
+ //Listen on new peer connection
888
+ #onConnectFn = () => {}
889
+ onJoin = f => (this.#onConnectFn = f)
890
+
891
+
892
+ //Listen on peer disconnect
893
+ #onDisconnectFn = () => {}
894
+ onLeave = f => (this.#onDisconnectFn = f)
895
+
896
+
897
+
898
+
899
+ /*
900
+ PRIVATE FUNCTION
901
+ */
902
+
903
+
904
+ //check the last seen in web peer
905
+ #trackLastSeen(){
906
+ const timeout = 25*1000;
907
+ const now = new Date().getTime();
908
+
909
+ //if webpeer last seen grather then timeout send onDisconnect
910
+ for(const peer of this.#connectedPeers){
911
+ const id = peer[0];
912
+ const last = peer[1].last;
913
+ const time = now-last;
914
+ if(time>timeout){
915
+ this.#connectedPeers.delete(id);
916
+ this.#connectedPeersArr.length = 0;
917
+ for(const peer of this.#connectedPeers){
918
+ const item = {id:peer[0],address:peer[1].addrs};
919
+ this.#connectedPeersArr.push(item);
920
+ }
921
+ this.#onDisconnectFn(id);
922
+
923
+ //remove id from room member
924
+ const rooms = Object.keys(this.#rooms);
925
+ for(const room of rooms){
926
+ if(this.#rooms[room].members.includes(id)){
927
+ const index = this.#rooms[room].members.indexOf(id);
928
+ this.#rooms[room].members.splice(index,1);
929
+ this.#rooms[room].onMembers(this.#rooms[room].members);
930
+ }
931
+ }
932
+ }
933
+ }
934
+ }
935
+
936
+ //check if this id is connected
937
+ #isConnected(id){
938
+ let peers = [];
939
+ for(const peer of this.#libp2p.getPeers()){
940
+ peers.push(peer.toString());
941
+ }
942
+ if(peers.includes(id)){
943
+ return true
944
+ }
945
+ else {
946
+ return false
947
+ }
948
+ }
949
+
950
+
951
+ //add multiaddr address to queue list
952
+ #dialMultiaddress(mddrs){
953
+ if(mddrs.length>0){
954
+
955
+ const id = mddrs[0].toString().split('/').pop();
956
+
957
+ const ids = this.#dialQueue.map((arr)=> arr[0].toString().split('/').pop());
958
+
959
+ //if peer id is already in the queque cancel queque
960
+ if(ids.includes(id)){
961
+ return
962
+ }
963
+
964
+ if(this.#webPeersId.includes(id) || id == CONFIG_KNOWN_BOOTSTRAP_PEER_IDS[0] ){
965
+ this.#dialQueue.unshift(mddrs);
966
+ }
967
+ else {
968
+ this.#dialQueue.push(mddrs);
969
+ }
970
+
971
+ }
972
+ }
973
+
974
+ //dial multiaddr address in queue list
975
+ #dialQueueList(){
976
+
977
+ if(!this.#isDialEnabled)return
978
+
979
+ const mddrsToDial = 3;
980
+
981
+ let queue = [];
982
+ for(const item of this.#libp2p.getDialQueue()){
983
+ const id = item.peerId.string;
984
+ queue.push(id);
985
+ }
986
+
987
+ if (queue.length > mddrsToDial)return
988
+
989
+ for(let i = 0; i < mddrsToDial; i++){
990
+ const mddrs = this.#dialQueue.shift();
991
+ if(mddrs != undefined && mddrs.length>0){
992
+
993
+ const id = mddrs[0].toString().split('/').pop();
994
+
995
+ if(this.#isConnected(id))continue
996
+ if(queue.includes(id)){continue;}
997
+
998
+ //dial with webtransport
999
+ this.#dialWebtransport(mddrs);
1000
+
1001
+ //fallback dial with websocket if enabled
1002
+ if(this.#isDialWebsocket){
1003
+ this.#dialWebsocket(mddrs);
1004
+ }
1005
+
1006
+ }
1007
+ else {
1008
+ break
1009
+ }
1010
+ }
1011
+
1012
+ }
1013
+
1014
+
1015
+ //announce and ping via pupsub peer discovery
1016
+ async #announce(){
1017
+ const topics = CONFIG_PUBSUB_PEER_DISCOVERY;
1018
+ const data = JSON.stringify({prefix:CONFIG_PREFIX,signal:'announce',id:this.#libp2p.peerId.toString(),address:this.address});
1019
+ const peer = {
1020
+ publicKey: this.#libp2p.peerId.publicKey,
1021
+ addrs: [uint8ArrayFromString(data)],
1022
+ };
1023
+ const encodedPeer = Peer.encode(peer);
1024
+ for(const topic of topics){
1025
+ await this.#libp2p.services.pubsub.publish(topic, encodedPeer);
1026
+ }
1027
+ }
1028
+ async #ping(){
1029
+ const topics = CONFIG_PUBSUB_PEER_DISCOVERY;
1030
+ const data = JSON.stringify({prefix:CONFIG_PREFIX,signal:'ping',id:this.#libp2p.peerId.toString(),address:this.address});
1031
+ const peer = {
1032
+ publicKey: this.#libp2p.peerId.publicKey,
1033
+ addrs: [uint8ArrayFromString(data)],
1034
+ };
1035
+ const encodedPeer = Peer.encode(peer);
1036
+ for(const topic of topics){
1037
+ await this.#libp2p.services.pubsub.publish(topic, encodedPeer);
1038
+ }
1039
+ }
1040
+
1041
+
1042
+ joinRoom = room => {
1043
+ if (this.#rooms[room]) {
1044
+ return [
1045
+ this.#rooms[room].sendMessage,
1046
+ this.#rooms[room].listenMessage,
1047
+ this.#rooms[room].onMembersChange
1048
+ ]
1049
+
1050
+
1051
+ }
1052
+
1053
+ if (!room) {
1054
+ throw mkErr('room is required')
1055
+ }
1056
+
1057
+ //join room version 1 user pupsub via pupsub peer discovery
1058
+ {
1059
+
1060
+ const topics = CONFIG_PUBSUB_PEER_DISCOVERY;
1061
+
1062
+ this.#rooms[room] = {
1063
+ onMessage : () => {},
1064
+ listenMessage : f => (this.#rooms[room] = {...this.#rooms[room], onMessage: f}),
1065
+ sendMessage : async (message) => {
1066
+ const data = JSON.stringify({prefix:CONFIG_PREFIX,room,message,id:this.#libp2p.peerId.toString()});
1067
+ const peer = {
1068
+ publicKey: this.#libp2p.peerId.publicKey,
1069
+ addrs: [uint8ArrayFromString(data)],
1070
+ };
1071
+ const encodedPeer = Peer.encode(peer);
1072
+ for(const topic of topics){
1073
+ await this.#libp2p.services.pubsub.publish(topic, encodedPeer);
1074
+ }
1075
+ },
1076
+ members : [this.id],
1077
+ onMembers : () => {},
1078
+ onMembersChange : f => {this.#rooms[room] = {...this.#rooms[room], onMembers: f};this.#rooms[room].onMembers(this.#rooms[room].members);},
1079
+ };
1080
+ }
1081
+
1082
+ return [
1083
+ this.#rooms[room].sendMessage,
1084
+ this.#rooms[room].listenMessage,
1085
+ this.#rooms[room].onMembersChange
1086
+ ]
1087
+ }
1088
+
1089
+
1090
+ //dial discovered peers
1091
+ /*#dialdiscoveredpeers(){
1092
+ setInterval(()=>{
1093
+ const keys = Array.from(this.#discoveredPeers.keys())
1094
+ for(const key of keys){
1095
+ if(!this.#dialedDiscoveredPeers.includes(key)){
1096
+ this.#dialedDiscoveredPeers.push(key)
1097
+ const addrs = this.#discoveredPeers.get(key)
1098
+ let mddrs = []
1099
+ for(const addr of addrs){
1100
+ const mddr = multiaddr(addr)
1101
+ mddrs.push(mddr)
1102
+ }
1103
+ this.#dialMultiaddress(mddrs)
1104
+ break
1105
+ }
1106
+ }
1107
+ },30*1000)
1108
+ }*/
1109
+
1110
+
1111
+ //dial random known bootstrap periodically
1112
+ #dialRandomBootstrap(){
1113
+ setInterval(()=>{
1114
+ //const keys = Array.from(this.#dialedKnownBootstrap.keys())
1115
+ const keys = CONFIG_KNOWN_BOOTSTRAP_PEER_IDS;
1116
+ const randomKey = Math.floor(Math.random() * keys.length);
1117
+ let ids = [];
1118
+ ids.push(keys[randomKey]);
1119
+
1120
+ //universal connectivity id for webpeer discovery and joinRoom version 1 to work
1121
+ ids.push(CONFIG_KNOWN_BOOTSTRAP_PEER_IDS[0]);
1122
+
1123
+ for(const id of ids){
1124
+ if(id == undefined)continue
1125
+ //const addrs = this.#dialedKnownBootstrap.get(id)
1126
+
1127
+ if(!this.#isConnected(id)){
1128
+ if(this.#connections.has(id))
1129
+ {
1130
+ let mddrs = [];
1131
+ const addr = this.#connections.get(id);
1132
+ const mddr = multiaddr(addr);
1133
+ mddrs.push(mddr);
1134
+ this.#dialMultiaddress(mddrs);
1135
+ }
1136
+ else if (this.#dialedKnownBootstrap.has(id)){
1137
+ let mddrs = [];
1138
+ const addrs = this.#dialedKnownBootstrap.get(id);
1139
+ for(const addr of addrs){
1140
+ const mddr = multiaddr(addr);
1141
+ mddrs.push(mddr);
1142
+ }
1143
+ this.#dialMultiaddress(mddrs);
1144
+ }
1145
+ else {
1146
+ const bootstrap = CONFIG_KNOWN_BOOTSTRAP_PEERS_ADDRS;
1147
+ const index = bootstrap.findIndex((peer)=>peer.Peers[0].ID == id);
1148
+ const addrs = bootstrap[index].Peers[0].Addrs;
1149
+ let mddrs = [];
1150
+ for(const addr of addrs){
1151
+ const peeraddr = addr+'/p2p/'+id;
1152
+ const mddr = multiaddr(peeraddr);
1153
+ mddrs.push(mddr);
1154
+ }
1155
+ this.#dialMultiaddress(mddrs);
1156
+ }
1157
+ }
1158
+ }
1159
+ },45*1000);
1160
+ }
1161
+
1162
+
1163
+ //track for good connection
1164
+ async #connectionTracker(){
1165
+
1166
+ for await (const { key, value } of this.#dbstore.query({})) {
1167
+ const id = key.toString().split('/')[1];
1168
+ const addr = new TextDecoder().decode(value);
1169
+ this.#dbstoreData.set(id,addr);
1170
+ }
1171
+
1172
+ setInterval(async ()=>{
1173
+
1174
+ //save peer address if connection is good
1175
+ const connections = this.#libp2p.getConnections();
1176
+ for(const connect of connections){
1177
+ const peer = connect.remotePeer;
1178
+ const remote = connect.remoteAddr;
1179
+ const upgraded = connect.timeline.upgraded;
1180
+ const bestlimit = 5*60*1000;
1181
+ const now = new Date().getTime();
1182
+ const besttime = now-upgraded;
1183
+ if(besttime>bestlimit){
1184
+ const addr = remote.toString();
1185
+ const id = peer.toString();
1186
+ if(!this.#webPeersId.includes(id) && !CONFIG_KNOWN_BOOTSTRAP_PEER_IDS.includes(id) && !this.#dbstoreData.get(id) && !addr.includes('p2p-circuit')){
1187
+ //await this.#dbstore.delete(new Key(id))
1188
+ await this.#dbstore.put(new Key(id), new TextEncoder().encode(addr));
1189
+ this.#dbstoreData.set(id,addr);
1190
+ }
1191
+ }
1192
+ const goodlimit = 60*1000;
1193
+ const goodtime = now-upgraded;
1194
+ if(goodtime>goodlimit){
1195
+ const id = peer.toString();
1196
+ if(!this.#dialedGoodPeers.has(id))this.#dialedGoodPeers.set(id,0);
1197
+ }
1198
+
1199
+ }
1200
+
1201
+
1202
+ let peers = [];
1203
+ for(const peer of this.#libp2p.getPeers()){
1204
+ peers.push(peer.toString());
1205
+ }
1206
+
1207
+
1208
+ //connect to saved best peer address
1209
+ //working great
1210
+ for(const peer of this.#dbstoreData){
1211
+ const id = peer[0];
1212
+ const addr = peer[1];
1213
+ if(peers.includes(id)){
1214
+ this.#connectionTrackerStore.set(id,0);
1215
+ continue
1216
+ }else {
1217
+ if(this.#connectionTrackerStore.has(id)){
1218
+ let current = this.#connectionTrackerStore.get(id);
1219
+ if(current>10)continue
1220
+ current++;
1221
+ this.#connectionTrackerStore.set(id,current);
1222
+ }
1223
+ else {
1224
+ this.#connectionTrackerStore.set(id,0);
1225
+ }
1226
+ let mddrs = [];
1227
+ const mddr = multiaddr(addr);
1228
+ mddrs.push(mddr);
1229
+ this.#dialMultiaddress(mddrs);
1230
+ }
1231
+ }
1232
+
1233
+ //connect to good peer address if it is disconnected
1234
+ const goods = Array.from(this.#dialedGoodPeers.keys());
1235
+ for(const id of goods){
1236
+ if(peers.includes(id)){
1237
+ this.#dialedGoodPeers.set(id,0);
1238
+ continue
1239
+ }
1240
+ else {
1241
+
1242
+ let count = this.#dialedGoodPeers.get(id);
1243
+ if (count < 15 || (count < 25 && this.#dialedKnownBootstrap.has(id))){
1244
+ const addr = this.#connections.get(id);
1245
+ let mddrs = [];
1246
+ const mddr = multiaddr(addr);
1247
+ mddrs.push(mddr);
1248
+ this.#dialMultiaddress(mddrs);
1249
+ count++;
1250
+ this.#dialedGoodPeers.set(id,count);
1251
+ }
1252
+ }
1253
+ }
1254
+
1255
+ },30*1000);
1256
+ }
1257
+
1258
+
1259
+ //update listen address on change
1260
+ //#ListenAddressChange = () => {}
1261
+ //#onSelfAddress = f => (this.#ListenAddressChange = f)
1262
+
1263
+
1264
+ //Periodically watch for connection
1265
+ #watchConnection(){
1266
+ setInterval(()=>{
1267
+ const peers = this.#libp2p.getPeers().length;
1268
+ if(peers == 0){
1269
+ this.#dialKnownPeers();
1270
+ }
1271
+ },60*1000);
1272
+ }
1273
+
1274
+
1275
+ //dial to all known bootstrap peers and DNS
1276
+ #dialKnownPeers(){
1277
+ this.#dialKnownBootstrap();
1278
+ setTimeout(()=>{
1279
+ const peers = this.#libp2p.getPeers().length;
1280
+ if(peers == 0){
1281
+ //currently not needed
1282
+ //this.#dialKnownID()
1283
+ setTimeout(()=>{
1284
+ const peers = this.#libp2p.getPeers().length;
1285
+ if(peers == 0){
1286
+ //currently not needed
1287
+ //this.#dialKnownDNS()
1288
+ setTimeout(()=>{
1289
+ this.#libp2p.getPeers().length;
1290
+ },15000);
1291
+ }
1292
+ },15000);
1293
+ }
1294
+ },15000);
1295
+ }
1296
+
1297
+
1298
+ //dial based on known bootsrap peers address
1299
+ #dialKnownBootstrap(){
1300
+ const bootstrap = CONFIG_KNOWN_BOOTSTRAP_PEERS_ADDRS;
1301
+ for(const peer of bootstrap){
1302
+ const address = peer.Peers[0].Addrs;
1303
+ const id = peer.Peers[0].ID;
1304
+ let mddrs = [];
1305
+ let addrs = [];
1306
+ for(const addr of address){
1307
+ const peeraddr = addr+'/p2p/'+id;
1308
+ const peermddr = multiaddr(peeraddr);
1309
+ addrs.push(peeraddr);
1310
+ mddrs.push(peermddr);
1311
+ }
1312
+
1313
+ this.#dialedKnownBootstrap.set(id,addrs);
1314
+ if(!this.#isConnected(id)){
1315
+ this.#dialMultiaddress(mddrs);
1316
+ }
1317
+
1318
+ }
1319
+ }
1320
+
1321
+
1322
+ //dial based on known peers ID
1323
+ /*async #dialKnownID(){
1324
+ const api = config.CONFIG_DELEGATED_API
1325
+ const delegatedClient = createDelegatedRoutingV1HttpApiClient(api)
1326
+ const BOOTSTRAP_PEER_IDS = config.CONFIG_KNOWN_BOOTSTRAP_PEER_IDS
1327
+ const peers = await Promise.all(
1328
+ BOOTSTRAP_PEER_IDS.map((peerId) => first(delegatedClient.getPeers(peerIdFromString(peerId)))),
1329
+ )
1330
+ for(const peer of peers){
1331
+ if(!peer)return
1332
+ const address = peer.Addrs
1333
+ const id = peer.ID
1334
+ let mddrs = []
1335
+ let addrs = []
1336
+ for(const addr of address){
1337
+ const peeraddr = addr.toString()+'/p2p/'+id.toString()
1338
+ const peermddr = multiaddr(peeraddr)
1339
+ addrs.push(peeraddr)
1340
+ mddrs.push(peermddr)
1341
+ }
1342
+
1343
+ this.#dialedKnownBootstrap.set(id,addrs)
1344
+ if(!this.#isConnected(id)){
1345
+ this.#dialMultiaddress(mddrs)
1346
+ }
1347
+ }
1348
+ }*/
1349
+
1350
+
1351
+ //dial based on known bootstrap DNS
1352
+ /*async #dialKnownDNS(){
1353
+ const dnsresolver = config.CONFIG_DNS_RESOLVER
1354
+ const bootstrapdns = config.CONFIG_KNOWN_BOOTSTRAP_DNS
1355
+ const response = await fetch(dnsresolver+'?name='+bootstrapdns+'&type=txt')
1356
+ const json = await response.json()
1357
+ const dns = json.Answer
1358
+ const BOOTSTRAP_PEER_IDS = []
1359
+ for(const dnsaddr of dns){
1360
+ const id = dnsaddr.data.split('/').pop()
1361
+ BOOTSTRAP_PEER_IDS.push(id)
1362
+ }
1363
+ const api = config.CONFIG_DELEGATED_API
1364
+ const delegatedClient = createDelegatedRoutingV1HttpApiClient(api)
1365
+ const peers = await Promise.all(
1366
+ BOOTSTRAP_PEER_IDS.map((peerId) => first(delegatedClient.getPeers(peerIdFromString(peerId)))),
1367
+ )
1368
+ for(const peer of peers){
1369
+ const address = peer.Addrs
1370
+ const id = peer.ID
1371
+ let mddrs = []
1372
+ let addrs = []
1373
+ for(const addr of address){
1374
+ const peeraddr = addr.toString()+'/p2p/'+id.toString()
1375
+ const peermddr = multiaddr(peeraddr)
1376
+ addrs.push(peeraddr)
1377
+ mddrs.push(peermddr)
1378
+ }
1379
+
1380
+ this.#dialedKnownBootstrap.set(id,addrs)
1381
+ if(!this.#isConnected(id)){
1382
+ this.#dialMultiaddress(mddrs)
1383
+ }
1384
+ }
1385
+
1386
+ }*/
1387
+
1388
+
1389
+ //dial based on known bootstrap DNS using DNS resolver only
1390
+ /*async #dialKnownDNSonly(){
1391
+ const dnsresolver = config.CONFIG_DNS_RESOLVER
1392
+ const bootstrapdns = config.CONFIG_KNOWN_BOOTSTRAP_DNS
1393
+ const response = await fetch(dnsresolver+'?name='+bootstrapdns+'&type=txt')
1394
+ const json = await response.json()
1395
+ const dns = json.Answer
1396
+
1397
+ for(const dnsitem of dns){
1398
+ const arr = dnsitem.data.split('/')
1399
+ const id = arr.pop()
1400
+ const dnsaddr = '_dnsaddr.'+arr[2]
1401
+ this.#dialDNSWebsocketWebtransport(id,dnsaddr)
1402
+ }
1403
+ }*/
1404
+
1405
+
1406
+ //dial DNS with webtransport and websocket
1407
+ /*async #dialDNSWebsocketWebtransport(id,dnsaddr){
1408
+ const dnsresolver = config.CONFIG_DNS_RESOLVER
1409
+ const response = await fetch(dnsresolver+'?name='+dnsaddr+'&type=txt')
1410
+ const json = await response.json()
1411
+ const dns = json.Answer
1412
+ let mddrs = []
1413
+ let addrs = []
1414
+ for(const dnsitem of dns){
1415
+ const arr = dnsitem.data.split('=')
1416
+ const dnsaddr = arr[1]
1417
+ const maddr = multiaddr(dnsaddr)
1418
+ mddrs.push(maddr)
1419
+ addrs.push(dnsaddr)
1420
+ }
1421
+
1422
+
1423
+ this.#isDialWebsocket = true
1424
+ this.#dialedKnownBootstrap.set(id,addrs)
1425
+
1426
+ this.#dialedKnownBootstrap.set(id,addrs)
1427
+ if(!this.#isConnected(id)){
1428
+ this.#dialMultiaddress(mddrs)
1429
+ this.#dialWebsocket(mddrs)
1430
+ }
1431
+ }*/
1432
+
1433
+
1434
+ //dial only webtransport multiaddrs
1435
+ async #dialWebtransport(multiaddrs){
1436
+ const webTransportMadrs = multiaddrs.filter((maddr) => maddr.protoNames().includes('webtransport')&&maddr.protoNames().includes('certhash'));
1437
+ for (const addr of webTransportMadrs) {
1438
+ try {
1439
+ //console.log(`attempting to dial webtransport multiaddr: %o`, addr.toString())
1440
+ await this.#libp2p.dial(addr);
1441
+ return // if we succeed dialing the peer, no need to try another address
1442
+ } catch (error) {
1443
+ //console.log(`failed to dial webtransport multiaddr: %o`, addr.toString())
1444
+ console.debug(error);
1445
+ }
1446
+ }
1447
+ }
1448
+
1449
+ //dial only webtransport multiaddrs
1450
+ /*#dialWebtransport1(multiaddrs){
1451
+ const webTransportMadrs = multiaddrs.filter((maddr) => maddr.protoNames().includes('webtransport')&&maddr.protoNames().includes('certhash'))
1452
+ if(webTransportMadrs.length == 0)return
1453
+ this.#libp2p.dial(webTransportMadrs).then((data)=>{console.warn(data)},(data)=>{console.warn(data)})
1454
+ }*/
1455
+
1456
+ //dial only websocket multiaddrs
1457
+ async #dialWebsocket(multiaddrs){
1458
+ const webSocketMadrs = multiaddrs.filter((maddr) => maddr.protoNames().includes('wss'));
1459
+ for (const addr of webSocketMadrs) {
1460
+ try {
1461
+ //console.log(`attempting to dial websocket multiaddr: %o`, addr)
1462
+ await this.#libp2p.dial(addr);
1463
+ return // if we succeed dialing the peer, no need to try another address
1464
+ } catch (error) {
1465
+ //console.log(`failed to dial websocket multiaddr: %o`, addr)
1466
+ console.debug(error);
1467
+ }
1468
+ }
1469
+ }
1470
+
1471
+
1472
+ //entry point to webpeerjs
1473
+ static async createWebpeer(){
1474
+
1475
+ // all libp2p debug logs
1476
+ localStorage.setItem('debug', 'libp2p:*');
1477
+
1478
+ const dbstore = new IDBDatastore(CONFIG_DBSTORE_PATH);
1479
+ await dbstore.open();
1480
+
1481
+ //let addrs = []
1482
+ const getbootstrap = CONFIG_KNOWN_BOOTSTRAP_PEERS_ADDRS;
1483
+ for(const peer of getbootstrap){
1484
+ const addrs = peer.Peers[0].Addrs;
1485
+ peer.Peers[0].ID;
1486
+ //let mddrs = []
1487
+ for(const addr of addrs){
1488
+ if(addr.includes('webtransport')&&addr.includes('certhash'));
1489
+ }
1490
+ }
1491
+
1492
+ let onMetricsFn = () => {};
1493
+ const onMetrics = f => (onMetricsFn = f);
1494
+
1495
+ //create libp2p instance
1496
+ const libp2p = await createLibp2p({
1497
+ addresses: {
1498
+ listen: [
1499
+ ],
1500
+ },
1501
+ transports:[
1502
+ webTransport(),
1503
+ circuitRelayTransport({
1504
+ discoverRelays: CONFIG_DISCOVER_RELAYS,
1505
+ reservationConcurrency: 1,
1506
+ maxReservationQueueLength: 3
1507
+ }),
1508
+ ],
1509
+ connectionManager: {
1510
+ maxConnections: CONFIG_MAX_CONNECTIONS,
1511
+ minConnections: CONFIG_MIN_CONNECTIONS,
1512
+ autoDialInterval:60e3,
1513
+ autoDialConcurrency:0,
1514
+ autoDialMaxQueueLength:0,
1515
+ autoDialPriority:1000,
1516
+ autoDialDiscoveredPeersDebounce:30e3,
1517
+ maxParallelDials: 3,
1518
+ dialTimeout: 5e3,
1519
+ maxIncomingPendingConnections: 5,
1520
+ maxDialQueueLength:10,
1521
+ inboundConnectionThreshold:3,
1522
+ maxPeerAddrsToDial:2,
1523
+ inboundUpgradeTimeout:5e3
1524
+ },
1525
+ connectionEncryption: [noise()],
1526
+ streamMuxers: [
1527
+ yamux({
1528
+ maxInboundStreams: 50,
1529
+ maxOutboundStreams: 50,
1530
+ })
1531
+ ],
1532
+ connectionGater: {
1533
+ filterMultiaddrForPeer: async (peer, multiaddrTest) => {
1534
+ const multiaddrString = multiaddrTest.toString();
1535
+ if (
1536
+ multiaddrString.includes("/ip4/127.0.0.1") ||
1537
+ multiaddrString.includes("/ip6/")
1538
+ ) {
1539
+ return false;
1540
+ }
1541
+ return true;
1542
+ },
1543
+ denyDialMultiaddr: async (multiaddrTest) => {
1544
+ const multiaddrString = multiaddrTest.toString();
1545
+ if (
1546
+ multiaddrString.includes("/ip4/127.0.0.1") ||
1547
+ multiaddrString.includes("/ip6/")
1548
+ ) {
1549
+ return true;
1550
+ }
1551
+ return false;
1552
+ },
1553
+ },
1554
+ peerDiscovery: [
1555
+ pubsubPeerDiscovery({
1556
+ interval: 10_000,
1557
+ topics: CONFIG_PUBSUB_PEER_DISCOVERY,
1558
+ listenOnly: false,
1559
+ }),
1560
+
1561
+ ],
1562
+ services: {
1563
+ pubsub: gossipsub({
1564
+ allowPublishToZeroTopicPeers: true,
1565
+ msgIdFn: msgIdFnStrictNoSign,
1566
+ ignoreDuplicatePublishError: true,
1567
+ }),
1568
+ identify: identify(),
1569
+ identifyPush: identifyPush(),
1570
+ aminoDHT: kadDHT({
1571
+ protocol: '/ipfs/kad/1.0.0',
1572
+ peerInfoMapper: removePrivateAddressesMapper,
1573
+ clientMode: false
1574
+ }),
1575
+
1576
+ },
1577
+ peerStore: {
1578
+ persistence: true,
1579
+ threshold: 1
1580
+ },
1581
+ metrics: simpleMetrics({
1582
+ onMetrics: (metrics) => {onMetricsFn(metrics);},
1583
+ intervalMs: 1000
1584
+ })
1585
+ });
1586
+
1587
+
1588
+
1589
+ //console.log(`Node started with id ${libp2p.peerId.toString()}`)
1590
+
1591
+ //DHT server mode act as bootstrap peer in IPFS network
1592
+ await libp2p.services.aminoDHT.setMode("server");
1593
+
1594
+
1595
+ //return webpeerjs class
1596
+ return new webpeerjs(libp2p,dbstore,onMetrics)
1597
+ }
1598
+ }
1599
+
1600
+ export { webpeerjs };