{ config, lib, pkgs, ... }: with import <stockholm/lib>; #genid let cfg = config.krebs.airdcpp; out = { options.krebs.airdcpp = api; config = lib.mkIf cfg.enable imp; }; api = with types;{ enable = mkEnableOption "airdcpp"; package = mkOption { type = package; default = pkgs.airdcpp-webclient; }; user = mkOption { description = '' user which will run airdcpp. if kept default a new user will be created ''; type = str; default = "airdcpp"; }; extraGroups = mkOption { description = ''extra groups for the user (only for default user)''; type = listOf str; default = []; example = [ "nginx" ]; }; stateDir = mkOption { description = '' directory for storing state (pid,config) ''; type = str; default = "/var/lib/airdcpp"; }; hubs = mkOption { type = attrsOf (submodule ( { config, ... }: { options = { Nick = mkOption { description = '' Nick Name for hub ''; type = str; default = cfg.dcpp.Nick; }; Password = mkOption { description = '' Password to be used WARNING: will be stored in plain text in /nix/store ''; type = str; default = ""; apply = lib.removeSuffix "\n"; }; Server = mkOption { description = '' URL to the hub (must be provided) ''; type = str; }; AutoConnect = mkOption { description = '' automatically connect to the hub ''; type = bool; default = false; }; }; })); description = "hubs which should be configured via Favorites.xml, Options are only used if no initial Favorites.xml file is provided and none exists"; default = {}; }; initialFavoritesConfigFile = mkOption { description = '' path inital Favorites.xml configuration if none exists ''; type = nullOr path; default = null; }; dcpp = { # entries in DCPlusPlus.xml Nick = mkOption { description = '' Nick Name for connection ''; type = str; default = "kevin"; }; InPort = mkOption { description = "Input Port"; type = int; default = 16849; }; UDPPort = mkOption { description = "UDP open Port"; type = int; default = 16849; }; TLSPort = mkOption { description = "TLS open Port"; type = int; default = 16869; }; DownloadSpeed = mkOption { description = "Total Download Speed in Mbps/s"; type = str; default = "100"; }; UploadSpeed = mkOption { description = "Total Upload Speed in Mbp/s"; type = str; default = "100"; }; DownloadDirectory = mkOption { description = "Directory, where new files will be saved into"; type = str; default = "${cfg.stateDir}/Download"; }; shares = mkOption { default = {}; type = attrsOf (submodule ( { config, ... }: { options = { path = mkOption { description = "path to the share"; type = str; }; incoming = mkOption { description = "incoming"; type = bool; default = false; }; }; })); }; initialConfigFile = mkOption { description = '' path inital DCPlusPlus.xml configuration if none exists ''; type = nullOr path; default = null; }; }; web = { port = mkOption { description = ''web-ui port NOTE: once the initial config had been written to the state directory it will not be replaced ''; type = int; default = 5600; }; initialConfigFile = mkOption { description = '' path inital WebServer.xml configuration if none exists ''; type = nullOr path; default = null; }; # TODO: tlsPort users = mkOption { type = attrsOf (submodule ( { config, ... }: { options = { password = mkOption { description = "password of user"; type = str; apply = lib.removeSuffix "\n"; }; permissions = mkOption { description = "user permissions"; type = str; default = "admin"; }; }; })); }; }; }; imp = let genUsers = users: concatMapStringsSep "\n" (user: ''<WebUser Username="${user.name}" Password="${user.password}" LastLogin="0" Permissions="${user.permissions}"/>'' ) (mapAttrsToList (name: val: val // { inherit name; }) users); webConfigFile = if (cfg.web.initialConfigFile == null) then builtins.trace "warning: airdcpp passwords are stored in plain text" pkgs.writeText "initial-config" '' <?xml version="1.0" encoding="utf-8" standalone="yes"?> <WebServer> <Config> <Server Port="${toString cfg.web.port}"/> <TLSServer Port="0" Certificate="" CertificateKey=""/> </Config> <WebUsers>${genUsers cfg.web.users} </WebUsers> </WebServer> '' else cfg.web.initialConfigFile; genHubs = hubs: concatMapStringsSep "\n" (hub: ''<Hub Name="${hub.name}" Connect="${ if hub.AutoConnect then "1" else "0" }" Description="" Password="${hub.Password}" Server="${hub.Server}" ChatUserSplit="0" UserListState="1" HubFrameOrder="" HubFrameWidths="" HubFrameVisible="" Group="" Bottom="0" Top="0" Right="0" Left="0" Nick="${hub.Nick}"/>'' ) (mapAttrsToList (name: val: val // { inherit name; }) hubs); favoritesConfigFile = if (cfg.initialFavoritesConfigFile == null) then builtins.trace "warning: airdcpp hub passwords are stored in plain text" pkgs.writeText "initial-config" '' <?xml version="1.0" encoding="utf-8" standalone="yes"?> <Favorites> <Hubs> ${genHubs cfg.hubs} </Hubs> </Favorites> '' else cfg.initialFavoritesConfigFile; genShares = shares: concatMapStringsSep "\n" (share: ''<Directory Virtual="${share.name}" Incoming="${ if share.incoming then "1" else "0" }" LastRefreshTime="0">${share.path}</Directory>'' ) (mapAttrsToList (name: val: val // { inherit name; }) shares); dcppConfigFile = if (cfg.dcpp.initialConfigFile == null) then pkgs.writeText "initial-config" '' <?xml version="1.0" encoding="utf-8" standalone="yes"?> <DCPlusPlus> <Settings> <Nick type="string">${cfg.dcpp.Nick}</Nick> <InPort type="int">${toString cfg.dcpp.InPort}</InPort> <UDPPort type="int">${toString cfg.dcpp.UDPPort}</UDPPort> <TLSPort type="int">${toString cfg.dcpp.TLSPort}</TLSPort> <DownloadDirectory type="string">${cfg.dcpp.DownloadDirectory}</DownloadDirectory> <AutoDetectIncomingConnection type="int">0</AutoDetectIncomingConnection> <NoIpOverride type="int">1</NoIpOverride> <WizardRunNew type="int">0</WizardRunNew> <IPUpdate type="int">0</IPUpdate> <AlwaysCCPM type="int">1</AlwaysCCPM> <DownloadSpeed type="string">${cfg.dcpp.DownloadSpeed}</DownloadSpeed> <UploadSpeed type="string">${cfg.dcpp.UploadSpeed}</UploadSpeed> </Settings> <Share Token="0" Name="Default"> ${genShares cfg.dcpp.shares} <NoShare/> </Share> <ChatFilterItems/> </DCPlusPlus> '' else cfg.dcpp.initialConfigFile; in { systemd.services.airdcpp = { description = "airdcpp webui"; after = [ "network.target" "local-fs.target" ]; wantedBy = [ "multi-user.target" ]; restartIfChanged = true; serviceConfig = { Type = "simple"; ExecStartPre = pkgs.writeDash "prepare-env" '' d=${cfg.stateDir}/WebServer.xml test -e $d || install -m700 -o${cfg.user} ${webConfigFile} $d d=${cfg.stateDir}/DCPlusPlus.xml test -e $d || install -m700 -o${cfg.user} ${dcppConfigFile} $d d=${cfg.stateDir}/Favorites.xml test -e $d || install -m700 -o${cfg.user} ${favoritesConfigFile} $d ''; PermissionsStartOnly = true; ExecStart = "${cfg.package}/bin/airdcppd -c=${cfg.stateDir} -p=${cfg.stateDir}/airdcpp.pid"; PrivateTmp = true; WorkingDirectory = cfg.stateDir; User = "${cfg.user}"; }; }; users = lib.mkIf (cfg.user == "airdcpp") { users.airdcpp = { uid = genid "airdcpp"; home = cfg.stateDir; createHome = true; isSystemUser = true; group = "airdcpp"; inherit (cfg) extraGroups; }; groups.airdcpp.gid = genid "airdcpp"; }; }; in out