122 lines · 5.2 KB · TypeScript
RawDownload
import { DesktopWslStateSchema, type DesktopWslState } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as Option from "effect/Option";import * as Schema from "effect/Schema"; import * as DesktopLifecycle from "../../app/DesktopLifecycle.ts";import * as DesktopAppSettings from "../../settings/DesktopAppSettings.ts";import * as DesktopWslBackend from "../../wsl/DesktopWslBackend.ts";import * as DesktopWslEnvironment from "../../wsl/DesktopWslEnvironment.ts";import * as IpcChannels from "../channels.ts";import { makeIpcMethod } from "../DesktopIpc.ts"; const readWslState: Effect.Effect<  DesktopWslState,  never,  | DesktopAppSettings.DesktopAppSettings  | DesktopWslEnvironment.DesktopWslEnvironment  | DesktopWslBackend.DesktopWslBackend> = Effect.gen(function* () {  const appSettings = yield* DesktopAppSettings.DesktopAppSettings;  const wslEnvironment = yield* DesktopWslEnvironment.DesktopWslEnvironment;  const wslBackend = yield* DesktopWslBackend.DesktopWslBackend;  const settings = yield* appSettings.get;  const available = yield* wslEnvironment.isAvailable;  // Only enumerate distros when WSL is actually available — listDistros on a  // non-WSL host would spawn wsl.exe and hit the timeout for nothing.  const distros = available ? yield* wslEnvironment.listDistros : [];  const preflightError = yield* wslBackend.lastPreflightError;  return {    enabled: settings.wslBackendEnabled,    distro: settings.wslDistro,    available,    wslOnly: settings.wslOnly,    distros,    // Only the dual-mode secondary records this; a wsl-only failure surfaces via    // a dialog + Windows fallback, so it stays null there.    preflightError: settings.wslOnly ? null : Option.getOrNull(preflightError),  };}); export const getWslState = makeIpcMethod({  channel: IpcChannels.GET_WSL_STATE_CHANNEL,  payload: Schema.Void,  result: DesktopWslStateSchema,  handler: Effect.fn("desktop.ipc.wsl.getState")(function* () {    return yield* readWslState;  }),}); export const setWslBackendEnabled = makeIpcMethod({  channel: IpcChannels.SET_WSL_BACKEND_ENABLED_CHANNEL,  payload: Schema.Boolean,  result: DesktopWslStateSchema,  handler: Effect.fn("desktop.ipc.wsl.setEnabled")(function* (enabled) {    const appSettings = yield* DesktopAppSettings.DesktopAppSettings;    const wslBackend = yield* DesktopWslBackend.DesktopWslBackend;    const lifecycle = yield* DesktopLifecycle.DesktopLifecycle;    const previousSettings = yield* appSettings.get;    const updateSettings = enabled      ? appSettings.setWslBackendEnabled(true)      : appSettings.applyWslWindowsFallback;    const change = yield* updateSettings;    const settings = yield* appSettings.get;    const changedWslOnlyPrimary = enabled      ? settings.wslOnly      : previousSettings.wslBackendEnabled && previousSettings.wslOnly;    if (changedWslOnlyPrimary && change.changed) {      const state = yield* readWslState;      yield* lifecycle.relaunch(`wslBackendEnabled=${enabled}`);      return state;    }    // Reconcile is idempotent and never fails; no need for a swap-style    // rollback when the WSL side has trouble coming up. With both    // backends running side by side, "WSL didn't start" is a transient    // state on one instance — the primary stays up either way.    yield* wslBackend.reconcile;    return yield* readWslState;  }),}); export const setWslDistro = makeIpcMethod({  channel: IpcChannels.SET_WSL_DISTRO_CHANNEL,  payload: Schema.NullOr(Schema.String),  result: DesktopWslStateSchema,  handler: Effect.fn("desktop.ipc.wsl.setDistro")(function* (distro) {    const appSettings = yield* DesktopAppSettings.DesktopAppSettings;    const wslBackend = yield* DesktopWslBackend.DesktopWslBackend;    const lifecycle = yield* DesktopLifecycle.DesktopLifecycle;    const change = yield* appSettings.setWslDistro(distro);    const settings = yield* appSettings.get;    // In active wsl-only mode the pool's primary IS the WSL backend, and its    // distro is captured when that backend starts, so relaunch to replace it.    // When WSL is disabled, this only stages a preference for the next enable.    if (settings.wslBackendEnabled && settings.wslOnly && change.changed) {      const state = yield* readWslState;      yield* lifecycle.relaunch(`wslDistro=${distro ?? "default"}`);      return state;    }    yield* wslBackend.reconcile;    return yield* readWslState;  }),}); export const setWslOnly = makeIpcMethod({  channel: IpcChannels.SET_WSL_ONLY_CHANNEL,  payload: Schema.Boolean,  result: DesktopWslStateSchema,  handler: Effect.fn("desktop.ipc.wsl.setOnly")(function* (enabled) {    // wsl-only decides which backend the pool spins up as "primary", and that    // decision is captured once at layer init. A disabled WSL backend always    // leaves Windows primary active, so mode changes can be staged without a    // relaunch and applied by the subsequent enable call.    const appSettings = yield* DesktopAppSettings.DesktopAppSettings;    const lifecycle = yield* DesktopLifecycle.DesktopLifecycle;    const change = yield* appSettings.setWslOnly(enabled);    const state = yield* readWslState;    if (state.enabled && change.changed) {      yield* lifecycle.relaunch(`wslOnly=${enabled}`);    }    return state;  }),});