nixpkgs/nixos/modules/services/networking/btsync.nix
Eelco Dolstra 29027fd1e1 Rewrite ‘with pkgs.lib’ -> ‘with lib’
Using pkgs.lib on the spine of module evaluation is problematic
because the pkgs argument depends on the result of module
evaluation. To prevent an infinite recursion, pkgs and some of the
modules are evaluated twice, which is inefficient. Using ‘with lib’
prevents this problem.
2014-04-14 16:26:48 +02:00

280 lines
8 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.btsync;
listenAddr = cfg.httpListenAddr + ":" + (toString cfg.httpListenPort);
boolStr = x: if x then "true" else "false";
optionalEmptyStr = b: v: optionalString (b != "") v;
webUIConfig = optionalString cfg.enableWebUI
''
"webui":
{
${optionalEmptyStr cfg.httpLogin "\"login\": \"${cfg.httpLogin}\","}
${optionalEmptyStr cfg.httpPass "\"password\": \"${cfg.httpPass}\","}
${optionalEmptyStr cfg.apiKey "\"api_key\": \"${cfg.apiKey}\","}
"listen": "${listenAddr}"
}
'';
knownHosts = e:
optionalString (e ? "knownHosts")
(concatStringsSep "," (map (v: "\"${v}\"") e."knownHosts"));
sharedFoldersRecord =
concatStringsSep "," (map (entry:
let helper = attr: v:
if (entry ? attr) then boolStr entry.attr else boolStr v;
in
''
{
"secret": "${entry.secret}",
"dir": "${entry.directory}",
"use_relay_server": ${helper "useRelayServer" true},
"use_tracker": ${helper "useTracker" true},
"use_dht": ${helper "useDHT" false},
"search_lan": ${helper "searchLAN" true},
"use_sync_trash": ${helper "useSyncTrash" true},
"known_hosts": [${knownHosts entry}]
}
'') cfg.sharedFolders);
sharedFoldersConfig = optionalString (cfg.sharedFolders != [])
''
"shared_folders":
[
${sharedFoldersRecord}
]
'';
configFile = pkgs.writeText "btsync.config"
''
{
"device_name": "${cfg.deviceName}",
"storage_path": "/var/lib/btsync",
"listening_port": ${toString cfg.listeningPort},
"use_gui": false,
"check_for_updates": ${boolStr cfg.checkForUpdates},
"use_upnp": ${boolStr cfg.useUpnp},
"download_limit": ${toString cfg.downloadLimit},
"upload_limit": ${toString cfg.uploadLimit},
"lan_encrypt_data": ${boolStr cfg.encryptLAN},
${webUIConfig}
${sharedFoldersConfig}
}
'';
in
{
options = {
services.btsync = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
If enabled, start the Bittorrent Sync daemon. Once enabled,
you can interact with the service through the Web UI, or
configure it in your NixOS configuration. Enabling the
<literal>btsync</literal> service also installs a
multi-instance systemd unit which can be used to start
user-specific copies of the daemon. Once installed, you can
use <literal>systemctl start btsync@user</literal> to start
the daemon only for user <literal>user</literal>, using the
configuration file located at
<literal>$HOME/.config/btsync.conf</literal>
'';
};
deviceName = mkOption {
type = types.str;
example = "Voltron";
description = ''
Name of the Bittorrent Sync device.
'';
};
listeningPort = mkOption {
type = types.int;
default = 0;
example = 44444;
description = ''
Listening port. Defaults to 0 which randomizes the port.
'';
};
checkForUpdates = mkOption {
type = types.bool;
default = true;
description = ''
Determines whether to check for updates and alert the user
about them in the UI.
'';
};
useUpnp = mkOption {
type = types.bool;
default = true;
description = ''
Use Universal Plug-n-Play (UPnP)
'';
};
downloadLimit = mkOption {
type = types.int;
default = 0;
example = 1024;
description = ''
Download speed limit. 0 is unlimited (default).
'';
};
uploadLimit = mkOption {
type = types.int;
default = 0;
example = 1024;
description = ''
Upload speed limit. 0 is unlimited (default).
'';
};
httpListenAddr = mkOption {
type = types.str;
default = "0.0.0.0";
example = "1.2.3.4";
description = ''
HTTP address to bind to.
'';
};
httpListenPort = mkOption {
type = types.int;
default = 9000;
description = ''
HTTP port to bind on.
'';
};
httpLogin = mkOption {
type = types.str;
example = "allyourbase";
description = ''
HTTP web login username.
'';
};
httpPass = mkOption {
type = types.str;
example = "arebelongtous";
description = ''
HTTP web login password.
'';
};
encryptLAN = mkOption {
type = types.bool;
default = true;
description = "Encrypt LAN data.";
};
enableWebUI = mkOption {
type = types.bool;
default = false;
description = ''
Enable Web UI for administration. Bound to the specified
<literal>httpListenAddress</literal> and
<literal>httpListenPort</literal>.
'';
};
apiKey = mkOption {
type = types.str;
default = "";
description = "API key, which enables the developer API.";
};
sharedFolders = mkOption {
default = [];
example =
[ { secret = "AHMYFPCQAHBM7LQPFXQ7WV6Y42IGUXJ5Y";
directory = "/home/user/sync_test";
useRelayServer = true;
useTracker = true;
useDHT = false;
searchLAN = true;
useSyncTrash = true;
knownHosts =
[ "192.168.1.2:4444"
"192.168.1.3:4444"
];
}
];
description = ''
Shared folder list. If enabled, web UI must be
disabled. Secrets can be generated using <literal>btsync
--generate-secret</literal>. Note that this secret will be
put inside the Nix store, so it is realistically not very
secret.
'';
};
};
};
config = mkIf cfg.enable {
assertions =
[ { assertion = cfg.deviceName != "";
message = "Device name cannot be empty.";
}
{ assertion = cfg.enableWebUI -> cfg.sharedFolders == [];
message = "If using shared folders, the web UI cannot be enabled.";
}
{ assertion = cfg.apiKey != "" -> cfg.enableWebUI;
message = "If you're using an API key, you must enable the web server.";
}
# TODO FIXME: the README says not specifying the login/pass means it
# should disable authentication, but apparently it doesn't?
{ assertion = cfg.enableWebUI -> cfg.httpLogin != "" && cfg.httpPass != "";
message = "If using the web UI, you must configure a login/password.";
}
# TODO FIXME: assert the existence of sharedFolder directories?
];
users.extraUsers.btsync = {
description = "Bittorrent Sync Service user";
home = "/var/lib/btsync";
createHome = true;
uid = config.ids.uids.btsync;
};
systemd.services.btsync = with pkgs; {
description = "Bittorrent Sync Service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
Restart = "on-abort";
User = "btsync";
ExecStart =
"${bittorrentSync}/bin/btsync --nodaemon --config ${configFile}";
};
};
systemd.services."btsync@" = with pkgs; {
description = "Bittorrent Sync Service for %i";
after = [ "network.target" ];
serviceConfig = {
Restart = "on-abort";
User = "%i";
ExecStart =
"${bittorrentSync}/bin/btsync --nodaemon --config %h/.config/btsync.conf";
};
};
environment.systemPackages = [ pkgs.bittorrentSync ];
};
}