174 lines · 6.2 KB · TypeScript
RawDownload
import type { EnvironmentMachineKind } from "@t3tools/contracts";import { HostProcessPlatform } from "@t3tools/shared/hostProcess";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem"; import * as ProcessRunner from "../processRunner.ts"; /** * Best-effort hardware detection for the environment icon. Every probe is * allowed to fail: a null result means "no signal", and the client draws a * generic server until the user picks something in Settings → Connections. */ const DMI_ROOT = "/sys/class/dmi/id";const KERNEL_RELEASE_PATH = "/proc/sys/kernel/osrelease"; // SMBIOS 3.x System Enclosure types (table 17). Codes that describe a shape// rather than a machine (docking stations, blades enclosures, IoT gateways)// fall through to null on purpose.const DMI_CHASSIS_KINDS: Readonly<Record<string, EnvironmentMachineKind>> = {  "3": "desktop", // Desktop  "4": "desktop", // Low Profile Desktop  "5": "desktop", // Pizza Box  "6": "desktop", // Mini Tower  "7": "desktop", // Tower  "8": "laptop", // Portable  "9": "laptop", // Laptop  "10": "laptop", // Notebook  "13": "desktop", // All in One  "14": "laptop", // Sub Notebook  "15": "desktop", // Space-saving  "16": "desktop", // Lunch Box  "17": "server", // Main Server Chassis  "18": "server", // Expansion Chassis  "19": "server", // SubChassis  "20": "server", // Bus Expansion Chassis  "21": "server", // Peripheral Chassis  "22": "server", // RAID Chassis  "23": "server", // Rack Mount Chassis  "24": "server", // Sealed-case PC  "28": "server", // Blade  "31": "laptop", // Convertible  "32": "laptop", // Detachable  "35": "desktop", // Mini PC}; // Hypervisors and cloud providers write themselves into the DMI vendor or// product strings; any hit means the box is a VM, and a VM reads as "cloud"// regardless of the chassis type the hypervisor fakes. Hyper-V is matched on// its "Virtual Machine" product, not the "Microsoft Corporation" vendor that// physical Surface devices share.const VIRTUALIZATION_MARKERS = [  "qemu",  "kvm",  "bochs",  "vmware",  "virtualbox",  "innotek",  "xen",  "parallels",  "amazon ec2",  "google compute engine",  "digitalocean",  "hetzner",  "linode",  "vultr",  "scaleway",  "openstack",  "cloud",  "virtual machine",]; function normalize(value: string | null | undefined): string | null {  const trimmed = value?.trim();  return trimmed && trimmed.length > 0 ? trimmed : null;} /** Marketing names and Intel-era model identifiers share these prefixes. */export function machineKindFromAppleProductName(name: string): EnvironmentMachineKind | null {  const normalized = name.trim().toLowerCase().replaceAll(/\s+/g, "");  if (normalized.startsWith("macmini")) return "mac-mini";  if (normalized.startsWith("macstudio")) return "mac-studio";  if (normalized.startsWith("macbook")) return "laptop";  if (normalized.startsWith("imac") || normalized.startsWith("macpro")) return "desktop";  return null;} export function machineKindFromDmi(input: {  readonly chassisType: string | null;  readonly sysVendor: string | null;  readonly productName: string | null;}): EnvironmentMachineKind | null {  const productName = input.productName ?? "";  const vendorAndProduct = `${input.sysVendor ?? ""} ${productName}`.toLowerCase();  if (VIRTUALIZATION_MARKERS.some((marker) => vendorAndProduct.includes(marker))) {    return "cloud";  }  // Apple hardware booting Linux (Asahi) still reports the Apple product name.  const appleKind = machineKindFromAppleProductName(productName);  if (appleKind !== null) {    return appleKind;  }  return input.chassisType === null ? null : (DMI_CHASSIS_KINDS[input.chassisType] ?? null);} const readOptionalFile = Effect.fn("readOptionalFile")(function* (path: string) {  const fileSystem = yield* FileSystem.FileSystem;  return yield* fileSystem.readFileString(path).pipe(    Effect.map(normalize),    Effect.catch(() => Effect.succeed(null)),  );}); const runProbe = Effect.fn("runMachineProbe")(function* (input: {  readonly command: string;  readonly args: ReadonlyArray<string>;}) {  const processRunner = yield* ProcessRunner.ProcessRunner;  return yield* processRunner    .run({      command: input.command,      args: input.args,      timeout: "5 seconds",      timeoutBehavior: "timedOutResult",    })    .pipe(      Effect.map((result) => (result.code === 0 ? normalize(result.stdout) : null)),      Effect.catch(() => Effect.succeed(null)),    );}); // IOKit's `product` node carries the marketing name ("Mac mini (2024)") on// Apple silicon; Intel Macs lack it, so `hw.model` ("Macmini8,1") is the// fallback. Both are single-digit-millisecond calls.const detectDarwinMachineKind = Effect.fn("detectDarwinMachineKind")(function* () {  const ioreg = yield* runProbe({ command: "ioreg", args: ["-rd1", "-n", "product"] });  const productName = ioreg?.match(/"product-name"\s*=\s*<"([^"]+)">/)?.[1] ?? null;  const fromProductName =    productName === null ? null : machineKindFromAppleProductName(productName);  if (fromProductName !== null) {    return fromProductName;  }  const model = yield* runProbe({ command: "sysctl", args: ["-n", "hw.model"] });  return model === null ? null : machineKindFromAppleProductName(model);}); const detectLinuxMachineKind = Effect.fn("detectLinuxMachineKind")(function* () {  const [kernelRelease, chassisType, sysVendor, productName] = yield* Effect.all([    readOptionalFile(KERNEL_RELEASE_PATH),    readOptionalFile(`${DMI_ROOT}/chassis_type`),    readOptionalFile(`${DMI_ROOT}/sys_vendor`),    readOptionalFile(`${DMI_ROOT}/product_name`),  ]);  // WSL exposes Microsoft in its kernel release on both WSL 1 and WSL 2.  // Check it before DMI because WSL 2 presents as a Hyper-V VM.  if (kernelRelease?.toLowerCase().includes("microsoft")) {    return "linux";  }  return machineKindFromDmi({ chassisType, sysVendor, productName });}); export const detectServerEnvironmentMachineKind = Effect.fn("detectServerEnvironmentMachineKind")(  function* () {    const platform = yield* HostProcessPlatform;    switch (platform) {      case "darwin":        return yield* detectDarwinMachineKind();      case "linux":        return yield* detectLinuxMachineKind();      default:        return null;    }  },);