UNPKG

libp2p

Version:

JavaScript implementation of libp2p, a modular peer to peer network stack

120 lines 3.94 kB
import { serviceCapabilities, serviceDependencies, isStartable } from '@libp2p/interface'; import { defaultLogger } from '@libp2p/logger'; import { MissingServiceError, UnmetServiceDependenciesError } from './errors.js'; class DefaultComponents { components = {}; _started = false; constructor(init = {}) { this.components = {}; for (const [key, value] of Object.entries(init)) { this.components[key] = value; } if (this.components.logger == null) { this.components.logger = defaultLogger(); } } isStarted() { return this._started; } async _invokeStartableMethod(methodName) { await Promise.all(Object.values(this.components) .filter(obj => isStartable(obj)) .map(async (startable) => { await startable[methodName]?.(); })); } async beforeStart() { await this._invokeStartableMethod('beforeStart'); } async start() { await this._invokeStartableMethod('start'); this._started = true; } async afterStart() { await this._invokeStartableMethod('afterStart'); } async beforeStop() { await this._invokeStartableMethod('beforeStop'); } async stop() { await this._invokeStartableMethod('stop'); this._started = false; } async afterStop() { await this._invokeStartableMethod('afterStop'); } } const OPTIONAL_SERVICES = [ 'metrics', 'connectionProtector', 'dns' ]; const NON_SERVICE_PROPERTIES = [ 'components', 'isStarted', 'beforeStart', 'start', 'afterStart', 'beforeStop', 'stop', 'afterStop', 'then', '_invokeStartableMethod' ]; export function defaultComponents(init = {}) { const components = new DefaultComponents(init); const proxy = new Proxy(components, { get(target, prop, receiver) { if (typeof prop === 'string' && !NON_SERVICE_PROPERTIES.includes(prop)) { const service = components.components[prop]; if (service == null && !OPTIONAL_SERVICES.includes(prop)) { throw new MissingServiceError(`${prop} not set`); } return service; } return Reflect.get(target, prop, receiver); }, set(target, prop, value) { if (typeof prop === 'string') { components.components[prop] = value; } else { Reflect.set(target, prop, value); } return true; } }); // @ts-expect-error component keys are proxied return proxy; } export function checkServiceDependencies(components) { const serviceCapabilities = {}; for (const service of Object.values(components.components)) { for (const capability of getServiceCapabilities(service)) { serviceCapabilities[capability] = true; } } for (const service of Object.values(components.components)) { for (const capability of getServiceDependencies(service)) { if (serviceCapabilities[capability] !== true) { throw new UnmetServiceDependenciesError(`Service "${getServiceName(service)}" required capability "${capability}" but it was not provided by any component, you may need to add additional configuration when creating your node.`); } } } } function getServiceCapabilities(service) { if (Array.isArray(service?.[serviceCapabilities])) { return service[serviceCapabilities]; } return []; } function getServiceDependencies(service) { if (Array.isArray(service?.[serviceDependencies])) { return service[serviceDependencies]; } return []; } function getServiceName(service) { return service?.[Symbol.toStringTag] ?? service?.toString() ?? 'unknown'; } //# sourceMappingURL=components.js.map