#!/bin/sh
set -eu

usage() {
  echo "usage: novij-storage-edge-backend render" >&2
  exit 2
}

die() {
  echo "novij-storage-edge-backend: $*" >&2
  exit 1
}

valid_target() {
  case "$1" in
    ""|*[!A-Za-z0-9.:-]*) return 1 ;;
    *) return 0 ;;
  esac
}

valid_port() {
  case "$1" in
    ""|*[!0-9]*) return 1 ;;
  esac
  [ "$1" -ge 1 ] && [ "$1" -le 65535 ]
}

valid_domain() {
  case "$1" in
    ""|*[!A-Za-z0-9.-]*) return 1 ;;
    *) return 0 ;;
  esac
}

[ "${1:-}" = "render" ] || usage

active_slot_file=${NOVIJ_STORAGE_EDGE_ACTIVE_SLOT_FILE:-/etc/novij/storage/active-slot}
target_host=${NOVIJ_STORAGE_EDGE_TARGET_HOST:-172.19.0.1}
blue_ws_port=${NOVIJ_STORAGE_EDGE_BLUE_WS_PORT:-38991}
green_ws_port=${NOVIJ_STORAGE_EDGE_GREEN_WS_PORT:-38994}
status_port=${NOVIJ_STORAGE_EDGE_STATUS_PORT:-38993}
admin_port=${NOVIJ_STORAGE_EDGE_ADMIN_PORT:-38996}
domain=${NOVIJ_STORAGE_DOMAIN:-}
output=${NOVIJ_STORAGE_EDGE_OUTPUT:-/opt/novij-mail/traefik/dynamic/novij-storage-backend.yml}

valid_target "$target_host" || die "NOVIJ_STORAGE_EDGE_TARGET_HOST is invalid"
valid_port "$blue_ws_port" || die "NOVIJ_STORAGE_EDGE_BLUE_WS_PORT is invalid"
valid_port "$green_ws_port" || die "NOVIJ_STORAGE_EDGE_GREEN_WS_PORT is invalid"
valid_port "$status_port" || die "NOVIJ_STORAGE_EDGE_STATUS_PORT is invalid"
valid_port "$admin_port" || die "NOVIJ_STORAGE_EDGE_ADMIN_PORT is invalid"
valid_domain "$domain" || die "NOVIJ_STORAGE_DOMAIN is invalid"
case "$output" in /*) ;; *) die "NOVIJ_STORAGE_EDGE_OUTPUT must be an absolute path" ;; esac

active_slot=single
if [ -s "$active_slot_file" ]; then
  active_slot=$(tr -d '[:space:]' <"$active_slot_file")
fi
case "$active_slot" in
  single|legacy|blue) ws_port=$blue_ws_port ;;
  green) ws_port=$green_ws_port ;;
  *) die "active slot is invalid: $active_slot" ;;
esac

directory=${output%/*}
[ "$directory" != "$output" ] || die "NOVIJ_STORAGE_EDGE_OUTPUT has no directory"
mkdir -p "$directory"
temporary=$(mktemp "$directory/.novij-storage-edge.XXXXXX")
trap 'rm -f "$temporary"' EXIT HUP INT TERM

cat >"$temporary" <<EOF
http:
  routers:
    novij-storage-status:
      entryPoints: [websecure]
      rule: "Host(\`${domain}\`) && (Path(\`/.well-known/novij/status.json\`) || Path(\`/healthz\`) || Path(\`/readyz\`) || Path(\`/version\`) || PathPrefix(\`/sync/\`) || Path(\`/internal/storage-sync/v1\`))"
      priority: 200
      middlewares: [novij-protocol-security, novij-storage-http-rate, novij-storage-inflight]
      service: novij-storage-status
      tls:
        certResolver: letsencrypt
  services:
    novij-storage-ws:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://${target_host}:${ws_port}"
    novij-storage-http:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://${target_host}:${admin_port}"
    novij-storage-status:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://${target_host}:${status_port}"
EOF

chmod 0640 "$temporary"
mv -f "$temporary" "$output"
trap - EXIT HUP INT TERM
echo "novij-storage-edge-backend: rendered $output for $active_slot"
