Skip to content

Commit 3143616

Browse files
authored
Merge pull request #25 from maxomatic458/stop-transfer
Stop transfer + update gui
2 parents 4779043 + fc7fcd6 commit 3143616

21 files changed

+492
-293
lines changed

Cargo.lock

Lines changed: 28 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ serde = { version = "1", features = ["derive"] }
2828
iroh = { version = "0.33.0" }
2929
hex = "0.4.3"
3030
copypasta = "0.10.1"
31+
base64 = "0.22.1"
3132

3233
[profile.release]
3334
lto = true

qs-cli/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ clap = { workspace = true }
1919
semver = { workspace = true }
2020
iroh = { workspace = true }
2121
rand = { workspace = true }
22-
qs-core = { workspace = true } # todo remove later
2322
bincode = { workspace = true, features = ["serde"] }
2423
copypasta = { workspace = true }
24+
base64 = { workspace = true }
2525

26+
qs-core = "0.4.0"
2627
async-compression = { version = "0.4.12", features = ["tokio", "gzip"] }
2728
indicatif = "0.17.8"
2829
dialoguer = "0.11.0"
2930
colored = "3.0.0"
3031
color-eyre = "0.6.3"
31-
base64 = "0.22.1"
3232

3333
[[bin]]
3434
path = "src/main.rs"

qs-cli/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ async fn main() -> color_eyre::Result<()> {
153153
pb.update(last_sent);
154154
}
155155
},
156+
// In the CLI we don't handle the interruption as the user can just Ctrl+C
157+
&mut || true,
156158
)
157159
.await
158160
.map_err(QuicSendError::Send)?;
@@ -213,6 +215,8 @@ async fn main() -> color_eyre::Result<()> {
213215
pb.update(last_received);
214216
}
215217
},
218+
// In the CLI we don't handle the interruption as the user can just Ctrl+C
219+
&mut || true,
216220
)
217221
.await
218222
.map_err(QuicSendError::Receive)?;

qs-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ bincode = { workspace = true }
2020
clap = { workspace = true }
2121
semver = { workspace = true }
2222
serde = { workspace = true, features = ["derive"] }
23-
async-compression = { version = "0.4.12", features = ["tokio", "gzip"] }
2423
iroh = { workspace = true }
24+
async-compression = { version = "0.4.12", features = ["tokio", "gzip"] }
2525

2626
[dev-dependencies]
2727
pretty_assertions = { workspace = true }

qs-core/src/receive.rs

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ use thiserror::Error;
1414
use tokio::io::AsyncWriteExt;
1515

1616
/// Generic receive function
17+
///
18+
/// # Returns
19+
/// * `Ok(true)` if the transfer should continue
20+
/// * `Ok(false)` if the transfer should stop
1721
pub async fn receive_file<R, W>(
1822
recv: &mut R,
1923
file: &mut W,
2024
skip: u64,
2125
size: u64,
2226
read_callback: &mut impl FnMut(u64),
23-
) -> std::io::Result<()>
27+
should_continue: &mut impl FnMut() -> bool,
28+
) -> std::io::Result<bool>
2429
where
2530
R: tokio::io::AsyncReadExt + Unpin,
2631
W: tokio::io::AsyncWriteExt + tokio::io::AsyncSeekExt + Unpin,
@@ -31,6 +36,10 @@ where
3136
let mut written = skip;
3237

3338
while written < size {
39+
if !should_continue() {
40+
return Ok(false);
41+
}
42+
3443
let to_write = std::cmp::min(BUF_SIZE as u64, size - written);
3544
let n = recv.read_exact(&mut buf[..to_write as usize]).await?;
3645

@@ -47,52 +56,70 @@ where
4756
read_callback(n as u64);
4857
}
4958

50-
Ok(())
59+
Ok(true)
5160
}
5261

