lexoffice_cli/resources/
file.rs

1use lexoffice::model::File;
2use lexoffice::request::Request;
3use lexoffice::Client;
4use lexoffice::Result;
5use mime_guess::get_extensions;
6use reqwest::header::CONTENT_TYPE;
7use std::pin::Pin;
8use std::str::FromStr;
9use structopt::StructOpt;
10use tokio::fs;
11use tokio::io::{AsyncWrite, AsyncWriteExt};
12use tokio_stream::StreamExt;
13
14/// file endpoint
15#[derive(Debug, StructOpt)]
16pub enum FileOpt {
17    /// Uploads a file
18    Upload(UploadOpt),
19    /// Downloads a file
20    Get(GetOpt),
21}
22
23impl FileOpt {
24    pub async fn exec(&self, client: Client) -> Result<()> {
25        let request = client.request::<File>();
26        match self {
27            Self::Upload(x) => x.exec(request).await,
28            Self::Get(x) => x.exec(request).await,
29        }
30    }
31}
32
33#[derive(Debug, StructOpt)]
34pub struct UploadOpt {
35    file: String,
36}
37
38impl UploadOpt {
39    pub async fn exec(&self, request: Request<File>) -> Result<()> {
40        println!("{}", request.upload_path(self.file.clone()).await?);
41        Ok(())
42    }
43}
44
45#[derive(Debug, StructOpt)]
46pub struct GetOpt {
47    id: String,
48    #[structopt(short, long)]
49    output: Option<String>,
50}
51
52impl GetOpt {
53    pub async fn exec(&self, request: Request<File>) -> Result<()> {
54        let response = request.by_id_str(&self.id).await?;
55        let output = if let Some(output) = &self.output {
56            output.clone()
57        } else {
58            let content_type = response
59                .headers()
60                .get(CONTENT_TYPE)
61                .expect("has Content-Type Header")
62                .to_str()
63                .unwrap();
64            let mime = mime::Mime::from_str(content_type).unwrap();
65            format!(
66                "{}.{}",
67                self.id,
68                get_extensions(mime.type_().as_str(), mime.subtype().as_str())
69                    .unwrap()[0]
70            )
71        };
72        let mut output: Pin<Box<dyn AsyncWrite>> = if output == "-" {
73            Box::pin(tokio::io::stdout())
74        } else {
75            Box::pin(fs::File::create(output).await?)
76        };
77        let mut stream = response.bytes_stream();
78        while let Some(x) = stream.next().await {
79            output.write_all(&x?).await?;
80        }
81        Ok(())
82    }
83}