use std::borrow::Cow; use std::path::{Path, PathBuf}; use rocket::http::uri::{self, FromUriParam}; use rocket::request::FromParam; use rand::{self, Rng}; /// Table to retrieve base62 values from. const BASE62: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /// A _probably_ unique paste ID. #[derive(UriDisplayPath)] pub struct PasteId<'a>(Cow<'a, str>); impl PasteId<'_> { /// Generate a _probably_ unique ID with `size` characters. For readability, /// the characters used are from the sets [0-9], [A-Z], [a-z]. The /// probability of a collision depends on the value of `size` and the number /// of IDs generated thus far. pub fn new(size: usize) -> PasteId<'static> { let mut id = String::with_capacity(size); let mut rng = rand::thread_rng(); for _ in 0..size { id.push(BASE62[rng.gen::() % 62] as char); } PasteId(Cow::Owned(id)) } pub fn file_path(&self) -> PathBuf { let root = concat!(env!("CARGO_MANIFEST_DIR"), "/", "upload"); Path::new(root).join(self.0.as_ref()) } } /// Returns an instance of `PasteId` if the path segment is a valid ID. /// Otherwise returns the invalid ID as the `Err` value. impl<'a> FromParam<'a> for PasteId<'a> { type Error = &'a str; fn from_param(param: &'a str) -> Result { match param.chars().all(|c| c.is_ascii_alphanumeric()) { true => Ok(PasteId(param.into())), false => Err(param) } } } impl<'a> FromUriParam for PasteId<'_> { type Target = PasteId<'a>; fn from_uri_param(param: &'a str) -> Self::Target { PasteId(param.into()) } }