@leofcoin/peernet 0.10.6 → 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.
- package/LICENSE +1 -1
- package/README.md +49 -49
- package/dist/browser/peernet.js +101814 -92947
- package/dist/commonjs/client-bd0caeb7.js +324 -0
- package/dist/commonjs/{codec-6367213c.js → codec-4a768e5e.js} +99 -89
- package/dist/commonjs/codec-format-interface.js +41 -24
- package/dist/commonjs/codec.js +3 -3
- package/dist/commonjs/dht-response.js +3 -3
- package/dist/commonjs/dht.js +23 -23
- package/dist/commonjs/hash.js +17 -7
- package/dist/commonjs/{http-42a6e555.js → http-2b0735ef.js} +19 -15
- package/dist/commonjs/peernet-message.js +12 -12
- package/dist/commonjs/peernet.js +1164 -966
- package/dist/commonjs/request.js +12 -12
- package/dist/commonjs/response.js +12 -12
- package/dist/module/peernet.js +1325 -1120
- package/index.html +4 -6
- package/package.json +31 -7
- package/rollup.config.js +33 -5
- package/rollup0.config.js +7 -0
- package/src/codec/codec-format-interface.js +40 -23
- package/src/codec/codec.js +21 -11
- package/src/codec/codecs.js +79 -79
- package/src/handlers/message.js +52 -52
- package/src/hash/hash.js +16 -6
- package/src/http/client/http-client.js +1 -1
- package/src/messages/chat-message.js +14 -14
- package/src/messages/data-response.js +14 -14
- package/src/messages/data.js +18 -18
- package/src/messages/dht-response.js +0 -1
- package/src/messages/dht.js +25 -25
- package/src/messages/peer-response.js +14 -14
- package/src/messages/peer.js +14 -14
- package/src/messages/peernet-message.js +14 -14
- package/src/messages/ps.js +14 -14
- package/src/messages/request.js +14 -14
- package/src/messages/response.js +14 -14
- package/src/peernet.js +31 -116
- package/test/codec.js +3 -2
- package/test/messages.js +7 -4
- package/test.js +11 -4
- package/webpack.config.js +35 -0
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -79
- package/coverage/lcov-report/codec-format-interface.js.html +0 -533
- package/coverage/lcov-report/codec.js.html +0 -677
- package/coverage/lcov-report/dht-response.js.html +0 -188
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/hash.js.html +0 -551
- package/coverage/lcov-report/index.html +0 -156
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -170
- package/coverage/lcov.info +0 -459
- package/debug.log +0 -3
- package/dist/browser/peernet.js.tmp-browserify-14074318104595318069 +0 -0
- package/dist/browser/peernet.js.tmp-browserify-45407634493269122267 +0 -0
- package/dist/browser/peernet.js.tmp-browserify-53722389064799025427 +0 -0
- package/dist/browser/peernet.js.tmp-browserify-96323030449218949300 +0 -0
- package/dist/codec/codec-format-interface.js +0 -433
- package/dist/codec/codec.js +0 -199
- package/dist/commonjs/codec-73adfc0f.js +0 -205
- package/dist/commonjs/http-2c603501.js +0 -324
- package/dist/commonjs/http-43f4fafe.js +0 -324
- package/dist/commonjs/http-a94c5a81.js +0 -324
- package/dist/commonjs/peernet-message-b6925673.js +0 -32
- package/dist/hash/hash.js +0 -340
- package/dist/messages/dht-response.js +0 -454
- package/dist/messages/dht.js +0 -453
- package/dist/messages/peernet.js +0 -456
- package/dist/module/http-273664bd.js +0 -317
- package/dist/module/http-8fe3c0d7.js +0 -317
- package/dist/module/http-c780c991.js +0 -317
- package/dist/module/http-f13e0d77.js +0 -317
package/dist/module/peernet.js
CHANGED
|
@@ -1,774 +1,584 @@
|
|
|
1
|
-
import
|
|
2
|
-
import sha256 from 'crypto-js/sha256';
|
|
3
|
-
import P2P from 'p2pt';
|
|
4
|
-
import LeofcoinStorage$1 from '@leofcoin/storage';
|
|
5
|
-
import { server } from 'websocket';
|
|
6
|
-
import { createServer } from 'http';
|
|
7
|
-
import Koa from 'koa';
|
|
1
|
+
import LeofcoinStorage from '@leofcoin/storage';
|
|
8
2
|
import protons from 'protons';
|
|
9
|
-
import bs32 from '
|
|
10
|
-
import bs58 from '
|
|
3
|
+
import bs32 from '@vandeurenglenn/base32';
|
|
4
|
+
import bs58 from '@vandeurenglenn/base58';
|
|
11
5
|
import isHex from 'is-hex';
|
|
12
6
|
import varint from 'varint';
|
|
13
7
|
import createKeccakHash from 'keccak';
|
|
14
|
-
import fetch
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
resolve(message.data);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
pubsub.subscribe('peernet.data', _onData);
|
|
44
|
-
|
|
45
|
-
// cleanup subscriptions
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
pubsub.unsubscribe('peernet.data', _onData);
|
|
48
|
-
}, 5000);
|
|
49
|
-
|
|
50
|
-
this.write(data);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
write(data) {
|
|
55
|
-
if (!Buffer.isBuffer(data)) data = Buffer.from(data);
|
|
56
|
-
|
|
57
|
-
this.bw.up += data.length;
|
|
58
|
-
this.connection.write(data);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
on(event = 'peernet.data', cb) {
|
|
62
|
-
this._events[event] = cb;
|
|
63
|
-
pubsub.subscribe(event, cb);
|
|
64
|
-
// this.connection.on(event, cb)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
removeListener(event = 'data', cb) {
|
|
68
|
-
delete this._events[event];
|
|
69
|
-
pubsub.unsubscribe(event, cb);
|
|
8
|
+
import fetch from 'node-fetch';
|
|
9
|
+
import generateAccount from '@leofcoin/generate-account';
|
|
10
|
+
import * as bs58check from 'bs58check';
|
|
11
|
+
import bs58check__default from 'bs58check';
|
|
12
|
+
import { generateMnemonic, mnemonicToSeed } from 'bip39';
|
|
13
|
+
import * as bip32 from 'bip32';
|
|
14
|
+
import { publicKeyConvert } from 'secp256k1';
|
|
15
|
+
import ecc from 'tiny-secp256k1';
|
|
16
|
+
import MultiSignature from 'multi-signature';
|
|
17
|
+
import AES from 'crypto-js/aes.js';
|
|
18
|
+
import 'crypto-js/sha512.js';
|
|
19
|
+
import ENC from 'crypto-js/enc-utf8.js';
|
|
20
|
+
|
|
21
|
+
/* socket-request-client version 1.6.1 */
|
|
22
|
+
|
|
23
|
+
class LittlePubSub {
|
|
24
|
+
constructor(verbose = true) {
|
|
25
|
+
this.subscribers = {};
|
|
26
|
+
this.verbose = verbose;
|
|
27
|
+
}
|
|
28
|
+
subscribe(event, handler, context) {
|
|
29
|
+
if (typeof context === 'undefined') {
|
|
30
|
+
context = handler;
|
|
31
|
+
}
|
|
32
|
+
this.subscribers[event] = this.subscribers[event] || { handlers: [], value: null};
|
|
33
|
+
this.subscribers[event].handlers.push(handler.bind(context));
|
|
70
34
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
pubsub.unsubscribe(event, this._events[event]);
|
|
35
|
+
unsubscribe(event, handler, context) {
|
|
36
|
+
if (typeof context === 'undefined') {
|
|
37
|
+
context = handler;
|
|
75
38
|
}
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.
|
|
39
|
+
if (this.subscribers[event]) {
|
|
40
|
+
const index = this.subscribers[event].handlers.indexOf(handler.bind(context));
|
|
41
|
+
this.subscribers[event].handlers.splice(index);
|
|
42
|
+
if (this.subscribers[event].handlers.length === 0) delete this.subscribers[event];
|
|
80
43
|
}
|
|
81
|
-
this.connection.destroy();
|
|
82
44
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
globalThis.connections = new Map();
|
|
91
|
-
globalThis.recentConnections = new Map();
|
|
92
|
-
globalThis.pubsub = globalThis.pubsub || new PubSub({verbose: false});
|
|
93
|
-
|
|
94
|
-
class PeernetClient {
|
|
95
|
-
constructor(options = {}) {
|
|
96
|
-
if (!options.id) options.id = Buffer.from('00000000000000000000000000000000');
|
|
97
|
-
if (!options.networkVersion) options.networkVersion = 'v0.1.0';
|
|
98
|
-
if (!options.networkName) options.networkName = 'peernet';
|
|
99
|
-
this.id = options.id;
|
|
100
|
-
|
|
101
|
-
this.topic = Buffer.from(sha256(`${options.networkName}-${options.networkVersion}`).toString());
|
|
102
|
-
|
|
103
|
-
const trackers = [
|
|
104
|
-
'wss://star.leofcoin.org',
|
|
105
|
-
'wss://tracker.openwebtorrent.com',
|
|
106
|
-
// 'wss://tracker.sloppyta.co:443/announce',
|
|
107
|
-
];
|
|
108
|
-
this.p2p = new P2P(trackers, this.topic.slice(0, 20));
|
|
109
|
-
this.p2p.on('peerconnect', (peer) => {
|
|
110
|
-
peer = new PeernetPeer(peer.id, peer);
|
|
111
|
-
connections.set(peer.id, peer);
|
|
112
|
-
pubsub.publish('peer:discovered', peer);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.p2p.on('peerclose', (peer) => {
|
|
116
|
-
// TODO: close peernetPeer
|
|
117
|
-
const peernetPeer = connections.get(peer.id);
|
|
118
|
-
if (peernetPeer) {
|
|
119
|
-
peernetPeer.close();
|
|
45
|
+
publish(event, change) {
|
|
46
|
+
if (this.subscribers[event]) {
|
|
47
|
+
if (this.verbose || this.subscribers[event].value !== change) {
|
|
48
|
+
this.subscribers[event].value = change;
|
|
49
|
+
this.subscribers[event].handlers.forEach(handler => {
|
|
50
|
+
handler(change, this.subscribers[event].value);
|
|
51
|
+
});
|
|
120
52
|
}
|
|
121
|
-
connections.delete(peer.id);
|
|
122
|
-
pubsub.publish('peer:disconnected', peer);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
this.p2p.start();
|
|
126
|
-
|
|
127
|
-
if (globalThis.process) {
|
|
128
|
-
process.on('SIGINT', async () => {
|
|
129
|
-
console.log('Caught interrupt signal');
|
|
130
|
-
this.close();
|
|
131
|
-
setTimeout(async () => {
|
|
132
|
-
process.exit();
|
|
133
|
-
}, 100);
|
|
134
|
-
});
|
|
135
|
-
} else {
|
|
136
|
-
globalThis.onbeforeunload = () => {
|
|
137
|
-
this.close();
|
|
138
|
-
};
|
|
139
53
|
}
|
|
140
|
-
//
|
|
141
|
-
// this.sw.on('close', () => {
|
|
142
|
-
// })
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
close() {
|
|
146
|
-
return this.p2p.destroy()
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
_peers() {
|
|
150
|
-
return this.p2p.getPeers()
|
|
151
54
|
}
|
|
152
55
|
}
|
|
153
56
|
|
|
154
|
-
var
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
if (method === 'remove') {
|
|
176
|
-
await globalThis[name].remove(key, value);
|
|
177
|
-
return send('ok')
|
|
178
|
-
}
|
|
179
|
-
value = await globalThis[name].get(key);
|
|
180
|
-
return send(value)
|
|
181
|
-
} catch (e) {
|
|
182
|
-
return error(e)
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
getConfig: async (params, {send, error}) => {
|
|
186
|
-
try {
|
|
187
|
-
const config = await api.getConfig(params);
|
|
188
|
-
send(config);
|
|
189
|
-
} catch (e) {
|
|
190
|
-
error(e);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
setMinerConfig: async (params, {send, error}) => {
|
|
194
|
-
try {
|
|
195
|
-
await api.setMinerConfig(params);
|
|
196
|
-
send('ok');
|
|
197
|
-
} catch (e) {
|
|
198
|
-
error(e);
|
|
57
|
+
var clientApi = _pubsub => {
|
|
58
|
+
const subscribe = (topic, cb) => {
|
|
59
|
+
_pubsub.subscribe(topic, cb);
|
|
60
|
+
};
|
|
61
|
+
const unsubscribe = (topic, cb) => {
|
|
62
|
+
_pubsub.unsubscribe(topic, cb);
|
|
63
|
+
};
|
|
64
|
+
const publish = (topic, value) => {
|
|
65
|
+
_pubsub.publish(topic, value);
|
|
66
|
+
};
|
|
67
|
+
const _connectionState = (state) => {
|
|
68
|
+
switch (state) {
|
|
69
|
+
case 0:
|
|
70
|
+
return 'connecting'
|
|
71
|
+
case 1:
|
|
72
|
+
return 'open'
|
|
73
|
+
case 2:
|
|
74
|
+
return 'closing'
|
|
75
|
+
case 3:
|
|
76
|
+
return 'closed'
|
|
199
77
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
78
|
+
};
|
|
79
|
+
const request = (client, request) => {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const state = _connectionState(client.readyState);
|
|
82
|
+
if (state !== 'open') return reject(`coudn't send request to ${client.id}, no open connection found.`)
|
|
83
|
+
request.id = Math.random().toString(36).slice(-12);
|
|
84
|
+
const handler = result => {
|
|
85
|
+
if (result && result.error) return reject(result.error)
|
|
86
|
+
resolve({result, id: request.id, handler});
|
|
87
|
+
unsubscribe(request.id, handler);
|
|
88
|
+
};
|
|
89
|
+
subscribe(request.id, handler);
|
|
90
|
+
send(client, request);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
const send = async (client, request) => {
|
|
94
|
+
return client.send(JSON.stringify(request))
|
|
95
|
+
};
|
|
96
|
+
const pubsub = client => {
|
|
97
|
+
return {
|
|
98
|
+
publish: (topic = 'pubsub', value) => {
|
|
99
|
+
return send(client, {url: 'pubsub', params: { topic, value }})
|
|
100
|
+
},
|
|
101
|
+
subscribe: (topic = 'pubsub', cb) => {
|
|
102
|
+
subscribe(topic, cb);
|
|
103
|
+
return send(client, {url: 'pubsub', params: { topic, subscribe: true }})
|
|
104
|
+
},
|
|
105
|
+
unsubscribe: (topic = 'pubsub', cb) => {
|
|
106
|
+
unsubscribe(topic, cb);
|
|
107
|
+
return send(client, {url: 'pubsub', params: { topic, unsubscribe: true }})
|
|
108
|
+
},
|
|
109
|
+
subscribers: _pubsub.subscribers
|
|
207
110
|
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
111
|
+
};
|
|
112
|
+
const server = (client) => {
|
|
113
|
+
return {
|
|
114
|
+
uptime: async () => {
|
|
115
|
+
try {
|
|
116
|
+
const { result, id, handler } = await request(client, {url: 'uptime'});
|
|
117
|
+
unsubscribe(id, handler);
|
|
118
|
+
return result
|
|
119
|
+
} catch (e) {
|
|
120
|
+
throw e
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
ping: async () => {
|
|
124
|
+
try {
|
|
125
|
+
const now = new Date().getTime();
|
|
126
|
+
const { result, id, handler } = await request(client, {url: 'ping'});
|
|
127
|
+
unsubscribe(id, handler);
|
|
128
|
+
return (Number(result) - now)
|
|
129
|
+
} catch (e) {
|
|
130
|
+
throw e
|
|
131
|
+
}
|
|
132
|
+
}
|
|
219
133
|
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
134
|
+
};
|
|
135
|
+
const peernet = (client) => {
|
|
136
|
+
return {
|
|
137
|
+
join: async (params) => {
|
|
138
|
+
try {
|
|
139
|
+
params.join = true;
|
|
140
|
+
const requested = { url: 'peernet', params };
|
|
141
|
+
const { result, id, handler } = await request(client, requested);
|
|
142
|
+
unsubscribe(id, handler);
|
|
143
|
+
return result
|
|
144
|
+
} catch (e) {
|
|
145
|
+
throw e
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
leave: async (params) => {
|
|
149
|
+
try {
|
|
150
|
+
params.join = false;
|
|
151
|
+
const requested = { url: 'peernet', params };
|
|
152
|
+
const { result, id, handler } = await request(client, requested);
|
|
153
|
+
unsubscribe(id, handler);
|
|
154
|
+
return result
|
|
155
|
+
} catch (e) {
|
|
156
|
+
throw e
|
|
157
|
+
}
|
|
158
|
+
}
|
|
227
159
|
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
} catch (e) {
|
|
244
|
-
console.log(e);
|
|
245
|
-
error(e);
|
|
160
|
+
};
|
|
161
|
+
return { send, request, pubsub, server, subscribe, unsubscribe, publish, peernet }
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (!globalThis.PubSub) globalThis.PubSub = LittlePubSub;
|
|
165
|
+
if (!globalThis.pubsub) globalThis.pubsub = new LittlePubSub({verbose: false});
|
|
166
|
+
const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry: false }) => {
|
|
167
|
+
const { retry } = options;
|
|
168
|
+
const api = clientApi(pubsub);
|
|
169
|
+
let tries = 0;
|
|
170
|
+
const onerror = error => {
|
|
171
|
+
if (pubsub.subscribers['error']) {
|
|
172
|
+
pubsub.publish('error', error);
|
|
173
|
+
} else {
|
|
174
|
+
console.error(error);
|
|
246
175
|
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
176
|
+
};
|
|
177
|
+
const onmessage = message => {
|
|
178
|
+
const {value, url, status, id} = JSON.parse(message.data.toString());
|
|
179
|
+
const publisher = id ? id : url;
|
|
180
|
+
if (status === 200) {
|
|
181
|
+
pubsub.publish(publisher, value);
|
|
182
|
+
} else {
|
|
183
|
+
pubsub.publish(publisher, {error: value});
|
|
254
184
|
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
185
|
+
};
|
|
186
|
+
const clientConnection = client => {
|
|
187
|
+
const startTime = new Date().getTime();
|
|
188
|
+
return {
|
|
189
|
+
client,
|
|
190
|
+
request: async req => {
|
|
191
|
+
const { result, id, handler } = await api.request(client, req);
|
|
192
|
+
pubsub.unsubscribe(id, handler);
|
|
193
|
+
return result
|
|
194
|
+
},
|
|
195
|
+
send: req => api.send(client, req),
|
|
196
|
+
subscribe: api.subscribe,
|
|
197
|
+
unsubscribe: api.unsubscribe,
|
|
198
|
+
subscribers: api.subscribers,
|
|
199
|
+
publish: api.publish,
|
|
200
|
+
pubsub: api.pubsub(client),
|
|
201
|
+
uptime: () => {
|
|
202
|
+
const now = new Date().getTime();
|
|
203
|
+
return (now - startTime)
|
|
204
|
+
},
|
|
205
|
+
peernet: api.peernet(client),
|
|
206
|
+
server: api.server(client),
|
|
207
|
+
close: exit => {
|
|
208
|
+
client.onclose = message => {
|
|
209
|
+
if (exit) process.exit();
|
|
210
|
+
};
|
|
211
|
+
client.close();
|
|
212
|
+
}
|
|
266
213
|
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
214
|
+
};
|
|
215
|
+
return new Promise((resolve, reject) => {
|
|
216
|
+
const init = () => {
|
|
217
|
+
let ws;
|
|
218
|
+
if (typeof process === 'object' && !globalThis.WebSocket) {
|
|
219
|
+
ws = require('websocket').w3cwebsocket;
|
|
220
|
+
} else {
|
|
221
|
+
ws = WebSocket;
|
|
222
|
+
}
|
|
223
|
+
const client = new ws(url, protocols);
|
|
224
|
+
client.onmessage = onmessage;
|
|
225
|
+
client.onerror = onerror;
|
|
226
|
+
client.onopen = () => {
|
|
227
|
+
tries = 0;
|
|
228
|
+
resolve(clientConnection(client));
|
|
229
|
+
};
|
|
230
|
+
client.onclose = message => {
|
|
231
|
+
tries++;
|
|
232
|
+
if (!retry) return reject(options)
|
|
233
|
+
if (tries > 5) {
|
|
234
|
+
console.log(`${protocols} Client Closed`);
|
|
235
|
+
console.error(`could not connect to - ${url}/`);
|
|
236
|
+
return resolve(clientConnection(client))
|
|
237
|
+
}
|
|
238
|
+
if (message.code === 1006) {
|
|
239
|
+
console.log('Retrying in 10 seconds');
|
|
240
|
+
setTimeout(() => {
|
|
241
|
+
return init();
|
|
242
|
+
}, retry);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
return init();
|
|
247
|
+
});
|
|
272
248
|
};
|
|
273
249
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
250
|
+
class Peer {
|
|
251
|
+
#connection
|
|
252
|
+
#ready = false
|
|
253
|
+
#connecting = false
|
|
254
|
+
#connected = false
|
|
255
|
+
#channelReady = false
|
|
256
|
+
#destroying = false
|
|
257
|
+
#destroyed = false
|
|
258
|
+
#isNegotiating = false
|
|
259
|
+
#firstNegotiation = true
|
|
260
|
+
#iceComplete = false
|
|
261
|
+
#remoteTracks = []
|
|
262
|
+
#remoteStreams = []
|
|
263
|
+
#pendingCandidates = []
|
|
264
|
+
#senderMap = new Map()
|
|
265
|
+
#iceCompleteTimer
|
|
266
|
+
#channel
|
|
267
|
+
|
|
268
|
+
get connection() {
|
|
269
|
+
return this.#connection
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
get connected() {
|
|
273
|
+
return this.#connected
|
|
274
|
+
}
|
|
279
275
|
|
|
280
276
|
/**
|
|
281
|
-
* @
|
|
282
|
-
*
|
|
283
|
-
* @param {object} connection socket connection
|
|
284
|
-
* @param {string} route the route to handle
|
|
285
|
-
*/
|
|
286
|
-
var socketConnection = (request, protocol, origin) => {
|
|
287
|
-
if (origin && !originIsAllowed(request.origin, origin)) {
|
|
288
|
-
// Make sure we only accept requests from an allowed origin
|
|
289
|
-
request.reject();
|
|
290
|
-
fullLog(`Connection from origin ${request.origin} rejected.`);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
// console.log(request);
|
|
294
|
-
const connection = request.accept(protocol, request.origin);
|
|
295
|
-
fullLog(`Connection accepted @${protocol}`);
|
|
296
|
-
return connection;
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* @module socketResponse
|
|
301
|
-
*
|
|
302
|
-
* @param {object} connection socket connection
|
|
303
|
-
* @param {string} url the request url
|
|
277
|
+
* @params {Object} options
|
|
278
|
+
* @params {string} options.channelName - this peerid : otherpeer id
|
|
304
279
|
*/
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const socketRequestServer = (options, routes = {}) => {
|
|
318
|
-
// if (!routes && !routes.port && options) routes = options;
|
|
319
|
-
// else if (!options && !routes) return console.error('no routes defined');
|
|
320
|
-
|
|
321
|
-
let {httpServer, httpsServer, port, protocol, credentials, origin, pubsub } = options;
|
|
322
|
-
if (!pubsub) pubsub = new PubSub({verbose: false});
|
|
323
|
-
if (!port) port = 6000;
|
|
324
|
-
const connections = [];
|
|
325
|
-
let connection;
|
|
326
|
-
const startTime = new Date().getTime();
|
|
327
|
-
// default routes
|
|
328
|
-
if (!routes.ping) routes.ping = (response) => response.send(new Date().getTime());
|
|
329
|
-
if (!routes.uptime) routes.uptime = (response) => {
|
|
330
|
-
const now = new Date().getTime();
|
|
331
|
-
response.send(now - startTime);
|
|
280
|
+
constructor(options = {}) {
|
|
281
|
+
this._in = this._in.bind(this);
|
|
282
|
+
this.offerOptions = options.offerOptions;
|
|
283
|
+
this.initiator = options.initiator;
|
|
284
|
+
this.streams = options.streams;
|
|
285
|
+
this.socketClient = options.socketClient;
|
|
286
|
+
this.id = options.id;
|
|
287
|
+
this.to = options.to;
|
|
288
|
+
this.bw = {
|
|
289
|
+
up: 0,
|
|
290
|
+
down: 0
|
|
332
291
|
};
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
292
|
+
|
|
293
|
+
this.channelName = options.channelName || Buffer.from(Math.random().toString(36).slice(-12)).toString('hex');
|
|
294
|
+
console.log(this.channelName);
|
|
295
|
+
this.options = options;
|
|
296
|
+
this.#init();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
set socketClient(value) {
|
|
300
|
+
// this.socketClient?.pubsub.unsubscribe('signal', this._in)
|
|
301
|
+
this._socketClient = value;
|
|
302
|
+
this._socketClient.pubsub.subscribe('signal', this._in);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
get socketClient() {
|
|
306
|
+
return this._socketClient
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
send(message) {
|
|
310
|
+
this.bw.up += message.length;
|
|
311
|
+
this.channel.send(message);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
request(data) {
|
|
315
|
+
return new Promise((resolve, reject) => {
|
|
316
|
+
const id = Math.random().toString(36).slice(-12);
|
|
317
|
+
data = new TextEncoder().encode(JSON.stringify({id, data}));
|
|
318
|
+
const _onData = message => {
|
|
319
|
+
message = JSON.parse(new TextDecoder().decode(message.data));
|
|
320
|
+
if (message.id === id) {
|
|
321
|
+
resolve(message.data);
|
|
322
|
+
pubsub.unsubscribe('peer:data', _onData);
|
|
358
323
|
}
|
|
359
|
-
else if (params.value !== undefined)
|
|
360
|
-
// should only be send raw to stars
|
|
361
|
-
// for (const connection of connections) {
|
|
362
|
-
// if (connection !== response.connection) connection.send(JSON.stringify({
|
|
363
|
-
// url: topic, status: 200, value: params
|
|
364
|
-
// }));
|
|
365
|
-
// }
|
|
366
|
-
pubsub.publish(topic, params.value);
|
|
367
|
-
response.send('ok', 200);
|
|
368
324
|
};
|
|
369
|
-
|
|
325
|
+
|
|
326
|
+
pubsub.subscribe('peer:data', _onData);
|
|
327
|
+
|
|
328
|
+
// cleanup subscriptions
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
pubsub.unsubscribe('peer:data', _onData);
|
|
331
|
+
}, 5000);
|
|
332
|
+
|
|
333
|
+
this.send(data);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async #init() {
|
|
338
|
+
try {
|
|
339
|
+
const iceServers = [{
|
|
340
|
+
urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
|
|
341
|
+
}];
|
|
342
|
+
|
|
343
|
+
this.#connection = new wrtc.RTCPeerConnection();
|
|
344
|
+
this.#connection.onicecandidate = ({ candidate }) => {
|
|
345
|
+
if (candidate) {
|
|
346
|
+
this.address = candidate.address;
|
|
347
|
+
this.port = candidate.port;
|
|
348
|
+
this.protocol = candidate.protocol;
|
|
349
|
+
this.ipFamily = this.address.includes('::') ? 'ipv6': 'ipv4';
|
|
350
|
+
this._sendMessage({candidate});
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
// if (this.initiator) this.#connection.onnegotiationneeded = () => {
|
|
354
|
+
// console.log('create offer');
|
|
355
|
+
this.#connection.ondatachannel = (message) => {
|
|
356
|
+
message.channel.onopen = () => {
|
|
357
|
+
this.#connected = true;
|
|
358
|
+
pubsub.publish('peer:connected', this);
|
|
359
|
+
};
|
|
360
|
+
message.channel.onclose = () => console.log('close');
|
|
361
|
+
message.channel.onmessage = (message) => {
|
|
362
|
+
if (message.to) {
|
|
363
|
+
if (message.to === this.id) pubsub.publish('peer:data', message);
|
|
364
|
+
} else pubsub.publish('peer:data', message);
|
|
365
|
+
this.bw.down += message.length;
|
|
366
|
+
};
|
|
367
|
+
this.channel = message.channel;
|
|
368
|
+
};
|
|
369
|
+
if (this.initiator) {
|
|
370
|
+
|
|
371
|
+
this.channel = this.#connection.createDataChannel('messageChannel');
|
|
372
|
+
this.channel.onopen = () => {
|
|
373
|
+
this.#connected = true;
|
|
374
|
+
pubsub.publish('peer:connected', this);
|
|
375
|
+
// this.channel.send('hi')
|
|
376
|
+
};
|
|
377
|
+
this.channel.onclose = () => this.close.bind(this);
|
|
378
|
+
|
|
379
|
+
this.channel.onmessage = (message) => {
|
|
380
|
+
if (message.to) {
|
|
381
|
+
if (message.to === this.id) pubsub.publish('peer:data', message);
|
|
382
|
+
} else pubsub.publish('peer:data', message);
|
|
383
|
+
this.bw.down += message.length;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const offer = await this.#connection.createOffer();
|
|
387
|
+
await this.#connection.setLocalDescription(offer);
|
|
388
|
+
|
|
389
|
+
this._sendMessage({'sdp': this.#connection.localDescription});
|
|
390
|
+
}
|
|
391
|
+
// }
|
|
392
|
+
|
|
393
|
+
} catch (e) {
|
|
394
|
+
console.log(e);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
_sendMessage(message) {
|
|
399
|
+
this.socketClient.send({url: 'signal', params: {
|
|
400
|
+
to: this.to,
|
|
401
|
+
from: this.id,
|
|
402
|
+
channelName: this.options.channelName,
|
|
403
|
+
...message
|
|
404
|
+
}});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async _in(message, data) {
|
|
408
|
+
// message = JSON.parse(message);
|
|
409
|
+
if (message.to !== this.id) return
|
|
410
|
+
// if (data.videocall) return this._startStream(true, false); // start video and audio stream
|
|
411
|
+
// if (data.call) return this._startStream(true, true); // start audio stream
|
|
412
|
+
if (message.candidate) {
|
|
413
|
+
this.remoteAddress = message.candidate.address;
|
|
414
|
+
this.remotePort = message.candidate.port;
|
|
415
|
+
this.remoteProtocol = message.candidate.protocol;
|
|
416
|
+
this.remoteIpFamily = this.remoteAddress?.includes('::') ? 'ipv6': 'ipv4';
|
|
417
|
+
return this.#connection.addIceCandidate(new wrtc.RTCIceCandidate(message.candidate));
|
|
370
418
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (connection !== response.connection)
|
|
379
|
-
socketResponse(connection, 'peernet', 'peernet').send({discovered: params.address});
|
|
380
|
-
}
|
|
381
|
-
return
|
|
419
|
+
try {
|
|
420
|
+
if (message.sdp) {
|
|
421
|
+
if (message.sdp.type === 'offer') {
|
|
422
|
+
await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
|
|
423
|
+
const answer = await this.#connection.createAnswer();
|
|
424
|
+
await this.#connection.setLocalDescription(answer);
|
|
425
|
+
this._sendMessage({'sdp': this.#connection.localDescription});
|
|
382
426
|
}
|
|
383
|
-
if (
|
|
384
|
-
|
|
385
|
-
return response.send()
|
|
427
|
+
if (message.sdp.type === 'answer') {
|
|
428
|
+
await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
|
|
386
429
|
}
|
|
387
|
-
|
|
430
|
+
}
|
|
431
|
+
} catch (e) {
|
|
432
|
+
console.log(e);
|
|
388
433
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
close() {
|
|
437
|
+
this.channel?.close();
|
|
438
|
+
this.#connection?.close();
|
|
439
|
+
|
|
440
|
+
this.socketClient.pubsub.unsubscribe('signal', this._in);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
class Client {
|
|
445
|
+
#peerConnection
|
|
446
|
+
#connections = {}
|
|
447
|
+
#stars = {}
|
|
448
|
+
|
|
449
|
+
get connections() {
|
|
450
|
+
return { ...this.#connections }
|
|
398
451
|
}
|
|
399
452
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
connection = socketConnection(request, protocol, origin);
|
|
408
|
-
connections.push(connection);
|
|
409
|
-
|
|
410
|
-
const routeHandler = message => {
|
|
411
|
-
let data;
|
|
412
|
-
if (message.type) {
|
|
413
|
-
switch (message.type) {
|
|
414
|
-
case 'binary':
|
|
415
|
-
data = message.binaryData.toString();
|
|
416
|
-
break;
|
|
417
|
-
case 'utf8':
|
|
418
|
-
data = message.utf8Data;
|
|
419
|
-
break;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
const { route, params, url, id, customEvent } = JSON.parse(data);
|
|
423
|
-
// ignore api when customEvent is defined
|
|
424
|
-
if (customEvent) return;
|
|
425
|
-
if (routes[url]) {
|
|
426
|
-
if (!params) return routes[url](socketResponse(connection, url, id));
|
|
427
|
-
return routes[url](params, socketResponse(connection, url, id));
|
|
428
|
-
}
|
|
429
|
-
else return socketResponse(connection, url, id).error(`nop handler found for '${message.url}'`);
|
|
430
|
-
};
|
|
453
|
+
constructor(id, identifiers = ['peernet-v0.1.0'], stars = []) {
|
|
454
|
+
this.id = id || Math.random().toString(36).slice(-12);
|
|
455
|
+
if (!Array.isArray(identifiers)) identifiers = [identifiers];
|
|
456
|
+
this.peerJoined = this.peerJoined.bind(this);
|
|
457
|
+
this.peerLeft = this.peerLeft.bind(this);
|
|
458
|
+
this.starLeft = this.starLeft.bind(this);
|
|
459
|
+
this.starJoined = this.starJoined.bind(this);
|
|
431
460
|
|
|
432
|
-
|
|
433
|
-
|
|
461
|
+
this._init(identifiers, stars);
|
|
462
|
+
}
|
|
434
463
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
var http = (config = {}) => {
|
|
442
|
-
if (typeof config !== 'object') config = {};
|
|
443
|
-
if (!config.protocol) config.protocol = 'peernet-v0.1.0';
|
|
444
|
-
if (!config.port) config.port = 2000;
|
|
445
|
-
if (!config.host) config.host = '127.0.0.1';
|
|
446
|
-
|
|
447
|
-
const app = new Koa();
|
|
448
|
-
|
|
449
|
-
app.use(async (ctx) => {
|
|
450
|
-
const url = ctx.url.split('/api/')[1];
|
|
451
|
-
if (url === 'version') ctx.body = {client: '@peernet/api/http', version};
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
const httpServer = createServer(app.callback());
|
|
455
|
-
|
|
456
|
-
config.httpServer = httpServer;
|
|
457
|
-
|
|
458
|
-
httpServer.listen(config.port, () => {
|
|
459
|
-
console.log(`listening on ${config.port}`);
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
return socketRequestServer(config, api$1)
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
var clientApi = _pubsub => {
|
|
466
|
-
|
|
467
|
-
const subscribe = (topic, cb) => {
|
|
468
|
-
_pubsub.subscribe(topic, cb);
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
const unsubscribe = (topic, cb) => {
|
|
472
|
-
_pubsub.unsubscribe(topic, cb);
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
const publish = (topic, value) => {
|
|
476
|
-
_pubsub.publish(topic, value);
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
const _connectionState = (state) => {
|
|
480
|
-
switch (state) {
|
|
481
|
-
case 0:
|
|
482
|
-
return 'connecting'
|
|
483
|
-
case 1:
|
|
484
|
-
return 'open'
|
|
485
|
-
case 2:
|
|
486
|
-
return 'closing'
|
|
487
|
-
case 3:
|
|
488
|
-
return 'closed'
|
|
464
|
+
async _init(identifiers, stars = []) {
|
|
465
|
+
if (stars.length === 0) {
|
|
466
|
+
stars.push('wss://star.leofcoin.org');
|
|
467
|
+
stars.push('ws://localhost:44444');
|
|
489
468
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
469
|
+
this.identifiers = identifiers;
|
|
470
|
+
this.starsConfig = stars;
|
|
471
|
+
// reconnectJob()
|
|
472
|
+
|
|
473
|
+
globalThis.wrtc = await import('wrtc');
|
|
474
|
+
for (const star of stars) {
|
|
475
|
+
try {
|
|
476
|
+
this.socketClient = await socketRequestClient(star, identifiers[0]);
|
|
477
|
+
const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
|
|
478
|
+
this.socketClient.peerId = id;
|
|
479
|
+
this.#stars[id] = this.socketClient;
|
|
480
|
+
} catch (e) {
|
|
481
|
+
if (stars.indexOf(star) === stars.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const peers = await this.socketClient.peernet.join({id: this.id});
|
|
485
|
+
for (const id of peers) {
|
|
486
|
+
if (id !== this.id && !this.#connections[id]) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id});
|
|
487
|
+
}
|
|
488
|
+
this.setupListeners();
|
|
489
|
+
|
|
490
|
+
pubsub.subscribe('peer:connected', (peer) => {
|
|
491
|
+
// peer.send(JSON.stringify({data: 'hello', from: this.id, to: peer.to}))
|
|
492
|
+
console.log({peer: peer.to});
|
|
493
|
+
console.log({id: peer.id});
|
|
494
|
+
console.log({id: this.id});
|
|
509
495
|
});
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
return send(client, {url: 'pubsub', params: { topic, subscribe: true }})
|
|
524
|
-
},
|
|
525
|
-
unsubscribe: (topic = 'pubsub', cb) => {
|
|
526
|
-
unsubscribe(topic, cb);
|
|
527
|
-
return send(client, {url: 'pubsub', params: { topic, unsubscribe: true }})
|
|
528
|
-
},
|
|
529
|
-
subscribers: _pubsub.subscribers
|
|
496
|
+
// pubsub.subscribe('peer:data', (data) => console.log({data}))
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
setupListeners() {
|
|
500
|
+
this.socketClient.subscribe('peer:joined', this.peerJoined);
|
|
501
|
+
this.socketClient.subscribe('peer:left', this.peerLeft);
|
|
502
|
+
this.socketClient.subscribe('star:left', this.starLeft);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
starJoined(id) {
|
|
506
|
+
if (this.#stars[id]) {
|
|
507
|
+
this.#stars[id].close();
|
|
508
|
+
delete this.#stars[id];
|
|
530
509
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
unsubscribe(id, handler);
|
|
539
|
-
return result
|
|
540
|
-
} catch (e) {
|
|
541
|
-
throw e
|
|
542
|
-
}
|
|
543
|
-
},
|
|
544
|
-
ping: async () => {
|
|
545
|
-
try {
|
|
546
|
-
const now = new Date().getTime();
|
|
547
|
-
const { result, id, handler } = await request(client, {url: 'ping'});
|
|
548
|
-
unsubscribe(id, handler);
|
|
549
|
-
return (Number(result) - now)
|
|
550
|
-
} catch (e) {
|
|
551
|
-
throw e
|
|
552
|
-
}
|
|
553
|
-
}
|
|
510
|
+
console.log(`star ${id} joined`);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async starLeft(id) {
|
|
514
|
+
if (this.#stars[id]) {
|
|
515
|
+
this.#stars[id].close();
|
|
516
|
+
delete this.#stars[id];
|
|
554
517
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
unsubscribe(id, handler);
|
|
565
|
-
return result
|
|
566
|
-
} catch (e) {
|
|
567
|
-
throw e
|
|
568
|
-
}
|
|
569
|
-
},
|
|
570
|
-
leave: async (params) => {
|
|
518
|
+
if (this.socketClient?.peerId === id) {
|
|
519
|
+
|
|
520
|
+
this.socketClient.unsubscribe('peer:joined', this.peerJoined);
|
|
521
|
+
this.socketClient.unsubscribe('peer:left', this.peerLeft);
|
|
522
|
+
this.socketClient.unsubscribe('star:left', this.starLeft);
|
|
523
|
+
this.socketClient.close();
|
|
524
|
+
this.socketClient = undefined;
|
|
525
|
+
|
|
526
|
+
for (const star of this.starsConfig) {
|
|
571
527
|
try {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
528
|
+
this.socketClient = await socketRequestClient(star, this.identifiers[0]);
|
|
529
|
+
if (!this.socketClient?.client?._connection.connected) return
|
|
530
|
+
const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
|
|
531
|
+
this.#stars[id] = this.socketClient;
|
|
532
|
+
|
|
533
|
+
this.socketClient.peerId = id;
|
|
534
|
+
|
|
535
|
+
const peers = await this.socketClient.peernet.join({id: this.id});
|
|
536
|
+
this.setupListeners();
|
|
537
|
+
for (const id of peers) {
|
|
538
|
+
if (id !== this.id) {
|
|
539
|
+
// close connection
|
|
540
|
+
if (this.#connections[id]) {
|
|
541
|
+
if (this.#connections[id].connected) await this.#connections[id].close();
|
|
542
|
+
delete this.#connections[id];
|
|
543
|
+
}
|
|
544
|
+
// reconnect
|
|
545
|
+
if (id !== this.id) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
}
|
|
577
549
|
} catch (e) {
|
|
578
|
-
|
|
550
|
+
console.log(e);
|
|
551
|
+
if (this.starsConfig.indexOf(star) === this.starsConfig.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
|
|
579
552
|
}
|
|
580
553
|
}
|
|
581
554
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
let tries = 0;
|
|
594
|
-
|
|
595
|
-
const onerror = error => {
|
|
596
|
-
if (pubsub.subscribers['error']) {
|
|
597
|
-
pubsub.publish('error', error);
|
|
598
|
-
} else {
|
|
599
|
-
console.error(error);
|
|
600
|
-
}
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
const onmessage = message => {
|
|
604
|
-
const {value, url, status, id} = JSON.parse(message.data.toString());
|
|
605
|
-
const publisher = id ? id : url;
|
|
606
|
-
if (status === 200) {
|
|
607
|
-
pubsub.publish(publisher, value);
|
|
608
|
-
} else {
|
|
609
|
-
pubsub.publish(publisher, {error: value});
|
|
555
|
+
|
|
556
|
+
console.log(`star ${id} left`);
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
peerLeft(id) {
|
|
562
|
+
if (this.#connections[id]) {
|
|
563
|
+
this.#connections[id].close();
|
|
564
|
+
delete this.#connections[id];
|
|
610
565
|
}
|
|
566
|
+
console.log(`peer ${id} left`);
|
|
567
|
+
}
|
|
611
568
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
return {
|
|
617
|
-
client,
|
|
618
|
-
request: async req => {
|
|
619
|
-
const { result, id, handler } = await api.request(client, req);
|
|
620
|
-
pubsub.unsubscribe(id, handler);
|
|
621
|
-
return result
|
|
622
|
-
},
|
|
623
|
-
send: req => api.send(client, req),
|
|
624
|
-
subscribe: api.subscribe,
|
|
625
|
-
unsubscribe: api.unsubscribe,
|
|
626
|
-
subscribers: api.subscribers,
|
|
627
|
-
publish: api.publish,
|
|
628
|
-
pubsub: api.pubsub(client),
|
|
629
|
-
uptime: () => {
|
|
630
|
-
const now = new Date().getTime();
|
|
631
|
-
return (now - startTime)
|
|
632
|
-
},
|
|
633
|
-
peernet: api.peernet(client),
|
|
634
|
-
server: api.server(client),
|
|
635
|
-
close: exit => {
|
|
636
|
-
client.onclose = message => {
|
|
637
|
-
if (exit) process.exit();
|
|
638
|
-
};
|
|
639
|
-
client.close();
|
|
640
|
-
}
|
|
569
|
+
peerJoined(id, signal) {
|
|
570
|
+
if (this.#connections[id]) {
|
|
571
|
+
if (this.#connections[id].connected) this.#connections[id].close();
|
|
572
|
+
delete this.#connections[id];
|
|
641
573
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (typeof process === 'object') {
|
|
648
|
-
ws = require('websocket').w3cwebsocket;
|
|
649
|
-
} else {
|
|
650
|
-
ws = WebSocket;
|
|
651
|
-
}
|
|
652
|
-
const client = new ws(url, protocols);
|
|
574
|
+
// RTCPeerConnection
|
|
575
|
+
this.#connections[id] = new Peer({initiator: true, channelName: `${this.id}:${id}`, socketClient: this.socketClient, id: this.id, to: id});
|
|
576
|
+
console.log(`peer ${id} joined`);
|
|
577
|
+
}
|
|
578
|
+
|
|
653
579
|
|
|
654
|
-
client.onmessage = onmessage;
|
|
655
|
-
client.onerror = onerror;
|
|
656
|
-
client.onopen = () => {
|
|
657
|
-
tries = 0;
|
|
658
|
-
resolve(clientConnection(client));
|
|
659
|
-
};
|
|
660
|
-
client.onclose = message => {
|
|
661
|
-
tries++;
|
|
662
|
-
if (!retry) return reject(options)
|
|
663
|
-
if (tries > 5) {
|
|
664
|
-
console.log(`${protocols} Client Closed`);
|
|
665
|
-
console.error(`could not connect to - ${url}/`);
|
|
666
|
-
return resolve(clientConnection(client))
|
|
667
|
-
}
|
|
668
|
-
if (message.code === 1006) {
|
|
669
|
-
console.log('Retrying in 10 seconds');
|
|
670
|
-
setTimeout(() => {
|
|
671
|
-
return init();
|
|
672
|
-
}, retry);
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
};
|
|
676
|
-
return init();
|
|
677
|
-
});
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
class HttpClientApi$1 {
|
|
681
|
-
constructor(config = {}) {
|
|
682
|
-
if (!config.apiPath) config.apiPath = 'api';
|
|
683
|
-
|
|
684
|
-
const address = `ws://${config.host}:${config.port}`;
|
|
685
|
-
|
|
686
|
-
this.apiUrl = (url) => `${address}/${url}`;
|
|
687
|
-
return (async () => {
|
|
688
|
-
this.client = await socketRequestClient(address, config.protocol, {pubsub: config.pubsub, retry: 3000});
|
|
689
|
-
return this
|
|
690
|
-
})()
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
async get(url, obj) {
|
|
694
|
-
const headers = {};
|
|
695
|
-
let body = null;
|
|
696
|
-
let method = 'GET';
|
|
697
|
-
if (obj) {
|
|
698
|
-
method = 'POST';
|
|
699
|
-
headers['Content-Type'] = 'application/json';
|
|
700
|
-
body = JSON.stringify(obj);
|
|
701
|
-
}
|
|
702
|
-
let response = await this.client.request(url, {headers, body, method});
|
|
703
|
-
const type = response.headers.get('content-type').split(';')[0];
|
|
704
|
-
if (type==='application/json') response = await response.json();
|
|
705
|
-
return response
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
async put(url, obj) {
|
|
709
|
-
const headers = {};
|
|
710
|
-
let body = {};
|
|
711
|
-
if (obj) {
|
|
712
|
-
headers['Content-Type'] = 'application/json';
|
|
713
|
-
body = JSON.stringify(obj);
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
let response = await fetch(this.apiUrl(url), {method: 'PUT', headers, body});
|
|
717
|
-
const type = response.headers.get('content-type').split(';')[0];
|
|
718
|
-
if (type==='application/json') response = await response.json();
|
|
719
|
-
return response
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
class HttpClientApi extends HttpClientApi$1 {
|
|
724
|
-
constructor(config = {}) {
|
|
725
|
-
config.apiPath = 'api';
|
|
726
|
-
return (async () => {
|
|
727
|
-
await super(config);
|
|
728
|
-
|
|
729
|
-
this.properties = {
|
|
730
|
-
wallet: 'get',
|
|
731
|
-
version: 'get',
|
|
732
|
-
addresses: 'get',
|
|
733
|
-
config: 'get',
|
|
734
|
-
account: 'get',
|
|
735
|
-
accounts: 'get',
|
|
736
|
-
transaction: 'any',
|
|
737
|
-
transactions: 'get',
|
|
738
|
-
block: 'get',
|
|
739
|
-
blocks: 'get',
|
|
740
|
-
};
|
|
741
|
-
this.keys = Object.keys(this.properties);
|
|
742
|
-
return this
|
|
743
|
-
})()
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
async request(url, data) {
|
|
747
|
-
return await this.client.request({url, params: data})
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
async ready() {
|
|
751
|
-
return await this.request('ready')
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
async version() {
|
|
755
|
-
return await this.request('version')
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
async account(index) {
|
|
759
|
-
return await this.request('account', {index})
|
|
760
|
-
}
|
|
761
580
|
}
|
|
762
581
|
|
|
763
|
-
var httpClient = (config = {}) => {
|
|
764
|
-
if (typeof config !== 'object') config = {};
|
|
765
|
-
if (!config.protocol) config.protocol = 'peernet-v0.1.0';
|
|
766
|
-
if (!config.port) config.port = 1000;
|
|
767
|
-
if (!config.host) config.host = '127.0.0.1';
|
|
768
|
-
|
|
769
|
-
return new HttpClientApi(config)
|
|
770
|
-
};
|
|
771
|
-
|
|
772
582
|
class LeofcoinStorageClient {
|
|
773
583
|
constructor(name, root) {
|
|
774
584
|
this.name = name;
|
|
@@ -816,84 +626,84 @@ message PeernetMessage {
|
|
|
816
626
|
optional string id = 5;
|
|
817
627
|
}`;
|
|
818
628
|
|
|
819
|
-
var codecs = {
|
|
820
|
-
// just a hash
|
|
821
|
-
'disco-hash': {
|
|
822
|
-
codec: '30',
|
|
823
|
-
hashAlg: 'dbl-keccak-512', // ,
|
|
824
|
-
// testnet: 'olivia'
|
|
825
|
-
},
|
|
826
|
-
'peernet-peer-response': {
|
|
827
|
-
codec: '707072',
|
|
828
|
-
hashAlg: 'keccak-256',
|
|
829
|
-
},
|
|
830
|
-
'peernet-peer': {
|
|
831
|
-
codec: '7070',
|
|
832
|
-
hashAlg: 'keccak-256',
|
|
833
|
-
},
|
|
834
|
-
'peernet-dht': {
|
|
835
|
-
codec: '706468',
|
|
836
|
-
hashAlg: 'keccak-256',
|
|
837
|
-
},
|
|
838
|
-
'peernet-dht-response': {
|
|
839
|
-
codec: '706472',
|
|
840
|
-
hashAlg: 'keccak-256',
|
|
841
|
-
},
|
|
842
|
-
// data
|
|
843
|
-
'peernet-data': {
|
|
844
|
-
codec: '706461',
|
|
845
|
-
hashAlg: 'keccak-256',
|
|
846
|
-
},
|
|
847
|
-
'peernet-data-response': {
|
|
848
|
-
codec: '70646172',
|
|
849
|
-
hashAlg: 'keccak-256',
|
|
850
|
-
},
|
|
851
|
-
// message
|
|
852
|
-
'peernet-message': {
|
|
853
|
-
codec: '706d65',
|
|
854
|
-
hashAlg: 'keccak-512',
|
|
855
|
-
},
|
|
856
|
-
// pubsub
|
|
857
|
-
'peernet-ps': {
|
|
858
|
-
codec: '707073',
|
|
859
|
-
hashAlg: 'keccak-256',
|
|
860
|
-
},
|
|
861
|
-
'peernet-response': {
|
|
862
|
-
codec: '7072',
|
|
863
|
-
hashAlg: 'keccak-256',
|
|
864
|
-
},
|
|
865
|
-
'peernet-request': {
|
|
866
|
-
codec: '707271',
|
|
867
|
-
hashAlg: 'keccak-256',
|
|
868
|
-
},
|
|
869
|
-
// normal block
|
|
870
|
-
'leofcoin-block': {
|
|
871
|
-
codec: '6c62',
|
|
872
|
-
hashAlg: 'dbl-keccak-512', // ,
|
|
873
|
-
// testnet: 'olivia'
|
|
874
|
-
},
|
|
875
|
-
'leofcoin-tx': {
|
|
876
|
-
codec: '6c74',
|
|
877
|
-
hashAlg: 'dbl-keccak-512', // ,
|
|
878
|
-
// testnet: 'olivia'
|
|
879
|
-
},
|
|
880
|
-
// itx
|
|
881
|
-
'leofcoin-itx': {
|
|
882
|
-
codec: '6c69',
|
|
883
|
-
hashAlg: 'keccak-512', // ,
|
|
884
|
-
// testnet: 'olivia'
|
|
885
|
-
},
|
|
886
|
-
// peer reputation
|
|
887
|
-
'leofcoin-pr': {
|
|
888
|
-
codec: '6c70',
|
|
889
|
-
hashAlg: 'keccak-256', // ,
|
|
890
|
-
// testnet: 'olivia'
|
|
891
|
-
},
|
|
892
|
-
// chat message
|
|
893
|
-
'chat-message': {
|
|
894
|
-
codec: '636d',
|
|
895
|
-
hashAlg: 'dbl-keccak-512',
|
|
896
|
-
},
|
|
629
|
+
var codecs = {
|
|
630
|
+
// just a hash
|
|
631
|
+
'disco-hash': {
|
|
632
|
+
codec: parseInt('30', 16),
|
|
633
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
634
|
+
// testnet: 'olivia'
|
|
635
|
+
},
|
|
636
|
+
'peernet-peer-response': {
|
|
637
|
+
codec: parseInt('707072', 16),
|
|
638
|
+
hashAlg: 'keccak-256',
|
|
639
|
+
},
|
|
640
|
+
'peernet-peer': {
|
|
641
|
+
codec: parseInt('7070', 16),
|
|
642
|
+
hashAlg: 'keccak-256',
|
|
643
|
+
},
|
|
644
|
+
'peernet-dht': {
|
|
645
|
+
codec: parseInt('706468', 16),
|
|
646
|
+
hashAlg: 'keccak-256',
|
|
647
|
+
},
|
|
648
|
+
'peernet-dht-response': {
|
|
649
|
+
codec: parseInt('706472', 16),
|
|
650
|
+
hashAlg: 'keccak-256',
|
|
651
|
+
},
|
|
652
|
+
// data
|
|
653
|
+
'peernet-data': {
|
|
654
|
+
codec: parseInt('706461', 16),
|
|
655
|
+
hashAlg: 'keccak-256',
|
|
656
|
+
},
|
|
657
|
+
'peernet-data-response': {
|
|
658
|
+
codec: parseInt('70646172', 16),
|
|
659
|
+
hashAlg: 'keccak-256',
|
|
660
|
+
},
|
|
661
|
+
// message
|
|
662
|
+
'peernet-message': {
|
|
663
|
+
codec: parseInt('706d65', 16),
|
|
664
|
+
hashAlg: 'keccak-512',
|
|
665
|
+
},
|
|
666
|
+
// pubsub
|
|
667
|
+
'peernet-ps': {
|
|
668
|
+
codec: parseInt('707073', 16),
|
|
669
|
+
hashAlg: 'keccak-256',
|
|
670
|
+
},
|
|
671
|
+
'peernet-response': {
|
|
672
|
+
codec: parseInt('7072', 16),
|
|
673
|
+
hashAlg: 'keccak-256',
|
|
674
|
+
},
|
|
675
|
+
'peernet-request': {
|
|
676
|
+
codec: parseInt('707271', 16),
|
|
677
|
+
hashAlg: 'keccak-256',
|
|
678
|
+
},
|
|
679
|
+
// normal block
|
|
680
|
+
'leofcoin-block': {
|
|
681
|
+
codec: parseInt('6c62', 16),
|
|
682
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
683
|
+
// testnet: 'olivia'
|
|
684
|
+
},
|
|
685
|
+
'leofcoin-tx': {
|
|
686
|
+
codec: parseInt('6c74', 16),
|
|
687
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
688
|
+
// testnet: 'olivia'
|
|
689
|
+
},
|
|
690
|
+
// itx
|
|
691
|
+
'leofcoin-itx': {
|
|
692
|
+
codec: parseInt('6c69', 16),
|
|
693
|
+
hashAlg: 'keccak-512', // ,
|
|
694
|
+
// testnet: 'olivia'
|
|
695
|
+
},
|
|
696
|
+
// peer reputation
|
|
697
|
+
'leofcoin-pr': {
|
|
698
|
+
codec: parseInt('6c70', 16),
|
|
699
|
+
hashAlg: 'keccak-256', // ,
|
|
700
|
+
// testnet: 'olivia'
|
|
701
|
+
},
|
|
702
|
+
// chat message
|
|
703
|
+
'chat-message': {
|
|
704
|
+
codec: parseInt('636d', 16),
|
|
705
|
+
hashAlg: 'dbl-keccak-512',
|
|
706
|
+
},
|
|
897
707
|
};
|
|
898
708
|
|
|
899
709
|
class PeernetCodec {
|
|
@@ -902,10 +712,9 @@ class PeernetCodec {
|
|
|
902
712
|
}
|
|
903
713
|
constructor(buffer) {
|
|
904
714
|
if (buffer) {
|
|
905
|
-
if (
|
|
715
|
+
if (buffer instanceof Uint8Array) {
|
|
906
716
|
const codec = varint.decode(buffer);
|
|
907
717
|
const name = this.getCodecName(codec);
|
|
908
|
-
|
|
909
718
|
if (name) {
|
|
910
719
|
this.name = name;
|
|
911
720
|
this.encoded = buffer;
|
|
@@ -913,12 +722,23 @@ class PeernetCodec {
|
|
|
913
722
|
} else {
|
|
914
723
|
this.encode(buffer);
|
|
915
724
|
}
|
|
725
|
+
} else if (buffer instanceof ArrayBuffer) {
|
|
726
|
+
const encoded = new Uint8Array(buffer.byteLength);
|
|
727
|
+
|
|
728
|
+
for (let i = 0; i < buffer.byteLength; i++) {
|
|
729
|
+
encoded[i] = buffer[i];
|
|
730
|
+
}
|
|
731
|
+
this.encoded = encoded;
|
|
732
|
+
// this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
|
|
733
|
+
this.decode(buffer);
|
|
734
|
+
return
|
|
916
735
|
}
|
|
917
736
|
if (typeof buffer === 'string') {
|
|
918
737
|
if (this.codecs[buffer]) this.fromName(buffer);
|
|
919
738
|
else if (isHex(buffer)) this.fromHex(buffer);
|
|
920
|
-
else if (bs32.
|
|
921
|
-
else this.fromBs58(buffer);
|
|
739
|
+
else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
|
|
740
|
+
else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
|
|
741
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
922
742
|
}
|
|
923
743
|
if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer);
|
|
924
744
|
}
|
|
@@ -953,7 +773,8 @@ class PeernetCodec {
|
|
|
953
773
|
|
|
954
774
|
getCodecName(codec) {
|
|
955
775
|
return Object.keys(this.codecs).reduce((p, c) => {
|
|
956
|
-
|
|
776
|
+
const item = this.codecs[c];
|
|
777
|
+
if (item.codec === codec) return c;
|
|
957
778
|
else return p;
|
|
958
779
|
}, undefined)
|
|
959
780
|
}
|
|
@@ -967,7 +788,7 @@ class PeernetCodec {
|
|
|
967
788
|
this.hashAlg = this.getHashAlg(this.name);
|
|
968
789
|
|
|
969
790
|
this.codec = this.getCodec(this.name);
|
|
970
|
-
this.codecBuffer =
|
|
791
|
+
this.codecBuffer = varint.encode(codec);
|
|
971
792
|
}
|
|
972
793
|
|
|
973
794
|
fromName(name) {
|
|
@@ -975,7 +796,7 @@ class PeernetCodec {
|
|
|
975
796
|
this.name = name;
|
|
976
797
|
this.codec = codec;
|
|
977
798
|
this.hashAlg = this.getHashAlg(name);
|
|
978
|
-
this.codecBuffer =
|
|
799
|
+
this.codecBuffer = varint.encode(codec);
|
|
979
800
|
}
|
|
980
801
|
|
|
981
802
|
toBs32() {
|
|
@@ -995,11 +816,10 @@ class PeernetCodec {
|
|
|
995
816
|
decode() {
|
|
996
817
|
const codec = varint.decode(this.encoded);
|
|
997
818
|
this.fromCodec(codec);
|
|
998
|
-
this.name = this.getCodecName(codec);
|
|
999
819
|
}
|
|
1000
820
|
|
|
1001
821
|
encode() {
|
|
1002
|
-
const codec =
|
|
822
|
+
const codec = varint.encode(this.decoded);
|
|
1003
823
|
this.encoded = codec;
|
|
1004
824
|
return this.encoded
|
|
1005
825
|
}
|
|
@@ -1025,18 +845,28 @@ class PeernetHash {
|
|
|
1025
845
|
|
|
1026
846
|
if (typeof buffer === 'string') {
|
|
1027
847
|
if (isHex(buffer)) this.fromHex(buffer);
|
|
1028
|
-
if (bs32.
|
|
1029
|
-
else this.fromBs58(buffer);
|
|
848
|
+
if (bs32.isBase32(buffer)) this.fromBs32(buffer);
|
|
849
|
+
else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
|
|
850
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
1030
851
|
} else if (typeof buffer === 'object') this.fromJSON(buffer);
|
|
1031
852
|
}
|
|
1032
853
|
}
|
|
1033
854
|
|
|
1034
855
|
get prefix() {
|
|
1035
|
-
|
|
856
|
+
const length = this.length;
|
|
857
|
+
const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length);
|
|
858
|
+
for (let i = 0; i < this.discoCodec.codecBuffer.length; i++) {
|
|
859
|
+
uint8Array[i] = this.discoCodec.codecBuffer[i];
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
for (let i = uint8Array.length - 1; i < length.length; i++) {
|
|
863
|
+
uint8Array[i] = length[i];
|
|
864
|
+
}
|
|
865
|
+
return uint8Array
|
|
1036
866
|
}
|
|
1037
867
|
|
|
1038
868
|
get length() {
|
|
1039
|
-
return
|
|
869
|
+
return varint.encode(this.size)
|
|
1040
870
|
}
|
|
1041
871
|
|
|
1042
872
|
get buffer() {
|
|
@@ -1153,25 +983,18 @@ class FormatInterface {
|
|
|
1153
983
|
constructor(buffer, proto, options = {}) {
|
|
1154
984
|
this.protoEncode = proto.encode;
|
|
1155
985
|
this.protoDecode = proto.decode;
|
|
1156
|
-
if (options.name) this.name = options.name;
|
|
1157
986
|
this.hashFormat = options.hashFormat || 'bs32';
|
|
1158
|
-
if (
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
this.fromEncoded(buffer);
|
|
1164
|
-
} else {
|
|
1165
|
-
this.create(buffer);
|
|
1166
|
-
}
|
|
1167
|
-
} else {
|
|
1168
|
-
if (typeof buffer === 'string') {
|
|
987
|
+
if (options.name) this.name = options.name;
|
|
988
|
+
if (buffer instanceof Uint8Array) return this.fromUint8Array(buffer)
|
|
989
|
+
else if (buffer instanceof ArrayBuffer) return this.fromArrayBuffer(buffer)
|
|
990
|
+
else if (buffer.name === options.name) return buffer
|
|
991
|
+
else if (typeof buffer === 'string') {
|
|
1169
992
|
if (isHex(buffer)) this.fromHex(buffer);
|
|
1170
|
-
else if (bs32.
|
|
1171
|
-
else this.fromBs58(buffer);
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
993
|
+
else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
|
|
994
|
+
else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
|
|
995
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
996
|
+
} else {
|
|
997
|
+
this.create(buffer);
|
|
1175
998
|
}
|
|
1176
999
|
}
|
|
1177
1000
|
|
|
@@ -1196,7 +1019,7 @@ class FormatInterface {
|
|
|
1196
1019
|
*/
|
|
1197
1020
|
decode() {
|
|
1198
1021
|
let encoded = this.encoded;
|
|
1199
|
-
const discoCodec = new PeernetCodec(this.encoded
|
|
1022
|
+
const discoCodec = new PeernetCodec(this.encoded);
|
|
1200
1023
|
encoded = encoded.slice(discoCodec.codecBuffer.length);
|
|
1201
1024
|
this.name = discoCodec.name;
|
|
1202
1025
|
this.decoded = this.protoDecode(encoded);
|
|
@@ -1209,16 +1032,40 @@ class FormatInterface {
|
|
|
1209
1032
|
encode(decoded) {
|
|
1210
1033
|
if (!decoded) decoded = this.decoded;
|
|
1211
1034
|
const codec = new PeernetCodec(this.name);
|
|
1212
|
-
|
|
1035
|
+
const encoded = this.protoEncode(decoded);
|
|
1036
|
+
const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length);
|
|
1037
|
+
uint8Array.set(codec.codecBuffer);
|
|
1038
|
+
uint8Array.set(encoded, codec.codecBuffer.length);
|
|
1039
|
+
this.encoded = uint8Array;
|
|
1213
1040
|
return this.encoded
|
|
1214
1041
|
}
|
|
1215
1042
|
|
|
1043
|
+
hasCodec() {
|
|
1044
|
+
if (!this.encoded) return false
|
|
1045
|
+
const codec = new PeernetCodec(this.encoded);
|
|
1046
|
+
if (codec.name) return true
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
fromUint8Array(buffer) {
|
|
1050
|
+
this.encoded = buffer;
|
|
1051
|
+
if (!this.hasCodec()) this.create(
|
|
1052
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
1053
|
+
);
|
|
1054
|
+
else this.decode();
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
fromArrayBuffer(buffer) {
|
|
1058
|
+
this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength);
|
|
1059
|
+
if (!this.hasCodec()) this.create(
|
|
1060
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
1061
|
+
);
|
|
1062
|
+
else this.decode();
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1216
1065
|
/**
|
|
1217
1066
|
* @param {Buffer} encoded
|
|
1218
1067
|
*/
|
|
1219
1068
|
fromEncoded(encoded) {
|
|
1220
|
-
const codec = new PeernetCodec(encoded);
|
|
1221
|
-
this.name = codec.name;
|
|
1222
1069
|
this.encoded = encoded;
|
|
1223
1070
|
this.decode();
|
|
1224
1071
|
}
|
|
@@ -1294,15 +1141,15 @@ class FormatInterface {
|
|
|
1294
1141
|
}
|
|
1295
1142
|
}
|
|
1296
1143
|
|
|
1297
|
-
class PeernetMessage extends FormatInterface {
|
|
1298
|
-
get keys() {
|
|
1299
|
-
return ['data', 'signature', 'from', 'to', 'id']
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
constructor(buffer) {
|
|
1303
|
-
const name = 'peernet-message';
|
|
1304
|
-
super(buffer, protons(proto$a).PeernetMessage, {name});
|
|
1305
|
-
}
|
|
1144
|
+
class PeernetMessage extends FormatInterface {
|
|
1145
|
+
get keys() {
|
|
1146
|
+
return ['data', 'signature', 'from', 'to', 'id']
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
constructor(buffer) {
|
|
1150
|
+
const name = 'peernet-message';
|
|
1151
|
+
super(buffer, protons(proto$a).PeernetMessage, {name});
|
|
1152
|
+
}
|
|
1306
1153
|
}
|
|
1307
1154
|
|
|
1308
1155
|
var proto$9 = `
|
|
@@ -1313,26 +1160,26 @@ message PeernetDHTMessage {
|
|
|
1313
1160
|
}
|
|
1314
1161
|
`;
|
|
1315
1162
|
|
|
1316
|
-
/**
|
|
1317
|
-
* @example `
|
|
1318
|
-
new DHTMessage(hash, store)
|
|
1319
|
-
// store = optional if not set, peernet checks every store
|
|
1320
|
-
let message = new DHTMessage('hashmvbs124xcfd...', 'transaction')
|
|
1321
|
-
message = new DHTMessage('hashmvbs124xcfd...', 'block')
|
|
1322
|
-
`
|
|
1323
|
-
*/
|
|
1324
|
-
class DHTMessage extends FormatInterface {
|
|
1325
|
-
/**
|
|
1326
|
-
*
|
|
1327
|
-
*/
|
|
1328
|
-
get keys() {
|
|
1329
|
-
return ['hash', 'store']
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
constructor(data) {
|
|
1333
|
-
const name = 'peernet-dht';
|
|
1334
|
-
super(data, protons(proto$9).PeernetDHTMessage, {name});
|
|
1335
|
-
}
|
|
1163
|
+
/**
|
|
1164
|
+
* @example `
|
|
1165
|
+
new DHTMessage(hash, store)
|
|
1166
|
+
// store = optional if not set, peernet checks every store
|
|
1167
|
+
let message = new DHTMessage('hashmvbs124xcfd...', 'transaction')
|
|
1168
|
+
message = new DHTMessage('hashmvbs124xcfd...', 'block')
|
|
1169
|
+
`
|
|
1170
|
+
*/
|
|
1171
|
+
class DHTMessage extends FormatInterface {
|
|
1172
|
+
/**
|
|
1173
|
+
*
|
|
1174
|
+
*/
|
|
1175
|
+
get keys() {
|
|
1176
|
+
return ['hash', 'store']
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
constructor(data) {
|
|
1180
|
+
const name = 'peernet-dht';
|
|
1181
|
+
super(data, protons(proto$9).PeernetDHTMessage, {name});
|
|
1182
|
+
}
|
|
1336
1183
|
}
|
|
1337
1184
|
|
|
1338
1185
|
var proto$8 = `
|
|
@@ -1362,19 +1209,19 @@ message PeernetDataMessage {
|
|
|
1362
1209
|
}
|
|
1363
1210
|
`;
|
|
1364
1211
|
|
|
1365
|
-
/**
|
|
1366
|
-
* @extends {CodecFormat}
|
|
1367
|
-
*/
|
|
1368
|
-
class DataMessage extends FormatInterface {
|
|
1369
|
-
get keys() {
|
|
1370
|
-
return ['hash', 'store']
|
|
1371
|
-
}
|
|
1372
|
-
/**
|
|
1373
|
-
* @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
|
|
1374
|
-
*/
|
|
1375
|
-
constructor(data) {
|
|
1376
|
-
super(data, protons(proto$7).PeernetDataMessage, {name: 'peernet-data'});
|
|
1377
|
-
}
|
|
1212
|
+
/**
|
|
1213
|
+
* @extends {CodecFormat}
|
|
1214
|
+
*/
|
|
1215
|
+
class DataMessage extends FormatInterface {
|
|
1216
|
+
get keys() {
|
|
1217
|
+
return ['hash', 'store']
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
|
|
1221
|
+
*/
|
|
1222
|
+
constructor(data) {
|
|
1223
|
+
super(data, protons(proto$7).PeernetDataMessage, {name: 'peernet-data'});
|
|
1224
|
+
}
|
|
1378
1225
|
}
|
|
1379
1226
|
|
|
1380
1227
|
var proto$6 = `
|
|
@@ -1384,15 +1231,15 @@ message PsMessage {
|
|
|
1384
1231
|
required bytes topic = 2;
|
|
1385
1232
|
}`;
|
|
1386
1233
|
|
|
1387
|
-
class PsMessage extends FormatInterface {
|
|
1388
|
-
get keys() {
|
|
1389
|
-
return ['data', 'topic']
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
constructor(buffer) {
|
|
1393
|
-
const name = 'peernet-ps';
|
|
1394
|
-
super(buffer, protons(proto$6).PsMessage, {name});
|
|
1395
|
-
}
|
|
1234
|
+
class PsMessage extends FormatInterface {
|
|
1235
|
+
get keys() {
|
|
1236
|
+
return ['data', 'topic']
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
constructor(buffer) {
|
|
1240
|
+
const name = 'peernet-ps';
|
|
1241
|
+
super(buffer, protons(proto$6).PsMessage, {name});
|
|
1242
|
+
}
|
|
1396
1243
|
}
|
|
1397
1244
|
|
|
1398
1245
|
var proto$5 = `
|
|
@@ -1402,15 +1249,15 @@ message PeernetPeerMessage {
|
|
|
1402
1249
|
}
|
|
1403
1250
|
`;
|
|
1404
1251
|
|
|
1405
|
-
class PeerMessage extends FormatInterface {
|
|
1406
|
-
get keys() {
|
|
1407
|
-
return ['id']
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
constructor(data) {
|
|
1411
|
-
const name = 'peernet-peer';
|
|
1412
|
-
super(data, protons(proto$5).PeernetPeerMessage, {name});
|
|
1413
|
-
}
|
|
1252
|
+
class PeerMessage extends FormatInterface {
|
|
1253
|
+
get keys() {
|
|
1254
|
+
return ['id']
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
constructor(data) {
|
|
1258
|
+
const name = 'peernet-peer';
|
|
1259
|
+
super(data, protons(proto$5).PeernetPeerMessage, {name});
|
|
1260
|
+
}
|
|
1414
1261
|
}
|
|
1415
1262
|
|
|
1416
1263
|
var proto$4 = `
|
|
@@ -1420,15 +1267,15 @@ message PeernetRequestMessage {
|
|
|
1420
1267
|
}
|
|
1421
1268
|
`;
|
|
1422
1269
|
|
|
1423
|
-
class RequestMessage extends FormatInterface {
|
|
1424
|
-
get keys() {
|
|
1425
|
-
return ['request']
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
constructor(data) {
|
|
1429
|
-
const name = 'peernet-request';
|
|
1430
|
-
super(data, protons(proto$4).PeernetRequestMessage, {name});
|
|
1431
|
-
}
|
|
1270
|
+
class RequestMessage extends FormatInterface {
|
|
1271
|
+
get keys() {
|
|
1272
|
+
return ['request']
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
constructor(data) {
|
|
1276
|
+
const name = 'peernet-request';
|
|
1277
|
+
super(data, protons(proto$4).PeernetRequestMessage, {name});
|
|
1278
|
+
}
|
|
1432
1279
|
}
|
|
1433
1280
|
|
|
1434
1281
|
var proto$3 = `
|
|
@@ -1438,15 +1285,15 @@ message PeernetResponseMessage {
|
|
|
1438
1285
|
}
|
|
1439
1286
|
`;
|
|
1440
1287
|
|
|
1441
|
-
class ResponseMessage extends FormatInterface {
|
|
1442
|
-
get keys() {
|
|
1443
|
-
return ['response']
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
constructor(data) {
|
|
1447
|
-
const name = 'peernet-response';
|
|
1448
|
-
super(data, protons(proto$3).PeernetResponseMessage, {name});
|
|
1449
|
-
}
|
|
1288
|
+
class ResponseMessage extends FormatInterface {
|
|
1289
|
+
get keys() {
|
|
1290
|
+
return ['response']
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
constructor(data) {
|
|
1294
|
+
const name = 'peernet-response';
|
|
1295
|
+
super(data, protons(proto$3).PeernetResponseMessage, {name});
|
|
1296
|
+
}
|
|
1450
1297
|
}
|
|
1451
1298
|
|
|
1452
1299
|
var proto$2 = `
|
|
@@ -1456,15 +1303,15 @@ message PeernetPeerMessageResponse {
|
|
|
1456
1303
|
}
|
|
1457
1304
|
`;
|
|
1458
1305
|
|
|
1459
|
-
class PeerMessageResponse extends FormatInterface {
|
|
1460
|
-
get keys() {
|
|
1461
|
-
return ['id']
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
constructor(data) {
|
|
1465
|
-
const name = 'peernet-peer-response';
|
|
1466
|
-
super(data, protons(proto$2).PeernetPeerMessageResponse, {name});
|
|
1467
|
-
}
|
|
1306
|
+
class PeerMessageResponse extends FormatInterface {
|
|
1307
|
+
get keys() {
|
|
1308
|
+
return ['id']
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
constructor(data) {
|
|
1312
|
+
const name = 'peernet-peer-response';
|
|
1313
|
+
super(data, protons(proto$2).PeernetPeerMessageResponse, {name});
|
|
1314
|
+
}
|
|
1468
1315
|
}
|
|
1469
1316
|
|
|
1470
1317
|
var proto$1 = `
|
|
@@ -1475,15 +1322,15 @@ message PeernetDataMessageResponse {
|
|
|
1475
1322
|
}
|
|
1476
1323
|
`;
|
|
1477
1324
|
|
|
1478
|
-
class DataMessageResponse extends FormatInterface {
|
|
1479
|
-
get keys() {
|
|
1480
|
-
return ['hash', 'data']
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
constructor(data) {
|
|
1484
|
-
const name = 'peernet-data-response';
|
|
1485
|
-
super(data, protons(proto$1).PeernetDataMessageResponse, {name});
|
|
1486
|
-
}
|
|
1325
|
+
class DataMessageResponse extends FormatInterface {
|
|
1326
|
+
get keys() {
|
|
1327
|
+
return ['hash', 'data']
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
constructor(data) {
|
|
1331
|
+
const name = 'peernet-data-response';
|
|
1332
|
+
super(data, protons(proto$1).PeernetDataMessageResponse, {name});
|
|
1333
|
+
}
|
|
1487
1334
|
}
|
|
1488
1335
|
|
|
1489
1336
|
var proto = `
|
|
@@ -1494,15 +1341,15 @@ message ChatMessage {
|
|
|
1494
1341
|
repeated string files = 4;
|
|
1495
1342
|
}`;
|
|
1496
1343
|
|
|
1497
|
-
class ChatMessage extends FormatInterface {
|
|
1498
|
-
get keys() {
|
|
1499
|
-
return ['author', 'value', 'timestamp', 'files']
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
constructor(buffer) {
|
|
1503
|
-
const name = 'chat-message';
|
|
1504
|
-
super(buffer, protons(proto).ChatMessage, {name});
|
|
1505
|
-
}
|
|
1344
|
+
class ChatMessage extends FormatInterface {
|
|
1345
|
+
get keys() {
|
|
1346
|
+
return ['author', 'value', 'timestamp', 'files']
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
constructor(buffer) {
|
|
1350
|
+
const name = 'chat-message';
|
|
1351
|
+
super(buffer, protons(proto).ChatMessage, {name});
|
|
1352
|
+
}
|
|
1506
1353
|
}
|
|
1507
1354
|
|
|
1508
1355
|
const debug = (log) => {
|
|
@@ -1524,7 +1371,7 @@ const protoFor = (data) => {
|
|
|
1524
1371
|
*/
|
|
1525
1372
|
const hasDaemon = async () => {
|
|
1526
1373
|
try {
|
|
1527
|
-
let response = await fetch
|
|
1374
|
+
let response = await fetch('http://127.0.0.1:1000/api/version');
|
|
1528
1375
|
response = await response.json();
|
|
1529
1376
|
return Boolean(response.client === '@peernet/api/http')
|
|
1530
1377
|
} catch (e) {
|
|
@@ -1660,7 +1507,7 @@ const getAddress = async () => {
|
|
|
1660
1507
|
const {address} = lastFetched;
|
|
1661
1508
|
const now = Math.round(new Date().getTime() / 1000);
|
|
1662
1509
|
if (now - address.timestamp > 1200000) {
|
|
1663
|
-
address.value = await fetch
|
|
1510
|
+
address.value = await fetch('https://icanhazip.com/');
|
|
1664
1511
|
address.value = await address.value.text();
|
|
1665
1512
|
address.timestamp = Math.round(new Date().getTime() / 1000);
|
|
1666
1513
|
lastFetched.address = address;
|
|
@@ -1702,7 +1549,7 @@ class DhtEarth {
|
|
|
1702
1549
|
async getCoordinates(address) {
|
|
1703
1550
|
// const {address} = parseAddress(provider)
|
|
1704
1551
|
const request = `https://whereis.leofcoin.org/?ip=${address}`;
|
|
1705
|
-
let response = await fetch
|
|
1552
|
+
let response = await fetch(request);
|
|
1706
1553
|
response = await response.json();
|
|
1707
1554
|
const {lat, lon} = response;
|
|
1708
1555
|
return {latitude: lat, longitude: lon}
|
|
@@ -1760,93 +1607,441 @@ class DhtEarth {
|
|
|
1760
1607
|
}
|
|
1761
1608
|
}
|
|
1762
1609
|
|
|
1610
|
+
var testnets = {
|
|
1611
|
+
'leofcoin:olivia': {
|
|
1612
|
+
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
1613
|
+
pubKeyHash: 0x73, // o
|
|
1614
|
+
scriptHash: 0x76, // p
|
|
1615
|
+
multiTxHash: 0x8b4125, // omtx
|
|
1616
|
+
payments: {
|
|
1617
|
+
version: 0,
|
|
1618
|
+
unspent: 0x1fa443d7 // ounsp
|
|
1619
|
+
},
|
|
1620
|
+
wif: 0x7D, // s
|
|
1621
|
+
multiCodec: 0x7c4,
|
|
1622
|
+
bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
|
|
1623
|
+
},
|
|
1624
|
+
'bitcoin:testnet': {
|
|
1625
|
+
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
1626
|
+
bech32: 'tb',
|
|
1627
|
+
pubKeyHash: 0x6f,
|
|
1628
|
+
scriptHash: 0xc4,
|
|
1629
|
+
wif: 0xef,
|
|
1630
|
+
bip32: {
|
|
1631
|
+
public: 0x043587cf,
|
|
1632
|
+
private: 0x04358394
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
};
|
|
1637
|
+
|
|
1638
|
+
// https://en.bitcoin.it/wiki/List_of_address_prefixes
|
|
1763
1639
|
/**
|
|
1764
|
-
*
|
|
1765
|
-
* @return {
|
|
1640
|
+
* Main network
|
|
1641
|
+
* @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
|
|
1766
1642
|
*/
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1643
|
+
const leofcoin = {
|
|
1644
|
+
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
1645
|
+
pubKeyHash: 0x30, // L
|
|
1646
|
+
scriptHash: 0x37, // P
|
|
1647
|
+
multiTxHash: 0x3adeed, // Lmtx
|
|
1648
|
+
payments: {
|
|
1649
|
+
version: 0,
|
|
1650
|
+
unspent: 0x0d6e0327 // Lunsp
|
|
1651
|
+
},
|
|
1652
|
+
coin_type: 640,
|
|
1653
|
+
wif: 0x3F, // S
|
|
1654
|
+
multiCodec: 0x3c4,
|
|
1655
|
+
bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
|
|
1656
|
+
testnet: testnets['leofcoin:olivia']
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
const bitcoin = {
|
|
1660
|
+
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
1661
|
+
bech32: 'bc',
|
|
1662
|
+
pubKeyHash: 0x00,
|
|
1663
|
+
scriptHash: 0x05,
|
|
1664
|
+
wif: 0x80,
|
|
1665
|
+
coin_type: 0,
|
|
1666
|
+
bip32: {
|
|
1667
|
+
public: 0x0488b21e, private: 0x0488ade4
|
|
1668
|
+
},
|
|
1669
|
+
testnet: testnets['bitcoin:testnet']
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
const litecoin = {
|
|
1673
|
+
messagePrefix: '\x19Litecoin Signed Message:\n',
|
|
1674
|
+
pubKeyHash: 0x30,
|
|
1675
|
+
scriptHash: 0x32,
|
|
1676
|
+
wif: 0xb0,
|
|
1677
|
+
bip32: {
|
|
1678
|
+
public: 0x019da462,
|
|
1679
|
+
private: 0x019d9cfe
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
const ethereum = {
|
|
1684
|
+
messagePrefix: '\x19Ethereum Signed Message:\n',
|
|
1685
|
+
pubKeyHash: 0x30,
|
|
1686
|
+
scriptHash: 0x32,
|
|
1687
|
+
bip32: {
|
|
1688
|
+
private: 0x0488ADE4, public: 0x0488B21E
|
|
1689
|
+
},
|
|
1690
|
+
coin_type: 60,
|
|
1691
|
+
wif: 0x45,//E
|
|
1692
|
+
multiCodec: 0x3c5
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* Our & supported networks
|
|
1697
|
+
* @return {leofcoin, olivia}
|
|
1698
|
+
*/
|
|
1699
|
+
var networks = {
|
|
1700
|
+
leofcoin,
|
|
1701
|
+
bitcoin,
|
|
1702
|
+
litecoin,
|
|
1703
|
+
ethereum
|
|
1704
|
+
};
|
|
1802
1705
|
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
* @param {string} message.data Peernet message
|
|
1814
|
-
* (PeernetMessage excluded) encoded as a string
|
|
1815
|
-
* @return signature
|
|
1816
|
-
*/
|
|
1817
|
-
async hashAndSignMessage(message) {
|
|
1818
|
-
const hasher = new PeernetHash(message, {name: 'peernet-message'});
|
|
1819
|
-
const identity = await walletStore.get('identity');
|
|
1706
|
+
const fromNetworkString = network => {
|
|
1707
|
+
const parts = network.split(':');
|
|
1708
|
+
network = networks[parts[0]];
|
|
1709
|
+
if (parts[1]) {
|
|
1710
|
+
if (network[parts[1]]) network = network[parts[1]];
|
|
1711
|
+
|
|
1712
|
+
network.coin_type = 1;
|
|
1713
|
+
}
|
|
1714
|
+
return network;
|
|
1715
|
+
};
|
|
1820
1716
|
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1717
|
+
const { encode: encode$1, decode: decode$1 } = bs58check__default;
|
|
1718
|
+
class HDWallet {
|
|
1719
|
+
|
|
1720
|
+
get chainCodeBuffer() {
|
|
1721
|
+
return this.ifNotLocked(() => this.hdnode.chainCode)
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
get chainCode() {
|
|
1725
|
+
return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
get privateKeyBuffer() {
|
|
1729
|
+
return this.ifNotLocked(() => this.hdnode.privateKey)
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
get privateKey() {
|
|
1733
|
+
return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
get publicKeyBuffer() {
|
|
1737
|
+
return this.ifNotLocked(() => this.hdnode.publicKey)
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
get publicKey() {
|
|
1741
|
+
return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
get address() {
|
|
1745
|
+
// override testnet coin_type
|
|
1746
|
+
let coin_type = this.hdnode.network.coin_type;
|
|
1747
|
+
if (coin_type === 1) {
|
|
1748
|
+
if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
|
|
1749
|
+
if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
|
|
1750
|
+
}
|
|
1751
|
+
if (coin_type === 60 || coin_type === 640) {
|
|
1752
|
+
let buffer = ecc.pointFromScalar(this.hdnode.__D, false);
|
|
1753
|
+
buffer = Buffer.from(publicKeyConvert(buffer, false)).slice(1);
|
|
1754
|
+
let hash = createKeccakHash('keccak256').update(buffer).digest();
|
|
1755
|
+
return hash.slice(-20).toString('hex')
|
|
1756
|
+
}
|
|
1757
|
+
return encode$1(this.neutered.publicKeyBuffer)
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
get accountAddress() {
|
|
1761
|
+
return this.ifNotLocked(() => encode$1(this.hdnode.publicKeyBuffer))
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
get isTestnet() {
|
|
1765
|
+
if (typeof network === 'string')
|
|
1766
|
+
this.hdnode.network = fromNetworkString(network);
|
|
1767
|
+
|
|
1768
|
+
return Boolean(this.hdnode.network.coin_type === 1)
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
constructor(network, hdnode) {
|
|
1772
|
+
if (typeof network === 'string') {
|
|
1773
|
+
this.networkName = network;
|
|
1774
|
+
this.network = fromNetworkString(network);
|
|
1775
|
+
} else if (typeof network === 'object')
|
|
1776
|
+
this.network = network;
|
|
1777
|
+
|
|
1778
|
+
if (hdnode) this.defineHDNode(hdnode);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
ifNotLocked(fn, params) {
|
|
1782
|
+
if (!this.locked) return fn(params);
|
|
1783
|
+
return null
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
defineHDNode(value) {
|
|
1787
|
+
Object.defineProperty(this, 'hdnode', {
|
|
1788
|
+
configurable: false,
|
|
1789
|
+
writable: false,
|
|
1790
|
+
value: value
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
validateNetwork(network) {
|
|
1795
|
+
if (!network && !this.network) return console.error(`expected network to be defined`);
|
|
1796
|
+
if (!network && this.network) network = this.network;
|
|
1797
|
+
if (typeof network === 'string') network = fromNetworkString(network);
|
|
1798
|
+
if (typeof network !== 'object') return console.error('network not found');
|
|
1799
|
+
return network;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
async generate(network) {
|
|
1803
|
+
network = this.validateNetwork(network);
|
|
1804
|
+
const mnemonic = generateMnemonic();
|
|
1805
|
+
const seed = await mnemonicToSeed(mnemonic);
|
|
1806
|
+
this.defineHDNode(bip32.fromSeed(seed, network));
|
|
1807
|
+
return mnemonic; // userpw
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* recover using mnemonic (recovery word list)
|
|
1812
|
+
*/
|
|
1813
|
+
async recover(mnemonic, network) {
|
|
1814
|
+
network = this.validateNetwork(network);
|
|
1815
|
+
const seed = await mnemonicToSeed(mnemonic);
|
|
1816
|
+
this.defineHDNode(bip32.fromSeed(seed, network));
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
load(base58, network) {
|
|
1820
|
+
network = this.validateNetwork(network);
|
|
1821
|
+
this.defineHDNode(bip32.fromBase58(base58, network));
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
save() {
|
|
1825
|
+
return this.hdnode.toBase58();
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
fromAddress(address, chainCode, network) {
|
|
1829
|
+
network = this.validateNetwork(network);
|
|
1830
|
+
// if (network.coin_type === 60) {
|
|
1831
|
+
// address = Buffer.from(address, 'hex')
|
|
1832
|
+
// } else {
|
|
1833
|
+
address = decode$1(address);
|
|
1834
|
+
// }
|
|
1835
|
+
|
|
1836
|
+
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
|
|
1837
|
+
this.defineHDNode(bip32.fromPublicKey(address, chainCode, network));
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
fromPublicKey(hex, chainCode, network) {
|
|
1841
|
+
network = this.validateNetwork(network);
|
|
1842
|
+
if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
|
|
1843
|
+
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
|
|
1844
|
+
this.defineHDNode(bip32.fromPublicKey(hex, chainCode, network));
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1825
1847
|
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1848
|
+
const { encode, decode } = bs58check;
|
|
1849
|
+
|
|
1850
|
+
// TODO: multihash addresses
|
|
1851
|
+
class HDAccount {
|
|
1852
|
+
/**
|
|
1853
|
+
* @param {number} depth - acount depth
|
|
1854
|
+
*/
|
|
1855
|
+
constructor(node, depth = 0) {
|
|
1856
|
+
this.node = node;
|
|
1857
|
+
this.depth = depth;
|
|
1858
|
+
this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
/**
|
|
1862
|
+
* @param {number} index - address index
|
|
1863
|
+
*/
|
|
1864
|
+
internal(index = 0) {
|
|
1865
|
+
return this.node.derivePath(`${this._prefix}1/${index}`)
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* @param {number} index - address index
|
|
1870
|
+
*/
|
|
1871
|
+
external(index = 0) {
|
|
1872
|
+
return this.node.derivePath(`${this._prefix}0/${index}`)
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
class MultiWallet extends HDWallet {
|
|
1877
|
+
constructor(network, hdnode) {
|
|
1878
|
+
const networkName = network;
|
|
1879
|
+
super(network, hdnode);
|
|
1880
|
+
if (typeof networkName === 'string') this.networkName = networkName;
|
|
1881
|
+
this.multiCodec = this.network.multiCodec;
|
|
1882
|
+
this.version = 0x00;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
get id() {
|
|
1886
|
+
const buffer = Buffer.concat([
|
|
1887
|
+
Buffer.from(varint.encode(this.multiCodec)),
|
|
1888
|
+
Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
|
|
1889
|
+
]);
|
|
1890
|
+
return encode(buffer)
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
get multiWIF() {
|
|
1894
|
+
return this.ifNotLocked(() => this.encode())
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
get neutered() {
|
|
1898
|
+
const neutered = this.ifNotLocked(() => new MultiWallet(this.network, this.hdnode.neutered()));
|
|
1899
|
+
if (neutered) this._neutered = neutered;
|
|
1900
|
+
return this._neutered
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
fromId(id) {
|
|
1904
|
+
let buffer = decode(id);
|
|
1905
|
+
varint.decode(buffer);
|
|
1906
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
1907
|
+
this.fromPublicKey(buffer, null, this.network);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
lock(key, multiWIF) {
|
|
1911
|
+
if (!multiWIF) multiWIF = this.multiWIF;
|
|
1912
|
+
this.encrypted = AES.encrypt(multiWIF.toString('hex'), key).toString();
|
|
1913
|
+
this.locked = true;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
unlock(key, encrypted) {
|
|
1917
|
+
if (!encrypted) encrypted = this.encrypted;
|
|
1918
|
+
this.import(AES.decrypt(encrypted, key).toString(ENC));
|
|
1919
|
+
this.locked = false;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
export() {
|
|
1923
|
+
return this.encode();
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* encodes the multiWIF and loads wallet from bs58
|
|
1928
|
+
*
|
|
1929
|
+
* @param {multiWIF} multiWIF - note a multiWIF is not the same as a wif
|
|
1930
|
+
*/
|
|
1931
|
+
import(multiWIF) {
|
|
1932
|
+
const { bs58, version, multiCodec } = this.decode(multiWIF);
|
|
1933
|
+
this.network = Object.values(networks).reduce((p, c) => {
|
|
1934
|
+
if (c.multiCodec===multiCodec) return c
|
|
1935
|
+
else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
|
|
1936
|
+
else return p
|
|
1937
|
+
}, networks['leofcoin']);
|
|
1938
|
+
this.load(bs58, this.network);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
/**
|
|
1942
|
+
* @return base58Check encoded string
|
|
1943
|
+
*/
|
|
1944
|
+
encode() {
|
|
1945
|
+
const buffer = Buffer.concat([
|
|
1946
|
+
Buffer.from(varint.encode(this.version)),
|
|
1947
|
+
Buffer.from(varint.encode(this.multiCodec)),
|
|
1948
|
+
decode(this.save())
|
|
1949
|
+
]);
|
|
1950
|
+
return encode(buffer);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
decode(bs58) {
|
|
1954
|
+
let buffer = decode(bs58);
|
|
1955
|
+
const version = varint.decode(buffer);
|
|
1956
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
1957
|
+
const multiCodec = varint.decode(buffer);
|
|
1958
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
1959
|
+
bs58 = encode(buffer);
|
|
1960
|
+
if (version !== this.version) throw TypeError('Invalid version');
|
|
1961
|
+
if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
|
|
1962
|
+
return { version, multiCodec, bs58 };
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
sign(hash) {
|
|
1966
|
+
return new MultiSignature(this.version, this.network.multiCodec)
|
|
1967
|
+
.sign(hash, this.privateKeyBuffer);
|
|
1968
|
+
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
verify(multiSignature, hash) {
|
|
1972
|
+
return new MultiSignature(this.version, this.network.multiCodec)
|
|
1973
|
+
.verify(multiSignature, hash, this.publicKeyBuffer)
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* @param {number} account - account to return chain for
|
|
1978
|
+
* @return { internal(addressIndex), external(addressIndex) }
|
|
1979
|
+
*/
|
|
1980
|
+
account(index) {
|
|
1981
|
+
return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* m / purpose' / coin_type' / account' / change / aadress_index
|
|
1986
|
+
*
|
|
1987
|
+
* see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
|
1988
|
+
*/
|
|
1989
|
+
derivePath(path) {
|
|
1990
|
+
return new MultiWallet(this.network, this.hdnode.derivePath(path))
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
derive(index) {
|
|
1994
|
+
return new MultiWallet(this.network, this.hdnode.derive(index));
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1847
1997
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1998
|
+
class MessageHandler {
|
|
1999
|
+
constructor(network) {
|
|
2000
|
+
this.network = network;
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* hash and sign message
|
|
2004
|
+
*
|
|
2005
|
+
* @param {object} message
|
|
2006
|
+
* @param {Buffer} message.from peer id
|
|
2007
|
+
* @param {Buffer} message.to peer id
|
|
2008
|
+
* @param {string} message.data Peernet message
|
|
2009
|
+
* (PeernetMessage excluded) encoded as a string
|
|
2010
|
+
* @return signature
|
|
2011
|
+
*/
|
|
2012
|
+
async hashAndSignMessage(message) {
|
|
2013
|
+
const hasher = new PeernetHash(message, {name: 'peernet-message'});
|
|
2014
|
+
const identity = await walletStore.get('identity');
|
|
2015
|
+
|
|
2016
|
+
const wallet = new MultiWallet(this.network);
|
|
2017
|
+
wallet.import(identity.multiWIF);
|
|
2018
|
+
return wallet.sign(hasher.hash.slice(0, 32))
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* @param {String} from - peer id
|
|
2023
|
+
* @param {String} to - peer id
|
|
2024
|
+
* @param {String|PeernetMessage} data - data encoded message string
|
|
2025
|
+
* or the messageNode itself
|
|
2026
|
+
*/
|
|
2027
|
+
async prepareMessage(from, to, data, id) {
|
|
2028
|
+
if (!Buffer.isBuffer(from)) from = new Buffer.from(from);
|
|
2029
|
+
if (!Buffer.isBuffer(to)) to = new Buffer.from(to);
|
|
2030
|
+
if (data.encoded) data = data.encoded;
|
|
2031
|
+
|
|
2032
|
+
const message = {
|
|
2033
|
+
from,
|
|
2034
|
+
to,
|
|
2035
|
+
data,
|
|
2036
|
+
};
|
|
2037
|
+
const signature = await this.hashAndSignMessage(message);
|
|
2038
|
+
const node = new PeernetMessage({
|
|
2039
|
+
...message,
|
|
2040
|
+
signature,
|
|
2041
|
+
});
|
|
2042
|
+
|
|
2043
|
+
return node
|
|
2044
|
+
}
|
|
1850
2045
|
}
|
|
1851
2046
|
|
|
1852
2047
|
const encapsulatedError = () => {
|
|
@@ -1925,7 +2120,7 @@ class Peernet {
|
|
|
1925
2120
|
if (this.hasDaemon) {
|
|
1926
2121
|
Storage = LeofcoinStorageClient;
|
|
1927
2122
|
} else {
|
|
1928
|
-
Storage = LeofcoinStorage
|
|
2123
|
+
Storage = LeofcoinStorage;
|
|
1929
2124
|
}
|
|
1930
2125
|
globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
|
|
1931
2126
|
await new Storage(`${prefix}-${name}`, root);
|
|
@@ -2007,13 +2202,7 @@ class Peernet {
|
|
|
2007
2202
|
const {daemon, environment} = await target();
|
|
2008
2203
|
this.hasDaemon = daemon;
|
|
2009
2204
|
|
|
2010
|
-
|
|
2011
|
-
globalThis.peernet.client = await httpClient({
|
|
2012
|
-
protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port,
|
|
2013
|
-
});
|
|
2014
|
-
} else {
|
|
2015
|
-
if (environment !== 'browser') http(options);
|
|
2016
|
-
}
|
|
2205
|
+
HTTP_IMPORT;
|
|
2017
2206
|
|
|
2018
2207
|
for (const store of this.defaultStores) {
|
|
2019
2208
|
await this.addStore(store, options.storePrefix, options.root);
|
|
@@ -2039,42 +2228,41 @@ class Peernet {
|
|
|
2039
2228
|
}
|
|
2040
2229
|
}
|
|
2041
2230
|
this._peerHandler = new PeerDiscovery(this.id);
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
else this.peerMap.set(id, peerIds);
|
|
2075
|
-
});
|
|
2231
|
+
this.peerId = this.id;
|
|
2232
|
+
|
|
2233
|
+
// pubsub.subscribe('peer:discovered', async (peer) => {
|
|
2234
|
+
// peer.on('peernet.data', async (message) => {
|
|
2235
|
+
// const id = message.id;
|
|
2236
|
+
// message = new PeernetMessage(Buffer.from(message.data.data));
|
|
2237
|
+
// const proto = protoFor(message.decoded.data);
|
|
2238
|
+
// await this._protoHandler({id, proto}, peer);
|
|
2239
|
+
// });
|
|
2240
|
+
// await this._peerHandler.discover(peer);
|
|
2241
|
+
// const fulldId = this._getPeerId(peer.id);
|
|
2242
|
+
// if (fulldId && this._discovered.indexOf(peer.id) === -1) {
|
|
2243
|
+
// this._discovered.push(peer.id);
|
|
2244
|
+
// pubsub.publish('peer:connected', peer);
|
|
2245
|
+
// }
|
|
2246
|
+
// });
|
|
2247
|
+
// pubsub.subscribe('peer:disconnected', async (peer) => {
|
|
2248
|
+
// let index = this._discovered.indexOf(peer.id)
|
|
2249
|
+
// if (index !== -1) this._discovered.splice(index, 1)
|
|
2250
|
+
// const id = this._getPeerId(peer.id)
|
|
2251
|
+
// let peerIds = this.peerMap.get(id)
|
|
2252
|
+
//
|
|
2253
|
+
// if (peerIds) {
|
|
2254
|
+
// index = peerIds.indexOf(peer.id)
|
|
2255
|
+
// if (index !== -1) peerIds.splice(index, 1)
|
|
2256
|
+
// } else {
|
|
2257
|
+
// peerIds = []
|
|
2258
|
+
// }
|
|
2259
|
+
//
|
|
2260
|
+
// if (peerIds.length === 0) this.peerMap.delete(id)
|
|
2261
|
+
// else this.peerMap.set(id, peerIds)
|
|
2262
|
+
// })
|
|
2076
2263
|
pubsub.subscribe('peer:connected', async (peer) => {
|
|
2077
|
-
console.log(
|
|
2264
|
+
console.log(peer);
|
|
2265
|
+
// console.log({connected: peer.id, as: this._getPeerId(peer.id) });
|
|
2078
2266
|
// peer.on('peernet.data', async (message) => {
|
|
2079
2267
|
// const id = message.id
|
|
2080
2268
|
// message = new PeernetMessage(Buffer.from(message.data.data))
|
|
@@ -2083,11 +2271,27 @@ class Peernet {
|
|
|
2083
2271
|
// })
|
|
2084
2272
|
});
|
|
2085
2273
|
|
|
2274
|
+
pubsub.subscribe('peer:data', async message => {
|
|
2275
|
+
console.log({message});
|
|
2276
|
+
if (!message.data) return
|
|
2277
|
+
const {id, data} = JSON.parse(new TextDecoder().decode(message.data));
|
|
2278
|
+
const uint8Array = new Uint8Array(Object.keys(data).length);
|
|
2279
|
+
for (var i = 0; i < Object.keys(data).length; i++) {
|
|
2280
|
+
uint8Array[i] = data[i];
|
|
2281
|
+
}
|
|
2282
|
+
message = new PeernetMessage(uint8Array);
|
|
2283
|
+
const proto = protoFor(message.decoded.data);
|
|
2284
|
+
|
|
2285
|
+
console.log(message.decoded);
|
|
2286
|
+
const from = new TextDecoder().decode(message.decoded.from);
|
|
2287
|
+
this._protoHandler({id, proto}, this.client.connections[from], from);
|
|
2288
|
+
});
|
|
2289
|
+
|
|
2086
2290
|
/**
|
|
2087
2291
|
* @access public
|
|
2088
2292
|
* @type {PeernetClient}
|
|
2089
2293
|
*/
|
|
2090
|
-
this.client = new
|
|
2294
|
+
this.client = new Client(this.id);
|
|
2091
2295
|
if (globalThis.onbeforeunload) {
|
|
2092
2296
|
globalThis.addEventListener('beforeunload', async () => this.client.close());
|
|
2093
2297
|
}
|
|
@@ -2112,55 +2316,56 @@ class Peernet {
|
|
|
2112
2316
|
* @param {Buffer} message - peernet message
|
|
2113
2317
|
* @param {PeernetPeer} peer - peernet peer
|
|
2114
2318
|
*/
|
|
2115
|
-
async _protoHandler(message, peer) {
|
|
2319
|
+
async _protoHandler(message, peer, from) {
|
|
2116
2320
|
const {id, proto} = message;
|
|
2321
|
+
console.log(message);
|
|
2117
2322
|
this.bw.down += proto.encoded.length;
|
|
2118
|
-
if (proto.name === 'peernet-peer') {
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
} else if (proto.name === 'peernet-peer-response') {
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
} else {
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2323
|
+
// if (proto.name === 'peernet-peer') {
|
|
2324
|
+
// const from = proto.decoded.id
|
|
2325
|
+
// if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
|
|
2326
|
+
// else {
|
|
2327
|
+
// const connections = this.peerMap.get(from)
|
|
2328
|
+
// if (connections.indexOf(peer.id) === -1) {
|
|
2329
|
+
// connections.push(peer.id)
|
|
2330
|
+
// this.peerMap.set(from, connections)
|
|
2331
|
+
// }
|
|
2332
|
+
// }
|
|
2333
|
+
// const data = new PeerMessageResponse({id: this.id})
|
|
2334
|
+
// const node = await this.prepareMessage(from, data.encoded)
|
|
2335
|
+
//
|
|
2336
|
+
// peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})))
|
|
2337
|
+
// this.bw.up += node.encoded.length
|
|
2338
|
+
// } else if (proto.name === 'peernet-peer-response') {
|
|
2339
|
+
// const from = proto.decoded.id
|
|
2340
|
+
// if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
|
|
2341
|
+
// else {
|
|
2342
|
+
// const connections = this.peerMap.get(from)
|
|
2343
|
+
// if (connections.indexOf(peer.id) === -1) {
|
|
2344
|
+
// connections.push(peer.id)
|
|
2345
|
+
// this.peerMap.set(from, connections)
|
|
2346
|
+
// }
|
|
2347
|
+
// }
|
|
2348
|
+
// } else {
|
|
2349
|
+
// let from = this._getPeerId(peer.id)
|
|
2350
|
+
// if (!from) {
|
|
2351
|
+
// const data = new PeerMessage({id: this.id})
|
|
2352
|
+
// const node = await this.prepareMessage(peer.id, data.encoded)
|
|
2353
|
+
// this.bw.up += node.encoded.length
|
|
2354
|
+
// let response = await peer.request(node.encoded)
|
|
2355
|
+
// response = protoFor(response)
|
|
2356
|
+
//
|
|
2357
|
+
// response = new PeerMessageResponse(response.decoded.data)
|
|
2358
|
+
//
|
|
2359
|
+
// from = response.decoded.id
|
|
2360
|
+
// if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
|
|
2361
|
+
// else {
|
|
2362
|
+
// const connections = this.peerMap.get(from)
|
|
2363
|
+
// if (connections.indexOf(peer.id) === -1) {
|
|
2364
|
+
// connections.push(peer.id)
|
|
2365
|
+
// this.peerMap.set(from, connections)
|
|
2366
|
+
// }
|
|
2367
|
+
// }
|
|
2368
|
+
// }
|
|
2164
2369
|
if (proto.name === 'peernet-dht') {
|
|
2165
2370
|
let { hash, store } = proto.decoded;
|
|
2166
2371
|
let has;
|
|
@@ -2175,7 +2380,7 @@ class Peernet {
|
|
|
2175
2380
|
const data = new DHTMessageResponse({hash, has});
|
|
2176
2381
|
const node = await this.prepareMessage(from, data.encoded);
|
|
2177
2382
|
|
|
2178
|
-
peer.
|
|
2383
|
+
peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
|
|
2179
2384
|
this.bw.up += node.encoded.length;
|
|
2180
2385
|
} else if (proto.name === 'peernet-data') {
|
|
2181
2386
|
let { hash, store } = proto.decoded;
|
|
@@ -2183,7 +2388,7 @@ class Peernet {
|
|
|
2183
2388
|
if (!store) {
|
|
2184
2389
|
store = await this.whichStore([...this.stores], hash);
|
|
2185
2390
|
} else {
|
|
2186
|
-
store = globalThis
|
|
2391
|
+
store = globalThis[`${store}Store`];
|
|
2187
2392
|
}
|
|
2188
2393
|
if (store && !store.private) {
|
|
2189
2394
|
data = await store.get(hash);
|
|
@@ -2192,7 +2397,7 @@ class Peernet {
|
|
|
2192
2397
|
data = new DataMessageResponse({hash, data: data.decoded ? Buffer.from(JSON.stringify(data)) : Buffer.from(data)});
|
|
2193
2398
|
|
|
2194
2399
|
const node = await this.prepareMessage(from, data.encoded);
|
|
2195
|
-
peer.
|
|
2400
|
+
peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
|
|
2196
2401
|
this.bw.up += node.encoded.length;
|
|
2197
2402
|
}
|
|
2198
2403
|
}
|
|
@@ -2208,7 +2413,7 @@ class Peernet {
|
|
|
2208
2413
|
const data = new PeerMessage({id: this.id});
|
|
2209
2414
|
const node = await this.prepareMessage(from, data.encoded);
|
|
2210
2415
|
|
|
2211
|
-
peer.
|
|
2416
|
+
peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
|
|
2212
2417
|
this.bw.up += node.encoded.length;
|
|
2213
2418
|
} else if (proto.name === 'peernet-request') {
|
|
2214
2419
|
// TODO: make dynamic
|
|
@@ -2217,14 +2422,14 @@ class Peernet {
|
|
|
2217
2422
|
if (method) {
|
|
2218
2423
|
const data = await method();
|
|
2219
2424
|
const node = await this.prepareMessage(from, data.encoded);
|
|
2220
|
-
peer.
|
|
2425
|
+
peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
|
|
2221
2426
|
this.bw.up += node.encoded.length;
|
|
2222
2427
|
}
|
|
2223
2428
|
} else if (proto.name === 'peernet-ps' &&
|
|
2224
2429
|
this._getPeerId(peer.id) !== this.id.toString()) {
|
|
2225
2430
|
globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
|
|
2226
2431
|
}
|
|
2227
|
-
}
|
|
2432
|
+
// }
|
|
2228
2433
|
}
|
|
2229
2434
|
|
|
2230
2435
|
/**
|
|
@@ -2339,7 +2544,7 @@ class Peernet {
|
|
|
2339
2544
|
if (this._getPeerId(peer.id) === id) return peer
|
|
2340
2545
|
});
|
|
2341
2546
|
|
|
2342
|
-
let data = new DataMessage({hash, store});
|
|
2547
|
+
let data = new DataMessage({hash, store: store.name ? store.name : store});
|
|
2343
2548
|
|
|
2344
2549
|
const node = await this.prepareMessage(id, data.encoded);
|
|
2345
2550
|
if (closest[0]) data = await closest[0].request(node.encoded);
|
|
@@ -2489,7 +2694,7 @@ class Peernet {
|
|
|
2489
2694
|
if (peer.connection._connected) {
|
|
2490
2695
|
if (peer.id.toString() !== this.peerId.toString()) {
|
|
2491
2696
|
const node = await this.prepareMessage(peer.id, data.encoded);
|
|
2492
|
-
peer.
|
|
2697
|
+
peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
|
|
2493
2698
|
}
|
|
2494
2699
|
} else {
|
|
2495
2700
|
this.removePeer(peer);
|