UNPKG

libp2p

Version:

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

144 lines 4.47 kB
import { connectionSymbol, LimitedConnectionError, ConnectionClosedError, ConnectionClosingError } from '@libp2p/interface'; import { setMaxListeners } from 'main-event'; const CLOSE_TIMEOUT = 500; /** * An implementation of the js-libp2p connection. * Any libp2p transport should use an upgrader to return this connection. */ export class ConnectionImpl { /** * Connection identifier. */ id; /** * Observed multiaddr of the remote peer */ remoteAddr; /** * Remote peer id */ remotePeer; direction; timeline; multiplexer; encryption; status; limits; log; /** * User provided tags * */ tags; /** * Reference to the new stream function of the multiplexer */ _newStream; /** * Reference to the close function of the raw connection */ _close; _abort; /** * Reference to the getStreams function of the muxer */ _getStreams; /** * An implementation of the js-libp2p connection. * Any libp2p transport should use an upgrader to return this connection. */ constructor(init) { const { remoteAddr, remotePeer, newStream, close, abort, getStreams } = init; this.id = `${(parseInt(String(Math.random() * 1e9))).toString(36)}${Date.now()}`; this.remoteAddr = remoteAddr; this.remotePeer = remotePeer; this.direction = init.direction; this.status = 'open'; this.timeline = init.timeline; this.multiplexer = init.multiplexer; this.encryption = init.encryption; this.limits = init.limits; this.log = init.logger.forComponent(`libp2p:connection:${this.direction}:${this.id}`); if (this.remoteAddr.getPeerId() == null) { this.remoteAddr = this.remoteAddr.encapsulate(`/p2p/${this.remotePeer}`); } this._newStream = newStream; this._close = close; this._abort = abort; this._getStreams = getStreams; this.tags = []; } [Symbol.toStringTag] = 'Connection'; [connectionSymbol] = true; /** * Get all the streams of the muxer */ get streams() { return this._getStreams(); } /** * Create a new stream from this connection */ async newStream(protocols, options) { if (this.status === 'closing') { throw new ConnectionClosingError('the connection is being closed'); } if (this.status === 'closed') { throw new ConnectionClosedError('the connection is closed'); } if (!Array.isArray(protocols)) { protocols = [protocols]; } if (this.limits != null && options?.runOnLimitedConnection !== true) { throw new LimitedConnectionError('Cannot open protocol stream on limited connection'); } const stream = await this._newStream(protocols, options); stream.direction = 'outbound'; return stream; } /** * Close the connection */ async close(options = {}) { if (this.status === 'closed' || this.status === 'closing') { return; } this.log('closing connection to %a', this.remoteAddr); this.status = 'closing'; if (options.signal == null) { const signal = AbortSignal.timeout(CLOSE_TIMEOUT); setMaxListeners(Infinity, signal); options = { ...options, signal }; } try { this.log.trace('closing underlying transport'); // close raw connection await this._close(options); this.log.trace('updating timeline with close time'); this.status = 'closed'; this.timeline.close = Date.now(); } catch (err) { this.log.error('error encountered during graceful close of connection to %a', this.remoteAddr, err); this.abort(err); } } abort(err) { if (this.status === 'closed') { return; } this.log.error('aborting connection to %a due to error', this.remoteAddr, err); this.status = 'closing'; // Abort raw connection this._abort(err); this.status = 'closed'; this.timeline.close = Date.now(); } } export function createConnection(init) { return new ConnectionImpl(init); } //# sourceMappingURL=index.js.map