diff --git a/flake.nix b/flake.nix index 86981b5..3307294 100644 --- a/flake.nix +++ b/flake.nix @@ -296,7 +296,7 @@ rsync-pull-targets = ./modules/rsync-pull-targets.nix; snakeoil-certs = ./modules/snakeoil-certs.nix; snappymail = ./modules/snappymail.nix; - drumknotty = ./modules/drumknotty.nix; + drumknotty = ./modules/drumknotty; }; devShells = forAllSystems (system: { diff --git a/hosts/skrot/configuration.nix b/hosts/skrot/configuration.nix index 473038b..fcc0000 100644 --- a/hosts/skrot/configuration.nix +++ b/hosts/skrot/configuration.nix @@ -40,30 +40,40 @@ services.drumknotty = { enable = true; kioskMode = true; - limitScreenWidth = 80; - limitScreenHeight = 42; - dibblerSettings = { - general.quit_allowed = false; - database = { - type = "postgresql"; - postgresql = { - username = "pvv_vv"; - dbname = "pvv_vv"; - host = "postgres.pvv.ntnu.no"; - password_file = config.sops.secrets."dibbler/postgresql/password".path; + screen = { + limitWidth = 80; + limitHeight = 42; + }; + + dibbler = { + enable = true; + settings = { + general.quit_allowed = false; + database = { + type = "postgresql"; + postgresql = { + username = "pvv_vv"; + dbname = "pvv_vv"; + host = "postgres.pvv.ntnu.no"; + password_file = config.sops.secrets."dibbler/postgresql/password".path; + }; }; }; }; - worblehatSettings = { - general.quit_allowed = false; - database = { - type = "postgresql"; - postgresql = { - username = "worblehat"; - dbname = "worblehat"; - host = "postgres.pvv.ntnu.no"; - password = config.sops.secrets."worblehat/postgresql/password".path; + + worblehat = { + enable = true; + settings = { + general.quit_allowed = false; + database = { + type = "postgresql"; + postgresql = { + username = "worblehat"; + dbname = "worblehat"; + host = "postgres.pvv.ntnu.no"; + password = config.sops.secrets."worblehat/postgresql/password".path; + }; }; }; }; diff --git a/modules/drumknotty.nix b/modules/drumknotty.nix deleted file mode 100644 index ba0e08a..0000000 --- a/modules/drumknotty.nix +++ /dev/null @@ -1,379 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - cfg = config.services.drumknotty; - - format = pkgs.formats.toml { }; -in -{ - options.services.drumknotty = { - enable = lib.mkEnableOption "DrumknoTTY"; - - dibblerPackage = lib.mkPackageOption pkgs "dibbler" { }; - worblehatPackage = lib.mkPackageOption pkgs "worblehat" { }; - screenPackage = lib.mkPackageOption pkgs "screen" { }; - - screenSessionName = lib.mkOption { - type = lib.types.str; - default = "drumknotty"; - example = "myscreensessionname"; - description = '' - Sets the screen session name. - ''; - }; - - createLocalDatabase = lib.mkEnableOption "" // { - description = '' - Whether to set up a local postgres database automatically. - - ::: {.note} - You must set up postgres manually before enabling this option. - ::: - ''; - }; - - kioskMode = lib.mkEnableOption "" // { - description = '' - Whether to let dibbler take over the entire machine. - - This will restrict the machine to a single TTY and make the program unquittable. - You can still get access to PTYs via SSH and similar, if enabled. - ''; - }; - - limitScreenHeight = lib.mkOption { - type = with lib.types; nullOr ints.unsigned; - default = null; - example = 42; - description = '' - If set, limits the height of the screen dibbler uses to the given number of lines. - ''; - }; - - limitScreenWidth = lib.mkOption { - type = with lib.types; nullOr ints.unsigned; - default = null; - example = 80; - description = '' - If set, limits the width of the screen dibbler uses to the given number of columns. - ''; - }; - - dibblerSettings = lib.mkOption { - description = "Configuration for dibbler"; - default = { }; - type = lib.types.submodule { - freeformType = format.type; - }; - }; - - worblehatSettings = lib.mkOption { - description = "Configuration for worblehat"; - default = { }; - type = lib.types.submodule { - freeformType = format.type; - }; - }; - - deadline-daemon = { - enable = lib.mkEnableOption "" // { - description = '' - Whether to enable the worblehat deadline-daemon service, - which periodically checks for upcoming deadlines and notifies users. - - Note that this service is independent of the main worblehat service, - and must be enabled separately. - ''; - }; - - onCalendar = lib.mkOption { - type = lib.types.str; - description = '' - How often to trigger rendering the map, - in the format of a systemd timer onCalendar configuration. - - See {manpage}`systemd.timer(5)`. - ''; - default = "*-*-* 10:15:00"; - }; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - environment.systemPackages = [ - cfg.dibblerPackage - cfg.worblehatPackage - ]; - - environment.etc."dibbler/dibbler.toml".source = format.generate "dibbler.toml" cfg.dibblerSettings; - environment.etc."worblehat/config.toml".source = - format.generate "worblehat-config.toml" cfg.worblehatSettings; - - users = { - users.drumknotty = { - group = "drumknotty"; - isNormalUser = true; - }; - groups.drumknotty = { }; - }; - - services.drumknotty.dibblerSettings = { - limits = { - low_credit_warning_limit = lib.mkDefault (-100); - user_recent_transaction_limit = lib.mkDefault 100; - }; - - printer = { - label_type = lib.mkDefault "62"; - label_rotate = lib.mkDefault false; - }; - }; - - services.drumknotty.worblehatSettings = { - logging = { - debug = lib.mkDefault true; - debug_sql = lib.mkDefault false; - }; - - database = { - type = lib.mkDefault "sqlite"; - sqlite.path = lib.mkDefault "./worblehat.sqlite"; - postgresql = { - host = lib.mkDefault "localhost"; - port = lib.mkDefault 5432; - username = lib.mkDefault "worblehat"; - password = lib.mkDefault "/var/lib/worblehat/db-password"; - database = lib.mkDefault "worblehat"; - }; - }; - - flask = { - TESTING = lib.mkDefault true; - DEBUG = lib.mkDefault true; - FLASK_ENV = lib.mkDefault "development"; - SECRET_KEY = lib.mkDefault "change-me"; - }; - - smtp = { - enabled = lib.mkDefault false; - host = lib.mkDefault "smtp.pvv.ntnu.no"; - port = lib.mkDefault 587; - username = lib.mkDefault "worblehat"; - password = lib.mkDefault "/var/lib/worblehat/smtp-password"; - from = lib.mkDefault "worblehat@pvv.ntnu.no"; - subject_prefix = lib.mkDefault "[Worblehat]"; - }; - - deadline_daemon = { - enabled = lib.mkDefault true; - dryrun = lib.mkDefault false; - warn_days_before_borrowing_deadline = lib.mkDefault [ - 5 - 1 - ]; - days_before_queue_position_expires = lib.mkDefault 14; - warn_days_before_expiring_queue_position_deadline = lib.mkDefault [ - 3 - 1 - ]; - }; - }; - - services.drumknotty.dibblerSettings.database = lib.mkIf cfg.createLocalDatabase { - type = "postgresql"; - postgresql.host = "/run/postgresql"; - }; - - services.postgresql = lib.mkIf cfg.createLocalDatabase { - ensureDatabases = [ - "dibbler" - "worblehat" - ]; - ensureUsers = [ - { - name = "drumknotty"; - ensureDBOwnership = true; - ensureClauses.login = true; - } - ]; - }; - - systemd.services.dibbler-setup-database = lib.mkIf cfg.createLocalDatabase { - description = "Dibbler database setup"; - wantedBy = [ "default.target" ]; - after = [ "postgresql.service" ]; - unitConfig = { - ConditionPathExists = "!/var/lib/dibbler/.db-setup-done"; - }; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${lib.getExe cfg.dibblerPackage} --config /etc/dibbler/dibbler.toml create-db"; - ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/dibbler/.db-setup-done"; - StateDirectory = "dibbler"; - - User = "drumknotty"; - Group = "drumknotty"; - }; - }; - - systemd.services.worblehat-setup-database = lib.mkIf cfg.createLocalDatabase { - description = "Worblehat database setup"; - wantedBy = [ "default.target" ]; - after = [ "postgresql.service" ]; - unitConfig = { - ConditionPathExists = "!/var/lib/worblehat/.db-setup-done"; - }; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${lib.getExe cfg.worblehatPackage} --config /etc/worblehat/config.toml create-db"; - ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/worblehat/.db-setup-done"; - StateDirectory = "worblehat"; - - User = "drumknotty"; - Group = "drumknotty"; - }; - }; - - } - (lib.mkIf cfg.kioskMode { - boot.kernelParams = [ - "console=tty1" - ]; - - users.users.drumknotty = { - extraGroups = [ "lp" ]; - shell = - (pkgs.writeShellScriptBin "login-shell" "${lib.getExe' cfg.screenPackage "screen"} -x ${cfg.screenSessionName} -p dibbler") - // { - shellPath = "/bin/login-shell"; - }; - }; - - services.drumknotty.dibblerSettings.general = { - quit_allowed = false; - stop_allowed = false; - }; - - services.drumknotty.worblehatSettings.general = { - quit_allowed = false; - stop_allowed = false; - }; - - systemd.services.drumknotty-screen-session = { - description = "Drumknotty Screen Session"; - wantedBy = [ - "default.target" - ]; - after = - if cfg.createLocalDatabase then - [ - "postgresql.service" - "dibbler-setup-database.service" - "worblehat-setup-database.service" - ] - else - [ - "network.target" - ]; - serviceConfig = - let - dibblerArgs = lib.cli.toCommandLineShellGNU { } { - config = "/etc/dibbler/dibbler.toml"; - }; - - worblehatArgs = lib.cli.toCommandLineShellGNU { } { - config = "/etc/worblehat/config.toml"; - }; - - in - { - Type = "forking"; - RemainAfterExit = false; - Restart = "always"; - RestartSec = "5s"; - SuccessExitStatus = 1; - - User = "drumknotty"; - Group = "drumknotty"; - - ExecStartPre = "-${lib.getExe' cfg.screenPackage "screen"} -X -S ${cfg.screenSessionName} kill"; - ExecStart = - let - screenArgs = lib.escapeShellArgs [ - # -dm creates the screen in detached mode without accessing it - "-dm" - - # Session name - "-S" - "${cfg.screenSessionName}" - - # Window name - "-t" - "dibbler" - - # Set optimal output mode instead of VT100 emulation - "-O" - - # Enable login mode, updates utmp entries - "-l" - ]; - - in - "${lib.getExe' cfg.screenPackage "screen"} ${screenArgs} ${lib.getExe cfg.dibblerPackage} ${dibblerArgs} loop"; - ExecStartPost = [ - "${lib.getExe' cfg.screenPackage "screen"} -S ${cfg.screenSessionName} -X screen -t worblehat ${lib.getExe cfg.worblehatPackage} ${worblehatArgs} cli" - ] - ++ lib.optionals (cfg.limitScreenWidth != null) [ - "${lib.getExe' cfg.screenPackage "screen"} -X -S ${cfg.screenSessionName} width ${toString cfg.limitScreenWidth}" - ] - ++ lib.optionals (cfg.limitScreenHeight != null) [ - "${lib.getExe' cfg.screenPackage "screen"} -X -S ${cfg.screenSessionName} height ${toString cfg.limitScreenHeight}" - ]; - }; - }; - - services.getty.autologinUser = "drumknotty"; - }) - (lib.mkIf cfg.deadline-daemon.enable { - systemd.timers.worblehat-deadline-daemon = { - description = "Worblehat Deadline Daemon"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = cfg.deadline-daemon.onCalendar; - Persistent = true; - }; - }; - - systemd.services.worblehat-deadline-daemon = { - description = "Worblehat Deadline Daemon"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - serviceConfig = { - Type = "oneshot"; - CPUSchedulingPolicy = "idle"; - IOSchedulingClass = "idle"; - - ExecStart = - let - worblehatArgs = lib.cli.toCommandLineShellGNU { } { - config = "/etc/worblehat/config.toml"; - }; - in - "${lib.getExe cfg.package} ${worblehatArgs} deadline-daemon"; - - User = "worblehat"; - Group = "worblehat"; - }; - }; - }) - - ] - ); - -} diff --git a/modules/drumknotty/default.nix b/modules/drumknotty/default.nix new file mode 100644 index 0000000..b2da9f7 --- /dev/null +++ b/modules/drumknotty/default.nix @@ -0,0 +1,198 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.drumknotty; +in +{ + imports = [ + ./dibbler.nix + ./worblehat.nix + ]; + + options.services.drumknotty = { + enable = lib.mkEnableOption "DrumknoTTY"; + + kioskMode = lib.mkEnableOption "" // { + description = '' + Whether to let dibbler take over the entire machine. + + This will restrict the machine to a single TTY and make the program unquittable. + You can still get access to PTYs via SSH and similar, if enabled. + ''; + }; + + screen = { + package = lib.mkPackageOption pkgs "screen" { }; + + sessionName = lib.mkOption { + type = lib.types.str; + default = "drumknotty"; + example = "myscreensessionname"; + description = '' + Sets the screen session name. + ''; + }; + + limitHeight = lib.mkOption { + type = with lib.types; nullOr ints.unsigned; + default = null; + example = 42; + description = '' + If set, limits the height of the screen dibbler uses to the given number of lines. + ''; + }; + + limitWidth = lib.mkOption { + type = with lib.types; nullOr ints.unsigned; + default = null; + example = 80; + description = '' + If set, limits the width of the screen dibbler uses to the given number of columns. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.enable -> lib.any (b: b) [ + cfg.dibbler.enable + cfg.worblehat.enable + ]; + message = "DrumknoTTY must have at least one service enabled"; + } + ]; + + users = { + users.drumknotty = { + group = "drumknotty"; + extraGroups = [ "lp" ]; + isNormalUser = true; + + # TODO: make this display the error log or error message in case that + # the screen session service is bootlooping or otherwise off. + shell = + lib.mkIf cfg.kioskMode + (pkgs.writeShellScriptBin "login-shell" + "${lib.getExe' cfg.screen.package "screen"} -x ${cfg.screen.sessionName} -p dibbler" + // { + shellPath = "/bin/login-shell"; + }); + }; + groups.drumknotty = { }; + }; + + boot.kernelParams = lib.mkIf cfg.kioskMode [ + "console=tty1" + ]; + + services.getty.autologinUser = lib.mkIf cfg.kioskMode "drumknotty"; + + systemd.services.drumknotty-screen-session = lib.mkIf cfg.kioskMode { + description = "Drumknotty Screen Session"; + wantedBy = [ + "default.target" + ]; + after = + # TODO: this could be refined + if (cfg.dibbler.createLocalDatabase || cfg.worblehat.createLocalDatabase) then + [ + "postgresql.service" + "dibbler-setup-database.service" + "worblehat-setup-database.service" + ] + else + [ + "network.target" + ]; + + serviceConfig = { + Type = "forking"; + RemainAfterExit = false; + Restart = "always"; + RestartSec = "5s"; + SuccessExitStatus = 1; + + User = "drumknotty"; + Group = "drumknotty"; + + ExecStartPre = + let + screenArgs = lib.escapeShellArgs [ + # Send the specified command to a running screen session + "-X" + + # Session name + "-S" + "${cfg.screen.sessionName}" + + "kill" + ]; + in + "-${lib.getExe' cfg.screen.package "screen"} ${screenArgs}"; + + ExecStart = + let + screenrc = let + convertToFile = lines: lib.pipe lines [ + lib.concatLists + (lib.concatStringsSep "\n") + (pkgs.writeText "drumknotty-screenrc") + ]; + in convertToFile [ + (lib.optionals (cfg.screen.limitWidth != null) [ + "screen width ${toString cfg.screen.limitWidth}" + ]) + (lib.optionals (cfg.screen.limitHeight != null) [ + "screen height ${toString cfg.screen.limitHeight}" + ]) + + (let + dibblerArgs = lib.cli.toCommandLineShellGNU { } { + config = "/etc/dibbler/dibbler.toml"; + }; + in lib.optionals cfg.dibbler.enable [ + "screen -t worblehat ${lib.getExe cfg.dibbler.package} ${dibblerArgs} loop" + + ]) + + (let + worblehatArgs = lib.cli.toCommandLineShellGNU { } { + config = "/etc/worblehat/config.toml"; + }; + in lib.optionals cfg.worblehat.enable [ + "screen -t worblehat ${lib.getExe cfg.worblehat.package} ${worblehatArgs} cli" + ]) + + [ "select 0" ] + ]; + + screenArgs = lib.escapeShellArgs [ + # -dm creates the screen in detached mode without accessing it + "-dm" + + # Session name + "-S" + "${cfg.screen.sessionName}" + + # Set optimal output mode instead of VT100 emulation + "-O" + + # Enable login mode, updates utmp entries + "-l" + + # Config file path + "-c" + "${screenrc}" + ]; + in + "${lib.getExe' cfg.screen.package "screen"} ${screenArgs}"; + }; + }; + }; +} diff --git a/modules/drumknotty/dibbler.nix b/modules/drumknotty/dibbler.nix new file mode 100644 index 0000000..02d42a2 --- /dev/null +++ b/modules/drumknotty/dibbler.nix @@ -0,0 +1,113 @@ +{ + config, + pkgs, + lib, + ... +}: +let + mainCfg = config.services.drumknotty; + cfg = config.services.drumknotty.dibbler; + + format = pkgs.formats.toml { }; +in +{ + options.services.drumknotty.dibbler = { + enable = lib.mkEnableOption ""; + + package = lib.mkPackageOption pkgs "dibbler" { }; + + settings = lib.mkOption { + description = "Configuration for dibbler"; + default = { }; + type = lib.types.submodule { + freeformType = format.type; + }; + }; + + createLocalDatabase = lib.mkEnableOption "" // { + description = '' + Whether to set up a local postgres database automatically. + + ::: {.note} + You must set up postgres manually before enabling this option. + ::: + ''; + }; + }; + + config = lib.mkIf (mainCfg.enable && cfg.enable) { + assertions = [ + { + assertion = cfg.createLocalDatabase -> config.services.postgresql.enable; + message = "PostgreSQL must be enabled for dibbler to create a local database"; + } + ]; + + environment.systemPackages = [ cfg.package ]; + environment.etc."dibbler/dibbler.toml".source = format.generate "dibbler.toml" cfg.settings; + + services.drumknotty.dibbler.settings = { + limits = { + low_credit_warning_limit = lib.mkDefault (-100); + user_recent_transaction_limit = lib.mkDefault 100; + }; + + printer = { + label_type = lib.mkDefault "62"; + label_rotate = lib.mkDefault false; + }; + + database = { + type = lib.mkIf cfg.createLocalDatabase "postgresql"; + postgresql = { + username = lib.mkDefault "dibbler"; + dbname = lib.mkDefault "dibbler"; + + host = lib.mkIf cfg.createLocalDatabase "/run/postgresql"; + }; + }; + }; + + services.drumknotty.dibbler.settings.general = lib.mkIf mainCfg.kioskMode { + quit_allowed = false; + stop_allowed = false; + }; + + services.postgresql = lib.mkIf cfg.createLocalDatabase { + authentication = '' + local ${cfg.settings.database.postgresql.dbname} ${cfg.settings.database.postgresql.username} peer map=${cfg.settings.database.postgresql.username} + ''; + identMap = '' + ${cfg.settings.database.postgresql.username} drumknotty ${cfg.settings.database.postgresql.username} + ''; + ensureDatabases = [ cfg.settings.database.postgresql.dbname ]; + ensureUsers = [{ + name = cfg.settings.database.postgresql.username; + ensureDBOwnership = true; + ensureClauses.login = true; + }]; + }; + + systemd.services.dibbler-setup-database = lib.mkIf cfg.createLocalDatabase { + description = "Dibbler database setup"; + + wantedBy = [ "default.target" ]; + requiredBy = [ "drumknotty-screen-session.service" ]; + before = [ "drumknotty-screen-session.service" ]; + after = [ "postgresql.service" ]; + + unitConfig = { + ConditionPathExists = "!/var/lib/dibbler/.db-setup-done"; + }; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe cfg.package} --config /etc/dibbler/dibbler.toml create-db"; + ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/dibbler/.db-setup-done"; + StateDirectory = "dibbler"; + + User = "drumknotty"; + Group = "drumknotty"; + }; + }; + }; +} diff --git a/modules/drumknotty/worblehat.nix b/modules/drumknotty/worblehat.nix new file mode 100644 index 0000000..b8e6a22 --- /dev/null +++ b/modules/drumknotty/worblehat.nix @@ -0,0 +1,209 @@ +{ + config, + pkgs, + lib, + ... +}: +let + mainCfg = config.services.drumknotty; + cfg = config.services.drumknotty.worblehat; + + format = pkgs.formats.toml { }; +in +{ + options.services.drumknotty.worblehat = { + enable = lib.mkEnableOption ""; + + package = lib.mkPackageOption pkgs "worblehat" { }; + + settings = lib.mkOption { + description = "Configuration for worblehat"; + default = { }; + type = lib.types.submodule { + freeformType = format.type; + }; + }; + + createLocalDatabase = lib.mkEnableOption "" // { + description = '' + Whether to set up a local postgres database automatically. + + ::: {.note} + You must set up postgres manually before enabling this option. + ::: + ''; + }; + + deadline-daemon = { + enable = lib.mkEnableOption "" // { + description = '' + Whether to enable the worblehat deadline-daemon service, + which periodically checks for upcoming deadlines and notifies users. + + Note that this service is independent of the main worblehat service, + and must be enabled separately. + ''; + }; + + onCalendar = lib.mkOption { + type = lib.types.str; + description = '' + How often to trigger rendering the map, + in the format of a systemd timer onCalendar configuration. + + See {manpage}`systemd.timer(5)`. + ''; + default = "*-*-* 10:15:00"; + }; + }; + }; + + config = lib.mkMerge [ + { + assertions = [ + { + assertion = cfg.createLocalDatabase -> config.services.postgresql.enable; + message = "PostgreSQL must be enabled for worblehat to create a local database"; + } + ]; + + # TODO: Retrieve defaults from the example config file in the project code. + services.drumknotty.worblehat.settings = { + logging = { + debug = lib.mkDefault true; + debug_sql = lib.mkDefault false; + }; + + database = { + type = lib.mkDefault "sqlite"; + sqlite.path = lib.mkDefault "./worblehat.sqlite"; + postgresql = { + host = lib.mkDefault "localhost"; + port = lib.mkDefault 5432; + username = lib.mkDefault "worblehat"; + password = lib.mkDefault "/var/lib/worblehat/db-password"; + database = lib.mkDefault "worblehat"; + }; + }; + + flask = { + TESTING = lib.mkDefault true; + DEBUG = lib.mkDefault true; + FLASK_ENV = lib.mkDefault "development"; + SECRET_KEY = lib.mkDefault "change-me"; + }; + + smtp = { + enabled = lib.mkDefault false; + host = lib.mkDefault "smtp.pvv.ntnu.no"; + port = lib.mkDefault 587; + username = lib.mkDefault "worblehat"; + password = lib.mkDefault "/var/lib/worblehat/smtp-password"; + from = lib.mkDefault "worblehat@pvv.ntnu.no"; + subject_prefix = lib.mkDefault "[Worblehat]"; + }; + + deadline_daemon = { + enabled = lib.mkDefault true; + dryrun = lib.mkDefault false; + warn_days_before_borrowing_deadline = lib.mkDefault [ + 5 + 1 + ]; + days_before_queue_position_expires = lib.mkDefault 14; + warn_days_before_expiring_queue_position_deadline = lib.mkDefault [ + 3 + 1 + ]; + }; + }; + } + + (lib.mkIf ((mainCfg.enable && cfg.enable) || cfg.deadline-daemon.enable) { + environment.systemPackages = [ cfg.package ]; + environment.etc."worblehat/config.toml".source = format.generate "worblehat-config.toml" cfg.settings; + }) + + (lib.mkIf (mainCfg.enable && cfg.enable) { + services.drumknotty.worblehat.settings.general = lib.mkIf mainCfg.kioskMode { + quit_allowed = false; + stop_allowed = false; + }; + + services.drumknotty.worblehat.settings.database = lib.mkIf cfg.createLocalDatabase { + type = "postgresql"; + postgresql.host = "/run/postgresql"; + }; + + services.postgresql = lib.mkIf cfg.createLocalDatabase { + authentication = '' + local ${cfg.settings.database.postgresql.database} ${cfg.settings.database.postgresql.username} peer map=${cfg.settings.database.postgresql.username} + ''; + identMap = '' + ${cfg.settings.database.postgresql.username} drumknotty ${cfg.settings.database.postgresql.username} + ''; + ensureDatabases = [ cfg.settings.database.postgresql.database ]; + ensureUsers = [{ + name = cfg.settings.database.postgresql.username; + ensureDBOwnership = true; + ensureClauses.login = true; + }]; + }; + + systemd.services.worblehat-setup-database = lib.mkIf cfg.createLocalDatabase { + description = "Worblehat database setup"; + + wantedBy = [ "default.target" ]; + requiredBy = [ "drumknotty-screen-session.service" ]; + before = [ "drumknotty-screen-session.service" ]; + after = [ "postgresql.service" ]; + + unitConfig = { + ConditionPathExists = "!/var/lib/worblehat/.db-setup-done"; + }; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe cfg.package} --config /etc/worblehat/config.toml create-db"; + ExecStartPost = "${lib.getExe' pkgs.coreutils "touch"} /var/lib/worblehat/.db-setup-done"; + StateDirectory = "worblehat"; + + User = "drumknotty"; + Group = "drumknotty"; + }; + }; + }) + + (lib.mkIf cfg.deadline-daemon.enable { + systemd.timers.worblehat-deadline-daemon = lib.mkIf cfg.deadline-daemon.enable { + description = "Worblehat Deadline Daemon"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.deadline-daemon.onCalendar; + Persistent = true; + }; + }; + + systemd.services.worblehat-deadline-daemon = lib.mkIf cfg.deadline-daemon.enable { + description = "Worblehat Deadline Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = "oneshot"; + CPUSchedulingPolicy = "idle"; + IOSchedulingClass = "idle"; + + ExecStart = + let + worblehatArgs = lib.cli.toCommandLineShellGNU { } { + config = "/etc/worblehat/config.toml"; + }; + in + "${lib.getExe cfg.package} ${worblehatArgs} deadline-daemon"; + + User = "drumknotty"; + Group = "drumknotty"; + }; + }; + }) + ]; +}