Dev #8
+10
-2
@@ -1,7 +1,15 @@
|
|||||||
{ pkgs, radiantwave, upgradeFlakeRef, radiantwavePlymouth, ... }:
|
{ config, pkgs, radiantwave, upgradeFlakeRef, radiantwavePlymouth, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
radiantApp = radiantwave.packages.${pkgs.system}.default;
|
radiantApp = radiantwave.packages.${pkgs.system}.default;
|
||||||
|
# When the live-updater module is enabled (currently dev variants only),
|
||||||
|
# RadiantWave launches through the mutable /var/lib/radiantwave/current
|
||||||
|
# pointer so it can be swapped without a full nixos-rebuild. Otherwise it
|
||||||
|
# launches straight from the immutable system closure as before.
|
||||||
|
launchBin =
|
||||||
|
if config.services.radiantwaveUpdater.enable or false
|
||||||
|
then "/var/lib/radiantwave/current/bin/radiantwave"
|
||||||
|
else "/run/current-system/sw/bin/radiantwave";
|
||||||
myKey = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook" ];
|
myKey = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook" ];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -159,7 +167,7 @@ in
|
|||||||
# Release the splash screen right before the compositor takes over the display
|
# Release the splash screen right before the compositor takes over the display
|
||||||
sudo -n plymouth quit --wait || true
|
sudo -n plymouth quit --wait || true
|
||||||
|
|
||||||
exec dbus-run-session cage -- /run/current-system/sw/bin/radiantwave -d -s > /tmp/kiosk.log 2>&1
|
exec dbus-run-session cage -- ${launchBin} -d -s > /tmp/kiosk.log 2>&1
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,18 @@
|
|||||||
|
|
||||||
revision = self.rev or self.dirtyRev or null;
|
revision = self.rev or self.dirtyRev or null;
|
||||||
|
|
||||||
|
# Live app-update side channel, dev-only for now. The manifest is
|
||||||
|
# served by the fileserver; closures are fetched (never built) from the
|
||||||
|
# dev Attic cache. Promotes to prod once validated.
|
||||||
|
radiantwaveDevUpdaterModule = { baseline }: {
|
||||||
|
services.radiantwaveUpdater = {
|
||||||
|
enable = true;
|
||||||
|
manifestUrl = "https://files.radiantwavetech.com/radiantwave-dev/manifest.json";
|
||||||
|
atticUrl = "https://attic.radiantwavetech.com/radiantwave-dev";
|
||||||
|
baselinePackage = baseline;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
mkKioskSystem = {
|
mkKioskSystem = {
|
||||||
system,
|
system,
|
||||||
radiantwave,
|
radiantwave,
|
||||||
@@ -79,6 +91,7 @@
|
|||||||
system.configurationRevision = revision;
|
system.configurationRevision = revision;
|
||||||
}
|
}
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
./radiantwave-updater.nix
|
||||||
disko.nixosModules.disko
|
disko.nixosModules.disko
|
||||||
diskModule
|
diskModule
|
||||||
nixos-facter-modules.nixosModules.facter
|
nixos-facter-modules.nixosModules.facter
|
||||||
@@ -116,6 +129,7 @@
|
|||||||
];
|
];
|
||||||
})
|
})
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
./radiantwave-updater.nix
|
||||||
radiantwave.nixosModules.default
|
radiantwave.nixosModules.default
|
||||||
{
|
{
|
||||||
networking.hostName = hostName;
|
networking.hostName = hostName;
|
||||||
@@ -194,6 +208,9 @@
|
|||||||
hostName = "radiantwavekiosk-dev";
|
hostName = "radiantwavekiosk-dev";
|
||||||
diskModule = ./disk-config.nix;
|
diskModule = ./disk-config.nix;
|
||||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-dev";
|
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-dev";
|
||||||
|
extraModules = [
|
||||||
|
(radiantwaveDevUpdaterModule { baseline = radiantwave-dev.packages.x86_64-linux.default; })
|
||||||
|
];
|
||||||
};
|
};
|
||||||
radiantwavekiosk-commercial = mkKioskSystem {
|
radiantwavekiosk-commercial = mkKioskSystem {
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
@@ -208,6 +225,9 @@
|
|||||||
hostName = "radiantwavekiosk-commercial-dev";
|
hostName = "radiantwavekiosk-commercial-dev";
|
||||||
diskModule = ./commercial-disk-config.nix;
|
diskModule = ./commercial-disk-config.nix;
|
||||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-commercial-dev";
|
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-commercial-dev";
|
||||||
|
extraModules = [
|
||||||
|
(radiantwaveDevUpdaterModule { baseline = radiantwave-dev.packages.x86_64-linux.default; })
|
||||||
|
];
|
||||||
};
|
};
|
||||||
# Rotated screen for android-style displays.
|
# Rotated screen for android-style displays.
|
||||||
radiantwavekiosk-android = mkKioskSystem {
|
radiantwavekiosk-android = mkKioskSystem {
|
||||||
@@ -228,6 +248,7 @@
|
|||||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-android-dev";
|
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-android-dev";
|
||||||
extraModules = [
|
extraModules = [
|
||||||
./rotated_display.nix
|
./rotated_display.nix
|
||||||
|
(radiantwaveDevUpdaterModule { baseline = radiantwave-dev.packages.x86_64-linux.default; })
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
# Raspberry Pi 5.
|
# Raspberry Pi 5.
|
||||||
@@ -240,6 +261,9 @@
|
|||||||
radiantwave = radiantwave-dev;
|
radiantwave = radiantwave-dev;
|
||||||
hostName = "radiantwavekiosk-rpi-dev";
|
hostName = "radiantwavekiosk-rpi-dev";
|
||||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-rpi-dev";
|
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-rpi-dev";
|
||||||
|
extraModules = [
|
||||||
|
(radiantwaveDevUpdaterModule { baseline = radiantwave-dev.packages.aarch64-linux.default; })
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# === USB Images ===
|
# === USB Images ===
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.radiantwaveUpdater;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.radiantwaveUpdater = {
|
||||||
|
enable = lib.mkEnableOption "live RadiantWave app updates via a polled manifest";
|
||||||
|
|
||||||
|
manifestUrl = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "HTTP(S) URL of the JSON manifest announcing the current app store path.";
|
||||||
|
};
|
||||||
|
|
||||||
|
atticUrl = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Attic cache URL to fetch the app closure from (fetch-only, never builds).";
|
||||||
|
};
|
||||||
|
|
||||||
|
baselinePackage = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
description = "Copy of RadiantWave baked into the system closure, used to seed the runtime pointer before the first update.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
# Runtime pointer the login shell launches RadiantWave from. Seeded on
|
||||||
|
# first boot to the baseline copy already baked into the system closure
|
||||||
|
# (so the ISO carries it with no duplication); the updater service later
|
||||||
|
# re-points it atomically to newer closures fetched from Attic.
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"L /var/lib/radiantwave/current - - - - ${cfg.baselinePackage.outPath}"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.radiantwave-updater = {
|
||||||
|
description = "Poll the RadiantWave manifest and swap the live app pointer";
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
set -u
|
||||||
|
|
||||||
|
NEW_PATH=$(${pkgs.curl}/bin/curl -fsSL "${cfg.manifestUrl}" \
|
||||||
|
| ${pkgs.jq}/bin/jq -er .storePath) || {
|
||||||
|
echo "radiantwave-updater: failed to fetch/parse manifest from ${cfg.manifestUrl}"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT=$(${pkgs.coreutils}/bin/readlink /var/lib/radiantwave/current 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -z "$NEW_PATH" ] || [ "$NEW_PATH" = "$CURRENT" ]; then
|
||||||
|
echo "radiantwave-updater: already current (''${CURRENT})"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch the closure from the signed Attic cache only. This never
|
||||||
|
# builds from source; it fails outright if the path isn't there.
|
||||||
|
echo "radiantwave-updater: acquiring ''${NEW_PATH}"
|
||||||
|
${pkgs.nix}/bin/nix copy --from "${cfg.atticUrl}" "$NEW_PATH" || {
|
||||||
|
echo "radiantwave-updater: nix copy failed for ''${NEW_PATH}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Atomic swap: the app never observes a half-updated pointer.
|
||||||
|
${pkgs.coreutils}/bin/ln -sfn "$NEW_PATH" /var/lib/radiantwave/current.tmp
|
||||||
|
${pkgs.coreutils}/bin/mv -T /var/lib/radiantwave/current.tmp /var/lib/radiantwave/current
|
||||||
|
echo "radiantwave-updater: swapped ''${CURRENT} -> ''${NEW_PATH}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.radiantwave-updater = {
|
||||||
|
description = "Check for RadiantWave app updates";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnBootSec = "2min";
|
||||||
|
OnUnitActiveSec = "2min";
|
||||||
|
Persistent = true;
|
||||||
|
Unit = "radiantwave-updater.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user