@chainsafe/libp2p-quic
Version:
A QUIC transport for libp2p
106 lines • 3.42 kB
JavaScript
import { raceSignal } from 'race-signal';
import { QuicStream } from './stream.js';
/**
* Each stream muxer factory is only configured for a single connection
*/
export class QuicStreamMuxerFactory {
#connection;
init;
protocol = 'quic';
constructor(init) {
this.#connection = init.connection;
this.init = init;
}
createStreamMuxer(init) {
return new QuicStreamMuxer({
...init,
connection: this.#connection,
logger: this.init.logger
});
}
}
class QuicStreamMuxer {
id;
#connection;
init;
log;
protocol = 'quic';
streams = [];
source = (async function* () { })();
sink = async function* () { };
controller = new AbortController();
constructor(init) {
this.id = init.connection.id();
this.#connection = init.connection;
this.init = init;
this.log = init.logger.forComponent('libp2p:quic:muxer');
void this.awaitInboundStreams();
this.log('new', this.id);
}
async awaitInboundStreams() {
while (true) {
try {
const stream = await raceSignal(this.#connection.inboundStream(), this.controller.signal);
this.onInboundStream(stream);
}
catch (e) {
this.log.error('%s error accepting stream - %e', this.id, e);
if (this.controller.signal.aborted) {
break;
}
}
}
this.log('%s no longer awaiting inbound streams', this.id);
}
onInboundStream = (str) => {
const stream = new QuicStream({
id: str.id(),
stream: str,
direction: 'inbound',
log: this.init.logger.forComponent(`libp2p:quic:stream:${this.#connection.id()}:${str.id()}:inbound`),
onEnd: () => {
const index = this.streams.findIndex(s => s === stream);
if (index !== -1) {
this.streams.splice(index, 1);
}
this.init.onStreamEnd?.(stream);
}
});
this.streams.push(stream);
this.init.onIncomingStream?.(stream);
};
async newStream(name) {
const str = await this.#connection.outboundStream();
this.controller.signal.throwIfAborted();
const stream = new QuicStream({
id: str.id(),
stream: str,
direction: 'outbound',
log: this.init.logger.forComponent(`libp2p:quic:stream:${this.#connection.id()}:${str.id()}:outbound`),
onEnd: () => {
const index = this.streams.findIndex(s => s === stream);
if (index !== -1) {
this.streams.splice(index, 1);
}
this.init.onStreamEnd?.(stream);
}
});
this.streams.push(stream);
return stream;
}
async close(options) {
this.controller.abort();
await Promise.all(this.streams.map(async (stream) => stream.close(options)));
this.streams = [];
this.log('%s closed', this.id);
}
abort(err) {
this.controller.abort();
for (const stream of this.streams) {
stream.abort(err);
}
this.streams = [];
this.log('%s aborted', this.id);
}
}
//# sourceMappingURL=stream-muxer.js.map