{ config, lib, pkgs, ... }: with lib; let nncpCfgFile = "/run/nncp.hjson"; programCfg = config.programs.nncp; callerCfg = config.services.nncp.caller; daemonCfg = config.services.nncp.daemon; settingsFormat = pkgs.formats.json { }; jsonCfgFile = settingsFormat.generate "nncp.json" programCfg.settings; pkg = programCfg.package; in { options = { programs.nncp = { enable = mkEnableOption "NNCP (Node to Node copy) utilities"; package = mkOption { type = types.package; default = pkgs.nncp; defaultText = literalExpression "pkgs.nncp"; description = "The NNCP package to use system-wide."; }; secrets = mkOption { type = with types; listOf str; example = [ "/run/keys/nncp.hjson" ]; description = '' A list of paths to NNCP configuration files that should not be in the Nix store. These files are layered on top of the values at . ''; }; settings = mkOption { type = settingsFormat.type; description = '' NNCP configuration, see . At runtime these settings will be overlayed by the contents of into the file ${nncpCfgFile}. Node keypairs go in secrets, do not specify them in settings as they will be leaked into /nix/store! ''; default = { }; }; }; services.nncp = { caller = { enable = mkEnableOption '' croned NNCP TCP daemon caller. The daemon will take configuration from ''; extraArgs = mkOption { type = with types; listOf str; description = "Extra command-line arguments to pass to caller."; default = [ ]; example = [ "-autotoss" ]; }; }; daemon = { enable = mkEnableOption '' NNCP TCP synronization daemon. The daemon will take configuration from ''; socketActivation = { enable = mkEnableOption '' Whether to run nncp-daemon persistently or socket-activated. ''; listenStreams = mkOption { type = with types; listOf str; description = '' TCP sockets to bind to. See . ''; default = [ "5400" ]; }; }; extraArgs = mkOption { type = with types; listOf str; description = "Extra command-line arguments to pass to daemon."; default = [ ]; example = [ "-autotoss" ]; }; }; }; }; config = mkIf (programCfg.enable or callerCfg.enable or daemonCfg.enable) { assertions = [{ assertion = with builtins; let callerCongfigured = let neigh = config.programs.nncp.settings.neigh or { }; in lib.lists.any (x: hasAttr "calls" x && x.calls != [ ]) (attrValues neigh); in !callerCfg.enable || callerCongfigured; message = "NNCP caller enabled but call configuration is missing"; }]; programs.nncp.settings = { spool = mkDefault "/var/spool/nncp"; log = mkDefault "/var/spool/nncp/log"; }; environment = mkIf programCfg.enable { systemPackages = [ pkg ]; etc."nncp.hjson".source = nncpCfgFile; }; systemd.tmpfiles.rules = [ "d ${programCfg.settings.spool} 0770 root uucp" "f ${programCfg.settings.log} 0770 root uucp" ]; system.activationScripts.nncp = '' nncpCfgDir=$(mktemp --directory nncp.XXXXXXXXXX) for f in ${jsonCfgFile} ${toString config.programs.nncp.secrets}; do tmpdir=$(mktemp --directory nncp.XXXXXXXXXX) ${pkg}/bin/nncp-cfgdir -cfg $f -dump $tmpdir ${pkgs.findutils}/bin/find $tmpdir -size 1c -delete cp -a $tmpdir/* $nncpCfgDir/ rm -rf $tmpdir done ${pkg}/bin/nncp-cfgdir -load $nncpCfgDir > ${nncpCfgFile} rm -rf $nncpCfgDir chgrp uucp ${nncpCfgFile} ''; systemd.services."nncp-caller" = { inherit (callerCfg) enable; description = "Croned NNCP TCP daemon caller."; documentation = [ "http://www.nncpgo.org/nncp_002dcaller.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = '' ${pkg}/bin/nncp-caller -noprogress -cfg "${nncpCfgFile}" ${ lib.strings.escapeShellArgs callerCfg.extraArgs }''; Group = "uucp"; UMask = "0002"; }; }; systemd.services."nncp-daemon" = mkIf daemonCfg.enable { enable = !daemonCfg.socketActivation.enable; description = "NNCP TCP syncronization daemon."; documentation = [ "http://www.nncpgo.org/nncp_002ddaemon.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = '' ${pkg}/bin/nncp-daemon -noprogress -cfg "${nncpCfgFile}" ${ lib.strings.escapeShellArgs daemonCfg.extraArgs }''; Restart = "on-failure"; Group = "uucp"; UMask = "0002"; }; }; systemd.services."nncp-daemon@" = mkIf daemonCfg.socketActivation.enable { description = "NNCP TCP syncronization daemon."; documentation = [ "http://www.nncpgo.org/nncp_002ddaemon.html" ]; after = [ "network.target" ]; serviceConfig = { ExecStart = '' ${pkg}/bin/nncp-daemon -noprogress -ucspi -cfg "${nncpCfgFile}" ${ lib.strings.escapeShellArgs daemonCfg.extraArgs }''; Group = "uucp"; UMask = "0002"; StandardInput = "socket"; StandardOutput = "inherit"; StandardError = "journal"; }; }; systemd.sockets.nncp-daemon = mkIf daemonCfg.socketActivation.enable { inherit (daemonCfg.socketActivation) listenStreams; description = "socket for NNCP TCP syncronization."; conflicts = [ "nncp-daemon.service" ]; wantedBy = [ "sockets.target" ]; socketConfig.Accept = true; }; }; }