libp2p-pubsub
Version:
112 lines • 3.72 kB
JavaScript
import debug from 'debug';
import { EventEmitter } from 'events';
import lp from 'it-length-prefixed';
import pushable from 'it-pushable';
import { pipe } from 'it-pipe';
import { source as abortable } from 'abortable-iterator';
import AbortController from 'abort-controller';
const log = Object.assign(debug('libp2p-pubsub:peer-streams'), {
error: debug('libp2p-pubsub:peer-streams:err')
});
/**
* Thin wrapper around a peer's inbound / outbound pubsub streams
*/
export class PeerStreams extends EventEmitter {
constructor(opts) {
super();
this.id = opts.id;
this.protocol = opts.protocol;
this._inboundAbortController = new AbortController();
}
/**
* Do we have a connection to read from?
*
* @type {boolean}
*/
get isReadable() {
return Boolean(this.inboundStream);
}
/**
* Do we have a connection to write on?
*
* @type {boolean}
*/
get isWritable() {
return Boolean(this.outboundStream);
}
/**
* Send a message to this peer.
* Throws if there is no `stream` to write to available.
*/
write(data) {
if (this.outboundStream == null) {
const id = this.id.toString();
throw new Error('No writable connection to ' + id);
}
this.outboundStream.push(data);
}
/**
* Attach a raw inbound stream and setup a read stream
*/
attachInboundStream(stream) {
// Create and attach a new inbound stream
// The inbound stream is:
// - abortable, set to only return on abort, rather than throw
// - transformed with length-prefix transform
this._rawInboundStream = stream;
this.inboundStream = abortable(pipe(this._rawInboundStream, lp.decode()), this._inboundAbortController.signal, { returnOnAbort: true });
this.emit('stream:inbound');
return this.inboundStream;
}
/**
* Attach a raw outbound stream and setup a write stream
*/
async attachOutboundStream(stream) {
// If an outbound stream already exists, gently close it
const _prevStream = this.outboundStream;
if (this.outboundStream != null) {
// End the stream without emitting a close event
await this.outboundStream.end();
}
this._rawOutboundStream = stream;
this.outboundStream = pushable({
onEnd: (shouldEmit) => {
// close writable side of the stream
if ((this._rawOutboundStream?.reset) != null) {
this._rawOutboundStream.reset();
}
this._rawOutboundStream = undefined;
this.outboundStream = undefined;
if (shouldEmit != null) {
this.emit('close');
}
}
});
pipe(this.outboundStream, lp.encode(), this._rawOutboundStream).catch((err) => {
log.error(err);
});
// Only emit if the connection is new
if (_prevStream == null) {
this.emit('stream:outbound');
}
}
/**
* Closes the open connection to peer
*/
close() {
// End the outbound stream
if (this.outboundStream != null) {
this.outboundStream.end();
}
// End the inbound stream
if (this.inboundStream != null) {
this._inboundAbortController.abort();
}
this._rawOutboundStream = undefined;
this.outboundStream = undefined;
this._rawInboundStream = undefined;
this.inboundStream = undefined;
this.emit('close');
}
}
//# sourceMappingURL=peer-streams.js.map