@libp2p/peer-store
Version:
Stores information about peers libp2p knows on the network
179 lines • 6.06 kB
JavaScript
/**
* @packageDocumentation
*
* The peer store is where libp2p stores data about the peers it has encountered on the network.
*/
import { peerIdFromCID } from '@libp2p/peer-id';
import { RecordEnvelope, PeerRecord } from '@libp2p/peer-record';
import all from 'it-all';
import { PersistentStore } from './store.js';
/**
* An implementation of PeerStore that stores data in a Datastore
*/
class PersistentPeerStore {
store;
events;
peerId;
log;
constructor(components, init = {}) {
this.log = components.logger.forComponent('libp2p:peer-store');
this.events = components.events;
this.peerId = components.peerId;
this.store = new PersistentStore(components, init);
}
[Symbol.toStringTag] = '@libp2p/peer-store';
async forEach(fn, query) {
this.log.trace('forEach await read lock');
const release = await this.store.lock.readLock();
this.log.trace('forEach got read lock');
try {
for await (const peer of this.store.all(query)) {
fn(peer);
}
}
finally {
this.log.trace('forEach release read lock');
release();
}
}
async all(query) {
this.log.trace('all await read lock');
const release = await this.store.lock.readLock();
this.log.trace('all got read lock');
try {
return await all(this.store.all(query));
}
finally {
this.log.trace('all release read lock');
release();
}
}
async delete(peerId) {
this.log.trace('delete await write lock');
const release = await this.store.lock.writeLock();
this.log.trace('delete got write lock');
try {
await this.store.delete(peerId);
}
finally {
this.log.trace('delete release write lock');
release();
}
}
async has(peerId) {
this.log.trace('has await read lock');
const release = await this.store.lock.readLock();
this.log.trace('has got read lock');
try {
return await this.store.has(peerId);
}
finally {
this.log.trace('has release read lock');
release();
}
}
async get(peerId) {
this.log.trace('get await read lock');
const release = await this.store.lock.readLock();
this.log.trace('get got read lock');
try {
return await this.store.load(peerId);
}
finally {
this.log.trace('get release read lock');
release();
}
}
async save(id, data) {
this.log.trace('save await write lock');
const release = await this.store.lock.writeLock();
this.log.trace('save got write lock');
try {
const result = await this.store.save(id, data);
this.#emitIfUpdated(id, result);
return result.peer;
}
finally {
this.log.trace('save release write lock');
release();
}
}
async patch(id, data) {
this.log.trace('patch await write lock');
const release = await this.store.lock.writeLock();
this.log.trace('patch got write lock');
try {
const result = await this.store.patch(id, data);
this.#emitIfUpdated(id, result);
return result.peer;
}
finally {
this.log.trace('patch release write lock');
release();
}
}
async merge(id, data) {
this.log.trace('merge await write lock');
const release = await this.store.lock.writeLock();
this.log.trace('merge got write lock');
try {
const result = await this.store.merge(id, data);
this.#emitIfUpdated(id, result);
return result.peer;
}
finally {
this.log.trace('merge release write lock');
release();
}
}
async consumePeerRecord(buf, expectedPeer) {
const envelope = await RecordEnvelope.openAndCertify(buf, PeerRecord.DOMAIN);
const peerId = peerIdFromCID(envelope.publicKey.toCID());
if (expectedPeer?.equals(peerId) === false) {
this.log('envelope peer id was not the expected peer id - expected: %p received: %p', expectedPeer, peerId);
return false;
}
const peerRecord = PeerRecord.createFromProtobuf(envelope.payload);
let peer;
try {
peer = await this.get(peerId);
}
catch (err) {
if (err.name !== 'NotFoundError') {
throw err;
}
}
// ensure seq is greater than, or equal to, the last received
if (peer?.peerRecordEnvelope != null) {
const storedEnvelope = await RecordEnvelope.createFromProtobuf(peer.peerRecordEnvelope);
const storedRecord = PeerRecord.createFromProtobuf(storedEnvelope.payload);
if (storedRecord.seqNumber >= peerRecord.seqNumber) {
this.log('sequence number was lower or equal to existing sequence number - stored: %d received: %d', storedRecord.seqNumber, peerRecord.seqNumber);
return false;
}
}
await this.patch(peerRecord.peerId, {
peerRecordEnvelope: buf,
addresses: peerRecord.multiaddrs.map(multiaddr => ({
isCertified: true,
multiaddr
}))
});
return true;
}
#emitIfUpdated(id, result) {
if (!result.updated) {
return;
}
if (this.peerId.equals(id)) {
this.events.safeDispatchEvent('self:peer:update', { detail: result });
}
else {
this.events.safeDispatchEvent('peer:update', { detail: result });
}
}
}
export function persistentPeerStore(components, init = {}) {
return new PersistentPeerStore(components, init);
}
//# sourceMappingURL=index.js.map