@@ -6,7 +6,8 @@ use console::Term;
6
6
use iroh:: { NodeId , SecretKey } ;
7
7
use iroh_blobs:: {
8
8
downloader2:: {
9
- DownloadRequest , Downloader , ObserveEvent , ObserveRequest , StaticContentDiscovery ,
9
+ print_bitmap, DownloadRequest , Downloader , ObserveEvent , ObserveRequest ,
10
+ StaticContentDiscovery ,
10
11
} ,
11
12
store:: Store ,
12
13
util:: total_bytes,
@@ -30,7 +31,11 @@ struct DownloadArgs {
30
31
#[ clap( help = "hash to download" ) ]
31
32
hash : Hash ,
32
33
34
+ #[ clap( help = "providers to download from" ) ]
33
35
providers : Vec < NodeId > ,
36
+
37
+ #[ clap( long, help = "path to save to" ) ]
38
+ path : Option < PathBuf > ,
34
39
}
35
40
36
41
#[ derive( Debug , Parser ) ]
@@ -139,77 +144,28 @@ impl BlobDownloadProgress {
139
144
}
140
145
}
141
146
142
- fn bitmap ( current : & [ ChunkNum ] , requested : & [ ChunkNum ] , n : usize ) -> String {
143
- // If n is 0, return an empty string.
144
- if n == 0 {
145
- return String :: new ( ) ;
146
- }
147
-
148
- // Determine the overall bitfield size.
149
- // Since the ranges are sorted, we take the last element as the total size.
150
- let total = if let Some ( & last) = requested. last ( ) {
151
- last. 0
152
- } else {
153
- // If there are no ranges, we assume the bitfield is empty.
154
- 0
155
- } ;
156
-
157
- // If total is 0, output n spaces.
158
- if total == 0 {
159
- return " " . repeat ( n) ;
160
- }
161
-
162
- let mut result = String :: with_capacity ( n) ;
163
-
164
- // For each of the n output buckets:
165
- for bucket in 0 ..n {
166
- // Calculate the bucket's start and end in the overall bitfield.
167
- let bucket_start = bucket as u64 * total / n as u64 ;
168
- let bucket_end = ( bucket as u64 + 1 ) * total / n as u64 ;
169
- let bucket_size = bucket_end. saturating_sub ( bucket_start) ;
170
-
171
- // Sum the number of bits that are set in this bucket.
172
- let mut set_bits = 0u64 ;
173
- for pair in current. chunks_exact ( 2 ) {
174
- let start = pair[ 0 ] ;
175
- let end = pair[ 1 ] ;
176
- // Determine the overlap between the bucket and the current range.
177
- let overlap_start = start. 0 . max ( bucket_start) ;
178
- let overlap_end = end. 0 . min ( bucket_end) ;
179
- if overlap_start < overlap_end {
180
- set_bits += overlap_end - overlap_start;
181
- }
147
+ async fn download ( args : DownloadArgs ) -> anyhow:: Result < ( ) > {
148
+ match & args. path {
149
+ Some ( path) => {
150
+ tokio:: fs:: create_dir_all ( path) . await ?;
151
+ let store = iroh_blobs:: store:: fs:: Store :: load ( path) . await ?;
152
+ // make sure we properly shut down the store on ctrl-c
153
+ let res = tokio:: select! {
154
+ x = download_impl( args, store. clone( ) ) => x,
155
+ _ = tokio:: signal:: ctrl_c( ) => Ok ( ( ) ) ,
156
+ } ;
157
+ store. shutdown ( ) . await ;
158
+ res
159
+ }
160
+ None => {
161
+ let store = iroh_blobs:: store:: mem:: Store :: new ( ) ;
162
+ download_impl ( args, store) . await
182
163
}
183
-
184
- // Calculate the fraction of the bucket that is set.
185
- let fraction = if bucket_size > 0 {
186
- set_bits as f64 / bucket_size as f64
187
- } else {
188
- 0.0
189
- } ;
190
-
191
- // Map the fraction to a grayscale character.
192
- let ch = if fraction == 0.0 {
193
- ' ' // completely empty
194
- } else if fraction == 1.0 {
195
- '█' // completely full
196
- } else if fraction < 0.25 {
197
- '░'
198
- } else if fraction < 0.5 {
199
- '▒'
200
- } else {
201
- '▓'
202
- } ;
203
-
204
- result. push ( ch) ;
205
164
}
206
-
207
- result
208
165
}
209
166
210
- async fn download ( args : DownloadArgs ) -> anyhow:: Result < ( ) > {
167
+ async fn download_impl < S : Store > ( args : DownloadArgs , store : S ) -> anyhow:: Result < ( ) > {
211
168
let endpoint = iroh:: Endpoint :: builder ( ) . discovery_n0 ( ) . bind ( ) . await ?;
212
- let store = iroh_blobs:: store:: mem:: Store :: new ( ) ;
213
169
let discovery = StaticContentDiscovery :: new ( Default :: default ( ) , args. providers ) ;
214
170
let downloader = Downloader :: builder ( endpoint, store)
215
171
. discovery ( discovery)
@@ -233,7 +189,7 @@ async fn download(args: DownloadArgs) -> anyhow::Result<()> {
233
189
progress. update ( chunk) ;
234
190
let current = progress. current . boundaries ( ) ;
235
191
let requested = progress. request . ranges . boundaries ( ) ;
236
- let bitmap = bitmap ( current, requested, rows as usize ) ;
192
+ let bitmap = print_bitmap ( current, requested, rows as usize ) ;
237
193
print ! ( "\r {bitmap}" ) ;
238
194
if progress. is_done ( ) {
239
195
println ! ( ) ;
0 commit comments