#!/usr/bin/env bash set -euo pipefail log() { printf '[asa-api] %s\n' "$*" >&2 } proxy_url="${ASA_PROXY:-socks5h://127.0.0.1:9050}" proxy_without_scheme="${proxy_url#*://}" proxy_host_port="${proxy_without_scheme%%/*}" proxy_host="${proxy_host_port%:*}" proxy_port="${proxy_host_port##*:}" if [[ -z "${proxy_host}" || "${proxy_host}" == "${proxy_host_port}" ]]; then proxy_host="127.0.0.1" fi if [[ "${proxy_host}" != "127.0.0.1" && "${proxy_host}" != "localhost" ]]; then log "ASA_PROXY must target a local Tor SOCKS listener. Got: ${proxy_url}" exit 1 fi if ! [[ "${proxy_port}" =~ ^[0-9]+$ ]]; then log "ASA_PROXY must include a numeric port. Got: ${proxy_url}" exit 1 fi control_port="${TOR_CONTROL_PORT:-9051}" if ! [[ "${control_port}" =~ ^[0-9]+$ ]]; then log "TOR_CONTROL_PORT must be numeric. Got: ${control_port}" exit 1 fi tor_root="/tmp/tor" tor_data_dir="${tor_root}/data" tor_cookie_path="${ASA_TOR_CONTROL_COOKIE:-${tor_root}/control.authcookie}" tor_pid_path="${tor_root}/tor.pid" torrc_path="${tor_root}/torrc" tor_probe_url="${ASA_TOR_PROBE_URL:-https://check.torproject.org/api/ip}" tor_startup_timeout="${ASA_TOR_STARTUP_TIMEOUT_SEC:-90}" if ! [[ "${tor_startup_timeout}" =~ ^[0-9]+$ ]]; then log "ASA_TOR_STARTUP_TIMEOUT_SEC must be numeric. Got: ${tor_startup_timeout}" exit 1 fi install -d -m 700 "${tor_root}" "${tor_data_dir}" "$(dirname "${tor_cookie_path}")" rm -f "${tor_pid_path}" "${tor_cookie_path}" cat > "${torrc_path}" <"/dev/tcp/${host}/${port}") >/dev/null 2>&1 } wait_for_tor() { local started_at now started_at="$(date +%s)" while true; do if ! kill -0 "${tor_pid}" 2>/dev/null; then wait "${tor_pid}" || true log "Tor exited before startup completed" exit 1 fi if curl --silent --show-error --fail --max-time 15 \ --proxy "${proxy_url}" \ "${tor_probe_url}" > "${tor_probe_file}" 2> "${tor_probe_error_file}"; then if grep -Eq '"IsTor"[[:space:]]*:[[:space:]]*true' "${tor_probe_file}"; then if [[ -r "${tor_cookie_path}" ]] && port_open "127.0.0.1" "${control_port}"; then return 0 fi fi fi now="$(date +%s)" if (( now - started_at >= tor_startup_timeout )); then log "Timed out waiting for Tor readiness" if [[ -s "${tor_probe_error_file}" ]]; then log "Last probe error: $(tail -n 1 "${tor_probe_error_file}")" fi if [[ -s "${tor_probe_file}" ]]; then log "Last probe body: $(tr -d '\n' < "${tor_probe_file}")" fi exit 1 fi sleep 1 done } wait_for_tor export ASA_PROXY="${proxy_url}" export TOR_CONTROL_PORT="${control_port}" export ASA_TOR_CONTROL_COOKIE="${tor_cookie_path}" log "Tor ready; starting API on port ${PORT:-7860}" exec Rscript -e 'pr <- plumber::plumb("R/plumber.R"); pr$run(host = "0.0.0.0", port = as.integer(Sys.getenv("PORT", "7860")))'