53-
/// Receive a directory
54-
// #[async_recursion]
62+
/// # Returns
63+
/// * `Ok(true)` if the transfer should continue
64+
/// * `Ok(false)` if the transfer should stop
5565
pub fn receive_directory<S>(
5666
send: &mut S,
5767
root_path: &std::path::Path,
5868
files: &[FileSendRecvTree],
5969
read_callback: &mut impl FnMut(u64),
60-
) -> std::io::Result<()>
70+
should_continue: &mut impl FnMut() -> bool,
71+
) -> std::io::Result<bool>
6172
where
6273
S: tokio::io::AsyncReadExt + Unpin + Send,
6374
{
6475
for file in files {
6576
match file {
6677
FileSendRecvTree::File { name, skip, size } => {
6778
let path = root_path.join(name);
68-
tokio::task::block_in_place(|| {
79+
80+
let continues = tokio::task::block_in_place(|| {
6981
let rt = tokio::runtime::Runtime::new().unwrap();
7082
rt.block_on(async {
7183
let mut file = tokio::fs::OpenOptions::new()
7284
.write(true)
7385
.create(true)
7486
.open(&path)
7587
.await?;
76-
receive_file(send, &mut file, *skip, *size, read_callback).await?;
88+
let continues = receive_file(
89+
send,
90+
&mut file,
91+
*skip,
92+
*size,
93+
read_callback,
94+
should_continue,
95+
)
96+
.await?;
7797

7898
file.sync_all().await?;
7999
file.shutdown().await?;
80-
Ok::<(), std::io::Error>(())
100+
Ok::<bool, std::io::Error>(continues)
81101
})
82102
})?;
103+
104+
if !continues {
105+
return Ok(false);
106+
}
83107
}
84108
FileSendRecvTree::Dir { name, files } => {
85109
let root_path = root_path.join(name);
86110

87111
if !root_path.exists() {
88112
std::fs::create_dir(&root_path)?;
89113
}
90-
receive_directory(send, &root_path, files, read_callback)?;
114+
115+
if !receive_directory(send, &root_path, files, read_callback, should_continue)? {
116+
return Ok(false);
117+
}
91118
}
92119
}
93120
}
94121

95-
Ok(())
122+
Ok(true)
96123
}
97124

98125
#[derive(Debug, Error)]
@@ -181,12 +208,18 @@ impl Receiver {
181208
/// * `initial_progress_callback` - Callback with the initial progress of each file to send (name, current, total)
182209
/// * `accept_files_callback` - Callback to accept or reject the files (Some(path) to accept, None to reject)
183210
/// * `read_callback` - Callback every time data is written to disk
211+
/// * `should_continue` - Callback to check if the transfer should continue
212+
///
213+
/// # Returns
214+
/// * `Ok(true)` if the transfer was finished successfully
215+
/// * `Ok(false)` if the transfer was stopped
184216
pub async fn receive_files(
185217
&mut self,
186218
mut initial_progress_callback: impl FnMut(&[(String, u64, u64)]),
187219
mut accept_files_callback: impl FnMut(&[FilesAvailable]) -> Option<PathBuf>,
188220
read_callback: &mut impl FnMut(u64),
189-
) -> Result<(), ReceiveError> {
221+
should_continue: &mut impl FnMut() -> bool,
222+
) -> Result<bool, ReceiveError> {
190223
match receive_packet::<SenderToReceiver>(&self.conn).await? {
191224
SenderToReceiver::ConnRequest { version_num } => {
192225
if version_num != QS_VERSION {
@@ -282,6 +315,8 @@ impl Receiver {
282315
let recv = self.conn.accept_uni().await?;
283316
let mut recv = GzipDecoder::new(tokio::io::BufReader::with_capacity(BUF_SIZE, recv));
284317

318+
let mut interrupted = false;
319+
285320
for file in to_receive.into_iter().flatten() {
286321
match file {
287322
FileSendRecvTree::File { name, skip, size } => {
@@ -292,9 +327,21 @@ impl Receiver {
292327
.open(&path)
293328
.await?;
294329

295-
receive_file(&mut recv, &mut file, skip, size, read_callback).await?;
330+
interrupted = !receive_file(
331+
&mut recv,
332+
&mut file,
333+
skip,
334+
size,
335+
read_callback,
336+
should_continue,
337+
)
338+
.await?;
296339
file.sync_all().await?;
297340
file.shutdown().await?;
341+
342+
if interrupted {
343+
break;
344+
}
298345
}
299346
FileSendRecvTree::Dir { name, files } => {
300347
let path = output_path.join(name);
@@ -303,12 +350,21 @@ impl Receiver {
303350
std::fs::create_dir(&path)?;
304351
}
305352

306-
receive_directory(&mut recv, &path, &files, read_callback)?;
353+
if !receive_directory(&mut recv, &path, &files, read_callback, should_continue)?
354+
{
355+
interrupted = true;
356+
break;
357+
}
307358
}
308359
}
309360
}
310361

311362
self.close().await;
312-
Ok(())
363+
364+
if interrupted {
365+
tracing::info!("transfer interrupted");
366+
}
367+
368+
Ok(!interrupted)
313369
}
314370
}

0 commit comments

Comments
 (0)