Skip to content

Commit

Permalink
Merge master into staging-next
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Sep 3, 2024
2 parents 1ca2d1d + c78e599 commit b7b46e4
Show file tree
Hide file tree
Showing 59 changed files with 1,317 additions and 893 deletions.
2 changes: 1 addition & 1 deletion .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Anderson Torres <[email protected]>
Atemu <[email protected]> <[email protected]>
Daniel Løvbrøtte Olsen <[email protected]> <[email protected]>
Fabian Affolter <[email protected]> <[email protected]>
goatastronaut0212 <goatastronaut0212@proton.me> <goatastronaut0212@outlook.com>
goatastronaut0212 <goatastronaut0212@outlook.com> <goatastronaut0212@proton.me>
Janne Heß <[email protected]> <[email protected]>
Jörg Thalheim <[email protected]> <[email protected]>
Martin Weinelt <[email protected]> <[email protected]>
Expand Down
6 changes: 6 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17035,6 +17035,12 @@
githubId = 1332289;
name = "Quentin Machu";
};
quincepie = {
email = "[email protected]";
github = "Quince-Pie";
githubId = 127546159;
name = "QuincePie";
};
quinn-dougherty = {
email = "[email protected]";
github = "quinn-dougherty";
Expand Down
3 changes: 3 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@
- The `antennas` package and the `services.antennas` module have been
removed as they only work with `tvheadend` (see above).

- The `services.syncplay` module now exposes all currently available command-line arguments for `syncplay-server` as options, as well as a `useACMEHost` option for easy TLS setup.
The systemd service now uses `DynamicUser`/`StateDirectory` and the `user` and `group` options have been deprecated.

## Other Notable Changes {#sec-release-24.11-notable-changes}

<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@
./services/web-apps/pretix.nix
./services/web-apps/prosody-filer.nix
./services/web-apps/rimgo.nix
./services/web-apps/rutorrent.nix
./services/web-apps/screego.nix
./services/web-apps/sftpgo.nix
./services/web-apps/suwayomi-server.nix
Expand Down
232 changes: 207 additions & 25 deletions nixos/modules/services/networking/syncplay.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,41 @@ let

cmdArgs =
[ "--port" cfg.port ]
++ optionals (cfg.isolateRooms) [ "--isolate-rooms" ]
++ optionals (!cfg.ready) [ "--disable-ready" ]
++ optionals (!cfg.chat) [ "--disable-chat" ]
++ optionals (cfg.salt != null) [ "--salt" cfg.salt ]
++ optionals (cfg.motdFile != null) [ "--motd-file" cfg.motdFile ]
++ optionals (cfg.roomsDBFile != null) [ "--rooms-db-file" cfg.roomsDBFile ]
++ optionals (cfg.permanentRoomsFile != null) [ "--permanent-rooms-file" cfg.permanentRoomsFile ]
++ [ "--max-chat-message-length" cfg.maxChatMessageLength ]
++ [ "--max-username-length" cfg.maxUsernameLength ]
++ optionals (cfg.statsDBFile != null) [ "--stats-db-file" cfg.statsDBFile ]
++ optionals (cfg.certDir != null) [ "--tls" cfg.certDir ]
++ optionals cfg.ipv4Only [ "--ipv4-only" ]
++ optionals cfg.ipv6Only [ "--ipv6-only" ]
++ optionals (cfg.interfaceIpv4 != "") [ "--interface-ipv4" cfg.interfaceIpv4 ]
++ optionals (cfg.interfaceIpv6 != "") [ "--interface-ipv6" cfg.interfaceIpv6 ]
++ cfg.extraArgs;

useACMEHostDir = optionalString (cfg.useACMEHost != null) config.security.acme.certs.${cfg.useACMEHost}.directory;
in
{
imports = [
(mkRemovedOptionModule [ "services" "syncplay" "user" ]
"The syncplay service now uses DynamicUser, override the systemd unit settings if you need the old functionality.")
(mkRemovedOptionModule [ "services" "syncplay" "group" ]
"The syncplay service now uses DynamicUser, override the systemd unit settings if you need the old functionality.")
];

options = {
services.syncplay = {
enable = mkOption {
type = types.bool;
default = false;
description = "If enabled, start the Syncplay server.";
description = ''
If enabled, start the Syncplay server.
'';
};

port = mkOption {
Expand All @@ -29,6 +52,39 @@ in
'';
};

passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to the file that contains the server password. If
`null`, the server doesn't require a password.
'';
};

isolateRooms = mkOption {
type = types.bool;
default = false;
description = ''
Enable room isolation.
'';
};

ready = mkOption {
type = types.bool;
default = true;
description = ''
Check readiness of users.
'';
};

chat = mkOption {
type = types.bool;
default = true;
description = ''
Chat with users in the same room.
'';
};

salt = mkOption {
type = types.nullOr types.str;
default = null;
Expand All @@ -37,7 +93,7 @@ in
instance to still work when the server is restarted. The salt will be
readable in the nix store and the processlist. If this is not
intended use `saltFile` instead. Mutually exclusive with
<option>services.syncplay.saltFile</option>.
{option}`services.syncplay.saltFile`.
'';
};

Expand All @@ -49,7 +105,83 @@ in
operator passwords generated by this server instance to still work
when the server is restarted. `null`, the server doesn't load the
salt from a file. Mutually exclusive with
<option>services.syncplay.salt</option>.
{option}`services.syncplay.salt`.
'';
};

motd = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Text to display when users join. The motd will be readable in the nix store
and the processlist. If this is not intended use `motdFile` instead.
Will be overriden by {option}`services.syncplay.motdFile`.
'';
};

motdFile = mkOption {
type = types.nullOr types.str;
default = if cfg.motd != null then (builtins.toFile "motd" cfg.motd) else null;
defaultText = literalExpression ''if services.syncplay.motd != null then (builtins.toFile "motd" services.syncplay.motd) else null'';
description = ''
Path to text to display when users join.
Will override {option}`services.syncplay.motd`.
'';
};

roomsDBFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "rooms.db";
description = ''
Path to SQLite database file to store room states.
Relative to the working directory provided by systemd.
'';
};

