downloadStream method
Implementation
Future<Stream<BinaryContent>> downloadStream(String path, {int chunkSize = 64 * 1024}) async {
final input = _StorageDownloadInputStream(path: path, chunkSize: chunkSize);
final output = await room.invoke(toolkit: "storage", tool: "download", input: ToolStreamInput(input.inputStream()));
if (output is! ToolStreamOutput) {
input.close();
throw _unexpectedResponseError("download");
}
Stream<BinaryContent> stream() async* {
var metadataReceived = false;
int? expectedSize;
var bytesReceived = 0;
try {
await for (final chunk in output.stream) {
if (chunk is ErrorContent) {
throw RoomServerException(chunk.text, code: chunk.code);
}
if (chunk is ControlContent) {
if (chunk.method == "close") {
if (!metadataReceived || expectedSize == null || bytesReceived != expectedSize) {
throw _unexpectedResponseError("download");
}
return;
}
throw _unexpectedResponseError("download");
}
if (chunk is! BinaryContent) {
throw _unexpectedResponseError("download");
}
final kind = chunk.headers["kind"];
if (kind == "start") {
final chunkName = chunk.headers["name"];
final chunkMimeType = chunk.headers["mime_type"];
final chunkSizeValue = chunk.headers["size"];
if (chunkName is! String || chunkMimeType is! String || chunkSizeValue is! int || chunkSizeValue < 0) {
throw _unexpectedResponseError("download");
}
metadataReceived = true;
expectedSize = chunkSizeValue;
yield chunk;
if (expectedSize > 0) {
input.requestNext();
}
continue;
}
if (kind != "data" || !metadataReceived || expectedSize == null) {
throw _unexpectedResponseError("download");
}
bytesReceived += chunk.data.length;
if (bytesReceived > expectedSize) {
throw _unexpectedResponseError("download");
}
yield chunk;
if (bytesReceived < expectedSize) {
input.requestNext();
}
}
} finally {
input.close();
}
}
return stream();
}