UNPKG

the-moby-effect

Version:
61 lines 3.1 kB
import * as Channel from "effect/Channel"; import * as Effect from "effect/Effect"; import * as Either from "effect/Either"; import * as Exit from "effect/Exit"; import * as Function from "effect/Function"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import { demuxMultiplexedToSeparateSinks, isMultiplexedChannel, isMultiplexedSocket } from "./multiplexed.js"; import { makeRawChannel, rawFromStreamWith } from "./raw.js"; /** @internal */ export const fan = /*#__PURE__*/Function.dual(arguments_ => isMultiplexedChannel(arguments_[0]) || isMultiplexedSocket(arguments_[0]), /*#__PURE__*/Effect.fnUntraced(function* (multiplexedInput, options) { const mutex = yield* Effect.makeSemaphore(1); const context = yield* Effect.context(); // Internal buffers const stdoutConsumerQueue = yield* Queue.bounded(options.requestedCapacity); const stderrConsumerQueue = yield* Queue.bounded(options.requestedCapacity); const stdinProducerQueue = yield* Queue.bounded(options.requestedCapacity); // We MUST only touch the underlying once!!! Very important!!! // Demux everything to and fro the correct places. We can touch // this more than once because it is wrapped with a mutex. const motherChannel = demuxMultiplexedToSeparateSinks(multiplexedInput, Function.pipe(Stream.fromQueue(stdinProducerQueue, { shutdown: true }), Stream.map(Either.match({ onRight: Exit.succeed, onLeft: Function.flow(Exit.mapBoth({ onFailure: Option.some, onSuccess: Function.compose(Option.none, Exit.fail) }), Exit.flatten) })), Stream.flattenExitOption, Stream.flattenChunks), Sink.fromQueue(stdoutConsumerQueue, { shutdown: true }), Sink.fromQueue(stderrConsumerQueue, { shutdown: true }), { bufferSize: 32, encoding: options.encoding }).pipe(mutex.withPermitsIfAvailable(1)).pipe(Effect.asVoid).pipe(Channel.fromEffect).pipe(Channel.provideContext(context)); // Any one of these will kick off the mother demux, but only one will const independentStdinChannel = Channel.toQueue(stdinProducerQueue).pipe(Channel.mapInput(Function.constVoid)).pipe(Channel.zipLeft(motherChannel, { concurrent: true })).pipe(makeRawChannel); // Any one of these will kick off the mother demux, but only one will const independentStdoutChannel = Stream.fromQueue(stdoutConsumerQueue).pipe(Stream.encodeText).pipe(rawFromStreamWith()).pipe(({ underlying }) => underlying).pipe(Channel.zipLeft(motherChannel, { concurrent: true })).pipe(makeRawChannel); // Any one of these will kick off the mother demux, but only one will const independentStderrChannel = Stream.fromQueue(stderrConsumerQueue).pipe(Stream.encodeText).pipe(rawFromStreamWith()).pipe(({ underlying }) => underlying).pipe(Channel.zipLeft(motherChannel, { concurrent: true })).pipe(makeRawChannel); return { stdin: independentStdinChannel, stdout: independentStdoutChannel, stderr: independentStderrChannel }; })); //# sourceMappingURL=fan.js.map