@leofcoin/peernet 0.17.1 → 0.18.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.
Files changed (112) hide show
  1. package/exports/browser/client-1c52a169.js +645 -0
  2. package/exports/browser/dht/dht.d.ts +30 -0
  3. package/exports/browser/discovery/peer-discovery.d.ts +7 -0
  4. package/exports/browser/errors/errors.d.ts +3 -0
  5. package/exports/browser/handlers/data.d.ts +2 -0
  6. package/exports/browser/handlers/message.d.ts +30 -0
  7. package/exports/browser/{index-019272d8.js → index-4a0fc4ea.js} +38 -923
  8. package/exports/browser/{index-3a25de4d.js → index-639f2260.js} +3 -1
  9. package/exports/browser/messages/chat.d.ts +6 -0
  10. package/exports/browser/messages/data-response.d.ts +6 -0
  11. package/exports/browser/messages/data.d.ts +10 -0
  12. package/exports/browser/messages/dht-response.d.ts +6 -0
  13. package/exports/browser/messages/dht.d.ts +14 -0
  14. package/exports/browser/messages/file-link.d.ts +10 -0
  15. package/exports/browser/messages/file.d.ts +10 -0
  16. package/exports/browser/messages/peer-response.d.ts +6 -0
  17. package/exports/browser/messages/peer.d.ts +6 -0
  18. package/exports/browser/messages/peernet.d.ts +6 -0
  19. package/exports/browser/messages/ps.d.ts +6 -0
  20. package/exports/browser/messages/request.d.ts +6 -0
  21. package/exports/browser/messages/response.d.ts +6 -0
  22. package/exports/browser/messages-6db1f01d.js +204 -0
  23. package/exports/browser/messages.d.ts +12 -0
  24. package/exports/browser/peer-info.d.ts +4 -0
  25. package/exports/browser/peernet-3b3933a5.js +3096 -0
  26. package/exports/browser/peernet.js +1 -1
  27. package/exports/browser/proto/chat-message.proto.d.ts +7 -0
  28. package/exports/browser/proto/data-response.proto.d.ts +5 -0
  29. package/exports/browser/proto/data.proto.d.ts +5 -0
  30. package/exports/browser/proto/dht-response.proto.d.ts +5 -0
  31. package/exports/browser/proto/dht.proto.d.ts +5 -0
  32. package/exports/browser/proto/file-link.proto.d.ts +6 -0
  33. package/exports/browser/proto/file.proto.d.ts +6 -0
  34. package/exports/browser/proto/peer-response.proto.d.ts +4 -0
  35. package/exports/browser/proto/peer.proto.d.ts +4 -0
  36. package/exports/browser/proto/peernet.proto.d.ts +8 -0
  37. package/exports/browser/proto/ps.proto.d.ts +5 -0
  38. package/exports/browser/proto/request.proto.d.ts +4 -0
  39. package/exports/browser/proto/response.proto.d.ts +4 -0
  40. package/exports/browser/utils/utils.d.ts +7 -0
  41. package/exports/dht/dht.d.ts +30 -0
  42. package/exports/discovery/peer-discovery.d.ts +7 -0
  43. package/exports/errors/errors.d.ts +3 -0
  44. package/exports/handlers/data.d.ts +2 -0
  45. package/exports/handlers/message.d.ts +30 -0
  46. package/exports/messages/chat.d.ts +6 -0
  47. package/exports/messages/data-response.d.ts +6 -0
  48. package/exports/messages/data.d.ts +10 -0
  49. package/exports/messages/dht-response.d.ts +6 -0
  50. package/exports/messages/dht.d.ts +14 -0
  51. package/exports/messages/file-link.d.ts +10 -0
  52. package/exports/messages/file.d.ts +10 -0
  53. package/exports/messages/peer-response.d.ts +6 -0
  54. package/exports/messages/peer.d.ts +6 -0
  55. package/exports/messages/peernet.d.ts +6 -0
  56. package/exports/messages/ps.d.ts +6 -0
  57. package/exports/messages/request.d.ts +6 -0
  58. package/exports/messages/response.d.ts +6 -0
  59. package/exports/messages-ebdc8c69.js +203 -0
  60. package/exports/messages.d.ts +12 -0
  61. package/exports/peer-info.d.ts +4 -0
  62. package/exports/peernet.js +863 -930
  63. package/exports/proto/chat-message.proto.d.ts +7 -0
  64. package/exports/proto/data-response.proto.d.ts +5 -0
  65. package/exports/proto/data.proto.d.ts +5 -0
  66. package/exports/proto/dht-response.proto.d.ts +5 -0
  67. package/exports/proto/dht.proto.d.ts +5 -0
  68. package/exports/proto/file-link.proto.d.ts +6 -0
  69. package/exports/proto/file.proto.d.ts +6 -0
  70. package/exports/proto/peer-response.proto.d.ts +4 -0
  71. package/exports/proto/peer.proto.d.ts +4 -0
  72. package/exports/proto/peernet.proto.d.ts +8 -0
  73. package/exports/proto/ps.proto.d.ts +5 -0
  74. package/exports/proto/request.proto.d.ts +4 -0
  75. package/exports/proto/response.proto.d.ts +4 -0
  76. package/exports/utils/utils.d.ts +7 -0
  77. package/package.json +4 -3
  78. package/rollup.config.js +9 -3
  79. package/src/messages/chat.js +0 -3
  80. package/src/messages/data-response.js +0 -3
  81. package/src/messages/data.js +0 -3
  82. package/src/messages/dht-response.js +0 -3
  83. package/src/messages/dht.js +0 -6
  84. package/src/messages/file-link.js +18 -0
  85. package/src/messages/file.js +0 -3
  86. package/src/messages/peer-response.js +0 -3
  87. package/src/messages/peer.js +0 -4
  88. package/src/messages/peernet.js +0 -3
  89. package/src/messages/ps.js +0 -4
  90. package/src/messages/request.js +0 -3
  91. package/src/messages/response.js +0 -3
  92. package/src/peernet.ts +26 -20
  93. package/src/proto/chat-message.proto.js +6 -7
  94. package/src/proto/data-response.proto.js +3 -6
  95. package/src/proto/data.proto.js +3 -6
  96. package/src/proto/dht-response.proto.js +3 -6
  97. package/src/proto/dht.proto.js +3 -6
  98. package/src/proto/file-link.proto.js +5 -0
  99. package/src/proto/file.proto.js +4 -13
  100. package/src/proto/peer-response.proto.js +2 -5
  101. package/src/proto/peer.proto.js +2 -5
  102. package/src/proto/peernet.proto.js +7 -9
  103. package/src/proto/ps.proto.js +4 -6
  104. package/src/proto/request.proto.js +2 -5
  105. package/src/proto/response.proto.js +2 -5
  106. package/test.js +2 -2
  107. package/test2.js +1 -1
  108. package/tsconfig.json +3 -9
  109. package/exports/browser/client-29660363.js +0 -690
  110. package/exports/browser/messages-4850566c.js +0 -303
  111. package/exports/browser/peernet-379769d5.js +0 -2896
  112. package/exports/messages-796c4d5c.js +0 -302
@@ -1,57 +1,59 @@
1
1
  import '@vandeurenglenn/debug';
2
2
  import PubSub from '@vandeurenglenn/little-pubsub';
3
- import { Codec, codecs } from '@leofcoin/codec-format-interface';
3
+ import { Codec } from '@leofcoin/codec-format-interface';
4
4
  import LeofcoinStorage from '@leofcoin/storage';
5
+ import { utils } from '@leofcoin/codecs';
5
6
 
6
7
  const BufferToUint8Array = data => {
7
- if (data.type === 'Buffer') {
8
- data = new Uint8Array(data.data);
9
- }
10
- return data
8
+ if (data.type === 'Buffer') {
9
+ data = new Uint8Array(data.data);
10
+ }
11
+ return data;
11
12
  };
12
-
13
13
  const protoFor = (message) => {
14
- const codec = new Codec(message);
15
- if (!codec.name) throw new Error('proto not found')
16
- const Proto = globalThis.peernet.protos[codec.name];
17
- if (!Proto) throw (new Error(`No proto defined for ${codec.name}`))
18
- return new Proto(message)
14
+ const codec = new Codec(message);
15
+ if (!codec.name)
16
+ throw new Error('proto not found');
17
+ const Proto = globalThis.peernet.protos[codec.name];
18
+ if (!Proto)
19
+ throw (new Error(`No proto defined for ${codec.name}`));
20
+ return new Proto(message);
19
21
  };
20
-
21
22
  /**
22
23
  * wether or not a peernet daemon is active
23
24
  * @return {Boolean}
24
25
  */
25
26
  const hasDaemon = async () => {
26
- try {
27
- let response = await fetch('http://127.0.0.1:1000/api/version');
28
- response = await response.json();
29
- return Boolean(response.client === '@peernet/api/http')
30
- } catch (e) {
31
- return false
32
- }
27
+ try {
28
+ let response = await fetch('http://127.0.0.1:1000/api/version');
29
+ response = await response.json();
30
+ return Boolean(response.client === '@peernet/api/http');
31
+ }
32
+ catch (e) {
33
+ return false;
34
+ }
33
35
  };
