@leofcoin/peernet 0.9.3 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/browser/peernet.js +651 -646
  2. package/dist/commonjs/codec-73adfc0f.js +205 -0
  3. package/dist/commonjs/codec-format-interface.js +5 -5
  4. package/dist/commonjs/codec.js +6 -199
  5. package/dist/commonjs/dht-response.js +1 -1
  6. package/dist/commonjs/dht.js +1 -1
  7. package/dist/commonjs/hash.js +4 -4
  8. package/dist/commonjs/peernet-message.js +1 -1
  9. package/dist/commonjs/peernet.js +653 -648
  10. package/dist/commonjs/request.js +1 -1
  11. package/dist/commonjs/response.js +1 -1
  12. package/dist/module/peernet.js +10 -4
  13. package/package.json +1 -1
  14. package/src/client.js +71 -0
  15. package/src/codec/codec-format-interface.js +139 -0
  16. package/src/codec/codec.js +114 -0
  17. package/src/codec/codecs.js +79 -0
  18. package/src/dht/dht.js +125 -0
  19. package/src/discovery/peer-discovery.js +75 -0
  20. package/src/errors/errors.js +12 -0
  21. package/src/handlers/message.js +52 -0
  22. package/src/hash/hash.js +145 -0
  23. package/src/http/api.js +115 -0
  24. package/src/http/client/api.js +41 -0
  25. package/src/http/client/client.js +10 -0
  26. package/src/http/client/http-client.js +44 -0
  27. package/src/http/client/storage.js +36 -0
  28. package/src/http/http.js +28 -0
  29. package/src/messages/chat-message.js +14 -0
  30. package/src/messages/data-response.js +14 -0
  31. package/src/messages/data.js +14 -0
  32. package/src/messages/dht-response.js +15 -0
  33. package/src/messages/dht.js +25 -0
  34. package/src/messages/peer-response.js +14 -0
  35. package/src/messages/peer.js +14 -0
  36. package/src/messages/peernet-message.js +14 -0
  37. package/src/messages/ps.js +14 -0
  38. package/src/messages/request.js +14 -0
  39. package/src/messages/response.js +14 -0
  40. package/src/peer-info.js +9 -0
  41. package/src/peer.js +43 -0
  42. package/src/peernet.js +680 -0
  43. package/src/proto/chat-message.proto.js +7 -0
  44. package/src/proto/data-response.proto.js +7 -0
  45. package/src/proto/data.proto.js +7 -0
  46. package/src/proto/dht-response.proto.js +7 -0
  47. package/src/proto/dht.proto.js +7 -0
  48. package/src/proto/peer-response.proto.js +6 -0
  49. package/src/proto/peer.proto.js +6 -0
  50. package/src/proto/peernet.proto.js +9 -0
  51. package/src/proto/ps.proto.js +6 -0
  52. package/src/proto/request.proto.js +6 -0
  53. package/src/proto/response.proto.js +6 -0
  54. package/src/server.js +25 -0
  55. package/src/utils/utils.js +78 -0
  56. package/.nyc_output/39a61420-013f-4db1-a597-7c5444da26e7.json +0 -1
  57. package/.nyc_output/4b387323-32a3-4eee-8f05-d13f2e0a5bf4.json +0 -1
  58. package/.nyc_output/ef71cf24-d9d9-45dd-814f-8d53cb6769f3.json +0 -1
  59. package/.nyc_output/processinfo/39a61420-013f-4db1-a597-7c5444da26e7.json +0 -1
  60. package/.nyc_output/processinfo/4b387323-32a3-4eee-8f05-d13f2e0a5bf4.json +0 -1
  61. package/.nyc_output/processinfo/ef71cf24-d9d9-45dd-814f-8d53cb6769f3.json +0 -1
  62. package/.nyc_output/processinfo/index.json +0 -1
@@ -261,7 +261,7 @@ class LeofcoinStorage$1 {
261
261
 
262
262
  }
263
263
 
264
- var version = "0.9.2";
264
+ var version = "0.9.4";
265
265
 
