chore: persist delete with test

This commit is contained in:
Vasco Santos 2020-04-28 09:34:13 +02:00 committed by Jacob Heun
parent 5123a8357b
commit 9ea9287bea
5 changed files with 118 additions and 64 deletions

View File

@ -113,9 +113,9 @@ All the knownw peer protocols are stored with a key pattern as follows:
_NOT_YET_IMPLEMENTED_ _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/<b32 peer id no padding>/{pub, priv}` ` /peers/keys/<b32 peer id no padding>`
**MetadataBook** **MetadataBook**

View File

@ -40,17 +40,24 @@ class AddressBook extends Book {
*/ */
super({ super({
peerStore, peerStore,
eventName: 'change:multiaddrs', event: {
eventProperty: 'multiaddrs', name: 'change:multiaddrs',
protoBuf: Protobuf, property: 'multiaddrs',
dsPrefix: '/peers/addrs/', transformer: (data) => data.map((address) => address.multiaddr)
eventTransformer: (data) => data.map((address) => address.multiaddr), },
dsSetTransformer: (data) => ({ ds: {
addrs: data.map((address) => address.multiaddr.buffer) prefix: '/peers/addrs/',
}), setTransformer: (data) => Protobuf.encode({
dsGetTransformer: (data) => data.addrs.map((a) => ({ addrs: data.map((address) => address.multiaddr.buffer)
multiaddr: multiaddr(a) }),
})) getTransformer: (encData) => {
const data = Protobuf.decode(encData)
return data.addrs.map((a) => ({
multiaddr: multiaddr(a)
}))
}
}
}) })
/** /**

View File

@ -23,35 +23,24 @@ class Book {
* @constructor * @constructor
* @param {Object} properties * @param {Object} properties
* @param {PeerStore} properties.peerStore PeerStore instance. * @param {PeerStore} properties.peerStore PeerStore instance.
* @param {string} properties.eventName Name of the event to emit by the PeerStore. * @param {Object} [properties.event] Event properties. If not provided, no events will be emitted.
* @param {string} properties.eventProperty Name of the property to emit by the PeerStore. * @param {string} [properties.event.name] Name of the event to emit by the PeerStore.
* @param {Object} properties.protoBuf Suffix of the Datastore Key * @param {string} [properties.event.property] Name of the property to emit by the PeerStore.
* @param {String} properties.dsPrefix Prefix of the Datastore Key * @param {function} [properties.events.transformer] Transformer function of the provided data for being emitted.
* @param {String} [properties.dsSuffix] Suffix of the Datastore Key * @param {Object} [properties.ds] Datastore properties. If not provided, no data will be persisted.
* @param {function} [properties.eventTransformer] Transformer function of the provided data for being emitted. * @param {String} [properties.ds.prefix] Prefix of the Datastore Key
* @param {function} [properties.dsSetTransformer] Transformer function of the provided data for being persisted. * @param {String} [properties.ds.suffix = ''] Suffix of the Datastore Key
* @param {function} [properties.dsGetTransformer] Transformer function of the persisted data to be loaded. * @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 ({ constructor ({
peerStore, peerStore,
eventName, event,
eventProperty, ds
protoBuf,
dsPrefix,
dsSuffix = '',
eventTransformer = passthrough,
dsSetTransformer = passthrough,
dsGetTransformer = passthrough
}) { }) {
this._ps = peerStore this._ps = peerStore
this.eventName = eventName this.event = event
this.eventProperty = eventProperty this.ds = ds
this.protoBuf = protoBuf
this.dsPrefix = dsPrefix
this.dsSuffix = dsSuffix
this.eventTransformer = eventTransformer
this.dsSetTransformer = dsSetTransformer
this.dsGetTransformer = dsGetTransformer
/** /**
* Map known peers to their data. * Map known peers to their data.
@ -67,23 +56,23 @@ class Book {
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async _loadData () { async _loadData () {
if (!this._ps._datastore || !this._ps._enabledPersistance) { if (!this._ps._datastore || !this._ps._enabledPersistance || !this.ds) {
return return
} }
const persistenceQuery = { const prefix = this.ds.prefix || ''
prefix: this.dsPrefix 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 { try {
// PeerId to add to the book // PeerId to add to the book
const b32key = key.toString() const b32key = key.toString()
.replace(this.dsPrefix, '') // remove prefix from key .replace(prefix, '') // remove prefix from key
.replace(this.dsSuffix, '') // remove suffix from key .replace(suffix, '') // remove suffix from key
const peerId = PeerId.createFromCID(b32key) const peerId = PeerId.createFromCID(b32key)
// Data in the format to add to the book // 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 // Add the book without persist the replicated data and emit modify
this._setData(peerId, data, { this._setData(peerId, data, {
persist: false, persist: false,
@ -113,10 +102,14 @@ class Book {
this._setPeerId(peerId) this._setPeerId(peerId)
// Emit event // Emit event
emit && this._ps.emit(this.eventName, { if (this.event && emit) {
peerId, const transformer = this.event.transformer || passthrough
[this.eventProperty]: this.eventTransformer(data)
}) this._ps.emit(this.event.name, {
peerId,
[this.event.property]: transformer(data)
})
}
// Add to Persistence datastore // Add to Persistence datastore
persist && await this._persistData(peerId, data) persist && await this._persistData(peerId, data)
@ -130,14 +123,18 @@ class Book {
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async _persistData (peerId, data) { async _persistData (peerId, data) {
if (!this._ps._datastore || !this._ps._enabledPersistance) { if (!this._ps._datastore || !this._ps._enabledPersistance || !this.ds) {
return return
} }
const prefix = this.ds.prefix || ''
const suffix = this.ds.suffix || ''
const transformer = this.ds.setTransformer || passthrough
const b32key = peerId.toString() const b32key = peerId.toString()
const k = `${this.dsPrefix}${b32key}${this.dsSuffix}` const k = `${prefix}${b32key}${suffix}`
try { try {
const value = this.protoBuf.encode(this.dsSetTransformer(data)) const value = transformer(data)
await this._ps._datastore.put(new Key(k), value) await this._ps._datastore.put(new Key(k), value)
} catch (err) { } catch (err) {
@ -192,13 +189,21 @@ class Book {
return false return false
} }
this._ps.emit(this.eventName, { // Emit event
this.event && this._ps.emit(this.event.name, {
peerId, peerId,
[this.eventProperty]: [] [this.event.property]: []
}) })
// Update Persistence datastore // 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 return true
} }

View File

@ -32,15 +32,22 @@ class ProtoBook extends Book {
*/ */
super({ super({
peerStore, peerStore,
eventName: 'change:protocols', event: {
eventProperty: 'protocols', name: 'change:protocols',
protoBuf: Protobuf, property: 'protocols',
dsPrefix: '/peers/protos/', transformer: (data) => Array.from(data)
eventTransformer: (data) => Array.from(data), },
dsSetTransformer: (data) => ({ ds: {
protocols: Array.from(data) prefix: '/peers/protos/',
}), setTransformer: (data) => Protobuf.encode({
dsGetTransformer: (data) => new Set(data.protocols) protocols: Array.from(data)
}),
getTransformer: (encData) => {
const data = Protobuf.decode(encData)
return new Set(data.protocols)
}
}
}) })
/** /**

View File

@ -305,4 +305,39 @@ describe('libp2p.peerStore', () => {
await newNode.stop() 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')
}
})
}) })