1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8let
9 cfg = config.services.artalk;
10 settingsFormat = pkgs.formats.json { };
11in
12{
13
14 meta = {
15 maintainers = with lib.maintainers; [ moraxyc ];
16 };
17
18 options = {
19 services.artalk = {
20 enable = lib.mkEnableOption "artalk, a comment system";
21 configFile = lib.mkOption {
22 type = lib.types.str;
23 default = "/etc/artalk/config.yml";
24 description = "Artalk config file path. If it is not exist, Artalk will generate one.";
25 };
26 allowModify = lib.mkOption {
27 type = lib.types.bool;
28 default = true;
29 description = "allow Artalk store the settings to config file persistently";
30 };
31 workdir = lib.mkOption {
32 type = lib.types.str;
33 default = "/var/lib/artalk";
34 description = "Artalk working directory";
35 };
36 user = lib.mkOption {
37 type = lib.types.str;
38 default = "artalk";
39 description = "Artalk user name.";
40 };
41
42 group = lib.mkOption {
43 type = lib.types.str;
44 default = "artalk";
45 description = "Artalk group name.";
46 };
47
48 package = lib.mkPackageOption pkgs "artalk" { };
49 settings = lib.mkOption {
50 type = lib.types.submodule {
51 freeformType = settingsFormat.type;
52 options = {
53 host = lib.mkOption {
54 type = lib.types.str;
55 default = "0.0.0.0";
56 description = ''
57 Artalk server listen host
58 '';
59 };
60 port = lib.mkOption {
61 type = lib.types.port;
62 default = 23366;
63 description = ''
64 Artalk server listen port
65 '';
66 };
67 };
68 };
69 default = { };
70 description = ''
71 The artalk configuration.
72
73 If you set allowModify to true, Artalk will be able to store the settings in the config file persistently. This section's content will update in the config file after the service restarts.
74
75 Options containing secret data should be set to an attribute set
76 containing the attribute `_secret` - a string pointing to a file
77 containing the value the option should be set to.
78 '';
79 };
80 };
81 };
82
83 config = lib.mkIf cfg.enable {
84 users.users.artalk = lib.optionalAttrs (cfg.user == "artalk") {
85 description = "artalk user";
86 isSystemUser = true;
87 group = cfg.group;
88 };
89 users.groups.artalk = lib.optionalAttrs (cfg.group == "artalk") { };
90
91 environment.systemPackages = [ cfg.package ];
92
93 systemd.services.artalk = {
94 after = [ "network.target" ];
95 wantedBy = [ "multi-user.target" ];
96 preStart =
97 ''
98 umask 0077
99 ${utils.genJqSecretsReplacementSnippet cfg.settings "/run/artalk/new"}
100 ''
101 + (
102 if cfg.allowModify then
103 ''
104 [ -e "${cfg.configFile}" ] || ${lib.getExe cfg.package} gen config "${cfg.configFile}"
105 cat "${cfg.configFile}" | ${lib.getExe pkgs.yj} > "/run/artalk/old"
106 ${lib.getExe pkgs.jq} -s '.[0] * .[1]' "/run/artalk/old" "/run/artalk/new" > "/run/artalk/result"
107 cat "/run/artalk/result" | ${lib.getExe pkgs.yj} -r > "${cfg.configFile}"
108 rm /run/artalk/{old,new,result}
109 ''
110 else
111 ''
112 cat /run/artalk/new | ${lib.getExe pkgs.yj} -r > "${cfg.configFile}"
113 rm /run/artalk/new
114 ''
115 );
116 serviceConfig = {
117 User = cfg.user;
118 Group = cfg.group;
119 Type = "simple";
120 ExecStart = "${lib.getExe cfg.package} server --config ${cfg.configFile} --workdir ${cfg.workdir} --host ${cfg.settings.host} --port ${builtins.toString cfg.settings.port}";
121 Restart = "on-failure";
122 RestartSec = "5s";
123 ConfigurationDirectory = [ "artalk" ];
124 StateDirectory = [ "artalk" ];
125 RuntimeDirectory = [ "artalk" ];
126 AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
127 ProtectHome = "yes";
128 };
129 };
130 };
131}