#!/bin/bash
# Push new content-addressed resource bundles from the shared spool to R2
# (served through cdn.war3replays.com). Bundles are immutable: uploaded
# once, cached forever. A marker in <spool>/uploaded/ tells the relays a
# digest is CDN-backed, which lets them send 36-byte references instead
# of inline bundle bytes even to browsers that never saw the content.
#
# Runs from w3cs-bundle-upload.timer. Credentials: /etc/w3cs/rclone.conf
# (root-only; object-scoped R2 keys).
set -euo pipefail

SPOOL=/home/ubuntu/w3cs-lab/bundle-spool
MARK="$SPOOL/uploaded"
REMOTE=r2:war3replays/resource-bundle
mkdir -p "$MARK"

# Snapshot the pending set first: files that appear during the upload are
# handled by the next run, so a marker is never written for an unuploaded
# file.
shopt -s nullglob
pending=()
for file in "$SPOOL"/*.bundle; do
  digest=$(basename "$file" .bundle)
  [ -e "$MARK/$digest" ] || pending+=("$file")
done
[ ${#pending[@]} -eq 0 ] && exit 0

# Hard-link into a staging dir with the served object names (<digest>.bin;
# extensionless keys are never edge-cacheable) so one rclone invocation
# moves the whole batch.
staging=$(mktemp -d /tmp/w3cs-bundle-upload.XXXXXX)
trap 'rm -rf "$staging"' EXIT
for file in "${pending[@]}"; do
  ln "$file" "$staging/$(basename "$file" .bundle).bin"
done

rclone --config /etc/w3cs/rclone.conf copy "$staging" "$REMOTE" \
  --ignore-existing --transfers 8 --retries 2 \
  --header-upload "Cache-Control: public, max-age=31536000, immutable"

# rclone exited 0: every staged object is in R2. Mark them so the relays
# start referencing these digests.
for file in "${pending[@]}"; do
  touch "$MARK/$(basename "$file" .bundle)"
done
echo "uploaded ${#pending[@]} bundle(s)"

# Rebuild per-(profile, map) packs from the session digest manifests and
# publish them: pack objects are content-addressed (immutable, cached
# forever); the per-replay manifest JSONs are mutable pointers with a
# short TTL. Pack building is idempotent and cheap when nothing changed.
/usr/local/sbin/w3cs-pack-build.py
PACK_OUT="$SPOOL/pack-out"
if [ -d "$PACK_OUT" ]; then
  # sync (not copy): the builder garbage-collects superseded pack
  # generations locally after a 24 h grace, and sync propagates those
  # deletions so the bucket cannot accrete dead packs. Immutable objects
  # never re-upload (same size and time).
  rclone --config /etc/w3cs/rclone.conf sync "$PACK_OUT" \
    r2:war3replays/resource-bundle-packs/ \
    --include "*.zpack" --transfers 4 --retries 2 \
    --header-upload "Cache-Control: public, max-age=31536000, immutable"
  rclone --config /etc/w3cs/rclone.conf copy "$PACK_OUT" \
    r2:war3replays/resource-bundle-packs/ \
    --include "replay-*.json" --transfers 4 --retries 2 \
    --header-upload "Cache-Control: public, max-age=300"
fi