permanentRooms = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
List of rooms that will be listed even if the room is empty.
Will be overriden by {option}`services.syncplay.permanentRoomsFile`.
'';
};

permanentRoomsFile = mkOption {
type = types.nullOr types.str;
default = if cfg.permanentRooms != [ ] then (builtins.toFile "perm" (builtins.concatStringsSep "\n" cfg.permanentRooms)) else null;
defaultText = literalExpression ''if services.syncplay.permanentRooms != [ ] then (builtins.toFile "perm" (builtins.concatStringsSep "\n" services.syncplay.permanentRooms)) else null'';
description = ''
File with list of rooms that will be listed even if the room is empty,
newline delimited.
Will override {option}`services.syncplay.permanentRooms`.
'';
};

maxChatMessageLength = mkOption {
type = types.ints.unsigned;
default = 150;
description = ''
Maximum number of characters in a chat message.
'';
};

maxUsernameLength = mkOption {
type = types.ints.unsigned;
default = 16;
description = ''
Maximum number of characters in a username.
'';
};

statsDBFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "stats.db";
description = ''
Path to SQLite database file to store stats.
Relative to the working directory provided by systemd.
'';
};

Expand All @@ -62,36 +194,63 @@ in
'';
};

extraArgs = mkOption {
type = types.listOf types.str;
default = [ ];
useACMEHost = mkOption {
type = types.nullOr types.str;
default = null;
example = "syncplay.example.com";
description = ''
Additional arguments to be passed to the service.
If set, use NixOS-generated ACME certificate with the specified name for TLS.
Note that it requires {option}`security.acme` to be setup, e.g., credentials provided if using DNS-01 validation.
'';
};

ipv4Only = mkOption {
type = types.bool;
default = false;
description = ''
Listen only on IPv4 when strting the server.
'';
};

user = mkOption {
ipv6Only = mkOption {
type = types.bool;
default = false;
description = ''
Listen only on IPv6 when strting the server.
'';
};

interfaceIpv4 = mkOption {
type = types.str;
default = "nobody";
default = "";
description = ''
User to use when running Syncplay.
The IP address to bind to for IPv4. Leaving it empty defaults to using all.
'';
};

group = mkOption {
interfaceIpv6 = mkOption {
type = types.str;
default = "nogroup";
default = "";
description = ''
Group to use when running Syncplay.
The IP address to bind to for IPv6. Leaving it empty defaults to using all.
'';
};

passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
extraArgs = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Path to the file that contains the server password. If
`null`, the server doesn't require a password.
Additional arguments to be passed to the service.
'';
};

package = mkOption {
type = types.package;
default = pkgs.syncplay-nogui;
defaultText = literalExpression "pkgs.syncplay-nogui";
description = ''
Package to use for syncplay.
'';
};
};
Expand All @@ -103,28 +262,51 @@ in
assertion = cfg.salt == null || cfg.saltFile == null;
message = "services.syncplay.salt and services.syncplay.saltFile are mutually exclusive.";
}
{
assertion = cfg.certDir == null || cfg.useACMEHost == null;
message = "services.syncplay.certDir and services.syncplay.useACMEHost are mutually exclusive.";
}
{
assertion = !cfg.ipv4Only || !cfg.ipv6Only;
message = "services.syncplay.ipv4Only and services.syncplay.ipv6Only are mutually exclusive.";
}
];

