Skip to content

Commit b16c0fa

Browse files
committed
Setup callback for send data progress
1 parent 7f21111 commit b16c0fa

File tree

9 files changed

+227
-46
lines changed

9 files changed

+227
-46
lines changed

pkgs/http/lib/http.dart

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:typed_data';
1010

1111
import 'src/client.dart';
1212
import 'src/exception.dart';
13+
import 'src/progress.dart';
1314
import 'src/request.dart';
1415
import 'src/response.dart';
1516
import 'src/streamed_request.dart';
@@ -23,6 +24,7 @@ export 'src/client.dart' hide zoneClient;
2324
export 'src/exception.dart';
2425
export 'src/multipart_file.dart';
2526
export 'src/multipart_request.dart';
27+
export 'src/progress.dart';
2628
export 'src/request.dart';
2729
export 'src/response.dart';
2830
export 'src/streamed_request.dart';
@@ -64,12 +66,25 @@ Future<Response> get(Uri url, {Map<String, String>? headers}) =>
6466
///
6567
/// [encoding] defaults to [utf8].
6668
///
69+
/// If [onSendProgress] is provided it will be called to indicate
70+
/// the upload progress
71+
///
6772
/// For more fine-grained control over the request, use [Request] or
6873
/// [StreamedRequest] instead.
69-
Future<Response> post(Uri url,
70-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
71-
_withClient((client) =>
72-
client.post(url, headers: headers, body: body, encoding: encoding));
74+
Future<Response> post(
75+
Uri url, {
76+
Map<String, String>? headers,
77+
Object? body,
78+
Encoding? encoding,
79+
Progress? onSendProgress,
80+
}) =>
81+
_withClient((client) => client.post(
82+
url,
83+
headers: headers,
84+
body: body,
85+
encoding: encoding,
86+
onSendProgress: onSendProgress,
87+
));
7388

7489
/// Sends an HTTP PUT request with the given headers and body to the given URL.
7590
///
@@ -87,12 +102,25 @@ Future<Response> post(Uri url,
87102
///
88103
/// [encoding] defaults to [utf8].
89104
///
105+
/// If [onSendProgress] is provided it will be called to indicate
106+
/// the upload progress
107+
///
90108
/// For more fine-grained control over the request, use [Request] or
91109
/// [StreamedRequest] instead.
92-
Future<Response> put(Uri url,
93-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
94-
_withClient((client) =>
95-
client.put(url, headers: headers, body: body, encoding: encoding));
110+
Future<Response> put(
111+
Uri url, {
112+
Map<String, String>? headers,
113+
Object? body,
114+
Encoding? encoding,
115+
Progress? onSendProgress,
116+
}) =>
117+
_withClient((client) => client.put(
118+
url,
119+
headers: headers,
120+
body: body,
121+
encoding: encoding,
122+
onSendProgress: onSendProgress,
123+
));
96124

97125
/// Sends an HTTP PATCH request with the given headers and body to the given
98126
/// URL.
@@ -111,24 +139,50 @@ Future<Response> put(Uri url,
111139
///
112140
/// [encoding] defaults to [utf8].
113141
///
142+
/// If [onSendProgress] is provided it will be called to indicate
143+
/// the upload progress
144+
///
114145
/// For more fine-grained control over the request, use [Request] or
115146
/// [StreamedRequest] instead.
116-
Future<Response> patch(Uri url,
117-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
118-
_withClient((client) =>
119-
client.patch(url, headers: headers, body: body, encoding: encoding));
147+
Future<Response> patch(
148+
Uri url, {
149+
Map<String, String>? headers,
150+
Object? body,
151+
Encoding? encoding,
152+
Progress? onSendProgress,
153+
}) =>
154+
_withClient((client) => client.patch(
155+
url,
156+
headers: headers,
157+
body: body,
158+
encoding: encoding,
159+
onSendProgress: onSendProgress,
160+
));
120161

121162
/// Sends an HTTP DELETE request with the given headers to the given URL.
122163
///
123164
/// This automatically initializes a new [Client] and closes that client once
124165
/// the request is complete. If you're planning on making multiple requests to
125166
/// the same server, you should use a single [Client] for all of those requests.
126167
///
168+
/// If [onSendProgress] is provided it will be called to indicate
169+
/// the upload progress
170+
///
127171
/// For more fine-grained control over the request, use [Request] instead.
128-
Future<Response> delete(Uri url,
129-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
130-
_withClient((client) =>
131-
client.delete(url, headers: headers, body: body, encoding: encoding));
172+
Future<Response> delete(
173+
Uri url, {
174+
Map<String, String>? headers,
175+
Object? body,
176+
Encoding? encoding,
177+
Progress? onSendProgress,
178+
}) =>
179+
_withClient((client) => client.delete(
180+
url,
181+
headers: headers,
182+
body: body,
183+
encoding: encoding,
184+
onSendProgress: onSendProgress,
185+
));
132186

133187
/// Sends an HTTP GET request with the given headers to the given URL and
134188
/// returns a Future that completes to the body of the response as a [String].

pkgs/http/lib/retry.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ final class RetryClient extends BaseClient {
105105
);
106106

107107
@override
108-
Future<StreamedResponse> send(BaseRequest request) async {
108+
Future<StreamedResponse> send(
109+
BaseRequest request, {
110+
Progress? onSendProgress,
111+
}) async {
109112
final splitter = StreamSplitter(request.finalize());
110113

111114
var i = 0;
112115
for (;;) {
113116
StreamedResponse? response;
114117
try {
115-
response = await _inner.send(_copyRequest(request, splitter.split()));
118+
response = await _inner.send(
119+
_copyRequest(request, splitter.split()),
120+
onSendProgress: onSendProgress,
121+
);
116122
} catch (error, stackTrace) {
117123
if (i == _retries || !await _whenError(error, stackTrace)) rethrow;
118124
}

pkgs/http/lib/src/base_client.dart

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'base_request.dart';
99
import 'byte_stream.dart';
1010
import 'client.dart';
1111
import 'exception.dart';
12+
import 'progress.dart';
1213
import 'request.dart';
1314
import 'response.dart';
1415
import 'streamed_response.dart';
@@ -27,24 +28,72 @@ abstract mixin class BaseClient implements Client {
2728
_sendUnstreamed('GET', url, headers);
2829

2930
@override
30-
Future<Response> post(Uri url,
31-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
32-
_sendUnstreamed('POST', url, headers, body, encoding);
31+
Future<Response> post(
32+
Uri url, {
33+
Map<String, String>? headers,
34+
Object? body,
35+
Encoding? encoding,
36+
Progress? onSendProgress,
37+
}) =>
38+
_sendUnstreamed(
39+
'POST',
40+
url,
41+
headers,
42+
body,
43+
encoding,
44+
onSendProgress,
45+
);
3346

3447
@override
35-
Future<Response> put(Uri url,
36-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
37-
_sendUnstreamed('PUT', url, headers, body, encoding);
48+
Future<Response> put(
49+
Uri url, {
50+
Map<String, String>? headers,
51+
Object? body,
52+
Encoding? encoding,
53+
Progress? onSendProgress,
54+
}) =>
55+
_sendUnstreamed(
56+
'PUT',
57+
url,
58+
headers,
59+
body,
60+
encoding,
61+
onSendProgress,
62+
);
3863

3964
@override
40-
Future<Response> patch(Uri url,
41-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
42-
_sendUnstreamed('PATCH', url, headers, body, encoding);
65+
Future<Response> patch(
66+
Uri url, {
67+
Map<String, String>? headers,
68+
Object? body,
69+
Encoding? encoding,
70+
Progress? onSendProgress,
71+
}) =>
72+
_sendUnstreamed(
73+
'PATCH',
74+
url,
75+
headers,
76+
body,
77+
encoding,
78+
onSendProgress,
79+
);
4380

4481
@override
45-
Future<Response> delete(Uri url,
46-
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
47-
_sendUnstreamed('DELETE', url, headers, body, encoding);
82+
Future<Response> delete(
83+
Uri url, {
84+
Map<String, String>? headers,
85+
Object? body,
86+
Encoding? encoding,
87+
Progress? onSendProgress,
88+
}) =>
89+
_sendUnstreamed(
90+
'DELETE',
91+
url,
92+
headers,
93+
body,
94+
encoding,
95+
onSendProgress,
96+
);
4897

4998
@override
5099
Future<String> read(Uri url, {Map<String, String>? headers}) async {
@@ -68,12 +117,15 @@ abstract mixin class BaseClient implements Client {
68117
/// later point, or it could already be closed when it's returned. Any
69118
/// internal HTTP errors should be wrapped as [ClientException]s.
70119
@override
71-
Future<StreamedResponse> send(BaseRequest request);
120+
Future<StreamedResponse> send(
121+
BaseRequest request, {
122+
Progress? onSendProgress,
123+
});
72124

73125
/// Sends a non-streaming [Request] and returns a non-streaming [Response].
74126
Future<Response> _sendUnstreamed(
75127
String method, Uri url, Map<String, String>? headers,
76-
[Object? body, Encoding? encoding]) async {
128+
[Object? body, Encoding? encoding, Progress? onSendProgress]) async {
77129
var request = Request(method, url);
78130

79131
if (headers != null) request.headers.addAll(headers);
@@ -90,7 +142,10 @@ abstract mixin class BaseClient implements Client {
90142
}
91143
}
92144

93-
return Response.fromStream(await send(request));
145+
return Response.fromStream(await send(
146+
request,
147+
onSendProgress: onSendProgress,
148+
));
94149
}
95150

96151
/// Throws an error if [response] is not successful.

pkgs/http/lib/src/base_request.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'base_client.dart';
1111
import 'base_response.dart';
1212
import 'byte_stream.dart';
1313
import 'client.dart';
14+
import 'progress.dart';
1415
import 'streamed_response.dart';
1516
import 'utils.dart';
1617

@@ -27,6 +28,9 @@ abstract class BaseRequest {
2728
/// Non-standard method names are also supported.
2829
final String method;
2930

31+
/// The callback to call for data send progress.
32+
Progress? onSendProgress;
33+
3034
/// The URL to which the request will be sent.
3135
final Uri url;
3236

@@ -130,7 +134,10 @@ abstract class BaseRequest {
130134
var client = Client();
131135

132136
try {
133-
var response = await client.send(this);
137+
var response = await client.send(
138+
this,
139+
onSendProgress: onSendProgress,
140+
);
134141
var stream = onDone(response.stream, client.close);
135142

136143
if (response case BaseResponseWithUrl(:final url)) {

pkgs/http/lib/src/browser_client.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'base_client.dart';
1111
import 'base_request.dart';
1212
import 'byte_stream.dart';
1313
import 'exception.dart';
14+
import 'progress.dart';
1415
import 'streamed_response.dart';
1516

1617
final _digitRegex = RegExp(r'^\d+$');
@@ -50,7 +51,10 @@ class BrowserClient extends BaseClient {
5051

5152
/// Sends an HTTP request and asynchronously returns the response.
5253
@override
53-
Future<StreamedResponse> send(BaseRequest request) async {
54+
Future<StreamedResponse> send(
55+
BaseRequest request,
56+
Progress? onSendProgress,
57+
) async {
5458
if (_isClosed) {
5559
throw ClientException(
5660
'HTTP request failed. Client is already closed.', request.url);

0 commit comments

Comments
 (0)