libp2p
Version:
JavaScript implementation of libp2p, a modular peer to peer network stack
144 lines • 4.47 kB
JavaScript
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