initial commit
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
self:
|
||||
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.radiantwave;
|
||||
in
|
||||
{
|
||||
options.services.radiantwave = {
|
||||
enable = lib.mkEnableOption "RadiantWave kiosk application";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = self.packages.${pkgs.system}.default;
|
||||
description = "The RadiantWave package to use.";
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "kiosk";
|
||||
description = "The user account the kiosk runs as.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Just put the package in the system path. The machine configuration owns
|
||||
# the display/audio session (see nixos/vm.nix for a working example).
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
};
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# NixOS test VM for RadiantWave — mirrors the production kiosk setup.
|
||||
#
|
||||
# Build & run:
|
||||
# nixos-rebuild build-vm --flake .#test-vm
|
||||
# ./result/bin/run-test-vm-vm
|
||||
#
|
||||
# - cage as the Wayland compositor (fullscreen kiosk)
|
||||
# - PipeWire audio (with a virtual sink for device-switch testing)
|
||||
# - NetworkManager for the WiFi provisioning page
|
||||
# - Auto-login as the kiosk user, app started via loginShellInit
|
||||
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
radiantWaveApp = config.services.radiantwave.package;
|
||||
in
|
||||
{
|
||||
# ── Hostname ──────────────────────────────────────────────────────────────
|
||||
networking.hostName = "radiantwave-test";
|
||||
|
||||
# ── RadiantWave module ────────────────────────────────────────────────────
|
||||
services.radiantwave.enable = true;
|
||||
|
||||
# ── Boot ──────────────────────────────────────────────────────────────────
|
||||
boot.loader.systemd-boot.enable = lib.mkForce false;
|
||||
boot.loader.efi.canTouchEfiVariables = lib.mkForce false;
|
||||
|
||||
# ── Packages ──────────────────────────────────────────────────────────────
|
||||
environment.systemPackages = [
|
||||
pkgs.cage
|
||||
pkgs.rsync
|
||||
pkgs.dbus
|
||||
pkgs.mesa
|
||||
pkgs.git
|
||||
pkgs.sqlite
|
||||
];
|
||||
|
||||
# ── Audio (PipeWire + virtual sink for device-switch testing) ─────────────
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
pulse.enable = true;
|
||||
extraConfig.pipewire."30-virtual-sink" = {
|
||||
"context.modules" = [
|
||||
{
|
||||
name = "libpipewire-module-loopback";
|
||||
args = {
|
||||
"node.name" = "virtual-speaker";
|
||||
"node.description" = "Virtual Speaker";
|
||||
"audio.position" = [ "FL" "FR" ];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# ── Seat ──────────────────────────────────────────────────────────────────
|
||||
services.seatd.enable = true;
|
||||
hardware.graphics.enable = true;
|
||||
|
||||
# ── Networking ────────────────────────────────────────────────────────────
|
||||
services.resolved.enable = false;
|
||||
networking.networkmanager.enable = true;
|
||||
systemd.services.NetworkManager-wait-online.enable = false;
|
||||
systemd.network.wait-online.enable = false;
|
||||
|
||||
# ── SSH ───────────────────────────────────────────────────────────────────
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "prohibit-password";
|
||||
PasswordAuthentication = true;
|
||||
};
|
||||
};
|
||||
|
||||
# ── User ──────────────────────────────────────────────────────────────────
|
||||
users.users.kiosk = {
|
||||
isNormalUser = true;
|
||||
uid = 1000;
|
||||
extraGroups = [ "audio" "video" "input" "networkmanager" "wheel" ];
|
||||
password = "kiosk";
|
||||
};
|
||||
services.getty.autologinUser = "kiosk";
|
||||
|
||||
# ── Data directories (matches the app's first-run paths) ──────────────────
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /home/kiosk/.local/radiantwave 0770 kiosk kiosk -"
|
||||
"d /home/kiosk/.local/radiantwave/audio 0755 kiosk kiosk -"
|
||||
];
|
||||
|
||||
# ── RadiantWave service (via loginShellInit, same as production) ──────────
|
||||
environment.loginShellInit = ''
|
||||
if [ "$(tty)" = "/dev/tty1" ]; then
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
# Smart Network Wait
|
||||
for i in {1..10}; do
|
||||
if ${pkgs.iputils}/bin/ping -c 1 8.8.8.8 &> /dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Graphics fixes (matches production)
|
||||
export SDL_VIDEODRIVER=wayland
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export WLR_RENDERER=pixman
|
||||
export WLR_NO_HARDWARE_CURSORS=1
|
||||
|
||||
cage -- ${radiantWaveApp}/bin/radiantwave > /tmp/kiosk.log 2>&1
|
||||
fi
|
||||
'';
|
||||
|
||||
# ── VM settings ───────────────────────────────────────────────────────────
|
||||
virtualisation = {
|
||||
memorySize = 4096;
|
||||
cores = 4;
|
||||
graphics = true;
|
||||
forwardPorts = [
|
||||
{ from = "host"; host.port = 2222; guest.port = 22; }
|
||||
];
|
||||
qemu.options = [
|
||||
"-device intel-hda"
|
||||
"-device hda-duplex"
|
||||
"-vga virtio"
|
||||
];
|
||||
};
|
||||
|
||||
services.logrotate.enable = false;
|
||||
|
||||
# ── Nix settings ──────────────────────────────────────────────────────────
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
nix.settings.accept-flake-config = true;
|
||||
|
||||
# ── Firewall (open for local dev) ─────────────────────────────────────────
|
||||
networking.firewall.enable = false;
|
||||
|
||||
system.stateVersion = "24.11";
|
||||
}
|
||||
Reference in New Issue
Block a user