App 2.41.0, server 2.9.0: recordings reach the server

A finished signal recording goes to an outbox and is sent gzipped with
the car's token (PUT /v1/logs/{name}); the service retries every 2
minutes while the car is offline. The server keeps the newest 200 on a
new volume (LOGS_DIR); reading takes a token of its own (LOGS_TOKEN).
fetch-logs in the dev shell fetches new ones into logs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
2026-10-27 10:22:40 +01:00
co-authored by Claude Opus 5.5
parent 16e6f349da
commit eebe840b6a
20 changed files with 840 additions and 13 deletions
+38 -1
View File
@@ -161,10 +161,46 @@
echo "Published $tag ($(basename "$apk") and .sha256) at $forge/$repo/releases/tag/$tag"
'';
};
# Fetches the files the car sent from its Logs tab (signal recordings) from the car
# server into logs/ (gitignored), those not there yet. Needs the server's LOGS_TOKEN,
# from $LOGS_TOKEN or ~/.config/nilsmg4/logs-token; sent in a header, never printed.
fetchLogs = pkgs.writeShellApplication {
name = "fetch-logs";
runtimeInputs = [ pkgs.curl pkgs.jq pkgs.coreutils pkgs.git ];
text = ''
server=''${SERVER_URL:-https://car.k8s.stinnesbeck.com}
token=''${LOGS_TOKEN:-}
if [ -z "$token" ] && [ -f "$HOME/.config/nilsmg4/logs-token" ]; then
token=$(tr -d '[:space:]' < "$HOME/.config/nilsmg4/logs-token")
fi
if [ -z "$token" ]; then
echo "fetch-logs: no token. Put the server's LOGS_TOKEN in ~/.config/nilsmg4/logs-token (or \$LOGS_TOKEN)." >&2
exit 1
fi
root=$(git rev-parse --show-toplevel)
mkdir -p "$root/logs"
auth=(-H "Authorization: Bearer $token")
fetched=0
while IFS= read -r name; do
# The server only stores such names; anything else is not a path to write to.
if ! [[ "$name" =~ ^[a-z0-9][a-z0-9-]{0,79}\.txt$ ]]; then
echo "fetch-logs: skipping an unexpected name" >&2
continue
fi
[ -f "$root/logs/$name" ] && continue
curl -sSf "''${auth[@]}" -o "$root/logs/$name.part" "$server/v1/logs/$name"
mv "$root/logs/$name.part" "$root/logs/$name"
echo "logs/$name"
fetched=$((fetched + 1))
done < <(curl -sSf "''${auth[@]}" "$server/v1/logs" | jq -r '.logs[].name')
echo "fetch-logs: $fetched new"
'';
};
in
{
default = pkgs.mkShell {
packages = [ jdk android.androidsdk buildCar publishCar pkgs.go pkgs.gopls pkgs.govulncheck pkgs.influxdb2-server pkgs.influxdb2-cli ];
packages = [ jdk android.androidsdk buildCar publishCar fetchLogs pkgs.go pkgs.gopls pkgs.govulncheck pkgs.influxdb2-server pkgs.influxdb2-cli ];
ANDROID_HOME = sdk;
ANDROID_SDK_ROOT = sdk;
@@ -179,6 +215,7 @@
echo " ./gradlew assembleUnstableDebug # build that can update itself (OTA)"
echo " build-car # unstable build signed for the car"
echo " publish-car # publish it for the in-app updater"
echo " fetch-logs # the car's recordings from the server, into logs/"
'';
};
});