1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.aria2;
7
8 homeDir = "/var/lib/aria2";
9
10 settingsDir = "${homeDir}";
11 sessionFile = "${homeDir}/aria2.session";
12 downloadDir = "${homeDir}/Downloads";
13
14 rangesToStringList = map (x: builtins.toString x.from +"-"+ builtins.toString x.to);
15
16 settingsFile = pkgs.writeText "aria2.conf"
17 ''
18 dir=${cfg.downloadDir}
19 listen-port=${concatStringsSep "," (rangesToStringList cfg.listenPortRange)}
20 rpc-listen-port=${toString cfg.rpcListenPort}
21 rpc-secret=${cfg.rpcSecret}
22 '';
23
24in
25{
26 options = {
27 services.aria2 = {
28 enable = mkOption {
29 type = types.bool;
30 default = false;
31 description = ''
32 Whether or not to enable the headless Aria2 daemon service.
33
34 Aria2 daemon can be controlled via the RPC interface using
35 one of many WebUI (http://localhost:6800/ by default).
36
37 Targets are downloaded to ${downloadDir} by default and are
38 accessible to users in the "aria2" group.
39 '';
40 };
41 openPorts = mkOption {
42 type = types.bool;
43 default = false;
44 description = ''
45 Open listen and RPC ports found in listenPortRange and rpcListenPort
46 options in the firewall.
47 '';
48 };
49 downloadDir = mkOption {
50 type = types.string;
51 default = "${downloadDir}";
52 description = ''
53 Directory to store downloaded files.
54 '';
55 };
56 listenPortRange = mkOption {
57 type = types.listOf types.attrs;
58 default = [ { from = 6881; to = 6999; } ];
59 description = ''
60 Set UDP listening port range used by DHT(IPv4, IPv6) and UDP tracker.
61 '';
62 };
63 rpcListenPort = mkOption {
64 type = types.int;
65 default = 6800;
66 description = "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535";
67 };
68 rpcSecret = mkOption {
69 type = types.string;
70 default = "aria2rpc";
71 description = ''
72 Set RPC secret authorization token.
73 Read https://aria2.github.io/manual/en/html/aria2c.html#rpc-auth to know how this option value is used.
74 '';
75 };
76 extraArguments = mkOption {
77 type = types.string;
78 example = "--rpc-listen-all --remote-time=true";
79 default = "";
80 description = ''
81 Additional arguments to be passed to Aria2.
82 '';
83 };
84 };
85 };
86
87 config = mkIf cfg.enable {
88
89 # Need to open ports for proper functioning
90 networking.firewall = mkIf cfg.openPorts {
91 allowedUDPPortRanges = config.services.aria2.listenPortRange;
92 allowedTCPPorts = [ config.services.aria2.rpcListenPort ];
93 };
94
95 users.extraUsers.aria2 = {
96 group = "aria2";
97 uid = config.ids.uids.aria2;
98 description = "aria2 user";
99 home = homeDir;
100 createHome = false;
101 };
102
103 users.extraGroups.aria2.gid = config.ids.gids.aria2;
104
105 systemd.services.aria2 = {
106 description = "aria2 Service";
107 after = [ "local-fs.target" "network.target" ];
108 wantedBy = [ "multi-user.target" ];
109 preStart = ''
110 mkdir -m 0770 -p "${homeDir}"
111 chown aria2:aria2 "${homeDir}"
112 if [[ ! -d "${config.services.aria2.downloadDir}" ]]
113 then
114 mkdir -m 0770 -p "${config.services.aria2.downloadDir}"
115 chown aria2:aria2 "${config.services.aria2.downloadDir}"
116 fi
117 if [[ ! -e "${sessionFile}" ]]
118 then
119 touch "${sessionFile}"
120 chown aria2:aria2 "${sessionFile}"
121 fi
122 cp -f "${settingsFile}" "${settingsDir}/aria2.conf"
123 '';
124
125 serviceConfig = {
126 Restart = "on-abort";
127 ExecStart = "${pkgs.aria2}/bin/aria2c --enable-rpc --conf-path=${settingsDir}/aria2.conf ${config.services.aria2.extraArguments} --save-session=${sessionFile}";
128 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
129 User = "aria2";
130 Group = "aria2";
131 PermissionsStartOnly = true;
132 };
133 };
134 };
135}