diff --git a/src/peer-store/README.md b/src/peer-store/README.md index 3dd121fa..f0407b65 100644 --- a/src/peer-store/README.md +++ b/src/peer-store/README.md @@ -113,9 +113,9 @@ All the knownw peer protocols are stored with a key pattern as follows: _NOT_YET_IMPLEMENTED_ -All public and private keys are stored under the following pattern: +All public keys are stored under the following pattern: -` /peers/keys//{pub, priv}` +` /peers/keys/` **MetadataBook** diff --git a/src/peer-store/address-book.js b/src/peer-store/address-book.js index d8ef75b7..62c47225 100644 --- a/src/peer-store/address-book.js +++ b/src/peer-store/address-book.js @@ -40,17 +40,24 @@ class AddressBook extends Book { */ super({ peerStore, - eventName: 'change:multiaddrs', - eventProperty: 'multiaddrs', - protoBuf: Protobuf, - dsPrefix: '/peers/addrs/', - eventTransformer: (data) => data.map((address) => address.multiaddr), - dsSetTransformer: (data) => ({ - addrs: data.map((address) => address.multiaddr.buffer) - }), - dsGetTransformer: (data) => data.addrs.map((a) => ({ - multiaddr: multiaddr(a) - })) + event: { + name: 'change:multiaddrs', + property: 'multiaddrs', + transformer: (data) => data.map((address) => address.multiaddr) + }, + ds: { + prefix: '/peers/addrs/', + setTransformer: (data) => Protobuf.encode({ + addrs: data.map((address) => address.multiaddr.buffer) + }), + getTransformer: (encData) => { + const data = Protobuf.decode(encData) + + return data.addrs.map((a) => ({ + multiaddr: multiaddr(a) + })) + } + } }) /** diff --git a/src/peer-store/book.js b/src/peer-store/book.js index ac8d5ea0..eb2369c2 100644 --- a/src/peer-store/book.js +++ b/src/peer-store/book.js @@ -23,35 +23,24 @@ class Book { * @constructor * @param {Object} properties * @param {PeerStore} properties.peerStore PeerStore instance. - * @param {string} properties.eventName Name of the event to emit by the PeerStore. - * @param {string} properties.eventProperty Name of the property to emit by the PeerStore. - * @param {Object} properties.protoBuf Suffix of the Datastore Key - * @param {String} properties.dsPrefix Prefix of the Datastore Key - * @param {String} [properties.dsSuffix] Suffix of the Datastore Key - * @param {function} [properties.eventTransformer] Transformer function of the provided data for being emitted. - * @param {function} [properties.dsSetTransformer] Transformer function of the provided data for being persisted. - * @param {function} [properties.dsGetTransformer] Transformer function of the persisted data to be loaded. + * @param {Object} [properties.event] Event properties. If not provided, no events will be emitted. + * @param {string} [properties.event.name] Name of the event to emit by the PeerStore. + * @param {string} [properties.event.property] Name of the property to emit by the PeerStore. + * @param {function} [properties.events.transformer] Transformer function of the provided data for being emitted. + * @param {Object} [properties.ds] Datastore properties. If not provided, no data will be persisted. + * @param {String} [properties.ds.prefix] Prefix of the Datastore Key + * @param {String} [properties.ds.suffix = ''] Suffix of the Datastore Key + * @param {function} [properties.ds.setTransformer] Transformer function of the provided data for being persisted. + * @param {function} [properties.ds.getTransformer] Transformer function of the persisted data to be loaded. */ constructor ({ peerStore, - eventName, - eventProperty, - protoBuf, - dsPrefix, - dsSuffix = '', - eventTransformer = passthrough, - dsSetTransformer = passthrough, - dsGetTransformer = passthrough + event, + ds }) { this._ps = peerStore - this.eventName = eventName - this.eventProperty = eventProperty - this.protoBuf = protoBuf - this.dsPrefix = dsPrefix - this.dsSuffix = dsSuffix - this.eventTransformer = eventTransformer - this.dsSetTransformer = dsSetTransformer - this.dsGetTransformer = dsGetTransformer + this.event = event + this.ds = ds /** * Map known peers to their data. @@ -67,23 +56,23 @@ class Book { * @return {Promise} */ async _loadData () { - if (!this._ps._datastore || !this._ps._enabledPersistance) { + if (!this._ps._datastore || !this._ps._enabledPersistance || !this.ds) { return } - const persistenceQuery = { - prefix: this.dsPrefix - } + const prefix = this.ds.prefix || '' + const suffix = this.ds.suffix || '' + const transformer = this.ds.getTransformer || passthrough - for await (const { key, value } of this._ps._datastore.query(persistenceQuery)) { + for await (const { key, value } of this._ps._datastore.query({ prefix })) { try { // PeerId to add to the book const b32key = key.toString() - .replace(this.dsPrefix, '') // remove prefix from key - .replace(this.dsSuffix, '') // remove suffix from key + .replace(prefix, '') // remove prefix from key + .replace(suffix, '') // remove suffix from key const peerId = PeerId.createFromCID(b32key) // Data in the format to add to the book - const data = this.dsGetTransformer(this.protoBuf.decode(value)) + const data = transformer(value) // Add the book without persist the replicated data and emit modify this._setData(peerId, data, { persist: false, @@ -113,10 +102,14 @@ class Book { this._setPeerId(peerId) // Emit event - emit && this._ps.emit(this.eventName, { - peerId, - [this.eventProperty]: this.eventTransformer(data) - }) + if (this.event && emit) { + const transformer = this.event.transformer || passthrough + + this._ps.emit(this.event.name, { + peerId, + [this.event.property]: transformer(data) + }) + } // Add to Persistence datastore persist && await this._persistData(peerId, data) @@ -130,14 +123,18 @@ class Book { * @return {Promise} */ async _persistData (peerId, data) { - if (!this._ps._datastore || !this._ps._enabledPersistance) { + if (!this._ps._datastore || !this._ps._enabledPersistance || !this.ds) { return } + const prefix = this.ds.prefix || '' + const suffix = this.ds.suffix || '' + const transformer = this.ds.setTransformer || passthrough + const b32key = peerId.toString() - const k = `${this.dsPrefix}${b32key}${this.dsSuffix}` + const k = `${prefix}${b32key}${suffix}` try { - const value = this.protoBuf.encode(this.dsSetTransformer(data)) + const value = transformer(data) await this._ps._datastore.put(new Key(k), value) } catch (err) { @@ -192,13 +189,21 @@ class Book { return false } - this._ps.emit(this.eventName, { + // Emit event + this.event && this._ps.emit(this.event.name, { peerId, - [this.eventProperty]: [] + [this.event.property]: [] }) // Update Persistence datastore - this._persistData(peerId, []) + if (this._ps._datastore && this._ps._enabledPersistance && this.ds) { + const prefix = this.ds.prefix || '' + const suffix = this.ds.suffix || '' + const b32key = peerId.toString() + + const k = `${prefix}${b32key}${suffix}` + this._ps._datastore.delete(new Key(k)) + } return true } diff --git a/src/peer-store/proto-book.js b/src/peer-store/proto-book.js index 48433cad..e7a1d0e1 100644 --- a/src/peer-store/proto-book.js +++ b/src/peer-store/proto-book.js @@ -32,15 +32,22 @@ class ProtoBook extends Book { */ super({ peerStore, - eventName: 'change:protocols', - eventProperty: 'protocols', - protoBuf: Protobuf, - dsPrefix: '/peers/protos/', - eventTransformer: (data) => Array.from(data), - dsSetTransformer: (data) => ({ - protocols: Array.from(data) - }), - dsGetTransformer: (data) => new Set(data.protocols) + event: { + name: 'change:protocols', + property: 'protocols', + transformer: (data) => Array.from(data) + }, + ds: { + prefix: '/peers/protos/', + setTransformer: (data) => Protobuf.encode({ + protocols: Array.from(data) + }), + getTransformer: (encData) => { + const data = Protobuf.decode(encData) + + return new Set(data.protocols) + } + } }) /** diff --git a/test/peer-store/peer-store.spec.js b/test/peer-store/peer-store.spec.js index 765316b6..64670748 100644 --- a/test/peer-store/peer-store.spec.js +++ b/test/peer-store/peer-store.spec.js @@ -305,4 +305,39 @@ describe('libp2p.peerStore', () => { await newNode.stop() }) + + it('should delete content from the datastore on delete', async () => { + const [peer] = await peerUtils.createPeerId({ number: 2 }) + const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const protocols = ['/ping/1.0.0'] + const spyDs = sinon.spy(memoryDatastore, 'delete') + const spyAddressBook = sinon.spy(libp2p.peerStore.addressBook, 'delete') + const spyProtoBook = sinon.spy(libp2p.peerStore.protoBook, 'delete') + + await libp2p.start() + + // AddressBook + await libp2p.peerStore.addressBook.set(peer, multiaddrs) + // ProtoBook + await libp2p.peerStore.protoBook.set(peer, protocols) + + expect(spyDs).to.have.property('callCount', 0) + + // Delete from PeerStore + libp2p.peerStore.delete(peer) + await libp2p.stop() + + expect(spyAddressBook).to.have.property('callCount', 1) + expect(spyProtoBook).to.have.property('callCount', 1) + expect(spyDs).to.have.property('callCount', 2) + + // Should have zero peer records stored in the datastore + const queryParams = { + prefix: '/peers/' + } + + for await (const _ of memoryDatastore.query(queryParams)) { // eslint-disable-line + throw new Error('Datastore should be empty') + } + }) })