#!/usr/bin/env bash # Starts the whole app: game server, Vite client and the Aspire dashboard. # Skips MSBuild when AppHost and Server dlls are newer than C# / csproj / props. # ./run-aspire.sh # ./run-aspire.sh --launch-profile http # ./run-aspire.sh --rebuild # ./run-aspire.sh --no-tailscale set -euo pipefail cd "$(dirname "$0")" log() { echo "[run-aspire] $*" } skip_tailscale() { log "WARNING: $*" echo " Friends cannot reach the client over the tailnet." echo " Continuing with local access only (http://localhost:5173)." } # Same rules as tools/apphost-uptodate.ps1 and LaunchBuildStamp.cs. needs_build() { local tfm=net10.0 local apphost="src/HSchool.AppHost/bin/${configuration}/${tfm}/HSchool.AppHost.dll" local server="src/HSchool.Server/bin/${configuration}/${tfm}/HSchool.Server.dll" [[ -f "$apphost" && -f "$server" ]] || return 0 local oldest=$apphost [[ "$server" -ot "$apphost" ]] && oldest=$server local name for name in global.json Directory.Build.props Directory.Packages.props; do [[ -f "$name" && "$name" -nt "$oldest" ]] && return 0 done [[ -d src ]] || return 0 local found found=$(find src \( -name bin -o -name obj -o -name node_modules \) -prune -o \ -type f \( -name '*.cs' -o -name '*.csproj' -o -name '*.props' \) -newer "$oldest" -print -quit) [[ -n "$found" ]] } configuration=Debug rebuild=0 tailscale_serve=1 dotnet_args=() expect_configuration=0 while [[ $# -gt 0 ]]; do if [[ $expect_configuration -eq 1 ]]; then configuration=$1 expect_configuration=0 shift continue fi case $1 in --rebuild) rebuild=1 ;; --no-tailscale) tailscale_serve=0 ;; -c|--configuration) expect_configuration=1 ;; *) dotnet_args+=("$1") ;; esac shift done if [[ $expect_configuration -eq 1 ]]; then log "missing value for -c / --configuration." exit 1 fi if ! command -v dotnet >/dev/null; then log "dotnet SDK not found in PATH." echo " Install .NET 10: https://dotnet.microsoft.com/download" exit 1 fi if ! command -v node >/dev/null; then log "Node.js not found in PATH - the client resource will fail to start." echo " Install Node 22.12 or newer: https://nodejs.org" echo fi need_build=0 if [[ $rebuild -eq 1 ]]; then log "--rebuild: building." need_build=1 elif needs_build; then log "sources changed or binaries missing, building." need_build=1 else log "binaries are up to date, skipping build." fi if [[ $need_build -eq 1 ]]; then echo if ! dotnet build src/HSchool.AppHost/HSchool.AppHost.csproj -c "$configuration"; then echo log "build failed." exit 1 fi echo fi client_tailscale_url= if [[ $tailscale_serve -eq 1 ]]; then if ! command -v tailscale >/dev/null; then skip_tailscale "tailscale not found in PATH." elif ! tailscale status >/dev/null 2>&1; then skip_tailscale "tailscale is not connected or not running." else log "tailscale serve --bg 5173" if ! tailscale serve --bg 5173; then skip_tailscale "tailscale serve failed." else line=$(tailscale serve status 2>/dev/null | head -n 1 || true) token=${line%% *} case $token in https://*) client_tailscale_url=$token ;; esac fi fi echo fi log "Starting the Aspire AppHost. Press Ctrl+C to shut everything down." log "Client: http://localhost:5173" if [[ -n "$client_tailscale_url" ]]; then log "Client (Tailscale): $client_tailscale_url" fi echo set +e dotnet run --project src/HSchool.AppHost/HSchool.AppHost.csproj --no-build --no-restore -c "$configuration" "${dotnet_args[@]}" exit_code=$? set -e if [[ $exit_code -ne 0 ]]; then echo log "AppHost exited with code ${exit_code}." fi exit "$exit_code"