getBlobStream method

  1. @override
Future<Stream<BlobResponse>> getBlobStream({
  1. required String sha256,
  2. required List<String> serverUrls,
  3. Nip01Event? authorization,
  4. int chunkSize = 1024 * 1024,
})
override

checks if the server supports range requests, if no server supports range requests, the entire blob is returned otherwise, the blob is returned in chunks. @see MDN HTTP range requests

Implementation

@override
Future<Stream<BlobResponse>> getBlobStream({
  required String sha256,
  required List<String> serverUrls,
  Nip01Event? authorization,
  int chunkSize = 1024 * 1024, // 1MB chunks
}) async {
  // Find a server that supports range requests
  String? supportedServer;
  int? contentLength;

  for (final url in serverUrls) {
    try {
      final rangeResponse = await supportsRangeRequests(
        sha256: sha256,
        serverUrl: url,
      );
      if (rangeResponse.first) {
        supportedServer = url;
        contentLength = rangeResponse.second;
        break;
      }
    } catch (_) {
      continue;
    }
  }

  if (supportedServer == null || contentLength == null) {
    // Fallback to regular download if no server supports range requests
    final bytes = await getBlob(sha256: sha256, serverUrls: serverUrls);
    return Stream.value(bytes);
  }

  // Create a stream controller to manage the chunks
  final controller = StreamController<BlobResponse>();

  // Start downloading chunks
  int offset = 0;
  while (offset < contentLength) {
    final end = (offset + chunkSize - 1).clamp(0, contentLength - 1);

    try {
      final chunk = await getBlob(
        sha256: sha256,
        serverUrls: [supportedServer],
        start: offset,
        end: end,
      );
      controller.add(chunk);
      offset = end + 1;
    } catch (e) {
      await controller.close();
      rethrow;
    }
  }

  await controller.close();
  return controller.stream;
}