Skip to content

Commit f0adc1e

Browse files
committed
use CancellationToken
1 parent e0b9a45 commit f0adc1e

8 files changed

Lines changed: 48 additions & 60 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vsd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ tokio = { version = "1", features = [
4646
"signal",
4747
] }
4848
tokio-stream = { version = "0.1", optional = true }
49+
tokio-util = "0.7"
4950
url = "2"
5051
vsd-mp4 = { version = "0.2.1", path = "../vsd-mp4", features = ["full"] }
5152
widevine = { version = "0.1.0", optional = true }

vsd/examples/download.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
// [dependencies]
44
// vsd = { version = "0.5", default-features = false, features = ["rustls-tls"]}
55

6-
use std::{
7-
path::PathBuf,
8-
sync::{Arc, atomic::AtomicBool},
9-
};
6+
use std::{path::PathBuf, sync::Arc};
107
use vsd::{
118
Downloader, Error, Muxer, Result,
129
playlist::MediaType,
1310
progress::{ProgressCallback, ProgressState},
1411
reqwest::Client,
1512
tokio,
13+
tokio_util::sync::CancellationToken,
1614
};
1715

1816
struct Progress;
@@ -46,8 +44,8 @@ async fn main() -> Result<()> {
4644
)
4745
.await?;
4846

49-
// You can clone this var and pause download by setting its value to false.
50-
let running = Arc::new(AtomicBool::new(true));
47+
// You can clone this token and call .cancel() to pause a download.
48+
let token = CancellationToken::new();
5149
let mut muxer = Muxer(Vec::new());
5250

5351
// Download first subtitle stream.
@@ -59,7 +57,7 @@ async fn main() -> Result<()> {
5957
);
6058

