downloadStream method

Future<Stream<BinaryContent>> downloadStream(
  1. String path, {
  2. int chunkSize = 64 * 1024,
})

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();
}