webpeerjs 0.2.1 → 0.2.3

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 CHANGED
@@ -1,11 +1,15 @@
1
- # WebPEER.js
1
+ # WebPEER
2
2
 
3
- WebPEER is a P2P Network that Runs in a Standard Browser.
3
+ WebPEER is a Decentralized P2P Network that Runs on Standard Browser. It allows developers to build peer-to-peer webapps without relying on centralized servers or specialized browsers. Aims to return internet control back to users.
4
4
 
5
5
  [>DEMO<](https://nuzulul.github.io/webpeerjs/demo/chat.html)
6
6
 
7
7
  ![WebPEER](webpeer.png)
8
8
 
9
+ ## Library
10
+
11
+ - [WebPEER.js](https://www.npmjs.com/package/webpeerjs) - JavaScript implementation designed as minimal, low level API provided to build decentralized P2P webapss on top WebPEER Network. Internally, it uses libp2p modular JavaScript stack as its engine.
12
+
9
13
  ## Security
10
14
 
11
15
  WebPEER Network run over [`libp2p gossipsub`](https://docs.libp2p.io/concepts/security/security-considerations/#publish--subscribe) protocol to enables communication between peers.
@@ -13,12 +17,14 @@ WebPEER Network run over [`libp2p gossipsub`](https://docs.libp2p.io/concepts/se
13
17
 
14
18
  > However, as a cooperative protocol, it may be possible for peers to interfere with the message routing algorithm in a way that disrupts the flow of messages through the network.
15
19
 
16
- ## Features
20
+ ## Benefit
17
21
 
18
- * ✅ Distributed P2P
22
+ * ✅ Decentralized P2P Network
19
23
  * ✅ Scalable Peers
20
- * ✅ Works in Browsers
21
- * ✅ Broadcast Messages
24
+ * ✅ Accessible in Standard Browser
25
+ * ✅ Broadcast Channel Provided
26
+ * ✅ No Server Required
27
+ * ✅ Freedom
22
28
 
23
29
  ## Ideas
24
30
 
@@ -26,13 +32,14 @@ WebPEER Network run over [`libp2p gossipsub`](https://docs.libp2p.io/concepts/se
26
32
  * Voting / Polling
27
33
  * Collaborative activity
28
34
  * IoT
29
- * social media
35
+ * Social media
30
36
  * Remote control
31
37
  * Multiplayer games
32
38
  * Distributed web
33
39
  * Signalling protocol
34
40
  * Location tracker
35
41
  * Activity tracker.
42
+ * Chat messenger
36
43
 
37
44
  ## Try it out!
38
45
 
@@ -66,7 +73,7 @@ CDN :
66
73
  </script>
67
74
  ```
68
75
 
69
- ## Example
76
+ ## Usage
70
77
 
71
78
  ```
72
79
  import { createWebPEER } from 'webpeerjs'
@@ -100,24 +107,27 @@ Create a new peer node.
100
107
 
101
108
  `config` - Configuration object contains:
102
109
 
103
- - `networkName` - Unique identifier name of your network.
110
+ - `networkName` - Unique identifier name of the network to build.
104
111
 
105
- - `rtcConfiguration` - **(optional)** Custom [rtcConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection) for WebRTC transport.
112
+ - `rtcConfiguration` - **(optional)** Custom [rtcConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection) for WebRTC connection.
106
113
 
107
114
  ### `peer.id`
108
115
 
109
- Get the unique ID of the peer node.
116
+ Get the unique ID of this peer node.
110
117
 
111
118
  ### `peer.status`
112
119
 
113
- Get the peer node status, returns `connected` or `disconnected`.
120
+ Get the peer node status, returns `connecting` or `connected`.
121
+
122
+ - `connecting` - Currently not connected and is trying to connect to the network.
123
+ - `connected` - Currently connected to the network.
114
124
 
115
125
  ### `room = peer.joinRoom(namespace)`
116
126
 
117
127
  Join to a room, returns an object.
118
128
 
119
- - `room.sendMessage()` - Function to broadcast message to the room.
120
- - `romm.onMessage((message,id)=>{})` - Listen on incoming broadcast message.
129
+ - `room.sendMessage()` - Method to broadcast message to the room.
130
+ - `romm.onMessage((message,peer_id)=>{})` - Listen on incoming broadcast message.
121
131
  - `room.onMembersChange((members)=>{})` - Listen on the room members update.
122
132
 
123
133
  ## See Also
@@ -126,5 +136,5 @@ Join to a room, returns an object.
126
136
 
127
137
  ## License
128
138
 
129
- [MIT (c) 2024](https://github.com/nuzulul/webpeerjs/blob/main/LICENSE) [Nuzulul Zulkarnain](https://github.com/nuzulul)
139
+ [MIT](https://github.com/nuzulul/webpeerjs/blob/main/LICENSE) (c) 2024 [Nuzulul Zulkarnain](https://github.com/nuzulul)
130
140
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "webpeerjs",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
- "description": "WebPEER is P2P Network that Runs in a Standard Browser",
5
+ "description": "WebPEER is P2P Network that Runs on Standard Browser",
6
6
  "main": "./src/webpeer.js",
7
7
  "module": "./src/webpeer.js",
8
8
  "exports": {
@@ -70,9 +70,9 @@
70
70
  "it-map": "^3.1.6",
71
71
  "it-pipe": "^3.0.1",
72
72
  "libp2p": "^3.3.4",
73
- "multiformats": "^14.0.2",
73
+ "multiformats": "^14.0.3",
74
74
  "protons-runtime": "^7.0.0",
75
- "signalingserver.js": "^0.0.6",
75
+ "signalingserver.js": "^0.0.7",
76
76
  "uint8arrays": "^6.1.1"
77
77
  }
78
78
  }
package/src/config.js CHANGED
@@ -6,7 +6,7 @@ export const CONFIG_PROTOCOL = '/'+prefix+'/1.0.0'
6
6
  export const CONFIG_BLOCKSTORE_PATH = prefix+'-blockstore'
7
7
  export const CONFIG_DATASTORE_PATH = prefix+'-datastore'
8
8
  export const CONFIG_DBSTORE_PATH = prefix+'-dbstore'
9
- export const CONFIG_MAX_CONNECTIONS = 30
9
+ export const CONFIG_MAX_CONNECTIONS = 50
10
10
  export const CONFIG_MIN_CONNECTIONS = 0
11
11
  export const CONFIG_DISCOVER_RELAYS = 1
12
12
  export const CONFIG_PEER_DISCOVERY_UNIVERSAL_CONNECTIVITY = 'universal-connectivity-browser-peer-discovery'
@@ -20,12 +20,12 @@ export const CONFIG_DELEGATED_API = 'https://delegated-ipfs.dev'
20
20
  export const CONFIG_DNS_RESOLVER = 'https://dns.google/resolve'
21
21
  export const CONFIG_KNOWN_BOOTSTRAP_DNS = '_dnsaddr.bootstrap.libp2p.io'
22
22
  export const CONFIG_JOIN_ROOM_VERSION = 1
23
- export const CONFIG_TIMEOUT_DIAL_KNOWN_PEERS = 15000
23
+ export const CONFIG_TIMEOUT_DIAL_KNOWN_PEERS = 15*1000
24
24
  export const CONFIG_RUN_ON_TRANSIENT_CONNECTION = false
25
- export const CONFIG_MESSAGE_SIZE_LIMIT = 100*1024 // 100KB
26
- export const CONFIG_DEBUG_ENABLED = true
25
+ export const CONFIG_DEBUG_ENABLED = false
27
26
  export const CONFIG_AUTODIAL_MAX_ERROR_LIMIT = 45
28
27
  export const CONFIG_DIAL_MAX_ERROR_LIMIT = 55
28
+ export const CONFIG_DIAL_WEBSOCKET_FIRST = true;
29
29
 
30
30
  // this list comes from https://github.com/ipfs/kubo/blob/196887cbe5fbcd41243c1dfb0db681a1cc2914ff/config/bootstrap_peers.go
31
31
  export const CONFIG_KNOWN_DEFAULT_BOOTSTRAP_ADDRESSES = [
package/src/webpeer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //! WebPEER.js -- https://github.com/nuzulul/webpeerjs
2
-
2
+
3
3
  import * as config from './config.js'
4
4
  import {
5
5
  mkErr,
@@ -97,9 +97,6 @@ class webpeerjs{
97
97
  //message tracker avoid double
98
98
  #msgIdtracker
99
99
 
100
- //inbound message time tracker
101
- #msgTimeTracker
102
-
103
100
  //map of peer exchange data
104
101
  #peerexchangedata
105
102
 
@@ -146,7 +143,6 @@ class webpeerjs{
146
143
  this.#lastTimeConnectToNetwork = new Date().getTime()
147
144
  this.#lastTimeReceiveData = new Date().getTime()
148
145
  this.#onConnectQueue = []
149
- this.#msgTimeTracker = new Map()
150
146
 
151
147
  this.peers = (function(f) {
152
148
  return f
@@ -156,7 +152,7 @@ class webpeerjs{
156
152
  return libp2p.status
157
153
  })(this.#libp2p);
158
154
 
159
- this.status = 'disconnected'
155
+ this.status = 'connecting'
160
156
 
161
157
  this.IPFS = (function(libp2p,discoveredPeers) {
162
158
  const obj = {libp2p,discoveredPeers}
@@ -448,17 +444,11 @@ class webpeerjs{
448
444
 
449
445
  //inbound message
450
446
  //use #msgIdtracker to prevent double message
451
- //use #msgTimeTracker to limit inbound message count /s
452
447
  if(message){
453
448
  const msgID = msgId+id
454
- let oldmsgtime = 0
455
449
  let newmsgtime = new Date().getTime()
456
- if(this.#msgTimeTracker.has(id))oldmsgtime = this.#msgTimeTracker.get(id)
457
- //const msgtimelimit = 1000
458
- const msgtimelimit = -1
459
- if(!this.#msgIdtracker.has(msgID) && newmsgtime-oldmsgtime>msgtimelimit){
450
+ if(!this.#msgIdtracker.has(msgID)){
460
451
  this.#msgIdtracker.set(msgID,newmsgtime)
461
- this.#msgTimeTracker.set(id,newmsgtime)
462
452
  this.#rooms[room].onMessage(message,id)
463
453
  }
464
454
  }
@@ -592,21 +582,21 @@ class webpeerjs{
592
582
  let count = this.#trackDisconnect.get(id)
593
583
  count++
594
584
  this.#trackDisconnect.set(id,count)
585
+
595
586
  //console.log(this.#trackDisconnect)
596
587
  if(count>5){
597
588
  if(config.CONFIG_KNOWN_BOOTSTRAP_PUBLIC_IDS.includes(id)){
598
589
  return
599
590
  }
600
- }
601
- else if(count>10){
602
591
  if(this.#dbstoreData.has(id)){
603
592
  this.#dbstoreData.delete(id)
604
593
  }
605
594
 
606
595
  if(!this.#webPeersId.includes(id) && !this.#dialedKnownBootstrap.has(id)){
607
596
  return
608
- }
597
+ }
609
598
  }
599
+
610
600
  }
611
601
  else{
612
602
  this.#trackDisconnect.set(id,0)
@@ -669,8 +659,14 @@ class webpeerjs{
669
659
  const addrs = []
670
660
  peer.addresses.forEach((address)=>{
671
661
  const addr = address.multiaddr.toString()+'/p2p/'+id
672
- if(addr.includes('webtransport') && addr.includes('certhash')){
673
- addrs.push(addr)
662
+ if(config.CONFIG_DIAL_WEBSOCKET_FIRST){
663
+ if(addr.includes('/webtransport/') || addr.includes('/ws/') || addr.includes('/wss/')){
664
+ addrs.push(addr)
665
+ }
666
+ }else{
667
+ if(addr.includes('webtransport') && addr.includes('certhash')){
668
+ addrs.push(addr)
669
+ }
674
670
  }
675
671
  })
676
672
  if(!config.CONFIG_RUN_ON_TRANSIENT_CONNECTION)addrs.reverse()
@@ -678,6 +674,7 @@ class webpeerjs{
678
674
  this.address = addrs
679
675
  this.#ping()
680
676
  this.#peerDiscoveryHybrid()
677
+
681
678
  if(addrs.length > 0){
682
679
  const broadcast = {
683
680
  id : this.id,
@@ -686,8 +683,13 @@ class webpeerjs{
686
683
  signalingserver.send(broadcast);
687
684
  this.status = 'connected'
688
685
  }else{
689
- this.status = 'disconnected'
686
+ if(this.#connectedPeers.size > 0){
687
+ this.status = 'connected'
688
+ }else{
689
+ this.status = 'connecting'
690
+ }
690
691
  }
692
+
691
693
  })
692
694
 
693
695
 
@@ -764,10 +766,11 @@ class webpeerjs{
764
766
 
765
767
  this.#registerProtocol()
766
768
 
767
-
769
+ //get on signal from metrics
768
770
  onMetrics((data)=>{
769
771
  const signal = metrics(data)
770
772
  this.#isDialEnabled = signal.isDialEnabled
773
+ if(!this.#isDialEnabled){console.log('dial disabled')};
771
774
  onDialFn(signal.isAutoDialEnabled)
772
775
 
773
776
  })
@@ -792,6 +795,14 @@ class webpeerjs{
792
795
  this.#garbageCollectionMsgIdTracker()
793
796
  },10e3)
794
797
 
798
+ //if no address and peers after timeout dial bootstarp with websocket
799
+ /*setTimeout(()=>{
800
+ if(this.address.length === 0 && this.#connectedPeersArr.length === 0){
801
+ console.log('backup');
802
+ this.#dialKnownDNS();
803
+ }
804
+ },90e3)*/
805
+
795
806
 
796
807
  /*setTimeout(async()=>{
797
808
  try{
@@ -874,10 +885,6 @@ class webpeerjs{
874
885
  const msgId = crypto.randomUUID();
875
886
  const data = JSON.stringify({prefix:config.CONFIG_PREFIX,room,message,id:this.#libp2p.peerId.toString(),msgId})
876
887
  const arr = uint8ArrayFromString(data)
877
- const sizelimit = config.CONFIG_MESSAGE_SIZE_LIMIT
878
- if(arr.byteLength > sizelimit){
879
- throw mkErr(`Only message less than ${sizelimit} byte allowed`);
880
- }
881
888
  const peer = {
882
889
  publicKey: this.#libp2p.peerId.publicKey,
883
890
  addrs: [arr],
@@ -983,6 +990,18 @@ class webpeerjs{
983
990
  const item = {id:peer[0],address:peer[1].addrs}
984
991
  this.#connectedPeersArr.push(item)
985
992
  }
993
+
994
+ //update status
995
+ if(this.#connectedPeers.size > 0){
996
+ this.status = 'connected';
997
+ }else{
998
+ if(this.address.length > 0){
999
+ this.status = 'connected';
1000
+ }else{
1001
+ this.status = 'connecting';
1002
+ }
1003
+ }
1004
+
986
1005
  this.#ping()
987
1006
  }
988
1007
 
@@ -1558,6 +1577,8 @@ class webpeerjs{
1558
1577
  }
1559
1578
  }
1560
1579
  }
1580
+
1581
+
1561
1582
  //track for good connection
1562
1583
  async #connectionTracker(){
1563
1584
 
@@ -1591,41 +1612,52 @@ class webpeerjs{
1591
1612
  }
1592
1613
 
1593
1614
 
1594
- //dial to all known bootstrap peers and DNS
1595
- #dialKnownPeers(){
1596
- setTimeout(()=>{
1597
- this.#dialSavedKnownID()
1598
- setTimeout(()=>{this.#dialUpdateSavedKnownID()},20000)
1599
- setTimeout(()=>{this.#findHybridPeer()},30000)
1600
- setTimeout(()=>{
1601
- const peers = this.#libp2p.getPeers().length
1602
- if(peers == 0){
1603
- this.#dialKnownID()
1604
- setTimeout(()=>{this.#findHybridPeer()},30000)
1605
- setTimeout(()=>{
1606
- const peers = this.#libp2p.getPeers().length
1607
- if(peers == 0){
1608
- this.#dialKnownBootstrap()
1609
- setTimeout(()=>{this.#findHybridPeer()},15000)
1610
- setTimeout(()=>{
1611
- const peers = this.#libp2p.getPeers().length
1612
- if(peers == 0){
1613
- this.#dialKnownDNS()
1614
- setTimeout(()=>{this.#findHybridPeer()},15000)
1615
- setTimeout(()=>{
1616
- const peers = this.#libp2p.getPeers().length
1617
- if(peers == 0){
1618
- this.#dialKnownDNSonly()
1619
- setTimeout(()=>{this.#findHybridPeer()},15000)
1620
- }
1621
- },config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS)
1622
- }
1623
- },config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS)
1624
- }
1625
- },config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS)
1626
- }
1627
- },config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS)
1628
- },5000)
1615
+ //dial to all known bootstrap peers
1616
+
1617
+ #dialKnownPeers(method){
1618
+
1619
+ const peers = this.#libp2p.getPeers().length;
1620
+
1621
+ if(!method){
1622
+ if(config.CONFIG_DIAL_WEBSOCKET_FIRST){
1623
+ this.#isDialWebsocket = true
1624
+ this.#onWebsocketFn(true)
1625
+ setTimeout(()=>this.#dialKnownPeers('default'), 5*1000);
1626
+ }else{
1627
+ setTimeout(()=>this.#dialKnownPeers('webtransport'), 5*1000);
1628
+ }
1629
+ }
1630
+
1631
+ if(method === 'default' && peers === 0){
1632
+ this.#dialDefaultBootstarp();
1633
+ setTimeout(()=>this.#dialKnownPeers('dnsonly'), config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS);
1634
+ }
1635
+
1636
+ if(method === 'webtransport' && peers === 0){
1637
+ this.#dialSavedKnownID();
1638
+ setTimeout(()=>this.#dialUpdateSavedKnownID(),20*1000);
1639
+ setTimeout(()=>this.#dialKnownPeers('id'), config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS);
1640
+ }
1641
+
1642
+ if(method === 'id' && peers === 0){
1643
+ this.#dialKnownID();
1644
+ setTimeout(()=>this.#dialKnownPeers('bootstarp'), config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS);
1645
+ }
1646
+
1647
+ if(method === 'bootstarp' && peers === 0){
1648
+ this.#dialKnownBootstrap();
1649
+ setTimeout(()=>this.#dialKnownPeers('dns'), config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS);
1650
+ }
1651
+
1652
+ if(method === 'dns' && peers === 0){
1653
+ this.#dialKnownDNS();
1654
+ setTimeout(()=>this.#dialKnownPeers('dnsonly'), config.CONFIG_TIMEOUT_DIAL_KNOWN_PEERS);
1655
+ }
1656
+
1657
+ if(method === 'dnsonly' && peers === 0){
1658
+ this.#dialKnownDNSonly();
1659
+ }
1660
+
1629
1661
  }
1630
1662
 
1631
1663
  async #findHybridPeer(){
@@ -1667,6 +1699,19 @@ class webpeerjs{
1667
1699
  }
1668
1700
  }
1669
1701
 
1702
+ async #dialDefaultBootstarp(){
1703
+ for(const addr of config.CONFIG_KNOWN_DEFAULT_BOOTSTRAP_ADDRESSES){
1704
+ const mddr = multiaddr(addr)
1705
+ try {
1706
+ //console.log(`attempting to dial websocket multiaddr: %o`, mddr)
1707
+ await this.#libp2p.dial(mddr)
1708
+ } catch (error) {
1709
+ //console.log(`failed to dial websocket multiaddr: %o`, mddr)
1710
+ mkDebug(error)
1711
+ }
1712
+ }
1713
+ }
1714
+
1670
1715
  async #dialSavedKnownID(){
1671
1716
 
1672
1717
  if(!navigator.onLine)return
@@ -1699,11 +1744,11 @@ class webpeerjs{
1699
1744
  const id = peer.ID
1700
1745
  let mddrs = []
1701
1746
  let addrs = []
1702
- for(const addr of address){
1703
- const peeraddr = addr.toString()+'/p2p/'+id.toString()
1704
- const peermddr = multiaddr(peeraddr)
1705
- addrs.push(peeraddr)
1706
- mddrs.push(peermddr)
1747
+ for(const rawaddr of address){
1748
+ const addr = rawaddr.toString()+'/p2p/'+id.toString()
1749
+ const mddr = multiaddr(addr)
1750
+ addrs.push(addr)
1751
+ mddrs.push(mddr)
1707
1752
  }
1708
1753
 
1709
1754
  this.#dialedKnownBootstrap.set(id,addrs)
@@ -1714,18 +1759,26 @@ class webpeerjs{
1714
1759
  }
1715
1760
  }
1716
1761
 
1762
+
1763
+ //Update saved bootstrap address
1717
1764
  async #dialUpdateSavedKnownID(){
1718
1765
 
1719
1766
  if(!navigator.onLine)return
1720
1767
  if(!this.#isDialEnabled)return
1721
1768
 
1722
1769
  let firsttime = true
1770
+
1723
1771
  for(const target of config.CONFIG_KNOWN_BOOTSTRAP_PEERS_IDS){
1772
+
1724
1773
  if(this.#dbstoreData.has(target)){
1725
1774
  firsttime = false
1726
1775
  }
1776
+ }
1777
+
1778
+ for(const target of config.CONFIG_KNOWN_BOOTSTRAP_PEERS_IDS){
1779
+
1727
1780
  if(!this.#connections.has(target) && (this.#dbstoreData.has(target) || firsttime)){
1728
- //console.log('#dialUpdateSavedKnownID()',target)
1781
+
1729
1782
  const api = config.CONFIG_DELEGATED_API
1730
1783
  const delegatedClient = delegatedRoutingV1HttpApiClient({url:api})({logger: defaultLogger()})
1731
1784
  const peer = await first(delegatedClient.getPeers(peerIdFromString(target)))
@@ -1739,11 +1792,11 @@ class webpeerjs{
1739
1792
  const id = peer.ID
1740
1793
  let mddrs = []
1741
1794
  let addrs = []
1742
- for(const addr of address){
1743
- const peeraddr = addr.toString()+'/p2p/'+id.toString()
1744
- const peermddr = multiaddr(peeraddr)
1745
- addrs.push(peeraddr)
1746
- mddrs.push(peermddr)
1795
+ for(const rawaddr of address){
1796
+ const addr = rawaddr.toString()+'/p2p/'+id.toString()
1797
+ const mddr = multiaddr(addr)
1798
+ addrs.push(addr)
1799
+ mddrs.push(mddr)
1747
1800
  }
1748
1801
 
1749
1802
  this.#dialedKnownBootstrap.set(id,addrs)
@@ -1865,7 +1918,7 @@ class webpeerjs{
1865
1918
 
1866
1919
  //dial based on known bootstrap DNS using DNS resolver only
1867
1920
  async #dialKnownDNSonly(){
1868
- console.log('#dialKnownDNSonly()')
1921
+ //console.log('#dialKnownDNSonly()')
1869
1922
  if(!navigator.onLine)return
1870
1923
  if(!this.#isDialEnabled)return
1871
1924
 
@@ -2020,7 +2073,7 @@ const createWebPEER = async (configuration) => {
2020
2073
  listen: listenaddress,
2021
2074
  },
2022
2075
  transports:[
2023
- webTransport(),
2076
+ //webTransport(),
2024
2077
  webSockets(),
2025
2078
  webRTC(webrtcconfig),
2026
2079
  circuitRelayTransport({