#!/bin/bash # LeCoffre Node - Script de lancement séquentiel avec progression # Lance les services dans l'ordre logique avec suivi de l'avancement set -e # Couleurs pour l'affichage RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Configuration START_TIME=$(date +%s) MAX_WAIT=300 # 5 minutes max par service # Fonction pour afficher un message avec timestamp print_message() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1" } # Fonction pour afficher la progression show_progress() { local current=$1 local total=$2 local service=$3 local percent=$((current * 100 / total)) echo -e "${CYAN}Progress: $current/$total ($percent%) - $service${NC}" } # Fonction pour afficher la progression détaillée show_detailed_progress() { local service_name=$1 echo -e "${CYAN}=== Detailed Progress ===${NC}" # Tor Bootstrap if docker ps --format '{{.Names}}' | grep -q "tor-proxy"; then local bootstrap_log=$(docker logs tor-proxy --tail 10 2>/dev/null | grep 'Bootstrapped' | tail -1 || echo "") if [ -n "$bootstrap_log" ]; then local progress=$(echo "$bootstrap_log" | grep -o '[0-9]\+%' | tail -1 || echo "0%") local stage=$(echo "$bootstrap_log" | grep -o '(.*)' | sed 's/[()]//g' || echo "starting") echo -e " ${YELLOW}Tor Bootstrap: $progress - $stage${NC}" else echo -e " ${YELLOW}Tor Bootstrap: Starting...${NC}" fi else echo -e " ${RED}Tor: Not running${NC}" fi # Bitcoin Signet if docker ps --format '{{.Names}}' | grep -q "bitcoin-signet"; then local info=$(docker exec bitcoin-signet bitcoin-cli -signet -conf=/etc/bitcoin/bitcoin.conf getblockchaininfo 2>/dev/null || echo '{}') local blocks=$(echo "$info" | jq -r '.blocks // 0' 2>/dev/null || echo "0") local headers=$(echo "$info" | jq -r '.headers // 0' 2>/dev/null || echo "0") local ibd=$(echo "$info" | jq -r '.initialblockdownload // false' 2>/dev/null || echo "true") local verification_progress=$(echo "$info" | jq -r '.verificationprogress // 0' 2>/dev/null || echo "0") if [ "$ibd" = "false" ] || [ "$blocks" -eq "$headers" ]; then echo -e " ${GREEN}Bitcoin Signet: Synced ($blocks blocks)${NC}" else local progress=$((blocks * 100 / headers)) local ver_percent=$(echo "$verification_progress * 100" | bc -l | cut -d. -f1 2>/dev/null || echo "0") echo -e " ${YELLOW}Bitcoin IBD: $blocks/$headers ($progress%) - Verification: $ver_percent%${NC}" fi else echo -e " ${RED}Bitcoin Signet: Not running${NC}" fi # BlindBit Oracle if docker ps --format '{{.Names}}' | grep -q "blindbit-oracle"; then local api_response=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8000/tweaks/1 2>/dev/null || echo "000") if [ "$api_response" = "200" ]; then echo -e " ${GREEN}BlindBit Oracle: Ready${NC}" else local scan_logs=$(docker logs blindbit-oracle --tail 5 2>/dev/null | grep -E "(scanning|scan|blocks|tweaks|processing)" | tail -1 || echo "") if [ -n "$scan_logs" ]; then echo -e " ${YELLOW}BlindBit Scan: $scan_logs${NC}" else echo -e " ${YELLOW}BlindBit: Starting...${NC}" fi fi else echo -e " ${RED}BlindBit Oracle: Not running${NC}" fi # SDK Relay if docker ps --format '{{.Names}}' | grep -q "sdk_relay"; then local ws_response=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8091/ 2>/dev/null || echo "000") if [ "$ws_response" = "200" ]; then echo -e " ${GREEN}SDK Relay: Ready${NC}" else local relay_logs=$(docker logs sdk_relay --tail 5 2>/dev/null | grep -E "(IBD|blocks|headers|waiting|scanning|connecting)" | tail -1 || echo "") if [ -n "$relay_logs" ]; then echo -e " ${YELLOW}SDK Relay Sync: $relay_logs${NC}" else echo -e " ${YELLOW}SDK Relay: Starting...${NC}" fi fi else echo -e " ${RED}SDK Relay: Not running${NC}" fi # URLs internes (Services Docker) echo -e "${CYAN}Internal URLs Status:${NC}" local internal_urls=( "http://localhost:8000/tweaks/1:BlindBit Oracle API" "http://localhost:8081/health:SDK Storage Health" "http://localhost:8091/:SDK Relay WebSocket" "http://localhost:8090/:SDK Relay HTTP" "http://localhost:3004/:LeCoffre Frontend" "http://localhost:3003/:IHM Client" "http://localhost:3005/api/health:Grafana Health" "http://localhost:3100/ready:Loki Health" "http://localhost:3006/api:Status API" ) for url_entry in "${internal_urls[@]}"; do local url="${url_entry%%:*}" local name="${url_entry##*:}" local response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$url" 2>/dev/null || echo "000") if [[ "$response" =~ ^(200|301|302|307|308)$ ]]; then echo -e " ${GREEN}$name: Accessible (HTTP $response)${NC}" else echo -e " ${YELLOW}$name: Not accessible (HTTP $response)${NC}" fi done # URLs publiques HTTPS echo -e "${CYAN}Public URLs Status:${NC}" local urls=( "https://dev4.4nkweb.com/status/:Status Page" "https://dev4.4nkweb.com/grafana/:Grafana Dashboard" "https://dev4.4nkweb.com/:Main Site" "https://dev4.4nkweb.com/lecoffre/:LeCoffre App" "https://dev4.4nkweb.com/lecoffre/login:LeCoffre Login" "https://dev4.4nkweb.com/lecoffre/authorized-client:Auth Callback" ) for url_entry in "${urls[@]}"; do local url="${url_entry%%:*}" local name="${url_entry##*:}" local response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$url" 2>/dev/null || echo "000") if [[ "$response" =~ ^(200|301|302|307|308)$ ]]; then echo -e " ${GREEN}$name: Accessible (HTTP $response)${NC}" else echo -e " ${YELLOW}$name: Not accessible (HTTP $response)${NC}" fi done # APIs externes echo -e "${CYAN}External APIs Status:${NC}" local api_urls=( "https://dev3.4nkweb.com/api/v1/health:Backend Health" "https://dev3.4nkweb.com/api/v1/status:Backend Status" ) for url_entry in "${api_urls[@]}"; do local url="${url_entry%%:*}" local name="${url_entry##*:}" local response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$url" 2>/dev/null || echo "000") if [ "$response" = "200" ]; then echo -e " ${GREEN}$name: Accessible (HTTP $response)${NC}" else echo -e " ${YELLOW}$name: Not accessible (HTTP $response)${NC}" fi done # Test API IdNot avec POST echo -e "${CYAN}Testing IdNot API:${NC}" local idnot_response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 -X POST \ -H "Content-Type: application/json" \ -d '{"next_url":"https://dev4.4nkweb.com/authorized-client"}' \ "https://dev3.4nkweb.com/api/v1/idnot/state" 2>/dev/null || echo "000") if [ "$idnot_response" = "200" ]; then echo -e " ${GREEN}IdNot State API: Accessible (HTTP $idnot_response)${NC}" else echo -e " ${YELLOW}IdNot State API: Not accessible (HTTP $idnot_response)${NC}" fi # URLs WebSocket publiques echo -e "${CYAN}WebSocket URLs Status:${NC}" local ws_urls=( "wss://dev3.4nkweb.com/ws/:Bootstrap Relay" ) for ws_entry in "${ws_urls[@]}"; do local ws_url="${ws_entry%%:*}" local ws_name="${ws_entry##*:}" # Test WebSocket avec timeout court local ws_test=$(timeout 3 wscat -c "$ws_url" --no-color 2>/dev/null && echo "connected" || echo "failed") if [ "$ws_test" = "connected" ]; then echo -e " ${GREEN}$ws_name: Connected${NC}" else echo -e " ${YELLOW}$ws_name: Not connected${NC}" fi done # Services externes (dépendances) echo -e "${CYAN}External Services Status:${NC}" local external_urls=( "https://mempool2.4nkweb.com/:Mempool Signet" "https://qual-connexion.idnot.fr/:IdNot Service" "https://qual-connexion.idnot.fr/IdPOAuth2/authorize/idnot_idp_v1:IdNot Auth" ) for url_entry in "${external_urls[@]}"; do local url="${url_entry%%:*}" local name="${url_entry##*:}" local response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$url" 2>/dev/null || echo "000") if [[ "$response" =~ ^(200|301|302|307|308)$ ]]; then echo -e " ${GREEN}$name: Accessible (HTTP $response)${NC}" else echo -e " ${YELLOW}$name: Not accessible (HTTP $response)${NC}" fi done echo -e "${CYAN}========================${NC}" } # Fonction pour attendre qu'un service soit healthy wait_for_healthy() { local service_name=$1 local max_wait=${2:-$MAX_WAIT} local wait_time=0 print_message "Waiting for $service_name to be healthy..." while [ $wait_time -lt $max_wait ]; do local status=$(docker inspect --format='{{.State.Health.Status}}' "$service_name" 2>/dev/null || echo "no-healthcheck") local running=$(docker inspect --format='{{.State.Running}}' "$service_name" 2>/dev/null || echo "false") if [ "$running" = "true" ] && [ "$status" = "healthy" ]; then echo -e "${GREEN}✓ $service_name is healthy${NC}" return 0 fi # Afficher la progression détaillée show_detailed_progress "$service_name" sleep 5 wait_time=$((wait_time + 5)) done echo -e "${RED}✗ Timeout waiting for $service_name${NC}" return 1 } # Fonction pour vérifier les variables d'environnement d'un service check_service_env() { local service_name=$1 local display_name=$2 print_message "Checking environment variables for $display_name..." # Vérifier que le fichier .env.master existe if [ ! -f "/home/debian/4NK_env/.env.master" ]; then echo -e "${RED}✗ Error: .env.master file not found${NC}" return 1 fi # Variables critiques par service case "$service_name" in "bitcoin") local critical_vars=("BITCOIN_RPC_USER" "BITCOIN_RPC_PASSWORD" "BITCOIN_RPC_PORT") ;; "blindbit") local critical_vars=("BLINDBIT_API_PORT" "BITCOIN_RPC_URL") ;; "sdk_relay") local critical_vars=("RELAY_PORT" "RELAY_HTTP_PORT" "STORAGE_URL") ;; "sdk_storage") local critical_vars=("STORAGE_PORT" "STORAGE_DATA_DIR") ;; "lecoffre-front") local critical_vars=("NEXT_PUBLIC_API_URL" "NEXT_PUBLIC_4NK_URL" "NEXT_PUBLIC_IDNOT_BASE_URL") ;; "ihm_client") local critical_vars=("VITE_API_URL" "VITE_4NK_URL" "VITE_RELAY_URL") ;; "grafana") local critical_vars=("GF_SECURITY_ADMIN_PASSWORD" "GF_DATABASE_TYPE") ;; "loki") local critical_vars=("LOKI_CONFIG_FILE" "LOKI_DATA_DIR") ;; "promtail") local critical_vars=("PROMTAIL_CONFIG_FILE" "LOKI_URL") ;; "status-api") local critical_vars=("STATUS_API_PORT" "STATUS_API_HOST") ;; *) echo -e "${YELLOW}⚠ No specific environment variables defined for $service_name${NC}" return 0 ;; esac # Vérifier chaque variable critique local missing_vars=() for var in "${critical_vars[@]}"; do if ! grep -q "^${var}=" /home/debian/4NK_env/.env.master; then missing_vars+=("$var") fi done if [ ${#missing_vars[@]} -eq 0 ]; then echo -e "${GREEN}✓ All critical environment variables present for $display_name${NC}" return 0 else echo -e "${RED}✗ Missing critical environment variables for $display_name:${NC}" for var in "${missing_vars[@]}"; do echo -e "${RED} - $var${NC}" done return 1 fi } # Fonction pour démarrer un service start_service() { local service_name=$1 local display_name=$2 # Vérifier les variables d'environnement avant de démarrer if ! check_service_env "$service_name" "$display_name"; then echo -e "${RED}✗ Environment check failed for $display_name. Continuing anyway...${NC}" fi print_message "Starting $display_name..." if ! docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml up -d "$service_name"; then echo -e "${YELLOW}⚠ Failed to start $display_name, continuing with next service...${NC}" return 0 fi # Attendre que le conteneur soit créé sleep 2 # Vérifier si le service a un healthcheck local has_healthcheck=$(docker inspect --format='{{.Config.Healthcheck}}' "$service_name" 2>/dev/null | grep -q "Test" && echo "true" || echo "false") if [ "$has_healthcheck" = "true" ]; then wait_for_healthy "$service_name" else # Pour les services sans healthcheck, attendre qu'ils soient running local wait_time=0 while [ $wait_time -lt 60 ]; do local running=$(docker inspect --format='{{.State.Running}}' "$service_name" 2>/dev/null || echo "false") if [ "$running" = "true" ]; then echo -e "${GREEN}✓ $display_name is running${NC}" break fi sleep 2 wait_time=$((wait_time + 2)) done fi } echo -e "${BLUE}========================================${NC}" echo -e "${BLUE} LeCoffre Node - Sequential Startup${NC}" echo -e "${BLUE}========================================${NC}" echo # Arrêter les services existants print_message "Stopping existing services..." docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml down --remove-orphans >/dev/null 2>&1 || true # Ordre de démarrage logique services=( "tor:Tor Proxy" "bitcoin:Bitcoin Signet" "blindbit:BlindBit Oracle" "sdk_storage:SDK Storage" "sdk_relay:SDK Relay" "lecoffre-front:LeCoffre Frontend" "ihm_client:IHM Client" "grafana:Grafana" "status-api:Status API" ) total_services=${#services[@]} current_service=0 # Démarrer les services dans l'ordre for service in "${services[@]}"; do current_service=$((current_service + 1)) service_name="${service%%:*}" display_name="${service##*:}" show_progress $current_service $total_services "$display_name" start_service "$service_name" "$display_name" echo done # Attendre un peu pour que tous les services se stabilisent print_message "Waiting for services to stabilize..." sleep 30 # Test complet des URLs echo -e "${BLUE}========================================${NC}" echo -e "${BLUE} Comprehensive URL Tests${NC}" echo -e "${BLUE}========================================${NC}" echo # Compteurs pour les tests d'URLs TOTAL_URLS=0 ACCESSIBLE_URLS=0 FAILED_URLS=0 # Fonction pour tester une URL avec comptage test_url_with_count() { local url="$1" local description="$2" local expected_codes="${3:-200}" local timeout="${4:-10}" TOTAL_URLS=$((TOTAL_URLS + 1)) print_message "Testing: $description" echo -e " ${CYAN}URL: $url${NC}" local response=$(curl -s -o /dev/null -w '%{http_code}' --max-time "$timeout" "$url" 2>/dev/null || echo "000") if [[ "$response" =~ ^($expected_codes)$ ]]; then echo -e " ${GREEN}✓${NC} Status: HTTP $response - Accessible" ACCESSIBLE_URLS=$((ACCESSIBLE_URLS + 1)) return 0 else echo -e " ${RED}✗${NC} Status: HTTP $response - Not accessible" FAILED_URLS=$((FAILED_URLS + 1)) return 1 fi } # Tests des URLs internes echo -e "${CYAN}=== URLs INTERNES (Services Docker) ===${NC}" # BlindBit Oracle API - Bug corrigé avec l'image fixed-source test_url_with_count "http://localhost:8000/tweaks/1" "BlindBit Oracle API" "200" 5 test_url_with_count "http://localhost:8081/health" "SDK Storage Health" "200" 5 test_url_with_count "http://localhost:8091/" "SDK Relay Health" "200" 5 test_url_with_count "http://localhost:3004/" "LeCoffre Frontend (root)" "200|301|302|307|308" 10 test_url_with_count "http://localhost:3004/login" "LeCoffre Frontend (login)" "200|301|302|307|308" 10 test_url_with_count "http://localhost:3004/lecoffre" "LeCoffre Frontend (app)" "200|301|302|307|308" 10 test_url_with_count "http://localhost:3003/" "IHM Client" "200" 10 test_url_with_count "http://localhost:3005/api/health" "Grafana Health" "200" 5 test_url_with_count "http://localhost:3005/" "Grafana Dashboard" "200|301|302" 10 test_url_with_count "http://localhost:3100/ready" "Loki Health" "200" 5 test_url_with_count "http://localhost:3006/api" "Status API" "200" 5 echo # Tests des URLs externes echo -e "${CYAN}=== URLs EXTERNES (Domaine Public) ===${NC}" test_url_with_count "https://dev4.4nkweb.com/" "Site Principal" "200|301|302" 15 test_url_with_count "https://dev4.4nkweb.com/status/" "Page de Statut" "200" 15 test_url_with_count "https://dev4.4nkweb.com/grafana/" "Dashboard Grafana" "200|301|302" 15 test_url_with_count "https://dev4.4nkweb.com/lecoffre/" "Application LeCoffre" "200|301|302" 15 test_url_with_count "https://dev4.4nkweb.com/lecoffre/login" "Login LeCoffre" "200|301|302" 15 test_url_with_count "https://dev4.4nkweb.com/lecoffre/authorized-client" "Callback d'authentification" "200|301|302" 15 echo # Tests des APIs externes echo -e "${CYAN}=== APIs EXTERNES (Backend Services) ===${NC}" test_url_with_count "https://dev3.4nkweb.com/api/v1/health" "API Backend Health" "200" 10 test_url_with_count "https://dev3.4nkweb.com/api/v1/status" "API Backend Status" "200" 10 # Test API IdNot avec POST print_message "Testing API POST: IdNot State Endpoint" echo -e " ${CYAN}URL: https://dev3.4nkweb.com/api/v1/idnot/state${NC}" echo -e " ${CYAN}Data: {\"next_url\":\"https://dev4.4nkweb.com/authorized-client\"}${NC}" TOTAL_URLS=$((TOTAL_URLS + 1)) local idnot_response=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 -X POST \ -H "Content-Type: application/json" \ -d '{"next_url":"https://dev4.4nkweb.com/authorized-client"}' \ "https://dev3.4nkweb.com/api/v1/idnot/state" 2>/dev/null || echo "000") if [ "$idnot_response" = "200" ]; then echo -e " ${GREEN}✓${NC} Status: HTTP $idnot_response - API accessible" ACCESSIBLE_URLS=$((ACCESSIBLE_URLS + 1)) else echo -e " ${RED}✗${NC} Status: HTTP $idnot_response - API not accessible" FAILED_URLS=$((FAILED_URLS + 1)) fi echo # Tests des WebSockets externes echo -e "${CYAN}=== WebSockets Externes ===${NC}" print_message "Testing WebSocket: Bootstrap Relay" echo -e " ${CYAN}URL: wss://dev3.4nkweb.com/ws/${NC}" TOTAL_URLS=$((TOTAL_URLS + 1)) local ws_test=$(timeout 5 wscat -c "wss://dev3.4nkweb.com/ws/" --no-color 2>/dev/null && echo "connected" || echo "failed") if [ "$ws_test" = "connected" ]; then echo -e " ${GREEN}✓${NC} Status: Connected" ACCESSIBLE_URLS=$((ACCESSIBLE_URLS + 1)) else echo -e " ${RED}✗${NC} Status: Not connected" FAILED_URLS=$((FAILED_URLS + 1)) fi echo # Tests des services externes echo -e "${CYAN}=== Services Externes (Dépendances) ===${NC}" test_url_with_count "https://mempool2.4nkweb.com/" "Mempool Signet" "200|301|302" 10 test_url_with_count "https://qual-connexion.idnot.fr/" "Service IdNot" "200|301|302" 10 test_url_with_count "https://qual-connexion.idnot.fr/IdPOAuth2/authorize/idnot_idp_v1" "IdNot Authorization" "200|301|302" 10 echo # Résumé final des tests d'URLs echo -e "${CYAN}=== RÉSUMÉ DES TESTS D'URLs ===${NC}" echo -e "${BLUE}Total URLs testées: $TOTAL_URLS${NC}" echo -e "${GREEN}URLs accessibles: $ACCESSIBLE_URLS${NC}" echo -e "${RED}URLs échouées: $FAILED_URLS${NC}" if [ $FAILED_URLS -eq 0 ]; then echo -e "${GREEN}🎉 Toutes les URLs sont accessibles !${NC}" elif [ $FAILED_URLS -lt $((TOTAL_URLS / 2)) ]; then echo -e "${YELLOW}⚠️ Certaines URLs ne sont pas accessibles, mais la majorité fonctionne.${NC}" else echo -e "${RED}❌ Trop d'URLs ne sont pas accessibles. Vérifiez la configuration.${NC}" fi echo # Afficher le statut final echo -e "${GREEN}🎉 All services started successfully!${NC}" echo echo -e "${BLUE}Final status:${NC}" docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml ps # Calculer le temps total end_time=$(date +%s) total_time=$((end_time - START_TIME)) minutes=$((total_time / 60)) seconds=$((total_time % 60)) echo echo -e "${GREEN}Total startup time: ${minutes}m ${seconds}s${NC}" echo echo -e "${BLUE}Useful commands:${NC}" echo -e " ${YELLOW}docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml logs -f${NC} # Voir les logs" echo -e " ${YELLOW}docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml down${NC} # Arrêter les services" echo -e " ${YELLOW}docker compose --env-file /home/debian/4NK_env/.env.master -f /home/debian/4NK_env/lecoffre_node/docker-compose.yml ps${NC} # Voir le statut" echo