@leofcoin/peernet 0.10.8 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +49 -49
  3. package/dist/browser/peernet.js +101813 -92946
  4. package/dist/commonjs/client-bd0caeb7.js +324 -0
  5. package/dist/commonjs/{codec-6367213c.js → codec-4a768e5e.js} +99 -89
  6. package/dist/commonjs/codec-format-interface.js +41 -24
  7. package/dist/commonjs/codec.js +3 -3
  8. package/dist/commonjs/dht-response.js +3 -3
  9. package/dist/commonjs/dht.js +23 -23
  10. package/dist/commonjs/hash.js +17 -7
  11. package/dist/commonjs/{http-42a6e555.js → http-2b0735ef.js} +19 -15
  12. package/dist/commonjs/peernet-message.js +12 -12
  13. package/dist/commonjs/peernet.js +1162 -964
  14. package/dist/commonjs/request.js +12 -12
  15. package/dist/commonjs/response.js +12 -12
  16. package/dist/module/peernet.js +1323 -1118
  17. package/index.html +4 -6
  18. package/package.json +31 -7
  19. package/rollup.config.js +33 -5
  20. package/rollup0.config.js +7 -0
  21. package/src/codec/codec-format-interface.js +40 -23
  22. package/src/codec/codec.js +21 -11
  23. package/src/codec/codecs.js +79 -79
  24. package/src/handlers/message.js +52 -52
  25. package/src/hash/hash.js +16 -6
  26. package/src/http/client/http-client.js +1 -1
  27. package/src/messages/chat-message.js +14 -14
  28. package/src/messages/data-response.js +14 -14
  29. package/src/messages/data.js +18 -18
  30. package/src/messages/dht-response.js +0 -1
  31. package/src/messages/dht.js +25 -25
  32. package/src/messages/peer-response.js +14 -14
  33. package/src/messages/peer.js +14 -14
  34. package/src/messages/peernet-message.js +14 -14
  35. package/src/messages/ps.js +14 -14
  36. package/src/messages/request.js +14 -14
  37. package/src/messages/response.js +14 -14
  38. package/src/peernet.js +29 -114
  39. package/test/codec.js +3 -2
  40. package/test/messages.js +7 -4
  41. package/test.js +11 -4
  42. package/webpack.config.js +35 -0
  43. package/coverage/lcov-report/base.css +0 -224
  44. package/coverage/lcov-report/block-navigation.js +0 -79
  45. package/coverage/lcov-report/codec-format-interface.js.html +0 -533
  46. package/coverage/lcov-report/codec.js.html +0 -677
  47. package/coverage/lcov-report/dht-response.js.html +0 -188
  48. package/coverage/lcov-report/favicon.png +0 -0
  49. package/coverage/lcov-report/hash.js.html +0 -551
  50. package/coverage/lcov-report/index.html +0 -156
  51. package/coverage/lcov-report/prettify.css +0 -1
  52. package/coverage/lcov-report/prettify.js +0 -2
  53. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  54. package/coverage/lcov-report/sorter.js +0 -170
  55. package/coverage/lcov.info +0 -459
  56. package/debug.log +0 -3
  57. package/dist/browser/peernet.js.tmp-browserify-14074318104595318069 +0 -0
  58. package/dist/browser/peernet.js.tmp-browserify-45407634493269122267 +0 -0
  59. package/dist/browser/peernet.js.tmp-browserify-53722389064799025427 +0 -0
  60. package/dist/browser/peernet.js.tmp-browserify-96323030449218949300 +0 -0
  61. package/dist/codec/codec-format-interface.js +0 -433
  62. package/dist/codec/codec.js +0 -199
  63. package/dist/commonjs/codec-73adfc0f.js +0 -205
  64. package/dist/commonjs/http-2c603501.js +0 -324
  65. package/dist/commonjs/http-43f4fafe.js +0 -324
  66. package/dist/commonjs/http-a94c5a81.js +0 -324
  67. package/dist/commonjs/peernet-message-b6925673.js +0 -32
  68. package/dist/hash/hash.js +0 -340
  69. package/dist/messages/dht-response.js +0 -454
  70. package/dist/messages/dht.js +0 -453
  71. package/dist/messages/peernet.js +0 -456
  72. package/dist/module/http-273664bd.js +0 -317
  73. package/dist/module/http-8fe3c0d7.js +0 -317
  74. package/dist/module/http-c780c991.js +0 -317
  75. package/dist/module/http-f13e0d77.js +0 -317
@@ -1,12 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var PubSub = require('@vandeurenglenn/little-pubsub');
4
- var sha256 = require('crypto-js/sha256');
5
- var P2P = require('p2pt');
6
- var LeofcoinStorage$1 = require('@leofcoin/storage');
7
- var websocket = require('websocket');
8
- var http$1 = require('http');
9
- var Koa = require('koa');
3
+ var LeofcoinStorage = require('@leofcoin/storage');
10
4
  var peernetMessage = require('./peernet-message.js');
11
5
  var dht = require('./dht.js');
12
6
  var dhtResponse = require('./dht-response.js');
@@ -14,782 +8,620 @@ var protons = require('protons');
14
8
  var codecFormatInterface = require('./codec-format-interface.js');
15
9
  var request = require('./request.js');
16
10
  var response = require('./response.js');
17
- var fetch$1 = require('node-fetch');
18
- var codec = require('./codec-6367213c.js');
11
+ var fetch = require('node-fetch');
12
+ var codec = require('./codec-4a768e5e.js');
19
13
  var hash = require('./hash.js');
20
- var MultiWallet = require('@leofcoin/multi-wallet');
21
- require('bs32');
22
- require('bs58');
14
+ var generateAccount = require('@leofcoin/generate-account');
15
+ var bs58check = require('bs58check');
16
+ var bip39 = require('bip39');
17
+ var bip32 = require('bip32');
18
+ var createKeccakHash = require('keccak');
19
+ var secp256k1 = require('secp256k1');
20
+ var ecc = require('tiny-secp256k1');
21
+ var MultiSignature = require('multi-signature');
22
+ var varint = require('varint');
23
+ var AES = require('crypto-js/aes.js');
24
+ require('crypto-js/sha512.js');
25
+ var ENC = require('crypto-js/enc-utf8.js');
26
+ require('@vandeurenglenn/base32');
27
+ require('@vandeurenglenn/base58');
23
28
  require('is-hex');
24
- require('varint');
25
- require('keccak');
26
29
 
27
30
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
28
31
 
