# syntax=docker/dockerfile:1

# Gebaut wird auf der Architektur des Bauwirts, übersetzt wird für die des
# Ziels — `dotnet publish -a` kann das. Ohne diese Trennung liefe der Bau für
# arm64 unter Emulation und dauerte ein Vielfaches.
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG TARGETARCH
WORKDIR /src

# Erst die Projektdateien, dann wiederherstellen: so bleibt die
# Paket-Wiederherstellung in der Ebenenzwischenablage, solange sich keine
# Abhängigkeit ändert. Ohne diesen Schritt lädt jeder Bau alles neu.
# `--parents` behält die Verzeichnisse bei. **Ein Muster statt einer Liste**,
# weil eine Liste bei jedem neuen Projekt vergessen wird — und dann scheitert
# erst der Bau im Container, nicht der auf dem Arbeitsrechner.
COPY --parents src/*/*.csproj ./
RUN dotnet restore src/Halo.Api/Halo.Api.csproj -a $TARGETARCH

COPY . .
RUN dotnet publish src/Halo.Api/Halo.Api.csproj -a $TARGETARCH -c Release -o /app --no-restore


FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime

# ffmpeg und die Treiber für Hardware-Beschleunigung.
#
# **Als eigenes Programm, nicht als Bibliothek.** Halo ruft es als Prozess
# auf; damit bleiben die Lizenzen getrennt (ffmpeg steht unter GPL) und ein
# Absturz dort nimmt den Server nicht mit.
#
# `mesa-va-drivers` bedient AMD und ältere Intel, `intel-media-va-driver` die
# neueren Intel — beide über VAAPI an `/dev/dri`. Welcher greift, entscheidet
# sich zur Laufzeit danach, was durchgereicht wurde.
#
# **Die Intel-Treiber nur auf amd64.** Es gibt sie für arm64 nicht, und ein
# unbedingtes `apt-get install` liess den Bau dort mit Code 100 abbrechen —
# eine Meldung, die nicht verrät, welches der sechs Pakete fehlt.
ARG TARGETARCH
RUN apt-get update \
 && apt-get install -y --no-install-recommends \
      ffmpeg libva2 libva-drm2 mesa-va-drivers \
 && if [ "$TARGETARCH" = "amd64" ]; then \
      apt-get install -y --no-install-recommends intel-media-va-driver i965-va-driver; \
    fi \
 && rm -rf /var/lib/apt/lists/*

# **Die Verzeichnisse müssen hier angelegt werden, nicht erst beim Start.**
# Docker legt den Einhängepunkt eines frischen benannten Volumes sonst als
# `root` an und übernimmt für ein leeres Volume die Rechte aus dem Image —
# gibt es das Verzeichnis im Image nicht, erbt es `root:root`, und der erste
# Start scheitert für jeden, der kein Bind Mount benutzt.
RUN mkdir -p /config /cache /transcode && chown -R 1000:1000 /config /cache /transcode

# **Kein root.** Die Kennung 1000 ist die des ersten Benutzers auf fast jedem
# Linux und auf den üblichen NAS-Geräten — wessen Dateien anders gehören, setzt
# in der Compose-Datei `user: "<uid>:<gid>"`. Das ist Docker-Bordmittel und
# braucht weder ein Startskript noch root im Container.
USER 1000:1000

ENV HALO_DATA=/config \
    HALO_CACHE=/cache \
    HALO_TRANSCODE=/transcode \
    ASPNETCORE_URLS=http://+:8080 \
    DOTNET_gcServer=0

WORKDIR /app
COPY --from=build /app .

EXPOSE 8080
VOLUME ["/config", "/cache", "/transcode"]

ENTRYPOINT ["dotnet", "Halo.Api.dll"]
