atagen

malice

public
Star0
Watch0
8c81366a752f49d6dae455bee8b0d7ecfab3e73d
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
flake.nixNix350 lines11.6 KB
1
{
2
  description = "Malice: a hosted Matrix client backed by macltok";
3
4
  inputs = {
5
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6
    fenix = {
7
      url = "github:nix-community/fenix";
8
      inputs.nixpkgs.follows = "nixpkgs";
9
    };
10
  };
11
12
  outputs =
13
    {
14
      self,
15
      nixpkgs,
16
      fenix,
17
    }:
18
    let
19
      systems = [
20
        "x86_64-linux"
21
        "aarch64-linux"
22
      ];
23
      forAllSystems = nixpkgs.lib.genAttrs systems;
24
      cleanSrc =
25
        root:
26
        nixpkgs.lib.cleanSourceWith {
27
          src = root;
28
          filter =
29
            path: type:
30
            nixpkgs.lib.cleanSourceFilter path type
31
            && !(
32
              type == "directory"
33
              && builtins.elem (baseNameOf path) [
34
                "target"
35
                "node_modules"
36
                "dist"
37
                "dist-device"
38
              ]
39
            );
40
        };
41
      workerLock = builtins.fromTOML (builtins.readFile ./crates/malice-worker/Cargo.lock);
42
      lockedVersion = name: (nixpkgs.lib.findFirst (p: p.name == name) null workerLock.package).version;
43
      # wasm-bindgen-test-runner refuses a module built by any other wasm-bindgen version
44
      wasmBindgenCli =
45
        pkgs:
46
        pkgs.buildWasmBindgenCli rec {
47
          src = pkgs.fetchCrate {
48
            pname = "wasm-bindgen-cli";
49
            version = lockedVersion "wasm-bindgen";
50
            hash = "sha256-a7lcXJnnZkYReja+iUO7NqqrWyv3toxnUgQb8s4IS5s=";
51
          };
52
          cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
53
            inherit src;
54
            inherit (src) pname version;
55
            hash = "sha256-R1Tas33Ursy8kqsxguAkG0ZhNed2n5uFTAhw1l2qlLY=";
56
          };
57
        };
58
      wasmToolchain =
59
        system:
60
        let
61
          toolchains = fenix.packages.${system};
62
        in
63
        toolchains.combine [
64
          toolchains.stable.cargo
65
          toolchains.stable.clippy
66
          toolchains.stable.rustc
67
          toolchains.stable.rustfmt
68
          toolchains.stable.rust-src
69
          toolchains.targets.wasm32-unknown-unknown.stable.rust-std
70
        ];
71
      webNodeModules =
72
        pkgs:
73
        pkgs.importNpmLock.buildNodeModules {
74
          npmRoot = ./web;
75
          nodejs = pkgs.nodejs_22;
76
        };
77
      buildWeb =
78
        pkgs:
79
        {
80
          pname,
81
          task,
82
          outDir,
83
          postPatch ? "",
84
        }:
85
        pkgs.stdenvNoCC.mkDerivation {
86
          inherit pname postPatch;
87
          version = "0.1.0";
88
          src = cleanSrc ./web;
89
          npmDeps = webNodeModules pkgs;
90
          disallowedReferences = [
91
            (webNodeModules pkgs)
92
            pkgs.nodejs_22
93
          ];
94
          nativeBuildInputs = [
95
            pkgs.nodejs_22
96
            pkgs.importNpmLock.hooks.linkNodeModulesHook
97
            pkgs.brotli
98
          ];
99
          buildPhase = ''
100
            runHook preBuild
101
            export HOME=$TMPDIR
102
            npm run ${task}
103
            runHook postBuild
104
          '';
105
          installPhase = ''
106
            runHook preInstall
107
            mkdir -p $out/share/malice
108
            cp -R ${outDir}/. $out/share/malice/
109
            find $out/share/malice -type f \( -name '*.wasm' -o -name '*.js' -o -name '*.css' -o -name '*.html' -o -name '*.svg' -o -name '*.json' -o -name '*.webmanifest' \) -size +1k \
110
              -exec brotli --best --keep {} \; -exec gzip -9 --keep {} \;
111
            runHook postInstall
112
          '';
113
        };
114
    in
