Rust AppView - highly experimental!

Compare changes

Choose any two refs to compare.

Changed files
+568 -1
parakeet-index
+1
.envrc
··· 1 + use flake
+1
.gitignore
··· 4 4 .env 5 5 Config.toml 6 6 data/ 7 + .direnv/
+98
flake.lock
··· 1 + { 2 + "nodes": { 3 + "crane": { 4 + "locked": { 5 + "lastModified": 1757183466, 6 + "narHash": "sha256-kTdCCMuRE+/HNHES5JYsbRHmgtr+l9mOtf5dpcMppVc=", 7 + "owner": "ipetkov", 8 + "repo": "crane", 9 + "rev": "d599ae4847e7f87603e7082d73ca673aa93c916d", 10 + "type": "github" 11 + }, 12 + "original": { 13 + "owner": "ipetkov", 14 + "repo": "crane", 15 + "type": "github" 16 + } 17 + }, 18 + "flake-utils": { 19 + "inputs": { 20 + "systems": "systems" 21 + }, 22 + "locked": { 23 + "lastModified": 1731533236, 24 + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 25 + "owner": "numtide", 26 + "repo": "flake-utils", 27 + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 28 + "type": "github" 29 + }, 30 + "original": { 31 + "owner": "numtide", 32 + "repo": "flake-utils", 33 + "type": "github" 34 + } 35 + }, 36 + "nixpkgs": { 37 + "locked": { 38 + "lastModified": 1758029226, 39 + "narHash": "sha256-TjqVmbpoCqWywY9xIZLTf6ANFvDCXdctCjoYuYPYdMI=", 40 + "owner": "NixOS", 41 + "repo": "nixpkgs", 42 + "rev": "08b8f92ac6354983f5382124fef6006cade4a1c1", 43 + "type": "github" 44 + }, 45 + "original": { 46 + "owner": "NixOS", 47 + "ref": "nixpkgs-unstable", 48 + "repo": "nixpkgs", 49 + "type": "github" 50 + } 51 + }, 52 + "root": { 53 + "inputs": { 54 + "crane": "crane", 55 + "flake-utils": "flake-utils", 56 + "nixpkgs": "nixpkgs", 57 + "rust-overlay": "rust-overlay" 58 + } 59 + }, 60 + "rust-overlay": { 61 + "inputs": { 62 + "nixpkgs": [ 63 + "nixpkgs" 64 + ] 65 + }, 66 + "locked": { 67 + "lastModified": 1758162771, 68 + "narHash": "sha256-hdZpMep6Z1gbgg9piUZ0BNusI6ZJaptBw6PHSN/3GD0=", 69 + "owner": "oxalica", 70 + "repo": "rust-overlay", 71 + "rev": "d0cabb6ae8f5b38dffaff9f4e6db57c0ae21d729", 72 + "type": "github" 73 + }, 74 + "original": { 75 + "owner": "oxalica", 76 + "repo": "rust-overlay", 77 + "type": "github" 78 + } 79 + }, 80 + "systems": { 81 + "locked": { 82 + "lastModified": 1681028828, 83 + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 84 + "owner": "nix-systems", 85 + "repo": "default", 86 + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 87 + "type": "github" 88 + }, 89 + "original": { 90 + "owner": "nix-systems", 91 + "repo": "default", 92 + "type": "github" 93 + } 94 + } 95 + }, 96 + "root": "root", 97 + "version": 7 98 + }
+464
flake.nix
··· 1 + { 2 + description = "Parakeet is a Rust-based Bluesky AppView"; 3 + inputs = { 4 + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 5 + crane.url = "github:ipetkov/crane"; 6 + flake-utils.url = "github:numtide/flake-utils"; 7 + rust-overlay = { 8 + url = "github:oxalica/rust-overlay"; 9 + inputs.nixpkgs.follows = "nixpkgs"; 10 + }; 11 + }; 12 + outputs = 13 + { 14 + self, 15 + nixpkgs, 16 + crane, 17 + flake-utils, 18 + rust-overlay, 19 + ... 20 + }: 21 + flake-utils.lib.eachDefaultSystem ( 22 + system: 23 + let 24 + pkgs = import nixpkgs { 25 + inherit system; 26 + overlays = [ (import rust-overlay) ]; 27 + }; 28 + craneLib = (crane.mkLib pkgs).overrideToolchain ( 29 + p: 30 + p.rust-bin.selectLatestNightlyWith ( 31 + toolchain: 32 + toolchain.default.override { 33 + extensions = [ 34 + "rust-src" 35 + "rust-analyzer" 36 + ]; 37 + } 38 + ) 39 + ); 40 + 41 + inherit (pkgs) lib; 42 + unfilteredRoot = ./.; # The original, unfiltered source 43 + src = lib.fileset.toSource { 44 + root = unfilteredRoot; 45 + fileset = lib.fileset.unions [ 46 + # Default files from crane (Rust and cargo files) 47 + (craneLib.fileset.commonCargoSources unfilteredRoot) 48 + ]; 49 + }; 50 + # Common arguments can be set here to avoid repeating them later 51 + commonArgs = { 52 + inherit src; 53 + strictDeps = true; 54 + nativeBuildInputs = with pkgs; [ 55 + pkg-config 56 + ]; 57 + buildInputs = [ 58 + # Add additional build inputs here 59 + pkgs.openssl 60 + pkgs.postgresql 61 + pkgs.libpq 62 + pkgs.clang 63 + pkgs.libclang 64 + pkgs.lld 65 + pkgs.protobuf 66 + ] 67 + ++ lib.optionals pkgs.stdenv.isDarwin [ 68 + # Additional darwin specific inputs can be set here 69 + pkgs.libiconv 70 + pkgs.darwin.apple_sdk.frameworks.Security 71 + ]; 72 + LIBCLANG_PATH = "${pkgs.llvmPackages_18.libclang.lib}/lib"; 73 + CLANG_PATH = "${pkgs.llvmPackages_18.clang}/bin/clang"; 74 + PROTOC_INCLUDE = "${pkgs.protobuf}/include"; 75 + PROTOC = "${pkgs.protobuf}/bin/protoc"; 76 + 77 + # Additional environment variables can be set directly 78 + # MY_CUSTOM_VAR = "some value"; 79 + }; 80 + 81 + # Build *just* the cargo dependencies, so we can reuse 82 + # all of that work (e.g. via cachix) when running in CI 83 + cargoArtifacts = craneLib.buildDepsOnly commonArgs; 84 + 85 + individualCrateArgs = commonArgs // { 86 + inherit cargoArtifacts; 87 + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; 88 + # NB: we disable tests since we'll run them all via cargo-nextest 89 + doCheck = false; 90 + }; 91 + fileSetForCrate = 92 + crate: 93 + lib.fileset.toSource { 94 + root = ./.; 95 + fileset = lib.fileset.unions [ 96 + ./Cargo.toml 97 + ./Cargo.lock 98 + ./migrations 99 + (craneLib.fileset.commonCargoSources ./consumer) 100 + ./consumer/src/db/sql 101 + (craneLib.fileset.commonCargoSources ./dataloader-rs) 102 + (craneLib.fileset.commonCargoSources ./did-resolver) 103 + (craneLib.fileset.commonCargoSources ./lexica) 104 + (craneLib.fileset.commonCargoSources ./parakeet) 105 + ./parakeet/src/sql 106 + (craneLib.fileset.commonCargoSources ./parakeet-db) 107 + (craneLib.fileset.commonCargoSources ./parakeet-index) 108 + ./parakeet-index/proto 109 + (craneLib.fileset.commonCargoSources ./parakeet-lexgen) 110 + (craneLib.fileset.commonCargoSources crate) 111 + ]; 112 + }; 113 + 114 + # Build the actual crate itself, reusing the dependency 115 + # artifacts from above. 116 + consumer = craneLib.buildPackage ( 117 + individualCrateArgs 118 + // { 119 + pname = "consumer"; 120 + cargoExtraArgs = "-p consumer"; 121 + src = fileSetForCrate ./consumer; 122 + postInstall = '' 123 + mkdir -p $out/{bin,lib/consumer} 124 + ''; 125 + } 126 + ); 127 + dataloader = craneLib.buildPackage ( 128 + individualCrateArgs 129 + // { 130 + pname = "dataloader"; 131 + cargoExtraArgs = "-p dataloader --features default"; 132 + src = fileSetForCrate ./dataloader-rs; 133 + } 134 + ); 135 + did-resolver = craneLib.buildPackage ( 136 + individualCrateArgs 137 + // { 138 + pname = "did-resolver"; 139 + cargoExtraArgs = "-p did-resolver"; 140 + src = fileSetForCrate ./did-resolver; 141 + } 142 + ); 143 + lexica = craneLib.buildPackage ( 144 + individualCrateArgs 145 + // { 146 + pname = "lexica"; 147 + cargoExtraArgs = "-p lexica"; 148 + src = fileSetForCrate ./lexica; 149 + } 150 + ); 151 + parakeet = craneLib.buildPackage ( 152 + individualCrateArgs 153 + // { 154 + pname = "parakeet"; 155 + cargoExtraArgs = "-p parakeet"; 156 + src = fileSetForCrate ./parakeet; 157 + } 158 + ); 159 + parakeet-db = craneLib.buildPackage ( 160 + individualCrateArgs 161 + // { 162 + pname = "parakeet-db"; 163 + cargoExtraArgs = "-p parakeet-db --features default"; 164 + src = fileSetForCrate ./parakeet-db; 165 + } 166 + ); 167 + parakeet-index = craneLib.buildPackage ( 168 + individualCrateArgs 169 + // { 170 + pname = "parakeet-index"; 171 + cargoExtraArgs = "-p parakeet-index --features server"; 172 + src = fileSetForCrate ./parakeet-index; 173 + } 174 + ); 175 + parakeet-lexgen = craneLib.buildPackage ( 176 + individualCrateArgs 177 + // { 178 + pname = "parakeet-lexgen"; 179 + cargoExtraArgs = "-p parakeet-lexgen"; 180 + src = fileSetForCrate ./parakeet-lexgen; 181 + } 182 + ); 183 + in 184 + { 185 + checks = { 186 + # Build the crate as part of `nix flake check` for convenience 187 + inherit 188 + consumer 189 + dataloader 190 + did-resolver 191 + lexica 192 + parakeet 193 + parakeet-db 194 + parakeet-index 195 + parakeet-lexgen 196 + ; 197 + }; 198 + 199 + packages = { 200 + default = parakeet; 201 + inherit 202 + consumer 203 + dataloader 204 + did-resolver 205 + lexica 206 + parakeet 207 + parakeet-db 208 + parakeet-index 209 + parakeet-lexgen 210 + ; 211 + }; 212 + 213 + devShells.default = craneLib.devShell { 214 + # Inherit inputs from checks. 215 + checks = self.checks.${system}; 216 + 217 + # Additional dev-shell environment variables can be set directly 218 + RUST_BACKTRACE = 1; 219 + NIXOS_OZONE_WL = 1; 220 + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; 221 + 222 + # Extra inputs can be added here; cargo and rustc are provided by default. 223 + packages = with pkgs; [ 224 + openssl 225 + bacon 226 + postgresql 227 + rust-analyzer 228 + rustfmt 229 + clippy 230 + git 231 + nixd 232 + direnv 233 + libpq 234 + clang 235 + libclang 236 + ]; 237 + }; 238 + } 239 + ) 240 + // flake-utils.lib.eachDefaultSystemPassThrough (system: { 241 + nixosModules = { 242 + default = 243 + { 244 + pkgs, 245 + lib, 246 + config, 247 + ... 248 + }: 249 + with lib; 250 + let 251 + cfg = config.services.parakeet; 252 + 253 + inherit (lib) 254 + mkEnableOption 255 + mkIf 256 + mkOption 257 + types 258 + ; 259 + in 260 + { 261 + options.services.parakeet = { 262 + enable = mkEnableOption "parakeet"; 263 + 264 + package = mkOption { 265 + type = types.package; 266 + default = self.packages.${pkgs.system}.default; 267 + description = "The path to the parakeet package."; 268 + }; 269 + 270 + environmentFiles = mkOption { 271 + type = types.listOf types.path; 272 + default = [ "/var/lib/parakeet/config.env" ]; 273 + description = '' 274 + File to load environment variables from. Loaded variables override 275 + values set in {option}`environment`. 276 + ''; 277 + }; 278 + }; 279 + config = mkIf cfg.enable { 280 + environment.systemPackages = [ 281 + self.packages.${pkgs.system}.consumer 282 + ]; 283 + systemd.services.consumer = { 284 + description = "consumer"; 285 + after = [ "network-online.target" ]; 286 + wants = [ "network-online.target" ]; 287 + wantedBy = [ "multi-user.target" ]; 288 + serviceConfig = { 289 + ExecStart = "${self.packages.${pkgs.system}.consumer}/bin/consumer --indexer"; 290 + Type = "exec"; 291 + 292 + EnvironmentFile = cfg.environmentFiles; 293 + User = "parakeet"; 294 + Group = "parakeet"; 295 + StateDirectory = "parakeet"; 296 + StateDirectoryMode = "0755"; 297 + Restart = "always"; 298 + 299 + # Hardening 300 + RemoveIPC = true; 301 + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; 302 + NoNewPrivileges = true; 303 + PrivateDevices = true; 304 + ProtectClock = true; 305 + ProtectKernelLogs = true; 306 + ProtectControlGroups = true; 307 + ProtectKernelModules = true; 308 + PrivateMounts = true; 309 + SystemCallArchitectures = [ "native" ]; 310 + MemoryDenyWriteExecute = false; # required by V8 JIT 311 + RestrictNamespaces = true; 312 + RestrictSUIDSGID = true; 313 + ProtectHostname = true; 314 + LockPersonality = true; 315 + ProtectKernelTunables = true; 316 + RestrictAddressFamilies = [ 317 + "AF_UNIX" 318 + "AF_INET" 319 + "AF_INET6" 320 + ]; 321 + RestrictRealtime = true; 322 + DeviceAllow = [ "" ]; 323 + ProtectSystem = "full"; 324 + ProtectProc = "invisible"; 325 + ProcSubset = "pid"; 326 + ProtectHome = true; 327 + PrivateUsers = true; 328 + PrivateTmp = true; 329 + UMask = "0077"; 330 + }; 331 + }; 332 + systemd.services.parakeet = { 333 + description = "parakeet"; 334 + after = [ "network-online.target" ]; 335 + wants = [ "network-online.target" ]; 336 + wantedBy = [ "multi-user.target" ]; 337 + serviceConfig = { 338 + ExecStart = "${cfg.package}/bin/parakeet"; 339 + Type = "exec"; 340 + 341 + EnvironmentFile = cfg.environmentFiles; 342 + User = "parakeet"; 343 + Group = "parakeet"; 344 + StateDirectory = "parakeet"; 345 + StateDirectoryMode = "0755"; 346 + Restart = "always"; 347 + 348 + # Hardening 349 + RemoveIPC = true; 350 + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; 351 + NoNewPrivileges = true; 352 + PrivateDevices = true; 353 + ProtectClock = true; 354 + ProtectKernelLogs = true; 355 + ProtectControlGroups = true; 356 + ProtectKernelModules = true; 357 + PrivateMounts = true; 358 + SystemCallArchitectures = [ "native" ]; 359 + MemoryDenyWriteExecute = false; # required by V8 JIT 360 + RestrictNamespaces = true; 361 + RestrictSUIDSGID = true; 362 + ProtectHostname = true; 363 + LockPersonality = true; 364 + ProtectKernelTunables = true; 365 + RestrictAddressFamilies = [ 366 + "AF_UNIX" 367 + "AF_INET" 368 + "AF_INET6" 369 + ]; 370 + RestrictRealtime = true; 371 + DeviceAllow = [ "" ]; 372 + ProtectSystem = "full"; 373 + ProtectProc = "invisible"; 374 + ProcSubset = "pid"; 375 + ProtectHome = true; 376 + PrivateUsers = true; 377 + PrivateTmp = true; 378 + UMask = "0077"; 379 + }; 380 + }; 381 + systemd.services.parakeet-index = { 382 + description = "parakeet-index"; 383 + after = [ "network-online.target" ]; 384 + wants = [ "network-online.target" ]; 385 + wantedBy = [ "multi-user.target" ]; 386 + serviceConfig = { 387 + ExecStart = "${self.packages.${pkgs.system}.parakeet-index}/bin/parakeet-index"; 388 + Type = "exec"; 389 + 390 + EnvironmentFile = cfg.environmentFiles; 391 + User = "parakeet"; 392 + Group = "parakeet"; 393 + StateDirectory = "parakeet"; 394 + StateDirectoryMode = "0755"; 395 + Restart = "always"; 396 + 397 + # Hardening 398 + RemoveIPC = true; 399 + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; 400 + NoNewPrivileges = true; 401 + PrivateDevices = true; 402 + ProtectClock = true; 403 + ProtectKernelLogs = true; 404 + ProtectControlGroups = true; 405 + ProtectKernelModules = true; 406 + PrivateMounts = true; 407 + SystemCallArchitectures = [ "native" ]; 408 + MemoryDenyWriteExecute = false; # required by V8 JIT 409 + RestrictNamespaces = true; 410 + RestrictSUIDSGID = true; 411 + ProtectHostname = true; 412 + LockPersonality = true; 413 + ProtectKernelTunables = true; 414 + RestrictAddressFamilies = [ 415 + "AF_UNIX" 416 + "AF_INET" 417 + "AF_INET6" 418 + ]; 419 + RestrictRealtime = true; 420 + DeviceAllow = [ "" ]; 421 + ProtectSystem = "full"; 422 + ProtectProc = "invisible"; 423 + ProcSubset = "pid"; 424 + ProtectHome = true; 425 + PrivateUsers = true; 426 + PrivateTmp = true; 427 + UMask = "0077"; 428 + }; 429 + }; 430 + users = { 431 + users.parakeet = { 432 + group = "parakeet"; 433 + isSystemUser = true; 434 + }; 435 + groups.parakeet = { }; 436 + }; 437 + services.postgresql = { 438 + enable = true; 439 + ensureUsers = [ 440 + { 441 + name = "parakeet"; 442 + ensureDBOwnership = true; 443 + } 444 + ]; 445 + ensureDatabases = [ "parakeet" ]; 446 + authentication = pkgs.lib.mkOverride 10 '' 447 + #type database DBuser auth-method 448 + local all all trust 449 + host all all 127.0.0.1/32 trust 450 + host all all ::1/128 trust 451 + ''; 452 + package = mkForce pkgs.postgresql_16; 453 + }; 454 + services.redis.servers.parakeet = { 455 + enable = true; 456 + # port = 0; 457 + unixSocket = "/run/redis-parakeet/redis.sock"; 458 + user = "parakeet"; 459 + }; 460 + }; 461 + }; 462 + }; 463 + }); 464 + }
+4 -1
parakeet-index/build.rs
··· 1 1 fn main() -> Result<(), Box<dyn std::error::Error>> { 2 - tonic_build::configure().compile_protos(&["proto/parakeet.proto"], &[""])?; 2 + tonic_build::configure().compile_protos( 3 + &[std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("proto/parakeet.proto")], 4 + &[std::path::Path::new(env!("CARGO_MANIFEST_DIR"))], 5 + )?; 3 6 4 7 Ok(()) 5 8 }