bobashare_admin/cli/
create.rs

1use std::path::PathBuf;
2
3use anyhow::{anyhow, Context};
4use bobashare::{generate_randomized_id, storage::file::FileBackend};
5use chrono::TimeDelta;
6use clap::{Args, Subcommand};
7use tokio::{
8    fs::File,
9    io::{self, AsyncWriteExt},
10};
11use tracing::{event, instrument, Level};
12
13#[derive(Debug, Clone, Args)]
14pub(crate) struct CreateUpload {
15    /// How long (in days) before the upload expires and is deleted.
16    ///
17    /// If not provided, the default is no expiry (permanent).
18    #[clap(short, long, value_parser)]
19    expiry: Option<u16>,
20    #[clap(short, long, value_parser)]
21    source_file: PathBuf,
22
23    #[clap(subcommand)]
24    name: NameOptions,
25}
26#[derive(Debug, Clone, Subcommand)]
27pub(crate) enum NameOptions {
28    /// Use a randomized name for the upload
29    Random {
30        /// The length of name to randomly generate
31        #[clap(short, long, default_value_t = 8)]
32        length: u16,
33    },
34    /// Use a specific name for the upload
35    Name {
36        #[clap(short, long)]
37        name: String,
38    },
39}
40
41#[instrument(skip(backend))]
42pub(crate) async fn create_upload(backend: FileBackend, args: CreateUpload) -> anyhow::Result<()> {
43    let expiry = args.expiry.map(|e| TimeDelta::try_days(e.into()).unwrap());
44    let name = match args.name {
45        // TODO: handle already existing name
46        NameOptions::Name { name } => name,
47        NameOptions::Random { length } => generate_randomized_id(length.into()),
48    };
49
50    let filename = args
51        .source_file
52        .file_name()
53        .ok_or_else(|| anyhow!("invalid filename for source file"))?
54        .to_string_lossy()
55        .to_string();
56    let mut file = File::open(&args.source_file)
57        .await
58        .with_context(|| format!("error opening file at {:?}", &args.source_file))?;
59    let mimetype = mime_guess::from_path(&args.source_file).first_or_octet_stream();
60
61    let mut upload = backend
62        .create_upload(name, filename, mimetype, expiry, None)
63        .await?;
64
65    println!("{:?}", upload.metadata);
66
67    let copied = io::copy(&mut file, &mut upload.file).await?;
68
69    event!(Level::DEBUG, "Wrote {} bytes to the upload file", copied);
70    upload.file.flush().await?;
71    upload.flush().await?;
72
73    Ok(())
74}