flake.nix
1 { 2 inputs = { 3 nixpkgs.url = "github:NixOS/nixpkgs/release-23.11"; 4 }; 5 6 outputs = { 7 self, 8 nixpkgs, 9 }: let 10 inherit (nixpkgs) lib; 11 defaultSystems = [ 12 "x86_64-linux" 13 "x86_64-darwin" 14 "aarch64-linux" 15 "aarch64-darwin" 16 ]; 17 eachDefaultSystem = f: 18 builtins.listToAttrs (map (system: { 19 name = system; 20 value = f (import nixpkgs {inherit system;}); 21 }) 22 defaultSystems); 23 in { 24 packages = eachDefaultSystem (pkgs: let 25 inherit (fromTOML (builtins.readFile ./Cargo.toml)) package; 26 in { 27 default = pkgs.rustPlatform.buildRustPackage { 28 pname = package.name; 29 version = package.version; 30 src = lib.fileset.toSource { 31 root = ./.; 32 fileset = lib.fileset.unions [ 33 ./Cargo.toml 34 ./Cargo.lock 35 ./src 36 ]; 37 }; 38 cargoLock.lockFile = ./Cargo.lock; 39 doCheck = false; 40 }; 41 }); 42 43 nixosModules.default = { 44 config, 45 lib, 46 pkgs, 47 ... 48 }: { 49 options.services.distodon = with lib; { 50 enable = mkEnableOption "distodon"; 51 debug = mkOption { 52 type = types.bool; 53 default = false; 54 }; 55 interval = mkOption { 56 type = types.ints.positive; 57 default = 600; 58 }; 59 chunkSize = mkOption { 60 type = types.ints.between 1 10; 61 default = 1; 62 }; 63 links = mkOption { 64 type = types.listOf (types.submodule { 65 options = { 66 mastodonServerUrl = mkOption { 67 type = types.str; 68 }; 69 mastodonUser = mkOption { 70 type = types.str; 71 }; 72 webhookUrl = mkOption { 73 type = types.nullOr types.str; 74 default = null; 75 }; 76 webhookUrlFile = mkOption { 77 type = types.nullOr types.path; 78 default = null; 79 }; 80 }; 81 }); 82 }; 83 }; 84 85 config = let 86 cfg = config.services.distodon; 87 links = builtins.genList (i: rec { 88 inherit i; 89 link = builtins.elemAt cfg.links i; 90 secretName = "webhook-url-${toString i}"; 91 }) (builtins.length cfg.links); 92 linksWithSecrets = builtins.filter ({link, ...}: link.webhookUrlFile != null) links; 93 94 configFile = (pkgs.formats.toml {}).generate "distodon-config.toml" { 95 interval = cfg.interval; 96 chunk_size = cfg.chunkSize; 97 links = map (link: 98 { 99 mastodon_server_url = link.mastodonServerUrl; 100 mastodon_user = link.mastodonUser; 101 } 102 // (lib.optionalAttrs (link.webhookUrl != null) { 103 webhook_url = link.webhookUrl; 104 })) 105 cfg.links; 106 }; 107 in 108 lib.mkIf cfg.enable { 109 assertions = lib.flatten (map ({ 110 webhookUrl, 111 webhookUrlFile, 112 ... 113 }: [ 114 { 115 assertion = (webhookUrl != null) != (webhookUrlFile != null); 116 message = "Exactly one of webhookUrl and webhookUrlFile must be set"; 117 } 118 ]) 119 cfg.links); 120 121 systemd.services.distodon = { 122 wantedBy = ["multi-user.target"]; 123 serviceConfig = { 124 User = "distodon"; 125 Group = "distodon"; 126 DynamicUser = true; 127 WorkingDirectory = "/run/distodon"; 128 RuntimeDirectory = "distodon"; 129 StateDirectory = "distodon"; 130 LoadCredential = builtins.map ({ 131 link, 132 secretName, 133 ... 134 }: "${secretName}:${link.webhookUrlFile}") 135 linksWithSecrets; 136 }; 137 environment = { 138 RUST_LOG = 139 if cfg.debug 140 then "debug" 141 else "info"; 142 }; 143 preStart = '' 144 cd /run/distodon 145 rm -f config.toml data 146 ln -s /var/lib/distodon data 147 cp ${configFile} config.toml 148 chmod 600 config.toml 149 150 ${builtins.concatStringsSep "\n" (map ({ 151 i, 152 secretName, 153 ... 154 }: '' 155 webhook_url=$(cat ''${CREDENTIALS_DIRECTORY}/${secretName}) 156 ${pkgs.yq}/bin/tomlq -i -t --argjson i ${toString i} --arg webhook_url "$webhook_url" '.links[$ARGS.named.i].webhook_url = $ARGS.named.webhook_url' config.toml 157 '') 158 linksWithSecrets)} 159 ''; 160 script = '' 161 ${self.packages.${pkgs.system}.default}/bin/distodon 162 ''; 163 }; 164 }; 165 }; 166 }; 167 }