import 'dart:io'; import 'dart:async'; import 'dart:convert'; import 'package:barcode_scanner/services/token_provider.dart'; import 'package:barcode_scanner/utils/app_constants.dart'; import 'package:barcode_scanner/utils/utils.dart'; import 'package:dio/io.dart'; import 'package:dio/dio.dart'; import 'package:flutter/widgets.dart'; class DioService { DioService({bool addAuthorization = false, required this.tokenProvider}) { _options = BaseOptions( baseUrl: AppConstants.baseUrl, connectTimeout: const Duration(seconds: 45), receiveTimeout: const Duration(seconds: 45), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json, text/plain, */*', 'DNT': '1', 'Referer': AppConstants.domain }, ); _dio = Dio(_options); //check bad certificate // ignore: deprecated_member_use (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) => true; return client; }; _dio.interceptors.add( InterceptorsWrapper( onRequest: (options, handler) async { final token = await tokenProvider.getToken(); if (token != null) { options.headers.addAll({"Authorization": "Bearer $token"}); debugPrint('Authorization ${options.headers["Authorization"]}'); final url = Uri.parse( "${options.baseUrl}${options.path}", ).replace(queryParameters: options.queryParameters).toString(); debugPrint('REQUEST[${options.method}] => PATH: $url'); debugPrint( 'REQUEST[${options.method}] => QUERY PARAMS: ${options.queryParameters}', ); } // Do something before request is sent return handler.next(options); //continue // If you want to resolve the request with some custom data, // you can resolve a `Response` object eg: `handler.resolve(response)`. // If you want to reject the request with a error message, // you can reject a `DioError` object eg: `handler.reject(dioError)` }, onResponse: (response, handler) { debugPrint( 'RESPONSE[${response.statusCode}] => DATA: ${jsonEncode(response.data)}', ); // Do something with response data return handler.next(response); // continue // If you want to reject the request with a error message, // you can reject a `DioError` object eg: `handler.reject(dioError)` }, onError: (DioException e, handler) async { debugPrint( 'ERROR[$e] => PATH: ${e.requestOptions.baseUrl}${e.requestOptions.path}', ); // Handling global errors (401 Unauthorized) if (e.response?.statusCode == 401) { debugPrint("Token expired !!!"); await tokenProvider.deleteToken(); // final refreshToken = await tokenProvider.getRefreshToken(); // try { // final response = await _dio.post( // AuthEndPoint.refreshToken, // data: {"refresh_token": refreshToken}, // ); // final newAccessToken = response.data["accessToken"]; // final newRefreshToken = response.data["refreshToken"]; // await tokenProvider.setToken(newAccessToken); // await tokenProvider.setRefreshToken(newRefreshToken); // // Réessayer la requête initiale avec le nouveau token // e.requestOptions.headers["Authorization"] = // "Bearer $newAccessToken"; // final retryResponse = await _dio.fetch(e.requestOptions); // return handler.resolve(retryResponse); // } catch (e) { // // Échec du refresh, l'utilisateur doit se reconnecter // await tokenProvider.deleteToken(); // } } // Do something with response error return handler.next(e); //continue // If you want to resolve the request with some custom data, // you can resolve a `Response` object eg: `handler.resolve(response)`. }, ), ); } late Dio _dio; late BaseOptions _options; late TokenProvider tokenProvider; Future> post({ required String path, Map? data, bool isFormData = false, }) async { late Response response; if (await checkInternetConnexion()) { try { response = await _dio.post( path, data: data != null ? (isFormData ? FormData.fromMap(data) : data) : null, ); } catch (error) { _exception(error); } } else { throw Exception("Vous n'êtes pas connecté à Internet"); } return response; } Future> get({ required String path, Map? queryParameters, }) async { late Response response; if (await checkInternetConnexion()) { try { response = await _dio.get(path, queryParameters: queryParameters); } catch (error) { _exception(error); } } else { throw Exception("Vous n'êtes pas connecté à Internet"); } return response; } Future> patch({ required String path, Map? data, Options? options, bool isFormData = false, }) async { late Response response; if (await checkInternetConnexion()) { try { response = await _dio.patch( path, data: data != null ? (isFormData ? FormData.fromMap(data) : data) : null, options: options, ); } catch (error) { _exception(error); } } else { throw Exception("Vous n'êtes pas connecté à Internet"); } return response; } Future> put({ required String path, Map? data, Options? options, bool isFormData = false, }) async { late Response response; if (await checkInternetConnexion()) { try { response = await _dio.put( path, data: data != null ? (isFormData ? FormData.fromMap(data) : data) : null, options: options, ); } catch (error) { _exception(error); } } else { throw Exception("Vous n'êtes pas connecté à Internet"); } return response; } Future> delete({ required String path, Map? queryParameters, Options? options, bool isFormData = false, }) async { late Response response; if (await checkInternetConnexion()) { try { response = await _dio.delete( path, options: options, queryParameters: queryParameters, ); } catch (error) { _exception(error); } } else { throw Exception("Vous n'êtes pas connecté à Internet"); } return response; } void _exception(error) { if (error is DioException) { throw error; } if (error is SocketException) { throw Exception("Vous n'êtes pas connecté à Internet"); } if (error is TimeoutException) { throw throw Exception("Time out"); } } Future> download( String urlPath, savePath, { ProgressCallback? onReceiveProgress, Map? queryParameters, CancelToken? cancelToken, bool deleteOnError = true, String lengthHeader = Headers.contentLengthHeader, data, options, }) async { late Response response; try { response = await _dio.download( urlPath, savePath, onReceiveProgress: onReceiveProgress, queryParameters: queryParameters, cancelToken: cancelToken, deleteOnError: deleteOnError, lengthHeader: lengthHeader, data: data, options: options, ); } catch (error) { _exception(error); } return response; } Future> uploadPatch( String endPoint, { ProgressCallback? onSendProgress, Map? queryParameters, CancelToken? cancelToken, bool deleteOnError = true, String lengthHeader = Headers.contentLengthHeader, data, options, }) async { late Response response; try { response = await _dio.request( endPoint, onSendProgress: onSendProgress, data: data, options: Options( method: 'PATCH', // or 'PUT' ), ); } catch (error) { _exception(error); } return response; } Future> uploadPost( String endPoint, { ProgressCallback? onSendProgress, Map? queryParameters, CancelToken? cancelToken, bool deleteOnError = true, String lengthHeader = Headers.contentLengthHeader, data, options, }) async { late Response response; try { response = await _dio.post( endPoint, onSendProgress: onSendProgress, data: data, ); } catch (error) { _exception(error); } return response; } }