the-moby-effect
Version:
Moby/Docker API client built using effect-ts
61 lines • 3.1 kB
JavaScript
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