WinBoat

repository·main·Indexed 12 days ago

https://github.com/tibixdev/winboat

A system for running Windows on Linux ('Windows for Penguins') featuring a Guest Server REST API for system metrics, RDP status, and application info, as well as a Guest Server Updater. Includes the Xel lightweight HTML5 widget toolkit for building native-like UIs and tools for managing QEMU QMP connections and container lifecycles.

Tokens
9.2K
Snippets
33
Records
45
Agent score
98%

What's inside WinBoat

  1. Overview of the Xel widget toolkit

    main
    Xel is an HTML5 widget toolkit designed for building native-like applications for the Web, Electron, and Hybrid environments. It follows the 'Keep It Simple' principle, utilizing plain JavaScript, HTML, and CSS without heavy abstraction layers or preprocessors. This makes it lightweight and easy to integrate into existing web projects.
  2. Understand the Xel licensing model

    main

    The Xel package uses a multi-license model depending on the specific files being used. Most of the NPM package and GitHub source code are licensed under the Xel License (MIT), but specific assets like themes and icons have their own distinct licenses:

    • General Files: Licensed under the Xel License (MIT).
    • Cupertino Theme Files (cupertino.css, cupertino-dark.css): Licensed under the Xel Cupertino License v1.
    • Material Icons (material.svg, material-outlined.svg): Licensed under the Material Icons License v1.
    • Fluent Icons (fluent.svg, fluent-outlined.svg): Licensed under the Fluent Icons License v1.
  3. Manage USB device passthrough with USBManager

    main

    The USBManager class provides a singleton interface for managing USB device passthrough to the guest VM. It automatically handles device attachment/detachment events and synchronizes the passthrough list with the WinboatConfig.

    Key capabilities include:

    • Automatic Passthrough: When a device is added to the passthrough list, it is automatically passed to the VM if the guest is online.
    • Dynamic Updates: Devices added or removed from the host are automatically passed to or removed from the VM if they are in the passthrough list.
    • MTP Handling: Automatically attempts to free MTP (Media Transfer Protocol) devices using fuser before passing them to the VM to prevent resource conflicts.
    import { USBManager } from './usbmanager';
    
    const usbManager = USBManager.getInstance();
  4. How Guest Server updates work

    main

    Winboat automatically manages the version synchronization between the host application and the Guest Server running inside the container.

    The Update Process:

    1. Detection: When the host detects that isOnline has become true, it compares its local version (VITE_APP_VERSION) with the version reported by the guest via ${WINBOAT_API_URL}/version.
    2. Trigger: If versions mismatch, checkVersionAndUpdateGuestServer() is triggered.
    3. Payload Delivery: The host sends a bundled update ZIP file to the ${WINBOAT_UPDATE_URL}/update endpoint using a POST request with guestUpdaterAuthHeaders.
    4. Atomic Application: The Guest Server Updater applies the update atomically. If the new server fails to start, it rolls back.
    5. Verification: The host waits (up to GUEST_ONLINE_TIMEOUT_MS) for the guest to report a healthy status before completing the update cycle.
  5. Generate ComposeConfig for container orchestration

    main

    The ComposeConfig type defines the structure for generating a Docker Compose-compatible configuration. It specifically defines a windows service with a required environment block containing system variables like VERSION, RAM_SIZE, CPU_CORES, DISK_SIZE, USERNAME, PASSWORD, HOME, LANGUAGE, ARGUMENTS, and HOST_PORTS.

    const compose: ComposeConfig = {
        name: 'winboat-instance',
        volumes: {
            '/host/path': '/guest/path'
        },
        services: {
            windows: {
                image: 'winboat-image',
                container_name: 'winboat-container',
                environment: {
                    VERSION: '...', // WindowsVersionKey
                    RAM_SIZE: '8G',
                    CPU_CORES: '4',
                    DISK_SIZE: '64G',
                    USERNAME: 'user',
                    PASSWORD: 'password',
                    HOME: '/home/user',
                    LANGUAGE: 'en-US',
                    ARGUMENTS: '',
                    HOST_PORTS: '8080:80'
                },
                ports: ['8080:80'],
                volumes: ['/host/data:/guest/data'],
                devices: ['/dev/bus/usb/001/001']
            }
        }
    };
  6. Configure Windows installation with InstallConfiguration

    main

    Use the InstallConfiguration type to define the parameters for a new Windows installation. This includes OS version, language, hardware allocation (CPU/RAM), user credentials, and storage settings. You can also specify a customIsoPath for non-standard ISO files and a sharedFolderPath for host-to-guest file sharing.

    const config: InstallConfiguration = {
        windowsVersion: '...', // WindowsVersionKey
        windowsLanguage: 'en-US',
        cpuCores: 4,
        ramGB: 8,
        installFolder: '/path/to/install',
        diskSpaceGB: 64,
        username: 'admin',
        password: 'securepassword',
        container: '...', // ContainerRuntimes
        customIsoPath: '/path/to/custom.iso',
        sharedFolderPath: '/path/to/share'
    };
  7. Available widgets in Xel

    main

    Xel provides a wide variety of UI components to build application interfaces. Supported widgets include:

    • Inputs & Controls: Buttons, Text inputs, Number inputs, Sliders, Selects, Checkboxes, Switches, Radios, Steppers.
    • Navigation & Layout: Tabs, Menus, Menubars, Cards, Drawers.
    • Overlays: Dialogs, Popovers, Context menus.
    • Feedback & Status: Progressbars, Throbbers, Swatchs.
  8. Review the Xel Cupertino License v1 restrictions

    main

    The Cupertino theme files (cupertino.css and cupertino-dark.css) are subject to the Xel Cupertino License v1.

    Key Restriction:

    • The software must be used and distributed as part of an Application bundle for the Apple macOS operating system.
    • Usage of these specific files with any other operating systems is PROHIBITED.
  9. Get system metrics via /metrics

    main

    To retrieve real-time hardware utilization, call the GET /metrics endpoint. The response includes CPU usage and frequency, RAM usage (in MB and percentage), and Disk usage (in MB and percentage).

    Example Response:

    {
      "cpu": {
        "usage": 12.5,
        "frequency": 3200
      },
      "ram": {
        "used": 8192,
        "total": 16384,
        "percentage": 50.0
      },
      "disk": {
        "used": 102400,
        "total": 512000,
        "percentage": 20.0
      }
    }
    GET /metrics
    
    Response:
    {
      "cpu": {
        "usage": 12.5,
        "frequency": 3200
      },
      "ram": {
        "used": 8192,
        "total": 16384,
        "percentage": 50.0
      },
      "disk": {
        "used": 102400,
        "total": 512000,
        "percentage": 20.0
      }
    }
  10. Access the Guest Server OEM directory

    main

    The guestServerOemDir() function returns the path to the OEM payload directory. This directory contains the files that are copied into the guest's C:\OEM mount during the installation process.

    import { guestServerOemDir } from './path/to/guestServer';
    
    const oemPath = guestServerOemDir();
  11. Remove a USB device from the passthrough list

    main

    Use removeDeviceFromPassthroughList(ptDevice) to stop passing a specific device to the VM and remove it from the WinboatConfig. If the guest is online and the device is currently passed through, it will be removed from the VM via QMP immediately.

    import { USBManager, type PTSerializableDeviceInfo } from './usbmanager';
    
    const usbManager = USBManager.getInstance();
    
    // ptDevice is a PTSerializableDeviceInfo object
    await usbManager.removeDeviceFromPassthroughList(ptDevice);
  12. Identify stale container errors

    main

    When interacting with containers, certain errors indicate that the container is in a stale or broken state (for example, if a passed-through USB device is no longer present on the host). In these cases, the container cannot be restarted and must be recreated from the compose file.

    You can use the isStaleContainerError(error) function to detect these specific failure patterns.

    import { isStaleContainerError } from "./path/to/container";
    
    try {
      await myContainerManager.container("start");
    } catch (error) {
      if (isStaleContainerError(error)) {
        console.error("Container is stale. Recreating from compose file...");
        // Logic to run myContainerManager.compose("down") then "up"
      }
    }