pict-rs/src/upload_manager.rs

643 lines
20 KiB
Rust
Raw Normal View History

2020-07-11 20:40:40 +00:00
use crate::{
config::Format,
2021-09-14 01:22:42 +00:00
error::{Error, UploadError},
2021-10-23 04:48:56 +00:00
ffmpeg::{InputFormat, ThumbnailFormat},
magick::{details_hint, ValidInputType},
migrate::{alias_id_key, alias_key, alias_key_bounds},
serde_str::Serde,
2021-10-23 04:48:56 +00:00
store::{Identifier, Store},
2020-07-11 20:40:40 +00:00
};
2020-06-06 21:41:17 +00:00
use actix_web::web;
use sha2::Digest;
use std::{string::FromUtf8Error, sync::Arc};
2020-06-14 15:07:31 +00:00
use tracing::{debug, error, info, instrument, warn, Span};
2021-09-16 22:51:20 +00:00
use tracing_futures::Instrument;
2020-06-06 21:41:17 +00:00
2021-10-18 23:44:05 +00:00
mod hasher;
mod session;
pub(super) use session::UploadManagerSession;
// TREE STRUCTURE
// - Alias Tree
// - alias -> hash
// - alias / id -> u64(id)
// - alias / delete -> delete token
// - Main Tree
// - hash -> filename
// - hash 0 u64(id) -> alias
2021-10-19 01:29:06 +00:00
// - DEPRECATED:
// - hash 2 variant path -> variant path
// - hash 2 vairant path details -> details
// - Filename Tree
// - filename -> hash
2021-10-19 01:29:06 +00:00
// - Details Tree
2021-10-23 04:48:56 +00:00
// - filename / S::Identifier -> details
2021-10-18 23:44:05 +00:00
// - Path Tree
2021-10-23 04:48:56 +00:00
// - filename -> S::Identifier
// - filename / variant path -> S::Identifier
// - filename / motion -> S::Identifier
2021-10-19 01:29:06 +00:00
2020-06-06 21:41:17 +00:00
#[derive(Clone)]
2021-10-23 04:48:56 +00:00
pub(crate) struct UploadManager<S> {
2020-06-06 21:41:17 +00:00
inner: Arc<UploadManagerInner>,
2021-10-23 04:48:56 +00:00
store: S,
2020-06-06 21:41:17 +00:00
}
2021-10-23 04:48:56 +00:00
pub(crate) struct UploadManagerInner {
2020-06-07 01:44:26 +00:00
format: Option<Format>,
2020-06-06 21:41:17 +00:00
hasher: sha2::Sha256,
2021-10-23 04:48:56 +00:00
pub(crate) alias_tree: sled::Tree,
pub(crate) filename_tree: sled::Tree,
pub(crate) main_tree: sled::Tree,
2021-10-19 01:29:06 +00:00
details_tree: sled::Tree,
2021-10-23 04:48:56 +00:00
pub(crate) identifier_tree: sled::Tree,
2020-06-07 00:29:15 +00:00
db: sled::Db,
2020-06-06 21:41:17 +00:00
}
2021-09-25 22:09:55 +00:00
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct Details {
width: usize,
height: usize,
content_type: Serde<mime::Mime>,
created_at: time::OffsetDateTime,
}
2020-06-14 15:07:31 +00:00
struct FilenameIVec {
inner: sled::IVec,
}
2021-10-23 04:48:56 +00:00
impl<S> UploadManager<S>
where
S: Store + 'static,
Error: From<S::Error>,
{
2020-06-06 21:41:17 +00:00
/// Create a new UploadManager
2021-10-23 04:48:56 +00:00
pub(crate) async fn new(store: S, db: sled::Db, format: Option<Format>) -> Result<Self, Error> {
2021-10-18 23:44:05 +00:00
let manager = UploadManager {
2020-06-06 21:41:17 +00:00
inner: Arc::new(UploadManagerInner {
2020-06-07 01:44:26 +00:00
format,
2020-06-06 21:41:17 +00:00
hasher: sha2::Sha256::new(),
2020-06-06 22:43:33 +00:00
alias_tree: db.open_tree("alias")?,
filename_tree: db.open_tree("filename")?,
2021-10-19 01:29:06 +00:00
details_tree: db.open_tree("details")?,
2020-09-14 21:42:31 +00:00
main_tree: db.open_tree("main")?,
2021-10-23 04:48:56 +00:00
identifier_tree: db.open_tree("path")?,
2020-06-06 21:41:17 +00:00
db,
}),
2021-10-23 04:48:56 +00:00
store,
2021-10-18 23:44:05 +00:00
};
Ok(manager)
2020-06-06 21:41:17 +00:00
}
2021-10-23 04:48:56 +00:00
pub(crate) fn store(&self) -> &S {
&self.store
}
pub(crate) fn inner(&self) -> &UploadManagerInner {
&self.inner
}
pub(crate) async fn still_identifier_from_filename(
2021-10-21 02:36:18 +00:00
&self,
filename: String,
2021-10-23 04:48:56 +00:00
) -> Result<S::Identifier, Error> {
let identifier = self.identifier_from_filename(filename.clone()).await?;
let details = if let Some(details) = self
.variant_details(identifier.clone(), filename.clone())
.await?
{
details
} else {
let hint = details_hint(&filename);
Details::from_store(self.store.clone(), identifier.clone(), hint).await?
};
2021-10-21 02:36:18 +00:00
if !details.is_motion() {
2021-10-23 04:48:56 +00:00
return Ok(identifier);
2021-10-21 02:36:18 +00:00
}
2021-10-23 04:48:56 +00:00
if let Some(motion_identifier) = self.motion_identifier(&filename).await? {
return Ok(motion_identifier);
2021-10-21 02:36:18 +00:00
}
let permit = crate::PROCESS_SEMAPHORE.acquire().await;
2021-10-23 04:48:56 +00:00
let mut reader = crate::ffmpeg::thumbnail(
self.store.clone(),
identifier,
InputFormat::Mp4,
ThumbnailFormat::Jpeg,
)
.await?;
let motion_identifier = self.store.save_async_read(&mut reader).await?;
2021-10-21 02:36:18 +00:00
drop(permit);
2021-10-23 04:48:56 +00:00
self.store_motion_path(&filename, &motion_identifier)
.await?;
Ok(motion_identifier)
2021-10-21 02:36:18 +00:00
}
2021-10-23 04:48:56 +00:00
async fn motion_identifier(&self, filename: &str) -> Result<Option<S::Identifier>, Error> {
let identifier_tree = self.inner.identifier_tree.clone();
2021-10-21 02:36:18 +00:00
let motion_key = format!("{}/motion", filename);
2021-10-23 04:48:56 +00:00
let opt = web::block(move || identifier_tree.get(motion_key.as_bytes())).await??;
2021-10-21 02:36:18 +00:00
if let Some(ivec) = opt {
2021-10-23 04:48:56 +00:00
return Ok(Some(S::Identifier::from_bytes(ivec.to_vec())?));
2021-10-21 02:36:18 +00:00
}
Ok(None)
}
async fn store_motion_path(
&self,
filename: &str,
2021-10-23 04:48:56 +00:00
identifier: &S::Identifier,
2021-10-21 02:36:18 +00:00
) -> Result<(), Error> {
2021-10-23 04:48:56 +00:00
let identifier_bytes = identifier.to_bytes()?;
2021-10-21 02:36:18 +00:00
let motion_key = format!("{}/motion", filename);
2021-10-23 04:48:56 +00:00
let identifier_tree = self.inner.identifier_tree.clone();
2021-10-21 02:36:18 +00:00
2021-10-23 04:48:56 +00:00
web::block(move || identifier_tree.insert(motion_key.as_bytes(), identifier_bytes))
.await??;
2021-10-21 02:36:18 +00:00
Ok(())
}
2021-10-19 04:37:11 +00:00
#[instrument(skip(self))]
2021-10-23 04:48:56 +00:00
pub(crate) async fn identifier_from_filename(
&self,
filename: String,
) -> Result<S::Identifier, Error> {
let identifier_tree = self.inner.identifier_tree.clone();
let path_ivec = web::block(move || identifier_tree.get(filename.as_bytes()))
2021-10-19 04:37:11 +00:00
.await??
.ok_or(UploadError::MissingFile)?;
2021-10-23 04:48:56 +00:00
let identifier = S::Identifier::from_bytes(path_ivec.to_vec())?;
2021-10-19 04:37:11 +00:00
2021-10-23 04:48:56 +00:00
Ok(identifier)
2021-10-19 04:37:11 +00:00
}
#[instrument(skip(self))]
2021-10-23 04:48:56 +00:00
async fn store_identifier(
&self,
filename: String,
identifier: &S::Identifier,
) -> Result<(), Error> {
let identifier_bytes = identifier.to_bytes()?;
let identifier_tree = self.inner.identifier_tree.clone();
web::block(move || identifier_tree.insert(filename.as_bytes(), identifier_bytes)).await??;
2021-10-19 04:37:11 +00:00
Ok(())
}
#[instrument(skip(self))]
2021-10-23 04:48:56 +00:00
pub(crate) async fn variant_identifier(
2021-10-19 04:37:11 +00:00
&self,
process_path: &std::path::Path,
filename: &str,
2021-10-23 04:48:56 +00:00
) -> Result<Option<S::Identifier>, Error> {
2021-10-19 04:37:11 +00:00
let key = self.variant_key(process_path, filename)?;
2021-10-23 04:48:56 +00:00
let identifier_tree = self.inner.identifier_tree.clone();
let path_opt = web::block(move || identifier_tree.get(key)).await??;
2021-10-19 04:37:11 +00:00
2021-10-23 04:48:56 +00:00
if let Some(ivec) = path_opt {
let identifier = S::Identifier::from_bytes(ivec.to_vec())?;
Ok(Some(identifier))
2021-10-19 04:37:11 +00:00
} else {
Ok(None)
}
}
/// Store the path to a generated image variant so we can easily clean it up later
2020-06-14 15:07:31 +00:00
#[instrument(skip(self))]
2021-10-19 04:37:11 +00:00
pub(crate) async fn store_variant(
&self,
variant_process_path: Option<&std::path::Path>,
2021-10-23 04:48:56 +00:00
identifier: &S::Identifier,
2021-10-19 04:37:11 +00:00
filename: &str,
) -> Result<(), Error> {
2021-10-23 04:48:56 +00:00
let key = if let Some(path) = variant_process_path {
self.variant_key(path, filename)?
} else {
let mut vec = filename.as_bytes().to_vec();
vec.extend(b"/");
vec.extend(&identifier.to_bytes()?);
vec
};
let identifier_tree = self.inner.identifier_tree.clone();
let identifier_bytes = identifier.to_bytes()?;
2020-06-14 15:07:31 +00:00
debug!("Storing variant");
2021-10-23 04:48:56 +00:00
web::block(move || identifier_tree.insert(key, identifier_bytes)).await??;
2020-06-14 15:07:31 +00:00
debug!("Stored variant");
Ok(())
}
/// Get the image details for a given variant
2021-09-25 22:09:55 +00:00
#[instrument(skip(self))]
pub(crate) async fn variant_details(
&self,
2021-10-23 04:48:56 +00:00
identifier: S::Identifier,
filename: String,
2021-09-14 01:22:42 +00:00
) -> Result<Option<Details>, Error> {
2021-10-23 04:48:56 +00:00
let key = self.details_key(identifier, &filename)?;
2021-10-19 01:29:06 +00:00
let details_tree = self.inner.details_tree.clone();
debug!("Getting details");
2021-10-19 01:29:06 +00:00
let opt = match web::block(move || details_tree.get(key)).await?? {
Some(ivec) => match serde_json::from_slice(&ivec) {
Ok(details) => Some(details),
Err(_) => None,
},
None => None,
};
debug!("Got details");
Ok(opt)
}
2021-09-25 22:09:55 +00:00
#[instrument(skip(self))]
pub(crate) async fn store_variant_details(
&self,
2021-10-23 04:48:56 +00:00
identifier: S::Identifier,
filename: String,
details: &Details,
2021-09-14 01:22:42 +00:00
) -> Result<(), Error> {
2021-10-23 04:48:56 +00:00
let key = self.details_key(identifier, &filename)?;
2021-10-19 01:29:06 +00:00
let details_tree = self.inner.details_tree.clone();
let details_value = serde_json::to_vec(details)?;
debug!("Storing details");
2021-10-19 01:29:06 +00:00
web::block(move || details_tree.insert(key, details_value)).await??;
debug!("Stored details");
Ok(())
}
/// Get a list of aliases for a given file
2021-09-14 01:22:42 +00:00
pub(crate) async fn aliases_by_filename(&self, filename: String) -> Result<Vec<String>, Error> {
let fname_tree = self.inner.filename_tree.clone();
let hash = web::block(move || fname_tree.get(filename.as_bytes()))
2021-02-10 22:57:42 +00:00
.await??
.ok_or(UploadError::MissingAlias)?;
self.aliases_by_hash(&hash).await
}
/// Get a list of aliases for a given alias
2021-09-14 01:22:42 +00:00
pub(crate) async fn aliases_by_alias(&self, alias: String) -> Result<Vec<String>, Error> {
let alias_tree = self.inner.alias_tree.clone();
let hash = web::block(move || alias_tree.get(alias.as_bytes()))
2021-02-10 22:57:42 +00:00
.await??
.ok_or(UploadError::MissingFilename)?;
self.aliases_by_hash(&hash).await
}
2021-09-14 01:22:42 +00:00
async fn aliases_by_hash(&self, hash: &sled::IVec) -> Result<Vec<String>, Error> {
let (start, end) = alias_key_bounds(hash);
2020-09-14 21:42:31 +00:00
let main_tree = self.inner.main_tree.clone();
let aliases = web::block(move || {
main_tree
.range(start..end)
.values()
.collect::<Result<Vec<_>, _>>()
})
2021-02-10 22:57:42 +00:00
.await??;
debug!("Got {} aliases for hash", aliases.len());
let aliases = aliases
.into_iter()
.filter_map(|s| String::from_utf8(s.to_vec()).ok())
.collect::<Vec<_>>();
for alias in aliases.iter() {
debug!("{}", alias);
}
Ok(aliases)
}
/// Delete an alias without a delete token
2021-09-14 01:22:42 +00:00
pub(crate) async fn delete_without_token(&self, alias: String) -> Result<(), Error> {
let token_key = delete_key(&alias);
let alias_tree = self.inner.alias_tree.clone();
let token = web::block(move || alias_tree.get(token_key.as_bytes()))
2021-02-10 22:57:42 +00:00
.await??
.ok_or(UploadError::MissingAlias)?;
self.delete(alias, String::from_utf8(token.to_vec())?).await
}
/// Delete the alias, and the file & variants if no more aliases exist
2020-06-14 18:56:42 +00:00
#[instrument(skip(self, alias, token))]
2021-09-14 01:22:42 +00:00
pub(crate) async fn delete(&self, alias: String, token: String) -> Result<(), Error> {
2020-06-07 00:29:15 +00:00
use sled::Transactional;
2020-09-14 21:42:31 +00:00
let main_tree = self.inner.main_tree.clone();
2020-06-07 00:29:15 +00:00
let alias_tree = self.inner.alias_tree.clone();
2020-06-14 15:07:31 +00:00
let span = Span::current();
2020-06-07 00:29:15 +00:00
let alias2 = alias.clone();
let hash = web::block(move || {
2020-09-14 21:42:31 +00:00
[&main_tree, &alias_tree].transaction(|v| {
2020-06-14 15:07:31 +00:00
let entered = span.enter();
2020-09-14 21:42:31 +00:00
let main_tree = &v[0];
2020-06-07 00:29:15 +00:00
let alias_tree = &v[1];
// -- GET TOKEN --
2020-06-14 15:07:31 +00:00
debug!("Deleting alias -> delete-token mapping");
2020-06-07 00:29:15 +00:00
let existing_token = alias_tree
.remove(delete_key(&alias2).as_bytes())?
2021-10-23 04:48:56 +00:00
.ok_or_else(|| trans_upload_error(UploadError::MissingAlias))?;
2020-06-07 00:29:15 +00:00
// Bail if invalid token
if existing_token != token {
warn!("Invalid delete token");
2021-10-23 04:48:56 +00:00
return Err(trans_upload_error(UploadError::InvalidToken));
2020-06-07 00:29:15 +00:00
}
// -- GET ID FOR HASH TREE CLEANUP --
2020-06-14 15:07:31 +00:00
debug!("Deleting alias -> id mapping");
2020-06-07 00:29:15 +00:00
let id = alias_tree
.remove(alias_id_key(&alias2).as_bytes())?
2021-10-23 04:48:56 +00:00
.ok_or_else(|| trans_upload_error(UploadError::MissingAlias))?;
let id = String::from_utf8(id.to_vec()).map_err(trans_utf8_error)?;
2020-06-07 00:29:15 +00:00
// -- GET HASH FOR HASH TREE CLEANUP --
2020-06-14 15:07:31 +00:00
debug!("Deleting alias -> hash mapping");
2020-06-07 00:29:15 +00:00
let hash = alias_tree
.remove(alias2.as_bytes())?
2021-10-23 04:48:56 +00:00
.ok_or_else(|| trans_upload_error(UploadError::MissingAlias))?;
2020-06-07 00:29:15 +00:00
// -- REMOVE HASH TREE ELEMENT --
2020-06-14 15:07:31 +00:00
debug!("Deleting hash -> alias mapping");
2020-09-14 21:42:31 +00:00
main_tree.remove(alias_key(&hash, &id))?;
2020-06-14 15:07:31 +00:00
drop(entered);
2020-06-07 00:29:15 +00:00
Ok(hash)
})
})
2021-02-10 22:57:42 +00:00
.await??;
2020-06-07 00:29:15 +00:00
2021-09-12 00:53:26 +00:00
self.check_delete_files(hash).await
}
2021-09-14 01:22:42 +00:00
async fn check_delete_files(&self, hash: sled::IVec) -> Result<(), Error> {
2020-06-07 03:21:42 +00:00
// -- CHECK IF ANY OTHER ALIASES EXIST --
2020-09-14 21:42:31 +00:00
let main_tree = self.inner.main_tree.clone();
2020-06-07 00:29:15 +00:00
let (start, end) = alias_key_bounds(&hash);
2020-06-14 15:07:31 +00:00
debug!("Checking for additional aliases referencing hash");
2020-06-07 00:29:15 +00:00
let any_aliases = web::block(move || {
2021-09-14 01:22:42 +00:00
Ok(main_tree.range(start..end).next().is_some()) as Result<bool, Error>
2020-06-07 00:29:15 +00:00
})
2021-02-10 22:57:42 +00:00
.await??;
2020-06-07 00:29:15 +00:00
// Bail if there are existing aliases
if any_aliases {
2020-06-14 15:07:31 +00:00
debug!("Other aliases reference file, not removing from disk");
2020-06-07 00:29:15 +00:00
return Ok(());
}
// -- DELETE HASH ENTRY --
2020-09-14 21:42:31 +00:00
let main_tree = self.inner.main_tree.clone();
let hash2 = hash.clone();
2020-06-14 15:07:31 +00:00
debug!("Deleting hash -> filename mapping");
2020-09-14 21:42:31 +00:00
let filename = web::block(move || main_tree.remove(&hash2))
2021-02-10 22:57:42 +00:00
.await??
.ok_or(UploadError::MissingFile)?;
2020-06-07 00:29:15 +00:00
2020-06-07 00:33:29 +00:00
// -- DELETE FILES --
let this = self.clone();
let cleanup_span = tracing::info_span!(
parent: None,
"Cleanup",
filename = &tracing::field::display(String::from_utf8_lossy(&filename)),
);
cleanup_span.follows_from(Span::current());
2020-06-14 15:07:31 +00:00
debug!("Spawning cleanup task");
2021-09-16 22:51:20 +00:00
actix_rt::spawn(
async move {
if let Err(e) = this
.cleanup_files(FilenameIVec::new(filename.clone()))
.await
{
error!("Error removing files from fs, {}", e);
}
info!(
"Files deleted for {:?}",
String::from_utf8(filename.to_vec())
);
2020-06-07 00:33:29 +00:00
}
.instrument(cleanup_span),
2021-09-16 22:51:20 +00:00
);
2020-06-07 00:29:15 +00:00
Ok(())
}
2021-09-12 00:53:26 +00:00
/// Fetch the real on-disk filename given an alias
#[instrument(skip(self))]
2021-09-14 01:22:42 +00:00
pub(crate) async fn from_alias(&self, alias: String) -> Result<String, Error> {
2021-09-12 00:53:26 +00:00
let tree = self.inner.alias_tree.clone();
debug!("Getting hash from alias");
let hash = web::block(move || tree.get(alias.as_bytes()))
.await??
.ok_or(UploadError::MissingAlias)?;
let main_tree = self.inner.main_tree.clone();
debug!("Getting filename from hash");
let filename = web::block(move || main_tree.get(hash))
.await??
.ok_or(UploadError::MissingFile)?;
let filename = String::from_utf8(filename.to_vec())?;
Ok(filename)
}
2021-10-23 04:48:56 +00:00
pub(crate) fn session(&self) -> UploadManagerSession<S> {
2021-10-18 23:44:05 +00:00
UploadManagerSession::new(self.clone())
2021-09-12 00:53:26 +00:00
}
// Find image variants and remove them from the DB and the disk
#[instrument(skip(self))]
2021-09-14 01:22:42 +00:00
async fn cleanup_files(&self, filename: FilenameIVec) -> Result<(), Error> {
2021-09-12 00:53:26 +00:00
let filename = filename.inner;
2021-10-19 04:37:11 +00:00
let filename2 = filename.clone();
2021-10-23 04:48:56 +00:00
let identifier_tree = self.inner.identifier_tree.clone();
let identifier = web::block(move || identifier_tree.remove(filename2)).await??;
2021-09-12 00:53:26 +00:00
let mut errors = Vec::new();
2021-10-23 04:48:56 +00:00
if let Some(identifier) = identifier {
let identifier = S::Identifier::from_bytes(identifier.to_vec())?;
debug!("Deleting {:?}", identifier);
if let Err(e) = self.store.remove(&identifier).await {
errors.push(e);
2021-10-19 04:37:11 +00:00
}
2021-09-12 00:53:26 +00:00
}
2021-10-19 01:29:06 +00:00
let filename2 = filename.clone();
2021-09-12 00:53:26 +00:00
let fname_tree = self.inner.filename_tree.clone();
debug!("Deleting filename -> hash mapping");
2021-10-19 01:29:06 +00:00
web::block(move || fname_tree.remove(filename2)).await??;
2021-09-12 00:53:26 +00:00
2021-10-19 01:29:06 +00:00
let path_prefix = filename.clone();
2021-10-23 04:48:56 +00:00
let identifier_tree = self.inner.identifier_tree.clone();
2021-09-12 00:53:26 +00:00
debug!("Fetching file variants");
2021-10-23 04:48:56 +00:00
let identifiers = web::block(move || {
identifier_tree
2021-10-19 01:29:06 +00:00
.scan_prefix(path_prefix)
.values()
.collect::<Result<Vec<sled::IVec>, sled::Error>>()
2021-09-12 00:53:26 +00:00
})
.await??;
2021-10-23 04:48:56 +00:00
debug!("{} files prepared for deletion", identifiers.len());
for id in identifiers {
let identifier = S::Identifier::from_bytes(id.to_vec())?;
2021-10-19 01:29:06 +00:00
2021-10-23 04:48:56 +00:00
debug!("Deleting {:?}", identifier);
if let Err(e) = self.store.remove(&identifier).await {
2021-10-19 01:29:06 +00:00
errors.push(e);
2021-09-12 00:53:26 +00:00
}
}
2021-10-19 01:29:06 +00:00
let path_prefix = filename.clone();
2021-10-23 04:48:56 +00:00
let identifier_tree = self.inner.identifier_tree.clone();
2021-10-19 01:29:06 +00:00
debug!("Deleting path info");
web::block(move || {
2021-10-23 04:48:56 +00:00
for res in identifier_tree.scan_prefix(path_prefix).keys() {
2021-10-19 01:29:06 +00:00
let key = res?;
2021-10-23 04:48:56 +00:00
identifier_tree.remove(key)?;
2021-10-19 01:29:06 +00:00
}
Ok(()) as Result<(), Error>
})
.await??;
2021-09-12 00:53:26 +00:00
for error in errors {
error!("Error deleting files, {}", error);
}
Ok(())
}
2021-10-19 04:37:11 +00:00
2021-10-23 04:48:56 +00:00
pub(crate) fn variant_key(
2021-10-19 04:37:11 +00:00
&self,
variant_process_path: &std::path::Path,
filename: &str,
) -> Result<Vec<u8>, Error> {
let path_string = variant_process_path
.to_str()
.ok_or(UploadError::Path)?
.to_string();
let vec = format!("{}/{}", filename, path_string).as_bytes().to_vec();
Ok(vec)
}
2021-10-23 04:48:56 +00:00
fn details_key(&self, identifier: S::Identifier, filename: &str) -> Result<Vec<u8>, Error> {
let mut vec = filename.as_bytes().to_vec();
vec.extend(b"/");
vec.extend(&identifier.to_bytes()?);
2021-10-19 04:37:11 +00:00
Ok(vec)
}
2021-09-12 00:53:26 +00:00
}
2021-10-18 23:44:05 +00:00
impl Details {
2021-10-21 02:36:18 +00:00
fn is_motion(&self) -> bool {
self.content_type.type_() == "video"
|| self.content_type.type_() == "image" && self.content_type.subtype() == "gif"
}
2021-10-18 23:44:05 +00:00
#[tracing::instrument("Details from bytes", skip(input))]
2021-10-23 04:48:56 +00:00
pub(crate) async fn from_bytes(
input: web::Bytes,
hint: Option<ValidInputType>,
) -> Result<Self, Error> {
let details = crate::magick::details_bytes(input, hint).await?;
2021-10-18 23:44:05 +00:00
Ok(Details::now(
details.width,
details.height,
details.mime_type,
))
}
2020-06-07 01:44:26 +00:00
2021-10-23 04:48:56 +00:00
#[tracing::instrument("Details from store")]
pub(crate) async fn from_store<S: Store>(
store: S,
identifier: S::Identifier,
expected_format: Option<ValidInputType>,
2021-10-23 19:14:12 +00:00
) -> Result<Self, Error>
where
Error: From<S::Error>,
{
2021-10-23 04:48:56 +00:00
let details = crate::magick::details_store(store, identifier, expected_format).await?;
2021-10-18 23:44:05 +00:00
Ok(Details::now(
details.width,
details.height,
details.mime_type,
))
}
2021-10-18 23:44:05 +00:00
fn now(width: usize, height: usize, content_type: mime::Mime) -> Self {
Details {
width,
height,
content_type: Serde::new(content_type),
created_at: time::OffsetDateTime::now_utc(),
2020-06-06 22:43:33 +00:00
}
}
2021-10-18 23:44:05 +00:00
pub(crate) fn content_type(&self) -> mime::Mime {
(*self.content_type).clone()
2020-06-06 22:43:33 +00:00
}
2021-10-18 23:44:05 +00:00
pub(crate) fn system_time(&self) -> std::time::SystemTime {
self.created_at.into()
}
}
2021-10-18 23:44:05 +00:00
impl FilenameIVec {
fn new(inner: sled::IVec) -> Self {
FilenameIVec { inner }
}
2020-06-06 22:43:33 +00:00
}
2021-10-23 04:48:56 +00:00
fn trans_upload_error(
upload_error: UploadError,
) -> sled::transaction::ConflictableTransactionError<Error> {
trans_err(upload_error)
}
fn trans_utf8_error(e: FromUtf8Error) -> sled::transaction::ConflictableTransactionError<Error> {
trans_err(e)
2021-10-19 01:29:06 +00:00
}
2021-09-14 01:22:42 +00:00
fn trans_err<E>(e: E) -> sled::transaction::ConflictableTransactionError<Error>
where
Error: From<E>,
{
sled::transaction::ConflictableTransactionError::Abort(e.into())
2020-06-07 00:29:15 +00:00
}
fn delete_key(alias: &str) -> String {
format!("{}/delete", alias)
}
2021-10-23 04:48:56 +00:00
impl<S> std::fmt::Debug for UploadManager<S> {
2021-10-18 23:44:05 +00:00
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("UploadManager").finish()
2021-10-13 04:16:31 +00:00
}
2021-10-18 23:44:05 +00:00
}
2021-10-13 04:16:31 +00:00
2021-10-18 23:44:05 +00:00
impl std::fmt::Debug for FilenameIVec {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", String::from_utf8(self.inner.to_vec()))
2021-09-04 17:42:40 +00:00
}
}