UNPKG

the-moby-effect

Version:
115 lines 4.84 kB
import * as Effect from "effect/Effect"; import * as Function from "effect/Function"; import * as Layer from "effect/Layer"; import * as Socket from "effect/unstable/socket/Socket"; import * as internalAgnostic from "./agnostic.js"; import * as internalConnection from "./connection.js"; /** @internal */ export const makeDispatcher = /*#__PURE__*/Effect.fnUntraced(function* (agentOptions) { const undiciLazy = yield* Effect.promise(() => import("undici")); const acquire = Effect.sync(() => new undiciLazy.Agent(agentOptions)); const release = agent => Effect.promise(() => agent.destroy()); const resource = Effect.acquireRelease(acquire, release); return yield* resource; }); /** @internal */ export const makeSshDispatcher = /*#__PURE__*/Effect.fnUntraced(function* (connectionOptions) { const ssh2Lazy = yield* Effect.promise(() => import("ssh2")); const undiciLazy = yield* Effect.promise(() => import("undici")); const sshClient = new ssh2Lazy.Client(); let sshConnection = "unopened"; let openFailedError = null; const connector = ( // oxlint-disable-next-line only-used-in-recursion _options, callback) => { const onError = error => callback(error, null); // No connection yet, start connecting if (sshConnection === "unopened") { sshConnection = "connecting"; const unableToOpen = error => { sshConnection = "open-failed"; openFailedError = error; onError(error); }; sshClient.once("ready", () => { sshConnection = "ready"; sshClient.off("error", unableToOpen); connector(_options, callback); }).once("error", unableToOpen).connect(connectionOptions); } // Already tried to connect but failed else if (sshConnection === "open-failed") { callback(openFailedError, null); } // Another connection attempt is already in progress, wait for it else if (sshConnection === "connecting") { sshClient.once("ready", () => { sshClient.off("error", onError); connector(_options, callback); }).once("error", onError); } // We are connected to the ssh server, now forward our stream local else if (sshConnection === "ready") { sshClient.openssh_forwardOutStreamLocal(connectionOptions.remoteSocketPath, (error, stream) => { sshClient.off("error", onError); if (error) return callback(error, null);else return callback(null, stream); }).once("error", onError); } // Should never happen else { return Function.absurd(sshConnection); } }; const acquire = Effect.sync(() => new undiciLazy.Agent({ connect: connector })); const release = _agent => Effect.promise(async () => { sshClient.end(); sshClient.destroy(); // await agent.close(); // await agent.destroy(); }); const resource = Effect.acquireRelease(acquire, release); return yield* resource; }); /** @internal */ export const getUndiciDispatcher = /*#__PURE__*/internalConnection.MobyConnectionOptions.$match({ ssh: options => makeSshDispatcher(options), socket: options => makeDispatcher({ connect: { socketPath: options.socketPath } }), http: options => makeDispatcher({ connect: { host: options.host, port: options.port, path: options.path } }), https: options => makeDispatcher({ connect: { ca: options.ca, key: options.key, cert: options.cert, passphrase: options.passphrase, host: options.host, port: options.port, path: options.path } }) }); /** @internal */ export const getUndiciWebsocketConstructor = connectionOptions => Function.pipe(Effect.promise(() => import("ws")), Effect.map(ws => { const prependedUrl = internalAgnostic.makeWebsocketRequestUrl(connectionOptions); return (url, protocols) => new ws.WebSocket(`${prependedUrl}${url}`, protocols); })); /** @internal */ export const makeUndiciHttpClientLayer = connectionOptions => { const dispatcherLive = Function.pipe(Effect.promise(() => import("@effect/platform-node/NodeHttpClient")), Effect.map(nodeHttpClientLazy => Layer.effect(nodeHttpClientLazy.Dispatcher, getUndiciDispatcher(connectionOptions))), Layer.unwrap); const websocketConstructorLive = Layer.effect(Socket.WebSocketConstructor, getUndiciWebsocketConstructor(connectionOptions)); const undiciHttpClientLive = Function.pipe(Effect.promise(() => import("@effect/platform-node/NodeHttpClient")), Effect.map(nodeHttpClientLazy => nodeHttpClientLazy.layerUndiciNoDispatcher), Layer.unwrap); const agnosticHttpClientLayer = internalAgnostic.makeAgnosticHttpClientLayer(connectionOptions); return agnosticHttpClientLayer.pipe(Layer.merge(websocketConstructorLive), Layer.provide(undiciHttpClientLive), Layer.provide(dispatcherLive)); }; //# sourceMappingURL=undici.js.map