atagen

malice

public
Star0
Watch0
850d5a52e9497c4bff4a5ca7532b304405795f36
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
flake.nixNix352 lines11.7 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
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
170
            meta.mainProgram = "malice-static";
171
          };
172
          server = pkgs.symlinkJoin {
173
            name = "malice";
174
            paths = [
175
              backend
176
              web
177
            ];
178
            nativeBuildInputs = [ pkgs.makeWrapper ];
179
            postBuild = ''
180
              wrapProgram $out/bin/malice --set MALICE_WEB_DIR ${web}/share/malice
181
            '';
182
          };
183
          # the wasm-bindgen `--target web` glue for malice-worker's `Host`, consumed by
184
          # web/src/worker/pkg (gitignored, worker-web's TS imports it as ./pkg/malice_worker.js)
185
          workerWasm = wasmPlatform.buildRustPackage {
186
            pname = "malice-worker-wasm";
187
            version = "0.1.0";
188
            src = cleanSrc ./.;
189
            cargoRoot = "crates/malice-worker";
190
            cargoLock = {
191
              lockFile = ./crates/malice-worker/Cargo.lock;
192
              allowBuiltinFetchGit = true;
193
            };
194
            nativeBuildInputs = [
195
              (wasmBindgenCli pkgs)
196
              pkgs.removeReferencesTo
197
            ];
198
            buildPhase = ''
199
              runHook preBuild
200
              cd crates/malice-worker
201
              cargo build --offline --frozen --release --lib --target wasm32-unknown-unknown
202
              mkdir -p $out
203
              wasm-bindgen --target web --out-dir $out --out-name malice_worker \
204
                target/wasm32-unknown-unknown/release/malice_worker.wasm
205
              remove-references-to -t ${wasmToolchain system} $out/*.wasm
206
              runHook postBuild
207
            '';
208
            doCheck = false;
209
            installPhase = "true";
210
            disallowedReferences = [ (wasmToolchain system) ];
211
          };
212
          web-device = buildWeb pkgs {
213
            pname = "malice-web-device";
214
            task = "build:device";
215
            outDir = "dist-device";
216
            postPatch = ''
217
              mkdir -p src/worker/pkg
218
              cp -R ${workerWasm}/. src/worker/pkg/
219
            '';
220
          };
221
          local = pkgs.symlinkJoin {
222
            name = "malice-local";
223
            meta.mainProgram = "malice-static";
224
            paths = [
225
              staticServer
226
              web-device
227
            ];
228
            nativeBuildInputs = [ pkgs.makeWrapper ];
229
            postBuild = ''
230
              wrapProgram $out/bin/malice-static \
231
                --set MALICE_WEB_DIR ${web-device}/share/malice
232
            '';
233
          };
234
        in
235
        {
236
          inherit
237
            web
238
            server
239
            web-device
240
            local
241
            ;
242
          default = server;
243
        }
244
      );
245
246
      devShells = forAllSystems (
247
        system:
248
        let
249
          pkgs = nixpkgs.legacyPackages.${system};
250
        in
251
        {
252
          default = pkgs.mkShell {
253
            packages = [
254
              (wasmToolchain system)
255
              (wasmBindgenCli pkgs)
256
              pkgs.rust-analyzer
257
              pkgs.nodejs_22
258
              pkgs.importNpmLock.hooks.linkNodeModulesHook
259
              pkgs.pkg-config
260
              pkgs.sqlite
261
              pkgs.firefox
262
              pkgs.geckodriver
263
              pkgs.chromium
264
              pkgs.matrix-continuwuity
265
              pkgs.nushell
266
            ];
267
            CHROMIUM_PATH = nixpkgs.lib.getExe pkgs.chromium;
268
            npmDeps = webNodeModules pkgs;
269
            # the hook's own npmRoot would be a store path, so link into the checkout's web/ instead
270
            shellHook = ''
271
              npmRoot="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/web" linkNodeModulesHook
272
            '';
273
            # fenix's rustc links through its bundled rust-lld, which skips nix's ld-wrapper and so
274
            # the store rpaths, leaving the native server unable to find libsqlite3 at run time
275
            "CARGO_TARGET_${
276
              nixpkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] pkgs.stdenv.hostPlatform.config)
277
            }_RUSTFLAGS" =
278
              "-C linker-features=-lld";
279
          };
280
        }
281
      );
282
283
      nixosModules.malice = import ./nix/module.nix { inherit self; };
284
      nixosModules.default = self.nixosModules.malice;
285
      checks = forAllSystems (
286
        system:
287
        let
288
          pkgs = nixpkgs.legacyPackages.${system};
289
          wasmPlatform = pkgs.makeRustPlatform {
290
            cargo = wasmToolchain system;
291
            rustc = wasmToolchain system;
292
          };
293
          # continuwuity refuses to start without /etc/resolv.conf, which the build sandbox lacks, or with
294
          # stdenv's deliberately bogus SSL_CERT_FILE. no exec, run.nu launches through a shell that exits at
295
          # once and would trip --die-with-parent, so this shell stays as the parent run.nu kills
296
          sandboxedHomeserver = pkgs.writeShellScriptBin "conduwuit" ''
297
            export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
298
            ${pkgs.lib.getExe pkgs.bubblewrap} --die-with-parent --dev-bind / / --tmpfs /etc \
299
              --ro-bind ${pkgs.writeText "resolv.conf" "nameserver 127.0.0.1\n"} /etc/resolv.conf \
300
              ${pkgs.lib.getExe' pkgs.matrix-continuwuity "conduwuit"} "$@"
301
          '';
302
        in
303
        {
304
          default = self.packages.${system}.default;
305
          worker-wasm = self.packages.${system}.web-device;
306
          web = pkgs.stdenvNoCC.mkDerivation {
307
            pname = "malice-web-check";
308
            version = "0.1.0";
309
            src = cleanSrc ./web;
310
            npmDeps = webNodeModules pkgs;
311
            nativeBuildInputs = [
312
              pkgs.nodejs_22
313
              pkgs.importNpmLock.hooks.linkNodeModulesHook
314
            ];
315
            buildPhase = ''
316
              runHook preBuild
317
              export HOME=$TMPDIR
318
              npm run check
319
              npm test
320
              runHook postBuild
321
            '';
322
            installPhase = "touch $out";
323
          };
324
          worker-browser = wasmPlatform.buildRustPackage {
325
            pname = "malice-worker-browser-check";
326
            version = "0.1.0";
327
            src = cleanSrc ./.;
328
            cargoRoot = "crates/malice-worker";
329
            cargoLock = {
330
              lockFile = ./crates/malice-worker/Cargo.lock;
331
              allowBuiltinFetchGit = true;
332
            };
333
            nativeBuildInputs = [
334
              (wasmBindgenCli pkgs)
335
              pkgs.firefox
336
              pkgs.geckodriver
337
              sandboxedHomeserver
338
              pkgs.nushell
339
            ];
340
            buildPhase = ''
341
              runHook preBuild
342
              export HOME=$TMPDIR
343
              nu --no-config-file crates/malice-worker/run.nu
344
              runHook postBuild
345
            '';
346
            doCheck = false;
347
            installPhase = "touch $out";
348
          };
349
        }
350
      );
351
    };
352
}