#!/usr/bin/env bash # Usage: ./scripts/fetch-year.sh YEAR [--reverse] # Fetches sequentially; prints JSON responses to stdout and errors to stderr. set -euo pipefail reverse=false year= for arg in "$@"; do case "$arg" in --reverse) reverse=true ;; *) if [[ -n $year ]]; then echo "Usage: $0 YEAR [--reverse]" >&2 exit 1 fi year=$arg ;; esac done if [[ -z $year ]]; then echo "Usage: $0 YEAR [--reverse]" >&2 exit 1 fi if [[ ! $year =~ ^[0-9]{4}$ || $year == 0000 ]]; then echo "YEAR must be a four-digit year from 0001 to 9999." >&2 exit 1 fi year_number=$((10#$year)) days_in_month=(31 28 31 30 31 30 31 31 30 31 30 31) if (( year_number % 400 == 0 || (year_number % 4 == 0 && year_number % 100 != 0) )); then days_in_month[1]=29 fi # Reuse a reachable service, or keep a port-forward alive while fetching. service_ready() { curl --fail --silent --output /dev/null --connect-timeout 1 --max-time 2 \ 'http://localhost:4101/api/health' } forward_pid= cleanup() { if [[ -n $forward_pid ]]; then kill "$forward_pid" 2>/dev/null || true wait "$forward_pid" 2>/dev/null || true forward_pid= fi } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM wait_for_pod() { local selector # Use the service's selector rather than assuming a particular pod label. if ! selector=$(kubectl -n sejs get svc btcdata --request-timeout=10s \ -o go-template='{{range $key, $value := .spec.selector}}{{$key}}={{$value}},{{end}}'); then return 1 fi selector=${selector%,} if [[ -z $selector ]]; then echo "Service sejs/btcdata has no pod selector." >&2 return 1 fi echo "Waiting up to 5 minutes for btcdata pods to become Ready..." >&2 kubectl -n sejs wait --for=condition=Ready pod --selector="$selector" \ --timeout=300s --request-timeout=310s >&2 } start_forward() { local attempt cleanup if ! command -v kubectl >/dev/null 2>&1; then echo "Service unavailable on localhost:4101 and kubectl is not installed." >&2 return 1 fi if ! wait_for_pod; then echo "btcdata pod readiness check failed; not opening a tunnel." >&2 return 1 fi echo "Starting kubectl port-forward for sejs/btcdata..." >&2 kubectl -n sejs port-forward svc/btcdata 4101:4101 >&2 & forward_pid=$! for (( attempt = 0; attempt < 30; attempt++ )); do if ! kill -0 "$forward_pid" 2>/dev/null; then echo "Port-forward exited before the service became ready." >&2 cleanup return 1 fi if service_ready; then return 0 fi sleep 1 done echo "Timed out waiting for the service on localhost:4101." >&2 cleanup return 1 } ensure_service() { local retry if service_ready; then return 0 fi for (( retry = 1; retry <= 3; retry++ )); do echo "Recovering port-forward (attempt $retry/3)..." >&2 if start_forward; then return 0 fi if (( retry < 3 )); then sleep 2 fi done echo "Unable to restore the service on localhost:4101." >&2 return 1 } fetch_date() { curl --fail --silent --show-error --connect-timeout 5 -X GET \ "http://localhost:4101/api/price/day/$1" \ -H "accept: application/json" --write-out '\n' } ensure_service || exit 1 # Generate dates without relying on platform-specific date command options. status=0 for (( month_index = 0; month_index < 12; month_index++ )); do month=$((month_index + 1)) if [[ $reverse == true ]]; then month=$((12 - month_index)) fi days=${days_in_month[month - 1]} for (( day_index = 0; day_index < days; day_index++ )); do day=$((day_index + 1)) if [[ $reverse == true ]]; then day=$((days - day_index)) fi printf -v date '%s-%02d-%02d' "$year" "$month" "$day" if ! fetch_date "$date"; then if ! service_ready; then ensure_service || exit 1 echo "Retrying $date after tunnel recovery..." >&2 if fetch_date "$date"; then continue fi fi echo "Failed to fetch $date" >&2 status=1 fi done done exit "$status"