// Author: fengshengxiong // Date: 2024/5/9 // Description: dio封装 import 'dart:io'; import 'package:dio/dio.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:tone_snap/components/base_easyloading.dart'; import 'package:tone_snap/data/api/music_api.dart'; import 'package:tone_snap/data/network/base_error.dart'; import 'package:tone_snap/data/network/dio_interceptor.dart'; import 'package:tone_snap/utils/log_util.dart'; class DioClient { static final DioClient _instance = DioClient._internal(); factory DioClient({String? baseUrl}) => getInstance(baseUrl: baseUrl); late Dio _dio; static DioClient getInstance({String? baseUrl}) { if (baseUrl == null) { return _instance._defaultBaseUrl(); } else { return _instance._newBaseUrl(baseUrl); } } /// 默认域名 DioClient _defaultBaseUrl() { if (_dio.options.baseUrl != MusicApi.baseUrl) { _dio.options.baseUrl = MusicApi.baseUrl; } return _instance; } /// 用于指定特定域名 DioClient _newBaseUrl(String baseUrl) { _dio.options.baseUrl = baseUrl; return _instance; } DioClient._internal() { _dio = Dio(); final baseOptions = BaseOptions( baseUrl: MusicApi.baseUrl, connectTimeout: const Duration(seconds: 30), receiveTimeout: const Duration(seconds: 30), ); _dio.options = baseOptions; _dio.interceptors.add(DioInterceptor()); _dio.interceptors.add(PrettyDioLogger( requestHeader: false, requestBody: true, responseBody: false, compact: false, maxWidth: 160, )); } /// 请求 Future request( String path, { required RequestMethod requestMethod, dynamic data, Map? queryParameters, CancelToken? cancelToken, Options? options, bool isFormData = false, T Function(Map)? formJson, required Function(T? result) success, Function(BaseError baseError)? fail, bool showLoading = false, bool showToast = false, }) async { try { BaseEasyLoading.loading(show: showLoading); _dio.options.method = requestMethod.method; Response response = await _dio.request( path, data: isFormData ? FormData.fromMap(data) : data, queryParameters: queryParameters, cancelToken: cancelToken, options: options, ); BaseEasyLoading.dismiss(dismiss: showLoading); if (response.statusCode == HttpStatus.ok) { if (response.data != null && formJson != null) { success(formJson(response.data)); } else { success(response.data); } } } catch (e) { BaseError baseError = getError(e); if (fail != null) fail(baseError); BaseEasyLoading.toast(baseError.message, show: showToast); LogUtil.e(e.toString()); } } /// 下载 Future download( String urlPath, dynamic savePath, { bool showToast = false, ProgressCallback? onReceiveProgress, Map? queryParameters, CancelToken? cancelToken, data, Options? options, required Function() success, Function(BaseError? err)? fail, }) async { try { await _dio.download( urlPath, savePath, onReceiveProgress: onReceiveProgress, queryParameters: queryParameters, cancelToken: cancelToken, data: data, options: Options(receiveTimeout: const Duration(seconds: 0)), ); success(); } catch (e) { BaseError baseError = getError(e); if (fail != null) fail(baseError); BaseEasyLoading.toast(baseError.message, show: showToast); LogUtil.e(baseError.message); } } BaseError getError(Object e) { if (e.runtimeType == DioException) { switch ((e as DioException).type) { case DioExceptionType.connectionTimeout: return OtherError(statusCode: DioExceptionType.connectionTimeout.index, statusMessage: 'Connection timed out'); case DioExceptionType.sendTimeout: return OtherError(statusCode: DioExceptionType.sendTimeout.index, statusMessage: 'Send timeout'); case DioExceptionType.receiveTimeout: return OtherError(statusCode: DioExceptionType.receiveTimeout.index, statusMessage: 'Receive timeout'); case DioExceptionType.badCertificate: return OtherError(statusCode: DioExceptionType.badCertificate.index, statusMessage: 'Certificate error'); case DioExceptionType.cancel: return OtherError(statusCode: DioExceptionType.cancel.index, statusMessage: 'Request canceled'); case DioExceptionType.connectionError: return OtherError(statusCode: DioExceptionType.connectionError.index, statusMessage: 'Connection error'); case DioExceptionType.unknown: return OtherError(statusCode: DioExceptionType.unknown.index, statusMessage: 'Unknown error'); case DioExceptionType.badResponse: final response = e.response; if (response!.statusCode == 401) { return NeedLogin(); } else if (response.statusCode == 403) { return NeedAuth(); } else { return OtherError( statusCode: response.statusCode, statusMessage: response.statusMessage, ); } } } return OtherError(statusCode: -1, statusMessage: 'Unknown error'); } } enum RequestMethod { get('GET'), post('POST'), put('PUT'), head('HEAD'), delete('DELETE'), patch('PATCH'); const RequestMethod( this.method, ); final String method; }