29
- var PubSub__default = /*#__PURE__*/_interopDefaultLegacy(PubSub);
30
- var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
31
- var P2P__default = /*#__PURE__*/_interopDefaultLegacy(P2P);
32
- var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage$1);
33
- var Koa__default = /*#__PURE__*/_interopDefaultLegacy(Koa);
34
- var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
35
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch$1);
36
- var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet);
37
-
38
- class PeernetPeer {
39
- constructor(id, connection) {
40
- this._events = {};
41
- this.bw = {
42
- up: 0,
43
- down: 0,
44
- };
45
- this.id = id;
46
- this.connection = connection;
47
-
48
- this.connection.on('data', (message) => {
49
- this.bw.down += message.length;
50
- pubsub.publish('peernet.data', JSON.parse(message.toString()));
51
- });
52
- }
53
-
54
- request(data) {
55
- return new Promise((resolve, reject) => {
56
- const id = Math.random().toString(36).slice(-12);
57
- data = Buffer.from(JSON.stringify({id, data}));
58
- const _onData = (message) => {
59
- if (message.id !== id) return
60
-
61
- resolve(message.data);
62
- };
63
-
64
- pubsub.subscribe('peernet.data', _onData);
65
-
66
- // cleanup subscriptions
67
- setTimeout(() => {
68
- pubsub.unsubscribe('peernet.data', _onData);
69
- }, 5000);
70
-
71
- this.write(data);
32
+ function _interopNamespace(e) {
33
+ if (e && e.__esModule) return e;
34
+ var n = Object.create(null);
35
+ if (e) {
36
+ Object.keys(e).forEach(function (k) {
37
+ if (k !== 'default') {
38
+ var d = Object.getOwnPropertyDescriptor(e, k);
39
+ Object.defineProperty(n, k, d.get ? d : {
40
+ enumerable: true,
41
+ get: function () { return e[k]; }
42
+ });
43
+ }
72
44
  });
73
45
  }
46
+ n["default"] = e;
47
+ return Object.freeze(n);
48
+ }
74
49
 
75
- write(data) {
76
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
77
-
78
- this.bw.up += data.length;
79
- this.connection.write(data);
80
- }
81
-
82
- on(event = 'peernet.data', cb) {
83
- this._events[event] = cb;
84
- pubsub.subscribe(event, cb);
85
- // this.connection.on(event, cb)
86
- }
87
-
88
- removeListener(event = 'data', cb) {
89
- delete this._events[event];
90
- pubsub.unsubscribe(event, cb);
50
+ var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage);
51
+ var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
52
+ var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
53
+ var generateAccount__default = /*#__PURE__*/_interopDefaultLegacy(generateAccount);
54
+ var bs58check__default = /*#__PURE__*/_interopDefaultLegacy(bs58check);
55
+ var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
56
+ var bip32__namespace = /*#__PURE__*/_interopNamespace(bip32);
57
+ var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
58
+ var ecc__default = /*#__PURE__*/_interopDefaultLegacy(ecc);
59
+ var MultiSignature__default = /*#__PURE__*/_interopDefaultLegacy(MultiSignature);
60
+ var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
61
+ var AES__default = /*#__PURE__*/_interopDefaultLegacy(AES);
62
+ var ENC__default = /*#__PURE__*/_interopDefaultLegacy(ENC);
63
+
64
+ /* socket-request-client version 1.6.1 */
65
+
66
+ class LittlePubSub {
67
+ constructor(verbose = true) {
68
+ this.subscribers = {};
69
+ this.verbose = verbose;
70
+ }
71
+ subscribe(event, handler, context) {
72
+ if (typeof context === 'undefined') {
73
+ context = handler;
74
+ }
75
+ this.subscribers[event] = this.subscribers[event] || { handlers: [], value: null};
76
+ this.subscribers[event].handlers.push(handler.bind(context));
91
77
  }
92
-
93
- close() {
94
- for (const event of Object.keys(this._events)) {
95
- pubsub.unsubscribe(event, this._events[event]);
78
+ unsubscribe(event, handler, context) {
79
+ if (typeof context === 'undefined') {
80
+ context = handler;
96
81
  }
97
- this._events = [];
98
-
99
- for (const event of this.connection._events.data) {
100
- this.connection.removeListener('data', event);
82
+ if (this.subscribers[event]) {
83
+ const index = this.subscribers[event].handlers.indexOf(handler.bind(context));
84
+ this.subscribers[event].handlers.splice(index);
85
+ if (this.subscribers[event].handlers.length === 0) delete this.subscribers[event];
101
86
  }
102
- this.connection.destroy();
103
87
  }
104
- }
105
-
106
- /**
107
- * Array of peers
108
- * @type {Array}
109
- * @property {PeernetPeer} peer Instance of Peer
110
- */
111
- globalThis.connections = new Map();
112
- globalThis.recentConnections = new Map();
113
- globalThis.pubsub = globalThis.pubsub || new PubSub__default["default"]({verbose: false});
114
-
115
- class PeernetClient {
116
- constructor(options = {}) {
117
- if (!options.id) options.id = Buffer.from('00000000000000000000000000000000');
118
- if (!options.networkVersion) options.networkVersion = 'v0.1.0';
119
- if (!options.networkName) options.networkName = 'peernet';
120
- this.id = options.id;
121
-
122
- this.topic = Buffer.from(sha256__default["default"](`${options.networkName}-${options.networkVersion}`).toString());
123
-
124
- const trackers = [
125
- 'wss://star.leofcoin.org',
126
- 'wss://tracker.openwebtorrent.com',
127
- // 'wss://tracker.sloppyta.co:443/announce',
128
- ];
129
- this.p2p = new P2P__default["default"](trackers, this.topic.slice(0, 20));
130
- this.p2p.on('peerconnect', (peer) => {
131
- peer = new PeernetPeer(peer.id, peer);
132
- connections.set(peer.id, peer);
133
- pubsub.publish('peer:discovered', peer);
134
- });
135
-
136
- this.p2p.on('peerclose', (peer) => {
137
- // TODO: close peernetPeer
138
- const peernetPeer = connections.get(peer.id);
139
- if (peernetPeer) {
140
- peernetPeer.close();
88
+ publish(event, change) {
89
+ if (this.subscribers[event]) {
90
+ if (this.verbose || this.subscribers[event].value !== change) {
91
+ this.subscribers[event].value = change;
92
+ this.subscribers[event].handlers.forEach(handler => {
93
+ handler(change, this.subscribers[event].value);
94
+ });
141
95
  }
142
- connections.delete(peer.id);
143
- pubsub.publish('peer:disconnected', peer);
144
- });
145
-
146
- this.p2p.start();
147
-
148
- if (globalThis.process) {
149
- process.on('SIGINT', async () => {
150
- console.log('Caught interrupt signal');
151
- this.close();
152
- setTimeout(async () => {
153
- process.exit();
154
- }, 100);
155
- });
156
- } else {
157
- globalThis.onbeforeunload = () => {
158
- this.close();
159
- };
160
96
  }
161
- //
162
- // this.sw.on('close', () => {
163
- // })
164
- }
165
-
166
- close() {
167
- return this.p2p.destroy()
168
- }
169
-
170
- _peers() {
171
- return this.p2p.getPeers()
172
97
  }
173
98
  }
174
99
 
175
- var version = "0.10.7";
176
-
177
- var api$1 = {
178
- version: ({send}) => send({client: '@peernet/api/http', version}),
179
- ready: ({send}) => {
180
- if (globalThis.states.ready) send(true);
181
- else pubsub.subscribe('ready', () => send(true));
182
- },
183
- storage: async (params, {send, error}) => {
184
- console.log(params);
185
- const {name, root, key, value, method} = params;
186
- try {
187
- if (name && root) {
188
- globalThis[name] = globalThis[name] || await new LeofcoinStorage(name, root);
189
- } else {
190
- return error('Expected name & root')
191
- }
192
- if (method === 'put') {
193
- await globalThis[name].put(key, value);
194
- return send('ok')
195
- }
196
- if (method === 'remove') {
197
- await globalThis[name].remove(key, value);
198
- return send('ok')
199
- }
200
- value = await globalThis[name].get(key);
201
- return send(value)
202
- } catch (e) {
203
- return error(e)
204
- }
205
- },
206
- getConfig: async (params, {send, error}) => {
207
- try {
208
- const config = await api.getConfig(params);
209
- send(config);
210
- } catch (e) {
211
- error(e);
212
- }
213
- },
214
- setMinerConfig: async (params, {send, error}) => {
215
- try {
216
- await api.setMinerConfig(params);
217
- send('ok');
218
- } catch (e) {
219
- error(e);
100
+ var clientApi = _pubsub => {
101
+ const subscribe = (topic, cb) => {
102
+ _pubsub.subscribe(topic, cb);
103
+ };
104
+ const unsubscribe = (topic, cb) => {
105
+ _pubsub.unsubscribe(topic, cb);
106
+ };
107
+ const publish = (topic, value) => {
108
+ _pubsub.publish(topic, value);
109
+ };
110
+ const _connectionState = (state) => {
111
+ switch (state) {
112
+ case 0:
113
+ return 'connecting'
114
+ case 1:
115
+ return 'open'
116
+ case 2:
117
+ return 'closing'
118
+ case 3:
119
+ return 'closed'
220
120
  }
221
- },
222
- getMinerConfig: async ({send, error}) => {
223
- try {
224
- const config = await api.getMinerConfig();
225
- send(config);
226
- } catch (e) {
227
- error(e);
121
+ };
122
+ const request = (client, request) => {
123
+ return new Promise((resolve, reject) => {
124
+ const state = _connectionState(client.readyState);
125
+ if (state !== 'open') return reject(`coudn't send request to ${client.id}, no open connection found.`)
126
+ request.id = Math.random().toString(36).slice(-12);
127
+ const handler = result => {
128
+ if (result && result.error) return reject(result.error)
129
+ resolve({result, id: request.id, handler});
130
+ unsubscribe(request.id, handler);
131
+ };
132
+ subscribe(request.id, handler);
133
+ send(client, request);
134
+ });
135
+ };
136
+ const send = async (client, request) => {
137
+ return client.send(JSON.stringify(request))
138
+ };
139
+ const pubsub = client => {
140
+ return {
141
+ publish: (topic = 'pubsub', value) => {
142
+ return send(client, {url: 'pubsub', params: { topic, value }})
143
+ },
144
+ subscribe: (topic = 'pubsub', cb) => {
145
+ subscribe(topic, cb);
146
+ return send(client, {url: 'pubsub', params: { topic, subscribe: true }})
147
+ },
148
+ unsubscribe: (topic = 'pubsub', cb) => {
149
+ unsubscribe(topic, cb);
150
+ return send(client, {url: 'pubsub', params: { topic, unsubscribe: true }})
151
+ },
152
+ subscribers: _pubsub.subscribers
228
153
  }
229
- },
230
- wallet: async ({send}) => {
231
- const wallet = await walletStore.get();
232
- send(wallet);
233
- },
234
- addresses: async ({send, error}) => {
235
- try {
236
- const adresses = await api.addresses();
237
- send(adresses);
238
- } catch (e) {
239
- error(e);
154
+ };
155
+ const server = (client) => {
156
+ return {
157
+ uptime: async () => {
158
+ try {
159
+ const { result, id, handler } = await request(client, {url: 'uptime'});
160
+ unsubscribe(id, handler);
161
+ return result
162
+ } catch (e) {
163
+ throw e
164
+ }
165
+ },
166
+ ping: async () => {
167
+ try {
168
+ const now = new Date().getTime();
169
+ const { result, id, handler } = await request(client, {url: 'ping'});
170
+ unsubscribe(id, handler);
171
+ return (Number(result) - now)
172
+ } catch (e) {
173
+ throw e
174
+ }
175
+ }
240
176
  }
241
- },
242
- accountNames: async (params, {send, error}) => {
243
- try {
244
- const adresses = await api.accountNames(params.index);
245
- send(adresses);
246
- } catch (e) {
247
- error(e);
177
+ };
178
+ const peernet = (client) => {
179
+ return {
180
+ join: async (params) => {
181
+ try {
182
+ params.join = true;
183
+ const requested = { url: 'peernet', params };
184
+ const { result, id, handler } = await request(client, requested);
185
+ unsubscribe(id, handler);
186
+ return result
187
+ } catch (e) {
188
+ throw e
189
+ }
190
+ },
191
+ leave: async (params) => {
192
+ try {
193
+ params.join = false;
194
+ const requested = { url: 'peernet', params };
195
+ const { result, id, handler } = await request(client, requested);
196
+ unsubscribe(id, handler);
197
+ return result
198
+ } catch (e) {
199
+ throw e
200
+ }
201
+ }
248
202
  }
249
- },
250
- accounts: async ({send}) => {
251
- const accounts = await accountStore.get();
252
- send(accounts);
253
- },
254
- account: async (params, {send}) => {
255
- const account = await accountStore.get(params);
256
- send(account);
257
- },
258
- balance: async (params, {send, error}) => {
259
- console.log('balance');
260
- try {
261
- console.log(await api.getBalanceForAddress(params.address));
262
- const value = await api.getBalanceForAddress(params.address);
263
- send(value);
264
- } catch (e) {
265
- console.log(e);
266
- error(e);
203
+ };
204
+ return { send, request, pubsub, server, subscribe, unsubscribe, publish, peernet }
205
+ };
206
+
207
+ if (!globalThis.PubSub) globalThis.PubSub = LittlePubSub;
208
+ if (!globalThis.pubsub) globalThis.pubsub = new LittlePubSub({verbose: false});
209
+ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry: false }) => {
210
+ const { retry } = options;
211
+ const api = clientApi(pubsub);
212
+ let tries = 0;
213
+ const onerror = error => {
214
+ if (pubsub.subscribers['error']) {
215
+ pubsub.publish('error', error);
216
+ } else {
217
+ console.error(error);
267
218
  }
268
- },
269
- balanceAfter: async (params, {send, error}) => {
270
- try {
271
- const value = await api.getBalanceForAddressAfter(params.address, params.index);
272
- send(value);
273
- } catch (e) {
274
- error(e);
219
+ };
220
+ const onmessage = message => {
221
+ const {value, url, status, id} = JSON.parse(message.data.toString());
222
+ const publisher = id ? id : url;
223
+ if (status === 200) {
224
+ pubsub.publish(publisher, value);
225
+ } else {
226
+ pubsub.publish(publisher, {error: value});
275
227
  }
276
- },
277
- mine: async (params, {send, error}) => {
278
- api.mine(params);
279
- send('ok');
280
- },
281
- lastBlock: async ({send, error}) => {
282
- try {
283
- const value = await api.lastBlock();
284
- send(value);
285
- } catch (e) {
286
- error(e);
228
+ };
229
+ const clientConnection = client => {
230
+ const startTime = new Date().getTime();
231
+ return {
232
+ client,
233
+ request: async req => {
234
+ const { result, id, handler } = await api.request(client, req);
235
+ pubsub.unsubscribe(id, handler);
236
+ return result
237
+ },
238
+ send: req => api.send(client, req),
239
+ subscribe: api.subscribe,
240
+ unsubscribe: api.unsubscribe,
241
+ subscribers: api.subscribers,
242
+ publish: api.publish,
243
+ pubsub: api.pubsub(client),
244
+ uptime: () => {
245
+ const now = new Date().getTime();
246
+ return (now - startTime)
247
+ },
248
+ peernet: api.peernet(client),
249
+ server: api.server(client),
250
+ close: exit => {
251
+ client.onclose = message => {
252
+ if (exit) process.exit();
253
+ };
254
+ client.close();
255
+ }
287
256
  }
288
- },
289
- };
290
-
291
- const fullLog = text => {
292
- return console.log(`${new Date()}: ${text}`)
257
+ };
258
+ return new Promise((resolve, reject) => {
259
+ const init = () => {
260
+ let ws;
261
+ if (typeof process === 'object' && !globalThis.WebSocket) {
262
+ ws = require('websocket').w3cwebsocket;
263
+ } else {
264
+ ws = WebSocket;
265
+ }
266
+ const client = new ws(url, protocols);
267
+ client.onmessage = onmessage;
268
+ client.onerror = onerror;
269
+ client.onopen = () => {
270
+ tries = 0;
271
+ resolve(clientConnection(client));
272
+ };
273
+ client.onclose = message => {
274
+ tries++;
275
+ if (!retry) return reject(options)
276
+ if (tries > 5) {
277
+ console.log(`${protocols} Client Closed`);
278
+ console.error(`could not connect to - ${url}/`);
279
+ return resolve(clientConnection(client))
280
+ }
281
+ if (message.code === 1006) {
282
+ console.log('Retrying in 10 seconds');
283
+ setTimeout(() => {
284
+ return init();
285
+ }, retry);
286
+ }
287
+ };
288
+ };
289
+ return init();
290
+ });
293
291
  };
294
292
 
295
- const originIsAllowed = (requestOrigin, origin) => {
296
- // put logic here to detect whether the specified origin is allowed.
297
- if (origin && requestOrigin !== origin) return false;
298
- return true;
299
- };
293
+ class Peer {
294
+ #connection
295
+ #ready = false
296
+ #connecting = false
297
+ #connected = false
298
+ #channelReady = false
299
+ #destroying = false
300
+ #destroyed = false
301
+ #isNegotiating = false
302
+ #firstNegotiation = true
303
+ #iceComplete = false
304
+ #remoteTracks = []
305
+ #remoteStreams = []
306
+ #pendingCandidates = []
307
+ #senderMap = new Map()
308
+ #iceCompleteTimer
309
+ #channel
310
+
311
+ get connection() {
312
+ return this.#connection
313
+ }
314
+
315
+ get connected() {
316
+ return this.#connected
317
+ }
300
318
 
301
319
  /**
302
- * @module socketResponse
303
- *
304
- * @param {object} connection socket connection
305
- * @param {string} route the route to handle
306
- */
307
- var socketConnection = (request, protocol, origin) => {
308
- if (origin && !originIsAllowed(request.origin, origin)) {
309
- // Make sure we only accept requests from an allowed origin
310
- request.reject();
311
- fullLog(`Connection from origin ${request.origin} rejected.`);
312
- return;
313
- }
314
- // console.log(request);
315
- const connection = request.accept(protocol, request.origin);
316
- fullLog(`Connection accepted @${protocol}`);
317
- return connection;
318
- };
319
-
320
- /**
321
- * @module socketResponse
322
- *
323
- * @param {object} connection socket connection
324
- * @param {string} url the request url
320
+ * @params {Object} options
321
+ * @params {string} options.channelName - this peerid : otherpeer id
325
322
  */
326
- var socketResponse = (connection, url, id, customEvent) => {
327
- const send = (data = 'ok', status = 200) => connection.send(
328
- JSON.stringify({url, status, value: data, id, customEvent})
329
- );
330
- const error = data => connection.send(JSON.stringify({url, value: data}));
331
- return {
332
- connection,
333
- send,
334
- error
335
- }
336
- };
337
-
338
- const socketRequestServer = (options, routes = {}) => {
339
- // if (!routes && !routes.port && options) routes = options;
340
- // else if (!options && !routes) return console.error('no routes defined');
341
-
342
- let {httpServer, httpsServer, port, protocol, credentials, origin, pubsub } = options;
343
- if (!pubsub) pubsub = new PubSub__default["default"]({verbose: false});
344
- if (!port) port = 6000;
345
- const connections = [];
346
- let connection;
347
- const startTime = new Date().getTime();
348
- // default routes
349
- if (!routes.ping) routes.ping = (response) => response.send(new Date().getTime());
350
- if (!routes.uptime) routes.uptime = (response) => {
351
- const now = new Date().getTime();
352
- response.send(now - startTime);
323
+ constructor(options = {}) {
324
+ this._in = this._in.bind(this);
325
+ this.offerOptions = options.offerOptions;
326
+ this.initiator = options.initiator;
327
+ this.streams = options.streams;
328
+ this.socketClient = options.socketClient;
329
+ this.id = options.id;
330
+ this.to = options.to;
331
+ this.bw = {
332
+ up: 0,
333
+ down: 0
353
334
  };
354
- if (!routes.pubsub) {
355
- routes.pubsub = (params, response) => {
356
- if (!response) {
357
- response = params;
358
- params = {};
359
- }
360
-
361
- if (!params.topic) params.topic = 'pubsub';
362
-
363
- const topic = params.topic;
364
- delete params.topic;
365
-
366
- if (params.subscribe) {
367
- pubsub.subscribe(topic, message => {
368
- response.connection.send(JSON.stringify({url: topic, status: 200, value: message}));
369
- });
370
- response.send('ok', 200);
371
- } else if (params.unsubscribe) {
372
- pubsub.unsubscribe(topic, message => {
373
- response.connection.send(JSON.stringify({url: topic, status: 200, value: message}));
374
- });
375
- for (const connection of connections) {
376
- if (connection !== response.connection) connection.send(JSON.stringify({url: topic, status: 200, value: params}));
377
- }
378
- response.send('ok', 200);
335
+
336
+ this.channelName = options.channelName || Buffer.from(Math.random().toString(36).slice(-12)).toString('hex');
337
+ console.log(this.channelName);
338
+ this.options = options;
339
+ this.#init();
340
+ }
341
+
342
+ set socketClient(value) {
343
+ // this.socketClient?.pubsub.unsubscribe('signal', this._in)
344
+ this._socketClient = value;
345
+ this._socketClient.pubsub.subscribe('signal', this._in);
346
+ }
347
+
348
+ get socketClient() {
349
+ return this._socketClient
350
+ }
351
+
352
+ send(message) {
353
+ this.bw.up += message.length;
354
+ this.channel.send(message);
355
+ }
356
+
357
+ request(data) {
358
+ return new Promise((resolve, reject) => {
359
+ const id = Math.random().toString(36).slice(-12);
360
+ data = new TextEncoder().encode(JSON.stringify({id, data}));
361
+ const _onData = message => {
362
+ message = JSON.parse(new TextDecoder().decode(message.data));
363
+ if (message.id === id) {
364
+ resolve(message.data);
365
+ pubsub.unsubscribe('peer:data', _onData);
379
366
  }
380
- else if (params.value !== undefined)
381
- // should only be send raw to stars
382
- // for (const connection of connections) {
383
- // if (connection !== response.connection) connection.send(JSON.stringify({
384
- // url: topic, status: 200, value: params
385
- // }));
386
- // }
387
- pubsub.publish(topic, params.value);
388
- response.send('ok', 200);
389
367
  };
390
-
368
+
369
+ pubsub.subscribe('peer:data', _onData);
370
+
371
+ // cleanup subscriptions
372
+ setTimeout(() => {
373
+ pubsub.unsubscribe('peer:data', _onData);
374
+ }, 5000);
375
+
376
+ this.send(data);
377
+ });
378
+ }
379
+
380
+ async #init() {
381
+ try {
382
+ const iceServers = [{
383
+ urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
384
+ }];
385
+
386
+ this.#connection = new wrtc.RTCPeerConnection();
387
+ this.#connection.onicecandidate = ({ candidate }) => {
388
+ if (candidate) {
389
+ this.address = candidate.address;
390
+ this.port = candidate.port;
391
+ this.protocol = candidate.protocol;
392
+ this.ipFamily = this.address.includes('::') ? 'ipv6': 'ipv4';
393
+ this._sendMessage({candidate});
394
+ }
395
+ };
396
+ // if (this.initiator) this.#connection.onnegotiationneeded = () => {
397
+ // console.log('create offer');
398
+ this.#connection.ondatachannel = (message) => {
399
+ message.channel.onopen = () => {
400
+ this.#connected = true;
401
+ pubsub.publish('peer:connected', this);
402
+ };
403
+ message.channel.onclose = () => console.log('close');
404
+ message.channel.onmessage = (message) => {
405
+ if (message.to) {
406
+ if (message.to === this.id) pubsub.publish('peer:data', message);
407
+ } else pubsub.publish('peer:data', message);
408
+ this.bw.down += message.length;
409
+ };
410
+ this.channel = message.channel;
411
+ };
412
+ if (this.initiator) {
413
+
414
+ this.channel = this.#connection.createDataChannel('messageChannel');
415
+ this.channel.onopen = () => {
416
+ this.#connected = true;
417
+ pubsub.publish('peer:connected', this);
418
+ // this.channel.send('hi')
419
+ };
420
+ this.channel.onclose = () => this.close.bind(this);
421
+
422
+ this.channel.onmessage = (message) => {
423
+ if (message.to) {
424
+ if (message.to === this.id) pubsub.publish('peer:data', message);
425
+ } else pubsub.publish('peer:data', message);
426
+ this.bw.down += message.length;
427
+ };
428
+
429
+ const offer = await this.#connection.createOffer();
430
+ await this.#connection.setLocalDescription(offer);
431
+
432
+ this._sendMessage({'sdp': this.#connection.localDescription});
433
+ }
434
+ // }
435
+
436
+ } catch (e) {
437
+ console.log(e);
438
+ }
439
+ }
440
+
441
+ _sendMessage(message) {
442
+ this.socketClient.send({url: 'signal', params: {
443
+ to: this.to,
444
+ from: this.id,
445
+ channelName: this.options.channelName,
446
+ ...message
447
+ }});
448
+ }
449
+
450
+ async _in(message, data) {
451
+ // message = JSON.parse(message);
452
+ if (message.to !== this.id) return
453
+ // if (data.videocall) return this._startStream(true, false); // start video and audio stream
454
+ // if (data.call) return this._startStream(true, true); // start audio stream
455
+ if (message.candidate) {
456
+ this.remoteAddress = message.candidate.address;
457
+ this.remotePort = message.candidate.port;
458
+ this.remoteProtocol = message.candidate.protocol;
459
+ this.remoteIpFamily = this.remoteAddress?.includes('::') ? 'ipv6': 'ipv4';
460
+ return this.#connection.addIceCandidate(new wrtc.RTCIceCandidate(message.candidate));
391
461
  }
392
- globalThis.peerMap = new Map();
393
- if (!routes.peernet) {
394
- routes.peernet = (params, response) => {
395
- if (params.join) {
396
- peerMap.set(params.peerId, params.address);
397
- response.send([...peerMap.values()]);
398
- for (const connection of connections) {
399
- if (connection !== response.connection)
400
- socketResponse(connection, 'peernet', 'peernet').send({discovered: params.address});
401
- }
402
- return
462
+ try {
463
+ if (message.sdp) {
464
+ if (message.sdp.type === 'offer') {
465
+ await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
466
+ const answer = await this.#connection.createAnswer();
467
+ await this.#connection.setLocalDescription(answer);
468
+ this._sendMessage({'sdp': this.#connection.localDescription});
403
469
  }
404
- if (!params.join) {
405
- peerMap.delete(params.peerId);
406
- return response.send()
470
+ if (message.sdp.type === 'answer') {
471
+ await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
407
472
  }
408
- };
473
+ }
474
+ } catch (e) {
475
+ console.log(e);
409
476
  }
410
- // if (!protocol) protocol = 'echo-protocol';
411
- if (!httpServer && !httpsServer) {
412
- const { createServer } = credentials ? require('https') : require('http');
413
- if (credentials) httpServer = createServer(credentials);
414
- else httpServer = createServer();
415
-
416
- httpServer.listen(port, () => {
417
- console.log(`listening on ${port}`);
418
- });
477
+ }
478
+
479
+ close() {
480
+ this.channel?.close();
481
+ this.#connection?.close();
482
+
483
+ this.socketClient.pubsub.unsubscribe('signal', this._in);
484
+ }
485
+ }
486
+
487
+ class Client {
488
+ #peerConnection
489
+ #connections = {}
490
+ #stars = {}
491
+
492
+ get connections() {
493
+ return { ...this.#connections }
419
494
  }
420
495
 
421
- const socketServer = new websocket.server({
422
- httpServer,
423
- autoAcceptConnections: false
424
- });
425
-
426
- socketServer.on('request', request => {
427
-
428
- connection = socketConnection(request, protocol, origin);
429
- connections.push(connection);
430
-
431
- const routeHandler = message => {
432
- let data;
433
- if (message.type) {
434
- switch (message.type) {
435
- case 'binary':
436
- data = message.binaryData.toString();
437
- break;
438
- case 'utf8':
439
- data = message.utf8Data;
440
- break;
441
- }
442
- }
443
- const { route, params, url, id, customEvent } = JSON.parse(data);
444
- // ignore api when customEvent is defined
445
- if (customEvent) return;
446
- if (routes[url]) {
447
- if (!params) return routes[url](socketResponse(connection, url, id));
448
- return routes[url](params, socketResponse(connection, url, id));
449
- }
450
- else return socketResponse(connection, url, id).error(`nop handler found for '${message.url}'`);
451
- };
496
+ constructor(id, identifiers = ['peernet-v0.1.0'], stars = []) {
497
+ this.id = id || Math.random().toString(36).slice(-12);
498
+ if (!Array.isArray(identifiers)) identifiers = [identifiers];
499
+ this.peerJoined = this.peerJoined.bind(this);
500
+ this.peerLeft = this.peerLeft.bind(this);
501
+ this.starLeft = this.starLeft.bind(this);
502
+ this.starJoined = this.starJoined.bind(this);
452
503
 
453
- connection.on('message', routeHandler);
454
- });
504
+ this._init(identifiers, stars);
505
+ }
455
506
 
456
- return {
457
- close: () => socketServer.shutDown(),
458
- connections
459
- };
460
- };
461
-
462
- var http = (config = {}) => {
463
- if (typeof config !== 'object') config = {};
464
- if (!config.protocol) config.protocol = 'peernet-v0.1.0';
465
- if (!config.port) config.port = 2000;
466
- if (!config.host) config.host = '127.0.0.1';
467
-
468
- const app = new Koa__default["default"]();
469
-
470
- app.use(async (ctx) => {
471
- const url = ctx.url.split('/api/')[1];
472
- if (url === 'version') ctx.body = {client: '@peernet/api/http', version};
473
- });
474
-
475
- const httpServer = http$1.createServer(app.callback());
476
-
477
- config.httpServer = httpServer;
478
-
479
- httpServer.listen(config.port, () => {
480
- console.log(`listening on ${config.port}`);
481
- });
482
-
483
- return socketRequestServer(config, api$1)
484
- };
485
-
486
- var clientApi = _pubsub => {
487
-
488
- const subscribe = (topic, cb) => {
489
- _pubsub.subscribe(topic, cb);
490
- };
491
-
492
- const unsubscribe = (topic, cb) => {
493
- _pubsub.unsubscribe(topic, cb);
494
- };
495
-
496
- const publish = (topic, value) => {
497
- _pubsub.publish(topic, value);
498
- };
499
-
500
- const _connectionState = (state) => {
501
- switch (state) {
502
- case 0:
503
- return 'connecting'
504
- case 1:
505
- return 'open'
506
- case 2:
507
- return 'closing'
508
- case 3:
509
- return 'closed'
507
+ async _init(identifiers, stars = []) {
508
+ if (stars.length === 0) {
509
+ stars.push('wss://star.leofcoin.org');
510
+ stars.push('ws://localhost:44444');
510
511
  }
511
- };
512
- /**
513
- * @param {string} type
514
- * @param {string} name
515
- * @param {object} params
516
- */
517
- const request = (client, request) => {
518
- return new Promise((resolve, reject) => {
519
-
520
- const state = _connectionState(client.readyState);
521
- if (state !== 'open') return reject(`coudn't send request to ${client.id}, no open connection found.`)
522
-
523
- request.id = Math.random().toString(36).slice(-12);
524
- const handler = result => {
525
- if (result && result.error) return reject(result.error)
526
- resolve({result, id: request.id, handler});
527
- };
528
- subscribe(request.id, handler);
529
- send(client, request);
512
+ this.identifiers = identifiers;
513
+ this.starsConfig = stars;
514
+ // reconnectJob()
515
+
516
+ globalThis.wrtc = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('wrtc')); });
517
+ for (const star of stars) {
518
+ try {
519
+ this.socketClient = await socketRequestClient(star, identifiers[0]);
520
+ const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
521
+ this.socketClient.peerId = id;
522
+ this.#stars[id] = this.socketClient;
523
+ } catch (e) {
524
+ if (stars.indexOf(star) === stars.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
525
+ }
526
+ }
527
+ const peers = await this.socketClient.peernet.join({id: this.id});
528
+ for (const id of peers) {
529
+ if (id !== this.id && !this.#connections[id]) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id});
530
+ }
531
+ this.setupListeners();
532
+
533
+ pubsub.subscribe('peer:connected', (peer) => {
534
+ // peer.send(JSON.stringify({data: 'hello', from: this.id, to: peer.to}))
535
+ console.log({peer: peer.to});
536
+ console.log({id: peer.id});
537
+ console.log({id: this.id});
530
538
  });
531
- };
532
-
533
- const send = async (client, request) => {
534
- return client.send(JSON.stringify(request))
535
- };
536
-
537
- const pubsub = client => {
538
- return {
539
- publish: (topic = 'pubsub', value) => {
540
- return send(client, {url: 'pubsub', params: { topic, value }})
541
- },
542
- subscribe: (topic = 'pubsub', cb) => {
543
- subscribe(topic, cb);
544
- return send(client, {url: 'pubsub', params: { topic, subscribe: true }})
545
- },
546
- unsubscribe: (topic = 'pubsub', cb) => {
547
- unsubscribe(topic, cb);
548
- return send(client, {url: 'pubsub', params: { topic, unsubscribe: true }})
549
- },
550
- subscribers: _pubsub.subscribers
539
+ // pubsub.subscribe('peer:data', (data) => console.log({data}))
540
+ }
541
+
542
+ setupListeners() {
543
+ this.socketClient.subscribe('peer:joined', this.peerJoined);
544
+ this.socketClient.subscribe('peer:left', this.peerLeft);
545
+ this.socketClient.subscribe('star:left', this.starLeft);
546
+ }
547
+
548
+ starJoined(id) {
549
+ if (this.#stars[id]) {
550
+ this.#stars[id].close();
551
+ delete this.#stars[id];
551
552
  }
552
- };
553
-
554
- const server = (client) => {
555
- return {
556
- uptime: async () => {
557
- try {
558
- const { result, id, handler } = await request(client, {url: 'uptime'});
559
- unsubscribe(id, handler);
560
- return result
561
- } catch (e) {
562
- throw e
563
- }
564
- },
565
- ping: async () => {
566
- try {
567
- const now = new Date().getTime();
568
- const { result, id, handler } = await request(client, {url: 'ping'});
569
- unsubscribe(id, handler);
570
- return (Number(result) - now)
571
- } catch (e) {
572
- throw e
573
- }
574
- }
553
+ console.log(`star ${id} joined`);
554
+ }
555
+
556
+ async starLeft(id) {
557
+ if (this.#stars[id]) {
558
+ this.#stars[id].close();
559
+ delete this.#stars[id];
575
560
  }
576
- };
577
-
578
- const peernet = (client) => {
579
- return {
580
- join: async (params) => {
581
- try {
582
- params.join = true;
583
- const requested = { url: 'peernet', params };
584
- const { result, id, handler } = await request(client, requested);
585
- unsubscribe(id, handler);
586
- return result
587
- } catch (e) {
588
- throw e
589
- }
590
- },
591
- leave: async (params) => {
561
+ if (this.socketClient?.peerId === id) {
562
+
563
+ this.socketClient.unsubscribe('peer:joined', this.peerJoined);
564
+ this.socketClient.unsubscribe('peer:left', this.peerLeft);
565
+ this.socketClient.unsubscribe('star:left', this.starLeft);
566
+ this.socketClient.close();
567
+ this.socketClient = undefined;
568
+
569
+ for (const star of this.starsConfig) {
592
570
  try {
593
- params.join = false;
594
- const requested = { url: 'peernet', params };
595
- const { result, id, handler } = await request(client, requested);
596
- unsubscribe(id, handler);
597
- return result
571
+ this.socketClient = await socketRequestClient(star, this.identifiers[0]);
572
+ if (!this.socketClient?.client?._connection.connected) return
573
+ const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
574
+ this.#stars[id] = this.socketClient;
575
+
576
+ this.socketClient.peerId = id;
577
+
578
+ const peers = await this.socketClient.peernet.join({id: this.id});
579
+ this.setupListeners();
580
+ for (const id of peers) {
581
+ if (id !== this.id) {
582
+ // close connection
583
+ if (this.#connections[id]) {
584
+ if (this.#connections[id].connected) await this.#connections[id].close();
585
+ delete this.#connections[id];
586
+ }
587
+ // reconnect
588
+ if (id !== this.id) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id});
589
+ }
590
+
591
+ }
598
592
  } catch (e) {
599
- throw e
593
+ console.log(e);
594
+ if (this.starsConfig.indexOf(star) === this.starsConfig.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
600
595
  }
601
596
  }
602
597
  }
603
- };
604
-
605
- return { send, request, pubsub, server, subscribe, unsubscribe, publish, peernet }
606
- };
607
-
608
- const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry: false, pubsub: false }) => {
609
- let { pubsub, retry } = options;
610
- if (!pubsub) pubsub = new PubSub__default["default"]({verbose: false});
611
-
612
- const api = clientApi(pubsub);
613
-
614
- let tries = 0;
615
-
616
- const onerror = error => {
617
- if (pubsub.subscribers['error']) {
618
- pubsub.publish('error', error);
619
- } else {
620
- console.error(error);
621
- }
622
- };
623
-
624
- const onmessage = message => {
625
- const {value, url, status, id} = JSON.parse(message.data.toString());
626
- const publisher = id ? id : url;
627
- if (status === 200) {
628
- pubsub.publish(publisher, value);
629
- } else {
630
- pubsub.publish(publisher, {error: value});
598
+
599
+ console.log(`star ${id} left`);
600
+
601
+
602
+ }
603
+
604
+ peerLeft(id) {
605
+ if (this.#connections[id]) {
606
+ this.#connections[id].close();
607
+ delete this.#connections[id];
631
608
  }
609
+ console.log(`peer ${id} left`);
610
+ }
632
611
 
633
- };
634
-
635
- const clientConnection = client => {
636
- const startTime = new Date().getTime();
637
- return {
638
- client,
639
- request: async req => {
640
- const { result, id, handler } = await api.request(client, req);
641
- pubsub.unsubscribe(id, handler);
642
- return result
643
- },
644
- send: req => api.send(client, req),
645
- subscribe: api.subscribe,
646
- unsubscribe: api.unsubscribe,
647
- subscribers: api.subscribers,
648
- publish: api.publish,
649
- pubsub: api.pubsub(client),
650
- uptime: () => {
651
- const now = new Date().getTime();
652
- return (now - startTime)
653
- },
654
- peernet: api.peernet(client),
655
- server: api.server(client),
656
- close: exit => {
657
- client.onclose = message => {
658
- if (exit) process.exit();
659
- };
660
- client.close();
661
- }
612
+ peerJoined(id, signal) {
613
+ if (this.#connections[id]) {
614
+ if (this.#connections[id].connected) this.#connections[id].close();
615
+ delete this.#connections[id];
662
616
  }
663
- };
664
-
665
- return new Promise((resolve, reject) => {
666
- const init = () => {
667
- let ws;
668
- if (typeof process === 'object') {
669
- ws = require('websocket').w3cwebsocket;
670
- } else {
671
- ws = WebSocket;
672
- }
673
- const client = new ws(url, protocols);
617
+ // RTCPeerConnection
618
+ this.#connections[id] = new Peer({initiator: true, channelName: `${this.id}:${id}`, socketClient: this.socketClient, id: this.id, to: id});
619
+ console.log(`peer ${id} joined`);
620
+ }
621
+
674
622
 
675
- client.onmessage = onmessage;
676
- client.onerror = onerror;
677
- client.onopen = () => {
678
- tries = 0;
679
- resolve(clientConnection(client));
680
- };
681
- client.onclose = message => {
682
- tries++;
683
- if (!retry) return reject(options)
684
- if (tries > 5) {
685
- console.log(`${protocols} Client Closed`);
686
- console.error(`could not connect to - ${url}/`);
687
- return resolve(clientConnection(client))
688
- }
689
- if (message.code === 1006) {
690
- console.log('Retrying in 10 seconds');
691
- setTimeout(() => {
692
- return init();
693
- }, retry);
694
- }
695
- };
696
- };
697
- return init();
698
- });
699
- };
700
-
701
- class HttpClientApi$1 {
702
- constructor(config = {}) {
703
- if (!config.apiPath) config.apiPath = 'api';
704
-
705
- const address = `ws://${config.host}:${config.port}`;
706
-
707
- this.apiUrl = (url) => `${address}/${url}`;
708
- return (async () => {
709
- this.client = await socketRequestClient(address, config.protocol, {pubsub: config.pubsub, retry: 3000});
710
- return this
711
- })()
712
- }
713
-
714
- async get(url, obj) {
715
- const headers = {};
716
- let body = null;
717
- let method = 'GET';
718
- if (obj) {
719
- method = 'POST';
720
- headers['Content-Type'] = 'application/json';
721
- body = JSON.stringify(obj);
722
- }
723
- let response = await this.client.request(url, {headers, body, method});
724
- const type = response.headers.get('content-type').split(';')[0];
725
- if (type==='application/json') response = await response.json();
726
- return response
727
- }
728
-
729
- async put(url, obj) {
730
- const headers = {};
731
- let body = {};
732
- if (obj) {
733
- headers['Content-Type'] = 'application/json';
734
- body = JSON.stringify(obj);
735
- }
736
-
737
- let response = await fetch(this.apiUrl(url), {method: 'PUT', headers, body});
738
- const type = response.headers.get('content-type').split(';')[0];
739
- if (type==='application/json') response = await response.json();
740
- return response
741
- }
742
- }
743
-
744
- class HttpClientApi extends HttpClientApi$1 {
745
- constructor(config = {}) {
746
- config.apiPath = 'api';
747
- return (async () => {
748
- await super(config);
749
-
750
- this.properties = {
751
- wallet: 'get',
752
- version: 'get',
753
- addresses: 'get',
754
- config: 'get',
755
- account: 'get',
756
- accounts: 'get',
757
- transaction: 'any',
758
- transactions: 'get',
759
- block: 'get',
760
- blocks: 'get',
761
- };
762
- this.keys = Object.keys(this.properties);
763
- return this
764
- })()
765
- }
766
-
767
- async request(url, data) {
768
- return await this.client.request({url, params: data})
769
- }
770
-
771
- async ready() {
772
- return await this.request('ready')
773
- }
774
-
775
- async version() {
776
- return await this.request('version')
777
- }
778
-
779
- async account(index) {
780
- return await this.request('account', {index})
781
- }
782
623
  }
783
624
 
784
- var httpClient = (config = {}) => {
785
- if (typeof config !== 'object') config = {};
786
- if (!config.protocol) config.protocol = 'peernet-v0.1.0';
787
- if (!config.port) config.port = 1000;
788
- if (!config.host) config.host = '127.0.0.1';
789
-
790
- return new HttpClientApi(config)
791
- };
792
-
793
625
  class LeofcoinStorageClient {
794
626
  constructor(name, root) {
795
627
  this.name = name;
@@ -835,19 +667,19 @@ message PeernetDataMessage {
835
667
  }
836
668
  `;
837
669
 
838
- /**
839
- * @extends {CodecFormat}
840
- */
841
- class DataMessage extends codecFormatInterface {
842
- get keys() {
843
- return ['hash', 'store']
844
- }
845
- /**
846
- * @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
847
- */
848
- constructor(data) {
849
- super(data, protons__default["default"](proto$5).PeernetDataMessage, {name: 'peernet-data'});
850
- }
670
+ /**
671
+ * @extends {CodecFormat}
672
+ */
673
+ class DataMessage extends codecFormatInterface {
674
+ get keys() {
675
+ return ['hash', 'store']
676
+ }
677
+ /**
678
+ * @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
679
+ */
680
+ constructor(data) {
681
+ super(data, protons__default["default"](proto$5).PeernetDataMessage, {name: 'peernet-data'});
682
+ }
851
683
  }
852
684
 
853
685
  var proto$4 = `
@@ -857,15 +689,15 @@ message PsMessage {
857
689
  required bytes topic = 2;
858
690
  }`;
859
691
 
860
- class PsMessage extends codecFormatInterface {
861
- get keys() {
862
- return ['data', 'topic']
863
- }
864
-
865
- constructor(buffer) {
866
- const name = 'peernet-ps';
867
- super(buffer, protons__default["default"](proto$4).PsMessage, {name});
868
- }
692
+ class PsMessage extends codecFormatInterface {
693
+ get keys() {
694
+ return ['data', 'topic']
695
+ }
696
+
697
+ constructor(buffer) {
698
+ const name = 'peernet-ps';
699
+ super(buffer, protons__default["default"](proto$4).PsMessage, {name});
700
+ }
869
701
  }
870
702
 
871
703
  var proto$3 = `
@@ -875,15 +707,15 @@ message PeernetPeerMessage {
875
707
  }
876
708
  `;
877
709
 
878
- class PeerMessage extends codecFormatInterface {
879
- get keys() {
880
- return ['id']
881
- }
882
-
883
- constructor(data) {
884
- const name = 'peernet-peer';
885
- super(data, protons__default["default"](proto$3).PeernetPeerMessage, {name});
886
- }
710
+ class PeerMessage extends codecFormatInterface {
711
+ get keys() {
712
+ return ['id']
713
+ }
714
+
715
+ constructor(data) {
716
+ const name = 'peernet-peer';
717
+ super(data, protons__default["default"](proto$3).PeernetPeerMessage, {name});
718
+ }
887
719
  }
888
720
 
889
721
  var proto$2 = `
@@ -893,15 +725,15 @@ message PeernetPeerMessageResponse {
893
725
  }
894
726
  `;
895
727
 
896
- class PeerMessageResponse extends codecFormatInterface {
897
- get keys() {
898
- return ['id']
899
- }
900
-
901
- constructor(data) {
902
- const name = 'peernet-peer-response';
903
- super(data, protons__default["default"](proto$2).PeernetPeerMessageResponse, {name});
904
- }
728
+ class PeerMessageResponse extends codecFormatInterface {
729
+ get keys() {
730
+ return ['id']
731
+ }
732
+
733
+ constructor(data) {
734
+ const name = 'peernet-peer-response';
735
+ super(data, protons__default["default"](proto$2).PeernetPeerMessageResponse, {name});
736
+ }
905
737
  }
906
738
 
907
739
  var proto$1 = `
@@ -912,15 +744,15 @@ message PeernetDataMessageResponse {
912
744
  }
913
745
  `;
914
746
 
915
- class DataMessageResponse extends codecFormatInterface {
916
- get keys() {
917
- return ['hash', 'data']
918
- }
919
-
920
- constructor(data) {
921
- const name = 'peernet-data-response';
922
- super(data, protons__default["default"](proto$1).PeernetDataMessageResponse, {name});
923
- }
747
+ class DataMessageResponse extends codecFormatInterface {
748
+ get keys() {
749
+ return ['hash', 'data']
750
+ }
751
+
752
+ constructor(data) {
753
+ const name = 'peernet-data-response';
754
+ super(data, protons__default["default"](proto$1).PeernetDataMessageResponse, {name});
755
+ }
924
756
  }
925
757
 
926
758
  var proto = `
@@ -931,15 +763,15 @@ message ChatMessage {
931
763
  repeated string files = 4;
932
764
  }`;
933
765
 
934
- class ChatMessage extends codecFormatInterface {
935
- get keys() {
936
- return ['author', 'value', 'timestamp', 'files']
937
- }
938
-
939
- constructor(buffer) {
940
- const name = 'chat-message';
941
- super(buffer, protons__default["default"](proto).ChatMessage, {name});
942
- }
766
+ class ChatMessage extends codecFormatInterface {
767
+ get keys() {
768
+ return ['author', 'value', 'timestamp', 'files']
769
+ }
770
+
771
+ constructor(buffer) {
772
+ const name = 'chat-message';
773
+ super(buffer, protons__default["default"](proto).ChatMessage, {name});
774
+ }
943
775
  }
944
776
 
945
777
  const debug = (log) => {
@@ -1197,93 +1029,441 @@ class DhtEarth {
1197
1029
  }
1198
1030
  }
1199
1031
 
1032
+ var testnets = {
1033
+ 'leofcoin:olivia': {
1034
+ messagePrefix: '\u0019Leofcoin Signed Message:',
1035
+ pubKeyHash: 0x73, // o
1036
+ scriptHash: 0x76, // p
1037
+ multiTxHash: 0x8b4125, // omtx
1038
+ payments: {
1039
+ version: 0,
1040
+ unspent: 0x1fa443d7 // ounsp
1041
+ },
1042
+ wif: 0x7D, // s
1043
+ multiCodec: 0x7c4,
1044
+ bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
1045
+ },
1046
+ 'bitcoin:testnet': {
1047
+ messagePrefix: '\x18Bitcoin Signed Message:\n',
1048
+ bech32: 'tb',
1049
+ pubKeyHash: 0x6f,
1050
+ scriptHash: 0xc4,
1051
+ wif: 0xef,
1052
+ bip32: {
1053
+ public: 0x043587cf,
1054
+ private: 0x04358394
1055
+ }
1056
+ }
1057
+
1058
+ };
1059
+
1060
+ // https://en.bitcoin.it/wiki/List_of_address_prefixes
1200
1061
  /**
1201
- * @params {String} network
1202
- * @return {object} { identity, accounts, config }
1062
+ * Main network
1063
+ * @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
1203
1064
  */
1204
- var generateAccount = async network => {
1205
- const wallet = new MultiWallet__default["default"](network);
1206
- /**
1207
- * @type {string}
1208
- */
1209
- const mnemonic = await wallet.generate();
1210
- /**
1211
- * @type {object}
1212
- */
1213
- const account = wallet.account(0);
1214
- /**
1215
- * @type {object}
1216
- */
1217
- const external = account.external(0);
1218
- const internal = account.internal(0);
1219
-
1220
- return {
1221
- identity: {
1222
- mnemonic,
1223
- multiWIF: wallet.export(),
1224
- publicKey: external.publicKey,
1225
- privateKey: external.privateKey,
1226
- walletId: external.id
1227
- },
1228
- accounts: [['main account', external.address, internal.address]],
1229
- config: {
1230
- miner: {
1231
- intensity: 1,
1232
- address: external.address,
1233
- donationAddress: undefined,
1234
- donationAmount: 1 //percent
1235
- }
1236
- }
1237
- }
1238
- };
1065
+ const leofcoin = {
1066
+ messagePrefix: '\u0019Leofcoin Signed Message:',
1067
+ pubKeyHash: 0x30, // L
1068
+ scriptHash: 0x37, // P
1069
+ multiTxHash: 0x3adeed, // Lmtx
1070
+ payments: {
1071
+ version: 0,
1072
+ unspent: 0x0d6e0327 // Lunsp
1073
+ },
1074
+ coin_type: 640,
1075
+ wif: 0x3F, // S
1076
+ multiCodec: 0x3c4,
1077
+ bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
1078
+ testnet: testnets['leofcoin:olivia']
1079
+ };
1080
+
1081
+ const bitcoin = {
1082
+ messagePrefix: '\x18Bitcoin Signed Message:\n',
1083
+ bech32: 'bc',
1084
+ pubKeyHash: 0x00,
1085
+ scriptHash: 0x05,
1086
+ wif: 0x80,
1087
+ coin_type: 0,
1088
+ bip32: {
1089
+ public: 0x0488b21e, private: 0x0488ade4
1090
+ },
1091
+ testnet: testnets['bitcoin:testnet']
1092
+ };
1093
+
1094
+ const litecoin = {
1095
+ messagePrefix: '\x19Litecoin Signed Message:\n',
1096
+ pubKeyHash: 0x30,
1097
+ scriptHash: 0x32,
1098
+ wif: 0xb0,
1099
+ bip32: {
1100
+ public: 0x019da462,
1101
+ private: 0x019d9cfe
1102
+ }
1103
+ };
1104
+
1105
+ const ethereum = {
1106
+ messagePrefix: '\x19Ethereum Signed Message:\n',
1107
+ pubKeyHash: 0x30,
1108
+ scriptHash: 0x32,
1109
+ bip32: {
1110
+ private: 0x0488ADE4, public: 0x0488B21E
1111
+ },
1112
+ coin_type: 60,
1113
+ wif: 0x45,//E
1114
+ multiCodec: 0x3c5
1115
+ };
1116
+
1117
+ /**
1118
+ * Our & supported networks
1119
+ * @return {leofcoin, olivia}
1120
+ */
1121
+ var networks = {
1122
+ leofcoin,
1123
+ bitcoin,
1124
+ litecoin,
1125
+ ethereum
1126
+ };
1239
1127
 
1240
- class MessageHandler {
1241
- constructor(network) {
1242
- this.network = network;
1243
- }
1244
- /**
1245
- * hash and sign message
1246
- *
1247
- * @param {object} message
1248
- * @param {Buffer} message.from peer id
1249
- * @param {Buffer} message.to peer id
1250
- * @param {string} message.data Peernet message
1251
- * (PeernetMessage excluded) encoded as a string
1252
- * @return signature
1253
- */
1254
- async hashAndSignMessage(message) {
1255
- const hasher = new hash(message, {name: 'peernet-message'});
1256
- const identity = await walletStore.get('identity');
1128
+ const fromNetworkString = network => {
1129
+ const parts = network.split(':');
1130
+ network = networks[parts[0]];
1131
+ if (parts[1]) {
1132
+ if (network[parts[1]]) network = network[parts[1]];
1133
+
1134
+ network.coin_type = 1;
1135
+ }
1136
+ return network;
1137
+ };
1257
1138
 
1258
- const wallet = new MultiWallet__default["default"](this.network);
1259
- wallet.import(identity.multiWIF);
1260
- return wallet.sign(hasher.hash.slice(0, 32))
1261
- }
1139
+ const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
1140
+ class HDWallet {
1141
+
1142
+ get chainCodeBuffer() {
1143
+ return this.ifNotLocked(() => this.hdnode.chainCode)
1144
+ }
1145
+
1146
+ get chainCode() {
1147
+ return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
1148
+ }
1149
+
1150
+ get privateKeyBuffer() {
1151
+ return this.ifNotLocked(() => this.hdnode.privateKey)
1152
+ }
1153
+
1154
+ get privateKey() {
1155
+ return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
1156
+ }
1157
+
1158
+ get publicKeyBuffer() {
1159
+ return this.ifNotLocked(() => this.hdnode.publicKey)
1160
+ }
1161
+
1162
+ get publicKey() {
1163
+ return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
1164
+ }
1165
+
1166
+ get address() {
1167
+ // override testnet coin_type
1168
+ let coin_type = this.hdnode.network.coin_type;
1169
+ if (coin_type === 1) {
1170
+ if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
1171
+ if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
1172
+ }
1173
+ if (coin_type === 60 || coin_type === 640) {
1174
+ let buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1175
+ buffer = Buffer.from(secp256k1.publicKeyConvert(buffer, false)).slice(1);
1176
+ let hash = createKeccakHash__default["default"]('keccak256').update(buffer).digest();
1177
+ return hash.slice(-20).toString('hex')
1178
+ }
1179
+ return encode$1(this.neutered.publicKeyBuffer)
1180
+ }
1181
+
1182
+ get accountAddress() {
1183
+ return this.ifNotLocked(() => encode$1(this.hdnode.publicKeyBuffer))
1184
+ }
1185
+
1186
+ get isTestnet() {
1187
+ if (typeof network === 'string')
1188
+ this.hdnode.network = fromNetworkString(network);
1189
+
1190
+ return Boolean(this.hdnode.network.coin_type === 1)
1191
+ }
1192
+
1193
+ constructor(network, hdnode) {
1194
+ if (typeof network === 'string') {
1195
+ this.networkName = network;
1196
+ this.network = fromNetworkString(network);
1197
+ } else if (typeof network === 'object')
1198
+ this.network = network;
1199
+
1200
+ if (hdnode) this.defineHDNode(hdnode);
1201
+ }
1202
+
1203
+ ifNotLocked(fn, params) {
1204
+ if (!this.locked) return fn(params);
1205
+ return null
1206
+ }
1207
+
1208
+ defineHDNode(value) {
1209
+ Object.defineProperty(this, 'hdnode', {
1210
+ configurable: false,
1211
+ writable: false,
1212
+ value: value
1213
+ });
1214
+ }
1215
+
1216
+ validateNetwork(network) {
1217
+ if (!network && !this.network) return console.error(`expected network to be defined`);
1218
+ if (!network && this.network) network = this.network;
1219
+ if (typeof network === 'string') network = fromNetworkString(network);
1220
+ if (typeof network !== 'object') return console.error('network not found');
1221
+ return network;
1222
+ }
1223
+
1224
+ async generate(network) {
1225
+ network = this.validateNetwork(network);
1226
+ const mnemonic = bip39.generateMnemonic();
1227
+ const seed = await bip39.mnemonicToSeed(mnemonic);
1228
+ this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1229
+ return mnemonic; // userpw
1230
+ }
1231
+
1232
+ /**
1233
+ * recover using mnemonic (recovery word list)
1234
+ */
1235
+ async recover(mnemonic, network) {
1236
+ network = this.validateNetwork(network);
1237
+ const seed = await bip39.mnemonicToSeed(mnemonic);
1238
+ this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1239
+ }
1240
+
1241
+ load(base58, network) {
1242
+ network = this.validateNetwork(network);
1243
+ this.defineHDNode(bip32__namespace.fromBase58(base58, network));
1244
+ }
1245
+
1246
+ save() {
1247
+ return this.hdnode.toBase58();
1248
+ }
1249
+
1250
+ fromAddress(address, chainCode, network) {
1251
+ network = this.validateNetwork(network);
1252
+ // if (network.coin_type === 60) {
1253
+ // address = Buffer.from(address, 'hex')
1254
+ // } else {
1255
+ address = decode$1(address);
1256
+ // }
1257
+
1258
+ if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
1259
+ this.defineHDNode(bip32__namespace.fromPublicKey(address, chainCode, network));
1260
+ }
1261
+
1262
+ fromPublicKey(hex, chainCode, network) {
1263
+ network = this.validateNetwork(network);
1264
+ if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
1265
+ if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
1266
+ this.defineHDNode(bip32__namespace.fromPublicKey(hex, chainCode, network));
1267
+ }
1268
+ }
1262
1269
 
1263
- /**
1264
- * @param {String} from - peer id
1265
- * @param {String} to - peer id
1266
- * @param {String|PeernetMessage} data - data encoded message string
1267
- * or the messageNode itself
1268
- */
1269
- async prepareMessage(from, to, data) {
1270
- if (!Buffer.isBuffer(from)) from = new Buffer.from(from);
1271
- if (!Buffer.isBuffer(to)) to = new Buffer.from(to);
1272
- if (data.encoded) data = data.encoded;
1273
-
1274
- const message = {
1275
- from,
1276
- to,
1277
- data,
1278
- };
1279
- const signature = await this.hashAndSignMessage(message);
1280
- const node = new peernetMessage({
1281
- ...message,
1282
- signature,
1283
- });
1270
+ const { encode, decode } = bs58check__namespace;
1271
+
1272
+ // TODO: multihash addresses
1273
+ class HDAccount {
1274
+ /**
1275
+ * @param {number} depth - acount depth
1276
+ */
1277
+ constructor(node, depth = 0) {
1278
+ this.node = node;
1279
+ this.depth = depth;
1280
+ this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
1281
+ }
1282
+
1283
+ /**
1284
+ * @param {number} index - address index
1285
+ */
1286
+ internal(index = 0) {
1287
+ return this.node.derivePath(`${this._prefix}1/${index}`)
1288
+ }
1289
+
1290
+ /**
1291
+ * @param {number} index - address index
1292
+ */
1293
+ external(index = 0) {
1294
+ return this.node.derivePath(`${this._prefix}0/${index}`)
1295
+ }
1296
+ }
1297
+
1298
+ class MultiWallet extends HDWallet {
1299
+ constructor(network, hdnode) {
1300
+ const networkName = network;
1301
+ super(network, hdnode);
1302
+ if (typeof networkName === 'string') this.networkName = networkName;
1303
+ this.multiCodec = this.network.multiCodec;
1304
+ this.version = 0x00;
1305
+ }
1306
+
1307
+ get id() {
1308
+ const buffer = Buffer.concat([
1309
+ Buffer.from(varint__default["default"].encode(this.multiCodec)),
1310
+ Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
1311
+ ]);
1312
+ return encode(buffer)
1313
+ }
1314
+
1315
+ get multiWIF() {
1316
+ return this.ifNotLocked(() => this.encode())
1317
+ }
1318
+
1319
+ get neutered() {
1320
+ const neutered = this.ifNotLocked(() => new MultiWallet(this.network, this.hdnode.neutered()));
1321
+ if (neutered) this._neutered = neutered;
1322
+ return this._neutered
1323
+ }
1324
+
1325
+ fromId(id) {
1326
+ let buffer = decode(id);
1327
+ varint__default["default"].decode(buffer);
1328
+ buffer = buffer.slice(varint__default["default"].decode.bytes);
1329
+ this.fromPublicKey(buffer, null, this.network);
1330
+ }
1331
+
1332
+ lock(key, multiWIF) {
1333
+ if (!multiWIF) multiWIF = this.multiWIF;
1334
+ this.encrypted = AES__default["default"].encrypt(multiWIF.toString('hex'), key).toString();
1335
+ this.locked = true;
1336
+ }
1337
+
1338
+ unlock(key, encrypted) {
1339
+ if (!encrypted) encrypted = this.encrypted;
1340
+ this.import(AES__default["default"].decrypt(encrypted, key).toString(ENC__default["default"]));
1341
+ this.locked = false;
1342
+ }
1343
+
1344
+ export() {
1345
+ return this.encode();
1346
+ }
1347
+
1348
+ /**
1349
+ * encodes the multiWIF and loads wallet from bs58
1350
+ *
1351
+ * @param {multiWIF} multiWIF - note a multiWIF is not the same as a wif
1352
+ */
1353
+ import(multiWIF) {
1354
+ const { bs58, version, multiCodec } = this.decode(multiWIF);
1355
+ this.network = Object.values(networks).reduce((p, c) => {
1356
+ if (c.multiCodec===multiCodec) return c
1357
+ else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
1358
+ else return p
1359
+ }, networks['leofcoin']);
1360
+ this.load(bs58, this.network);
1361
+ }
1362
+
1363
+ /**
1364
+ * @return base58Check encoded string
1365
+ */
1366
+ encode() {
1367
+ const buffer = Buffer.concat([
1368
+ Buffer.from(varint__default["default"].encode(this.version)),
1369
+ Buffer.from(varint__default["default"].encode(this.multiCodec)),
1370
+ decode(this.save())
1371
+ ]);
1372
+ return encode(buffer);
1373
+ }
1374
+
1375
+ decode(bs58) {
1376
+ let buffer = decode(bs58);
1377
+ const version = varint__default["default"].decode(buffer);
1378
+ buffer = buffer.slice(varint__default["default"].decode.bytes);
1379
+ const multiCodec = varint__default["default"].decode(buffer);
1380
+ buffer = buffer.slice(varint__default["default"].decode.bytes);
1381
+ bs58 = encode(buffer);
1382
+ if (version !== this.version) throw TypeError('Invalid version');
1383
+ if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
1384
+ return { version, multiCodec, bs58 };
1385
+ }
1386
+
1387
+ sign(hash) {
1388
+ return new MultiSignature__default["default"](this.version, this.network.multiCodec)
1389
+ .sign(hash, this.privateKeyBuffer);
1390
+
1391
+ }
1392
+
1393
+ verify(multiSignature, hash) {
1394
+ return new MultiSignature__default["default"](this.version, this.network.multiCodec)
1395
+ .verify(multiSignature, hash, this.publicKeyBuffer)
1396
+ }
1397
+
1398
+ /**
1399
+ * @param {number} account - account to return chain for
1400
+ * @return { internal(addressIndex), external(addressIndex) }
1401
+ */
1402
+ account(index) {
1403
+ return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
1404
+ }
1405
+
1406
+ /**
1407
+ * m / purpose' / coin_type' / account' / change / aadress_index
1408
+ *
1409
+ * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1410
+ */
1411
+ derivePath(path) {
1412
+ return new MultiWallet(this.network, this.hdnode.derivePath(path))
1413
+ }
1414
+
1415
+ derive(index) {
1416
+ return new MultiWallet(this.network, this.hdnode.derive(index));
1417
+ }
1418
+ }
1284
1419
 
1285
- return node
1286
- }
1420
+ class MessageHandler {
1421
+ constructor(network) {
1422
+ this.network = network;
1423
+ }
1424
+ /**
1425
+ * hash and sign message
1426
+ *
1427
+ * @param {object} message
1428
+ * @param {Buffer} message.from peer id
1429
+ * @param {Buffer} message.to peer id
1430
+ * @param {string} message.data Peernet message
1431
+ * (PeernetMessage excluded) encoded as a string
1432
+ * @return signature
1433
+ */
1434
+ async hashAndSignMessage(message) {
1435
+ const hasher = new hash(message, {name: 'peernet-message'});
1436
+ const identity = await walletStore.get('identity');
1437
+
1438
+ const wallet = new MultiWallet(this.network);
1439
+ wallet.import(identity.multiWIF);
1440
+ return wallet.sign(hasher.hash.slice(0, 32))
1441
+ }
1442
+
1443
+ /**
1444
+ * @param {String} from - peer id
1445
+ * @param {String} to - peer id
1446
+ * @param {String|PeernetMessage} data - data encoded message string
1447
+ * or the messageNode itself
1448
+ */
1449
+ async prepareMessage(from, to, data, id) {
1450
+ if (!Buffer.isBuffer(from)) from = new Buffer.from(from);
1451
+ if (!Buffer.isBuffer(to)) to = new Buffer.from(to);
1452
+ if (data.encoded) data = data.encoded;
1453
+
1454
+ const message = {
1455
+ from,
1456
+ to,
1457
+ data,
1458
+ };
1459
+ const signature = await this.hashAndSignMessage(message);
1460
+ const node = new peernetMessage({
1461
+ ...message,
1462
+ signature,
1463
+ });
1464
+
1465
+ return node
1466
+ }
1287
1467
  }
1288
1468
 
1289
1469
  const encapsulatedError = () => {
@@ -1300,7 +1480,7 @@ const nothingFoundError = (hash) => {
1300
1480
  };
1301
1481
 
1302
1482
  globalThis.leofcoin = globalThis.leofcoin || {};
1303
- globalThis.globalSub = globalThis.globalSub || new PubSub__default["default"]({verbose: true});
1483
+ globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
1304
1484
 
1305
1485
  /**
1306
1486
  * @access public
@@ -1445,12 +1625,14 @@ class Peernet {
1445
1625
  this.hasDaemon = daemon;
1446
1626
 
1447
1627
  if (this.hasDaemon) {
1448
- globalThis.peernet.client = await httpClient({
1449
- protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port,
1450
- });
1451
- } else {
1452
- if (environment !== 'browser') http(options);
1453
- }
1628
+ const httpClient = await Promise.resolve().then(function () { return require('./client-bd0caeb7.js'); });
1629
+ globalThis.peernet.client = await httpClient.default({
1630
+ protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port
1631
+ });
1632
+ } else {
1633
+ const http = await Promise.resolve().then(function () { return require('./http-2b0735ef.js'); });
1634
+ if (environment !== 'browser') http.default(options);
1635
+ }
1454
1636
 
1455
1637
  for (const store of this.defaultStores) {
1456
1638
  await this.addStore(store, options.storePrefix, options.root);
@@ -1462,7 +1644,7 @@ class Peernet {
1462
1644
  } catch (e) {
1463
1645
  if (e.code === 'ERR_NOT_FOUND') {
1464
1646
  const wallet = {};
1465
- const {identity, accounts, config} = await generateAccount(this.network);
1647
+ const {identity, accounts, config} = await generateAccount__default["default"](this.network);
1466
1648
  wallet.identity = identity;
1467
1649
  wallet.accounts = accounts;
1468
1650
  wallet.version = 1;
@@ -1476,42 +1658,41 @@ class Peernet {
1476
1658
  }
1477
1659
  }
1478
1660
  this._peerHandler = new PeerDiscovery(this.id);
1479
- // peernet id
1480
- const id = Buffer.from(this.id.slice(0, 32));
1481
- this.peerId = id;
1482
-
1483
- pubsub.subscribe('peer:discovered', async (peer) => {
1484
- peer.on('peernet.data', async (message) => {
1485
- const id = message.id;
1486
- message = new peernetMessage(Buffer.from(message.data.data));
1487
- const proto = protoFor(message.decoded.data);
1488
- await this._protoHandler({id, proto}, peer);
1489
- });
1490
- await this._peerHandler.discover(peer);
1491
- const fulldId = this._getPeerId(peer.id);
1492
- if (fulldId && this._discovered.indexOf(peer.id) === -1) {
1493
- this._discovered.push(peer.id);
1494
- pubsub.publish('peer:connected', peer);
1495
- }
1496
- });
1497
- pubsub.subscribe('peer:disconnected', async (peer) => {
1498
- let index = this._discovered.indexOf(peer.id);
1499
- if (index !== -1) this._discovered.splice(index, 1);
1500
- const id = this._getPeerId(peer.id);
1501
- let peerIds = this.peerMap.get(id);
1502
-
1503
- if (peerIds) {
1504
- index = peerIds.indexOf(peer.id);
1505
- if (index !== -1) peerIds.splice(index, 1);
1506
- } else {
1507
- peerIds = [];
1508
- }
1509
-
1510
- if (peerIds.length === 0) this.peerMap.delete(id);
1511
- else this.peerMap.set(id, peerIds);
1512
- });
1661
+ this.peerId = this.id;
1662
+
1663
+ // pubsub.subscribe('peer:discovered', async (peer) => {
1664
+ // peer.on('peernet.data', async (message) => {
1665
+ // const id = message.id;
1666
+ // message = new PeernetMessage(Buffer.from(message.data.data));
1667
+ // const proto = protoFor(message.decoded.data);
1668
+ // await this._protoHandler({id, proto}, peer);
1669
+ // });
1670
+ // await this._peerHandler.discover(peer);
1671
+ // const fulldId = this._getPeerId(peer.id);
1672
+ // if (fulldId && this._discovered.indexOf(peer.id) === -1) {
1673
+ // this._discovered.push(peer.id);
1674
+ // pubsub.publish('peer:connected', peer);
1675
+ // }
1676
+ // });
1677
+ // pubsub.subscribe('peer:disconnected', async (peer) => {
1678
+ // let index = this._discovered.indexOf(peer.id)
1679
+ // if (index !== -1) this._discovered.splice(index, 1)
1680
+ // const id = this._getPeerId(peer.id)
1681
+ // let peerIds = this.peerMap.get(id)
1682
+ //
1683
+ // if (peerIds) {
1684
+ // index = peerIds.indexOf(peer.id)
1685
+ // if (index !== -1) peerIds.splice(index, 1)
1686
+ // } else {
1687
+ // peerIds = []
1688
+ // }
1689
+ //
1690
+ // if (peerIds.length === 0) this.peerMap.delete(id)
1691
+ // else this.peerMap.set(id, peerIds)
1692
+ // })
1513
1693
  pubsub.subscribe('peer:connected', async (peer) => {
1514
- console.log({connected: peer.id, as: this._getPeerId(peer.id) });
1694
+ console.log(peer);
1695
+ // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
1515
1696
  // peer.on('peernet.data', async (message) => {
1516
1697
  // const id = message.id
1517
1698
  // message = new PeernetMessage(Buffer.from(message.data.data))
@@ -1520,11 +1701,27 @@ class Peernet {
1520
1701
  // })
1521
1702
  });
1522
1703
 
1704
+ pubsub.subscribe('peer:data', async message => {
1705
+ console.log({message});
1706
+ if (!message.data) return
1707
+ const {id, data} = JSON.parse(new TextDecoder().decode(message.data));
1708
+ const uint8Array = new Uint8Array(Object.keys(data).length);
1709
+ for (var i = 0; i < Object.keys(data).length; i++) {
1710
+ uint8Array[i] = data[i];
1711
+ }
1712
+ message = new peernetMessage(uint8Array);
1713
+ const proto = protoFor(message.decoded.data);
1714
+
1715
+ console.log(message.decoded);
1716
+ const from = new TextDecoder().decode(message.decoded.from);
1717
+ this._protoHandler({id, proto}, this.client.connections[from], from);
1718
+ });
1719
+
1523
1720
  /**
1524
1721
  * @access public
1525
1722
  * @type {PeernetClient}
1526
1723
  */
1527
- this.client = new PeernetClient({...options, id});
1724
+ this.client = new Client(this.id);
1528
1725
  if (globalThis.onbeforeunload) {
1529
1726
  globalThis.addEventListener('beforeunload', async () => this.client.close());
1530
1727
  }
@@ -1549,55 +1746,56 @@ class Peernet {
1549
1746
  * @param {Buffer} message - peernet message
1550
1747
  * @param {PeernetPeer} peer - peernet peer
1551
1748
  */
1552
- async _protoHandler(message, peer) {
1749
+ async _protoHandler(message, peer, from) {
1553
1750
  const {id, proto} = message;
1751
+ console.log(message);
1554
1752
  this.bw.down += proto.encoded.length;
1555
- if (proto.name === 'peernet-peer') {
1556
- const from = proto.decoded.id;
1557
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
1558
- else {
1559
- const connections = this.peerMap.get(from);
1560
- if (connections.indexOf(peer.id) === -1) {
1561
- connections.push(peer.id);
1562
- this.peerMap.set(from, connections);
1563
- }
1564
- }
1565
- const data = new PeerMessageResponse({id: this.id});
1566
- const node = await this.prepareMessage(from, data.encoded);
1567
-
1568
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1569
- this.bw.up += node.encoded.length;
1570
- } else if (proto.name === 'peernet-peer-response') {
1571
- const from = proto.decoded.id;
1572
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
1573
- else {
1574
- const connections = this.peerMap.get(from);
1575
- if (connections.indexOf(peer.id) === -1) {
1576
- connections.push(peer.id);
1577
- this.peerMap.set(from, connections);
1578
- }
1579
- }
1580
- } else {
1581
- let from = this._getPeerId(peer.id);
1582
- if (!from) {
1583
- const data = new PeerMessage({id: this.id});
1584
- const node = await this.prepareMessage(peer.id, data.encoded);
1585
- this.bw.up += node.encoded.length;
1586
- let response = await peer.request(node.encoded);
1587
- response = protoFor(response);
1588
-
1589
- response = new PeerMessageResponse(response.decoded.data);
1590
-
1591
- from = response.decoded.id;
1592
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
1593
- else {
1594
- const connections = this.peerMap.get(from);
1595
- if (connections.indexOf(peer.id) === -1) {
1596
- connections.push(peer.id);
1597
- this.peerMap.set(from, connections);
1598
- }
1599
- }
1600
- }
1753
+ // if (proto.name === 'peernet-peer') {
1754
+ // const from = proto.decoded.id
1755
+ // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
1756
+ // else {
1757
+ // const connections = this.peerMap.get(from)
1758
+ // if (connections.indexOf(peer.id) === -1) {
1759
+ // connections.push(peer.id)
1760
+ // this.peerMap.set(from, connections)
1761
+ // }
1762
+ // }
1763
+ // const data = new PeerMessageResponse({id: this.id})
1764
+ // const node = await this.prepareMessage(from, data.encoded)
1765
+ //
1766
+ // peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})))
1767
+ // this.bw.up += node.encoded.length
1768
+ // } else if (proto.name === 'peernet-peer-response') {
1769
+ // const from = proto.decoded.id
1770
+ // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
1771
+ // else {
1772
+ // const connections = this.peerMap.get(from)
1773
+ // if (connections.indexOf(peer.id) === -1) {
1774
+ // connections.push(peer.id)
1775
+ // this.peerMap.set(from, connections)
1776
+ // }
1777
+ // }
1778
+ // } else {
1779
+ // let from = this._getPeerId(peer.id)
1780
+ // if (!from) {
1781
+ // const data = new PeerMessage({id: this.id})
1782
+ // const node = await this.prepareMessage(peer.id, data.encoded)
1783
+ // this.bw.up += node.encoded.length
1784
+ // let response = await peer.request(node.encoded)
1785
+ // response = protoFor(response)
1786
+ //
1787
+ // response = new PeerMessageResponse(response.decoded.data)
1788
+ //
1789
+ // from = response.decoded.id
1790
+ // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
1791
+ // else {
1792
+ // const connections = this.peerMap.get(from)
1793
+ // if (connections.indexOf(peer.id) === -1) {
1794
+ // connections.push(peer.id)
1795
+ // this.peerMap.set(from, connections)
1796
+ // }
1797
+ // }
1798
+ // }
1601
1799
  if (proto.name === 'peernet-dht') {
1602
1800
  let { hash, store } = proto.decoded;
1603
1801
  let has;
@@ -1612,7 +1810,7 @@ class Peernet {
1612
1810
  const data = new dhtResponse({hash, has});
1613
1811
  const node = await this.prepareMessage(from, data.encoded);
1614
1812
 
1615
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1813
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
1616
1814
  this.bw.up += node.encoded.length;
1617
1815
  } else if (proto.name === 'peernet-data') {
1618
1816
  let { hash, store } = proto.decoded;
@@ -1629,7 +1827,7 @@ class Peernet {
1629
1827
  data = new DataMessageResponse({hash, data: data.decoded ? Buffer.from(JSON.stringify(data)) : Buffer.from(data)});
1630
1828
 
1631
1829
  const node = await this.prepareMessage(from, data.encoded);
1632
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1830
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
1633
1831
  this.bw.up += node.encoded.length;
1634
1832
  }
1635
1833
  }
@@ -1645,7 +1843,7 @@ class Peernet {
1645
1843
  const data = new PeerMessage({id: this.id});
1646
1844
  const node = await this.prepareMessage(from, data.encoded);
1647
1845
 
1648
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1846
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
1649
1847
  this.bw.up += node.encoded.length;
1650
1848
  } else if (proto.name === 'peernet-request') {
1651
1849
  // TODO: make dynamic
@@ -1654,14 +1852,14 @@ class Peernet {
1654
1852
  if (method) {
1655
1853
  const data = await method();
1656
1854
  const node = await this.prepareMessage(from, data.encoded);
1657
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1855
+ peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1658
1856
  this.bw.up += node.encoded.length;
1659
1857
  }
1660
1858
  } else if (proto.name === 'peernet-ps' &&
1661
1859
  this._getPeerId(peer.id) !== this.id.toString()) {
1662
1860
  globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
1663
1861
  }
1664
- }
1862
+ // }
1665
1863
  }
1666
1864
 
1667
1865
  /**
@@ -1926,7 +2124,7 @@ class Peernet {
1926
2124
  if (peer.connection._connected) {
1927
2125
  if (peer.id.toString() !== this.peerId.toString()) {
1928
2126
  const node = await this.prepareMessage(peer.id, data.encoded);
1929
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2127
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
1930
2128
  }
1931
2129
  } else {
1932
2130
  this.removePeer(peer);