UNPKG

libp2p

Version:

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

116 lines 3.98 kB
import { IpNet } from '@chainsafe/netmask'; import { InvalidParametersError } from '@libp2p/interface'; import { getNetConfig } from '@libp2p/utils'; import { Circuit } from '@multiformats/multiaddr-matcher'; /** * These are speculative protocols that are run automatically on connection open * so are usually not the reason the connection was opened. * * Consequently when requested it should be safe to close connections that only * have these protocol streams open. */ const DEFAULT_CLOSABLE_PROTOCOLS = [ // identify '/ipfs/id/1.0.0', // identify-push '/ipfs/id/push/1.0.0', // autonat '/libp2p/autonat/1.0.0', // dcutr '/libp2p/dcutr' ]; /** * Close the passed connection if it has no streams, or only closable protocol * streams, falling back to aborting the connection if closing it cleanly fails. */ export async function safelyCloseConnectionIfUnused(connection, options) { const streamProtocols = connection?.streams?.map(stream => stream.protocol) ?? []; const closableProtocols = options?.closableProtocols ?? DEFAULT_CLOSABLE_PROTOCOLS; // if the connection has protocols not in the closable protocols list, do not // close the connection if (streamProtocols.filter(proto => proto != null && !closableProtocols.includes(proto)).length > 0) { return; } try { await connection?.close(options); } catch (err) { connection?.abort(err); } } /** * Converts a multiaddr string or object to an IpNet object. * If the multiaddr doesn't include /ipcidr, it will encapsulate with the appropriate CIDR: * - /ipcidr/32 for IPv4 * - /ipcidr/128 for IPv6 * * @param {string | Multiaddr} ma - The multiaddr object to convert. * @returns {IpNet} The converted IpNet object. * @throws {Error} Throws an error if the multiaddr is not valid. */ export function multiaddrToIpNet(ma) { const config = getNetConfig(ma); let mask = config.cidr; if (config.type !== 'ip4' && config.type !== 'ip6') { throw new InvalidParametersError(`Multiaddr ${ma} was not an IPv4 or IPv6 address`); } // Check if /ipcidr is already present if (mask == null) { switch (config.type) { case 'ip4': { mask = 32; break; } case 'ip6': { mask = 128; break; } default: { throw new InvalidParametersError(`Multiaddr ${ma} was not an IPv4 or IPv6 address`); } } } return new IpNet(config.host, mask); } /** * Returns true if the passed multiaddr would result in a direct connection to * the peer. * * Currently only circuit relay addresses are supported as indirect connections. */ export function isDirect(ma) { return !Circuit.exactMatch(ma); } /** * If there is an existing non-limited connection to the remote peer return it, * unless it is indirect and at least one of the passed dial addresses would * result in a direct connection */ export function findExistingConnection(peerId, connections, dialAddresses) { if (peerId == null || connections == null) { return; } const existingConnection = connections .sort((a, b) => { if (a.direct) { return -1; } if (b.direct) { return 1; } return 0; }) .find(con => con.limits == null); if (existingConnection == null || existingConnection.direct || dialAddresses == null) { return existingConnection; } // we have an indirect, but unlimited connection - test the dial addresses to // see if any of them would result in a direct connection, in which case allow // the attempt to upgrade to a direct connection const wouldUpgradeToDirect = dialAddresses.some(ma => isDirect(ma)); if (wouldUpgradeToDirect) { return; } return existingConnection; } //# sourceMappingURL=utils.js.map