266
266
  var api$1 = {
267
267
  version: ({send}) => send({client: '@peernet/api/http', version}),
@@ -1956,651 +1956,656 @@ const nothingFoundError = (hash) => {
1956
1956
  return new Error(`nothing found for ${hash}`)
1957
1957
  };
1958
1958
 
1959
- globalThis.leofcoin = globalThis.leofcoin || {};
1960
- globalThis.globalSub = globalThis.globalSub || new PubSub__default['default']({verbose: true});
1961
-
1962
- /**
1963
- * @access public
1964
- * @example
1965
- * const peernet = new Peernet();
1966
- */
1967
- class Peernet {
1968
- /**
1969
- * @access public
1970
- * @param {Object} options
1971
- * @param {String} options.network - desired network
1972
- * @param {String} options.root - path to root directory
1973
- * @param {String} options.storePrefix - prefix for datatores (lfc)
1974
- *
1975
- * @return {Promise} instance of Peernet
1976
- *
1977
- * @example
1978
- * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
1979
- */
1980
- constructor(options = {}) {
1981
- this._discovered = [];
1982
- /**
1983
- * @property {String} network - current network
1984
- */
1985
- this.network = options.network || 'leofcoin';
1986
- const parts = this.network.split(':');
1987
-
1988
- if (!options.storePrefix) options.storePrefix = 'lfc';
1989
- if (!options.port) options.port = 2000;
1990
- if (!options.root) {
1991
- if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
1992
- else options.root = `.${this.network}/peernet`;
1993
- }
1994
- globalThis.peernet = this;
1995
- return this._init(options)
1996
- }
1997
-
1998
- get defaultStores() {
1999
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
2000
- }
2001
-
2002
- addProto(name, proto) {
2003
- if (!globalThis.peernet.protos[name]) globalThis.peernet.protos[name] = proto;
2004
- }
2005
-
2006
- addCodec(name, proto) {
2007
- if (!globalThis.peernet.codecs[name]) globalThis.peernet.codecs[name] = proto;
2008
- }
2009
-
2010
- async addStore(name, prefix, root, isPrivate = true) {
2011
- if (name === 'block' || name === 'transaction' || name === 'chain' ||
2012
- name === 'data' || name === 'message') isPrivate = false;
2013
-
2014
- let Storage;
2015
- if (this.hasDaemon) {
2016
- Storage = LeofcoinStorageClient;
2017
- } else {
2018
- Storage = LeofcoinStorage$1;
2019
- }
2020
- globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
2021
- await new Storage(`${prefix}-${name}`, root);
2022
-
2023
- globalThis[`${name}Store`].private = isPrivate;
2024
- if (!isPrivate) this.stores.push(name);
2025
- }
2026
-
2027
-
2028
- /**
2029
- * @see MessageHandler
2030
- */
2031
- prepareMessage(to, data) {
2032
- return this._messageHandler.prepareMessage(this.id, to, data)
2033
- }
2034
-
2035
- /**
2036
- * @access public
2037
- *
2038
- * @return {Array} peerId
2039
- */
2040
- get peers() {
2041
- return [...connections.values()]
2042
- }
2043
-
2044
- /**
2045
- * @private
2046
- *
2047
- * @param {Object} options
2048
- * @param {String} options.root - path to root directory
2049
- *
2050
- * @return {Promise} instance of Peernet
2051
- */
2052
- async _init(options) {
2053
- // peernetDHT aka closesPeer by coordinates
2054
- /**
2055
- * @type {Object}
2056
- * @property {Object} peer Instance of Peer
2057
- */
2058
- this.dht = new DhtEarth();
2059
- /**
2060
- * @type {Map}
2061
- * @property {Object} peer Instance of Peer
2062
- */
2063
- this.peerMap = new Map();
2064
- this.stores = [];
2065
- this.requestProtos = {};
2066
- this.storePrefix = options.storePrefix;
2067
- this.root = options.root;
2068
-
2069
- /**
2070
- * proto Object containing protos
2071
- * @type {Object}
2072
- * @property {PeernetMessage} protos[peernet-message] messageNode
2073
- * @property {DHTMessage} protos[peernet-dht] messageNode
2074
- * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
2075
- * @property {DataMessage} protos[peernet-data] messageNode
2076
- * @property {DataMessageResponse} protos[peernet-data-response] messageNode
2077
- */
2078
- globalThis.peernet.protos = {
2079
- 'peernet-request': RequestMessage,
2080
- 'peernet-response': ResponseMessage,
2081
- 'peernet-peer': PeerMessage,
2082
- 'peernet-peer-response': PeerMessageResponse,
2083
- 'peernet-message': PeernetMessage,
2084
- 'peernet-dht': DHTMessage,
2085
- 'peernet-dht-response': DHTMessageResponse,
2086
- 'peernet-data': DataMessage,
2087
- 'peernet-data-response': DataMessageResponse,
2088
- 'peernet-ps': PsMessage,
2089
- 'chat-message': ChatMessage,
2090
- };
2091
- this.protos = globalThis.peernet.protos;
2092
-
2093
- this._messageHandler = new MessageHandler(this.network);
2094
-
2095
- const {daemon, environment} = await target();
2096
- this.hasDaemon = daemon;
2097
-
2098
- if (this.hasDaemon) {
2099
- globalThis.peernet.client = await httpClient({
2100
- protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port,
2101
- });
2102
- } else {
2103
- if (environment !== 'browser') http(options);
2104
- }
2105
-
2106
- for (const store of this.defaultStores) {
2107
- await this.addStore(store, options.storePrefix, options.root);
2108
- }
2109
-
2110
- try {
2111
- const pub = await accountStore.get('public');
2112
- this.id = pub.walletId;
2113
- } catch (e) {
2114
- if (e.code === 'ERR_NOT_FOUND') {
2115
- const wallet = {};
2116
- const {identity, accounts, config} = await generateAccount(this.network);
2117
- wallet.identity = identity;
2118
- wallet.accounts = accounts;
2119
- wallet.version = 1;
2120
- walletStore.put(wallet);
2121
- await accountStore.put('config', config);
2122
- await accountStore.put('public', {walletId: wallet.identity.walletId});
2123
-
2124
- this.id = wallet.identity.walletId;
2125
- } else {
2126
- throw e
2127
- }
2128
- }
2129
- this._peerHandler = new PeerDiscovery(this.id);
2130
- // peernet id
2131
- const id = Buffer.from(this.id.slice(0, 32));
2132
- this.peerId = id;
2133
-
2134
- pubsub.subscribe('peer:discovered', async (peer) => {
2135
- this._peerHandler.discover(peer);
2136
- peer.on('peernet.data', async (message) => {
2137
- const id = message.id;
2138
- message = new PeernetMessage(Buffer.from(message.data.data));
2139
- const proto = protoFor(message.decoded.data);
2140
- await this._protoHandler({id, proto}, peer);
2141
- const fulldId = this._getPeerId(peer.id);
2142
- if (fulldId && this._discovered.indexOf(peer.id) === -1) {
2143
- this._discovered.push(peer.id);
2144
- pubsub.publish('peer:connected', peer);
2145
- }
2146
- });
2147
- });
2148
- pubsub.subscribe('peer:disconnected', async (peer) => {
2149
- let index = this._discovered.indexOf(peer.id);
2150
- if (index !== -1) this._discovered.splice(index, 1);
2151
- const id = this._getPeerId(peer.id);
2152
- let peerIds = this.peerMap.get(id);
2153
-
2154
- if (peerIds) {
2155
- index = peerIds.indexOf(peer.id);
2156
- if (index !== -1) peerIds.splice(index, 1);
2157
- } else {
2158
- peerIds = [];
2159
- }
2160
-
2161
- if (peerIds.length === 0) this.peerMap.delete(id);
2162
- else this.peerMap.set(id, peerIds);
2163
- });
2164
- pubsub.subscribe('peer:connected', async (peer) => {
2165
- console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2166
- // peer.on('peernet.data', async (message) => {
2167
- // const id = message.id
2168
- // message = new PeernetMessage(Buffer.from(message.data.data))
2169
- // const proto = protoFor(message.decoded.data)
2170
- // this._protoHandler({id, proto}, peer)
2171
- // })
2172
- });
2173
-
2174
- /**
2175
- * @access public
2176
- * @type {PeernetClient}
2177
- */
2178
- this.client = new PeernetClient({...options, id});
2179
- return this
2180
- }
2181
-
2182
- _getPeerId(id) {
2183
- for (const entry of [...this.peerMap.entries()]) {
2184
- for (const _id of entry[1]) {
2185
- if (_id === id) return entry[0]
2186
- }
2187
- }
2188
- }
2189
-
2190
- addRequestHandler(name, method) {
2191
- this.requestProtos[name] = method;
2192
- }
2193
-
2194
- /**
2195
- * @private
2196
- *
2197
- * @param {Buffer} message - peernet message
2198
- * @param {PeernetPeer} peer - peernet peer
2199
- */
2200
- async _protoHandler(message, peer) {
2201
- const {id, proto} = message;
2202
- if (proto.name === 'peernet-peer') {
2203
- const from = proto.decoded.id;
2204
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2205
- else {
2206
- const connections = this.peerMap.get(from);
2207
- if (connections.indexOf(peer.id) === -1) {
2208
- connections.push(peer.id);
2209
- this.peerMap.set(from, connections);
2210
- }
2211
- }
2212
- const data = new PeerMessageResponse({id: this.id});
2213
- const node = await this.prepareMessage(from, data.encoded);
2214
-
2215
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2216
- } else if (proto.name === 'peernet-peer-response') {
2217
- const from = proto.decoded.id;
2218
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2219
- else {
2220
- const connections = this.peerMap.get(from);
2221
- if (connections.indexOf(peer.id) === -1) {
2222
- connections.push(peer.id);
2223
- this.peerMap.set(from, connections);
2224
- }
2225
- }
2226
- } else {
2227
- let from = this._getPeerId(peer.id);
2228
- if (!from) {
2229
- const data = new PeerMessage({id: this.id});
2230
- const node = await this.prepareMessage(peer.id, data.encoded);
2231
-
2232
- let response = await peer.request(node.encoded);
2233
- response = protoFor(response);
2234
- response = new PeerMessageResponse(response.decoded.data);
2235
-
2236
- from = response.decoded.id;
2237
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2238
- else {
2239
- const connections = this.peerMap.get(from);
2240
- if (connections.indexOf(peer.id) === -1) {
2241
- connections.push(peer.id);
2242
- this.peerMap.set(from, connections);
2243
- }
2244
- }
2245
- }
2246
- if (proto.name === 'peernet-dht') {
2247
- let { hash, store } = proto.decoded;
2248
- let has;
2249
-
2250
- if (!store) {
2251
- has = await this.has(hash);
2252
- } else {
2253
- store = globalThis[`${store}Store`];
2254
- if (store.private) has = false;
2255
- else has = await store.has(hash);
2256
- }
2257
- const data = new DHTMessageResponse({hash, has});
2258
- const node = await this.prepareMessage(from, data.encoded);
2259
-
2260
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2261
- } else if (proto.name === 'peernet-data') {
2262
- let { hash, store } = proto.decoded;
2263
- let data;
2264
-
2265
- if (!store) {
2266
- data = await this.get(hash);
2267
- } else {
2268
- store = globalThis[`${store}Store`];
2269
- if (store.private) {
2270
- // TODO: ban
2271
- return
2272
- } else data = await store.get(hash);
2273
- }
2274
-
2275
- if (data) {
2276
- data = new DataMessageResponse({hash, data: Buffer.from(data)});
2277
-
2278
- const node = await this.prepareMessage(from, data.encoded);
2279
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2280
- }
2281
- } else if (proto.name === 'peernet-peer') {
2282
- const from = proto.decoded.id;
2283
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2284
- else {
2285
- const connections = this.peerMap.get(from);
2286
- connections.push(peer.id);
2287
- this.peerMap.set(from, connections);
2288
- }
2289
- const data = new PeerMessage({id: this.id});
2290
- const node = await this.prepareMessage(from, data.encoded);
2291
-
2292
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2293
- } else if (proto.name === 'peernet-request') {
2294
- // TODO: make dynamic
2295
- // exposeddevapi[proto.decoded.request](proto.decoded.params)
2296
- const method = this.requestProtos[proto.decoded.request];
2297
- if (method) {
2298
- const data = await method();
2299
- const node = await this.prepareMessage(from, data.encoded);
2300
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2301
- }
2302
-
2303
- } else if (proto.name === 'peernet-ps' &&
2304
- this._getPeerId(peer.id) !== this.id.toString()) {
2305
- globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
2306
- }
2307
- }
2308
- }
2309
-
2310
- /**
2311
- * performs a walk and resolves first encounter
2312
- *
2313
- * @param {String} hash
2314
- */
2315
- async walk(hash) {
2316
- if (!hash) throw new Error('hash expected, received undefined')
2317
- const data = new DHTMessage({hash});
2318
- this.client.id;
2319
- for (const peer of this.peers) {
2320
- const node = await this.prepareMessage(peer.id, data.encoded);
2321
-
2322
- const result = await peer.request(node.encoded);
2323
-
2324
- let proto = protoFor(result.data);
2325
-
2326
- if (proto.name !== 'peernet-message') throw encapsulatedError()
2327
- const from = proto.decoded.from;
2328
- proto = protoFor(proto.decoded.data);
2329
-
2330
- if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2331
-
2332
- // TODO: give ip and port (just used for location)
2333
- if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2334
- peer.connection.remoteFamily = 'ipv4';
2335
- peer.connection.remoteAddress = '127.0.0.1';
2336
- peer.connection.remotePort = '0000';
2337
- }
2338
-
2339
- const peerInfo = {
2340
- family: peer.connection.remoteFamily || peer.connection.localFamily,
2341
- address: peer.connection.remoteAddress || peer.connection.localAddress,
2342
- port: peer.connection.remotePort || peer.connection.localPort,
2343
- id: from,
2344
- };
2345
-
2346
- if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2347
- }
2348
- return
2349
- }
2350
-
2351
- /**
2352
- * Override DHT behavior, try's finding the content three times
2353
- *
2354
- * @param {String} hash
2355
- */
2356
- async providersFor(hash) {
2357
- let providers = await this.dht.providersFor(hash);
2358
- // walk the network to find a provider
2359
- if (!providers || providers.length === 0) {
2360
- await this.walk(hash);
2361
- providers = await this.dht.providersFor(hash);
2362
- // second walk the network to find a provider
2363
- if (!providers || providers.length === 0) {
2364
- await this.walk(hash);
2365
- providers = await this.dht.providersFor(hash);
2366
- }
2367
- // last walk
2368
- if (!providers || providers.length === 0) {
2369
- await this.walk(hash);
2370
- providers = await this.dht.providersFor(hash);
2371
- }
2372
- }
2373
- // undefined if no providers given
2374
- return providers
2375
- }
2376
-
2377
- get block() {
2378
- return {
2379
- get: async (hash) => {
2380
- const data = await blockStore.has(hash);
2381
- if (data) return await blockStore.get(hash)
2382
- return this.requestData(hash)
2383
- },
2384
- put: async (hash, data) => {
2385
- if (await blockStore.has(hash)) return
2386
- return await blockStore.put(hash, data)
2387
- },
2388
- has: async (hash) => await blockStore.has(hash, 'block'),
2389
- }
2390
- }
2391
-
2392
- get transaction() {
2393
- return {
2394
- get: async (hash) => {
2395
- const data = await transactionStore.has(hash);
2396
- if (data) return await transactionStore.get(hash)
2397
- return this.requestData(hash, 'transaction')
2398
- },
2399
- put: async (hash, data) => {
2400
- if (await transactionStore.has(hash)) return
2401
- return await transactionStore.put(hash, data)
2402
- },
2403
- has: async (hash) => await transactionStore.has(hash),
2404
- }
2405
- }
2406
-
2407
- async requestData(hash, store) {
2408
- const providers = await this.providersFor(hash);
2409
- if (!providers || providers.size === 0) throw nothingFoundError(hash)
2410
- debug(`found ${providers.size} provider(s) for ${hash}`);
2411
- // get closest peer on earth
2412
- const closestPeer = await this.dht.closestPeer(providers);
2413
- // get peer instance by id
2414
- if (!closestPeer || !closestPeer.id) return this.requestData(hash, store)
2415
-
2416
- const id = closestPeer.id.toString();
2417
- if (this.peers) {
2418
- let closest = this.peers.filter((peer) => {
2419
- if (this._getPeerId(peer.id) === id) return peer
2420
- });
2421
-
2422
- let data = new DataMessage({hash, store});
2423
-
2424
- const node = await this.prepareMessage(id, data.encoded);
2425
- if (closest[0]) data = await closest[0].request(node.encoded);
2426
- else {
2427
- closest = this.peers.filter((peer) => {
2428
- if (peer.id.toString() === id) return peer
2429
- });
2430
- if (closest[0]) data = await closest[0].request(node.encoded);
2431
- }
2432
- if (data.data) {
2433
- let proto = protoFor(Buffer.from(data.data));
2434
- proto = protoFor(proto.decoded.data);
2435
- return proto.decoded.data
2436
- }
2437
-
2438
- // this.put(hash, proto.decoded.data)
2439
- }
2440
- return null
2441
- }
2442
-
2443
-
2444
- get message() {
2445
- return {
2446
- /**
2447
- * Get content for given message hash
2448
- *
2449
- * @param {String} hash
2450
- */
2451
- get: async (hash) => {
2452
- debug(`get message ${hash}`);
2453
- const message = await messageStore.has(hash);
2454
- if (message) return await messageStore.get(hash)
2455
- return this.requestData(hash, 'message')
2456
- },
2457
- /**
2458
- * put message content
2459
- *
2460
- * @param {String} hash
2461
- * @param {Buffer} message
2462
- */
2463
- put: async (hash, message) => await messageStore.put(hash, message),
2464
- /**
2465
- * @param {String} hash
2466
- * @return {Boolean}
2467
- */
2468
- has: async (hash) => await messageStore.has(hash),
2469
- }
2470
- }
2471
-
2472
- get data() {
2473
- return {
2474
- /**
2475
- * Get content for given data hash
2476
- *
2477
- * @param {String} hash
2478
- */
2479
- get: async (hash) => {
2480
- debug(`get data ${hash}`);
2481
- const data = await dataStore.has(hash);
2482
- if (data) return await dataStore.get(hash)
2483
- return this.requestData(hash, 'data')
2484
- },
2485
- /**
2486
- * put data content
2487
- *
2488
- * @param {String} hash
2489
- * @param {Buffer} data
2490
- */
2491
- put: async (hash, data) => await dataStore.put(hash, data),
2492
- /**
2493
- * @param {String} hash
2494
- * @return {Boolean}
2495
- */
2496
- has: async (hash) => await dataStore.has(hash),
2497
- }
2498
- }
2499
-
2500
- /**
2501
- * goes trough given stores and tries to find data for given hash
2502
- * @param {Array} stores
2503
- * @param {string} hash
2504
- */
2505
- async whichStore(stores, hash) {
2506
- let store = stores.pop();
2507
- store = globalThis[`${store}Store`];
2508
- if (store) {
2509
- const has = await store.has(hash);
2510
- if (has) return store
2511
- if (stores.length > 0) return this.whichStore(stores, hash)
2512
- } else return null
2513
- }
2514
-
2515
- /**
2516
- * Get content for given hash
2517
- *
2518
- * @param {String} hash
2519
- */
2520
- async get(hash, store) {
2521
- debug(`get ${hash}`);
2522
- let data;
2523
- if (store) store = globalThis[`${store}Store`];
2524
- if (!store) store = await this.whichStore([...this.stores], hash);
2525
- if (store && await store.has(hash)) data = await store.get(hash);
2526
- if (data) return data
2527
-
2528
- return this.requestData(hash, 'data')
2529
- }
2530
-
2531
- /**
2532
- * put content
2533
- *
2534
- * @param {String} hash
2535
- * @param {Buffer} data
2536
- */
2537
- async put(hash, data, store = 'data') {
2538
- store = globalThis[`${store}Store`];
2539
- return await store.put(hash, data)
2540
- }
2541
-
2542
- /**
2543
- * @param {String} hash
2544
- * @return {Boolean}
2545
- */
2546
- async has(hash) {
2547
- const store = await this.whichStore([...this.stores], hash);
2548
- if (store) {
2549
- if (store.private) return false
2550
- else return true
2551
- }
2552
- return false
2553
- }
2554
-
2555
- /**
2556
- *
2557
- * @param {String} topic
2558
- * @param {String|Object|Array|Boolean|Buffer} data
2559
- */
2560
- async publish(topic, data) {
2561
- // globalSub.publish(topic, data)
2562
- if (!Buffer.isBuffer(topic)) topic = Buffer.from(topic);
2563
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
2564
- const id = Math.random().toString(36).slice(-12);
2565
- data = new PsMessage({data, topic});
2566
- for (const peer of this.peers) {
2567
- if (peer.connection._connected) {
2568
- if (peer.id.toString() !== this.peerId.toString()) {
2569
- const node = await this.prepareMessage(peer.id, data.encoded);
2570
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2571
- }
2572
- } else {
2573
- this.removePeer(peer);
2574
- }
2575
- // TODO: if peer subscribed
2576
- }
2577
- }
2578
-
2579
- createHash(data, name) {
2580
- return new PeernetHash(data, {name})
2581
- }
2582
-
2583
- /**
2584
- *
2585
- * @param {String} topic
2586
- * @param {Method} cb
2587
- */
2588
- async subscribe(topic, cb) {
2589
- // TODO: if peer subscribed
2590
- globalSub.subscribe(topic, cb);
2591
- }
2592
-
2593
- async removePeer(peer) {
2594
- connections.delete(peer.id);
2595
- }
2596
- // async block(index) {
2597
- // const _values = []
2598
- // for (const peer of this.peers) {
2599
- // const value = await peer.request({type: 'block', index})
2600
- // console.log(value);
2601
- // }
2602
- //
2603
- // }
1959
+ globalThis.leofcoin = globalThis.leofcoin || {};
1960
+ globalThis.globalSub = globalThis.globalSub || new PubSub__default['default']({verbose: true});
1961
+
1962
+ /**
1963
+ * @access public
1964
+ * @example
1965
+ * const peernet = new Peernet();
1966
+ */
1967
+ class Peernet {
1968
+ /**
1969
+ * @access public
1970
+ * @param {Object} options
1971
+ * @param {String} options.network - desired network
1972
+ * @param {String} options.root - path to root directory
1973
+ * @param {String} options.storePrefix - prefix for datatores (lfc)
1974
+ *
1975
+ * @return {Promise} instance of Peernet
1976
+ *
1977
+ * @example
1978
+ * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
1979
+ */
1980
+ constructor(options = {}) {
1981
+ this._discovered = [];
1982
+ /**
1983
+ * @property {String} network - current network
1984
+ */
1985
+ this.network = options.network || 'leofcoin';
1986
+ const parts = this.network.split(':');
1987
+
1988
+ if (!options.storePrefix) options.storePrefix = 'lfc';
1989
+ if (!options.port) options.port = 2000;
1990
+ if (!options.root) {
1991
+ if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
1992
+ else options.root = `.${this.network}/peernet`;
1993
+ }
1994
+ globalThis.peernet = this;
1995
+ return this._init(options)
1996
+ }
1997
+
1998
+ get defaultStores() {
1999
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
2000
+ }
2001
+
2002
+ addProto(name, proto) {
2003
+ if (!this.protos[name]) this.protos[name] = proto;
2004
+ }
2005
+
2006
+ addCodec(name, codec) {
2007
+ if (!this.codecs[name]) this.codecs[name] = codec;
2008
+ }
2009
+
2010
+ async addStore(name, prefix, root, isPrivate = true) {
2011
+ if (name === 'block' || name === 'transaction' || name === 'chain' ||
2012
+ name === 'data' || name === 'message') isPrivate = false;
2013
+
2014
+ let Storage;
2015
+ if (this.hasDaemon) {
2016
+ Storage = LeofcoinStorageClient;
2017
+ } else {
2018
+ Storage = LeofcoinStorage$1;
2019
+ }
2020
+ globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
2021
+ await new Storage(`${prefix}-${name}`, root);
2022
+
2023
+ globalThis[`${name}Store`].private = isPrivate;
2024
+ if (!isPrivate) this.stores.push(name);
2025
+ }
2026
+
2027
+
2028
+ /**
2029
+ * @see MessageHandler
2030
+ */
2031
+ prepareMessage(to, data) {
2032
+ return this._messageHandler.prepareMessage(this.id, to, data)
2033
+ }
2034
+
2035
+ /**
2036
+ * @access public
2037
+ *
2038
+ * @return {Array} peerId
2039
+ */
2040
+ get peers() {
2041
+ return [...connections.values()]
2042
+ }
2043
+
2044
+ /**
2045
+ * @private
2046
+ *
2047
+ * @param {Object} options
2048
+ * @param {String} options.root - path to root directory
2049
+ *
2050
+ * @return {Promise} instance of Peernet
2051
+ */
2052
+ async _init(options) {
2053
+ // peernetDHT aka closesPeer by coordinates
2054
+ /**
2055
+ * @type {Object}
2056
+ * @property {Object} peer Instance of Peer
2057
+ */
2058
+ this.dht = new DhtEarth();
2059
+ /**
2060
+ * @type {Map}
2061
+ * @property {Object} peer Instance of Peer
2062
+ */
2063
+ this.peerMap = new Map();
2064
+ this.stores = [];
2065
+ this.requestProtos = {};
2066
+ this.storePrefix = options.storePrefix;
2067
+ this.root = options.root;
2068
+
2069
+ /**
2070
+ * proto Object containing protos
2071
+ * @type {Object}
2072
+ * @property {PeernetMessage} protos[peernet-message] messageNode
2073
+ * @property {DHTMessage} protos[peernet-dht] messageNode
2074
+ * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
2075
+ * @property {DataMessage} protos[peernet-data] messageNode
2076
+ * @property {DataMessageResponse} protos[peernet-data-response] messageNode
2077
+ */
2078
+ globalThis.peernet.protos = {
2079
+ 'peernet-request': RequestMessage,
2080
+ 'peernet-response': ResponseMessage,
2081
+ 'peernet-peer': PeerMessage,
2082
+ 'peernet-peer-response': PeerMessageResponse,
2083
+ 'peernet-message': PeernetMessage,
2084
+ 'peernet-dht': DHTMessage,
2085
+ 'peernet-dht-response': DHTMessageResponse,
2086
+ 'peernet-data': DataMessage,
2087
+ 'peernet-data-response': DataMessageResponse,
2088
+ 'peernet-ps': PsMessage,
2089
+ 'chat-message': ChatMessage,
2090
+ };
2091
+
2092
+ this.protos = globalThis.peernet.protos;
2093
+ this.codecs = codecs;
2094
+
2095
+ this._messageHandler = new MessageHandler(this.network);
2096
+
2097
+ const {daemon, environment} = await target();
2098
+ this.hasDaemon = daemon;
2099
+
2100
+ if (this.hasDaemon) {
2101
+ globalThis.peernet.client = await httpClient({
2102
+ protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port,
2103
+ });
2104
+ } else {
2105
+ if (environment !== 'browser') http(options);
2106
+ }
2107
+
2108
+ for (const store of this.defaultStores) {
2109
+ await this.addStore(store, options.storePrefix, options.root);
2110
+ }
2111
+
2112
+ try {
2113
+ const pub = await accountStore.get('public');
2114
+ this.id = pub.walletId;
2115
+ } catch (e) {
2116
+ if (e.code === 'ERR_NOT_FOUND') {
2117
+ const wallet = {};
2118
+ const {identity, accounts, config} = await generateAccount(this.network);
2119
+ wallet.identity = identity;
2120
+ wallet.accounts = accounts;
2121
+ wallet.version = 1;
2122
+ walletStore.put(wallet);
2123
+ await accountStore.put('config', config);
2124
+ await accountStore.put('public', {walletId: wallet.identity.walletId});
2125
+
2126
+ this.id = wallet.identity.walletId;
2127
+ } else {
2128
+ throw e
2129
+ }
2130
+ }
2131
+ this._peerHandler = new PeerDiscovery(this.id);
2132
+ // peernet id
2133
+ const id = Buffer.from(this.id.slice(0, 32));
2134
+ this.peerId = id;
2135
+
2136
+ pubsub.subscribe('peer:discovered', async (peer) => {
2137
+ this._peerHandler.discover(peer);
2138
+ peer.on('peernet.data', async (message) => {
2139
+ const id = message.id;
2140
+ message = new PeernetMessage(Buffer.from(message.data.data));
2141
+ const proto = protoFor(message.decoded.data);
2142
+ await this._protoHandler({id, proto}, peer);
2143
+ const fulldId = this._getPeerId(peer.id);
2144
+ if (fulldId && this._discovered.indexOf(peer.id) === -1) {
2145
+ this._discovered.push(peer.id);
2146
+ pubsub.publish('peer:connected', peer);
2147
+ }
2148
+ });
2149
+ });
2150
+ pubsub.subscribe('peer:disconnected', async (peer) => {
2151
+ let index = this._discovered.indexOf(peer.id);
2152
+ if (index !== -1) this._discovered.splice(index, 1);
2153
+ const id = this._getPeerId(peer.id);
2154
+ let peerIds = this.peerMap.get(id);
2155
+
2156
+ if (peerIds) {
2157
+ index = peerIds.indexOf(peer.id);
2158
+ if (index !== -1) peerIds.splice(index, 1);
2159
+ } else {
2160
+ peerIds = [];
2161
+ }
2162
+
2163
+ if (peerIds.length === 0) this.peerMap.delete(id);
2164
+ else this.peerMap.set(id, peerIds);
2165
+ });
2166
+ pubsub.subscribe('peer:connected', async (peer) => {
2167
+ console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2168
+ // peer.on('peernet.data', async (message) => {
2169
+ // const id = message.id
2170
+ // message = new PeernetMessage(Buffer.from(message.data.data))
2171
+ // const proto = protoFor(message.decoded.data)
2172
+ // this._protoHandler({id, proto}, peer)
2173
+ // })
2174
+ });
2175
+
2176
+ /**
2177
+ * @access public
2178
+ * @type {PeernetClient}
2179
+ */
2180
+ this.client = new PeernetClient({...options, id});
2181
+ return this
2182
+ }
2183
+
2184
+ _getPeerId(id) {
2185
+ for (const entry of [...this.peerMap.entries()]) {
2186
+ for (const _id of entry[1]) {
2187
+ if (_id === id) return entry[0]
2188
+ }
2189
+ }
2190
+ }
2191
+
2192
+ addRequestHandler(name, method) {
2193
+ this.requestProtos[name] = method;
2194
+ }
2195
+
2196
+ /**
2197
+ * @private
2198
+ *
2199
+ * @param {Buffer} message - peernet message
2200
+ * @param {PeernetPeer} peer - peernet peer
2201
+ */
2202
+ async _protoHandler(message, peer) {
2203
+ const {id, proto} = message;
2204
+ if (proto.name === 'peernet-peer') {
2205
+ const from = proto.decoded.id;
2206
+ if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2207
+ else {
2208
+ const connections = this.peerMap.get(from);
2209
+ if (connections.indexOf(peer.id) === -1) {
2210
+ connections.push(peer.id);
2211
+ this.peerMap.set(from, connections);
2212
+ }
2213
+ }
2214
+ const data = new PeerMessageResponse({id: this.id});
2215
+ const node = await this.prepareMessage(from, data.encoded);
2216
+
2217
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2218
+ } else if (proto.name === 'peernet-peer-response') {
2219
+ const from = proto.decoded.id;
2220
+ if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2221
+ else {
2222
+ const connections = this.peerMap.get(from);
2223
+ if (connections.indexOf(peer.id) === -1) {
2224
+ connections.push(peer.id);
2225
+ this.peerMap.set(from, connections);
2226
+ }
2227
+ }
2228
+ } else {
2229
+ let from = this._getPeerId(peer.id);
2230
+ if (!from) {
2231
+ const data = new PeerMessage({id: this.id});
2232
+ const node = await this.prepareMessage(peer.id, data.encoded);
2233
+
2234
+ let response = await peer.request(node.encoded);
2235
+ response = protoFor(response);
2236
+ response = new PeerMessageResponse(response.decoded.data);
2237
+
2238
+ from = response.decoded.id;
2239
+ if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2240
+ else {
2241
+ const connections = this.peerMap.get(from);
2242
+ if (connections.indexOf(peer.id) === -1) {
2243
+ connections.push(peer.id);
2244
+ this.peerMap.set(from, connections);
2245
+ }
2246
+ }
2247
+ }
2248
+ if (proto.name === 'peernet-dht') {
2249
+ let { hash, store } = proto.decoded;
2250
+ let has;
2251
+
2252
+ if (!store) {
2253
+ has = await this.has(hash);
2254
+ } else {
2255
+ store = globalThis[`${store}Store`];
2256
+ if (store.private) has = false;
2257
+ else has = await store.has(hash);
2258
+ }
2259
+ const data = new DHTMessageResponse({hash, has});
2260
+ const node = await this.prepareMessage(from, data.encoded);
2261
+
2262
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2263
+ } else if (proto.name === 'peernet-data') {
2264
+ let { hash, store } = proto.decoded;
2265
+ let data;
2266
+
2267
+ if (!store) {
2268
+ data = await this.get(hash);
2269
+ } else {
2270
+ store = globalThis[`${store}Store`];
2271
+ if (store.private) {
2272
+ // TODO: ban
2273
+ return
2274
+ } else data = await store.get(hash);
2275
+ }
2276
+
2277
+ if (data) {
2278
+ data = new DataMessageResponse({hash, data: Buffer.from(data)});
2279
+
2280
+ const node = await this.prepareMessage(from, data.encoded);
2281
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2282
+ }
2283
+ } else if (proto.name === 'peernet-peer') {
2284
+ const from = proto.decoded.id;
2285
+ if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2286
+ else {
2287
+ const connections = this.peerMap.get(from);
2288
+ connections.push(peer.id);
2289
+ this.peerMap.set(from, connections);
2290
+ }
2291
+ const data = new PeerMessage({id: this.id});
2292
+ const node = await this.prepareMessage(from, data.encoded);
2293
+
2294
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2295
+ } else if (proto.name === 'peernet-request') {
2296
+ // TODO: make dynamic
2297
+ // exposeddevapi[proto.decoded.request](proto.decoded.params)
2298
+ const method = this.requestProtos[proto.decoded.request];
2299
+ if (method) {
2300
+ const data = await method();
2301
+ const node = await this.prepareMessage(from, data.encoded);
2302
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2303
+ }
2304
+ } else if (proto.name === 'peernet-ps' &&
2305
+ this._getPeerId(peer.id) !== this.id.toString()) {
2306
+ globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
2307
+ }
2308
+ }
2309
+ }
2310
+
2311
+ /**
2312
+ * performs a walk and resolves first encounter
2313
+ *
2314
+ * @param {String} hash
2315
+ */
2316
+ async walk(hash) {
2317
+ if (!hash) throw new Error('hash expected, received undefined')
2318
+ const data = new DHTMessage({hash});
2319
+ this.client.id;
2320
+ for (const peer of this.peers) {
2321
+ const node = await this.prepareMessage(peer.id, data.encoded);
2322
+
2323
+ const result = await peer.request(node.encoded);
2324
+
2325
+ let proto = protoFor(result.data);
2326
+
2327
+ if (proto.name !== 'peernet-message') throw encapsulatedError()
2328
+ const from = proto.decoded.from;
2329
+ proto = protoFor(proto.decoded.data);
2330
+
2331
+ if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2332
+
2333
+ // TODO: give ip and port (just used for location)
2334
+ if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2335
+ peer.connection.remoteFamily = 'ipv4';
2336
+ peer.connection.remoteAddress = '127.0.0.1';
2337
+ peer.connection.remotePort = '0000';
2338
+ }
2339
+
2340
+ const peerInfo = {
2341
+ family: peer.connection.remoteFamily || peer.connection.localFamily,
2342
+ address: peer.connection.remoteAddress || peer.connection.localAddress,
2343
+ port: peer.connection.remotePort || peer.connection.localPort,
2344
+ id: from,
2345
+ };
2346
+
2347
+ if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2348
+ }
2349
+ return
2350
+ }
2351
+
2352
+ /**
2353
+ * Override DHT behavior, try's finding the content three times
2354
+ *
2355
+ * @param {String} hash
2356
+ */
2357
+ async providersFor(hash) {
2358
+ let providers = await this.dht.providersFor(hash);
2359
+ // walk the network to find a provider
2360
+ if (!providers || providers.length === 0) {
2361
+ await this.walk(hash);
2362
+ providers = await this.dht.providersFor(hash);
2363
+ // second walk the network to find a provider
2364
+ if (!providers || providers.length === 0) {
2365
+ await this.walk(hash);
2366
+ providers = await this.dht.providersFor(hash);
2367
+ }
2368
+ // last walk
2369
+ if (!providers || providers.length === 0) {
2370
+ await this.walk(hash);
2371
+ providers = await this.dht.providersFor(hash);
2372
+ }
2373
+ }
2374
+ // undefined if no providers given
2375
+ return providers
2376
+ }
2377
+
2378
+ get block() {
2379
+ return {
2380
+ get: async (hash) => {
2381
+ const data = await blockStore.has(hash);
2382
+ if (data) return await blockStore.get(hash)
2383
+ return this.requestData(hash)
2384
+ },
2385
+ put: async (hash, data) => {
2386
+ if (await blockStore.has(hash)) return
2387
+ return await blockStore.put(hash, data)
2388
+ },
2389
+ has: async (hash) => await blockStore.has(hash, 'block'),
2390
+ }
2391
+ }
2392
+
2393
+ get transaction() {
2394
+ return {
2395
+ get: async (hash) => {
2396
+ const data = await transactionStore.has(hash);
2397
+ if (data) return await transactionStore.get(hash)
2398
+ return this.requestData(hash, 'transaction')
2399
+ },
2400
+ put: async (hash, data) => {
2401
+ if (await transactionStore.has(hash)) return
2402
+ return await transactionStore.put(hash, data)
2403
+ },
2404
+ has: async (hash) => await transactionStore.has(hash),
2405
+ }
2406
+ }
2407
+
2408
+ async requestData(hash, store) {
2409
+ const providers = await this.providersFor(hash);
2410
+ if (!providers || providers.size === 0) throw nothingFoundError(hash)
2411
+ debug(`found ${providers.size} provider(s) for ${hash}`);
2412
+ // get closest peer on earth
2413
+ const closestPeer = await this.dht.closestPeer(providers);
2414
+ // get peer instance by id
2415
+ if (!closestPeer || !closestPeer.id) return this.requestData(hash, store)
2416
+
2417
+ const id = closestPeer.id.toString();
2418
+ if (this.peers) {
2419
+ let closest = this.peers.filter((peer) => {
2420
+ if (this._getPeerId(peer.id) === id) return peer
2421
+ });
2422
+
2423
+ let data = new DataMessage({hash, store});
2424
+
2425
+ const node = await this.prepareMessage(id, data.encoded);
2426
+ if (closest[0]) data = await closest[0].request(node.encoded);
2427
+ else {
2428
+ closest = this.peers.filter((peer) => {
2429
+ if (peer.id.toString() === id) return peer
2430
+ });
2431
+ if (closest[0]) data = await closest[0].request(node.encoded);
2432
+ }
2433
+ if (data.data) {
2434
+ let proto = protoFor(Buffer.from(data.data));
2435
+ proto = protoFor(proto.decoded.data);
2436
+ return proto.decoded.data
2437
+ }
2438
+
2439
+ // this.put(hash, proto.decoded.data)
2440
+ }
2441
+ return null
2442
+ }
2443
+
2444
+
2445
+ get message() {
2446
+ return {
2447
+ /**
2448
+ * Get content for given message hash
2449
+ *
2450
+ * @param {String} hash
2451
+ */
2452
+ get: async (hash) => {
2453
+ debug(`get message ${hash}`);
2454
+ const message = await messageStore.has(hash);
2455
+ if (message) return await messageStore.get(hash)
2456
+ return this.requestData(hash, 'message')
2457
+ },
2458
+ /**
2459
+ * put message content
2460
+ *
2461
+ * @param {String} hash
2462
+ * @param {Buffer} message
2463
+ */
2464
+ put: async (hash, message) => await messageStore.put(hash, message),
2465
+ /**
2466
+ * @param {String} hash
2467
+ * @return {Boolean}
2468
+ */
2469
+ has: async (hash) => await messageStore.has(hash),
2470
+ }
2471
+ }
2472
+
2473
+ get data() {
2474
+ return {
2475
+ /**
2476
+ * Get content for given data hash
2477
+ *
2478
+ * @param {String} hash
2479
+ */
2480
+ get: async (hash) => {
2481
+ debug(`get data ${hash}`);
2482
+ const data = await dataStore.has(hash);
2483
+ if (data) return await dataStore.get(hash)
2484
+ return this.requestData(hash, 'data')
2485
+ },
2486
+ /**
2487
+ * put data content
2488
+ *
2489
+ * @param {String} hash
2490
+ * @param {Buffer} data
2491
+ */
2492
+ put: async (hash, data) => await dataStore.put(hash, data),
2493
+ /**
2494
+ * @param {String} hash
2495
+ * @return {Boolean}
2496
+ */
2497
+ has: async (hash) => await dataStore.has(hash),
2498
+ }
2499
+ }
2500
+
2501
+ /**
2502
+ * goes trough given stores and tries to find data for given hash
2503
+ * @param {Array} stores
2504
+ * @param {string} hash
2505
+ */
2506
+ async whichStore(stores, hash) {
2507
+ let store = stores.pop();
2508
+ store = globalThis[`${store}Store`];
2509
+ if (store) {
2510
+ const has = await store.has(hash);
2511
+ if (has) return store
2512
+ if (stores.length > 0) return this.whichStore(stores, hash)
2513
+ } else return null
2514
+ }
2515
+
2516
+ /**
2517
+ * Get content for given hash
2518
+ *
2519
+ * @param {String} hash
2520
+ */
2521
+ async get(hash, store) {
2522
+ debug(`get ${hash}`);
2523
+ let data;
2524
+ if (store) store = globalThis[`${store}Store`];
2525
+ if (!store) store = await this.whichStore([...this.stores], hash);
2526
+ if (store && await store.has(hash)) data = await store.get(hash);
2527
+ if (data) return data
2528
+
2529
+ return this.requestData(hash, 'data')
2530
+ }
2531
+
2532
+ /**
2533
+ * put content
2534
+ *
2535
+ * @param {String} hash
2536
+ * @param {Buffer} data
2537
+ */
2538
+ async put(hash, data, store = 'data') {
2539
+ store = globalThis[`${store}Store`];
2540
+ return await store.put(hash, data)
2541
+ }
2542
+
2543
+ /**
2544
+ * @param {String} hash
2545
+ * @return {Boolean}
2546
+ */
2547
+ async has(hash) {
2548
+ const store = await this.whichStore([...this.stores], hash);
2549
+ if (store) {
2550
+ if (store.private) return false
2551
+ else return true
2552
+ }
2553
+ return false
2554
+ }
2555
+
2556
+ /**
2557
+ *
2558
+ * @param {String} topic
2559
+ * @param {String|Object|Array|Boolean|Buffer} data
2560
+ */
2561
+ async publish(topic, data) {
2562
+ // globalSub.publish(topic, data)
2563
+ if (!Buffer.isBuffer(topic)) topic = Buffer.from(topic);
2564
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data);
2565
+ const id = Math.random().toString(36).slice(-12);
2566
+ data = new PsMessage({data, topic});
2567
+ for (const peer of this.peers) {
2568
+ if (peer.connection._connected) {
2569
+ if (peer.id.toString() !== this.peerId.toString()) {
2570
+ const node = await this.prepareMessage(peer.id, data.encoded);
2571
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
2572
+ }
2573
+ } else {
2574
+ this.removePeer(peer);
2575
+ }
2576
+ // TODO: if peer subscribed
2577
+ }
2578
+ }
2579
+
2580
+ createHash(data, name) {
2581
+ return new PeernetHash(data, {name})
2582
+ }
2583
+
2584
+ /**
2585
+ *
2586
+ * @param {String} topic
2587
+ * @param {Method} cb
2588
+ */
2589
+ async subscribe(topic, cb) {
2590
+ // TODO: if peer subscribed
2591
+ globalSub.subscribe(topic, cb);
2592
+ }
2593
+
2594
+ async removePeer(peer) {
2595
+ connections.delete(peer.id);
2596
+ }
2597
+
2598
+ get Buffer() {
2599
+ return Buffer
2600
+ }
2601
+ // async block(index) {
2602
+ // const _values = []
2603
+ // for (const peer of this.peers) {
2604
+ // const value = await peer.request({type: 'block', index})
2605
+ // console.log(value);
2606
+ // }
2607
+ //
2608
+ // }
2604
2609
  }
2605
2610
 
2606
2611
  module.exports = Peernet;