a89c7894cf
Backend: - FastAPI avec PostgreSQL et Redis - Authentification JWT complète - API REST pour musique, playlists, recherche - Streaming audio via yt-dlp - SQLAlchemy 2.0 async Frontend: - Flutter avec thème néon cyberpunk - State management Riverpod - Layout adaptatif desktop/mobile - Lecteur audio avec mini-player Infrastructure: - Docker Compose (PostgreSQL + Redis) - Scripts d'installation automatisés - Scripts de build pour exécutables Fichiers ajoutés: - BUILD_CLIENT_*.bat/sh: Scripts de compilation - BUILD_CLIENT_README.md: Documentation compilation - CHECK_FLUTTER.sh: Vérificateur d'environnement - requirements.txt mis à jour pour Python 3.13 - Modèles SQLAlchemy corrigés (metadata -> extra_metadata) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
77 lines
2.2 KiB
Dart
77 lines
2.2 KiB
Dart
/// API Service - Main HTTP client using Dio
|
|
library;
|
|
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
|
|
|
|
import '../../../core/constants/api_constants.dart';
|
|
import '../../providers/auth_provider.dart';
|
|
|
|
/// API Service provider
|
|
final apiServiceProvider = Provider<Dio>((ref) {
|
|
final authState = ref.watch(authProvider);
|
|
final token = authState?.accessToken;
|
|
|
|
final options = BaseOptions(
|
|
baseUrl: ApiConstants.baseUrl,
|
|
connectTimeout: const Duration(milliseconds: ApiConstants.connectionTimeoutMs),
|
|
receiveTimeout: const Duration(milliseconds: ApiConstants.receiveTimeoutMs),
|
|
sendTimeout: const Duration(milliseconds: ApiConstants.sendTimeoutMs),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
if (token != null) 'Authorization': 'Bearer $token',
|
|
},
|
|
);
|
|
|
|
final dio = Dio(options);
|
|
|
|
// Add logger in debug mode
|
|
dio.interceptors.add(
|
|
PrettyDioLogger(
|
|
requestHeader: true,
|
|
requestBody: true,
|
|
responseBody: true,
|
|
responseHeader: false,
|
|
error: true,
|
|
compact: true,
|
|
),
|
|
);
|
|
|
|
// Add token refresh interceptor
|
|
dio.interceptors.add(
|
|
InterceptorsWrapper(
|
|
onError: (error, handler) async {
|
|
if (error.response?.statusCode == 401) {
|
|
// Try to refresh token
|
|
try {
|
|
final newToken = await ref.read(authProvider.notifier).refreshToken();
|
|
if (newToken != null) {
|
|
// Retry original request with new token
|
|
final opts = options.copyWith(
|
|
headers: {
|
|
...options.headers,
|
|
'Authorization': 'Bearer $newToken',
|
|
},
|
|
);
|
|
final clonedReq = await dio.fetch(opts..path = error.requestOptions.path);
|
|
return handler.resolve(clonedReq);
|
|
}
|
|
} catch (e) {
|
|
// Refresh failed, logout user
|
|
ref.read(authProvider.notifier).logout();
|
|
}
|
|
}
|
|
return handler.next(error);
|
|
},
|
|
),
|
|
);
|
|
|
|
return dio;
|
|
});
|
|
|
|
/// Get API client
|
|
Dio getDio(Ref ref) {
|
|
return ref.read(apiServiceProvider);
|
|
}
|