diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000..e087c9f --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,35 @@ +# Copyright © 2025-26 l5yth & contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Nix + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + flake-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Nix + uses: cachix/install-nix-action@v30 + with: + extra_nix_config: | + experimental-features = nix-command flakes + - name: Run flake checks + run: nix flake check diff --git a/README.md b/README.md index 39d587d..9578ed1 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,45 @@ example `ALLOWED_CHANNELS="Chat,Ops"`); packets on other channels are discarded. Use `HIDDEN_CHANNELS` to block specific channels from the web UI even when they appear in the allowlist. +## Nix + +For the dev shell, run: + +```bash +nix develop +``` + +The shell provides Ruby plus the Python ingestor dependencies (including `meshtastic` +and `protobuf`). To sanity-check that the ingestor starts, run `python -m data.mesh` +with the usual environment variables (`INSTANCE_DOMAIN`, `API_TOKEN`, `CONNECTION`). + +To run the packaged apps directly: + +```bash +nix run .#web +nix run .#ingestor +``` + +Minimal NixOS module snippet: + +```nix +services.potato-mesh = { + enable = true; + apiTokenFile = config.sops.secrets.potato-mesh-api-token.path; + dataDir = "/var/lib/potato-mesh"; + port = 41447; + instanceDomain = "https://mesh.me"; + siteName = "Nix Mesh"; + contactLink = "homeserver.mx"; + mapCenter = "28.96,-13.56"; + frequency = "868MHz"; + ingestor = { + enable = true; + connection = "192.168.X.Y:4403"; + }; +}; +``` + ## Docker Docker images are published on Github for each release: diff --git a/flake.nix b/flake.nix index aa1ce1d..e4caad8 100644 --- a/flake.nix +++ b/flake.nix @@ -14,6 +14,7 @@ # Python environment for the ingestor pythonEnv = pkgs.python3.withPackages (ps: with ps; [ meshtastic + protobuf requests ]); @@ -22,7 +23,11 @@ name = "potato-mesh-web"; runtimeInputs = [ pkgs.ruby pkgs.bundler pkgs.sqlite pkgs.git pkgs.gnumake pkgs.gcc ]; text = '' - BASEDIR="''${XDG_DATA_HOME:-$HOME/.local/share}/potato-mesh" + if [ -n "''${XDG_DATA_HOME:-}" ]; then + BASEDIR="$XDG_DATA_HOME" + else + BASEDIR="$HOME/.local/share/potato-mesh" + fi WORKDIR="$BASEDIR/web" mkdir -p "$WORKDIR" @@ -60,7 +65,11 @@ runtimeInputs = [ pythonEnv ]; text = '' # The ingestor needs to run from parent directory with data/ folder - BASEDIR="''${XDG_DATA_HOME:-$HOME/.local/share}/potato-mesh" + if [ -n "''${XDG_DATA_HOME:-}" ]; then + BASEDIR="$XDG_DATA_HOME" + else + BASEDIR="$HOME/.local/share/potato-mesh" + fi if [ ! -d "$BASEDIR/data" ]; then mkdir -p "$BASEDIR" cp -rT "${./data}" "$BASEDIR/data/" @@ -107,6 +116,27 @@ echo "To run the ingestor: cd data && python mesh.py" ''; }; + + checks.potato-mesh-nixos = pkgs.testers.nixosTest { + name = "potato-mesh-data-dir"; + nodes.machine = { lib, ... }: { + imports = [ self.nixosModules.default ]; + services.potato-mesh = { + enable = true; + apiToken = "test-token"; + dataDir = "/var/lib/potato-mesh"; + ingestor.enable = true; + }; + systemd.services.potato-mesh-ingestor.wantedBy = lib.mkForce []; + }; + testScript = '' + machine.start + machine.succeed("grep -q 'XDG_DATA_HOME=/var/lib/potato-mesh' /etc/systemd/system/potato-mesh-web.service") + machine.succeed("grep -q 'XDG_DATA_HOME=/var/lib/potato-mesh' /etc/systemd/system/potato-mesh-ingestor.service") + machine.succeed("grep -q 'WorkingDirectory=/var/lib/potato-mesh' /etc/systemd/system/potato-mesh-web.service") + machine.succeed("grep -q 'WorkingDirectory=/var/lib/potato-mesh' /etc/systemd/system/potato-mesh-ingestor.service") + ''; + }; } ) // { # NixOS module @@ -327,6 +357,7 @@ INSTANCE_DOMAIN = "http://127.0.0.1:${toString cfg.port}"; CONNECTION = cfg.ingestor.connection; DEBUG = if cfg.debug then "1" else "0"; + XDG_DATA_HOME = cfg.dataDir; } // lib.optionalAttrs (cfg.allowedChannels != null) { ALLOWED_CHANNELS = cfg.allowedChannels; } // lib.optionalAttrs (cfg.hiddenChannels != null) {