22
22
//! getter can not connect to an impersonated provider and the provider does not offer the
23
23
//! download to an impersonated getter.
24
24
25
- use std:: cmp:: Ordering ;
26
25
use std:: future:: Future ;
27
26
use std:: net:: Ipv4Addr ;
28
27
use std:: ops:: Deref ;
@@ -33,7 +32,8 @@ use std::task::Poll;
33
32
use anyhow:: { anyhow, bail, ensure, format_err, Context as _, Result } ;
34
33
use async_channel:: Receiver ;
35
34
use futures_lite:: StreamExt ;
36
- use iroh:: get:: { DataStream , Options } ;
35
+ use iroh:: blobs:: Collection ;
36
+ use iroh:: get:: DataStream ;
37
37
use iroh:: progress:: ProgressEmitter ;
38
38
use iroh:: protocol:: AuthToken ;
39
39
use iroh:: provider:: { DataSource , Event , Provider , Ticket } ;
@@ -53,6 +53,8 @@ use crate::{e2ee, EventType};
53
53
54
54
use super :: { export_database, DBFILE_BACKUP_NAME } ;
55
55
56
+ const MAX_CONCURRENT_DIALS : u8 = 16 ;
57
+
56
58
/// Provide or send a backup of this device.
57
59
///
58
60
/// This creates a backup of the current device and starts a service which offers another
@@ -387,122 +389,74 @@ pub async fn get_backup(context: &Context, qr: Qr) -> Result<()> {
387
389
}
388
390
389
391
async fn get_backup_inner ( context : & Context , qr : Qr ) -> Result < ( ) > {
390
- let mut ticket = match qr {
392
+ let ticket = match qr {
391
393
Qr :: Backup { ticket } => ticket,
392
394
_ => bail ! ( "QR code for backup must be of type DCBACKUP" ) ,
393
395
} ;
394
396
if ticket. addrs . is_empty ( ) {
395
397
bail ! ( "ticket is missing addresses to dial" ) ;
396
398
}
397
399
398
- // Crude sorting, most local wifi's are in the 192.168.0.0/24 range so this will try
399
- // them first.
400
- ticket. addrs . sort_by ( |a, b| {
401
- let a = a. to_string ( ) ;
402
- let b = b. to_string ( ) ;
403
- if a. starts_with ( "192.168." ) && !b. starts_with ( "192.168." ) {
404
- Ordering :: Less
405
- } else if b. starts_with ( "192.168." ) && !a. starts_with ( "192.168." ) {
406
- Ordering :: Greater
407
- } else {
408
- Ordering :: Equal
400
+ match transfer_from_provider ( context, & ticket) . await {
401
+ Ok ( ( ) ) => {
402
+ delete_and_reset_all_device_msgs ( context) . await ?;
403
+ context. emit_event ( ReceiveProgress :: Completed . into ( ) ) ;
404
+ Ok ( ( ) )
409
405
}
410
- } ) ;
411
- for addr in & ticket. addrs {
412
- let opts = Options {
413
- addr : * addr,
414
- peer_id : Some ( ticket. peer ) ,
415
- keylog : false ,
416
- } ;
417
- info ! ( context, "attempting to contact {}" , addr) ;
418
- match transfer_from_provider ( context, & ticket, opts) . await {
419
- Ok ( _) => {
420
- delete_and_reset_all_device_msgs ( context) . await ?;
421
- context. emit_event ( ReceiveProgress :: Completed . into ( ) ) ;
422
- return Ok ( ( ) ) ;
423
- }
424
- Err ( TransferError :: ConnectionError ( err) ) => {
425
- warn ! ( context, "Connection error: {err:#}." ) ;
426
- continue ;
427
- }
428
- Err ( TransferError :: Other ( err) ) => {
429
- // Clean up any blobs we already wrote.
430
- let readdir = fs:: read_dir ( context. get_blobdir ( ) ) . await ?;
431
- let mut readdir = ReadDirStream :: new ( readdir) ;
432
- while let Some ( dirent) = readdir. next ( ) . await {
433
- if let Ok ( dirent) = dirent {
434
- fs:: remove_file ( dirent. path ( ) ) . await . ok ( ) ;
435
- }
406
+ Err ( err) => {
407
+ // Clean up any blobs we already wrote.
408
+ let readdir = fs:: read_dir ( context. get_blobdir ( ) ) . await ?;
409
+ let mut readdir = ReadDirStream :: new ( readdir) ;
410
+ while let Some ( dirent) = readdir. next ( ) . await {
411
+ if let Ok ( dirent) = dirent {
412
+ fs:: remove_file ( dirent. path ( ) ) . await . ok ( ) ;
436
413
}
437
- context. emit_event ( ReceiveProgress :: Failed . into ( ) ) ;
438
- return Err ( err) ;
439
414
}
415
+ context. emit_event ( ReceiveProgress :: Failed . into ( ) ) ;
416
+ Err ( err)
440
417
}
441
418
}
442
- Err ( anyhow ! ( "failed to contact provider" ) )
443
- }
444
-
445
- /// Error during a single transfer attempt.
446
- ///
447
- /// Mostly exists to distinguish between `ConnectionError` and any other errors.
448
- #[ derive( Debug , thiserror:: Error ) ]
449
- enum TransferError {
450
- #[ error( "connection error" ) ]
451
- ConnectionError ( #[ source] anyhow:: Error ) ,
452
- #[ error( "other" ) ]
453
- Other ( #[ source] anyhow:: Error ) ,
454
419
}
455
420
456
- async fn transfer_from_provider (
457
- context : & Context ,
458
- ticket : & Ticket ,
459
- opts : Options ,
460
- ) -> Result < ( ) , TransferError > {
421
+ async fn transfer_from_provider ( context : & Context , ticket : & Ticket ) -> Result < ( ) > {
461
422
let progress = ProgressEmitter :: new ( 0 , ReceiveProgress :: max_blob_progress ( ) ) ;
462
423
spawn_progress_proxy ( context. clone ( ) , progress. subscribe ( ) ) ;
463
- let mut connected = false ;
464
424
let on_connected = || {
465
425
context. emit_event ( ReceiveProgress :: Connected . into ( ) ) ;
466
- connected = true ;
426
+ async { Ok ( ( ) ) }
427
+ } ;
428
+ let on_collection = |collection : & Collection | {
429
+ context. emit_event ( ReceiveProgress :: CollectionReceived . into ( ) ) ;
430
+ progress. set_total ( collection. total_blobs_size ( ) ) ;
467
431
async { Ok ( ( ) ) }
468
432
} ;
469
433
let jobs = Mutex :: new ( JoinSet :: default ( ) ) ;
470
434
let on_blob =
471
435
|hash, reader, name| on_blob ( context, & progress, & jobs, ticket, hash, reader, name) ;
472
- let res = iroh:: get:: run (
473
- ticket. hash ,
474
- ticket. token ,
475
- opts,
436
+
437
+ // Perform the transfer.
438
+ let keylog = false ; // Do not enable rustls SSLKEYLOGFILE env var functionality
439
+ let stats = iroh:: get:: run_ticket (
440
+ ticket,
441
+ keylog,
442
+ MAX_CONCURRENT_DIALS ,
476
443
on_connected,
477
- |collection| {
478
- context. emit_event ( ReceiveProgress :: CollectionReceived . into ( ) ) ;
479
- progress. set_total ( collection. total_blobs_size ( ) ) ;
480
- async { Ok ( ( ) ) }
481
- } ,
444
+ on_collection,
482
445
on_blob,
483
446
)
484
- . await ;
447
+ . await ? ;
485
448
486
449
let mut jobs = jobs. lock ( ) . await ;
487
450
while let Some ( job) = jobs. join_next ( ) . await {
488
- job. context ( "job failed" ) . map_err ( TransferError :: Other ) ?;
451
+ job. context ( "job failed" ) ?;
489
452
}
490
-
491
453
drop ( progress) ;
492
- match res {
493
- Ok ( stats) => {
494
- info ! (
495
- context,
496
- "Backup transfer finished, transfer rate is {} Mbps." ,
497
- stats. mbits( )
498
- ) ;
499
- Ok ( ( ) )
500
- }
501
- Err ( err) => match connected {
502
- true => Err ( TransferError :: Other ( err) ) ,
503
- false => Err ( TransferError :: ConnectionError ( err) ) ,
504
- } ,
505
- }
454
+ info ! (
455
+ context,
456
+ "Backup transfer finished, transfer rate was {} Mbps." ,
457
+ stats. mbits( )
458
+ ) ;
459
+ Ok ( ( ) )
506
460
}
507
461
508
462
/// Get callback when a blob is received from the provider.
0 commit comments