Files

194 lines
6.1 KiB
Nix

{
description = "xonotic-exporter dev shell";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
# Python env with all runtime + dev deps
pythonEnv = pkgs.python313.withPackages (
ps: with ps; [
(ps.buildPythonPackage rec {
pname = "xrcon";
version = "0.2";
format = "setuptools";
src = ps.fetchPypi {
inherit pname version;
sha256 = "sha256-xRuZXgf09zrQUpneR2DTBYr7W08GYOc2TmaVp71rcqs=";
};
build-system = [ ps.setuptools ];
dependencies = [ ps.six ];
})
prometheus-client
pytest
pytest-asyncio
mypy
black
isort
ruff
pip
]
);
# Convenience script: start a local Xonotic dedicated server
startXonotic = pkgs.writeShellScriptBin "start-xonotic-server" ''
set -euo pipefail
PORT=''${XONOTIC_PORT:-26010}
RCON_PW=''${XONOTIC_RCON_PASSWORD:-devpassword}
DATADIR=''${XONOTIC_DATADIR:-$PWD/.xonotic-data}
CFGDIR="$DATADIR/data"
mkdir -p "$CFGDIR"
cat > "$CFGDIR/config.cfg" <<EOF
hostname "xonotic-dev-server"
sv_public -1
rcon_password "$RCON_PW"
rcon_secure 0
EOF
cat > "$CFGDIR/server.cfg" <<EOF
gametype dm
minplayers 0
bot_number 2
timelimit 20
fraglimit 30
EOF
echo "Starting Xonotic dedicated server on UDP :$PORT (rcon pw: $RCON_PW)"
exec ${pkgs.xonotic-dedicated}/bin/xonotic-dedicated \
-userdir "$DATADIR" \
-port "$PORT" \
"$@"
'';
# Convenience script: query the local test server
queryServer = pkgs.writeShellScriptBin "query-xonotic" ''
set -euo pipefail
PORT=''${XONOTIC_PORT:-26010}
PW=''${XONOTIC_RCON_PASSWORD:-devpassword}
exec xonotic-exporter query \
--host localhost \
--port "$PORT" \
--password "$PW" \
--mode 0 \
"$@"
'';
# Generate a minimal dev config for the exporter
genConfig = pkgs.writeShellScriptBin "gen-exporter-config" ''
PORT=''${XONOTIC_PORT:-26010}
PW=''${XONOTIC_RCON_PASSWORD:-devpassword}
OUT=''${1:-dev-config.toml}
cat > "$OUT" <<EOF
[exporter]
host = "0.0.0.0"
port = 9260
[[servers]]
name = "dev"
host = "localhost"
port = $PORT
rcon_password = "$PW"
rcon_mode = 0
EOF
echo "Wrote exporter config to $OUT"
'';
in
{
devShells.default = pkgs.mkShell {
name = "xonotic-exporter";
packages = [
pythonEnv
# Xonotic dedicated server
pkgs.xonotic-dedicated
# The project itself (editable install via pip in shellHook)
# Network / protocol debugging
pkgs.netcat-gnu # nc — poke UDP ports
pkgs.tcpdump # capture RCON UDP traffic
pkgs.wireshark-cli # tshark for scripted captures
pkgs.socat # relay / inspect UDP
pkgs.nmap # port scanning / service detection
# Metrics & observability
pkgs.prometheus # run a local prometheus instance
pkgs.grafana # dashboard for scraped metrics
pkgs.curl # hit the /metrics endpoint
# Dev tools
pkgs.git
pkgs.gnumake
pkgs.jq # inspect JSON / TOML-adjacent debugging
pkgs.ripgrep
pkgs.fd
pkgs.watchexec # re-run tests on file change
pkgs.just # task runner (justfile)
pkgs.entr # alternative file watcher
# Convenience scripts defined above
startXonotic
queryServer
genConfig
];
shellHook = ''
echo ""
echo " "
echo " xonotic-exporter dev shell "
echo " "
echo ""
export PYTHONPATH="$PWD/.dev-packages:$PYTHONPATH"
export PYTHONDONTWRITEBYTECODE=1
export PYTHONUNBUFFERED=1
DEV_PKG="$PWD/.dev-packages"
PTH="$DEV_PKG/__editable__.xonotic_exporter-1.0.0.pth"
export PATH="$PWD/.dev-packages/bin:$PATH"
if [ ! -f "$PTH" ]; then
echo " Installing xonotic-exporter (editable)..."
pip install -e . --target "$DEV_PKG" --quiet || echo " pip install failed check pyproject.toml"
else
echo " xonotic-exporter already installed, skipping pip."
fi
echo ""
echo " Commands:"
echo " start-xonotic-server spin up a local Xonotic dedicated server"
echo " query-xonotic one-shot RCON query against the dev server"
echo " gen-exporter-config write a dev config.toml"
echo " xonotic-exporter serve dev-config.toml start the HTTP exporter"
echo ""
echo " Env overrides:"
echo " XONOTIC_PORT (default 26010)"
echo " XONOTIC_RCON_PASSWORD (default devpassword)"
echo " XONOTIC_DATADIR (default .xonotic-data/)"
echo ""
'';
};
}
);
}