131 lines
4.0 KiB
Nix
131 lines
4.0 KiB
Nix
|
flake:
|
||
|
{
|
||
|
config,
|
||
|
lib,
|
||
|
pkgs,
|
||
|
...
|
||
|
}:
|
||
|
|
||
|
let
|
||
|
inherit (lib)
|
||
|
filterAttrs
|
||
|
foldl
|
||
|
imap1
|
||
|
mapAttrsToList
|
||
|
mkEnableOption
|
||
|
mkIf
|
||
|
mkMerge
|
||
|
mkOption
|
||
|
mkPackageOption
|
||
|
types
|
||
|
;
|
||
|
in
|
||
|
{
|
||
|
options = {
|
||
|
services.intake = {
|
||
|
package = mkPackageOption pkgs "intake" { };
|
||
|
|
||
|
extraPackages = mkOption {
|
||
|
type = types.listOf types.package;
|
||
|
default = [ ];
|
||
|
description = "Extra packages available to all enabled users and their intake services.";
|
||
|
};
|
||
|
|
||
|
users = mkOption {
|
||
|
description = "User intake service definitions.";
|
||
|
default = { };
|
||
|
type = types.attrsOf (
|
||
|
types.submodule {
|
||
|
options = {
|
||
|
enable = mkEnableOption "intake, a universal and extensible feed aggregator.";
|
||
|
|
||
|
dataDir = mkOption {
|
||
|
type = types.str;
|
||
|
default = "/home/$USER/.local/share/intake";
|
||
|
description = "The data directory for this user's intake service.";
|
||
|
};
|
||
|
|
||
|
listen.addr = mkOption {
|
||
|
type = types.str;
|
||
|
default = "127.0.0.1";
|
||
|
description = "The listen address for this user's intake service.";
|
||
|
};
|
||
|
|
||
|
listen.port = mkOption {
|
||
|
type = types.port;
|
||
|
default = 80;
|
||
|
description = "The listen port for this user's intake service.";
|
||
|
};
|
||
|
|
||
|
extraPackages = mkOption {
|
||
|
type = types.listOf types.package;
|
||
|
default = [ ];
|
||
|
description = "Extra packages available to this user and their intake service.";
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
config =
|
||
|
let
|
||
|
intakeCfg = config.services.intake;
|
||
|
enabledUsers = filterAttrs (userName: userCfg: userCfg.enable) intakeCfg.users;
|
||
|
enabledUserNames = mapAttrsToList (userName: userCfg: userName) enabledUsers;
|
||
|
userPackages = userName: [ intakeCfg.package ] ++ intakeCfg.extraPackages ++ intakeCfg.users.${userName}.extraPackages;
|
||
|
crontabWrapper = pkgs.writeShellScriptBin "crontab" ''
|
||
|
exec ${config.security.wrapperDir}/crontab "$@"
|
||
|
'';
|
||
|
in
|
||
|
{
|
||
|
# Apply the overlay so intake is included in pkgs.
|
||
|
nixpkgs.overlays = [ flake.overlays.default ];
|
||
|
|
||
|
# Give every intake user the shared packages and their user-specific packages.
|
||
|
users.users =
|
||
|
let
|
||
|
addPackagesToUser = userName: {
|
||
|
${userName}.packages = userPackages userName;
|
||
|
};
|
||
|
in
|
||
|
mkMerge (map addPackagesToUser enabledUserNames);
|
||
|
|
||
|
# Enable cron
|
||
|
services.cron.enable = true;
|
||
|
|
||
|
# Define a user service for each configured user
|
||
|
systemd.services =
|
||
|
let
|
||
|
runScript =
|
||
|
userName:
|
||
|
pkgs.writeShellScript "intake-run.sh" ''
|
||
|
mkdir -p $INTAKE_DATA_DIR
|
||
|
# Add the setuid wrapper directory so `crontab` is accessible
|
||
|
export PATH="${config.security.wrapperDir}:$PATH"
|
||
|
${intakeCfg.package}/bin/intake serve --addr ${enabledUsers.${userName}.listen.addr} --port ${toString enabledUsers.${userName}.listen.port}
|
||
|
'';
|
||
|
# systemd service definition for a single user, given `services.intake.users.userName` = `userCfg`
|
||
|
userServiceConfig = userName: userCfg: {
|
||
|
"intake-${userName}" = {
|
||
|
description = "Intake service for user ${userName}";
|
||
|
script = "${runScript userName}";
|
||
|
path = [ crontabWrapper ] ++ intakeCfg.extraPackages ++ userCfg.extraPackages;
|
||
|
environment = {
|
||
|
INTAKE_DATA_DIR = "/home/${userName}/.local/share/intake";
|
||
|
};
|
||
|
serviceConfig = {
|
||
|
User = userName;
|
||
|
Type = "simple";
|
||
|
};
|
||
|
wantedBy = [ "multi-user.target" ];
|
||
|
after = [ "network.target" ];
|
||
|
enable = userCfg.enable;
|
||
|
};
|
||
|
};
|
||
|
in
|
||
|
mkMerge (mapAttrsToList userServiceConfig enabledUsers);
|
||
|
};
|
||
|
}
|