@leofcoin/peernet 0.11.14 → 0.11.17

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- /* socket-request-client version 1.6.1 */
3
+ /* socket-request-client version 1.6.3 */
4
4
 
5
5
  class LittlePubSub {
6
6
  constructor(verbose = true) {
@@ -187,9 +187,6 @@ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry
187
187
  peernet: api.peernet(client),
188
188
  server: api.server(client),
189
189
  close: exit => {
190
- client.onclose = message => {
191
- if (exit) process.exit();
192
- };
193
190
  client.close();
194
191
  }
195
192
  }
@@ -25,14 +25,14 @@ class FormatInterface {
25
25
  this.protoDecode = proto.decode;
26
26
  this.hashFormat = options.hashFormat || 'bs32';
27
27
  if (options.name) this.name = options.name;
28
- if (buffer instanceof Uint8Array) return this.fromUint8Array(buffer)
29
- else if (buffer instanceof ArrayBuffer) return this.fromArrayBuffer(buffer)
28
+ if (buffer instanceof Uint8Array) this.fromUint8Array(buffer);
29
+ else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer);
30
30
  else if (buffer.name === options.name) return buffer
31
- else if (typeof buffer === 'string') {
32
- if (isHex__default["default"](buffer)) this.fromHex(buffer);
33
- else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
34
- else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
35
- else throw new Error(`unsupported string ${buffer}`)
31
+ else if (buffer instanceof String) {
32
+ if (isHex__default["default"](buffer)) this.fromHex(buffer);
33
+ else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
34
+ else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
35
+ else throw new Error(`unsupported string ${buffer}`)
36
36
  } else {
37
37
  this.create(buffer);
38
38
  }
@@ -10,7 +10,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
10
10
  var PubSub__default = /*#__PURE__*/_interopDefaultLegacy(PubSub);
11
11
  var Koa__default = /*#__PURE__*/_interopDefaultLegacy(Koa);
12
12
 
13
- var version = "0.11.13";
13
+ var version = "0.11.16";
14
14
 
15
15
  var api$1 = {
16
16
  version: ({send}) => send({client: '@peernet/api/http', version}),
@@ -12,18 +12,15 @@ var response = require('./response.js');
12
12
  var fetch = require('node-fetch');
13
13
  var codec = require('./codec-45796010.js');
14
14
  var hash = require('./hash.js');
15
- var generateAccount = require('@leofcoin/generate-account');
15
+ var MultiWallet$1 = require('@leofcoin/multi-wallet');
16
16
  var bs58check = require('bs58check');
17
- var bip39 = require('bip39');
18
17
  var bip32 = require('bip32');
19
18
  var createKeccakHash = require('keccak');
20
- var secp256k1 = require('secp256k1');
21
19
  var ecc = require('tiny-secp256k1');
20
+ var Mnemonic = require('@leofcoin/mnemonic');
22
21
  var MultiSignature = require('multi-signature');
23
22
  var varint = require('varint');
24
- var AES = require('crypto-js/aes.js');
25
- require('crypto-js/sha512.js');
26
- var ENC = require('crypto-js/enc-utf8.js');
23
+ var randombytes = require('randombytes');
27
24
  require('@vandeurenglenn/base32');
28
25
  require('@vandeurenglenn/base58');
29
26
  require('@vandeurenglenn/is-hex');
@@ -51,18 +48,18 @@ function _interopNamespace(e) {
51
48
  var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage);
52
49
  var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
53
50
  var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
54
- var generateAccount__default = /*#__PURE__*/_interopDefaultLegacy(generateAccount);
51
+ var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet$1);
55
52
  var bs58check__default = /*#__PURE__*/_interopDefaultLegacy(bs58check);
56
53
  var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
57
54
  var bip32__namespace = /*#__PURE__*/_interopNamespace(bip32);
58
55
  var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
59
56
  var ecc__default = /*#__PURE__*/_interopDefaultLegacy(ecc);
57
+ var Mnemonic__default = /*#__PURE__*/_interopDefaultLegacy(Mnemonic);
60
58
  var MultiSignature__default = /*#__PURE__*/_interopDefaultLegacy(MultiSignature);
61
59
  var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
62
- var AES__default = /*#__PURE__*/_interopDefaultLegacy(AES);
63
- var ENC__default = /*#__PURE__*/_interopDefaultLegacy(ENC);
60
+ var randombytes__default = /*#__PURE__*/_interopDefaultLegacy(randombytes);
64
61
 
65
- /* socket-request-client version 1.6.1 */
62
+ /* socket-request-client version 1.6.3 */
66
63
 
67
64
  class LittlePubSub {
68
65
  constructor(verbose = true) {
@@ -249,9 +246,6 @@ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry
249
246
  peernet: api.peernet(client),
250
247
  server: api.server(client),
251
248
  close: exit => {
252
- client.onclose = message => {
253
- if (exit) process.exit();
254
- };
255
249
  client.close();
256
250
  }
257
251
  }
@@ -318,6 +312,10 @@ class Peer {
318
312
  return this.#connected
319
313
  }
320
314
 
315
+ get readyState() {
316
+ return this.channel?.readyState
317
+ }
318
+
321
319
  /**
322
320
  * @params {Object} options
323
321
  * @params {string} options.channelName - this peerid : otherpeer id
@@ -357,8 +355,19 @@ constructor(options = {}) {
357
355
  }
358
356
 
359
357
  send(message) {
360
- this.bw.up += message.length || message.byteLength;
361
- this.channel.send(message);
358
+ switch (this.channel?.readyState) {
359
+ case 'open':
360
+ this.bw.up += message.length || message.byteLength;
361
+ this.channel.send(message);
362
+ break;
363
+ case 'closed':
364
+ case 'closing':
365
+ debug('channel already closed, this usually means a bad implementation, try checking the readyState or check if the peer is connected before sending');
366
+ break;
367
+ case undefined:
368
+ debug(`trying to send before a channel is created`);
369
+ break;
370
+ }
362
371
  }
363
372
 
364
373
  request(data) {
@@ -431,7 +440,6 @@ constructor(options = {}) {
431
440
  this.channel.onmessage = (message) => {
432
441
  pubsub.publish('peer:data', message);
433
442
  debug(`incoming message from ${this.peerId}`);
434
- debug(message);
435
443
  this.bw.down += message.length || message.byteLength;
436
444
  };
437
445
 
@@ -491,6 +499,7 @@ constructor(options = {}) {
491
499
 
492
500
  close() {
493
501
  debug(`closing ${this.peerId}`);
502
+ this.#connected = false;
494
503
  this.channel?.close();
495
504
  this.#connection?.close();
496
505
 
@@ -507,6 +516,10 @@ class Client {
507
516
  return { ...this.#connections }
508
517
  }
509
518
 
519
+ get peers() {
520
+ return Object.entries(this.#connections)
521
+ }
522
+
510
523
  constructor(id, identifiers = ['peernet-v0.1.0'], stars = []) {
511
524
  this.id = id || Math.random().toString(36).slice(-12);
512
525
  if (!Array.isArray(identifiers)) identifiers = [identifiers];
@@ -621,6 +634,15 @@ class Client {
621
634
  debug(`peer ${id} joined`);
622
635
  }
623
636
 
637
+ removePeer(peer) {
638
+ const id = peer.peerId || peer;
639
+ if (this.#connections[id]) {
640
+ this.#connections[id].connected && this.#connections[id].close();
641
+ delete this.#connections[id];
642
+ }
643
+ debug(`peer ${id} removed`);
644
+ }
645
+
624
646
 
625
647
  }
626
648
 
@@ -1027,6 +1049,43 @@ class DhtEarth {
1027
1049
  }
1028
1050
  }
1029
1051
 
1052
+ /**
1053
+ * @params {String} network
1054
+ * @return {object} { identity, accounts, config }
1055
+ */
1056
+ var generateAccount = async network => {
1057
+ let wallet = new MultiWallet__default["default"](network);
1058
+ /**
1059
+ * @type {string}
1060
+ */
1061
+ const mnemonic = await wallet.generate();
1062
+
1063
+ wallet = new MultiWallet__default["default"](network);
1064
+ await wallet.recover(mnemonic, network);
1065
+ /**
1066
+ * @type {object}
1067
+ */
1068
+ const account = wallet.account(0);
1069
+ /**
1070
+ * @type {object}
1071
+ */
1072
+ const external = account.external(0);
1073
+ const internal = account.internal(0);
1074
+
1075
+ return {
1076
+ identity: {
1077
+ mnemonic,
1078
+ // multiWIF: wallet.export(),
1079
+ publicKey: external.publicKey,
1080
+ privateKey: external.privateKey,
1081
+ walletId: external.id
1082
+ },
1083
+ accounts: [['main account', external.address, internal.address]]
1084
+ // config: {
1085
+ // }
1086
+ }
1087
+ };
1088
+
1030
1089
  var testnets = {
1031
1090
  'leofcoin:olivia': {
1032
1091
  messagePrefix: '\u0019Leofcoin Signed Message:',
@@ -1080,6 +1139,7 @@ const bitcoin = {
1080
1139
  messagePrefix: '\x18Bitcoin Signed Message:\n',
1081
1140
  bech32: 'bc',
1082
1141
  pubKeyHash: 0x00,
1142
+ multiCodec: 0x00,
1083
1143
  scriptHash: 0x05,
1084
1144
  wif: 0x80,
1085
1145
  coin_type: 0,
@@ -1128,12 +1188,15 @@ const fromNetworkString = network => {
1128
1188
  network = networks[parts[0]];
1129
1189
  if (parts[1]) {
1130
1190
  if (network[parts[1]]) network = network[parts[1]];
1131
-
1191
+
1132
1192
  network.coin_type = 1;
1133
1193
  }
1134
1194
  return network;
1135
1195
  };
1136
1196
 
1197
+ // import { createHash } from 'crypto'
1198
+ // import { createHash as _createHash } from './hash'
1199
+
1137
1200
  const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
1138
1201
  class HDWallet {
1139
1202
 
@@ -1161,20 +1224,48 @@ class HDWallet {
1161
1224
  return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
1162
1225
  }
1163
1226
 
1227
+ get ethereumAddress() {
1228
+ const buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1229
+ let hash = createKeccakHash__default["default"]('keccak256').update(buffer.slice(1)).digest();
1230
+ return `0x${hash.slice(-20).toString('hex')}`
1231
+ }
1232
+
1233
+ // async bitcoinAddress() {
1234
+ // const chainCode = this.privateKeyBuffer
1235
+ //
1236
+ // const node = bip32.fromPrivateKey(this.privateKeyBuffer, chainCode, networks['bitcoin'])
1237
+ // let buffer = await _createHash(node.publicKey, 'SHA-256')
1238
+ // buffer = createHash('ripemd160').update(buffer).digest()
1239
+ // // buffer = Buffer.from(`0x00${buffer.toString('hex')}`, 'hex')
1240
+ // // buffer = createHash('sha256').update(buffer).digest()
1241
+ // // const mainHash = buffer
1242
+ // // buffer = createHash('sha256').update(buffer).digest()
1243
+ // // const checksum = buffer.toString('hex').substring(0, 8)
1244
+ // // return base58.encode(Buffer.concat([mainHash, Buffer.from(checksum, 'hex')]))
1245
+ // const payload = Buffer.allocUnsafe(21)
1246
+ // payload.writeUInt8(networks['bitcoin'].pubKeyHash, 0)
1247
+ // buffer.copy(payload, 1)
1248
+ //
1249
+ // return encode(payload)
1250
+ // }
1251
+
1252
+ get leofcoinAddress() {
1253
+ return encode$1(this.neutered.publicKeyBuffer)
1254
+ }
1255
+
1164
1256
  get address() {
1165
- // override testnet coin_type
1166
- let coin_type = this.hdnode.network.coin_type;
1257
+ return this.getAddressForCoin()
1258
+ }
1259
+
1260
+ getAddressForCoin(coin_type) {
1261
+ if (!coin_type) coin_type = this.hdnode.network.coin_type;
1167
1262
  if (coin_type === 1) {
1168
1263
  if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
1169
1264
  if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
1170
1265
  }
1171
- if (coin_type === 60 || coin_type === 640) {
1172
- let buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1173
- buffer = Buffer.from(secp256k1.publicKeyConvert(buffer, false)).slice(1);
1174
- let hash = createKeccakHash__default["default"]('keccak256').update(buffer).digest();
1175
- return hash.slice(-20).toString('hex')
1176
- }
1177
- return encode$1(this.neutered.publicKeyBuffer)
1266
+ // if (coin_type === 0) return this.bitcoinAddress
1267
+ if (coin_type === 60) return this.ethereumAddress
1268
+ if (coin_type === 640) return this.leofcoinAddress
1178
1269
  }
1179
1270
 
1180
1271
  get accountAddress() {
@@ -1221,10 +1312,10 @@ class HDWallet {
1221
1312
 
1222
1313
  async generate(password, network) {
1223
1314
  network = this.validateNetwork(network);
1224
- const mnemonic = bip39.generateMnemonic(256);
1225
- const seed = await bip39.mnemonicToSeed(mnemonic, password);
1315
+ const mnemonic = new Mnemonic__default["default"]().generate();
1316
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1226
1317
  this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1227
- return mnemonic; // userpw
1318
+ return mnemonic;
1228
1319
  }
1229
1320
 
1230
1321
  /**
@@ -1232,7 +1323,7 @@ class HDWallet {
1232
1323
  */
1233
1324
  async recover(mnemonic, password, network) {
1234
1325
  network = this.validateNetwork(network, password);
1235
- const seed = await bip39.mnemonicToSeed(mnemonic);
1326
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1236
1327
  this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1237
1328
  }
1238
1329
 
@@ -1265,6 +1356,71 @@ class HDWallet {
1265
1356
  }
1266
1357
  }
1267
1358
 
1359
+ const { subtle } = require('crypto').webcrypto;
1360
+
1361
+ const generateAesKey = async (length = 256) => {
1362
+ const key = await subtle.generateKey({
1363
+ name: 'AES-CBC',
1364
+ length
1365
+ }, true, ['encrypt', 'decrypt']);
1366
+
1367
+ return key;
1368
+ };
1369
+
1370
+ const importAesKey = async (exported, format = 'raw', length = 256) => {
1371
+ return await subtle.importKey(format, exported, {
1372
+ name: 'AES-CBC',
1373
+ length
1374
+ }, true, ['encrypt', 'decrypt'])
1375
+ };
1376
+
1377
+ const exportAesKey = async (key, format = 'raw') => {
1378
+ return await subtle.exportKey(format, key)
1379
+ };
1380
+
1381
+ const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
1382
+ name: 'AES-CBC',
1383
+ iv,
1384
+ }, key, uint8Array);
1385
+
1386
+ const uint8ArrayToHex = uint8Array =>
1387
+ [...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
1388
+
1389
+ const arrayBufferToHex = arrayBuffer =>
1390
+ uint8ArrayToHex(new Uint8Array(arrayBuffer));
1391
+
1392
+ const hexToUint8Array = hex =>
1393
+ new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
1394
+
1395
+ const encrypt = async string => {
1396
+ const ec = new TextEncoder();
1397
+ const key = await generateAesKey();
1398
+ const iv = await randombytes__default["default"](16);
1399
+
1400
+ const ciphertext = await encryptAes(ec.encode(string), key, iv);
1401
+ const exported = await exportAesKey(key);
1402
+
1403
+ return {
1404
+ key: arrayBufferToHex(exported),
1405
+ iv: iv.toString('hex'),
1406
+ cipher: arrayBufferToHex(ciphertext)
1407
+ }
1408
+ };
1409
+
1410
+ const decrypt = async (cipher, key, iv) => {
1411
+ if (!key.type) key = await importAesKey(hexToUint8Array(key));
1412
+ cipher = new Uint8Array(hexToUint8Array(cipher));
1413
+ iv = new Uint8Array(hexToUint8Array(iv));
1414
+
1415
+ const dec = new TextDecoder();
1416
+ const plaintext = await subtle.decrypt({
1417
+ name: 'AES-CBC',
1418
+ iv,
1419
+ }, key, cipher);
1420
+
1421
+ return dec.decode(plaintext);
1422
+ };
1423
+
1268
1424
  const { encode, decode } = bs58check__namespace;
1269
1425
 
1270
1426
  // TODO: multihash addresses
@@ -1295,9 +1451,7 @@ class HDAccount {
1295
1451
 
1296
1452
  class MultiWallet extends HDWallet {
1297
1453
  constructor(network, hdnode) {
1298
- const networkName = network;
1299
1454
  super(network, hdnode);
1300
- if (typeof networkName === 'string') this.networkName = networkName;
1301
1455
  this.multiCodec = this.network.multiCodec;
1302
1456
  this.version = 0x00;
1303
1457
  }
@@ -1315,7 +1469,7 @@ class MultiWallet extends HDWallet {
1315
1469
  }
1316
1470
 
1317
1471
  get neutered() {
1318
- const neutered = this.ifNotLocked(() => new MultiWallet(this.network, this.hdnode.neutered()));
1472
+ const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
1319
1473
  if (neutered) this._neutered = neutered;
1320
1474
  return this._neutered
1321
1475
  }
@@ -1324,18 +1478,19 @@ class MultiWallet extends HDWallet {
1324
1478
  let buffer = decode(id);
1325
1479
  varint__default["default"].decode(buffer);
1326
1480
  buffer = buffer.slice(varint__default["default"].decode.bytes);
1327
- this.fromPublicKey(buffer, null, this.network);
1481
+ this.fromPublicKey(buffer, null, this.networkName);
1328
1482
  }
1329
1483
 
1330
- lock(key, multiWIF) {
1484
+ async lock(multiWIF) {
1331
1485
  if (!multiWIF) multiWIF = this.multiWIF;
1332
- this.encrypted = AES__default["default"].encrypt(multiWIF.toString('hex'), key).toString();
1486
+ this.encrypted = await encrypt(multiWIF.toString('hex'));
1333
1487
  this.locked = true;
1488
+ return this.encrypted
1334
1489
  }
1335
1490
 
1336
- unlock(key, encrypted) {
1337
- if (!encrypted) encrypted = this.encrypted;
1338
- this.import(AES__default["default"].decrypt(encrypted, key).toString(ENC__default["default"]));
1491
+ async unlock({key, iv, cipher}) {
1492
+ const decrypted = await decrypt(cipher, key, iv);
1493
+ this.import(decrypted);
1339
1494
  this.locked = false;
1340
1495
  }
1341
1496
 
@@ -1355,7 +1510,7 @@ class MultiWallet extends HDWallet {
1355
1510
  else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
1356
1511
  else return p
1357
1512
  }, networks['leofcoin']);
1358
- this.load(bs58, this.network);
1513
+ this.load(bs58, this.networkName);
1359
1514
  }
1360
1515
 
1361
1516
  /**
@@ -1398,7 +1553,7 @@ class MultiWallet extends HDWallet {
1398
1553
  * @return { internal(addressIndex), external(addressIndex) }
1399
1554
  */
1400
1555
  account(index) {
1401
- return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
1556
+ return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
1402
1557
  }
1403
1558
 
1404
1559
  /**
@@ -1407,11 +1562,11 @@ class MultiWallet extends HDWallet {
1407
1562
  * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1408
1563
  */
1409
1564
  derivePath(path) {
1410
- return new MultiWallet(this.network, this.hdnode.derivePath(path))
1565
+ return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
1411
1566
  }
1412
1567
 
1413
1568
  derive(index) {
1414
- return new MultiWallet(this.network, this.hdnode.derive(index));
1569
+ return new MultiWallet(this.networkName, this.hdnode.derive(index));
1415
1570
  }
1416
1571
  }
1417
1572
 
@@ -1434,7 +1589,7 @@ class MessageHandler {
1434
1589
  let identity = await walletStore.get('identity');
1435
1590
  identity = JSON.parse(new TextDecoder().decode(identity));
1436
1591
  const wallet = new MultiWallet(this.network);
1437
- wallet.import(identity.multiWIF);
1592
+ wallet.recover(identity.mnemonic);
1438
1593
  return wallet.sign(Buffer.from(hasher.hash).slice(0, 32))
1439
1594
  }
1440
1595
 
@@ -1538,7 +1693,7 @@ class Peernet {
1538
1693
  if (this.hasDaemon) {
1539
1694
  Storage = LeofcoinStorageClient;
1540
1695
  } else {
1541
- Storage = globalThis.LeofcoinStorage?.default ? globalThis.LeofcoinStorage.default : LeofcoinStorage__default["default"];
1696
+ Storage = globalThis.LeofcoinStorage ? globalThis.LeofcoinStorage : LeofcoinStorage__default["default"];
1542
1697
  }
1543
1698
  globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
1544
1699
  await new Storage(name, root);
@@ -1635,12 +1790,12 @@ class Peernet {
1635
1790
  this.hasDaemon = daemon;
1636
1791
 
1637
1792
  if (this.hasDaemon) {
1638
- const httpClient = await Promise.resolve().then(function () { return require('./client-1a1f75e6.js'); });
1793
+ const httpClient = await Promise.resolve().then(function () { return require('./client-5633ba04.js'); });
1639
1794
  globalThis.peernet.client = await httpClient.default({
1640
1795
  protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port
1641
1796
  });
1642
1797
  } else {
1643
- const http = await Promise.resolve().then(function () { return require('./http-68dd2b96.js'); });
1798
+ const http = await Promise.resolve().then(function () { return require('./http-feac1075.js'); });
1644
1799
  if (environment !== 'browser') http.default(options);
1645
1800
  }
1646
1801
 
@@ -1653,7 +1808,7 @@ class Peernet {
1653
1808
  this.id = JSON.parse(new TextDecoder().decode(pub)).walletId;
1654
1809
  } catch (e) {
1655
1810
  if (e.code === 'ERR_NOT_FOUND') {
1656
- const {identity, accounts, config} = await generateAccount__default["default"](this.network);
1811
+ const {identity, accounts, config} = await generateAccount(this.network);
1657
1812
  walletStore.put('version', new TextEncoder().encode(1));
1658
1813
  walletStore.put('accounts', new TextEncoder().encode(accounts));
1659
1814
  walletStore.put('identity', new TextEncoder().encode(JSON.stringify(identity)));
@@ -1708,6 +1863,16 @@ class Peernet {
1708
1863
  this.requestProtos[name] = method;
1709
1864
  }
1710
1865
 
1866
+ sendMessage(peer, id, data) {
1867
+ if (peer.readyState === 'open') {
1868
+ peer.send(new TextEncoder().encode(JSON.stringify({id, data})));
1869
+ this.bw.up += data.length;
1870
+ } else if (peer.readyState === 'closed') {
1871
+ this.removePeer(peer);
1872
+ }
1873
+
1874
+ }
1875
+
1711
1876
  /**
1712
1877
  * @private
1713
1878
  *
@@ -1732,8 +1897,7 @@ class Peernet {
1732
1897
  const data = new dhtResponse({hash, has});
1733
1898
  const node = await this.prepareMessage(from, data.encoded);
1734
1899
 
1735
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1736
- this.bw.up += node.encoded.length;
1900
+ this.sendMessage(peer, id, node.encoded);
1737
1901
  } else if (proto.name === 'peernet-data') {
1738
1902
  let { hash, store } = proto.decoded;
1739
1903
  let data;
@@ -1746,24 +1910,19 @@ class Peernet {
1746
1910
  data = await store.get(hash);
1747
1911
 
1748
1912
  if (data) {
1749
- data = new DataMessageResponse({hash, data: data.decoded ? new TextEncoder().encode(JSON.stringify(data.decoded)) : data});
1913
+ data = new DataMessageResponse({hash, data});
1750
1914
 
1751
1915
  const node = await this.prepareMessage(from, data.encoded);
1752
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1753
- this.bw.up += node.encoded.length;
1916
+ this.sendMessage(peer, id, node.encoded);
1754
1917
  }
1755
1918
  }
1756
1919
 
1757
1920
  } else if (proto.name === 'peernet-request') {
1758
- // TODO: make dynamic
1759
- // exposeddevapi[proto.decoded.request](proto.decoded.params)
1760
1921
  const method = this.requestProtos[proto.decoded.request];
1761
1922
  if (method) {
1762
1923
  const data = await method();
1763
1924
  const node = await this.prepareMessage(from, data.encoded);
1764
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1765
-
1766
- this.bw.up += node.encoded.length;
1925
+ this.sendMessage(peer, id, node.encoded);
1767
1926
  }
1768
1927
  } else if (proto.name === 'peernet-ps' && peer.peerId !== this.id) {
1769
1928
  globalSub.publish(new TextDecoder().decode(proto.decoded.topic), proto.decoded.data);
@@ -2033,13 +2192,9 @@ class Peernet {
2033
2192
  const id = Math.random().toString(36).slice(-12);
2034
2193
  data = new PsMessage({data, topic});
2035
2194
  for (const peer of this.connections) {
2036
- if (peer.connected) {
2037
- if (peer.peerId !== this.peerId) {
2038
- const node = await this.prepareMessage(peer.peerId, data.encoded);
2039
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
2040
- }
2041
- } else {
2042
- this.removePeer(peer);
2195
+ if (peer.peerId !== this.peerId) {
2196
+ const node = await this.prepareMessage(peer.peerId, data.encoded);
2197
+ this.sendMessage(peer, id, node.encoded);
2043
2198
  }
2044
2199
  // TODO: if peer subscribed
2045
2200
  }
@@ -2060,7 +2215,7 @@ class Peernet {
2060
2215
  }
2061
2216
 
2062
2217
  async removePeer(peer) {
2063
- delete this.client.connections[peer.peerId];
2218
+ return this.client.removePeer(peer)
2064
2219
  }
2065
2220
 
2066
2221
  get Buffer() {