-
-
Notifications
You must be signed in to change notification settings - Fork 13.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nixos/rtorrent: add rtorrent tmux service (user and system) #30850
Changes from all commits
beb325b
362c2d1
e3a6212
837c930
eec11ce
4a13a17
d649599
3f8ab2b
05802c1
ca2b6f3
c2f6eb6
d410579
fccf076
07ec7d0
33a0cc4
acd98d7
80a4569
86d5553
61a74f6
19a5c41
11e4b5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
{ config, pkgs, lib, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
cfg = config.services.rtorrent; | ||
in | ||
{ | ||
options.services.rtorrent = { | ||
enable = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Whether to enable a system service for rtorrent (via tmux). | ||
Use `sudo -u rtorrent tmux attach` to manage rtorrent, | ||
and `Ctrl-B d` to detach. | ||
|
||
If true, services.rtorrent.install is considered true, whatever its value. | ||
''; | ||
}; | ||
install = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Whether to install a user service for rtorrent (via tmux). | ||
The service must be manually started for each user with | ||
``. | ||
|
||
The service must be manually started for each user with | ||
`systemctl --user start rtorrent`. To start rtorrent on boot as a | ||
system service, instead set services.rtorrent.enable = true. | ||
|
||
Once the service has started, use `tmux -L rtorrent attach` to manage rtorrent. | ||
''; | ||
}; | ||
|
||
dataDir = mkOption { | ||
type = types.str; | ||
default = "/var/lib/rtorrent"; | ||
description = '' | ||
If enabled as a system service, the directory where rtorrent stores its data files. | ||
If installed as a user service, this value is ignored. | ||
''; | ||
}; | ||
|
||
configFile = mkOption { | ||
type = types.str; | ||
default = "/var/lib/rtorrent/rtorrent.rc"; | ||
description = '' | ||
If enabled as a system service, the location of rtorrent's config file. | ||
If installed as a user service, this value is ignored. | ||
''; | ||
}; | ||
|
||
userDataDir = mkOption { | ||
type = types.str; | ||
default = "rtorrent"; | ||
description = '' | ||
If installed as a user service, the directory where rtorrent stores its data files relative to $HOME. | ||
If enabled as a system service, this value is ignored. | ||
''; | ||
}; | ||
|
||
userConfigFile = mkOption { | ||
type = types.str; | ||
default = ".rtorrent.rc"; | ||
description = '' | ||
If installed as a user service, the location of rtorrent's config file relative to $HOME. | ||
If enabled as a system service, this value is ignored. | ||
''; | ||
}; | ||
|
||
user = mkOption { | ||
type = types.str; | ||
default = "rtorrent"; | ||
description = '' | ||
User account under which rtorrent runs, if enabled as a system service. | ||
Ignored if installed as a user service. | ||
''; | ||
}; | ||
|
||
group = mkOption { | ||
type = types.str; | ||
default = "rtorrent"; | ||
description = '' | ||
Group under which rtorrent runs, if enabled as a system service. | ||
Ignored if installed as a user service. | ||
''; | ||
}; | ||
|
||
package = mkOption { | ||
type = types.package; | ||
default = pkgs.rtorrent; | ||
defaultText = "pkgs.rtorrent"; | ||
description = "The rtorrent package to use."; | ||
}; | ||
}; | ||
|
||
config = mkIf (cfg.enable || cfg.install) { | ||
users.groups = mkIf (cfg.enable && cfg.group == "rtorrent") { | ||
rtorrent.gid = config.ids.gids.rtorrent; | ||
}; | ||
users.extraUsers = mkIf (cfg.enable && cfg.user == "rtorrent") { | ||
rtorrent = { | ||
uid = config.ids.uids.rtorrent; | ||
group = cfg.group; | ||
shell = pkgs.bashInteractive; | ||
home = cfg.dataDir; | ||
createHome = true; | ||
}; | ||
}; | ||
systemd.services.rtorrent = mkIf cfg.enable { | ||
description = "rTorrent system service (via tmux)"; | ||
after = [ "network.target" ]; | ||
# Default rtorrent.rc (in preStart) uses bash, which needs to be on the $PATH | ||
path = [ cfg.package pkgs.tmux pkgs.bash pkgs.procps ]; | ||
preStart = '' | ||
test -f "${cfg.configFile}" || { | ||
echo "creating default rtorrent config file at ${cfg.configFile}." | ||
cat > "${cfg.configFile}" << EOF | ||
'' + replaceStrings [ "/home/USERNAME/rtorrent" ] [ cfg.dataDir ] (readFile ./rtorrent.rc) + "\nEOF\n}"; | ||
wantedBy = [ "multi-user.target" ]; | ||
serviceConfig = { | ||
Type = "forking"; | ||
KillMode = "none"; | ||
User = cfg.user; | ||
Group = cfg.group; | ||
ExecStart = "${pkgs.tmux}/bin/tmux new-session -c ${cfg.dataDir} -s rtorrent -n rtorrent -d rtorrent -n -o import=${cfg.configFile}"; | ||
ExecStop = "${pkgs.bash}/bin/bash -c \"tmux send-keys -t rtorrent C-q && while pidof rtorrent > /dev/null; do sleep 0.5; done\""; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks very hacky. Not sure if there is a better way to solve this together with tmux but it doesn't feel right to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah it's a little reminiscent of creaky init scripts. https://wiki.archlinux.org/index.php/RTorrent#Systemd_services_using_tmux_or_screen |
||
WorkingDirectory = "${cfg.dataDir}"; | ||
Restart = "on-failure"; | ||
}; | ||
}; | ||
systemd.user.services.rtorrent = mkIf (!cfg.enable) { | ||
description = "rTorrent user service (via tmux)"; | ||
after = [ "network.target" ]; | ||
# Default rtorrent.rc (in preStart) uses bash, which needs to be on the $PATH | ||
path = [ cfg.package pkgs.tmux pkgs.bash pkgs.procps ]; | ||
preStart = '' | ||
test -d $HOME/${cfg.userDataDir} || { | ||
echo "Creating rtorrent data directory at $HOME/${cfg.userDataDir}." | ||
mkdir $HOME/${cfg.userDataDir} | ||
} | ||
if test -e $HOME/${cfg.userDataDir}/.session/rtorrent.lock && test -z `pidof rtorrent`; then | ||
rm -f $HOME/${cfg.userDataDir}/.session/rtorrent.lock | ||
fi | ||
|
||
test -f $HOME/${cfg.userConfigFile} || { | ||
echo "creating default rtorrent config file at $HOME/${cfg.userConfigFile}." | ||
cat > $HOME/${cfg.userConfigFile} << EOF | ||
'' + replaceStrings [ "/home/USERNAME/rtorrent" ] [ "$HOME/${cfg.userDataDir}" ] (readFile ./rtorrent.rc) + "\nEOF\n}"; | ||
environment = { HOME = "%h"; }; | ||
serviceConfig = { | ||
Type = "forking"; | ||
ExecStart = "${pkgs.tmux}/bin/tmux -L rtorrent new-session -s rt -n rtorrent -d rtorrent -n -o import=%h/${cfg.userConfigFile}"; | ||
ExecStop = "${pkgs.bash}/bin/bash -c \"tmux -L rtorrent send-keys -t rt:rtorrent.0 C-q; while pidof rtorrent > /dev/null; do echo stopping rtorrent...; sleep 1; done\""; | ||
Restart = "on-failure"; | ||
}; | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
############################################################################# | ||
# A minimal rTorrent configuration that provides the basic features | ||
# you want to have in addition to the built-in defaults. | ||
# | ||
# See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template | ||
# for an up-to-date version. | ||
############################################################################# | ||
|
||
# Instance layout (base paths) | ||
method.insert = cfg.basedir, private|const|string, (cat,"/home/USERNAME/rtorrent/") | ||
method.insert = cfg.watch, private|const|string, (cat,(cfg.basedir),"watch/") | ||
method.insert = cfg.logs, private|const|string, (cat,(cfg.basedir),"log/") | ||
method.insert = cfg.logfile, private|const|string, (cat,(cfg.logs),"rtorrent-",(system.time),".log") | ||
|
||
# Create instance directories | ||
execute.throw = bash, -c, (cat,\ | ||
"builtin cd \"", (cfg.basedir), "\" ",\ | ||
"&& mkdir -p .session download log watch/{load,start}") | ||
|
||
# Listening port for incoming peer traffic (fixed; you can also randomize it) | ||
network.port_range.set = 50000-50000 | ||
network.port_random.set = no | ||
|
||
# Tracker-less torrent and UDP tracker support | ||
# (conservative settings for 'private' trackers, change for 'public') | ||
dht.mode.set = disable | ||
protocol.pex.set = no | ||
trackers.use_udp.set = no | ||
|
||
# Peer settings | ||
throttle.max_uploads.set = 100 | ||
throttle.max_uploads.global.set = 250 | ||
|
||
throttle.min_peers.normal.set = 20 | ||
throttle.max_peers.normal.set = 60 | ||
throttle.min_peers.seed.set = 30 | ||
throttle.max_peers.seed.set = 80 | ||
trackers.numwant.set = 80 | ||
|
||
protocol.encryption.set = allow_incoming,try_outgoing,enable_retry | ||
|
||
# Limits for file handle resources, this is optimized for | ||
# an `ulimit` of 1024 (a common default). You MUST leave | ||
# a ceiling of handles reserved for rTorrent's internal needs! | ||
network.http.max_open.set = 50 | ||
network.max_open_files.set = 600 | ||
network.max_open_sockets.set = 300 | ||
|
||
# Memory resource usage (increase if you have a large number of items loaded, | ||
# and/or the available resources to spend) | ||
pieces.memory.max.set = 1800M | ||
network.xmlrpc.size_limit.set = 4M | ||
|
||
# Basic operational settings (no need to change these) | ||
session.path.set = (cat, (cfg.basedir), ".session/") | ||
directory.default.set = (cat, (cfg.basedir), "download/") | ||
log.execute = (cat, (cfg.logs), "execute.log") | ||
##log.xmlrpc = (cat, (cfg.logs), "xmlrpc.log") | ||
execute.nothrow = bash, -c, (cat, "echo >",\ | ||
(session.path), "rtorrent.pid", " ", (system.pid)) | ||
|
||
# Other operational settings (check & adapt) | ||
encoding.add = utf8 | ||
system.umask.set = 0027 | ||
system.cwd.set = (directory.default) | ||
network.http.dns_cache_timeout.set = 25 | ||
##network.http.capath.set = "/etc/ssl/certs" | ||
##network.http.ssl_verify_peer.set = 0 | ||
##network.http.ssl_verify_host.set = 0 | ||
##pieces.hash.on_completion.set = no | ||
##keys.layout.set = qwerty | ||
|
||
##view.sort_current = seeding, greater=d.ratio= | ||
schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M)) | ||
|
||
# Some additional values and commands | ||
method.insert = system.startup_time, value|const, (system.time) | ||
method.insert = d.data_path, simple,\ | ||
"if=(d.is_multi_file),\ | ||
(cat, (d.directory), /),\ | ||
(cat, (d.directory), /, (d.name))" | ||
method.insert = d.session_file, simple, "cat=(session.path), (d.hash), .torrent" | ||
|
||
# Watch directories (add more as you like, but use unique schedule names) | ||
schedule2 = watch_start, 10, 10, ((load.start, (cat, (cfg.watch), "start/*.torrent"))) | ||
schedule2 = watch_load, 11, 10, ((load.normal, (cat, (cfg.watch), "load/*.torrent"))) | ||
|
||
# Logging: | ||
# Levels = critical error warn notice info debug | ||
# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_* | ||
print = (cat, "Logging to ", (cfg.logfile)) | ||
log.open_file = "log", (cfg.logfile) | ||
log.add_output = "info", "log" | ||
##log.add_output = "tracker_debug", "log" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate text.