Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -960,8 +960,12 @@ describe("DesktopBackendConfiguration", () => {
DesktopBackendConfiguration.DesktopBackendConfiguration,
);
// oxlint-disable-next-line t3code/no-manual-effect-runtime-in-tests -- Same reason: this is the synchronous resolution the IPC handler performs.
const label = Effect.runSync(configuration.resolvePrimaryLabel);
assert.equal(typeof label, "string");
const label = Effect.runSync(
configuration.resolvePrimaryLabel.pipe(
Effect.provideService(HostProcess.Hostname, "DESKTOP-PC"),
),
);
assert.equal(label, "DESKTOP-PC");
} finally {
await runtime.dispose();
}
Expand Down
6 changes: 4 additions & 2 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as NodeOS from "node:os";

import { parsePersistedServerObservabilitySettings } from "@t3tools/shared/serverSettings";
import { currentDesktopBootstrapToken } from "@t3tools/shared/desktopBootstrapToken";
import { wslEnvironmentLabel } from "@t3tools/shared/environmentLabel";
import * as HostProcess from "@t3tools/shared/HostProcess";
import * as Clock from "effect/Clock";
import * as Context from "effect/Context";
Expand Down Expand Up @@ -831,10 +832,11 @@ export const make = Effect.gen(function* () {
}).pipe(Effect.withSpan("desktop.backendConfiguration.resolvePrimary")),
resolvePrimaryLabel: Effect.gen(function* () {
const { useWsl, distro } = yield* describePrimary;
const hostname = yield* HostProcess.Hostname;
if (!useWsl) {
return environment.platform === "win32" ? "Windows" : "Local environment";
return environment.platform === "win32" ? hostname : "Local environment";
}
return distro ? `WSL (${distro})` : "WSL";
return wslEnvironmentLabel(hostname, distro);
}).pipe(Effect.withSpan("desktop.backendConfiguration.resolvePrimaryLabel")),
// The span options depend on each request's port and distro.
resolveWsl: Effect.fnUntraced(
Expand Down
12 changes: 8 additions & 4 deletions apps/desktop/src/ipc/methods/window.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const readyWslConfig: DesktopBackendManager.DesktopBackendStartConfig = {

const defaultWslInstance: DesktopBackendManager.DesktopBackendInstance = {
id: DesktopBackendManager.BackendInstanceId("wsl:default"),
label: Effect.succeed("WSL (default distro)"),
label: Effect.succeed("DESKTOP-PC WSL"),
start: Effect.void,
stop: () => Effect.void,
currentConfig: Effect.succeedSome(readyWslConfig),
Expand All @@ -87,7 +87,11 @@ const backendConfigurationLayer = Layer.succeed(
);

const bootstrapsLayer = (instances: ReadonlyArray<DesktopBackendManager.DesktopBackendInstance>) =>
Layer.merge(DesktopBackendPool.layerTest([...instances]), backendConfigurationLayer);
Layer.mergeAll(
DesktopBackendPool.layerTest([...instances]),
backendConfigurationLayer,
Layer.succeed(HostProcess.Hostname, "DESKTOP-PC"),
);

describe("getLocalEnvironmentBootstraps", () => {
it.effect("hands out the current window's token to a backend launched with the secret", () =>
Expand All @@ -97,7 +101,7 @@ describe("getLocalEnvironmentBootstraps", () => {
assert.deepEqual(result, [
{
id: "wsl:default",
label: "WSL (Ubuntu)",
label: "DESKTOP-PC WSL (Ubuntu)",
runningDistro: "Ubuntu",
httpBaseUrl: "http://127.0.0.1:3774/",
wsBaseUrl: "ws://127.0.0.1:3774/",
Expand Down Expand Up @@ -148,7 +152,7 @@ describe("getLocalEnvironmentBootstraps", () => {
assert.deepEqual(result, [
{
id: "wsl:default",
label: "WSL (default distro)",
label: "DESKTOP-PC WSL",
runningDistro: null,
httpBaseUrl: null,
wsBaseUrl: null,
Expand Down
6 changes: 5 additions & 1 deletion apps/desktop/src/ipc/methods/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from "@t3tools/contracts";
import { PROJECT_FAVICON_EXTENSIONS } from "@t3tools/shared/projectFavicon";
import { resolveEditorCommand } from "@t3tools/shared/editor";
import { wslEnvironmentLabel } from "@t3tools/shared/environmentLabel";
import * as HostProcess from "@t3tools/shared/HostProcess";
import { isRelayTracingEnabled } from "@t3tools/shared/otelEnvironment";
import * as FileSystem from "effect/FileSystem";
Expand Down Expand Up @@ -151,7 +152,10 @@ export const getLocalEnvironmentBootstraps = DesktopIpc.makeSyncIpcMethod({
const runningDistro = config.value.runningDistro ?? null;
bootstraps.push({
id: instance.id,
label: runningDistro === null ? yield* instance.label : `WSL (${runningDistro})`,
label:
runningDistro === null
? yield* instance.label
: wslEnvironmentLabel(yield* HostProcess.Hostname, runningDistro),
runningDistro,
httpBaseUrl: httpBaseUrl.href,
wsBaseUrl: toWebSocketBaseUrl(httpBaseUrl),
Expand Down
8 changes: 4 additions & 4 deletions apps/desktop/src/wsl/DesktopWslBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as Option from "effect/Option";
import * as Ref from "effect/Ref";
import * as Semaphore from "effect/Semaphore";

import { wslEnvironmentLabel } from "@t3tools/shared/environmentLabel";
import * as HostProcess from "@t3tools/shared/HostProcess";
import * as NetService from "@t3tools/shared/Net";

import * as DesktopObservability from "../app/DesktopObservability.ts";
Expand Down Expand Up @@ -38,9 +40,6 @@ const resolveTargetInstanceId = (distro: string | null): DesktopBackendPool.Back
const isWslInstanceId = (id: DesktopBackendPool.BackendInstanceId): boolean =>
id.startsWith(WSL_INSTANCE_ID_PREFIX);

const buildLabel = (distro: string | null): string =>
distro === null ? "WSL (default distro)" : `WSL (${distro})`;

// WSL auto-forwards loopback ports, so only IPv4 loopback availability matters.
const scanForWslPort = Effect.fn("desktop.wslBackend.scanForWslPort")(function* (
startPort: number,
Expand All @@ -65,6 +64,7 @@ export const layer = Layer.effect(
const wslEnvironment = yield* DesktopWslEnvironment.DesktopWslEnvironment;
const appSettings = yield* DesktopAppSettings.DesktopAppSettings;
const net = yield* NetService.NetService;
const hostname = yield* HostProcess.Hostname;
// Serialize bootstrap and IPC reconciles so concurrent reads cannot register competing WSL instances.
const reconcileMutex = yield* Semaphore.make(1);

Expand Down Expand Up @@ -118,7 +118,7 @@ export const layer = Layer.effect(
const instance = yield* pool
.register({
id: targetId,
label: Effect.succeed(buildLabel(input.distro)),
label: Effect.succeed(wslEnvironmentLabel(hostname, input.distro)),
configResolve: configuration.resolveWsl({ port: allocatedPort, distro: input.distro }),
onPreflightFailed: (failure) =>
Ref.set(preflightErrorRef, Option.some(failure.reason)).pipe(Effect.as(false)),
Expand Down
76 changes: 76 additions & 0 deletions apps/server/src/environment/ServerEnvironmentLabel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { expect, it } from "@effect/vitest";
import * as HostProcess from "@t3tools/shared/HostProcess";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";

import * as ProcessRunner from "../processRunner.ts";
import { resolveServerEnvironmentLabel } from "./ServerEnvironmentLabel.ts";

const resolveLinuxLabel = (input: {
readonly kernelRelease: string;
readonly env: NodeJS.ProcessEnv;
}) =>
resolveServerEnvironmentLabel({ cwdBaseName: "project" }).pipe(
Effect.provideService(
ProcessRunner.ProcessRunner,
ProcessRunner.ProcessRunner.of({
run: () =>
Effect.succeed({
stdout: "",
stderr: "",
code: ChildProcessSpawner.ExitCode(1),
timedOut: false,
stdoutTruncated: false,
stderrTruncated: false,
stdoutInvalidUtf8: false,
stderrInvalidUtf8: false,
}),
}),
),
Effect.provide(
Layer.mergeAll(
FileSystem.layerNoop({
exists: () => Effect.succeed(false),
readFileString: (path) =>
path === "/proc/sys/kernel/osrelease"
? Effect.succeed(input.kernelRelease)
: Effect.die(`unexpected read: ${path}`),
}),
Layer.succeed(HostProcess.Platform, "linux"),
Layer.succeed(HostProcess.Hostname, "DESKTOP-PC"),
Layer.succeed(HostProcess.Environment, input.env),
),
),
);

it.effect("labels a WSL server with its host and distro", () =>
Effect.gen(function* () {
const label = yield* resolveLinuxLabel({
kernelRelease: "6.6.87.2-microsoft-standard-WSL2\n",
env: { WSL_DISTRO_NAME: "Ubuntu" },
});
expect(label).toBe("DESKTOP-PC WSL (Ubuntu)");
}),
);

it.effect("labels a WSL server without a distro name by its host", () =>
Effect.gen(function* () {
const label = yield* resolveLinuxLabel({
kernelRelease: "6.6.87.2-microsoft-standard-WSL2\n",
env: {},
});
expect(label).toBe("DESKTOP-PC WSL");
}),
);

it.effect("keeps the hostname for non-WSL Linux", () =>
Effect.gen(function* () {
const label = yield* resolveLinuxLabel({
kernelRelease: "6.8.0-45-generic\n",
env: { WSL_DISTRO_NAME: "Ubuntu" },
});
expect(label).toBe("DESKTOP-PC");
}),
);
19 changes: 18 additions & 1 deletion apps/server/src/environment/ServerEnvironmentLabel.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { wslEnvironmentLabel } from "@t3tools/shared/environmentLabel";
import * as HostProcess from "@t3tools/shared/HostProcess";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
Expand Down Expand Up @@ -179,15 +180,31 @@ const resolveFriendlyHostLabel = Effect.fn("resolveFriendlyHostLabel")(function*
return null;
});

const isWsl = Effect.fn("isWsl")(function* () {
if ((yield* HostProcess.Platform) !== "linux") {
return false;
}
const fileSystem = yield* FileSystem.FileSystem;
const kernelRelease = yield* fileSystem
.readFileString("/proc/sys/kernel/osrelease")
.pipe(Effect.orElseSucceed(() => ""));
return kernelRelease.toLowerCase().includes("microsoft");
});

export const resolveServerEnvironmentLabel = Effect.fn("resolveServerEnvironmentLabel")(function* (
input: ResolveServerEnvironmentLabelInput,
) {
const hostname = normalizeLabel(yield* HostProcess.Hostname);
if (hostname && (yield* isWsl())) {
const distro = normalizeLabel((yield* HostProcess.Environment).WSL_DISTRO_NAME);
return wslEnvironmentLabel(hostname, distro);
}

const friendlyHostLabel = yield* resolveFriendlyHostLabel();
if (friendlyHostLabel) {
return friendlyHostLabel;
}

const hostname = normalizeLabel(yield* HostProcess.Hostname);
if (hostname) {
return hostname;
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/connection/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ const loadSecondaryConnectionRegistration = Effect.fn(
}).pipe(Effect.mapError(mapRemoteEnvironmentError));
// Desktop operations need the pool backend id to reach the owning instance; RPC uses the environment id.
const connectionId = desktopLocalConnectionId(entry.id);
const label = entry.label || descriptor.label;
const label = descriptor.label || entry.label;
return {
registration: new BearerConnectionRegistration({
target: new BearerConnectionTarget({
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@
"types": "./src/observability.ts",
"import": "./src/observability.ts"
},
"./environmentLabel": {
"types": "./src/environmentLabel.ts",
"import": "./src/environmentLabel.ts"
},
"./otelEnvironment": {
"types": "./src/otelEnvironment.ts",
"import": "./src/otelEnvironment.ts"
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/environmentLabel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// WSL inherits the Windows hostname; distinguish the environments on every client.
export function wslEnvironmentLabel(hostname: string, distro: string | null): string {
return distro ? `${hostname} WSL (${distro})` : `${hostname} WSL`;
}
Loading