tidy_browser/
utils.rs

1use std::{
2    fmt::Display,
3    fs::File,
4    io::{ErrorKind, IoSlice, Write},
5    path::PathBuf,
6};
7
8use decrypt_cookies::{chromium::ChromiumCookie, prelude::cookies::CookiesInfo};
9use snafu::ResultExt;
10use tokio::task::{self, JoinHandle};
11
12use crate::error;
13
14/// Copy from nightly [`Write::write_all_vectored`]
15/// TODO: Use std method
16pub(crate) fn write_all_vectored(
17    file: &mut File,
18    mut bufs: &mut [IoSlice<'_>],
19) -> std::io::Result<()> {
20    IoSlice::advance_slices(&mut bufs, 0);
21    while !bufs.is_empty() {
22        match file.write_vectored(bufs) {
23            Ok(0) => {
24                return Err(std::io::Error::new(
25                    std::io::ErrorKind::WriteZero,
26                    "failed to write whole buffer",
27                ));
28            },
29            Ok(n) => IoSlice::advance_slices(&mut bufs, n),
30            Err(ref e) if matches!(e.kind(), ErrorKind::Interrupted) => {},
31            Err(e) => return Err(e),
32        }
33    }
34    Ok(())
35}
36
37pub(crate) fn write_cookies<S>(
38    out_file: PathBuf,
39    cookies: Vec<impl CookiesInfo + Send + 'static>,
40    sep: S,
41) -> JoinHandle<Result<(), error::Error>>
42where
43    S: Display + Send + Clone + 'static,
44{
45    task::spawn_blocking(move || {
46        let mut file = File::options()
47            .write(true)
48            .create(true)
49            .truncate(true)
50            .open(&out_file)
51            .context(error::IoSnafu { path: out_file.clone() })?;
52
53        let header = <ChromiumCookie as CookiesInfo>::csv_header(sep.clone());
54
55        let mut slices = Vec::with_capacity(2 + cookies.len() * 2);
56        slices.push(IoSlice::new(header.as_bytes()));
57        slices.push(IoSlice::new(b"\n"));
58
59        let csvs: Vec<_> = cookies
60            .into_iter()
61            .map(|v| v.to_csv(sep.clone()))
62            .collect();
63
64        for csv in &csvs {
65            slices.push(IoSlice::new(csv.as_bytes()));
66            slices.push(IoSlice::new(b"\n"));
67        }
68
69        write_all_vectored(&mut file, &mut slices)
70            .context(error::IoSnafu { path: out_file.clone() })?;
71
72        Ok::<(), error::Error>(())
73    })
74}