import 'dart:async'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import '../core/config/environment.dart'; import '../data/datasources/remote/api_client.dart'; // 조건부 import - 웹 플랫폼에서만 dart:js 사용 import 'health_check_service_stub.dart' if (dart.library.js) 'health_check_service_web.dart' as platform; /// API 헬스체크 테스트를 위한 서비스 class HealthCheckService { final ApiClient _apiClient; Timer? _healthCheckTimer; bool _isMonitoring = false; HealthCheckService({ApiClient? apiClient}) : _apiClient = apiClient ?? ApiClient(); /// 헬스체크 API 호출 Future> checkHealth() async { try { debugPrint('=== 헬스체크 시작 ==='); debugPrint('API Base URL: ${Environment.apiBaseUrl}'); debugPrint('Full URL: ${Environment.apiBaseUrl}/health'); final response = await _apiClient.get('/health'); debugPrint('응답 상태 코드: ${response.statusCode}'); debugPrint('응답 데이터: ${response.data}'); return { 'success': true, 'data': response.data, 'statusCode': response.statusCode, }; } on DioException catch (e) { debugPrint('=== DioException 발생 ==='); debugPrint('에러 타입: ${e.type}'); debugPrint('에러 메시지: ${e.message}'); debugPrint('에러 응답: ${e.response?.data}'); debugPrint('에러 상태 코드: ${e.response?.statusCode}'); // CORS 에러인지 확인 if (e.type == DioExceptionType.connectionError || e.type == DioExceptionType.unknown) { debugPrint('⚠️ CORS 또는 네트워크 연결 문제일 가능성이 있습니다.'); } return { 'success': false, 'error': e.message ?? '알 수 없는 에러', 'errorType': e.type.toString(), 'statusCode': e.response?.statusCode, 'responseData': e.response?.data, }; } catch (e) { debugPrint('=== 일반 에러 발생 ==='); debugPrint('에러: $e'); return { 'success': false, 'error': e.toString(), }; } } /// 직접 Dio로 테스트 (인터셉터 없이) Future> checkHealthDirect() async { try { debugPrint('=== 직접 Dio 헬스체크 시작 ==='); final dio = Dio(BaseOptions( baseUrl: Environment.apiBaseUrl, connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, )); // 로깅 인터셉터만 추가 dio.interceptors.add(LogInterceptor( requestBody: true, responseBody: true, requestHeader: true, responseHeader: true, error: true, )); final response = await dio.get('/health'); return { 'success': true, 'data': response.data, 'statusCode': response.statusCode, }; } catch (e) { debugPrint('직접 Dio 에러: $e'); return { 'success': false, 'error': e.toString(), }; } } /// 주기적인 헬스체크 시작 (30초마다) void startPeriodicHealthCheck() { if (_isMonitoring) return; debugPrint('=== 주기적 헬스체크 모니터링 시작 ==='); _isMonitoring = true; // 즉시 한 번 체크 _performHealthCheck(); // 30초마다 체크 _healthCheckTimer = Timer.periodic(const Duration(seconds: 30), (_) { _performHealthCheck(); }); } /// 주기적인 헬스체크 중지 void stopPeriodicHealthCheck() { debugPrint('=== 주기적 헬스체크 모니터링 중지 ==='); _isMonitoring = false; _healthCheckTimer?.cancel(); _healthCheckTimer = null; } /// 헬스체크 수행 및 알림 표시 Future _performHealthCheck() async { final result = await checkHealth(); if (!result['success'] || result['data']?['status'] != 'healthy') { _showBrowserNotification(result); } } /// 브라우저 알림 표시 void _showBrowserNotification(Map result) { if (!kIsWeb) return; try { final status = result['data']?['status'] ?? 'unreachable'; final message = result['error'] ?? 'Server status: $status'; debugPrint('=== 브라우저 알림 표시 ==='); debugPrint('상태: $status'); debugPrint('메시지: $message'); // 플랫폼별 알림 처리 platform.showNotification( 'Server Health Check Alert', message, status, ); } catch (e) { debugPrint('브라우저 알림 표시 실패: $e'); } } /// 모니터링 상태 확인 bool get isMonitoring => _isMonitoring; }