python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / torrent / rtorrent.nix
blob935c11e3eb0051f52e378c730aa0cc40a7560983
1 { config, options, pkgs, lib, ... }:
3 with lib;
5 let
7   cfg = config.services.rtorrent;
8   opt = options.services.rtorrent;
10 in {
11   options.services.rtorrent = {
12     enable = mkEnableOption (lib.mdDoc "rtorrent");
14     dataDir = mkOption {
15       type = types.str;
16       default = "/var/lib/rtorrent";
17       description = lib.mdDoc ''
18         The directory where rtorrent stores its data files.
19       '';
20     };
22     downloadDir = mkOption {
23       type = types.str;
24       default = "${cfg.dataDir}/download";
25       defaultText = literalExpression ''"''${config.${opt.dataDir}}/download"'';
26       description = lib.mdDoc ''
27         Where to put downloaded files.
28       '';
29     };
31     user = mkOption {
32       type = types.str;
33       default = "rtorrent";
34       description = lib.mdDoc ''
35         User account under which rtorrent runs.
36       '';
37     };
39     group = mkOption {
40       type = types.str;
41       default = "rtorrent";
42       description = lib.mdDoc ''
43         Group under which rtorrent runs.
44       '';
45     };
47     package = mkOption {
48       type = types.package;
49       default = pkgs.rtorrent;
50       defaultText = literalExpression "pkgs.rtorrent";
51       description = lib.mdDoc ''
52         The rtorrent package to use.
53       '';
54     };
56     port = mkOption {
57       type = types.port;
58       default = 50000;
59       description = lib.mdDoc ''
60         The rtorrent port.
61       '';
62     };
64     openFirewall = mkOption {
65       type = types.bool;
66       default = false;
67       description = lib.mdDoc ''
68         Whether to open the firewall for the port in {option}`services.rtorrent.port`.
69       '';
70     };
72     rpcSocket = mkOption {
73       type = types.str;
74       readOnly = true;
75       default = "/run/rtorrent/rpc.sock";
76       description = lib.mdDoc ''
77         RPC socket path.
78       '';
79     };
81     configText = mkOption {
82       type = types.lines;
83       default = "";
84       description = lib.mdDoc ''
85         The content of {file}`rtorrent.rc`. The [modernized configuration template](https://rtorrent-docs.readthedocs.io/en/latest/cookbook.html#modernized-configuration-template) with the values specified in this module will be prepended using mkBefore. You can use mkForce to overwrite the config completly.
86       '';
87     };
88   };
90   config = mkIf cfg.enable {
92     users.groups = mkIf (cfg.group == "rtorrent") {
93       rtorrent = {};
94     };
96     users.users = mkIf (cfg.user == "rtorrent") {
97       rtorrent = {
98         group = cfg.group;
99         shell = pkgs.bashInteractive;
100         home = cfg.dataDir;
101         description = "rtorrent Daemon user";
102         isSystemUser = true;
103       };
104     };
106     networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.port ];
108     services.rtorrent.configText = mkBefore ''
109       # Instance layout (base paths)
110       method.insert = cfg.basedir, private|const|string, (cat,"${cfg.dataDir}/")
111       method.insert = cfg.watch,   private|const|string, (cat,(cfg.basedir),"watch/")
112       method.insert = cfg.logs,    private|const|string, (cat,(cfg.basedir),"log/")
113       method.insert = cfg.logfile, private|const|string, (cat,(cfg.logs),(system.time),".log")
114       method.insert = cfg.rpcsock, private|const|string, (cat,"${cfg.rpcSocket}")
116       # Create instance directories
117       execute.throw = sh, -c, (cat, "mkdir -p ", (cfg.basedir), "/session ", (cfg.watch), " ", (cfg.logs))
119       # Listening port for incoming peer traffic (fixed; you can also randomize it)
120       network.port_range.set = ${toString cfg.port}-${toString cfg.port}
121       network.port_random.set = no
123       # Tracker-less torrent and UDP tracker support
124       # (conservative settings for 'private' trackers, change for 'public')
125       dht.mode.set = disable
126       protocol.pex.set = no
127       trackers.use_udp.set = no
129       # Peer settings
130       throttle.max_uploads.set = 100
131       throttle.max_uploads.global.set = 250
133       throttle.min_peers.normal.set = 20
134       throttle.max_peers.normal.set = 60
135       throttle.min_peers.seed.set = 30
136       throttle.max_peers.seed.set = 80
137       trackers.numwant.set = 80
139       protocol.encryption.set = allow_incoming,try_outgoing,enable_retry
141       # Limits for file handle resources, this is optimized for
142       # an `ulimit` of 1024 (a common default). You MUST leave
143       # a ceiling of handles reserved for rTorrent's internal needs!
144       network.http.max_open.set = 50
145       network.max_open_files.set = 600
146       network.max_open_sockets.set = 3000
148       # Memory resource usage (increase if you have a large number of items loaded,
149       # and/or the available resources to spend)
150       pieces.memory.max.set = 1800M
151       network.xmlrpc.size_limit.set = 4M
153       # Basic operational settings (no need to change these)
154       session.path.set = (cat, (cfg.basedir), "session/")
155       directory.default.set = "${cfg.downloadDir}"
156       log.execute = (cat, (cfg.logs), "execute.log")
157       ##log.xmlrpc = (cat, (cfg.logs), "xmlrpc.log")
158       execute.nothrow = sh, -c, (cat, "echo >", (session.path), "rtorrent.pid", " ", (system.pid))
160       # Other operational settings (check & adapt)
161       encoding.add = utf8
162       system.umask.set = 0027
163       system.cwd.set = (cfg.basedir)
164       network.http.dns_cache_timeout.set = 25
165       schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M))
167       # Watch directories (add more as you like, but use unique schedule names)
168       #schedule2 = watch_start, 10, 10, ((load.start, (cat, (cfg.watch), "start/*.torrent")))
169       #schedule2 = watch_load, 11, 10, ((load.normal, (cat, (cfg.watch), "load/*.torrent")))
171       # Logging:
172       #   Levels = critical error warn notice info debug
173       #   Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
174       print = (cat, "Logging to ", (cfg.logfile))
175       log.open_file = "log", (cfg.logfile)
176       log.add_output = "info", "log"
177       ##log.add_output = "tracker_debug", "log"
179       # XMLRPC
180       scgi_local = (cfg.rpcsock)
181       schedule = scgi_group,0,0,"execute.nothrow=chown,\":rtorrent\",(cfg.rpcsock)"
182       schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",(cfg.rpcsock)"
183     '';
185     systemd = {
186       services = {
187         rtorrent = let
188           rtorrentConfigFile = pkgs.writeText "rtorrent.rc" cfg.configText;
189         in {
190           description = "rTorrent system service";
191           after = [ "network.target" ];
192           path = [ cfg.package pkgs.bash ];
193           wantedBy = [ "multi-user.target" ];
194           serviceConfig = {
195             User = cfg.user;
196             Group = cfg.group;
197             Type = "simple";
198             Restart = "on-failure";
199             WorkingDirectory = cfg.dataDir;
200             ExecStartPre=''${pkgs.bash}/bin/bash -c "if test -e ${cfg.dataDir}/session/rtorrent.lock && test -z $(${pkgs.procps}/bin/pidof rtorrent); then rm -f ${cfg.dataDir}/session/rtorrent.lock; fi"'';
201             ExecStart="${cfg.package}/bin/rtorrent -n -o system.daemon.set=true -o import=${rtorrentConfigFile}";
202             RuntimeDirectory = "rtorrent";
203             RuntimeDirectoryMode = 755;
204           };
205         };
206       };
208       tmpfiles.rules = [ "d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} -" ];
209     };
210   };