magic-wormhole / magic-wormhole.rs

Rust implementation of Magic Wormhole, with new features and enhancements
European Union Public License 1.2
722 stars 78 forks source link

init_add_porgressbar #112

Closed moaz-mokhtar closed 3 years ago

moaz-mokhtar commented 3 years ago

Progress Bar added as discussed in issue #98 .

ryanmcgrath commented 3 years ago

I think, ideally, this shouldn't use ProgressBar outside of the bin/src example - by using it in src/transfer you're expecting that every client would be a console application, but this doesn't hold true if someone's building a GUI on top of this.

moaz-mokhtar commented 3 years ago

I think, ideally, this shouldn't use ProgressBar outside of the bin/src example - by using it in src/transfer you're expecting that every client would be a console application, but this doesn't hold true if someone's building a GUI on top of this.

I'm very thankful for this notice @ryanmcgrath . I'm going to redesign the solution but where should the console progress bar appeared?

ryanmcgrath commented 3 years ago

So you want to edit src/bin/main.rs to do any actual ProgressBar creation/update calls. src/transfer.rs (and any other files) should really just have a reporting mechanism so that any higher level progress bar can reflect it.

You could expose this with a channel, I think - or maybe just take a callback method like Fn(progress) that fires, and any handler can then update however necessary.

moaz-mokhtar commented 3 years ago

I have a challenge for this issue. Still I'm studying how to fix, but need more hints.

moaz-mokhtar commented 3 years ago

I found a library called notify which can notify about file status which can be used. But it is challenging how to apply the concept.

ryanmcgrath commented 3 years ago

Mmm, I'm not sure this needs another crate to solve the issue - can you pass an Fn(u64) down, and instead of calling pbr.set, call that?

Then, for example, the bin/ example could create a progressbar, and just pass a callback to update it.

piegamesde commented 3 years ago

What exactly are your struggling with?

The way I'd go about this is to simply move the progress bar code into main.rs, and then ask myself "which information do I need that must be exposed by the library in order to make this work again?".

moaz-mokhtar commented 3 years ago

Thank you for cooperation and feedback.

I did implement below:

transfer.rs

// ============= Applying transfer progresison report ======
#[derive(Debug)]
pub struct TransferWatcher {
    transferred: u64,
    total: u64,
}

impl TransferWatcher {
    pub fn new(_total: u64) -> Self {
        TransferWatcher {
            total: _total,
            transferred: 0,
        }
    }

    pub fn update_transferred(&mut self, _transferred: u64) {
        self.transferred = self.transferred + _transferred;
    }
}

 ... 
// encrypt and send the file to tcp stream and return the sha256 sum
// of the file before encryption.
async fn send_records( ... ) -> Result<Vec<u8>> {
 ... 
    let mut transfer_watcher = TransferWatcher::new(file_size);
 ... 
    loop {
        // read a block of 4096 bytes
        let n = file.read(&mut plaintext[..]).await?;
        count += n;
        // debug!("sending {} bytes", n);

        // send the encrypted record
        transit.send_record(&plaintext[0..n]).await?;

        transfer_watcher.update_transferred(
            count
                .to_value()
                .to_u64()
                .expect("Can't convert to usize to u64."),
        );

 ... 
    }
    // pb.finish_print("Transfer done");

    Ok(hasher.finalize_fixed().to_vec())
}

My challenge is how the main.rs reported each time transferred data changed. Below is the function in the main.rs which sending the file.

main.rs: send_file function

 ... 
transfer::send_file(&mut wormhole, file, &relay_server.parse().unwrap())
            .await
            .unwrap();
 ... 

transfer.rs: send_file function

/// Send a file to the other side
pub async fn send_file( ... ) -> Result<()> {
 ... 
    debug!("Beginning file transfer");

    tcp_file_send(&mut transit, &filepath)
        .await
        .context("Could not send file")
}

transfer.rs: tcp_file_send function

async fn tcp_file_send( ... ) -> Result<()> {
    // 11. send the file as encrypted records.
    let checksum = send_records(filepath, transit).await?;
 ... 
    debug!("transfer complete!");
    Ok(())
}
piegamesde commented 3 years ago

Yes, that's a tricky question. You basically have two options on how to implement this right now:

  1. You can take in a callback (as function pointer, probably FnMut) while sending, that you call every time some progress is made. The main then passes a callback that updates the progress bar from that data.
  2. You can use a communication channel (Sender/Receiver) pair. The main then spawns a new task before sending, that listens in the loop on the receiver for some progress information to display. The transfer logic pushes updates on to the sender side when progress is made.
moaz-mokhtar commented 3 years ago

Apologize, I'm still facing a challenge and working on it.

piegamesde commented 3 years ago

I'm going to close this as superseded by #116. Thank you for your efforts. If you want, you can pick it up after #116 is merged and make the CLI more pretty.

moaz-mokhtar commented 3 years ago

Very thankful for your cooperation, and apologize which I didn't finalize it.

piegamesde commented 3 years ago

No worries. We're all doing it in our free time