34
-
35
36
  const https = () => {
36
- if (!globalThis.location) return false;
37
- return Boolean(globalThis.location.protocol === 'https:')
37
+ if (!globalThis.location)
38
+ return false;
39
+ return Boolean(globalThis.location.protocol === 'https:');
38
40
  };
39
-
40
41
  /**
41
42
  * Get current environment
42
43
  * @return {String} current environment [node, electron, browser]
43
44
  */
44
45
  const environment = () => {
45
- const _navigator = globalThis.navigator;
46
- if (!_navigator) {
47
- return 'node'
48
- } else if (_navigator && /electron/i.test(_navigator.userAgent)) {
49
- return 'electron'
50
- } else {
51
- return 'browser'
52
- }
46
+ const _navigator = globalThis.navigator;
47
+ if (!_navigator) {
48
+ return 'node';
49
+ }
50
+ else if (_navigator && /electron/i.test(_navigator.userAgent)) {
51
+ return 'electron';
52
+ }
53
+ else {
54
+ return 'browser';
55
+ }
53
56
  };
54
-
55
57
  /**
56
58
  * * Get current environment
57
59
  * @return {Object} result
@@ -59,84 +61,84 @@ const environment = () => {
59
61
  * @property {Boolean} reult.environment Current environment
60
62
  */
61
63
  const target = async () => {
62
- let daemon = false;
63
- if (!https()) daemon = await hasDaemon();
64
-
65
- return {daemon, environment: environment()}
64
+ let daemon = false;
65
+ if (!https())
66
+ daemon = await hasDaemon();
67
+ return { daemon, environment: environment() };
66
68
  };
67
69
 
68
70
  class PeerDiscovery {
69
- constructor(id) {
70
- this.id = id;
71
- }
72
-
73
- _getPeerId(id) {
74
- if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0) return false
75
-
76
- for (const entry of [...peernet.peerMap.entries()]) {
77
- for (const _id of entry[1]) {
78
- if (_id === id) return entry[0]
79
- }
80
- }
81
- }
82
-
83
- async discover(peer) {
84
- let id = this._getPeerId(peer.id);
85
- if (id) return id
86
- const data = await new peernet.protos['peernet-peer']({id: this.id});
87
- const node = await peernet.prepareMessage(peer.id, data.encoded);
88
-
89
- let response = await peer.request(node.encoded);
90
- response = await protoFor(response);
91
- response = await new peernet.protos['peernet-peer-response'](response.decoded.data);
92
-
93
- id = response.decoded.id;
94
- if (id === this.id) return;
95
-
96
- if (!peernet.peerMap.has(id)) peernet.peerMap.set(id, [peer.id]);
97
- else {
98
- const connections = peernet.peerMap.get(id);
99
- if (connections.indexOf(peer.id) === -1) {
100
- connections.push(peer.id);
101
- peernet.peerMap.set(peer.id, connections);
102
- }
103
- }
104
- return id
105
- }
106
-
107
- async discoverHandler(message, peer) {
108
- const {id, proto} = message;
109
- // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
110
- if (proto.name === 'peernet-peer') {
111
- const from = proto.decoded.id;
112
- if (from === this.id) return;
113
-
114
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
115
- else {
116
- const connections = peernet.peerMap.get(from);
117
- if (connections.indexOf(peer.id) === -1) {
118
- connections.push(peer.id);
119
- peernet.peerMap.set(from, connections);
71
+ constructor(id) {
72
+ this.id = id;
73
+ }
74
+ _getPeerId(id) {
75
+ if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0)
76
+ return false;
77
+ for (const entry of [...peernet.peerMap.entries()]) {
78
+ for (const _id of entry[1]) {
79
+ if (_id === id)
80
+ return entry[0];
81
+ }
120
82
  }
121
- }
122
- const data = await new peernet.protos['peernet-peer-response']({id: this.id});
123
- const node = await peernet.prepareMessage(from, data.encoded);
124
-
125
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
126
- } else if (proto.name === 'peernet-peer-response') {
127
- const from = proto.decoded.id;
128
- if (from === this.id) return;
129
-
130
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
131
- else {
132
- const connections = peernet.peerMap.get(from);
133
- if (connections.indexOf(peer.id) === -1) {
134
- connections.push(peer.id);
135
- peernet.peerMap.set(from, connections);
83
+ }
84
+ async discover(peer) {
85
+ let id = this._getPeerId(peer.id);
86
+ if (id)
87
+ return id;
88
+ const data = await new peernet.protos['peernet-peer']({ id: this.id });
89
+ const node = await peernet.prepareMessage(peer.id, data.encoded);
90
+ let response = await peer.request(node.encoded);
91
+ response = await protoFor(response);
92
+ response = await new peernet.protos['peernet-peer-response'](response.decoded.data);
93
+ id = response.decoded.id;
94
+ if (id === this.id)
95
+ return;
96
+ if (!peernet.peerMap.has(id))
97
+ peernet.peerMap.set(id, [peer.id]);
98
+ else {
99
+ const connections = peernet.peerMap.get(id);
100
+ if (connections.indexOf(peer.id) === -1) {
101
+ connections.push(peer.id);
102
+ peernet.peerMap.set(peer.id, connections);
103
+ }
104
+ }
105
+ return id;
106
+ }
107
+ async discoverHandler(message, peer) {
108
+ const { id, proto } = message;
109
+ // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
110
+ if (proto.name === 'peernet-peer') {
111
+ const from = proto.decoded.id;
112
+ if (from === this.id)
113
+ return;
114
+ if (!peernet.peerMap.has(from))
115
+ peernet.peerMap.set(from, [peer.id]);
116
+ else {
117
+ const connections = peernet.peerMap.get(from);
118
+ if (connections.indexOf(peer.id) === -1) {
119
+ connections.push(peer.id);
120
+ peernet.peerMap.set(from, connections);
121
+ }
122
+ }
123
+ const data = await new peernet.protos['peernet-peer-response']({ id: this.id });
124
+ const node = await peernet.prepareMessage(from, data.encoded);
125
+ peer.write(Buffer.from(JSON.stringify({ id, data: node.encoded })));
126
+ }
127
+ else if (proto.name === 'peernet-peer-response') {
128
+ const from = proto.decoded.id;
129
+ if (from === this.id)
130
+ return;
131
+ if (!peernet.peerMap.has(from))
132
+ peernet.peerMap.set(from, [peer.id]);
133
+ else {
134
+ const connections = peernet.peerMap.get(from);
135
+ if (connections.indexOf(peer.id) === -1) {
136
+ connections.push(peer.id);
137
+ peernet.peerMap.set(from, connections);
138
+ }
139
+ }
136
140
  }
137
- }
138
141
  }
139
- }
140
142
  }
141
143
 
142
144
  /**
@@ -145,873 +147,804 @@ class PeerDiscovery {
145
147
  * @property {Object} ptr
146
148
  */
147
149
  const lastFetched = {
148
- address: {
149
- value: undefined,
150
- timestamp: 0,
151
- },
152
- ptr: {
153
- value: undefined,
154
- timestamp: 0,
155
- },
150
+ address: {
151
+ value: undefined,
152
+ timestamp: 0,
153
+ },
154
+ ptr: {
155
+ value: undefined,
156
+ timestamp: 0,
157
+ },
156
158
  };
157
-
158
159
  const getAddress = async () => {
159
- const {address} = lastFetched;
160
- const now = Math.round(new Date().getTime() / 1000);
161
- if (now - address.timestamp > 1200000) {
162
- address.value = await fetch('https://icanhazip.com/');
163
- address.value = await address.value.text();
164
- address.timestamp = Math.round(new Date().getTime() / 1000);
165
- lastFetched.address = address;
166
- }
167
-
168
- return address.value
160
+ const { address } = lastFetched;
161
+ const now = Math.round(new Date().getTime() / 1000);
162
+ if (now - address.timestamp > 1200000) {
163
+ address.value = await fetch('https://icanhazip.com/');
164
+ address.value = await address.value.text();
165
+ address.timestamp = Math.round(new Date().getTime() / 1000);
166
+ lastFetched.address = address;
167
+ }
168
+ return address.value;
169
169
  };
170
-
171
170
  const degreesToRadians = (degrees) => {
172
- return degrees * Math.PI / 180;
171
+ return degrees * Math.PI / 180;
173
172
  };
174
-
175
173
  const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
176
- const earthRadiusKm = 6371;
177
-
178
- const dLat = degreesToRadians(lat2-lat1);
179
- const dLon = degreesToRadians(lon2-lon1);
180
-
181
- lat1 = degreesToRadians(lat1);
182
- lat2 = degreesToRadians(lat2);
183
- const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
184
- Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
185
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
186
- return earthRadiusKm * c;
174
+ const earthRadiusKm = 6371;
175
+ const dLat = degreesToRadians(lat2 - lat1);
176
+ const dLon = degreesToRadians(lon2 - lon1);
177
+ lat1 = degreesToRadians(lat1);
178
+ lat2 = degreesToRadians(lat2);
179
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
180
+ Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
181
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
182
+ return earthRadiusKm * c;
187
183
  };
