1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.syncplay;
7
8 cmdArgs =
9 [ "--port" cfg.port ]
10 ++ optionals (cfg.salt != null) [ "--salt" cfg.salt ]
11 ++ optionals (cfg.certDir != null) [ "--tls" cfg.certDir ]
12 ++ cfg.extraArgs;
13
14in
15{
16 options = {
17 services.syncplay = {
18 enable = mkOption {
19 type = types.bool;
20 default = false;
21 description = "If enabled, start the Syncplay server.";
22 };
23
24 port = mkOption {
25 type = types.port;
26 default = 8999;
27 description = ''
28 TCP port to bind to.
29 '';
30 };
31
32 salt = mkOption {
33 type = types.nullOr types.str;
34 default = null;
35 description = ''
36 Salt to allow room operator passwords generated by this server
37 instance to still work when the server is restarted. The salt will be
38 readable in the nix store and the processlist. If this is not
39 intended use `saltFile` instead. Mutually exclusive with
40 <option>services.syncplay.saltFile</option>.
41 '';
42 };
43
44 saltFile = mkOption {
45 type = types.nullOr types.path;
46 default = null;
47 description = ''
48 Path to the file that contains the server salt. This allows room
49 operator passwords generated by this server instance to still work
50 when the server is restarted. `null`, the server doesn't load the
51 salt from a file. Mutually exclusive with
52 <option>services.syncplay.salt</option>.
53 '';
54 };
55
56 certDir = mkOption {
57 type = types.nullOr types.path;
58 default = null;
59 description = ''
60 TLS certificates directory to use for encryption. See
61 <https://github.com/Syncplay/syncplay/wiki/TLS-support>.
62 '';
63 };
64
65 extraArgs = mkOption {
66 type = types.listOf types.str;
67 default = [ ];
68 description = ''
69 Additional arguments to be passed to the service.
70 '';
71 };
72
73 user = mkOption {
74 type = types.str;
75 default = "nobody";
76 description = ''
77 User to use when running Syncplay.
78 '';
79 };
80
81 group = mkOption {
82 type = types.str;
83 default = "nogroup";
84 description = ''
85 Group to use when running Syncplay.
86 '';
87 };
88
89 passwordFile = mkOption {
90 type = types.nullOr types.path;
91 default = null;
92 description = ''
93 Path to the file that contains the server password. If
94 `null`, the server doesn't require a password.
95 '';
96 };
97 };
98 };
99
100 config = mkIf cfg.enable {
101 assertions = [
102 {
103 assertion = cfg.salt == null || cfg.saltFile == null;
104 message = "services.syncplay.salt and services.syncplay.saltFile are mutually exclusive.";
105 }
106 ];
107 systemd.services.syncplay = {
108 description = "Syncplay Service";
109 wantedBy = [ "multi-user.target" ];
110 wants = [ "network-online.target" ];
111 after = [ "network-online.target" ];
112
113 serviceConfig = {
114 User = cfg.user;
115 Group = cfg.group;
116 LoadCredential = lib.optional (cfg.passwordFile != null) "password:${cfg.passwordFile}"
117 ++ lib.optional (cfg.saltFile != null) "salt:${cfg.saltFile}";
118 };
119
120 script = ''
121 ${lib.optionalString (cfg.passwordFile != null) ''
122 export SYNCPLAY_PASSWORD=$(cat "''${CREDENTIALS_DIRECTORY}/password")
123 ''}
124 ${lib.optionalString (cfg.saltFile != null) ''
125 export SYNCPLAY_SALT=$(cat "''${CREDENTIALS_DIRECTORY}/salt")
126 ''}
127 exec ${pkgs.syncplay-nogui}/bin/syncplay-server ${escapeShellArgs cmdArgs}
128 '';
129 };
130 };
131}