1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.honk;
9
10 honk-initdb-script =
11 cfg:
12 pkgs.writeShellApplication {
13 name = "honk-initdb-script";
14
15 runtimeInputs = with pkgs; [ coreutils ];
16
17 text = ''
18 PW=$(cat "$CREDENTIALS_DIRECTORY/honk_passwordFile")
19
20 echo -e "${cfg.username}\n''$PW\n${cfg.host}:${toString cfg.port}\n${cfg.servername}" | ${lib.getExe cfg.package} -datadir "$STATE_DIRECTORY" init
21 '';
22 };
23in
24{
25 options = {
26 services.honk = {
27 enable = lib.mkEnableOption "the Honk server";
28 package = lib.mkPackageOption pkgs "honk" { };
29
30 host = lib.mkOption {
31 default = "127.0.0.1";
32 description = ''
33 The host name or IP address the server should listen to.
34 '';
35 type = lib.types.str;
36 };
37
38 port = lib.mkOption {
39 default = 8080;
40 description = ''
41 The port the server should listen to.
42 '';
43 type = lib.types.port;
44 };
45
46 username = lib.mkOption {
47 description = ''
48 The admin account username.
49 '';
50 type = lib.types.str;
51 };
52
53 passwordFile = lib.mkOption {
54 description = ''
55 Password for admin account.
56 NOTE: Should be string not a store path, to prevent the password from being world readable
57 '';
58 type = lib.types.path;
59 };
60
61 servername = lib.mkOption {
62 description = ''
63 The server name.
64 '';
65 type = lib.types.str;
66 };
67
68 extraJS = lib.mkOption {
69 default = null;
70 description = ''
71 An extra JavaScript file to be loaded by the client.
72 '';
73 type = lib.types.nullOr lib.types.path;
74 };
75
76 extraCSS = lib.mkOption {
77 default = null;
78 description = ''
79 An extra CSS file to be loaded by the client.
80 '';
81 type = lib.types.nullOr lib.types.path;
82 };
83 };
84 };
85
86 config = lib.mkIf cfg.enable {
87 assertions = [
88 {
89 assertion = cfg.username or "" != "";
90 message = ''
91 You have to define a username for Honk (`services.honk.username`).
92 '';
93 }
94 {
95 assertion = cfg.servername or "" != "";
96 message = ''
97 You have to define a servername for Honk (`services.honk.servername`).
98 '';
99 }
100 ];
101
102 systemd.services.honk-initdb = {
103 description = "Honk server database setup";
104 requiredBy = [ "honk.service" ];
105 before = [ "honk.service" ];
106
107 serviceConfig = {
108 LoadCredential = [
109 "honk_passwordFile:${cfg.passwordFile}"
110 ];
111 Type = "oneshot";
112 StateDirectory = "honk";
113 DynamicUser = true;
114 RemainAfterExit = true;
115 ExecStart = lib.getExe (honk-initdb-script cfg);
116 PrivateTmp = true;
117 };
118
119 unitConfig = {
120 ConditionPathExists = [
121 # Skip this service if the database already exists
122 "!%S/honk/honk.db"
123 ];
124 };
125 };
126
127 systemd.services.honk = {
128 description = "Honk server";
129 wantedBy = [ "multi-user.target" ];
130 after = [ "network.target" ];
131 bindsTo = [ "honk-initdb.service" ];
132 preStart = ''
133 mkdir -p $STATE_DIRECTORY/views
134 ${lib.optionalString (cfg.extraJS != null) "ln -fs ${cfg.extraJS} $STATE_DIRECTORY/views/local.js"}
135 ${lib.optionalString (
136 cfg.extraCSS != null
137 ) "ln -fs ${cfg.extraCSS} $STATE_DIRECTORY/views/local.css"}
138 ${lib.getExe cfg.package} -datadir $STATE_DIRECTORY -viewdir ${cfg.package}/share/honk backup $STATE_DIRECTORY/backup
139 ${lib.getExe cfg.package} -datadir $STATE_DIRECTORY -viewdir ${cfg.package}/share/honk upgrade
140 ${lib.getExe cfg.package} -datadir $STATE_DIRECTORY -viewdir ${cfg.package}/share/honk cleanup
141 '';
142 serviceConfig = {
143 ExecStart = ''
144 ${lib.getExe cfg.package} -datadir $STATE_DIRECTORY -viewdir ${cfg.package}/share/honk
145 '';
146 StateDirectory = "honk";
147 DynamicUser = true;
148 PrivateTmp = "yes";
149 Restart = "on-failure";
150 };
151 };
152 };
153
154 meta = {
155 maintainers = with lib.maintainers; [ drupol ];
156 doc = ./honk.md;
157 };
158}