#!/bin/bash PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" HTTPS_PROXY_PID_FILE="/tmp/sr-system-https-proxy.pid" BACKEND_LOG="/tmp/backend.log" FRONTEND_LOG="/tmp/frontend.log" # --- Helper functions --- # Wait until a given port is free (no LISTEN state). # Usage: wait_port_free # Returns 0 if free, 1 if timeout. wait_port_free() { local port=$1 local timeout=${2:-15} local waited=0 while [ $waited -lt $timeout ]; do if ! lsof -i :"$port" -P -n -s TCP:LISTEN >/dev/null 2>&1; then # Port is free — no LISTEN socket return 0 fi sleep 1 waited=$((waited + 1)) done # One last check if ! lsof -i :"$port" -P -n -s TCP:LISTEN >/dev/null 2>&1; then return 0 fi return 1 } # Wait until the backend health endpoint responds. # Usage: wait_backend_ready # Returns 0 if ready, 1 if timeout. wait_backend_ready() { local timeout=${1:-60} local waited=0 while [ $waited -lt $timeout ]; do if curl -sf http://localhost:8080/api/v1/health >/dev/null 2>&1; then return 0 fi # Also check if the JVM process is still alive sleep 2 waited=$((waited + 2)) done return 1 } # Kill all processes listening on a port, then wait for release. # Usage: stop_port stop_port() { local port=$1 local timeout=${2:-10} if lsof -ti:"$port" >/dev/null 2>&1; then kill -9 "$(lsof -ti:"$port")" 2>/dev/null || true wait_port_free "$port" "$timeout" || true return 0 fi return 1 } # Stop the Gradle daemon for the backend project. stop_gradle_daemon() { if [ -f "$PROJECT_DIR/backend/gradlew" ]; then cd "$PROJECT_DIR/backend" DB_PASSWORD='!Tp@rtner$' ./gradlew --stop >/dev/null 2>&1 || true fi } # --- Main commands --- case "${1:-}" in stop) echo "=== SR System - Stopping Services ===" if [ -f "$HTTPS_PROXY_PID_FILE" ]; then kill "$(cat "$HTTPS_PROXY_PID_FILE")" 2>/dev/null && echo " HTTPS proxy stopped." || true rm -f "$HTTPS_PROXY_PID_FILE" fi if stop_port 8080; then echo " Backend stopped." else echo " Backend not running." fi if lsof -ti:3000 >/dev/null 2>&1; then kill -9 "$(lsof -ti:3000)" 2>/dev/null echo " Frontend stopped." else echo " Frontend not running." fi if lsof -ti:3443 >/dev/null 2>&1; then kill -9 "$(lsof -ti:3443)" 2>/dev/null echo " HTTPS proxy stopped." fi echo " Stopping Gradle daemon..." stop_gradle_daemon echo "=== Done ===" exit 0 ;; restart) "$0" stop # Port and daemon are fully released after stop "$0" exit 0 ;; https) # Start services first "$0" 2>/dev/null echo "" CERT="$PROJECT_DIR/192.168.31.168+2.pem" KEY="$PROJECT_DIR/192.168.31.168+2-key.pem" if [ ! -f "$CERT" ]; then echo "SSL certificate not found. Creating..." mkcert 192.168.31.168 localhost 127.0.0.1 2>/dev/null echo " Cert created." echo "" echo " To trust on iPhone:" echo " 1. Open http://192.168.31.168:3000/192.168.31.168+2.pem in Safari" echo " 2. Download and install the profile" echo " 3. Settings → General → About → Certificate Trust Settings → Enable" fi echo "[3/3] Starting HTTPS proxy (WebSocket enabled)..." nohup node "$PROJECT_DIR/https-proxy.js" "$CERT" "$KEY" localhost 3000 3443 0.0.0.0 > /tmp/https-proxy.log 2>&1 & HTTPS_PID=$! echo "$HTTPS_PID" > "$HTTPS_PROXY_PID_FILE" echo " Waiting for HTTPS proxy..." for i in $(seq 1 5); do sleep 1 if curl -sk -o /dev/null https://192.168.31.168:3443/ 2>/dev/null; then break; fi done echo "" echo " iPhone: https://192.168.31.168:3443" echo "" echo " Note: iOS shows 'Not Secure'. Tap 'Show Details' -> 'Visit This Website'." echo " Camera works after accepting the certificate." exit 0 ;; esac echo "=== SR System - Starting Services ===" # ---- Backend ---- if lsof -ti:8080 >/dev/null 2>&1; then BACKEND_PID=$(lsof -ti:8080) echo "[1/2] Backend already running (PID: $BACKEND_PID)" else echo "[1/2] Starting Spring Boot backend..." # 1. Ensure port 8080 is fully released (handle TIME_WAIT from killed processes) if lsof -i :8080 -P -n >/dev/null 2>&1; then echo " Port 8080 in use — waiting for release..." kill -9 "$(lsof -ti:8080)" 2>/dev/null || true if ! wait_port_free 8080 15; then echo " ERROR: Port 8080 still bound after 15s. Aborting." exit 1 fi fi # 2. Stop any stale Gradle daemon (avoids "daemon already running" race) echo " Stopping any stale Gradle daemon..." stop_gradle_daemon # 3. Start backend via bootRun echo " Starting bootRun..." cd "$PROJECT_DIR/backend" DB_PASSWORD='!Tp@rtner$' nohup ./gradlew bootRun --no-daemon > "$BACKEND_LOG" 2>&1 & BACKEND_PID=$! echo " Backend PID: $BACKEND_PID" # 4. Wait for backend to become ready (up to 60s) echo " Waiting for backend on port 8080..." if wait_backend_ready 60; then echo " Backend ready!" else echo " Backend failed to start. Check $BACKEND_LOG" tail -30 "$BACKEND_LOG" 2>/dev/null || true exit 1 fi fi # ---- Frontend ---- if lsof -ti:3000 >/dev/null 2>&1; then FRONTEND_PID=$(lsof -ti:3000) echo "[2/2] Frontend already running (PID: $FRONTEND_PID)" else echo "[2/2] Starting Next.js frontend..." cd "$PROJECT_DIR" nohup npx next dev -H 0.0.0.0 -p 3000 > "$FRONTEND_LOG" 2>&1 & FRONTEND_PID=$! echo " Frontend PID: $FRONTEND_PID" sleep 3 fi echo "" echo "=== SR System is running ===" echo " Local: http://localhost:3000" echo " Network: http://192.168.31.168:3000" echo " Backend: http://localhost:8080" echo "" echo " For iPhone camera (HTTPS):" echo " ./start.sh https" echo "" echo "Commands:" echo " ./start.sh - Start services" echo " ./start.sh https - Start + HTTPS proxy (for iPhone camera)" echo " ./start.sh stop - Stop all services" echo " ./start.sh restart - Restart all services"