warnings = optional (cfg.interfaceIpv4 != "" && cfg.ipv6Only) "You have specified services.syncplay.interfaceIpv4 but IPv4 is disabled by services.syncplay.ipv6Only."
++ optional (cfg.interfaceIpv6 != "" && cfg.ipv4Only) "You have specified services.syncplay.interfaceIpv6 but IPv6 is disabled by services.syncplay.ipv4Only.";

security.acme.certs = mkIf (cfg.useACMEHost != null) {
"${cfg.useACMEHost}".reloadServices = [ "syncplay.service" ];
};

networking.firewall.allowedTCPPorts = [ cfg.port ];
systemd.services.syncplay = {
description = "Syncplay Service";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];

serviceConfig = {
User = cfg.user;
Group = cfg.group;
LoadCredential = lib.optional (cfg.passwordFile != null) "password:${cfg.passwordFile}"
++ lib.optional (cfg.saltFile != null) "salt:${cfg.saltFile}";
DynamicUser = true;
StateDirectory = "syncplay";
WorkingDirectory = "%S/syncplay";
LoadCredential = optional (cfg.passwordFile != null) "password:${cfg.passwordFile}"
++ optional (cfg.saltFile != null) "salt:${cfg.saltFile}"
++ optionals (cfg.useACMEHost != null) [
"cert.pem:${useACMEHostDir}/cert.pem"
"privkey.pem:${useACMEHostDir}/key.pem"
"chain.pem:${useACMEHostDir}/chain.pem"
];
};

script = ''
${lib.optionalString (cfg.passwordFile != null) ''
${optionalString (cfg.passwordFile != null) ''
export SYNCPLAY_PASSWORD=$(cat "''${CREDENTIALS_DIRECTORY}/password")
''}
${lib.optionalString (cfg.saltFile != null) ''
${optionalString (cfg.saltFile != null) ''
export SYNCPLAY_SALT=$(cat "''${CREDENTIALS_DIRECTORY}/salt")
''}
exec ${pkgs.syncplay-nogui}/bin/syncplay-server ${escapeShellArgs cmdArgs}
exec ${cfg.package}/bin/syncplay-server ${escapeShellArgs cmdArgs} ${optionalString (cfg.useACMEHost != null) "--tls $CREDENTIALS_DIRECTORY"}
'';
};
};
Expand Down
Loading

0 comments on commit b7b46e4

Please sign in to comment.