6159
// If stream is already downloaded then no progress updates will be triggered.
62-
let dl_info = match stream.download(&config, &running, Arc::new(Progress)).await {
60+
let dl_info = match stream.download(&config, Arc::new(Progress), &token).await {
6361
Ok(info) => info,
6462
Err(Error::UnsupportedEncryption(e)) => {
6563
println!("Unsupported encryption {}", e);
@@ -69,8 +67,8 @@ async fn main() -> Result<()> {
6967
println!("Stream has no segments");
7068
continue;
7169
}
72-
Err(Error::MissingKey(kid)) => {
73-
println!("Missing decryption key for {kid}");
70+
Err(Error::MissingKey(key_id)) => {
71+
println!("Missing decryption key for {key_id}");
7472
continue;
7573
}
7674
Err(Error::DownloadInterrupted) => {

vsd/src/core/dl.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@ use crate::{
66
};
77
use colored::Colorize;
88
use log::{info, warn};
9-
use std::{
10-
collections::HashSet,
11-
sync::{
12-
Arc,
13-
atomic::{AtomicBool, Ordering},
14-
},
15-
};
9+
use std::collections::HashSet;
10+
use tokio_util::sync::CancellationToken;
1611
use vsd_mp4::{boxes::TencBox, pssh::PsshBox};
1712

1813
pub async fn download_streams(
@@ -23,13 +18,13 @@ pub async fn download_streams(
2318
dump_pssh_info(config, &streams).await?;
2419
}
2520

26-
let running = Arc::new(AtomicBool::new(true));
27-
let ctrlc = running.clone();
21+
let token = CancellationToken::new();
22+
let ctrlc_token = token.clone();
2823

2924
tokio::spawn(async move {
30-
if tokio::signal::ctrl_c().await.is_ok() && ctrlc.load(Ordering::SeqCst) {
25+
if tokio::signal::ctrl_c().await.is_ok() && !ctrlc_token.is_cancelled() {
3126
warn!("Aborting download due to Ctrl+C.");
32-
ctrlc.store(false, Ordering::SeqCst);
27+
ctrlc_token.cancel();
3328
}
3429

3530
if tokio::signal::ctrl_c().await.is_ok() {
@@ -39,7 +34,6 @@ pub async fn download_streams(
3934
});
4035

4136
let mut muxer = Muxer(Vec::new());
42-
let running = running.clone();
4337
let total = streams.len();
4438

4539
for (i, stream) in streams.iter().enumerate() {
@@ -60,11 +54,11 @@ pub async fn download_streams(
6054
if stream.media_type == MediaType::Subtitles {
6155
muxer
6256
.0
63-
.push(sub::download(config, &running, pb, stream).await?);
57+
.push(sub::download(config, pb, &token, stream).await?);
6458
} else {
6559
muxer
6660
.0
67-
.push(vid::download(config, &running, pb, stream).await?);
61+
.push(vid::download(config, pb, &token, stream).await?);
6862
}
6963
}
7064

vsd/src/core/sub.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use crate::{
88
use colored::Colorize;
99
use log::{debug, info, warn};
1010
use reqwest::{Url, header};
11-
use std::sync::atomic::{AtomicBool, Ordering};
1211
use tokio::{fs::File, io::AsyncWriteExt, task::JoinSet};
12+
use tokio_util::sync::CancellationToken;
1313
use vsd_mp4::sub::{StppSubsParser, WvttSubsParser, ttml};
1414

1515
enum SubtitleType {
@@ -49,8 +49,8 @@ fn detect_codec(codecs: Option<&str>, data: &[u8], ext: &str) -> (&'static str,
4949

5050
pub async fn download(
5151
config: &DownloadConfig,
52-
running: &AtomicBool,
53-
pb: Progress,
52+
progress: Progress,
53+
token: &CancellationToken,
5454
stream: &MediaPlaylist,
5555
) -> Result<Stream> {
5656
let base_url = stream.uri.parse::<Url>()?;
@@ -99,18 +99,18 @@ pub async fn download(
9999
);
100100
}
101101

102-
pb.update(size);
102+
progress.update(size);
103103

104104
let remaining = &stream.segments[1..];
105105

106106
if !remaining.is_empty() {
107-
let pb_handle = pb.spawn();
107+
let progress_handle = progress.spawn();
108108
let max_threads = config.max_threads as usize;
109109
let mut set: JoinSet<Result<(usize, Vec<u8>)>> = JoinSet::new();
110110
let mut results = vec![None; remaining.len()];
111111

112112
for (i, segment) in remaining.iter().enumerate() {
113-
if !running.load(Ordering::SeqCst) {
113+
if token.is_cancelled() {
114114
break;
115115
}
116116

@@ -123,7 +123,7 @@ pub async fn download(
123123
return Err(e);
124124
}
125125
};
126-
pb.update(bytes.len());
126+
progress.update(bytes.len());
127127
results[i] = Some(bytes);
128128
}
129129
}
@@ -150,20 +150,20 @@ pub async fn download(
150150
return Err(e);
151151
}
152152
};
153-
pb.update(bytes.len());
153+
progress.update(bytes.len());
154154
results[i] = Some(bytes);
155155
}
156156

157157
for mut bytes in results.into_iter().flatten() {
158158
data.append(&mut bytes);
159159
}
160160

161-
pb_handle.abort();
161+
progress_handle.abort();
162162
}
163163

164-
pb.finish();
164+
progress.finish();
165165

166-
if !running.load(Ordering::SeqCst) {
166+
if token.is_cancelled() {
167167
return Err(Error::DownloadInterrupted);
168168
}
169169

vsd/src/core/vid.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ use crate::{
77
use colored::Colorize;
88
use log::{debug, info, trace, warn};
99
use reqwest::{StatusCode, Url, header};
10-
use std::sync::{
11-
Arc,
12-
atomic::{AtomicBool, Ordering},
13-
};
10+
use std::sync::Arc;
1411
use tokio::{
1512
fs::{self, File},
1613
io::{self, AsyncWriteExt},
1714
task::JoinSet,
1815
};
16+
use tokio_util::sync::CancellationToken;
1917
use vsd_mp4::{
2018
boxes::TencBox,
2119
decrypt::{CencDecrypter, HlsAes128Decrypter, HlsSampleAesDecrypter},
@@ -26,8 +24,8 @@ const PNG_HEADER: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
2624

2725
pub async fn download(
2826
config: &DownloadConfig,
29-
running: &AtomicBool,
30-
pb: Progress,
27+
progress: Progress,
28+
token: &CancellationToken,
3129
stream: &MediaPlaylist,
3230
) -> Result<Stream> {
3331
if let Some(Segment {
@@ -69,7 +67,7 @@ pub async fn download(
6967

7068
let base_url = stream.uri.parse::<Url>()?;
7169
let ext = stream.extension();
72-
let pb_handle = pb.spawn();
70+
let progress_handle = progress.spawn();
7371
let temp_dir = temp_file.with_extension("");
7472
let mut auto_increment_iv = false;
7573
let mut decrypter = Decrypter::None;
@@ -97,14 +95,14 @@ pub async fn download(
9795
let mut set: JoinSet<Result<usize>> = JoinSet::new();
9896

9997
for (i, segment) in stream.segments.iter().enumerate() {
100-
if !running.load(Ordering::SeqCst) {
98+
if token.is_cancelled() {
10199
break;
102100
}
103101

104102
while set.len() >= max_threads {
105103
if let Some(Ok(result)) = set.join_next().await {
106104
match result {
107-
Ok(bytes) => pb.update(bytes),
105+
Ok(bytes) => progress.update(bytes),
108106
Err(e) => {
109107
set.abort_all();
110108
return Err(e);
@@ -190,7 +188,7 @@ pub async fn download(
190188

191189
if out_file.exists() {
192190
let size = fs::metadata(&out_file).await?.len();
193-
pb.skip(size as usize);
191+
progress.skip(size as usize);
194192
continue;
195193
}
196194

@@ -261,18 +259,18 @@ pub async fn download(
261259

262260
while let Some(Ok(result)) = set.join_next().await {
263261
match result {
264-
Ok(bytes) => pb.update(bytes),
262+
Ok(bytes) => progress.update(bytes),
265263
Err(e) => {
266264
set.abort_all();
267265
return Err(e);
268266
}
269267
}
270268
}
271269

272-
pb_handle.abort();
273-
pb.finish();
270+
progress_handle.abort();
271+
progress.finish();
274272

275-
if !running.load(Ordering::SeqCst) {
273+
if token.is_cancelled() {
276274
return Err(Error::DownloadInterrupted);
277275
}
278276

vsd/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ pub use core::{DownloadConfig, Downloader, Muxer, Stream};
2121
pub use error::{Error, Result};
2222
pub use reqwest;
2323
pub use tokio;
24+
pub use tokio_util;
2425
pub use utils::find_ffmpeg;
2526
pub use vsd_mp4;

vsd/src/playlist.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,8 @@ use reqwest::{
1212
header::{self, HeaderValue},
1313
};
1414
use serde::Serialize;
15-
use std::{
16-
cmp::Reverse,
17-
collections::HashSet,
18-
fmt::Display,
19-
path::PathBuf,
20-
sync::{Arc, atomic::AtomicBool},
21-
};
15+
use std::{cmp::Reverse, collections::HashSet, fmt::Display, path::PathBuf, sync::Arc};
16+
use tokio_util::sync::CancellationToken;
2217
use vsd_mp4::{boxes::TencBox, pssh::PsshBox};
2318

2419
#[derive(Debug, Serialize)]
@@ -277,18 +272,18 @@ impl MediaPlaylist {
277272
pub async fn download(
278273
&self,
279274
config: &DownloadConfig,
280-
running: &AtomicBool,
281-
callback: Arc<dyn ProgressCallback>,
275+
progress: Arc<dyn ProgressCallback>,
276+
token: &CancellationToken,
282277
) -> Result<Stream> {
283278
if self.segments.is_empty() {
284279
return Err(Error::MissingSegments);
285280
}
286281

287-
let pb = Progress::new(&self.id, self.segments.len(), Some(callback));
282+
let progress = Progress::new(&self.id, self.segments.len(), Some(progress));
288283
let temp_file = if self.media_type == MediaType::Subtitles {
289-
core::sub::download(config, running, pb, self).await?
284+
core::sub::download(config, progress, token, self).await?
290285
} else {
291-
core::vid::download(config, running, pb, self).await?
286+
core::vid::download(config, progress, token, self).await?
292287
};
293288

294289
Ok(temp_file)

0 commit comments

Comments
 (0)