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