@@ -29,8 +29,11 @@ use n0_future::{future, stream, Stream, StreamExt};
29
29
use quinn:: SendStream ;
30
30
use range_collections:: { range_set:: RangeSetRange , RangeSet2 } ;
31
31
use ref_cast:: RefCast ;
32
+ use serde:: { Deserialize , Serialize } ;
32
33
use tokio:: io:: AsyncWriteExt ;
33
34
use tracing:: trace;
35
+ mod reader;
36
+ pub use reader:: BlobReader ;
34
37
35
38
// Public reexports from the proto module.
36
39
//
@@ -102,6 +105,38 @@ impl Blobs {
102
105
} )
103
106
}
104
107
108
+ /// Create a reader for the given hash. The reader implements [`tokio::io::AsyncRead`] and [`tokio::io::AsyncSeek`]
109
+ /// and therefore can be used to read the blob's content.
110
+ ///
111
+ /// Any access to parts of the blob that are not present will result in an error.
112
+ ///
113
+ /// Example:
114
+ /// ```rust
115
+ /// use iroh_blobs::{store::mem::MemStore, api::blobs::Blobs};
116
+ /// use tokio::io::AsyncReadExt;
117
+ ///
118
+ /// # async fn example() -> anyhow::Result<()> {
119
+ /// let store = MemStore::new();
120
+ /// let tag = store.add_slice(b"Hello, world!").await?;
121
+ /// let mut reader = store.reader(tag.hash);
122
+ /// let mut buf = String::new();
123
+ /// reader.read_to_string(&mut buf).await?;
124
+ /// assert_eq!(buf, "Hello, world!");
125
+ /// # Ok(())
126
+ /// }
127
+ /// ```
128
+ pub fn reader ( & self , hash : impl Into < Hash > ) -> BlobReader {
129
+ self . reader_with_opts ( ReaderOptions { hash : hash. into ( ) } )
130
+ }
131
+
132
+ /// Create a reader for the given options. The reader implements [`tokio::io::AsyncRead`] and [`tokio::io::AsyncSeek`]
133
+ /// and therefore can be used to read the blob's content.
134
+ ///
135
+ /// Any access to parts of the blob that are not present will result in an error.
136
+ pub fn reader_with_opts ( & self , options : ReaderOptions ) -> BlobReader {
137
+ BlobReader :: new ( self . clone ( ) , options)
138
+ }
139
+
105
140
/// Delete a blob.
106
141
///
107
142
/// This function is not public, because it does not work as expected when called manually,
@@ -647,6 +682,12 @@ impl<'a> AddProgress<'a> {
647
682
}
648
683
}
649
684
685
+ /// Options for an async reader for blobs that supports AsyncRead and AsyncSeek.
686
+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
687
+ pub struct ReaderOptions {
688
+ pub hash : Hash ,
689
+ }
690
+
650
691
/// An observe result. Awaiting this will return the current state.
651
692
///
652
693
/// Calling [`ObserveProgress::stream`] will return a stream of updates, where
@@ -856,7 +897,7 @@ impl ExportRangesProgress {
856
897
/// range of 0..100, you will get the entire first chunk, 0..1024.
857
898
///
858
899
/// It is up to the caller to clip the ranges to the requested ranges.
859
- pub async fn stream ( self ) -> impl Stream < Item = ExportRangesItem > {
900
+ pub fn stream ( self ) -> impl Stream < Item = ExportRangesItem > {
860
901
Gen :: new ( |co| async move {
861
902
let mut rx = match self . inner . await {
862
903
Ok ( rx) => rx,
0 commit comments