From 1f934dad304efab18eb2be404323ce9a3218902d Mon Sep 17 00:00:00 2001
From: MayNiklas <info@niklas-steffen.de>
Date: Thu, 23 Sep 2021 10:48:29 +0200
Subject: [PATCH] nixos/owncast: init owncast service

---
 nixos/modules/module-list.nix           |  1 +
 nixos/modules/services/misc/owncast.nix | 98 +++++++++++++++++++++++++
 nixos/tests/all-tests.nix               |  1 +
 nixos/tests/owncast.nix                 | 21 ++++++
 4 files changed, 121 insertions(+)
 create mode 100644 nixos/modules/services/misc/owncast.nix
 create mode 100644 nixos/tests/owncast.nix

diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 71a1118fd38e..6cfaadf3e208 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -552,6 +552,7 @@
   ./services/misc/octoprint.nix
   ./services/misc/ombi.nix
   ./services/misc/osrm.nix
+  ./services/misc/owncast.nix
   ./services/misc/packagekit.nix
   ./services/misc/paperless-ng.nix
   ./services/misc/parsoid.nix
diff --git a/nixos/modules/services/misc/owncast.nix b/nixos/modules/services/misc/owncast.nix
new file mode 100644
index 000000000000..0852335238fd
--- /dev/null
+++ b/nixos/modules/services/misc/owncast.nix
@@ -0,0 +1,98 @@
+{ lib, pkgs, config, ... }:
+with lib;
+let cfg = config.services.owncast;
+in {
+
+  options.services.owncast = {
+
+    enable = mkEnableOption "owncast";
+
+    dataDir = mkOption {
+      type = types.str;
+      default = "/var/lib/owncast";
+      description = ''
+        The directory where owncast stores its data files. If left as the default value this directory will automatically be created before the owncast server starts, otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership and permissions.
+      '';
+    };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Open the appropriate ports in the firewall for owncast.
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = "owncast";
+      description = "User account under which owncast runs.";
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "owncast";
+      description = "Group under which owncast runs.";
+    };
+
+    listen = mkOption {
+      type = types.str;
+      default = "127.0.0.1";
+      example = "0.0.0.0";
+      description = "The IP address to bind the owncast web server to.";
+    };
+
+    port = mkOption {
+      type = types.port;
+      default = 8080;
+      description = ''
+        TCP port where owncast web-gui listens.
+      '';
+    };
+
+    rtmp-port = mkOption {
+      type = types.port;
+      default = 1935;
+      description = ''
+        TCP port where owncast rtmp service listens.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.owncast = {
+      description = "A self-hosted live video and web chat server";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = mkMerge [
+        {
+          User = cfg.user;
+          Group = cfg.group;
+          WorkingDirectory = cfg.dataDir;
+          ExecStart = "${pkgs.owncast}/bin/owncast -webserverport ${toString cfg.port} -rtmpport ${toString cfg.rtmp-port} -webserverip ${cfg.listen}";
+          Restart = "on-failure";
+        }
+        (mkIf (cfg.dataDir == "/var/lib/owncast") {
+          StateDirectory = "owncast";
+        })
+      ];
+    };
+
+    users.users = mkIf (cfg.user == "owncast") {
+      owncast = {
+        isSystemUser = true;
+        group = cfg.group;
+        description = "owncast system user";
+      };
+    };
+
+    users.groups = mkIf (cfg.group == "owncast") { owncast = { }; };
+
+    networking.firewall =
+      mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.rtmp-port ] ++ optional (cfg.listen != "127.0.0.1") cfg.port; };
+
+  };
+  meta = { maintainers = with lib.maintainers; [ MayNiklas ]; };
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 6baa986b2bda..ce3598466ee6 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -326,6 +326,7 @@ in
   openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
   openstack-image-userdata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).userdata or {};
   opentabletdriver = handleTest ./opentabletdriver.nix {};
+  owncast = handleTest ./owncast.nix {};
   image-contents = handleTest ./image-contents.nix {};
   orangefs = handleTest ./orangefs.nix {};
   os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
diff --git a/nixos/tests/owncast.nix b/nixos/tests/owncast.nix
new file mode 100644
index 000000000000..e54d2cc5dd48
--- /dev/null
+++ b/nixos/tests/owncast.nix
@@ -0,0 +1,21 @@
+{ system ? builtins.currentSystem, config ? { }
+, pkgs ? import ../.. { inherit system config; } }:
+
+with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; };
+makeTest {
+  name = "owncast";
+  meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ MayNiklas ]; };
+
+  nodes = {
+    client = { ... }: {
+      environment.systemPackages = [ curl ];
+      services.owncast = { enable = true; };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    client.wait_for_unit("owncast.service")
+    client.succeed("curl localhost:8080/api/status")
+  '';
+}