cosmic checkpoint
This commit is contained in:
parent
4031a614a8
commit
f623faa0ef
26 changed files with 1163 additions and 538 deletions
|
@ -7,32 +7,84 @@
|
|||
inherit (lib) mkOption;
|
||||
inherit (lib.attrsets) mapAttrs mapAttrs' nameValuePair;
|
||||
inherit (lib) getExe getExe';
|
||||
# make a firefox webapp entry for the client app
|
||||
# make a firefox webapp + hidden .desktop entry for the client app
|
||||
make-firefox = cfg:
|
||||
mapAttrs' (
|
||||
name: cfg:
|
||||
nameValuePair "${name}-client"
|
||||
{
|
||||
inherit (cfg) name id;
|
||||
inherit (cfg) name;
|
||||
url = "http://127.0.0.1:${builtins.toString cfg.port}";
|
||||
extraSettings = config.programs.firefox.profiles.default.settings;
|
||||
hidden = true;
|
||||
}
|
||||
)
|
||||
cfg;
|
||||
# make a systemd service for running the backend
|
||||
make-systemd = cfg:
|
||||
# make a systemd service for running the frontend
|
||||
make-systemd-service = cfg:
|
||||
mapAttrs' (
|
||||
name: cfg:
|
||||
if
|
||||
(cfg.service
|
||||
!= null)
|
||||
then
|
||||
nameValuePair "${cfg.name}-frontend" {
|
||||
Unit = {
|
||||
Description = "${cfg.name} Frontend";
|
||||
WantedBy = lib.mkForce [];
|
||||
};
|
||||
|
||||
Service = cfg.service;
|
||||
}
|
||||
else nameValuePair "" {}
|
||||
)
|
||||
cfg;
|
||||
# modify systemd units to be PartOf this target
|
||||
modify-systemd-services = cfg:
|
||||
lib.listToAttrs (lib.flatten (lib.mapAttrsToList (
|
||||
name: cfg: (map (
|
||||
req: {
|
||||
name = "${req}";
|
||||
value = {
|
||||
Unit = {
|
||||
PartOf = "${lib.toLower cfg.name}.target";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
cfg.requires.services)
|
||||
)
|
||||
cfg));
|
||||
modify-quadlets = cfg:
|
||||
lib.listToAttrs (lib.flatten (lib.mapAttrsToList (
|
||||
name: cfg: (map (
|
||||
req: {
|
||||
name = "${req}";
|
||||
value = {
|
||||
unitConfig = {
|
||||
PartOf = "${lib.toLower cfg.name}.target";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
cfg.requires.containers)
|
||||
)
|
||||
cfg));
|
||||
# make a systemd target to collate dependencies
|
||||
make-systemd-target = cfg:
|
||||
mapAttrs (
|
||||
name: cfg: {
|
||||
Unit = {
|
||||
Description = "${cfg.name} Backend";
|
||||
Description = "${cfg.name} Target";
|
||||
WantedBy = lib.mkForce [];
|
||||
Requires =
|
||||
(map (req: req + ".service") cfg.requires.services)
|
||||
++ (map (req: "podman-" + req + ".service") cfg.requires.containers);
|
||||
};
|
||||
Service = cfg.service;
|
||||
}
|
||||
)
|
||||
cfg;
|
||||
# make desktop shortcuts and a script which will handle starting both the above
|
||||
# make desktop shortcuts and a script which will handle starting everything
|
||||
make-xdg = cfg:
|
||||
mapAttrs (
|
||||
name: cfg: {
|
||||
|
@ -42,45 +94,72 @@
|
|||
notify-send = "${getExe' pkgs.libnotify "notify-send"} -a \"${cfg.name}\"";
|
||||
systemctl = "${getExe' pkgs.systemd "systemctl"}";
|
||||
dex = "${getExe pkgs.dex}";
|
||||
curl = "${getExe pkgs.curl}";
|
||||
podman = "${getExe pkgs.podman}";
|
||||
makeContainerCheck = container: ''[ "$(${podman} inspect -f {{.State.Health.Status}} ${container})" == "healthy" ]'';
|
||||
# makeContainerCheck = container: ''
|
||||
# [ ${podman} inspect -f {{.State.Status}} ${container})" != "running" ]
|
||||
# '';
|
||||
containerChecks =
|
||||
if (cfg.requires.containers != [])
|
||||
then
|
||||
''
|
||||
container_checks() {
|
||||
if ''
|
||||
+ (lib.concatMapStringsSep " && "
|
||||
(container: makeContainerCheck container)
|
||||
cfg.requires.containers)
|
||||
+ ''
|
||||
; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
''
|
||||
else ''
|
||||
container_checks() {
|
||||
return 0
|
||||
}
|
||||
'';
|
||||
in
|
||||
pkgs.writeShellScript "${name}"
|
||||
''
|
||||
set -euo pipefail
|
||||
${notify-send} "Launching backend.." "Please be patient."
|
||||
${systemctl} --user start ${name}
|
||||
attempts=0
|
||||
success=false
|
||||
|
||||
while [[ $attempts -lt $((20*9)) ]]; do
|
||||
if [[ $(${curl} -sf http://127.0.0.1:${builtins.toString cfg.port} --output /dev/null; printf $?) -eq 0 ]]; then
|
||||
${notify-send} "Backend up." "Launching client.."
|
||||
success=true
|
||||
break
|
||||
else
|
||||
attempts=$((attempts+1))
|
||||
if [[ $(($attempts % 20)) -eq 0 ]]; then
|
||||
${notify-send} "Launching backend.." "Still launching.. ($((attempts/2))s)"
|
||||
fi
|
||||
exit_error() {
|
||||
${notify-send} -w "Failure" $1
|
||||
exit 1
|
||||
}
|
||||
|
||||
${containerChecks}
|
||||
|
||||
${notify-send} "Launching ${name} backend.." "Please be patient."
|
||||
${systemctl} --user start ${name}.target || exit_error "Failed to launch!"
|
||||
|
||||
checks=0
|
||||
until container_checks; do
|
||||
sleep 2
|
||||
checks=$((checks+1))
|
||||
if [ $((checks%10)) -eq 0 ]; then
|
||||
${notify-send} "Waiting for backend."
|
||||
fi
|
||||
if [ $checks -ge 60 ]; then
|
||||
${systemctl} --no-block --user stop ${name}.target
|
||||
exit_error "Failed to launch!"
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if [[ ! $success ]]; then
|
||||
${notify-send} "Failure" "Failed to launch backend!"
|
||||
${systemctl} --user kill ${name}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
${notify-send} "Launching ${name}.."
|
||||
${dex} -w ~/.nix-profile/share/applications/${name}-client.desktop
|
||||
|
||||
${notify-send} "Goodbye" "Shutting down."
|
||||
${systemctl} --user stop ${name}
|
||||
${systemctl} --user stop ${name}.target
|
||||
exit 0
|
||||
''}";
|
||||
}
|
||||
)
|
||||
cfg;
|
||||
cfg = config.localWebApps;
|
||||
in {
|
||||
options.localWebApps = mkOption {
|
||||
default = {};
|
||||
|
@ -104,29 +183,59 @@ in {
|
|||
default = null;
|
||||
};
|
||||
|
||||
id = mkOption {
|
||||
type = int;
|
||||
description = "Firefox profile ID for the webapp's client";
|
||||
requires = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
containers = mkOption {
|
||||
type = listOf str;
|
||||
default = [];
|
||||
};
|
||||
services = mkOption {
|
||||
type = listOf str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
description = "Containers or services this app requires.";
|
||||
};
|
||||
|
||||
service = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
execStartPre = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
execStart = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
execStop = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
description = "Submodule containing exec[StartPre/Start/Stop] commands for any required systemd service";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = int;
|
||||
description = "Local port the webapp should host on.";
|
||||
};
|
||||
|
||||
service = mkOption {
|
||||
type = attrsOf str;
|
||||
description = "The service settings for systemd user service. Requires at least ExecStart.";
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
config = {
|
||||
programs.firefox.webapps = make-firefox config.localWebApps;
|
||||
programs.firefox.webapps = make-firefox cfg;
|
||||
|
||||
systemd.user.services = make-systemd config.localWebApps;
|
||||
systemd.user.targets = make-systemd-target cfg;
|
||||
systemd.user.services = (make-systemd-service cfg) // (modify-systemd-services cfg);
|
||||
services.podman.containers = modify-quadlets cfg;
|
||||
|
||||
xdg.desktopEntries = make-xdg config.localWebApps;
|
||||
xdg.desktopEntries = make-xdg cfg;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue