1{ lib, ... }:
2{
3 name = "postgres-websockets";
4
5 meta = {
6 maintainers = with lib.maintainers; [ wolfgangwalther ];
7 };
8
9 nodes.machine =
10 {
11 config,
12 lib,
13 pkgs,
14 ...
15 }:
16 {
17 environment.systemPackages = [ pkgs.websocat ];
18
19 services.postgresql = {
20 enable = true;
21 initialScript = pkgs.writeText "init.sql" ''
22 CREATE ROLE "postgres-websockets" LOGIN NOINHERIT;
23 CREATE ROLE "postgres-websockets_with_password" LOGIN NOINHERIT PASSWORD 'password';
24 '';
25 };
26
27 services.postgres-websockets = {
28 enable = true;
29 jwtSecretFile = "/run/secrets/jwt.secret";
30 environment.PGWS_DB_URI.dbname = "postgres";
31 environment.PGWS_LISTEN_CHANNEL = "websockets-listener";
32 };
33
34 specialisation.withPassword.configuration = {
35 services.postgresql.enableTCPIP = true;
36 services.postgres-websockets = {
37 pgpassFile = "/run/secrets/.pgpass";
38 environment.PGWS_DB_URI.host = "localhost";
39 environment.PGWS_DB_URI.user = "postgres-websockets_with_password";
40 };
41 };
42 };
43
44 extraPythonPackages = p: [ p.pyjwt ];
45
46 testScript =
47 { nodes, ... }:
48 let
49 withPassword = "${nodes.machine.system.build.toplevel}/specialisation/withPassword";
50 in
51 ''
52 machine.execute("""
53 mkdir -p /run/secrets
54 echo reallyreallyreallyreallyverysafe > /run/secrets/jwt.secret
55 """)
56
57 import jwt
58 token = jwt.encode({ "mode": "rw" }, "reallyreallyreallyreallyverysafe")
59
60 def test():
61 machine.wait_for_unit("postgresql.service")
62 machine.wait_for_unit("postgres-websockets.service")
63
64 machine.succeed(f"echo 'hi there' | websocat --no-close 'ws://localhost:3000/test/{token}' > output &")
65 machine.sleep(1)
66 machine.succeed("grep 'hi there' output")
67
68 machine.succeed("""
69 sudo -u postgres psql -c "SELECT pg_notify('websockets-listener', json_build_object('channel', 'test', 'event', 'message', 'payload', 'Hello World')::text);" >/dev/null
70 """)
71 machine.sleep(1)
72 machine.succeed("grep 'Hello World' output")
73
74 with subtest("without password"):
75 test()
76
77 with subtest("with password"):
78 machine.execute("""
79 echo "*:*:*:*:password" > /run/secrets/.pgpass
80 """)
81 machine.succeed("${withPassword}/bin/switch-to-configuration test >&2")
82 test()
83 '';
84}