188
-
189
184
  class DhtEarth {
190
- /**
191
- *
192
- */
193
- constructor() {
194
- this.providerMap = new Map();
195
- }
196
-
197
- /**
198
- * @param {Object} address
199
- * @return {Object} {latitude: lat, longitude: lon}
200
- */
201
- async getCoordinates(address) {
202
- // const {address} = parseAddress(provider)
203
- const request = `https://whereis.leofcoin.org/?ip=${address}`;
204
- let response = await fetch(request);
205
- response = await response.json();
206
- const {lat, lon} = response;
207
- return {latitude: lat, longitude: lon}
208
- }
209
-
210
- /**
211
- * @param {Object} peer
212
- * @param {Object} provider
213
- * @return {Object} {provider, distance}
214
- */
215
- async getDistance(peer, provider) {
216
- const {latitude, longitude} = await this.getCoordinates(provider.address);
217
- return {provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)}
218
- }
219
-
220
- /**
221
- * @param {Array} providers
222
- * @return {Object} closestPeer
223
- */
224
- async closestPeer(providers) {
225
- let all = [];
226
- const address = await getAddress();
227
- const peerLoc = await this.getCoordinates(address);
228
-
229
- for (const provider of providers) {
230
- if (provider.address === '127.0.0.1') all.push({provider, distance: 0});
231
- else all.push(this.getDistance(peerLoc, provider));
232
- }
233
-
234
- all = await Promise.all(all);
235
- all = all.sort((previous, current) => previous.distance - current.distance);
236
- return all[0].provider;
237
- }
238
-
239
- /**
240
- * @param {String} hash
241
- * @return {Array} providers
242
- */
243
- providersFor(hash) {
244
- return this.providerMap.get(hash);
245
- }
246
-
247
- /**
248
- * @param {String} address
249
- * @param {String} hash
250
- * @return {Array} providers
251
- */
252
- async addProvider(address, hash) {
253
- let providers = [];
254
- if (this.providerMap.has(hash)) providers = this.providerMap.get(hash);
255
-
256
- providers = new Set([...providers, address]);
257
- this.providerMap.set(hash, providers);
258
- return providers;
259
- }
185
+ /**
186
+ *
187
+ */
188
+ constructor() {
189
+ this.providerMap = new Map();
190
+ }
191
+ /**
192
+ * @param {Object} address
193
+ * @return {Object} {latitude: lat, longitude: lon}
194
+ */
195
+ async getCoordinates(address) {
196
+ // const {address} = parseAddress(provider)
197
+ const request = `https://whereis.leofcoin.org/?ip=${address}`;
198
+ let response = await fetch(request);
199
+ response = await response.json();
200
+ const { lat, lon } = response;
201
+ return { latitude: lat, longitude: lon };
202
+ }
203
+ /**
204
+ * @param {Object} peer
205
+ * @param {Object} provider
206
+ * @return {Object} {provider, distance}
207
+ */
208
+ async getDistance(peer, provider) {
209
+ const { latitude, longitude } = await this.getCoordinates(provider.address);
210
+ return { provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude) };
211
+ }
212
+ /**
213
+ * @param {Array} providers
214
+ * @return {Object} closestPeer
215
+ */
216
+ async closestPeer(providers) {
217
+ let all = [];
218
+ const address = await getAddress();
219
+ const peerLoc = await this.getCoordinates(address);
220
+ for (const provider of providers) {
221
+ if (provider.address === '127.0.0.1')
222
+ all.push({ provider, distance: 0 });
223
+ else
224
+ all.push(this.getDistance(peerLoc, provider));
225
+ }
226
+ all = await Promise.all(all);
227
+ all = all.sort((previous, current) => previous.distance - current.distance);
228
+ return all[0].provider;
229
+ }
230
+ /**
231
+ * @param {String} hash
232
+ * @return {Array} providers
233
+ */
234
+ providersFor(hash) {
235
+ return this.providerMap.get(hash);
236
+ }
237
+ /**
238
+ * @param {String} address
239
+ * @param {String} hash
240
+ * @return {Array} providers
241
+ */
242
+ async addProvider(address, hash) {
243
+ let providers = [];
244
+ if (this.providerMap.has(hash))
245
+ providers = this.providerMap.get(hash);
246
+ providers = new Set([...providers, address]);
247
+ this.providerMap.set(hash, providers);
248
+ return providers;
249
+ }
260
250
  }
261
251
 
262
252
  class MessageHandler {
263
- constructor(network) {
264
- this.network = network;
265
- }
266
- /**
267
- * hash and sign message
268
- *
269
- * @param {object} message
270
- * @param {Buffer} message.from peer id
271
- * @param {Buffer} message.to peer id
272
- * @param {string} message.data Peernet message
273
- * (PeernetMessage excluded) encoded as a string
274
- * @return message
275
- */
276
- async hashAndSignMessage(message) {
277
- let identity = await walletStore.get('identity');
278
- identity = JSON.parse(identity);
279
- if (!globalThis.MultiWallet) {
280
- const importee = await import(/* webpackChunkName: "multi-wallet" */ '@leofcoin/multi-wallet');
281
- globalThis.MultiWallet = importee.default;
282
- }
283
- const wallet = new MultiWallet(this.network);
284
- wallet.recover(identity.mnemonic);
285
- message.decoded.signature = wallet.sign(Buffer.from(await message.hash).slice(0, 32));
286
- return message
287
- }
288
-
289
- /**
290
- * @param {String} from - peer id
291
- * @param {String} to - peer id
292
- * @param {String|PeernetMessage} data - data encoded message string
293
- * or the messageNode itself
294
- */
295
- async prepareMessage(message) {
296
- if (message.keys.includes('signature')) {
297
- message = await this.hashAndSignMessage(message);
298
- }
299
-
300
- return message
301
- }
253
+ constructor(network) {
254
+ this.network = network;
255
+ }
256
+ /**
257
+ * hash and sign message
258
+ *
259
+ * @param {object} message
260
+ * @param {Buffer} message.from peer id
261
+ * @param {Buffer} message.to peer id
262
+ * @param {string} message.data Peernet message
263
+ * (PeernetMessage excluded) encoded as a string
264
+ * @return message
265
+ */
266
+ async hashAndSignMessage(message) {
267
+ let identity = await walletStore.get('identity');
268
+ identity = JSON.parse(identity);
269
+ if (!globalThis.MultiWallet) {
270
+ const importee = await import(/* webpackChunkName: "multi-wallet" */ '@leofcoin/multi-wallet');
271
+ globalThis.MultiWallet = importee.default;
272
+ }
273
+ const wallet = new MultiWallet(this.network);
274
+ wallet.recover(identity.mnemonic);
275
+ message.decoded.signature = wallet.sign(Buffer.from(await message.hash).slice(0, 32));
276
+ return message;
277
+ }
278
+ /**
279
+ * @param {String} from - peer id
280
+ * @param {String} to - peer id
281
+ * @param {String|PeernetMessage} data - data encoded message string
282
+ * or the messageNode itself
283
+ */
284
+ async prepareMessage(message) {
285
+ if (message.keys.includes('signature')) {
286
+ message = await this.hashAndSignMessage(message);
287
+ }
288
+ return message;
289
+ }
302
290
  }
303
291
 
