@moonwall/cli
Version:
Testing framework for the Moon family of projects
95 lines (92 loc) • 2.7 kB
JavaScript
// src/internal/effect/PortDiscoveryService.ts
import { Effect, Context, Layer, Schedule } from "effect";
import { exec } from "child_process";
import { promisify } from "util";
// src/internal/effect/errors.ts
import { Data } from "effect";
var PortDiscoveryError = class extends Data.TaggedError("PortDiscoveryError") {
};
var NodeLaunchError = class extends Data.TaggedError("NodeLaunchError") {
};
var NodeReadinessError = class extends Data.TaggedError("NodeReadinessError") {
};
var ProcessError = class extends Data.TaggedError("ProcessError") {
};
var StartupCacheError = class extends Data.TaggedError("StartupCacheError") {
};
var FileLockError = class extends Data.TaggedError("FileLockError") {
};
// src/internal/effect/PortDiscoveryService.ts
var execAsync = promisify(exec);
var PortDiscoveryService = class extends Context.Tag("PortDiscoveryService")() {
};
var parsePortsFromLsof = (stdout) => {
const ports = [];
const lines = stdout.split("\n");
for (const line of lines) {
const regex = /(?:.+):(\d+)/;
const match = line.match(regex);
if (match) {
ports.push(Number.parseInt(match[1], 10));
}
}
return ports;
};
var attemptPortDiscovery = (pid) => Effect.tryPromise({
try: () => execAsync(`lsof -p ${pid} -n -P | grep LISTEN`),
catch: (cause) => new PortDiscoveryError({
cause,
pid,
attempts: 1
})
}).pipe(
Effect.flatMap(({ stdout }) => {
const ports = parsePortsFromLsof(stdout);
if (ports.length === 0) {
return Effect.fail(
new PortDiscoveryError({
cause: new Error("No ports found in lsof output"),
pid,
attempts: 1
})
);
}
const rpcPort = ports.find((p) => p !== 30333 && p !== 9615);
if (!rpcPort) {
if (ports.length === 1) {
return Effect.succeed(ports[0]);
}
return Effect.fail(
new PortDiscoveryError({
cause: new Error(
`No RPC port found in range 9000-20000 and multiple ports detected (found ports: ${ports.join(", ")})`
),
pid,
attempts: 1
})
);
}
return Effect.succeed(rpcPort);
})
);
var discoverPortWithRetry = (pid, maxAttempts = 1200) => attemptPortDiscovery(pid).pipe(
Effect.retry(
Schedule.fixed("50 millis").pipe(Schedule.compose(Schedule.recurs(maxAttempts - 1)))
),
Effect.catchAll(
(error) => Effect.fail(
new PortDiscoveryError({
cause: error,
pid,
attempts: maxAttempts
})
)
)
);
var PortDiscoveryServiceLive = Layer.succeed(PortDiscoveryService, {
discoverPort: discoverPortWithRetry
});
export {
PortDiscoveryService,
PortDiscoveryServiceLive
};