From c20b128f24aebd0a43a3cbe66b128bcbd7f327d5 Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Wed, 12 Aug 2026 18:11:21 +0300 Subject: [PATCH] nix,localinfra: local dev setup for deliberi Signed-off-by: Anirudh Oppiliappan --- .air/deliberi.toml | 10 ++++ docker-compose.yml | 32 ++++++++++++ flake.nix | 12 +++++ localinfra/deliberi.Dockerfile | 34 +++++++++++++ nix/modules/deliberi.nix | 93 ++++++++++++++++++++++++++++++++++ nix/pkgs/deliberi.nix | 24 +++++++++ 6 files changed, 205 insertions(+) create mode 100644 .air/deliberi.toml create mode 100644 localinfra/deliberi.Dockerfile create mode 100644 nix/modules/deliberi.nix create mode 100644 nix/pkgs/deliberi.nix diff --git a/.air/deliberi.toml b/.air/deliberi.toml new file mode 100644 index 00000000..2564ad7e --- /dev/null +++ b/.air/deliberi.toml @@ -0,0 +1,10 @@ +root = "." +tmp_dir = "out" + +[build] +cmd = "go build -tags libsqlite3 -o out/deliberi.out cmd/deliberi/main.go" +bin = "out/deliberi.out" + +include_ext = ["go"] +exclude_dir = ["avatar", "camo", "sites", "indexes", "nix", "tmp"] +stop_on_error = true diff --git a/docker-compose.yml b/docker-compose.yml index ec36c721..a0ae2ce0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -442,6 +442,37 @@ services: condition: service_completed_successfully networks: [tngl] + deliberi: + build: + context: . + dockerfile: localinfra/deliberi.Dockerfile + restart: unless-stopped + environment: + DELIBERI_DEV: "true" + DELIBERI_HOSTNAME: deliberi.tngl.boltless.dev + DELIBERI_LISTEN_ADDR: 0.0.0.0:6565 + DELIBERI_DB_PATH: /var/lib/deliberi/deliberi.db + DELIBERI_PLC_URL: https://plc.tngl.boltless.dev + DELIBERI_JETSTREAM_ENDPOINT: wss://jetstream.tngl.boltless.dev/subscribe + DELIBERI_BOBBIN_API_URL: http://bobbin:8090 + DELIBERI_BASE_URL: https://tngl.boltless.dev + DELIBERI_PDS_HOST: https://pds.tngl.boltless.dev + volumes: + - deliberi-data:/var/lib/deliberi + - ./localinfra/certs/root.crt:/usr/local/share/ca-certificates/caddy.crt:ro + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:6565/xrpc/_health"] + interval: 2s + timeout: 2s + retries: 30 + start_period: 5s + ports: + - "6565:6565" + depends_on: + pds: + condition: service_healthy + networks: [tngl] + pdsls: build: context: . @@ -662,6 +693,7 @@ volumes: go-cache: go-mod-cache: appview-data: + deliberi-data: hydrant-data: bobbin-cargo: bobbin-target: diff --git a/flake.nix b/flake.nix index 31808078..32510684 100644 --- a/flake.nix +++ b/flake.nix @@ -192,6 +192,7 @@ gitmirror = self.callPackage ./nix/pkgs/gitmirror.nix { src = self.rustSrc; }; + deliberi = self.callPackage ./nix/pkgs/deliberi.nix {}; bobbin = self.callPackage ./nix/pkgs/bobbin.nix {}; zoekt-webserver = self.callPackage ./nix/pkgs/zoekt-webserver.nix {}; zoekt-tngl-indexserver = self.callPackage ./nix/pkgs/zoekt-tngl-indexserver.nix {}; @@ -221,6 +222,7 @@ tap knotmirror gitmirror + deliberi bobbin zoekt-webserver zoekt-tngl-indexserver @@ -264,6 +266,7 @@ tap knotmirror gitmirror + deliberi bobbin zoekt-webserver zoekt-tngl-indexserver @@ -686,6 +689,15 @@ services.tangled.appview.package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.appview; }; + nixosModules.deliberi = { + lib, + pkgs, + ... + }: { + imports = [./nix/modules/deliberi.nix]; + + services.tangled.deliberi.package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.deliberi; + }; nixosModules.knotmirror = { lib, pkgs, diff --git a/localinfra/deliberi.Dockerfile b/localinfra/deliberi.Dockerfile new file mode 100644 index 00000000..8485aca2 --- /dev/null +++ b/localinfra/deliberi.Dockerfile @@ -0,0 +1,34 @@ +# Development only. Not for production use. + +FROM golang:1.25-alpine AS builder + +RUN apk add --no-cache git build-base sqlite-dev + +ENV CGO_ENABLED=1 +ENV GOCACHE=/go/cache +ENV GOMODCACHE=/go/mod + +WORKDIR /src + +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/cache \ + --mount=type=cache,target=/go/mod \ + go mod download + +COPY . . +RUN --mount=type=cache,target=/go/cache \ + --mount=type=cache,target=/go/mod \ + go build -tags libsqlite3 -o /out/deliberi ./cmd/deliberi + +FROM alpine:3.24 + +RUN apk add --no-cache ca-certificates sqlite-libs tini + +COPY --from=builder /out/deliberi /usr/local/bin/deliberi +RUN chmod 0755 /usr/local/bin/deliberi + +VOLUME /var/lib/deliberi +EXPOSE 6565 + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["sh", "-c", "if [ -f /usr/local/share/ca-certificates/caddy.crt ]; then update-ca-certificates; fi && exec /usr/local/bin/deliberi serve"] diff --git a/nix/modules/deliberi.nix b/nix/modules/deliberi.nix new file mode 100644 index 00000000..97168526 --- /dev/null +++ b/nix/modules/deliberi.nix @@ -0,0 +1,93 @@ +{ + config, + pkgs, + lib, + ... +}: let + cfg = config.services.tangled.deliberi; +in + with lib; { + options.services.tangled.deliberi = { + enable = mkEnableOption "tangled deliberi notification + email service"; + + package = mkOption { + type = types.package; + description = "deliberi package to run"; + }; + + listenAddr = mkOption { + type = types.str; + default = "0.0.0.0:6565"; + description = "address the xrpc + health server binds to"; + }; + + hostname = mkOption { + type = types.str; + description = "public hostname; derives deliberi's did:web identity"; + }; + + dbPath = mkOption { + type = types.str; + default = "/var/lib/deliberi/deliberi.db"; + description = "path to deliberi's sqlite database"; + }; + + plcUrl = mkOption { + type = types.str; + default = "https://plc.directory"; + }; + + jetstreamEndpoint = mkOption { + type = types.str; + default = "wss://jetstream1.us-east.bsky.network/subscribe"; + }; + + bobbinApiUrl = mkOption { + type = types.str; + default = "https://api.tangled.org"; + description = "base url hosting subscription.listRecipients"; + }; + + baseUrl = mkOption { + type = types.str; + default = "https://tangled.org"; + description = "public frontend url used for links in digest emails"; + }; + + dev = mkOption { + type = types.bool; + default = false; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "file with secret env vars (DELIBERI_RESEND_API_KEY, DELIBERI_PDS_ADMIN_SECRET, ...)"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.deliberi = { + description = "tangled deliberi notification + email service"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + serviceConfig = { + LogsDirectory = "deliberi"; + StateDirectory = "deliberi"; + EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; + Environment = [ + "DELIBERI_LISTEN_ADDR=${cfg.listenAddr}" + "DELIBERI_HOSTNAME=${cfg.hostname}" + "DELIBERI_DB_PATH=${cfg.dbPath}" + "DELIBERI_PLC_URL=${cfg.plcUrl}" + "DELIBERI_JETSTREAM_ENDPOINT=${cfg.jetstreamEndpoint}" + "DELIBERI_BOBBIN_API_URL=${cfg.bobbinApiUrl}" + "DELIBERI_BASE_URL=${cfg.baseUrl}" + "DELIBERI_DEV=${boolToString cfg.dev}" + ]; + ExecStart = "${getExe cfg.package} serve"; + Restart = "always"; + }; + }; + }; + } diff --git a/nix/pkgs/deliberi.nix b/nix/pkgs/deliberi.nix new file mode 100644 index 00000000..18311a47 --- /dev/null +++ b/nix/pkgs/deliberi.nix @@ -0,0 +1,24 @@ +{ + buildGoApplication, + modules, + sqlite-lib, + src, +}: +buildGoApplication { + pname = "deliberi"; + version = "0.1.0"; + inherit src modules; + + doCheck = false; + + subPackages = ["cmd/deliberi"]; + tags = ["libsqlite3"]; + + env.CGO_CFLAGS = "-I ${sqlite-lib}/include "; + env.CGO_LDFLAGS = "-L ${sqlite-lib}/lib"; + CGO_ENABLED = 1; + + meta = { + mainProgram = "deliberi"; + }; +} -- 2.51.2