libobs_wrapper\bootstrap/
extract.rs1use std::{
2 env::current_exe,
3 path::{Path, PathBuf},
4};
5
6use async_stream::stream;
7use futures_core::Stream;
8use futures_util::{pin_mut, StreamExt};
9use sevenz_rust::{default_entry_extract_fn, Password, SevenZReader};
10use tokio::task;
11pub enum ExtractStatus {
12 Error(anyhow::Error),
13 Progress(f32, String),
14}
15
16pub(crate) async fn extract_obs(
17 archive_file: &Path,
18) -> anyhow::Result<impl Stream<Item = ExtractStatus>> {
19 log::info!("Extracting OBS at {}", archive_file.display());
20
21 let path = PathBuf::from(archive_file);
22
23 let destination = current_exe()?;
24 let destination = destination
25 .parent()
26 .ok_or_else(|| anyhow::anyhow!("Should be able to get parent of exe"))?
27 .join("obs_new");
28
29 let dest = destination.clone();
31 let stream = stream! {
32 yield Ok((0.0, "Reading file...".to_string()));
33 let mut sz = SevenZReader::open(&path, Password::empty())?;
34 let (tx, mut rx) = tokio::sync::mpsc::channel(5);
35
36 let total = sz.archive().files.len() as f32;
37 if !dest.exists() {
38 std::fs::create_dir_all(&dest)?;
39 }
40
41 let mut curr = 0;
42 let mut r = task::spawn_blocking(move || {
43 sz.for_each_entries(|entry, reader| {
44 curr += 1;
45 tx.blocking_send((curr as f32 / total, format!("Extracting {}", entry.name()))).unwrap();
46
47 let dest_path = dest.join(entry.name());
48
49 default_entry_extract_fn(entry, reader, &dest_path)
50 })?;
51
52 Result::<_, anyhow::Error>::Ok((1.0, "Extraction done".to_string()))
53 });
54
55 loop {
56 tokio::select! {
57 m = rx.recv() => {
58 match m {
59 Some(e) => yield Ok(e),
60 None => break
61 }
62 },
63 res = &mut r => {
64 match res {
65 Ok(e) => yield e,
66 Err(e) => {
67 yield Err(e.into());
68 }
69 }
70
71 break;
72 }
73 };
74 }
75
76 yield Ok((1.0, "Extraction done".to_string()));
77 };
78
79 Ok(stream! {
80 pin_mut!(stream);
81 while let Some(status) = stream.next().await {
82 match status {
83 Ok(e) => yield ExtractStatus::Progress(e.0, e.1),
84 Err(err) => {
85 log::error!("Error extracting OBS: {:?}", err);
86 yield ExtractStatus::Error(err);
87 return;
88 }
89 }
90 }
91
92 })
93}