multipart method
Future<String>
multipart(
- SharedFile file, {
- bool? storeMode,
- ProgressListener? onProgress,
- CancelToken? cancelToken,
- int? maxConcurrentChunkRequests,
Make upload to /multipart
endpoint
maxConcurrentChunkRequests
maximum concurrent requests
cancelToken
make cancelable request
Implementation
Future<String> multipart(
SharedFile file, {
bool? storeMode,
ProgressListener? onProgress,
CancelToken? cancelToken,
int? maxConcurrentChunkRequests,
}) async {
maxConcurrentChunkRequests ??= options.multipartMaxConcurrentChunkRequests;
final filename = file.name;
final filesize = await file.length();
final mimeType = file.mimeType;
assert(filesize > _kRecomendedMaxFilesizeForBaseUpload,
'Minimum file size to use with Multipart Uploads is 10MB');
final completer = Completer<String>();
final startTransaction = createMultipartRequest(
'POST', buildUri('$uploadUrl/multipart/start/'), false)
..fields.addAll({
'UPLOADCARE_PUB_KEY': publicKey,
'UPLOADCARE_STORE': resolveStoreModeParam(storeMode),
'filename': filename,
'size': filesize.toString(),
'content_type': mimeType,
if (options.useSignedUploads) ..._signUpload(),
});
if (cancelToken != null) {
cancelToken.onCancel = _completeWithError(
completer: completer,
action: () => startTransaction.cancel(),
cancelMessage: cancelToken.cancelMessage,
);
}
// ignore: unawaited_futures
resolveStreamedResponse(startTransaction.send()).then((map) {
final urls = (map['parts'] as List).cast<String>();
final uuid = map['uuid'] as String;
final inProgressActions = <UcRequest>[];
ProgressEntity progress = ProgressEntity(0, filesize);
if (onProgress != null) onProgress(progress);
return Future.wait(List.generate(urls.length, (index) {
final url = urls[index];
final offset = index * _kChunkSize;
final diff = filesize - offset;
final bytesToRead = _kChunkSize < diff ? _kChunkSize : diff;
return Future.value(() {
if (cancelToken != null && cancelToken.isCanceled) {
return Future.value(null);
}
return file
.openRead(offset, offset + bytesToRead)
.toList()
.then((bytesList) => bytesList.expand((list) => list).toList())
.then((bytes) => createRequest('PUT', buildUri(url), false)
..bodyBytes = bytes
..headers.addAll({
'Content-Type': mimeType,
}))
.then((request) {
inProgressActions.add(request);
return resolveStreamedResponseStatusCode(request.send())
.then((response) {
inProgressActions.remove(request);
if (onProgress != null) {
onProgress(progress = progress.copyWith(
uploaded: progress.uploaded + bytesToRead,
));
}
return response;
});
});
});
})).then((actions) {
if (cancelToken != null) {
cancelToken.onCancel = _completeWithError(
completer: completer,
action: () => inProgressActions.forEach(
(request) => request.cancel(),
),
cancelMessage: cancelToken.cancelMessage,
);
}
return ConcurrentRunner<Response?>(maxConcurrentChunkRequests!, actions)
.run();
}).then((_) {
final finishTransaction = createMultipartRequest(
'POST', buildUri('$uploadUrl/multipart/complete/'), false)
..fields.addAll({
'UPLOADCARE_PUB_KEY': publicKey,
'uuid': uuid,
if (options.useSignedUploads) ..._signUpload(),
});
if (!completer.isCompleted) {
completer.complete(
resolveStreamedResponse(finishTransaction.send()).then((_) => uuid),
);
}
});
}).catchError((e) {
if (!completer.isCompleted) {
completer.completeError(e);
}
});
return completer.future;
}