#!/usr/bin/env bash set -euo pipefail # ANSI color codes for pretty output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' BOLD='\033[1m' NC='\033[0m' # No Color # Global cleanup function to handle error conditions and graceful exit cleanup() { # Restore strict error checking set -e # Remove any temporary files if needed # Add any necessary cleanup operations here # The exit status passed to the function exit $1 } # Set up trap to call cleanup function on script exit or interruptions trap 'cleanup $?' EXIT trap 'cleanup 1' INT TERM # Function to print colorful messages echo_info() { printf "${BLUE}[INFO]${NC} %s\n" "$1" } echo_success() { printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } echo_warning() { printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } echo_error() { printf "${RED}[ERROR]${NC} %s\n" "$1" } show_banner() { printf "${BLUE}${BOLD}\n" printf "\n" printf " # \n" printf " # # # #### ##### ## # # \n" printf " # # # # # # # # # # \n" printf " # # # #### # # # # # \n" printf " # # # # # ##### ###### # \n" printf " # # # # # # # # # # \n" printf " ##### #### #### # # # # \n" printf "\n" printf "\n" printf " # # # # ##### ###### ##### #### # # # ##### #### # # \n" printf " # # # # # # # # # # # # # # # # # # \n" printf " # # # # # ##### # # #### # # # # # ###### \n" printf " ####### # ##### # ##### # # ## # # # # # # \n" printf " # # # # # # # # # ## ## # # # # # # \n" printf " # # # # ###### # # #### # # # # #### # # \n" printf "\n" sleep 1 printf "${NC}\n" printf "🚀 ${BLUE}One-Click Docker Setup${NC} 🚀\n" } # Detect Docker Compose version detect_docker_compose() { # Check Docker or Podman if command -v docker &> /dev/null; then CONTAINER_ENGINE="docker" echo_success "Docker is installed." echo "" elif command -v podman &> /dev/null; then CONTAINER_ENGINE="podman" echo_success "Podman is installed." echo "" else echo_error "Neither Docker nor Podman is installed. Please install one of them to proceed." echo_info "Visit https://docs.docker.com/get-docker/ or https://podman.io/docs/installation for installation instructions." echo_info "After installation, re-run this script: scripts/setup.sh" echo "" exit 1 fi # Check Docker Compose or Podman Compose if $CONTAINER_ENGINE compose version &> /dev/null; then DOCKER_COMPOSE="$CONTAINER_ENGINE compose" echo_success "Compose is installed for $CONTAINER_ENGINE." echo "" else echo_error "Compose is not installed for $CONTAINER_ENGINE. Please install $CONTAINER_ENGINE compose to proceed." echo "" if [ "$CONTAINER_ENGINE" = "docker" ]; then echo_info "Visit https://docs.docker.com/compose/install/ for installation instructions." echo "" elif [ "$CONTAINER_ENGINE" = "podman" ]; then echo_info "Visit https://podman-desktop.io/docs/compose/setting-up-compose for installation instructions." echo "" fi echo_info "After installation, re-run this script: scripts/setup.sh" echo "" exit 1 fi } check_prerequisites() { # Check curl if ! command -v curl &> /dev/null; then echo_error "curl is not installed. Please install curl to proceed." echo "" exit 1 fi echo_success "curl is installed." echo "" # Check ports required_ports=(8080 9000 9050 5432 6379 9060) unavailable_ports=() for port in "${required_ports[@]}"; do if command -v nc &> /dev/null; then if nc -z localhost "$port" 2>/dev/null; then unavailable_ports+=("$port") fi elif command -v lsof &> /dev/null; then if lsof -i :"$port" &> /dev/null; then unavailable_ports+=("$port") fi else echo_warning "Neither nc nor lsof available to check ports. Skipping port check." echo "" break fi done if [ ${#unavailable_ports[@]} -ne 0 ]; then echo_warning "The following ports are already in use: ${unavailable_ports[*]}" echo_warning "This might cause conflicts with Hyperswitch services." echo "" echo -n "Do you want to continue anyway? (y/n): " read -n 1 -r REPLY echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi else echo "" fi } setup_config() { if [ ! -f "config/docker_compose.toml" ]; then echo_error "Configuration file 'config/docker_compose.toml' not found. Please ensure the file exists and is correctly configured." exit 1 fi } select_profile() { printf "\n" printf "Select a setup option:\n" printf "1) ${YELLOW}Standard Setup${NC}: ${BLUE}[Recommended]${NC} Ideal for quick trial.\n" printf " Services included: ${BLUE}App Server, Control Center, PostgreSQL and Redis${NC}\n" printf "\n" printf "2) ${YELLOW}Full Stack Setup${NC}: Ideal for comprehensive end-to-end payment testing.\n" printf " Services included: ${BLUE}Everything in Standard, Monitoring and Scheduler${NC}\n" printf "\n" printf "3) ${YELLOW}Standalone App Server${NC}: Ideal for API-first integration testing.\n" printf " Services included: ${BLUE}App Server, PostgreSQL and Redis)${NC}\n" echo "" local profile_selected=false while [ "$profile_selected" = false ]; do echo -n "Enter your choice (1-3): " read -n 1 profile_choice echo case $profile_choice in 1) PROFILE="standard" profile_selected=true ;; 2) PROFILE="full" profile_selected=true ;; 3) PROFILE="standalone" profile_selected=true ;; *) echo_error "Invalid choice. Please enter 1, 2, or 3." ;; esac done echo "Selected setup: $PROFILE" } start_services() { case $PROFILE in standalone) $DOCKER_COMPOSE up -d pg redis-standalone migration_runner hyperswitch-server ;; standard) $DOCKER_COMPOSE up -d ;; full) $DOCKER_COMPOSE --profile scheduler --profile monitoring --profile olap --profile full_setup up -d ;; esac } check_services_health() { # Wait for the hyperswitch-server to be healthy MAX_RETRIES=30 RETRY_INTERVAL=5 RETRIES=0 while [ $RETRIES -lt $MAX_RETRIES ]; do response=$(curl -s -w "\\nStatus_Code:%{http_code}" http://localhost:8080/health) status_code=$(echo "$response" | grep "Status_Code:" | cut -d':' -f2) response_body=$(echo "$response" | head -n1) if [ "$status_code" = "200" ] && [ "$response_body" = "health is good" ]; then print_access_info return fi RETRIES=$((RETRIES+1)) if [ $RETRIES -eq $MAX_RETRIES ]; then printf "\n" echo_error "${RED}${BOLD}Hyperswitch server did not become healthy in the expected time." printf "Check logs with: $DOCKER_COMPOSE logs hyperswitch-server, Or reach out to us on slack(https://hyperswitch-io.slack.com/) for help.\n" printf "\n" else printf "Waiting for server to become healthy... (%d/%d)\n" $RETRIES $MAX_RETRIES sleep $RETRY_INTERVAL fi done } configure_account() { # Temporarily disable strict error checking to prevent premature exit set +e local show_credentials_flag=false BASE_URL="http://localhost:8080" EMAIL="demo@hyperswitch.com" PASSWORD="Hyperswitch@123" # Initialize merchant_id and profile_id to empty strings merchant_id="" profile_id="" # Function to make API calls with proper headers make_api_call() { local method=$1 local endpoint=$2 local data=$3 local auth_header=${4:-} # Ensure endpoint starts with /user if it doesn't already if [[ ! $endpoint =~ ^/user && ! $endpoint =~ ^/health && ! $endpoint =~ ^/accounts && ! $endpoint =~ ^/account ]]; then endpoint="/user$endpoint" fi local headers=(-H "Content-Type: application/json" -H "api-key: hyperswitch" -H "User-Agent: HyperSwitch-Shell-Client/1.0" -H "Referer: http://localhost:9000/") if [ -n "$auth_header" ]; then headers+=(-H "authorization: Bearer $auth_header") fi if [ -n "$merchant_id" ]; then headers+=(-H "X-Merchant-Id: $merchant_id") fi if [ -n "$profile_id" ]; then headers+=(-H "X-Profile-Id: $profile_id") fi local curl_cmd if [ "$method" = "GET" ]; then curl_cmd=(curl -s -X "$method" "${headers[@]}" "$BASE_URL$endpoint") else curl_cmd=(curl -s -X "$method" "${headers[@]}" -d "$data" "$BASE_URL$endpoint") fi local retries=3 local i=0 while [ $i -lt $retries ]; do response=$("${curl_cmd[@]}") local response_code=$("${curl_cmd[@]}" -o /dev/null -s -w "%{http_code}") if [ $response_code -lt 400 ]; then echo "$response" return 0 fi i=$((i+1)) done return 1 } # Test the health endpoint first to ensure the API is responsive health_response=$(curl -s -w "\\nStatus_Code:%{http_code}" "$BASE_URL/health") health_status_code=$(echo "$health_response" | grep "Status_Code:" | cut -d':' -f2) health_response_body=$(echo "$health_response" | head -n1) # Try signin first signin_payload="{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" signin_response=$(make_api_call "POST" "/signin" "$signin_payload") status_code=$? # Check if user needs to be created if [[ $status_code -ne 0 || $(echo "$signin_response" | grep -q "error"; echo $?) -eq 0 ]]; then # User doesn't exist or login failed, create new account signup_payload="{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\",\"country\":\"IN\"}" # Only try signing up once - using exact headers from browser # For making signup request without verbose logging signup_cmd="curl -s -X POST '$BASE_URL/user/signup' \ -H 'Accept: */*' \ -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \ -H 'Content-Type: application/json' \ -H 'Origin: http://localhost:9000' \ -H 'Referer: http://localhost:9000/' \ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36' \ -H 'api-key: hyperswitch' \ -d '$signup_payload'" signup_response=$(eval "$signup_cmd") # Extract token from signup response token=$(echo "$signup_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) token_type=$(echo "$signup_response" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4) if [ -n "$token" ]; then show_credentials_flag=true fi is_new_user=true else auth_response="$signin_response" token=$(echo "$auth_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) token_type=$(echo "$auth_response" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4) if [ -n "$token" ]; then show_credentials_flag=true fi is_new_user=false fi # Handle 2FA if needed if [ "$token_type" = "totp" ]; then MAX_RETRIES=3 for i in $(seq 1 $MAX_RETRIES); do terminate_response=$(curl -s -X GET -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer $token" "$BASE_URL/user/2fa/terminate?skip_two_factor_auth=true") new_token=$(echo "$terminate_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) if [ -n "$new_token" ]; then token="$new_token" break else if [ $i -lt $MAX_RETRIES ]; then sleep 1 fi fi done fi # Get user info if [ -n "$token" ]; then user_info_cmd="curl -s -X GET -H 'Content-Type: application/json' -H 'api-key: hyperswitch' -H 'authorization: Bearer $token' '$BASE_URL/user'" user_info=$(eval "$user_info_cmd") else user_info="{}" fi merchant_id=$(echo "$user_info" | grep -o '"merchant_id":"[^"]*"' | cut -d'"' -f4 || echo "") profile_id=$(echo "$user_info" | grep -o '"profile_id":"[^"]*"' | cut -d'"' -f4 || echo "") # Configure account for new users if [ "$is_new_user" = true ] && [ -n "$merchant_id" ] && [ -n "$token" ]; then # Create merchant account merchant_payload="{\"merchant_id\":\"$merchant_id\",\"merchant_name\":\"Test\"}" merchant_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer $token" -d "$merchant_payload" "$BASE_URL/accounts/$merchant_id") # Configure connector connector_payload=$(cat <