| ... | ... | @@ -1,18 +1,7 @@ |
| 1 | 1 | import net from "node:net"; |
| 2 | 2 | import os from "node:os"; |
| 3 | 3 | |
| 4 | | import { |
| 5 | | ServiceMap, |
| 6 | | Data, |
| 7 | | Effect, |
| 8 | | Layer, |
| 9 | | Option, |
| 10 | | Config, |
| 11 | | Path, |
| 12 | | Schema, |
| 13 | | FileSystem, |
| 14 | | PlatformError, |
| 15 | | } from "effect"; |
| 4 | import { ServiceMap, Data, Effect, Layer, Option, Config, Path, Schema, FileSystem } from "effect"; |
| 16 | 5 | import { Command, Flag } from "effect/unstable/cli"; |
| 17 | 6 | |
| 18 | 7 | import { fixPath } from "./fixPath"; |
| ... | ... | @@ -37,7 +26,7 @@ export interface CliConfigShape { |
| 37 | 26 | readonly cwd: string; |
| 38 | 27 | readonly fixPath: Effect.Effect<unknown, never>; |
| 39 | 28 | readonly findAvailablePort: (preferred: number) => Effect.Effect<number, StartupError>; |
| 40 | | readonly resolveStaticDir: () => Effect.Effect<string | undefined, PlatformError.PlatformError>; |
| 29 | readonly resolveStaticDir: () => Effect.Effect<string | undefined>; |
| 41 | 30 | } |
| 42 | 31 | |
| 43 | 32 | export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()( |
| ... | ... | @@ -87,11 +76,11 @@ const resolveStateDir = Effect.fn(function* (raw: string | undefined) { |
| 87 | 76 | return resolve(yield* expandHomePath(raw.trim())); |
| 88 | 77 | }); |
| 89 | 78 | |
| 90 | | async function findAvailablePort(preferred: number): Promise<number> { |
| 91 | | return new Promise((resolve, reject) => { |
| 79 | const findAvailablePort = (preferred: number) => |
| 80 | Effect.callback<number, StartupError>((resume) => { |
| 92 | 81 | const server = net.createServer(); |
| 93 | 82 | server.listen(preferred, () => { |
| 94 | | server.close(() => resolve(preferred)); |
| 83 | server.close(() => resume(Effect.succeed(preferred))); |
| 95 | 84 | }); |
| 96 | 85 | server.on("error", () => { |
| 97 | 86 | const fallback = net.createServer(); |
| ... | ... | @@ -99,14 +88,20 @@ async function findAvailablePort(preferred: number): Promise<number> { |
| 99 | 88 | const addr = fallback.address(); |
| 100 | 89 | const port = typeof addr === "object" && addr !== null ? addr.port : 0; |
| 101 | 90 | fallback.close(() => { |
| 102 | | if (port > 0) resolve(port); |
| 103 | | else reject(new Error("Could not find an available port.")); |
| 91 | resume( |
| 92 | port > 0 |
| 93 | ? Effect.succeed(port) |
| 94 | : Effect.fail(new StartupError({ message: "Could not find an available port." })), |
| 95 | ); |
| 104 | 96 | }); |
| 105 | 97 | }); |
| 106 | | fallback.on("error", reject); |
| 98 | fallback.on("error", (cause) => { |
| 99 | resume( |
| 100 | Effect.fail(new StartupError({ message: "Failed to find an available port", cause })), |
| 101 | ); |
| 102 | }); |
| 107 | 103 | }); |
| 108 | 104 | }); |
| 109 | | } |
| 110 | 105 | |
| 111 | 106 | const resolveStaticDir = Effect.fn(function* () { |
| 112 | 107 | const { join, resolve } = yield* Path.Path; |
| ... | ... | @@ -249,12 +244,7 @@ export const CliConfigLive = Layer.effect( |
| 249 | 244 | return { |
| 250 | 245 | cwd: process.cwd(), |
| 251 | 246 | fixPath: Effect.sync(fixPath), |
| 252 | | findAvailablePort: (preferred) => |
| 253 | | Effect.tryPromise({ |
| 254 | | try: () => findAvailablePort(preferred), |
| 255 | | catch: (cause) => |
| 256 | | new StartupError({ message: "Failed to discover an available port", cause }), |
| 257 | | }), |
| 247 | findAvailablePort, |
| 258 | 248 | resolveStaticDir: () => |
| 259 | 249 | resolveStaticDir().pipe( |
| 260 | 250 | Effect.provideService(FileSystem.FileSystem, fileSystem), |