upload<T> method
Future<Result<T> >
upload<T>(
- String path, {
- required List<
UploadFile> files, - Map<
String, String> ? fields, - JsonParser<
T> ? parser, - ProgressCallback? onProgress,
- RequestOptions? options,
override
Handles large multipart file uploads with progress tracking.
Implementation
@override
Future<Result<T>> upload<T>(
String path, {
required List<UploadFile> files,
Map<String, String>? fields,
JsonParser<T>? parser,
ProgressCallback? onProgress,
RequestOptions? options,
}) async {
final builder = MultipartBodyBuilder();
fields?.forEach(builder.addField);
for (final f in files) {
builder.addFile(f, await f.readBytes());
}
final (body, totalBytes) = builder.build();
final effectiveBase = options?.baseUrl ?? _config.baseUrl;
final uri = _buildUri(effectiveBase, path, null);
final headers = _mergeHeaders(_config.defaultHeaders, options?.headers);
headers[HttpHeaders.contentTypeHeader] = builder.contentType;
headers[HttpHeaders.contentLengthHeader] = totalBytes.toString();
HttpClientRequest req;
try {
req = await _http.openUrl('POST', uri);
} on SocketException catch (e) {
return Failure(ConnectionException('Cannot reach ${uri.host}', cause: e));
}
headers.forEach(req.headers.set);
// Stream with progress.
const chunkSize = 65536; // 64 KiB
var sent = 0;
for (var offset = 0; offset < body.length; offset += chunkSize) {
final end = (offset + chunkSize).clamp(0, body.length);
req.add(body.sublist(offset, end));
sent += end - offset;
onProgress?.call(sent, totalBytes);
}
late HttpClientResponse response;
try {
response = await req.close();
} on SocketException catch (e) {
return Failure(
ConnectionException('Upload failed: ${e.message}', cause: e),
);
}
final rawBody = await _readBody(response);
final responseHeaders = <String, String>{};
response.headers.forEach((n, v) => responseHeaders[n] = v.join(', '));
final responseCtx = ResponseContext(
statusCode: response.statusCode,
headers: responseHeaders,
body: rawBody,
request: RequestContext(uri: uri, method: 'POST', headers: headers),
);
return _parseResponse<T>(responseCtx, parser);
}