diff --git a/.idea/dio_smart_retry.iml b/.idea/dio_smart_retry.iml index 0df1d15..1676d1b 100644 --- a/.idea/dio_smart_retry.iml +++ b/.idea/dio_smart_retry.iml @@ -10,6 +10,5 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 639900d..6e86672 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/CHANGELOG.md b/CHANGELOG.md index ecf0800..f7550a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## 6.0.0 +- Updated internal libraries. +- Bumped minimum Dart SDK to 3.0. +- Added `MultipartFileRecreatable` documentation. +- Refactors static constructors to factories. +- Adds a new `MultipartFileRecreatable.fromBytes` factory compatible with web. +- Added a new `headers` parameter. +- You can now read the file's content with `MultipartFileRecreatable.data`. +- **Breaking:** `MultipartFileRecreatable.filename` is now a named parameter to match `dio`. +- **Breaking:** Removed `MultipartFileRecreatable.filePath` since it was not being used internally. + ## 5.0.0 - Add supporting of the new dio 5.+ diff --git a/README.md b/README.md index b0e70a9..6f81fb6 100644 --- a/README.md +++ b/README.md @@ -129,4 +129,30 @@ final formData = data: formData, ); ``` -See the full example in the test: https://github.com/rodion-m/dio_smart_retry/blob/63a3bddae8b5a0581c35c4ae5e973996561d9100/test/multipart_retry_tests.dart#L32-L61 \ No newline at end of file +See the full example in the test: https://github.com/rodion-m/dio_smart_retry/blob/63a3bddae8b5a0581c35c4ae5e973996561d9100/test/multipart_retry_tests.dart#L32-L61 + +## Migrating to 6.0 + +Version 6.0 introduces 2 breaking changes: +- `MultipartFileRecreatable.filename` is now a named parameter +- `MultipartFileRecreatable.filePath` is now removed + +To update to the latest version, if you were using the `MultipartFileRecreatable` constructor, remove the `filePath` parameter and change `filename` to a named parameter: + +Old: +```dart +return MultipartFileRecreatable( + stream, + length, + filename, + filePath, +); +``` +New: +```dart +return MultipartFileRecreatable( + stream, + length, + filename: filename, +); +``` \ No newline at end of file diff --git a/lib/src/default_retry_evaluator.dart b/lib/src/default_retry_evaluator.dart index f22f06b..0f39b91 100644 --- a/lib/src/default_retry_evaluator.dart +++ b/lib/src/default_retry_evaluator.dart @@ -11,9 +11,9 @@ class DefaultRetryEvaluator { /// Returns true only if the response hasn't been cancelled /// or got a bad status code. // ignore: avoid-unused-parameters - FutureOr evaluate(DioError error, int attempt) { + FutureOr evaluate(DioException error, int attempt) { bool shouldRetry; - if (error.type == DioErrorType.badResponse) { + if (error.type == DioExceptionType.badResponse) { final statusCode = error.response?.statusCode; if (statusCode != null) { shouldRetry = isRetryable(statusCode); @@ -21,8 +21,8 @@ class DefaultRetryEvaluator { shouldRetry = true; } } else { - shouldRetry = - error.type != DioErrorType.cancel && error.error is! FormatException; + shouldRetry = error.type != DioExceptionType.cancel && + error.error is! FormatException; } currentAttempt = attempt; return shouldRetry; diff --git a/lib/src/multipart_file_recreatable.dart b/lib/src/multipart_file_recreatable.dart index 093324b..768380e 100644 --- a/lib/src/multipart_file_recreatable.dart +++ b/lib/src/multipart_file_recreatable.dart @@ -4,21 +4,39 @@ import 'package:dio/dio.dart'; import 'package:http_parser/http_parser.dart'; import 'package:path/path.dart' as p; +/// Creates an instance of [MultipartFile] that can be recreated and reused. class MultipartFileRecreatable extends MultipartFile { + /// Default constructor. MultipartFileRecreatable( - Stream> stream, - int length, + super.stream, + super.length, { + super.filename, + super.contentType, + super.headers, + }) : data = stream; + + /// Creates a [MultipartFileRecreatable] object with [bytes]. + factory MultipartFileRecreatable.fromBytes( + List bytes, { String? filename, - this.filePath, { MediaType? contentType, - }) : super(stream, length, filename: filename, contentType: contentType); - final String filePath; + Map>? headers, + }) { + return MultipartFileRecreatable( + Stream.fromIterable(>[bytes]), + bytes.length, + filename: filename, + contentType: contentType, + headers: headers, + ); + } - // ignore: prefer_constructors_over_static_methods - static MultipartFileRecreatable fromFileSync( + /// Creates a [MultipartFileRecreatable] object from a [File] in [filePath]. + factory MultipartFileRecreatable.fromFileSync( String filePath, { String? filename, MediaType? contentType, + Map>? headers, }) { filename ??= p.basename(filePath); final file = File(filePath); @@ -27,15 +45,23 @@ class MultipartFileRecreatable extends MultipartFile { return MultipartFileRecreatable( stream, length, - filename, - filePath, + filename: filename, contentType: contentType, + headers: headers, ); } - MultipartFileRecreatable recreate() => fromFileSync( - filePath, - filename: filename, - contentType: contentType, - ); + /// The stream that will emit the file's contents. + final Stream> data; + + /// Recreates the [MultipartFileRecreatable] object. + MultipartFileRecreatable recreate() { + return MultipartFileRecreatable( + data, + length, + filename: filename, + contentType: contentType, + headers: headers, + ); + } } diff --git a/lib/src/retry_interceptor.dart b/lib/src/retry_interceptor.dart index 6950a7e..c90f05a 100644 --- a/lib/src/retry_interceptor.dart +++ b/lib/src/retry_interceptor.dart @@ -6,7 +6,10 @@ import 'package:dio_smart_retry/src/http_status_codes.dart'; import 'package:dio_smart_retry/src/multipart_file_recreatable.dart'; import 'package:dio_smart_retry/src/retry_not_supported_exception.dart'; -typedef RetryEvaluator = FutureOr Function(DioError error, int attempt); +typedef RetryEvaluator = FutureOr Function( + DioException error, + int attempt, +); /// An interceptor that will try to send failed request again class RetryInterceptor extends Interceptor { @@ -35,7 +38,7 @@ class RetryInterceptor extends Interceptor { 'retryableExtraStatuses', ); } - if(retries < 0) { + if (retries < 0) { throw ArgumentError( '[retries] cannot be less than 0', 'retries', @@ -82,11 +85,11 @@ class RetryInterceptor extends Interceptor { /// Redirects to [DefaultRetryEvaluator.evaluate] /// with [defaultRetryableStatuses] - static final FutureOr Function(DioError error, int attempt) + static final FutureOr Function(DioException error, int attempt) defaultRetryEvaluator = DefaultRetryEvaluator(defaultRetryableStatuses).evaluate; - Future _shouldRetry(DioError error, int attempt) async { + Future _shouldRetry(DioException error, int attempt) async { try { return await _retryEvaluator(error, attempt); } catch (e) { @@ -105,7 +108,10 @@ class RetryInterceptor extends Interceptor { } @override - Future onError(DioError err, ErrorInterceptorHandler handler) async { + Future onError( + DioException err, + ErrorInterceptorHandler handler, + ) async { if (err.requestOptions.disableRetry) { return super.onError(err, handler); } @@ -135,7 +141,7 @@ class RetryInterceptor extends Interceptor { requestOptions = _recreateOptions(err.requestOptions); } on RetryNotSupportedException catch (e) { return super.onError( - DioError(requestOptions: requestOptions, error: e), + DioException(requestOptions: requestOptions, error: e), handler, ); } @@ -153,7 +159,7 @@ class RetryInterceptor extends Interceptor { await dio .fetch(requestOptions) .then((value) => handler.resolve(value)); - } on DioError catch (e) { + } on DioException catch (e) { super.onError(e, handler); } } @@ -191,6 +197,7 @@ class RetryInterceptor extends Interceptor { } var _multipartFileChecked = false; + void _printErrorIfRequestHasMultipartFile(RequestOptions options) { if (_multipartFileChecked) return; if (options.data is FormData) { diff --git a/pubspec.yaml b/pubspec.yaml index 9ea5827..c5d3e80 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,20 +1,20 @@ name: dio_smart_retry description: Retry library for Dio and Dio package made with love. By default, the request will be retried only for appropriate retryable http statuses. -version: 5.0.0 +version: 6.0.0 repository: https://github.com/rodion-m/dio_smart_retry issue_tracker: https://github.com/rodion-m/dio_smart_retry/issues homepage: https://github.com/rodion-m/dio_smart_retry documentation: https://github.com/rodion-m/dio_smart_retry#contents environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: - dio: ^5.0.0 + dio: ^5.3.3 http_parser: ^4.0.2 - path: ^1.8.2 + path: ^1.8.3 dev_dependencies: - dart_code_metrics: ^5.6.0 - test: ^1.23.1 - very_good_analysis: ^4.0.0+1 + dart_code_metrics: ^5.7.6 + test: ^1.24.9 + very_good_analysis: ^5.1.0 diff --git a/test/multipart_retry_tests.dart b/test/multipart_retry_tests.dart index 69e70ad..dd31293 100644 --- a/test/multipart_retry_tests.dart +++ b/test/multipart_retry_tests.dart @@ -22,7 +22,7 @@ void main() { 'https://rodion-m.ru/mock/post500.php', data: formData, ); - } on DioError catch (error) { + } on DioException catch (error) { exception = error.error; } @@ -51,8 +51,8 @@ void main() { 'https://rodion-m.ru/mock/post500.php', data: formData, ); - } on DioError catch (error) { - if (error.type != DioErrorType.badResponse) { + } on DioException catch (error) { + if (error.type != DioExceptionType.badResponse) { rethrow; } } diff --git a/test/override_retryable_statuses_test.dart b/test/override_retryable_statuses_test.dart index b8dbe81..c35b620 100644 --- a/test/override_retryable_statuses_test.dart +++ b/test/override_retryable_statuses_test.dart @@ -20,8 +20,8 @@ void main() { try { await dio.get('https://mock.codes/400'); - } on DioError catch (error) { - if (error.type != DioErrorType.badResponse || + } on DioException catch (error) { + if (error.type != DioExceptionType.badResponse || error.response?.statusCode != 400) { rethrow; }