Skip to content

Commit

Permalink
Clean codes (#24)
Browse files Browse the repository at this point in the history
* 🔥 Clean codes

* ⚡️ Make all `cancelFuture` void

* ⚡️ Make `ResponseBody.statusCode` non-nullable

* ⚡️ Return correct stack traces in the HTTP/2 adapter

* ⚡️ Improve interceptors

* ⚡️ Const `DioError`

* ⚡️ Improve the constructor of `CookieManager`

* 💚 Fix tests

* 🔥 Remove usages of `DefaultHttpClientAdapter`

* 🔥 Remove stubs

* 📝 Finish the migration guide

* 📝 Format tables in READMEs

* 🚀 Migrate new `kIsWeb`

* ⚡️ Improve how to initiate adapters

* 🎨 Consist naming

* ⚡️ Improve adapters

* 🔥 Remove empty stack traces for `DioError`

* 🥅 Improve `catchError`s

* 🔥 Remove locks
  • Loading branch information
AlexV525 authored Dec 12, 2022
1 parent 0b2b23a commit 6bc14fd
Show file tree
Hide file tree
Showing 80 changed files with 1,549 additions and 1,497 deletions.
200 changes: 138 additions & 62 deletions README-ZH.md

Large diffs are not rendered by default.

177 changes: 98 additions & 79 deletions README.md

Large diffs are not rendered by default.

200 changes: 138 additions & 62 deletions dio/README-ZH.md

Large diffs are not rendered by default.

171 changes: 109 additions & 62 deletions dio/README.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions dio/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ analyzer:
errors:
deprecated_member_use_from_same_package: ignore
todo: ignore
linter:
rules:
- prefer_final_fields: true
- prefer_final_locals: true
- prefer_final_in_for_each: true
- unnecessary_parenthesis: true
2 changes: 1 addition & 1 deletion dio/example/dio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:dio/dio.dart';

/// More examples see https://github.com/flutterchina/dio/tree/master/example
void main() async {
var dio = Dio();
final dio = Dio();
final response = await dio.get('https://google.com');
print(response.data);
}
2 changes: 1 addition & 1 deletion dio/lib/io.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export 'src/entry/dio_for_native.dart' show DioForNative;
export 'src/adapters/io_adapter.dart'
show DefaultHttpClientAdapter, IOHttpClientAdapter;
export 'src/dio/dio_for_native.dart' show DioForNative;
37 changes: 18 additions & 19 deletions dio/lib/src/adapter.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:dio/src/adapters/universal_adapter.dart';

import 'options.dart';
import 'redirect_record.dart';

/// HttpAdapter is a bridge between Dio and HttpClient.
///
/// Dio: Implements standard and friendly API for developer.
import 'adapters/io_adapter.dart'
if (dart.library.html) 'adapters/browser_adapter.dart' as adapter;

/// [HttpAdapter] is a bridge between [Dio] and [HttpClient].
///
/// HttpClient: It is the real object that makes Http
/// [Dio] implements standard and friendly API for developer.
/// [HttpClient] is the real object that makes Http
/// requests.
///
/// We can use any HttpClient not just "dart:io:HttpClient" to
/// make the Http request. All we need is providing a [HttpClientAdapter].
/// We can use any [HttpClient]s not just "dart:io:HttpClient" to
/// make the HTTP request. All we need is to provide a [HttpClientAdapter].
///
/// The default HttpClientAdapter for Dio is [HttpClientAdapter].
///
/// If you want to customize the `HttpClientAdapter` you should instead use
/// either `DefaultHttpClientAdapter` on `dart:io` platforms
/// or `BrowserHttpClientAdapter` on `dart:html` platforms.
/// If you want to customize the [HttpClientAdapter] you should instead use
/// either [IOHttpClientAdapter] on `dart:io` platforms
/// or [BrowserHttpClientAdapter] on `dart:html` platforms.
///
/// ```dart
/// dio.httpClientAdapter = HttpClientAdapter();
/// ```
abstract class HttpClientAdapter {
factory HttpClientAdapter() => createAdapter();
factory HttpClientAdapter() => adapter.createAdapter();

/// We should implement this method to make real http requests.
///
/// [options]: The request options
/// [options] are the request options.
///
/// [requestStream] The request stream, It will not be null
/// only when http method is one of "POST","PUT","PATCH"
Expand All @@ -37,18 +37,17 @@ abstract class HttpClientAdapter {
/// We should give priority to using requestStream(not options.data) as request data.
/// because supporting stream ensures the `onSendProgress` works.
///
/// [cancelFuture]: When cancelled the request, [cancelFuture] will be resolved!
/// When cancelled the request, [cancelFuture] will be resolved!
/// you can listen cancel event by it, for example:
///
/// ```dart
/// cancelFuture?.then((_)=>print("request cancelled!"))
/// ```
/// [cancelFuture]: will be null when the request is not set [CancelToken].
/// [cancelFuture] will be null when the request is not set [CancelToken].
Future<ResponseBody> fetch(
RequestOptions options,
Stream<Uint8List>? requestStream,
Future? cancelFuture,
Future<void>? cancelFuture,
);

void close({bool force = false});
Expand All @@ -71,7 +70,7 @@ class ResponseBody {
late Map<String, List<String>> headers;

/// Http status code
int? statusCode;
int statusCode;

/// Returns the reason phrase associated with the status code.
/// The reason phrase must be set before the body is written
Expand Down
51 changes: 29 additions & 22 deletions dio/lib/src/adapters/browser_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
bool withCredentials = false;

@override
Future<ResponseBody> fetch(RequestOptions options,
Stream<Uint8List>? requestStream, Future? cancelFuture) async {
var xhr = HttpRequest();
Future<ResponseBody> fetch(
RequestOptions options,
Stream<Uint8List>? requestStream,
Future<void>? cancelFuture,
) async {
final xhr = HttpRequest();
_xhrs.add(xhr);
xhr
..open(options.method, '${options.uri}')
..responseType = 'arraybuffer';

var _withCredentials = options.extra['withCredentials'];

if (_withCredentials != null) {
xhr.withCredentials = _withCredentials == true;
final withCredentials = options.extra['withCredentials'];
if (withCredentials != null) {
xhr.withCredentials = withCredentials == true;
} else {
xhr.withCredentials = withCredentials;
}
Expand All @@ -50,14 +52,14 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
xhr.timeout = (connectTimeout + receiveTimeout).inMilliseconds;
}

var completer = Completer<ResponseBody>();
final completer = Completer<ResponseBody>();

xhr.onLoad.first.then((_) {
Uint8List body = (xhr.response as ByteBuffer).asUint8List();
completer.complete(
ResponseBody.fromBytes(
body,
xhr.status,
xhr.status!,
headers: xhr.responseHeaders.map((k, v) => MapEntry(k, v.split(','))),
statusMessage: xhr.statusText,
isRedirect: xhr.status == 302 || xhr.status == 301,
Expand Down Expand Up @@ -111,7 +113,7 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
uploadStopwatch.start();
}

var duration = uploadStopwatch.elapsed;
final duration = uploadStopwatch.elapsed;
if (duration > sendTimeout) {
uploadStopwatch.stop();
completer.completeError(
Expand All @@ -138,14 +140,14 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
connectTimeoutTimer = null;
}

final reveiveTimeout = options.receiveTimeout;
if (reveiveTimeout != null) {
final receiveTimeout = options.receiveTimeout;
if (receiveTimeout != null) {
if (!uploadStopwatch.isRunning) {
uploadStopwatch.start();
}

final duration = downloadStopwatch.elapsed;
if (duration > reveiveTimeout) {
if (duration > receiveTimeout) {
downloadStopwatch.stop();
completer.completeError(
DioError.receiveTimeout(
Expand Down Expand Up @@ -179,7 +181,7 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
);
});

cancelFuture?.then((err) {
cancelFuture?.then((_) {
if (xhr.readyState < 4 && xhr.readyState > 0) {
connectTimeoutTimer?.cancel();
try {
Expand All @@ -192,27 +194,32 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
// so need to manual throw the cancel error to avoid Future hang ups.
// or added xhr.onAbort like axios did https://github.com/axios/axios/blob/master/lib/adapters/xhr.js#L102-L111
if (!completer.isCompleted) {
completer.completeError(err);
completer.completeError(
DioError.requestCancelled(
requestOptions: options,
reason: 'The XMLHttpRequest was aborted.',
),
);
}
}
});

if (requestStream != null) {
var _completer = Completer<Uint8List>();
var sink = ByteConversionSink.withCallback(
(bytes) => _completer.complete(Uint8List.fromList(bytes)));
final completer = Completer<Uint8List>();
final sink = ByteConversionSink.withCallback(
(bytes) => completer.complete(Uint8List.fromList(bytes)),
);
requestStream.listen(
sink.add,
onError: _completer.completeError,
onError: (Object e, StackTrace s) => completer.completeError(e, s),
onDone: sink.close,
cancelOnError: true,
);
var bytes = await _completer.future;
final bytes = await completer.future;
xhr.send(bytes);
} else {
xhr.send();
}

return completer.future.whenComplete(() {
_xhrs.remove(xhr);
});
Expand All @@ -224,7 +231,7 @@ class BrowserHttpClientAdapter implements HttpClientAdapter {
@override
void close({bool force = false}) {
if (force) {
for (var xhr in _xhrs) {
for (final xhr in _xhrs) {
xhr.abort();
}
}
Expand Down
54 changes: 20 additions & 34 deletions dio/lib/src/adapters/io_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ class IOHttpClientAdapter implements HttpClientAdapter {
Future<ResponseBody> fetch(
RequestOptions options,
Stream<Uint8List>? requestStream,
Future? cancelFuture,
Future<void>? cancelFuture,
) async {
if (_closed) {
throw Exception(
"Can't establish connection after [HttpClientAdapter] closed!");
}
var _httpClient = _configHttpClient(cancelFuture, options.connectTimeout);
var reqFuture = _httpClient.openUrl(options.method, options.uri);
final httpClient = _configHttpClient(cancelFuture, options.connectTimeout);
final reqFuture = httpClient.openUrl(options.method, options.uri);

late HttpClientRequest request;
try {
Expand Down Expand Up @@ -75,7 +75,7 @@ class IOHttpClientAdapter implements HttpClientAdapter {
throw DioError.connectionTimeout(
requestOptions: options,
timeout: options.connectTimeout ??
_httpClient.connectionTimeout ??
httpClient.connectionTimeout ??
Duration.zero,
error: e,
stackTrace: stackTrace,
Expand All @@ -87,8 +87,8 @@ class IOHttpClientAdapter implements HttpClientAdapter {
request.persistentConnection = options.persistentConnection;

if (requestStream != null) {
// Transform the request data
var future = request.addStream(requestStream);
// Transform the request data.
Future<dynamic> future = request.addStream(requestStream);
final sendTimeout = options.sendTimeout;
if (sendTimeout != null) {
future = future.timeout(
Expand All @@ -107,7 +107,7 @@ class IOHttpClientAdapter implements HttpClientAdapter {
}

final stopwatch = Stopwatch()..start();
var future = request.close();
Future<HttpClientResponse> future = request.close();
final receiveTimeout = options.receiveTimeout;
if (receiveTimeout != null) {
future = future.timeout(
Expand Down Expand Up @@ -138,7 +138,7 @@ class IOHttpClientAdapter implements HttpClientAdapter {
}
}

var stream =
final stream =
responseStream.transform<Uint8List>(StreamTransformer.fromHandlers(
handleData: (data, sink) {
stopwatch.stop();
Expand All @@ -158,7 +158,7 @@ class IOHttpClientAdapter implements HttpClientAdapter {
},
));

var headers = <String, List<String>>{};
final headers = <String, List<String>>{};
responseStream.headers.forEach((key, values) {
headers[key] = values;
});
Expand All @@ -176,37 +176,23 @@ class IOHttpClientAdapter implements HttpClientAdapter {
}

HttpClient _configHttpClient(
Future? cancelFuture,
Future<void>? cancelFuture,
Duration? connectionTimeout,
) {
HttpClient client = onHttpClientCreate?.call(HttpClient()) ?? HttpClient();
if (cancelFuture != null) {
var _httpClient = HttpClient();
_httpClient.userAgent = null;
if (onHttpClientCreate != null) {
//user can return a HttpClient instance
_httpClient = onHttpClientCreate!(_httpClient) ?? _httpClient;
}
_httpClient.idleTimeout = Duration(seconds: 0);
cancelFuture.whenComplete(() {
Future.delayed(Duration(seconds: 0)).then((e) {
try {
_httpClient.close(force: true);
} catch (e) {
//...
}
});
});
return _httpClient..connectionTimeout = connectionTimeout;
client.userAgent = null;
client.idleTimeout = Duration(seconds: 0);
cancelFuture.whenComplete(() => client.close(force: true));
return client..connectionTimeout = connectionTimeout;
}
if (_defaultHttpClient == null) {
_defaultHttpClient = HttpClient();
_defaultHttpClient!.idleTimeout = Duration(seconds: 3);
if (onHttpClientCreate != null) {
//user can return a HttpClient instance
_defaultHttpClient =
onHttpClientCreate!(_defaultHttpClient!) ?? _defaultHttpClient;
client.idleTimeout = Duration(seconds: 3);
if (onHttpClientCreate?.call(client) != null) {
client = onHttpClientCreate!(client)!;
}
_defaultHttpClient!.connectionTimeout = connectionTimeout;
client.connectionTimeout = connectionTimeout;
_defaultHttpClient = client;
}
return _defaultHttpClient!..connectionTimeout = connectionTimeout;
}
Expand Down
6 changes: 0 additions & 6 deletions dio/lib/src/adapters/universal_adapter.dart

This file was deleted.

Loading

0 comments on commit 6bc14fd

Please sign in to comment.