getBlob method

  1. @override
Future<BlobResponse> getBlob({
  1. required String sha256,
  2. required List<String> serverUrls,
  3. Nip01Event? authorization,
  4. int? start,
  5. int? end,
})
override

Gets a blob by trying servers sequentially until success If authorization is null, the server must be public If start and end are null, the entire blob is returned start and end are used to download a range of bytes, @see MDN HTTP range requests

Implementation

@override
Future<BlobResponse> getBlob({
  required String sha256,
  required List<String> serverUrls,
  Nip01Event? authorization,
  int? start,
  int? end,
}) async {
  Exception? lastError;

  for (final url in serverUrls) {
    try {
      final headers = <String, String>{};
      if (start != null) {
        // Create range header in format "bytes=start-end"
        // If end is null, it means "until the end of the file"
        headers['range'] = 'bytes=$start-${end ?? ''}';
      }

      if (authorization != null) {
        headers['Authorization'] = "Nostr ${authorization.toBase64()}";
      }

      final response = await client.get(
        url: Uri.parse('$url/$sha256'),
        headers: headers,
      );

      // Check for both 200 (full content) and 206 (partial content) status codes
      if (response.statusCode == 200 || response.statusCode == 206) {
        return BlobResponse(
          data: response.bodyBytes,
          mimeType: response.headers['content-type'],
          contentLength:
              int.tryParse(response.headers['content-length'] ?? ''),
          contentRange: response.headers['content-range'] ?? '',
        );
      }
      lastError = Exception('HTTP ${response.statusCode}');
    } catch (e) {
      lastError = e is Exception ? e : Exception(e.toString());
    }
  }

  throw Exception(
      'Failed to get blob from any of the servers. Last error: $lastError');
}