feat: add OpenList upload support and upload tasks monitoring page
Backend: - Add OpenListRecordArtifactUploader implementing AList-compatible API upload - Add Uploading status to RecordArtifactUploadStatus enum - Add MarkUploadStarted() to RecordResult entity for upload progress tracking - Add ListUploadStatus API endpoint with pagination and status filtering - Add UploadTaskItemDto and UploadTaskListResponse models - Add upload segment count stats (uploaded/failed/uploading) to session DTO - Add OpenListUploadSettingsDto and upload target type OpenList Frontend: - Add UploadTasksView page with route /upload-tasks - Add upload status labels and UploadTaskItem types - Refactor MainLayout navigation and clean up main.css - Polish DashboardView, MetricCard, StatusBadge, RightDrawer components - Update SettingsView to support OpenList upload configuration Build: - Add frontend/Dockerfile.arm64 for ARM64 frontend image - Update build-arm64-image.sh script Other: - Add segment_completed_openlist.sh trigger script - Add prototype/ directory with UI mockups - Add frontend .dockerignore refinements Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build the LiveRecorder WebApi image for linux/arm64 and export it as a
|
||||
# gzip-compressed `docker load`-able archive.
|
||||
# Build both the LiveRecorder WebApi and Frontend (nginx) images for
|
||||
# linux/arm64 and export them as a single gzip-compressed `docker load`-able
|
||||
# archive.
|
||||
#
|
||||
# The docker-compose.yml uses a split architecture:
|
||||
# nginx (frontend) — Vue SPA served by nginx, proxies /api/* to api:8080
|
||||
# api (backend) — .NET 8 WebApi
|
||||
#
|
||||
# Both images must be ARM64 for a full deployment on an ARM64 host.
|
||||
#
|
||||
# Target environment: Windows + Docker Desktop (WSL2 backend) + a host HTTP proxy.
|
||||
# It encodes the workarounds discovered while building from a network where the
|
||||
@@ -18,8 +25,9 @@
|
||||
# scripts/build-arm64-image.sh
|
||||
#
|
||||
# Override defaults via env vars:
|
||||
# PROXY=http://127.0.0.1:10808 IMAGE_TAG=live-recorder-webapi:arm64
|
||||
# OUTPUT=live-recorder-webapi-arm64.tar.gz WSL_DISTRO=Ubuntu
|
||||
# PROXY=http://127.0.0.1:10808
|
||||
# OUTPUT=live-recorder-arm64.tar.gz
|
||||
# WSL_DISTRO=Ubuntu
|
||||
set -euo pipefail
|
||||
|
||||
# --- Resolve repo root (script lives in <root>/scripts) ---
|
||||
@@ -30,30 +38,26 @@ cd "$ROOT_DIR"
|
||||
# --- Config ---
|
||||
PROXY="${PROXY:-http://127.0.0.1:10808}"
|
||||
PROXY_HOST="${PROXY_HOST:-http://host.docker.internal:${PROXY##*:}}" # container-visible proxy
|
||||
IMAGE_TAG="${IMAGE_TAG:-live-recorder-webapi:arm64}"
|
||||
OUTPUT="${OUTPUT:-live-recorder-webapi-arm64.tar.gz}"
|
||||
DOCKERFILE="${DOCKERFILE:-src/LiveRecorder.WebApi/Dockerfile}"
|
||||
API_IMAGE_TAG="${API_IMAGE_TAG:-live-recorder-webapi:arm64}"
|
||||
FRONTEND_IMAGE_TAG="${FRONTEND_IMAGE_TAG:-live-recorder-frontend:arm64}"
|
||||
OUTPUT="${OUTPUT:-live-recorder-arm64.tar.gz}"
|
||||
WSL_DISTRO="${WSL_DISTRO:-Ubuntu}"
|
||||
SDK_IMAGE="mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim"
|
||||
RUNTIME_IMAGE="mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim"
|
||||
DOTNET_SDK_IMAGE="mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim"
|
||||
DOTNET_RUNTIME_IMAGE="mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim"
|
||||
NGINX_IMAGE="${NGINX_IMAGE:-nginx:1.27-alpine}"
|
||||
NO_PROXY_HOSTS="mirrors.tuna.tsinghua.edu.cn,.tsinghua.edu.cn,localhost,127.0.0.1"
|
||||
|
||||
log() { printf '\n\033[1;36m[%s] %s\033[0m\n' "$(date +%H:%M:%S)" "$*"; }
|
||||
die() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
|
||||
|
||||
# --- 1. Ensure ARM64 emulation works -----------------------------------------
|
||||
# binfmt_misc lives in the (shared) WSL2 kernel and is lost on `wsl --shutdown`/reboot,
|
||||
# so this is idempotent and re-runs the registration whenever emulation is missing.
|
||||
ensure_arm64_emulation() {
|
||||
if docker run --rm --platform linux/arm64 "$RUNTIME_IMAGE" uname -m 2>/dev/null | grep -q aarch64; then
|
||||
if docker run --rm --platform linux/arm64 "$DOTNET_RUNTIME_IMAGE" uname -m 2>/dev/null | grep -q aarch64; then
|
||||
log "ARM64 emulation already works — skipping binfmt registration."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Registering qemu-aarch64 emulation via the '$WSL_DISTRO' WSL distro..."
|
||||
# Install the statically-linked emulator inside the distro, then re-register it pointing
|
||||
# directly at the static binary with the F (fix-binary) flag — the kernel opens the
|
||||
# interpreter at registration time so the held fd works inside Docker build containers.
|
||||
wsl.exe -d "$WSL_DISTRO" -u root -- bash -lc '
|
||||
set -e
|
||||
if [ ! -x /usr/bin/qemu-aarch64-static ]; then
|
||||
@@ -67,7 +71,7 @@ ensure_arm64_emulation() {
|
||||
> /proc/sys/fs/binfmt_misc/register
|
||||
' || die "binfmt registration failed (need a Debian/Ubuntu WSL distro named '$WSL_DISTRO' with apt)."
|
||||
|
||||
docker run --rm --platform linux/arm64 "$RUNTIME_IMAGE" uname -m 2>/dev/null | grep -q aarch64 \
|
||||
docker run --rm --platform linux/arm64 "$DOTNET_RUNTIME_IMAGE" uname -m 2>/dev/null | grep -q aarch64 \
|
||||
|| die "ARM64 emulation still not working after registration."
|
||||
log "ARM64 emulation registered and verified."
|
||||
}
|
||||
@@ -85,33 +89,53 @@ pull_with_retry() {
|
||||
docker image inspect "$img" >/dev/null 2>&1 || die "Could not pull $img (network)."
|
||||
}
|
||||
|
||||
# --- 3. Build ----------------------------------------------------------------
|
||||
build_image() {
|
||||
log "Building $IMAGE_TAG for linux/arm64 (restore via proxy, apt via mirror)..."
|
||||
# --- 3. Build API image ------------------------------------------------------
|
||||
build_api_image() {
|
||||
log "Building $API_IMAGE_TAG for linux/arm64 (restore via proxy, apt via mirror)..."
|
||||
docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
-f "$DOCKERFILE" \
|
||||
-t "$IMAGE_TAG" \
|
||||
-f src/LiveRecorder.WebApi/Dockerfile \
|
||||
-t "$API_IMAGE_TAG" \
|
||||
--build-arg "HTTP_PROXY=$PROXY_HOST" \
|
||||
--build-arg "HTTPS_PROXY=$PROXY_HOST" \
|
||||
--build-arg "NO_PROXY=$NO_PROXY_HOSTS" \
|
||||
--build-arg "DOTNET_SDK_IMAGE=$DOTNET_SDK_IMAGE" \
|
||||
--build-arg "DOTNET_RUNTIME_IMAGE=$DOTNET_RUNTIME_IMAGE" \
|
||||
--pull=false \
|
||||
--load \
|
||||
.
|
||||
}
|
||||
|
||||
# --- 4. Export + compress ----------------------------------------------------
|
||||
export_image() {
|
||||
log "Exporting $IMAGE_TAG -> $OUTPUT ..."
|
||||
# --- 4. Build Frontend (nginx) image -----------------------------------------
|
||||
# Frontend dist is pre-built locally (npm run build inside frontend/) and copied
|
||||
# directly — avoids running Node.js under QEMU ARM64 emulation which is prohibitively
|
||||
# slow. Build context is frontend/ (not repo root) to bypass .dockerignore rules.
|
||||
build_frontend_image() {
|
||||
log "Building $FRONTEND_IMAGE_TAG for linux/arm64 (pre-built dist -> nginx)..."
|
||||
docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
-f frontend/Dockerfile.arm64 \
|
||||
-t "$FRONTEND_IMAGE_TAG" \
|
||||
--pull=false \
|
||||
--load \
|
||||
frontend
|
||||
}
|
||||
|
||||
# --- 5. Export both images as a single archive -------------------------------
|
||||
export_images() {
|
||||
log "Exporting $API_IMAGE_TAG + $FRONTEND_IMAGE_TAG -> $OUTPUT ..."
|
||||
local tar="${OUTPUT%.gz}"
|
||||
docker save "$IMAGE_TAG" -o "$tar"
|
||||
docker save "$API_IMAGE_TAG" "$FRONTEND_IMAGE_TAG" -o "$tar"
|
||||
gzip -f "$tar"
|
||||
log "Done: $(ls -lh "$OUTPUT" | awk '{print $5, $9}')"
|
||||
log "Load on an arm64 host with: docker load < $OUTPUT"
|
||||
log "Then start with: docker compose up -d"
|
||||
}
|
||||
|
||||
ensure_arm64_emulation
|
||||
pull_with_retry "$SDK_IMAGE"
|
||||
pull_with_retry "$RUNTIME_IMAGE"
|
||||
build_image
|
||||
export_image
|
||||
pull_with_retry "$DOTNET_SDK_IMAGE"
|
||||
pull_with_retry "$DOTNET_RUNTIME_IMAGE"
|
||||
pull_with_retry "$NGINX_IMAGE"
|
||||
build_api_image
|
||||
build_frontend_image
|
||||
export_images
|
||||
|
||||
Reference in New Issue
Block a user