304
- const dataHandler = async message => {
305
- if (!message) return
306
-
307
- const {data, id, from} = message;
308
- const proto = await protoFor(data);
309
-
310
- peernet._protoHandler({id, proto}, peernet.client.connections[from], from);
292
+ const dataHandler = async (message) => {
293
+ if (!message)
294
+ return;
295
+ const { data, id, from } = message;
296
+ const proto = await protoFor(data);
297
+ peernet._protoHandler({ id, proto }, peernet.client.connections[from], from);
311
298
  };
312
299
 
313
- const dhtError = (proto) => {
314
- const text = `Received proto ${proto.name} expected peernet-dht-response`;
315
- return new Error(`Routing error: ${text}`)
316
- };
317
-
318
- const nothingFoundError = (hash) => {
319
- return new Error(`nothing found for ${hash}`)
300
+ const dhtError = (proto) => {
301
+ const text = `Received proto ${proto.name} expected peernet-dht-response`;
302
+ return new Error(`Routing error: ${text}`);
303
+ };
304
+ const nothingFoundError = (hash) => {
305
+ return new Error(`nothing found for ${hash}`);
320
306
  };
321
307
 
322
308
  globalThis.LeofcoinStorage = LeofcoinStorage;
323
-
324
309
  globalThis.leofcoin = globalThis.leofcoin || {};
325
310
  globalThis.pubsub = globalThis.pubsub || new PubSub();
326
- globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
327
-
311
+ globalThis.globalSub = globalThis.globalSub || new PubSub(true);
328
312
  /**
329
313
  * @access public
330
314
  * @example
331
315
  * const peernet = new Peernet();
332
316
  */
333
317
  class Peernet {
334
- /**
335
- * @access public
336
- * @param {Object} options
337
- * @param {String} options.network - desired network
338
- * @param {String} options.stars - star list for selected network (these should match, don't mix networks)
339
- * @param {String} options.root - path to root directory
340
- * @param {String} options.storePrefix - prefix for datatores (lfc)
341
- *
342
- * @return {Promise} instance of Peernet
343
- *
344
- * @example
345
- * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
346
- */
347
- constructor(options = {}) {
348
- this._discovered = [];
349
- /**
350
- * @property {String} network - current network
351
- */
352
- this.network = options.network || 'leofcoin';
353
- this.stars = options.stars;
354
- const parts = this.network.split(':');
355
- this.networkVersion = options.networkVersion || parts.length > 1 ? parts[1] : 'mainnet';
356
-
357
- if (!options.storePrefix) options.storePrefix = 'lfc';
358
- if (!options.port) options.port = 2000;
359
- if (!options.root) {
360
- parts[1] ? options.root = `.${parts[0]}/${parts[1]}` : options.root = `.${this.network}`;
361
- }
362
-
363
- globalThis.peernet = this;
364
- this.bw = {
365
- up: 0,
366
- down: 0,
367
- };
368
- return this._init(options)
369
- }
370
-
371
- get defaultStores() {
372
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
373
- }
374
-
375
- addProto(name, proto) {
376
- if (!globalThis.peernet.protos[name]) globalThis.peernet.protos[name] = proto;
377
- }
378
-
379
- addCodec(name, codec) {
380
- if (!this.codecs[name]) this.codecs[name] = codec;
381
- }
382
-
383
- async addStore(name, prefix, root, isPrivate = true) {
384
- if (name === 'block' || name === 'transaction' || name === 'chain' ||
385
- name === 'data' || name === 'message') isPrivate = false;
386
-
387
- let Storage;
388
-
389
- this.hasDaemon ? Storage = LeofcoinStorageClient : Storage = LeofcoinStorage;
390
-
391
- if (!globalThis[`${name}Store`]) {
392
- globalThis[`${name}Store`] = new Storage(name, root);
393
- await globalThis[`${name}Store`].init();
394
- }
395
-
396
- globalThis[`${name}Store`].private = isPrivate;
397
- if (!isPrivate) this.stores.push(name);
398
- }
399
-
400
-
401
- /**
402
- * @see MessageHandler
403
- */
404
- prepareMessage(data) {
405
- return this._messageHandler.prepareMessage(data)
406
- }
407
-
408
- /**
409
- * @access public
410
- *
411
- * @return {Array} peerId
412
- */
413
- get peers() {
414
- return Object.keys(this.client.connections)
415
- }
416
-
417
- get connections() {
418
- return Object.values(this.client.connections)
419
- }
420
-
421
- get peerEntries() {
422
- return Object.entries(this.client.connections)
423
- }
424
-
425
- /**
426
- * @return {String} id - peerId
427
- */
428
- getConnection(id) {
429
- return this.client.connections[id]
430
- }
431
-
432
- /**
433
- * @private
434
- *
435
- * @param {Object} options
436
- * @param {String} options.root - path to root directory
437
- *
438
- * @return {Promise} instance of Peernet
439
- */
440
- async _init(options) {
441
- // peernetDHT aka closesPeer by coordinates
318
+ stores = [];
442
319
  /**
443
320
  * @type {Object}
444
321
  * @property {Object} peer Instance of Peer
445
322
  */
446
- this.dht = new DhtEarth();
323
+ dht = new DhtEarth();
324
+ /** @leofcoin/peernet-swarm/client */
325
+ client;
326
+ network;
327
+ stars;
328
+ networkVersion;
329
+ bw;
447
330
  /**
448
- * @type {Map}
449
- * @property {Object} peer Instance of Peer
331
+ * @access public
332
+ * @param {Object} options
333
+ * @param {String} options.network - desired network
334
+ * @param {String} options.stars - star list for selected network (these should match, don't mix networks)
335
+ * @param {String} options.root - path to root directory
336
+ * @param {String} options.storePrefix - prefix for datatores (lfc)
337
+ *
338
+ * @return {Promise} instance of Peernet
339
+ *
340
+ * @example
341
+ * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
450
342
  */
451
- this.stores = [];
452
- this.codecs = {...codecs};
453
- this.requestProtos = {};
454
- this.storePrefix = options.storePrefix;
455
- this.root = options.root;
456
-
457
- const {
458
- RequestMessage,
459
- ResponseMessage,
460
- PeerMessage,
461
- PeerMessageResponse,
462
- PeernetMessage,
463
- DHTMessage,
464
- DHTMessageResponse,
465
- DataMessage,
466
- DataMessageResponse,
467
- PsMessage,
468
- ChatMessage,
469
- PeernetFile
470
- // FolderMessageResponse
471
- } = await import(/* webpackChunkName: "messages" */ './messages-796c4d5c.js');
472
-
343
+ constructor(options) {
344
+ /**
345
+ * @property {String} network - current network
346
+ */
347
+ this.network = options.network || 'leofcoin';
348
+ this.stars = options.stars;
349
+ const parts = this.network.split(':');
350
+ this.networkVersion = options.networkVersion || parts.length > 1 ? parts[1] : 'mainnet';
351
+ if (!options.storePrefix)
352
+ options.storePrefix = 'lfc';
353
+ if (!options.port)
354
+ options.port = 2000;
355
+ if (!options.root) {
356
+ parts[1] ? options.root = `.${parts[0]}/${parts[1]}` : options.root = `.${this.network}`;
357
+ }
358
+ globalThis.peernet = this;
359
+ this.bw = {
360
+ up: 0,
361
+ down: 0,
362
+ };
363
+ return this._init(options);
364
+ }
365
+ get defaultStores() {
366
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message'];
367
+ }
368
+ addProto(name, proto) {
369
+ if (!globalThis.peernet.protos[name])
370
+ globalThis.peernet.protos[name] = proto;
371
+ }
372
+ addCodec(codec) {
373
+ return utils.addCodec(codec);
374
+ }
375
+ async addStore(name, prefix, root, isPrivate = true) {
376
+ if (name === 'block' || name === 'transaction' || name === 'chain' ||
377
+ name === 'data' || name === 'message')
378
+ isPrivate = false;
379
+ let Storage;
380
+ this.hasDaemon ? Storage = LeofcoinStorageClient : Storage = LeofcoinStorage;
381
+ if (!globalThis[`${name}Store`]) {
382
+ globalThis[`${name}Store`] = new Storage(name, root);
383
+ await globalThis[`${name}Store`].init();
384
+ }
385
+ globalThis[`${name}Store`].private = isPrivate;
386
+ if (!isPrivate)
387
+ this.stores.push(name);
388
+ }
473
389
  /**
474
- * proto Object containing protos
475
- * @type {Object}
476
- * @property {PeernetMessage} protos[peernet-message] messageNode
477
- * @property {DHTMessage} protos[peernet-dht] messageNode
478
- * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
479
- * @property {DataMessage} protos[peernet-data] messageNode
480
- * @property {DataMessageResponse} protos[peernet-data-response] messageNode
390
+ * @see MessageHandler
481
391
  */
482
-
483
- globalThis.peernet.protos = {
484
- 'peernet-request': RequestMessage,
485
- 'peernet-response': ResponseMessage,
486
- 'peernet-peer': PeerMessage,
487
- 'peernet-peer-response': PeerMessageResponse,
488
- 'peernet-message': PeernetMessage,
489
- 'peernet-dht': DHTMessage,
490
- 'peernet-dht-response': DHTMessageResponse,
491
- 'peernet-data': DataMessage,
492
- 'peernet-data-response': DataMessageResponse,
493
- 'peernet-ps': PsMessage,
494
- 'chat-message': ChatMessage,
495
- 'peernet-file': PeernetFile
496
- };
497
-
498
- this._messageHandler = new MessageHandler(this.network);
499
-
500
- const {daemon, environment} = await target();
501
- this.hasDaemon = daemon;
502
-
503
- for (const store of this.defaultStores) {
504
- await this.addStore(store, options.storePrefix, options.root);
505
- }
506
-
507
- const accountExists = await accountStore.has('public');
508
- if (accountExists) {
509
- const pub = await accountStore.get('public');
510
- this.id = JSON.parse(new TextDecoder().decode(pub)).walletId;
511
- let accounts = await walletStore.get('accounts');
512
- accounts = new TextDecoder().decode(accounts);
513
- const selected = await walletStore.get('selected-account');
514
- globalThis.peernet.selectedAccount = new TextDecoder().decode(selected);
515
-
516
- // fixing account issue (string while needs to be a JSON)
517
- // TODO: remove when on mainnet
518
- try {
519
- this.accounts = JSON.parse(accounts);
520
- } catch {
521
- this.accounts = [accounts.split(',')];
522
- }
523
- } else {
524
- const importee = await import(/* webpackChunkName: "generate-account" */ '@leofcoin/generate-account');
525
- const generateAccount = importee.default;
526
- const {identity, accounts, config} = await generateAccount(this.network);
527
- // await accountStore.put('config', JSON.stringify(config));
528
- await accountStore.put('public', JSON.stringify({walletId: identity.walletId}));
529
-
530
- await walletStore.put('version', String(1));
531
- await walletStore.put('accounts', JSON.stringify(accounts));
532
- await walletStore.put('selected-account', accounts[0][1]);
533
- await walletStore.put('identity', JSON.stringify(identity));
534
-
535
- globalThis.peernet.selectedAccount = accounts[0][1];
536
- this.id = identity.walletId;
537
- }
538
- this._peerHandler = new PeerDiscovery(this.id);
539
- this.peerId = this.id;
540
-
541
- pubsub.subscribe('peer:connected', async (peer) => {
542
- // console.log(peer);
543
- // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
544
- // peer.on('peernet.data', async (message) => {
545
- // const id = message.id
546
- // message = new PeernetMessage(Buffer.from(message.data.data))
547
- // const proto = protoFor(message.decoded.data)
548
- // this._protoHandler({id, proto}, peer)
549
- // })
550
- });
551
-
392
+ prepareMessage(data) {
393
+ return this._messageHandler.prepareMessage(data);
394
+ }
552
395
  /**
553
- * converts data -> message -> proto
554
- * @see DataHandler
396
+ * @access public
397
+ *
398
+ * @return {Array} peerId
555
399
  */
556
- pubsub.subscribe('peer:data', dataHandler);
557
-
558
-
559
- const importee = await import(/* webpackChunkName: "peernet-swarm" */ '@leofcoin/peernet-swarm/client');
400
+ get peers() {
401
+ return Object.keys(this.client.connections);
402
+ }
403
+ get connections() {
404
+ return Object.values(this.client.connections);
405
+ }
406
+ get peerEntries() {
407
+ return Object.entries(this.client.connections);
408
+ }
560
409
  /**
561
- * @access public
562
- * @type {PeernetClient}
410
+ * @return {String} id - peerId
563
411
  */
564
- this.client = new importee.default(this.id, this.networkVersion, this.stars);
565
- if (globalThis.navigator) {
566
- globalThis.addEventListener('beforeunload', async () => this.client.close());
567
- } else {
568
- process.on('SIGTERM', async () => {
569
- process.stdin.resume();
570
- await this.client.close();
571
- process.exit();
572
- });
573
- }
574
- return this
575
- }
576
-
577
- addRequestHandler(name, method) {
578
- this.requestProtos[name] = method;
579
- }
580
-
581
- sendMessage(peer, id, data) {
582
- if (peer.readyState === 'open') {
583
- peer.send(data, id);
584
- this.bw.up += data.length;
585
- } else if (peer.readyState === 'closed') ;
586
-
587
- }
588
-
589
- async handleDHT(peer, id, proto) {
590
- let { hash, store } = proto.decoded;
591
- let has;
592
-
593
- if (store) {
594
- store = globalThis[`${store}Store`];
595
- has = store.private ? false : await store.has(hash);
596
- } else {
597
- has = await this.has(hash);
598
- }
599
-
600
- const data = await new globalThis.peernet.protos['peernet-dht-response']({hash, has});
601
- const node = await this.prepareMessage(data);
602
-
603
- this.sendMessage(peer, id, node.encoded);
604
- }
605
-
606
- async handleData(peer, id, proto) {
607
- let { hash, store } = proto.decoded;
608
- let data;
609
- store = globalThis[`${store}Store`] || await this.whichStore([...this.stores], hash);
610
-
611
- if (store && !store.private) {
612
- data = await store.get(hash);
613
-
614
- if (data) {
615
- data = await new globalThis.peernet.protos['peernet-data-response']({hash, data});
616
-
617
- const node = await this.prepareMessage(data);
618
- this.sendMessage(peer, id, node.encoded);
619
- }
620
- }
621
- }
622
-
623
- async handleRequest(peer, id, proto) {
624
- const method = this.requestProtos[proto.decoded.request];
625
- if (method) {
626
- const data = await method();
627
- const node = await this.prepareMessage(data);
628
- this.sendMessage(peer, id, node.encoded);
629
- }
630
- }
631
-
632
- /**
633
- * @private
634
- *
635
- * @param {Buffer} message - peernet message
636
- * @param {PeernetPeer} peer - peernet peer
637
- */
638
- async _protoHandler(message, peer, from) {
639
- const {id, proto} = message;
640
- this.bw.down += proto.encoded.length;
641
- switch(proto.name) {
642
- case 'peernet-dht': {
643
- this.handleDHT(peer, id, proto);
644
- break
645
- }
646
- case 'peenet-data': {
647
- this.handleData(peer, id, proto);
648
- break
649
- }
650
- case 'peernet-request': {
651
- this.handleRequest(peer, id, proto);
652
- }
653
-
654
- case 'peernet-ps': {
655
- if (peer.peerId !== this.id) globalSub.publish(proto.decoded.topic, proto.decoded.data);
656
- }
657
- }
658
- }
659
-
660
- /**
661
- * performs a walk and resolves first encounter
662
- *
663
- * @param {String} hash
664
- */
665
- async walk(hash) {
666
- if (!hash) throw new Error('hash expected, received undefined')
667
- const data = await new globalThis.peernet.protos['peernet-dht']({hash});
668
- this.client.id;
669
- const walk = async peer => {
670
- const node = await this.prepareMessage(data);
671
- let result = await peer.request(node.encoded);
672
- result = new Uint8Array(Object.values(result));
673
- const proto = await protoFor(result);
674
- if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
675
-
676
- // TODO: give ip and port (just used for location)
677
- if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
678
- peer.connection.remoteFamily = 'ipv4';
679
- peer.connection.remoteAddress = '127.0.0.1';
680
- peer.connection.remotePort = '0000';
681
- }
682
-
683
- const peerInfo = {
684
- family: peer.connection.remoteFamily || peer.connection.localFamily,
685
- address: peer.connection.remoteAddress || peer.connection.localAddress,
686
- port: peer.connection.remotePort || peer.connection.localPort,
687
- id: peer.peerId,
688
- };
689
-
690
- if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
691
- };
692
- let walks = [];
693
- for (const peer of this.connections) {
694
- if (peer.peerId !== this.id) {
695
- walks.push(walk(peer));
696
- }
697
- }
698
- return Promise.all(walks)
699
- }
700
-
701
- /**
702
- * Override DHT behavior, try's finding the content three times
703
- *
704
- * @param {String} hash
705
- */
706
- async providersFor(hash) {
707
- let providers = await this.dht.providersFor(hash);
708
- // walk the network to find a provider
709
- if (!providers || providers.length === 0) {
710
- await this.walk(hash);
711
- providers = await this.dht.providersFor(hash);
712
- // second walk the network to find a provider
713
- if (!providers || providers.length === 0) {
714
- await this.walk(hash);
715
- providers = await this.dht.providersFor(hash);
716
- }
717
- // last walk
718
- if (!providers || providers.length === 0) {
719
- await this.walk(hash);
720
- providers = await this.dht.providersFor(hash);
721
- }
722
- }
723
- // undefined if no providers given
724
- return providers
725
- }
726
-
727
- get block() {
728
- return {
729
- get: async (hash) => {
730
- const data = await blockStore.has(hash);
731
- if (data) return blockStore.get(hash)
732
- return this.requestData(hash, 'block')
733
- },
734
- put: async (hash, data) => {
735
- if (await blockStore.has(hash)) return
736
- return await blockStore.put(hash, data)
737
- },
738
- has: async (hash) => await blockStore.has(hash, 'block'),
739
- }
740
- }
741
-
742
- get transaction() {
743
- return {
744
- get: async (hash) => {
745
- const data = await transactionStore.has(hash);
746
- if (data) return await transactionStore.get(hash)
747
- return this.requestData(hash, 'transaction')
748
- },
749
- put: async (hash, data) => {
750
- if (await transactionStore.has(hash)) return
751
- return await transactionStore.put(hash, data)
752
- },
753
- has: async (hash) => await transactionStore.has(hash),
754
- }
755
- }
756
-
757
- async requestData(hash, store) {
758
- const providers = await this.providersFor(hash);
759
- if (!providers || providers.size === 0) throw nothingFoundError(hash)
760
- debug(`found ${providers.size} provider(s) for ${hash}`);
761
- // get closest peer on earth
762
- const closestPeer = await this.dht.closestPeer(providers);
763
- // get peer instance by id
764
- if (!closestPeer || !closestPeer.id) return this.requestData(hash, store?.name || store)
765
-
766
- const id = closestPeer.id;
767
- if (this.connections) {
768
- let closest = this.connections.filter((peer) => {
769
- if (peer.peerId === id) return peer
770
- });
771
-
772
- let data = await new globalThis.peernet.protos['peernet-data']({hash, store: store?.name || store});
773
-
774
- const node = await this.prepareMessage(data);
775
- if (closest[0]) data = await closest[0].request(node.encoded);
776
- else {
777
- closest = this.connections.filter((peer) => {
778
- if (peer.peerId === id) return peer
412
+ getConnection(id) {
413
+ return this.client.connections[id];
414
+ }
415
+ /**
416
+ * @private
417
+ *
418
+ * @param {Object} options
419
+ * @param {String} options.root - path to root directory
420
+ *
421
+ * @return {Promise} instance of Peernet
422
+ */
423
+ async _init(options) {
424
+ this.requestProtos = {};
425
+ this.storePrefix = options.storePrefix;
426
+ this.root = options.root;
427
+ const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
428
+ // FolderMessageResponse
429
+ } = await import(/* webpackChunkName: "messages" */ './messages-ebdc8c69.js');
430
+ /**
431
+ * proto Object containing protos
432
+ * @type {Object}
433
+ * @property {PeernetMessage} protos[peernet-message] messageNode
434
+ * @property {DHTMessage} protos[peernet-dht] messageNode
435
+ * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
436
+ * @property {DataMessage} protos[peernet-data] messageNode
437
+ * @property {DataMessageResponse} protos[peernet-data-response] messageNode
438
+ */
439
+ globalThis.peernet.protos = {
440
+ 'peernet-request': RequestMessage,
441
+ 'peernet-response': ResponseMessage,
442
+ 'peernet-peer': PeerMessage,
443
+ 'peernet-peer-response': PeerMessageResponse,
444
+ 'peernet-message': PeernetMessage,
445
+ 'peernet-dht': DHTMessage,
446
+ 'peernet-dht-response': DHTMessageResponse,
447
+ 'peernet-data': DataMessage,
448
+ 'peernet-data-response': DataMessageResponse,
449
+ 'peernet-ps': PsMessage,
450
+ 'chat-message': ChatMessage,
451
+ 'peernet-file': PeernetFile
452
+ };
453
+ this._messageHandler = new MessageHandler(this.network);
454
+ const { daemon, environment } = await target();
455
+ this.hasDaemon = daemon;
456
+ for (const store of this.defaultStores) {
457
+ await this.addStore(store, options.storePrefix, options.root);
458
+ }
459
+ const accountExists = await accountStore.has('public');
460
+ if (accountExists) {
461
+ const pub = await accountStore.get('public');
462
+ this.id = JSON.parse(new TextDecoder().decode(pub)).walletId;
463
+ let accounts = await walletStore.get('accounts');
464
+ accounts = new TextDecoder().decode(accounts);
465
+ const selected = await walletStore.get('selected-account');
466
+ globalThis.peernet.selectedAccount = new TextDecoder().decode(selected);
467
+ // fixing account issue (string while needs to be a JSON)
468
+ // TODO: remove when on mainnet
469
+ try {
470
+ this.accounts = JSON.parse(accounts);
471
+ }
472
+ catch {
473
+ this.accounts = [accounts.split(',')];
474
+ }
475
+ }
476
+ else {
477
+ const importee = await import(/* webpackChunkName: "generate-account" */ '@leofcoin/generate-account');
478
+ const generateAccount = importee.default;
479
+ const { identity, accounts, config } = await generateAccount(this.network);
480
+ // await accountStore.put('config', JSON.stringify(config));
481
+ await accountStore.put('public', JSON.stringify({ walletId: identity.walletId }));
482
+ await walletStore.put('version', String(1));
483
+ await walletStore.put('accounts', JSON.stringify(accounts));
484
+ await walletStore.put('selected-account', accounts[0][1]);
485
+ await walletStore.put('identity', JSON.stringify(identity));
486
+ globalThis.peernet.selectedAccount = accounts[0][1];
487
+ this.id = identity.walletId;
488
+ }
489
+ this._peerHandler = new PeerDiscovery(this.id);
490
+ this.peerId = this.id;
491
+ pubsub.subscribe('peer:connected', async (peer) => {
492
+ // console.log(peer);
493
+ // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
494
+ // peer.on('peernet.data', async (message) => {
495
+ // const id = message.id
496
+ // message = new PeernetMessage(Buffer.from(message.data.data))
497
+ // const proto = protoFor(message.decoded.data)
498
+ // this._protoHandler({id, proto}, peer)
499
+ // })
779
500
  });
780
- if (closest[0]) data = await closest[0].request(node.encoded);
781
- }
782
- data = new Uint8Array(Object.values(data));
783
- const proto = await protoFor(data);
784
- // TODO: store data automaticly or not
785
- return BufferToUint8Array(proto.decoded.data)
786
-
787
- // this.put(hash, proto.decoded.data)
788
- }
789
- return
790
- }
791
-
792
-
793
- get message() {
794
- return {
795
- /**
796
- * Get content for given message hash
797
- *
798
- * @param {String} hash
799
- */
800
- get: async (hash) => {
801
- debug(`get message ${hash}`);
802
- const message = await messageStore.has(hash);
803
- if (message) return await messageStore.get(hash)
804
- return this.requestData(hash, 'message')
805
- },
806
- /**
807
- * put message content
808
- *
809
- * @param {String} hash
810
- * @param {Buffer} message
811
- */
812
- put: async (hash, message) => await messageStore.put(hash, message),
813
- /**
814
- * @param {String} hash
815
- * @return {Boolean}
816
- */
817
- has: async (hash) => await messageStore.has(hash),
818
- }
819
- }
820
-
821
- get data() {
822
- return {
823
- /**
824
- * Get content for given data hash
825
- *
826
- * @param {String} hash
827
- */
828
- get: async (hash) => {
829
- debug(`get data ${hash}`);
830
- const data = await dataStore.has(hash);
831
- if (data) return await dataStore.get(hash)
832
- return this.requestData(hash, 'data')
833
- },
834
- /**
835
- * put data content
836
- *
837
- * @param {String} hash
838
- * @param {Buffer} data
839
- */
840
- put: async (hash, data) => await dataStore.put(hash, data),
841
- /**
842
- * @param {String} hash
843
- * @return {Boolean}
844
- */
845
- has: async (hash) => await dataStore.has(hash),
846
- }
847
- }
848
-
849
- get folder() {
850
- return {
851
- /**
852
- * Get content for given data hash
853
- *
854
- * @param {String} hash
855
- */
856
- get: async (hash) => {
857
- debug(`get data ${hash}`);
858
- const data = await dataStore.has(hash);
859
- if (data) return await dataStore.get(hash)
860
- return this.requestData(hash, 'data')
861
- },
862
- /**
863
- * put data content
864
- *
865
- * @param {String} hash
866
- * @param {Buffer} data
867
- */
868
- put: async (hash, data) => await dataStore.put(hash, data),
869
- /**
870
- * @param {String} hash
871
- * @return {Boolean}
872
- */
873
- has: async (hash) => await dataStore.has(hash),
874
- }
875
- }
876
-
877
- async addFolder(files) {
878
- const links = [];
879
- for (const file of files) {
880
- const fileNode = await new globalThis.peernet.protos['peernet-file'](file);
881
- const hash = await fileNode.hash;
882
- await dataStore.put(hash, fileNode.encoded);
883
- links.push({hash, path: file.path});
884
- }
885
- const node = await new globalThis.peernet.protos['peernet-file']({path: '/', links});
886
- const hash = await node.hash;
887
- await dataStore.put(hash, node.encoded);
888
-
889
- return hash
890
- }
891
-
892
- async ls(hash, options) {
893
- let data;
894
- const has = await dataStore.has(hash);
895
- data = has ? await dataStore.get(hash) : await this.requestData(hash, 'data');
896
-
897
- const node = await new peernet.protos['peernet-file'](data);
898
- await node.decode();
899
- console.log(data);
900
- const paths = [];
901
- if (node.decoded?.links.length === 0) throw new Error(`${hash} is a file`)
902
- for (const {path, hash} of node.decoded.links) {
903
- paths.push({path, hash});
904
- }
905
- if (options?.pin) await dataStore.put(hash, node.encoded);
906
- return paths
907
- }
908
-
909
- async cat(hash, options) {
910
- let data;
911
- const has = await dataStore.has(hash);
912
- data = has ? await dataStore.get(hash) : await this.requestData(hash, 'data');
913
- const node = await new peernet.protos['peernet-file'](data);
914
-
915
- if (node.decoded?.links.length > 0) throw new Error(`${hash} is a directory`)
916
- if (options?.pin) await dataStore.put(hash, node.encoded);
917
- return node.decoded.content
918
- }
919
-
920
- /**
921
- * goes trough given stores and tries to find data for given hash
922
- * @param {Array} stores
923
- * @param {string} hash
924
- */
925
- async whichStore(stores, hash) {
926
- let store = stores.pop();
927
- store = globalThis[`${store}Store`];
928
- if (store) {
929
- const has = await store.has(hash);
930
- if (has) return store
931
- if (stores.length > 0) return this.whichStore(stores, hash)
932
- } else return
933
- }
934
-
935
- /**
936
- * Get content for given hash
937
- *
938
- * @param {String} hash - the hash of the wanted data
939
- * @param {String} store - storeName to access
940
- */
941
- async get(hash, store) {
942
- debug(`get ${hash}`);
943
- let data;
944
- if (store) store = globalThis[`${store}Store`];
945
- if (!store) store = await this.whichStore([...this.stores], hash);
946
- if (store && await store.has(hash)) data = await store.get(hash);
947
- if (data) return data
948
-
949
- return this.requestData(hash, store?.name || store)
950
- }
951
-
952
- /**
953
- * put content
954
- *
955
- * @param {String} hash
956
- * @param {Buffer} data
957
- * @param {String} store - storeName to access
958
- */
959
- async put(hash, data, store = 'data') {
960
- store = globalThis[`${store}Store`];
961
- return store.put(hash, data)
962
- }
963
-
964
- /**
965
- * @param {String} hash
966
- * @return {Boolean}
967
- */
968
- async has(hash) {
969
- const store = await this.whichStore([...this.stores], hash);
970
- if (store) {
971
- return store.private ? false : true
972
- }
973
- return false
974
- }
975
-
976
- /**
977
- *
978
- * @param {String} topic
979
- * @param {String|Object|Array|Boolean|Buffer} data
980
- */
981
- async publish(topic, data) {
982
- // globalSub.publish(topic, data)
983
- const id = Math.random().toString(36).slice(-12);
984
- data = await new globalThis.peernet.protos['peernet-ps']({data, topic});
985
- for (const peer of this.connections) {
986
- if (peer.peerId !== this.peerId) {
501
+ /**
502
+ * converts data -> message -> proto
503
+ * @see DataHandler
504
+ */
505
+ pubsub.subscribe('peer:data', dataHandler);
506
+ const importee = await import('@leofcoin/peernet-swarm/client');
507
+ /**
508
+ * @access public
509
+ * @type {PeernetClient}
510
+ */
511
+ this.client = new importee.default(this.id, this.networkVersion, this.stars);
512
+ if (globalThis.navigator) {
513
+ globalThis.addEventListener('beforeunload', async () => this.client.close());
514
+ }
515
+ else {
516
+ process.on('SIGTERM', async () => {
517
+ process.stdin.resume();
518
+ await this.client.close();
519
+ process.exit();
520
+ });
521
+ }
522
+ return this;
523
+ }
524
+ addRequestHandler(name, method) {
525
+ this.requestProtos[name] = method;
526
+ }
527
+ sendMessage(peer, id, data) {
528
+ if (peer.readyState === 'open') {
529
+ peer.send(data, id);
530
+ this.bw.up += data.length;
531
+ }
532
+ else if (peer.readyState === 'closed') ;
533
+ }
534
+ async handleDHT(peer, id, proto) {
535
+ let { hash, store } = proto.decoded;
536
+ let has;
537
+ if (store) {
538
+ store = globalThis[`${store}Store`];
539
+ has = store.private ? false : await store.has(hash);
540
+ }
541
+ else {
542
+ has = await this.has(hash);
543
+ }
544
+ const data = await new globalThis.peernet.protos['peernet-dht-response']({ hash, has });
987
545
  const node = await this.prepareMessage(data);
988
546
  this.sendMessage(peer, id, node.encoded);
989
- }
990
- // TODO: if peer subscribed
991
- }
992
- }
993
-
994
- createHash(data, name) {
995
- return new CodeHash(data, {name})
996
- }
997
-
998
- /**
999
- *
1000
- * @param {String} topic
1001
- * @param {Method} cb
1002
- */
1003
- async subscribe(topic, callback) {
1004
- // TODO: if peer subscribed
1005
- globalSub.subscribe(topic, callback);
1006
- }
1007
-
1008
- async removePeer(peer) {
1009
- return this.client.removePeer(peer)
1010
- }
1011
-
1012
- get Buffer() {
1013
- return Buffer
1014
- }
547
+ }
548
+ async handleData(peer, id, proto) {
549
+ let { hash, store } = proto.decoded;
550
+ let data;
551
+ store = globalThis[`${store}Store`] || await this.whichStore([...this.stores], hash);
552
+ if (store && !store.private) {
553
+ data = await store.get(hash);
554
+ if (data) {
555
+ data = await new globalThis.peernet.protos['peernet-data-response']({ hash, data });
556
+ const node = await this.prepareMessage(data);
557
+ this.sendMessage(peer, id, node.encoded);
558
+ }
559
+ }
560
+ }
561
+ async handleRequest(peer, id, proto) {
562
+ const method = this.requestProtos[proto.decoded.request];
563
+ if (method) {
564
+ const data = await method();
565
+ const node = await this.prepareMessage(data);
566
+ this.sendMessage(peer, id, node.encoded);
567
+ }
568
+ }
569
+ /**
570
+ * @private
571
+ *
572
+ * @param {Buffer} message - peernet message
573
+ * @param {PeernetPeer} peer - peernet peer
574
+ */
575
+ async _protoHandler(message, peer, from) {
576
+ const { id, proto } = message;
577
+ this.bw.down += proto.encoded.length;
578
+ switch (proto.name) {
579
+ case 'peernet-dht': {
580
+ this.handleDHT(peer, id, proto);
581
+ break;
582
+ }
583
+ case 'peenet-data': {
584
+ this.handleData(peer, id, proto);
585
+ break;
586
+ }
587
+ case 'peernet-request': {
588
+ this.handleRequest(peer, id, proto);
589
+ }
590
+ case 'peernet-ps': {
591
+ if (peer.peerId !== this.id)
592
+ globalSub.publish(proto.decoded.topic, proto.decoded.data);
593
+ }
594
+ }
595
+ }
596
+ /**
597
+ * performs a walk and resolves first encounter
598
+ *
599
+ * @param {String} hash
600
+ */
601
+ async walk(hash) {
602
+ if (!hash)
603
+ throw new Error('hash expected, received undefined');
604
+ const data = await new globalThis.peernet.protos['peernet-dht']({ hash });
605
+ this.client.id;
606
+ const walk = async (peer) => {
607
+ const node = await this.prepareMessage(data);
608
+ let result = await peer.request(node.encoded);
609
+ result = new Uint8Array(Object.values(result));
610
+ const proto = await protoFor(result);
611
+ if (proto.name !== 'peernet-dht-response')
612
+ throw dhtError(proto.name);
613
+ // TODO: give ip and port (just used for location)
614
+ if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
615
+ peer.connection.remoteFamily = 'ipv4';
616
+ peer.connection.remoteAddress = '127.0.0.1';
617
+ peer.connection.remotePort = '0000';
618
+ }
619
+ const peerInfo = {
620
+ family: peer.connection.remoteFamily || peer.connection.localFamily,
621
+ address: peer.connection.remoteAddress || peer.connection.localAddress,
622
+ port: peer.connection.remotePort || peer.connection.localPort,
623
+ id: peer.peerId,
624
+ };
625
+ if (proto.decoded.has)
626
+ this.dht.addProvider(peerInfo, proto.decoded.hash);
627
+ };
628
+ let walks = [];
629
+ for (const peer of this.connections) {
630
+ if (peer.peerId !== this.id) {
631
+ walks.push(walk(peer));
632
+ }
633
+ }
634
+ return Promise.all(walks);
635
+ }
636
+ /**
637
+ * Override DHT behavior, try's finding the content three times
638
+ *
639
+ * @param {String} hash
640
+ */
641
+ async providersFor(hash) {
642
+ let providers = await this.dht.providersFor(hash);
643
+ // walk the network to find a provider
644
+ if (!providers || providers.length === 0) {
645
+ await this.walk(hash);
646
+ providers = await this.dht.providersFor(hash);
647
+ // second walk the network to find a provider
648
+ if (!providers || providers.length === 0) {
649
+ await this.walk(hash);
650
+ providers = await this.dht.providersFor(hash);
651
+ }
652
+ // last walk
653
+ if (!providers || providers.length === 0) {
654
+ await this.walk(hash);
655
+ providers = await this.dht.providersFor(hash);
656
+ }
657
+ }
658
+ // undefined if no providers given
659
+ return providers;
660
+ }
661
+ get block() {
662
+ return {
663
+ get: async (hash) => {
664
+ const data = await blockStore.has(hash);
665
+ if (data)
666
+ return blockStore.get(hash);
667
+ return this.requestData(hash, 'block');
668
+ },
669
+ put: async (hash, data) => {
670
+ if (await blockStore.has(hash))
671
+ return;
672
+ return await blockStore.put(hash, data);
673
+ },
674
+ has: async (hash) => await blockStore.has(hash, 'block'),
675
+ };
676
+ }
677
+ get transaction() {
678
+ return {
679
+ get: async (hash) => {
680
+ const data = await transactionStore.has(hash);
681
+ if (data)
682
+ return await transactionStore.get(hash);
683
+ return this.requestData(hash, 'transaction');
684
+ },
685
+ put: async (hash, data) => {
686
+ if (await transactionStore.has(hash))
687
+ return;
688
+ return await transactionStore.put(hash, data);
689
+ },
690
+ has: async (hash) => await transactionStore.has(hash),
691
+ };
692
+ }
693
+ async requestData(hash, store) {
694
+ const providers = await this.providersFor(hash);
695
+ if (!providers || providers.size === 0)
696
+ throw nothingFoundError(hash);
697
+ debug(`found ${providers.size} provider(s) for ${hash}`);
698
+ // get closest peer on earth
699
+ const closestPeer = await this.dht.closestPeer(providers);
700
+ // get peer instance by id
701
+ if (!closestPeer || !closestPeer.id)
702
+ return this.requestData(hash, store?.name || store);
703
+ const id = closestPeer.id;
704
+ if (this.connections) {
705
+ let closest = this.connections.filter((peer) => {
706
+ if (peer.peerId === id)
707
+ return peer;
708
+ });
709
+ let data = await new globalThis.peernet.protos['peernet-data']({ hash, store: store?.name || store });
710
+ const node = await this.prepareMessage(data);
711
+ if (closest[0])
712
+ data = await closest[0].request(node.encoded);
713
+ else {
714
+ closest = this.connections.filter((peer) => {
715
+ if (peer.peerId === id)
716
+ return peer;
717
+ });
718
+ if (closest[0])
719
+ data = await closest[0].request(node.encoded);
720
+ }
721
+ data = new Uint8Array(Object.values(data));
722
+ const proto = await protoFor(data);
723
+ // TODO: store data automaticly or not
724
+ return BufferToUint8Array(proto.decoded.data);
725
+ // this.put(hash, proto.decoded.data)
726
+ }
727
+ return;
728
+ }
729
+ get message() {
730
+ return {
731
+ /**
732
+ * Get content for given message hash
733
+ *
734
+ * @param {String} hash
735
+ */
736
+ get: async (hash) => {
737
+ debug(`get message ${hash}`);
738
+ const message = await messageStore.has(hash);
739
+ if (message)
740
+ return await messageStore.get(hash);
741
+ return this.requestData(hash, 'message');
742
+ },
743
+ /**
744
+ * put message content
745
+ *
746
+ * @param {String} hash
747
+ * @param {Buffer} message
748
+ */
749
+ put: async (hash, message) => await messageStore.put(hash, message),
750
+ /**
751
+ * @param {String} hash
752
+ * @return {Boolean}
753
+ */
754
+ has: async (hash) => await messageStore.has(hash),
755
+ };
756
+ }
757
+ get data() {
758
+ return {
759
+ /**
760
+ * Get content for given data hash
761
+ *
762
+ * @param {String} hash
763
+ */
764
+ get: async (hash) => {
765
+ debug(`get data ${hash}`);
766
+ const data = await dataStore.has(hash);
767
+ if (data)
768
+ return await dataStore.get(hash);
769
+ return this.requestData(hash, 'data');
770
+ },
771
+ /**
772
+ * put data content
773
+ *
774
+ * @param {String} hash
775
+ * @param {Buffer} data
776
+ */
777
+ put: async (hash, data) => await dataStore.put(hash, data),
778
+ /**
779
+ * @param {String} hash
780
+ * @return {Boolean}
781
+ */
782
+ has: async (hash) => await dataStore.has(hash),
783
+ };
784
+ }
785
+ get folder() {
786
+ return {
787
+ /**
788
+ * Get content for given data hash
789
+ *
790
+ * @param {String} hash
791
+ */
792
+ get: async (hash) => {
793
+ debug(`get data ${hash}`);
794
+ const data = await dataStore.has(hash);
795
+ if (data)
796
+ return await dataStore.get(hash);
797
+ return this.requestData(hash, 'data');
798
+ },
799
+ /**
800
+ * put data content
801
+ *
802
+ * @param {String} hash
803
+ * @param {Buffer} data
804
+ */
805
+ put: async (hash, data) => await dataStore.put(hash, data),
806
+ /**
807
+ * @param {String} hash
808
+ * @return {Boolean}
809
+ */
810
+ has: async (hash) => await dataStore.has(hash),
811
+ };
812
+ }
813
+ async addFolder(files) {
814
+ const links = [];
815
+ for (const file of files) {
816
+ const fileNode = await new globalThis.peernet.protos['peernet-file'](file);
817
+ const hash = await fileNode.hash;
818
+ await dataStore.put(hash, fileNode.encoded);
819
+ links.push({ hash, path: file.path });
820
+ }
821
+ const node = await new globalThis.peernet.protos['peernet-file']({ path: '/', links });
822
+ const hash = await node.hash;
823
+ await dataStore.put(hash, node.encoded);
824
+ return hash;
825
+ }
826
+ async ls(hash, options) {
827
+ let data;
828
+ const has = await dataStore.has(hash);
829
+ data = has ? await dataStore.get(hash) : await this.requestData(hash, 'data');
830
+ const node = await new peernet.protos['peernet-file'](data);
831
+ await node.decode();
832
+ console.log(data);
833
+ const paths = [];
834
+ if (node.decoded?.links.length === 0)
835
+ throw new Error(`${hash} is a file`);
836
+ for (const { path, hash } of node.decoded.links) {
837
+ paths.push({ path, hash });
838
+ }
839
+ if (options?.pin)
840
+ await dataStore.put(hash, node.encoded);
841
+ return paths;
842
+ }
843
+ async cat(hash, options) {
844
+ let data;
845
+ const has = await dataStore.has(hash);
846
+ data = has ? await dataStore.get(hash) : await this.requestData(hash, 'data');
847
+ const node = await new peernet.protos['peernet-file'](data);
848
+ if (node.decoded?.links.length > 0)
849
+ throw new Error(`${hash} is a directory`);
850
+ if (options?.pin)
851
+ await dataStore.put(hash, node.encoded);
852
+ return node.decoded.content;
853
+ }
854
+ /**
855
+ * goes trough given stores and tries to find data for given hash
856
+ * @param {Array} stores
857
+ * @param {string} hash
858
+ */
859
+ async whichStore(stores, hash) {
860
+ let store = stores.pop();
861
+ store = globalThis[`${store}Store`];
862
+ if (store) {
863
+ const has = await store.has(hash);
864
+ if (has)
865
+ return store;
866
+ if (stores.length > 0)
867
+ return this.whichStore(stores, hash);
868
+ }
869
+ else
870
+ return;
871
+ }
872
+ /**
873
+ * Get content for given hash
874
+ *
875
+ * @param {String} hash - the hash of the wanted data
876
+ * @param {String} store - storeName to access
877
+ */
878
+ async get(hash, store) {
879
+ debug(`get ${hash}`);
880
+ let data;
881
+ if (store)
882
+ store = globalThis[`${store}Store`];
883
+ if (!store)
884
+ store = await this.whichStore([...this.stores], hash);
885
+ if (store && await store.has(hash))
886
+ data = await store.get(hash);
887
+ if (data)
888
+ return data;
889
+ return this.requestData(hash, store?.name || store);
890
+ }
891
+ /**
892
+ * put content
893
+ *
894
+ * @param {String} hash
895
+ * @param {Buffer} data
896
+ * @param {String} store - storeName to access
897
+ */
898
+ async put(hash, data, store = 'data') {
899
+ store = globalThis[`${store}Store`];
900
+ return store.put(hash, data);
901
+ }
902
+ /**
903
+ * @param {String} hash
904
+ * @return {Boolean}
905
+ */
906
+ async has(hash) {
907
+ const store = await this.whichStore([...this.stores], hash);
908
+ if (store) {
909
+ return store.private ? false : true;
910
+ }
911
+ return false;
912
+ }
913
+ /**
914
+ *
915
+ * @param {String} topic
916
+ * @param {String|Object|Array|Boolean|Buffer} data
917
+ */
918
+ async publish(topic, data) {
919
+ // globalSub.publish(topic, data)
920
+ const id = Math.random().toString(36).slice(-12);
921
+ data = await new globalThis.peernet.protos['peernet-ps']({ data, topic });
922
+ for (const peer of this.connections) {
923
+ if (peer.peerId !== this.peerId) {
924
+ const node = await this.prepareMessage(data);
925
+ this.sendMessage(peer, id, node.encoded);
926
+ }
927
+ // TODO: if peer subscribed
928
+ }
929
+ }
930
+ createHash(data, name) {
931
+ return new CodeHash(data, { name });
932
+ }
933
+ /**
934
+ *
935
+ * @param {String} topic
936
+ * @param {Method} cb
937
+ */
938
+ async subscribe(topic, callback) {
939
+ // TODO: if peer subscribed
940
+ globalSub.subscribe(topic, callback);
941
+ }
942
+ async removePeer(peer) {
943
+ return this.client.removePeer(peer);
944
+ }
945
+ get Buffer() {
946
+ return Buffer;
947
+ }
1015
948
  }
1016
949
  globalThis.Peernet = Peernet;
1017
950