115
    {
116
      packages = forAllSystems (
117
        system:
118
        let
119
          pkgs = nixpkgs.legacyPackages.${system};
120
          wasmPlatform = pkgs.makeRustPlatform {
121
            cargo = wasmToolchain system;
122
            rustc = wasmToolchain system;
123
          };
124
          web = buildWeb pkgs {
125
            pname = "malice-web";
126
            task = "build";
127
            outDir = "dist";
128
          };
129
          backend = pkgs.rustPlatform.buildRustPackage {
130
            pname = "malice-server";
131
            version = "0.1.0";
132
            src = cleanSrc ./.;
133
            cargoLock = {
134
              lockFile = ./Cargo.lock;
135
              allowBuiltinFetchGit = true;
136
            };
137
            nativeBuildInputs = [ pkgs.pkg-config ];
138
            buildInputs = [ pkgs.sqlite ];
139
            cargoBuildFlags = [
140
              "-p"
141
              "malice"
142
            ];
143
            cargoTestFlags = [
144
              "-p"
145
              "malice"
146
            ];
147
            # preBuild = "export NIX_BUILD_CORES=2";
148
            preCheck = ''
149
              cargo build --release --bin malice --target ${pkgs.stdenv.hostPlatform.rust.rustcTarget} --offline --locked
150
            '';
151
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
152
          };
153
          staticServer = pkgs.rustPlatform.buildRustPackage {
154
            pname = "malice-static";
155
            version = "0.1.0";
156
            src = cleanSrc ./.;
157
            cargoLock = {
158
              lockFile = ./Cargo.lock;
159
              allowBuiltinFetchGit = true;
160
            };
161
            cargoBuildFlags = [
162
              "-p"
163
              "malice-static"
164
            ];
165
            cargoTestFlags = [
166
              "-p"
167
              "malice-static"
168
            ];
169
            meta.mainProgram = "malice-static";
170
          };
171
          server = pkgs.symlinkJoin {
172
            name = "malice";
173
            paths = [
174
              backend
175
              web
176
            ];
177
            nativeBuildInputs = [ pkgs.makeWrapper ];
178
            postBuild = ''
179
              wrapProgram $out/bin/malice --set MALICE_WEB_DIR ${web}/share/malice
180
            '';
181
          };
182
          # the wasm-bindgen `--target web` glue for malice-worker's `Host`, consumed by
183
          # web/src/worker/pkg (gitignored, worker-web's TS imports it as ./pkg/malice_worker.js)
184
          workerWasm = wasmPlatform.buildRustPackage {
185
            pname = "malice-worker-wasm";
186
            version = "0.1.0";
187
            src = cleanSrc ./.;
188
            cargoRoot = "crates/malice-worker";
189
            cargoLock = {
190
              lockFile = ./crates/malice-worker/Cargo.lock;
191
              allowBuiltinFetchGit = true;
192
            };
193
            nativeBuildInputs = [
194
              (wasmBindgenCli pkgs)
195
              pkgs.removeReferencesTo
196
            ];
197
            buildPhase = ''
198
              runHook preBuild
199
              cd crates/malice-worker
200
              cargo build --offline --frozen --release --lib --target wasm32-unknown-unknown
201
              mkdir -p $out
202
              wasm-bindgen --target web --out-dir $out --out-name malice_worker \
203
                target/wasm32-unknown-unknown/release/malice_worker.wasm
204
              remove-references-to -t ${wasmToolchain system} $out/*.wasm
205
              runHook postBuild
206
            '';
207
            doCheck = false;
208
            installPhase = "true";
209
            disallowedReferences = [ (wasmToolchain system) ];
210
          };
211
          web-device = buildWeb pkgs {
212
            pname = "malice-web-device";
213
            task = "build:device";
214
            outDir = "dist-device";
215
            postPatch = ''
216
              mkdir -p src/worker/pkg
217
              cp -R ${workerWasm}/. src/worker/pkg/
218
            '';
219
          };
220
          local = pkgs.symlinkJoin {
221
            name = "malice-local";
222
            paths = [
223
              staticServer
224
              web-device
225
            ];
226
            nativeBuildInputs = [ pkgs.makeWrapper ];
227
            postBuild = ''
228
              wrapProgram $out/bin/malice-static \
229
                --set MALICE_WEB_DIR ${web-device}/share/malice
230
            '';
231
          };
232
        in
233
        {
234
          inherit
235
            web
236
            server
237
            web-device
238
            local
239
            ;
240
          default = server;
241
        }
242
      );
243
244
      devShells = forAllSystems (
245
        system:
246
        let
247
          pkgs = nixpkgs.legacyPackages.${system};
248
        in
249
        {
250
          default = pkgs.mkShell {
251
            packages = [
252
              (wasmToolchain system)
253
              (wasmBindgenCli pkgs)
254
              pkgs.rust-analyzer
255
              pkgs.nodejs_22
256
              pkgs.importNpmLock.hooks.linkNodeModulesHook
257
              pkgs.pkg-config
258
              pkgs.sqlite
259
              pkgs.firefox
260
              pkgs.geckodriver
261
              pkgs.chromium
262
              pkgs.matrix-continuwuity
263
              pkgs.nushell
264
            ];
265
            CHROMIUM_PATH = nixpkgs.lib.getExe pkgs.chromium;
266
            npmDeps = webNodeModules pkgs;
267
            # the hook's own npmRoot would be a store path, so link into the checkout's web/ instead
268
            shellHook = ''
269
              npmRoot="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/web" linkNodeModulesHook
270
            '';
271
            # fenix's rustc links through its bundled rust-lld, which skips nix's ld-wrapper and so
272
            # the store rpaths, leaving the native server unable to find libsqlite3 at run time
273
            "CARGO_TARGET_${
274
              nixpkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] pkgs.stdenv.hostPlatform.config)
275
            }_RUSTFLAGS" =
276
              "-C linker-features=-lld";
277
          };
278
        }
279
      );
280
281
      nixosModules.malice = import ./nix/module.nix { inherit self; };
282
      nixosModules.default = self.nixosModules.malice;
283
      checks = forAllSystems (
284
        system:
285
        let
286
          pkgs = nixpkgs.legacyPackages.${system};
287
          wasmPlatform = pkgs.makeRustPlatform {
288
            cargo = wasmToolchain system;
289
            rustc = wasmToolchain system;
290
          };
291
          # continuwuity refuses to start without /etc/resolv.conf, which the build sandbox lacks, or with
292
          # stdenv's deliberately bogus SSL_CERT_FILE. no exec, run.nu launches through a shell that exits at
293
          # once and would trip --die-with-parent, so this shell stays as the parent run.nu kills
294
          sandboxedHomeserver = pkgs.writeShellScriptBin "conduwuit" ''
295
            export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
296
            ${pkgs.lib.getExe pkgs.bubblewrap} --die-with-parent --dev-bind / / --tmpfs /etc \
297
              --ro-bind ${pkgs.writeText "resolv.conf" "nameserver 127.0.0.1\n"} /etc/resolv.conf \
298
              ${pkgs.lib.getExe' pkgs.matrix-continuwuity "conduwuit"} "$@"
299
          '';
300
        in
301
        {
302
          default = self.packages.${system}.default;
303
          worker-wasm = self.packages.${system}.web-device;
304
          web = pkgs.stdenvNoCC.mkDerivation {
305
            pname = "malice-web-check";
306
            version = "0.1.0";
307
            src = cleanSrc ./web;
308
            npmDeps = webNodeModules pkgs;
309
            nativeBuildInputs = [
310
              pkgs.nodejs_22
311
              pkgs.importNpmLock.hooks.linkNodeModulesHook
312
            ];
313
            buildPhase = ''
314
              runHook preBuild
315
              export HOME=$TMPDIR
316
              npm run check
317
              npm test
318
              runHook postBuild
319
            '';
320
            installPhase = "touch $out";
321
          };
322
          worker-browser = wasmPlatform.buildRustPackage {
323
            pname = "malice-worker-browser-check";
324
            version = "0.1.0";
325
            src = cleanSrc ./.;
326
            cargoRoot = "crates/malice-worker";
327
            cargoLock = {
328
              lockFile = ./crates/malice-worker/Cargo.lock;
329
              allowBuiltinFetchGit = true;
330
            };
331
            nativeBuildInputs = [
332
              (wasmBindgenCli pkgs)
333
              pkgs.firefox
334
              pkgs.geckodriver
335
              sandboxedHomeserver
336
              pkgs.nushell
337
            ];
338
            buildPhase = ''
339
              runHook preBuild
340
              export HOME=$TMPDIR
341
              nu --no-config-file crates/malice-worker/run.nu
342
              runHook postBuild
343
            '';
344
            doCheck = false;
345
            installPhase = "touch $out";
346
          };
347
        }
348
      );
349
    };
350
}