mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-11-14 00:13:59 +00:00
Clean tracing, simplify validation, rename InputFormat -> VideoFormat
This commit is contained in:
parent
e7cf21f862
commit
718f09c43a
15 changed files with 107 additions and 168 deletions
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
ffmpeg::InputFormat,
|
ffmpeg::VideoFormat,
|
||||||
magick::{video_mp4, video_webm, ValidInputType},
|
magick::{video_mp4, video_webm, ValidInputType},
|
||||||
serde_str::Serde,
|
serde_str::Serde,
|
||||||
store::Store,
|
store::Store,
|
||||||
|
@ -29,7 +29,6 @@ impl Details {
|
||||||
|| self.content_type.type_() == "image" && self.content_type.subtype() == "gif"
|
|| self.content_type.type_() == "image" && self.content_type.subtype() == "gif"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument("Details from bytes", skip(input))]
|
|
||||||
pub(crate) async fn from_bytes(input: web::Bytes, hint: ValidInputType) -> Result<Self, Error> {
|
pub(crate) async fn from_bytes(input: web::Bytes, hint: ValidInputType) -> Result<Self, Error> {
|
||||||
let details = if hint.is_video() {
|
let details = if hint.is_video() {
|
||||||
crate::ffmpeg::details_bytes(input.clone()).await?
|
crate::ffmpeg::details_bytes(input.clone()).await?
|
||||||
|
@ -51,7 +50,6 @@ impl Details {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument("Details from store")]
|
|
||||||
pub(crate) async fn from_store<S: Store + 'static>(
|
pub(crate) async fn from_store<S: Store + 'static>(
|
||||||
store: S,
|
store: S,
|
||||||
identifier: S::Identifier,
|
identifier: S::Identifier,
|
||||||
|
@ -100,17 +98,17 @@ impl Details {
|
||||||
self.created_at.into()
|
self.created_at.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_input_format(&self) -> Option<InputFormat> {
|
pub(crate) fn to_input_format(&self) -> Option<VideoFormat> {
|
||||||
if *self.content_type == mime::IMAGE_GIF {
|
if *self.content_type == mime::IMAGE_GIF {
|
||||||
return Some(InputFormat::Gif);
|
return Some(VideoFormat::Gif);
|
||||||
}
|
}
|
||||||
|
|
||||||
if *self.content_type == video_mp4() {
|
if *self.content_type == video_mp4() {
|
||||||
return Some(InputFormat::Mp4);
|
return Some(VideoFormat::Mp4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if *self.content_type == video_webm() {
|
if *self.content_type == video_webm() {
|
||||||
return Some(InputFormat::Webm);
|
return Some(VideoFormat::Webm);
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::process::Process;
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::AsyncRead;
|
||||||
|
|
||||||
#[tracing::instrument(name = "Clearing metadata", skip(input))]
|
#[tracing::instrument(level = "trace", skip(input))]
|
||||||
pub(crate) fn clear_metadata_bytes_read(input: Bytes) -> std::io::Result<impl AsyncRead + Unpin> {
|
pub(crate) fn clear_metadata_bytes_read(input: Bytes) -> std::io::Result<impl AsyncRead + Unpin> {
|
||||||
let process = Process::run("exiftool", &["-all=", "-", "-out", "-"])?;
|
let process = Process::run("exiftool", &["-all=", "-", "-out", "-"])?;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{AudioCodec, VideoCodec},
|
config::{AudioCodec, ImageFormat, VideoCodec},
|
||||||
error::{Error, UploadError},
|
error::{Error, UploadError},
|
||||||
magick::{Details, ValidInputType},
|
magick::{Details, ValidInputType},
|
||||||
process::Process,
|
process::Process,
|
||||||
|
@ -7,10 +7,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) enum InputFormat {
|
pub(crate) enum VideoFormat {
|
||||||
Gif,
|
Gif,
|
||||||
Mp4,
|
Mp4,
|
||||||
Webm,
|
Webm,
|
||||||
|
@ -28,7 +27,26 @@ pub(crate) enum ThumbnailFormat {
|
||||||
// Webp,
|
// Webp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputFormat {
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(crate) enum FileFormat {
|
||||||
|
Image(ImageFormat),
|
||||||
|
Video(VideoFormat),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidInputType {
|
||||||
|
pub(crate) fn to_file_format(self) -> FileFormat {
|
||||||
|
match self {
|
||||||
|
Self::Gif => FileFormat::Video(VideoFormat::Gif),
|
||||||
|
Self::Mp4 => FileFormat::Video(VideoFormat::Mp4),
|
||||||
|
Self::Webm => FileFormat::Video(VideoFormat::Webm),
|
||||||
|
Self::Jpeg => FileFormat::Image(ImageFormat::Jpeg),
|
||||||
|
Self::Png => FileFormat::Image(ImageFormat::Png),
|
||||||
|
Self::Webp => FileFormat::Image(ImageFormat::Webp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VideoFormat {
|
||||||
const fn to_file_extension(self) -> &'static str {
|
const fn to_file_extension(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Gif => ".gif",
|
Self::Gif => ".gif",
|
||||||
|
@ -121,10 +139,10 @@ impl AudioCodec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FORMAT_MAPPINGS: &[(&str, InputFormat)] = &[
|
const FORMAT_MAPPINGS: &[(&str, VideoFormat)] = &[
|
||||||
("gif", InputFormat::Gif),
|
("gif", VideoFormat::Gif),
|
||||||
("mp4", InputFormat::Mp4),
|
("mp4", VideoFormat::Mp4),
|
||||||
("webm", InputFormat::Webm),
|
("webm", VideoFormat::Webm),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) async fn input_type_bytes(input: Bytes) -> Result<Option<ValidInputType>, Error> {
|
pub(crate) async fn input_type_bytes(input: Bytes) -> Result<Option<ValidInputType>, Error> {
|
||||||
|
@ -155,6 +173,7 @@ pub(crate) async fn details_bytes(input: Bytes) -> Result<Option<Details>, Error
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(f))]
|
||||||
async fn details_file<F, Fut>(f: F) -> Result<Option<Details>, Error>
|
async fn details_file<F, Fut>(f: F) -> Result<Option<Details>, Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(crate::file::File) -> Fut,
|
F: FnOnce(crate::file::File) -> Fut,
|
||||||
|
@ -193,7 +212,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_details(output: std::borrow::Cow<'_, str>) -> Result<Option<Details>, Error> {
|
fn parse_details(output: std::borrow::Cow<'_, str>) -> Result<Option<Details>, Error> {
|
||||||
tracing::info!("OUTPUT: {}", output);
|
tracing::debug!("OUTPUT: {}", output);
|
||||||
|
|
||||||
let mut lines = output.lines();
|
let mut lines = output.lines();
|
||||||
|
|
||||||
|
@ -230,7 +249,7 @@ fn parse_details_inner(
|
||||||
width: &str,
|
width: &str,
|
||||||
height: &str,
|
height: &str,
|
||||||
frames: &str,
|
frames: &str,
|
||||||
format: InputFormat,
|
format: VideoFormat,
|
||||||
) -> Result<Details, Error> {
|
) -> Result<Details, Error> {
|
||||||
let width = width.parse().map_err(|_| UploadError::UnsupportedFormat)?;
|
let width = width.parse().map_err(|_| UploadError::UnsupportedFormat)?;
|
||||||
let height = height.parse().map_err(|_| UploadError::UnsupportedFormat)?;
|
let height = height.parse().map_err(|_| UploadError::UnsupportedFormat)?;
|
||||||
|
@ -244,10 +263,10 @@ fn parse_details_inner(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Transcode video", skip(input))]
|
#[tracing::instrument(skip(input))]
|
||||||
pub(crate) async fn trancsocde_bytes(
|
pub(crate) async fn trancsocde_bytes(
|
||||||
input: Bytes,
|
input: Bytes,
|
||||||
input_format: InputFormat,
|
input_format: VideoFormat,
|
||||||
permit_audio: bool,
|
permit_audio: bool,
|
||||||
video_codec: VideoCodec,
|
video_codec: VideoCodec,
|
||||||
audio_codec: Option<AudioCodec>,
|
audio_codec: Option<AudioCodec>,
|
||||||
|
@ -318,11 +337,11 @@ pub(crate) async fn trancsocde_bytes(
|
||||||
Ok(Box::pin(clean_reader))
|
Ok(Box::pin(clean_reader))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Create video thumbnail")]
|
#[tracing::instrument]
|
||||||
pub(crate) async fn thumbnail<S: Store>(
|
pub(crate) async fn thumbnail<S: Store>(
|
||||||
store: S,
|
store: S,
|
||||||
from: S::Identifier,
|
from: S::Identifier,
|
||||||
input_format: InputFormat,
|
input_format: VideoFormat,
|
||||||
format: ThumbnailFormat,
|
format: ThumbnailFormat,
|
||||||
) -> Result<impl AsyncRead + Unpin, Error> {
|
) -> Result<impl AsyncRead + Unpin, Error> {
|
||||||
let input_file = crate::tmp_file::tmp_file(Some(input_format.to_file_extension()));
|
let input_file = crate::tmp_file::tmp_file(Some(input_format.to_file_extension()));
|
||||||
|
|
|
@ -126,7 +126,7 @@ mod io_uring {
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
pub(crate) async fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
pub(crate) async fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
||||||
tracing::info!("Opening io-uring file: {:?}", path.as_ref());
|
tracing::debug!("Opening io-uring file: {:?}", path.as_ref());
|
||||||
Ok(File {
|
Ok(File {
|
||||||
path: path.as_ref().to_owned(),
|
path: path.as_ref().to_owned(),
|
||||||
inner: tracing::trace_span!(parent: None, "Open File")
|
inner: tracing::trace_span!(parent: None, "Open File")
|
||||||
|
@ -136,7 +136,7 @@ mod io_uring {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn create(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
pub(crate) async fn create(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
||||||
tracing::info!("Creating io-uring file: {:?}", path.as_ref());
|
tracing::debug!("Creating io-uring file: {:?}", path.as_ref());
|
||||||
Ok(File {
|
Ok(File {
|
||||||
path: path.as_ref().to_owned(),
|
path: path.as_ref().to_owned(),
|
||||||
inner: tracing::trace_span!(parent: None, "Create File")
|
inner: tracing::trace_span!(parent: None, "Create File")
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
config::ImageFormat,
|
config::ImageFormat,
|
||||||
details::Details,
|
details::Details,
|
||||||
error::Error,
|
error::Error,
|
||||||
ffmpeg::{InputFormat, ThumbnailFormat},
|
ffmpeg::{ThumbnailFormat, VideoFormat},
|
||||||
repo::{Alias, FullRepo},
|
repo::{Alias, FullRepo},
|
||||||
store::Store,
|
store::Store,
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ pub(crate) async fn generate<R: FullRepo, S: Store + 'static>(
|
||||||
alias: Alias,
|
alias: Alias,
|
||||||
thumbnail_path: PathBuf,
|
thumbnail_path: PathBuf,
|
||||||
thumbnail_args: Vec<String>,
|
thumbnail_args: Vec<String>,
|
||||||
input_format: Option<InputFormat>,
|
input_format: Option<VideoFormat>,
|
||||||
thumbnail_format: Option<ThumbnailFormat>,
|
thumbnail_format: Option<ThumbnailFormat>,
|
||||||
hash: R::Bytes,
|
hash: R::Bytes,
|
||||||
) -> Result<(Details, Bytes), Error> {
|
) -> Result<(Details, Bytes), Error> {
|
||||||
|
@ -52,7 +52,7 @@ async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
alias: Alias,
|
alias: Alias,
|
||||||
thumbnail_path: PathBuf,
|
thumbnail_path: PathBuf,
|
||||||
thumbnail_args: Vec<String>,
|
thumbnail_args: Vec<String>,
|
||||||
input_format: Option<InputFormat>,
|
input_format: Option<VideoFormat>,
|
||||||
thumbnail_format: Option<ThumbnailFormat>,
|
thumbnail_format: Option<ThumbnailFormat>,
|
||||||
hash: R::Bytes,
|
hash: R::Bytes,
|
||||||
) -> Result<(Details, Bytes), Error> {
|
) -> Result<(Details, Bytes), Error> {
|
||||||
|
@ -68,7 +68,7 @@ async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
let reader = crate::ffmpeg::thumbnail(
|
let reader = crate::ffmpeg::thumbnail(
|
||||||
store.clone(),
|
store.clone(),
|
||||||
identifier,
|
identifier,
|
||||||
input_format.unwrap_or(InputFormat::Mp4),
|
input_format.unwrap_or(VideoFormat::Mp4),
|
||||||
thumbnail_format.unwrap_or(ThumbnailFormat::Jpeg),
|
thumbnail_format.unwrap_or(ThumbnailFormat::Jpeg),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -27,7 +27,7 @@ where
|
||||||
identifier: Option<S::Identifier>,
|
identifier: Option<S::Identifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Aggregate", skip(stream))]
|
#[tracing::instrument(skip(stream))]
|
||||||
async fn aggregate<S>(mut stream: S) -> Result<Bytes, Error>
|
async fn aggregate<S>(mut stream: S) -> Result<Bytes, Error>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Result<Bytes, Error>> + Unpin,
|
S: Stream<Item = Result<Bytes, Error>> + Unpin,
|
||||||
|
@ -41,7 +41,7 @@ where
|
||||||
Ok(buf.into_bytes())
|
Ok(buf.into_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Ingest", skip(stream))]
|
#[tracing::instrument(skip(stream))]
|
||||||
pub(crate) async fn ingest<R, S>(
|
pub(crate) async fn ingest<R, S>(
|
||||||
repo: &R,
|
repo: &R,
|
||||||
store: &S,
|
store: &S,
|
||||||
|
@ -231,12 +231,13 @@ where
|
||||||
{
|
{
|
||||||
#[tracing::instrument(name = "Drop Session", skip(self), fields(hash = ?self.hash, alias = ?self.alias, identifier = ?self.identifier))]
|
#[tracing::instrument(name = "Drop Session", skip(self), fields(hash = ?self.hash, alias = ?self.alias, identifier = ?self.identifier))]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
let cleanup_parent_span = tracing::info_span!(parent: None, "Dropped session cleanup");
|
||||||
|
cleanup_parent_span.follows_from(Span::current());
|
||||||
|
|
||||||
if let Some(hash) = self.hash.take() {
|
if let Some(hash) = self.hash.take() {
|
||||||
let repo = self.repo.clone();
|
let repo = self.repo.clone();
|
||||||
|
|
||||||
let cleanup_span =
|
let cleanup_span = tracing::info_span!(parent: cleanup_parent_span.clone(), "Session cleanup hash", hash = ?hash);
|
||||||
tracing::info_span!(parent: None, "Session cleanup hash", hash = ?hash);
|
|
||||||
cleanup_span.follows_from(Span::current());
|
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
||||||
actix_rt::spawn(
|
actix_rt::spawn(
|
||||||
|
@ -251,9 +252,7 @@ where
|
||||||
if let Some(alias) = self.alias.take() {
|
if let Some(alias) = self.alias.take() {
|
||||||
let repo = self.repo.clone();
|
let repo = self.repo.clone();
|
||||||
|
|
||||||
let cleanup_span =
|
let cleanup_span = tracing::info_span!(parent: cleanup_parent_span.clone(), "Session cleanup alias", alias = ?alias);
|
||||||
tracing::info_span!(parent: None, "Session cleanup alias", alias = ?alias);
|
|
||||||
cleanup_span.follows_from(Span::current());
|
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
||||||
actix_rt::spawn(
|
actix_rt::spawn(
|
||||||
|
@ -275,8 +274,7 @@ where
|
||||||
if let Some(identifier) = self.identifier.take() {
|
if let Some(identifier) = self.identifier.take() {
|
||||||
let repo = self.repo.clone();
|
let repo = self.repo.clone();
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: None, "Session cleanup identifier", identifier = ?identifier);
|
let cleanup_span = tracing::info_span!(parent: cleanup_parent_span, "Session cleanup identifier", identifier = ?identifier);
|
||||||
cleanup_span.follows_from(Span::current());
|
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
||||||
actix_rt::spawn(
|
actix_rt::spawn(
|
||||||
|
|
|
@ -10,7 +10,6 @@ use tokio::{
|
||||||
io::{AsyncRead, AsyncReadExt},
|
io::{AsyncRead, AsyncReadExt},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
pub(crate) fn details_hint(alias: &Alias) -> Option<ValidInputType> {
|
pub(crate) fn details_hint(alias: &Alias) -> Option<ValidInputType> {
|
||||||
let ext = alias.extension()?;
|
let ext = alias.extension()?;
|
||||||
|
@ -114,14 +113,7 @@ pub(crate) struct Details {
|
||||||
pub(crate) frames: Option<usize>,
|
pub(crate) frames: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Clear Metadata", skip(input))]
|
#[tracing::instrument(level = "debug", skip(input))]
|
||||||
pub(crate) fn clear_metadata_bytes_read(input: Bytes) -> std::io::Result<impl AsyncRead + Unpin> {
|
|
||||||
let process = Process::run("magick", &["convert", "-", "-strip", "-"])?;
|
|
||||||
|
|
||||||
Ok(process.bytes_read(input))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(name = "Convert", skip(input))]
|
|
||||||
pub(crate) fn convert_bytes_read(
|
pub(crate) fn convert_bytes_read(
|
||||||
input: Bytes,
|
input: Bytes,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
|
@ -139,7 +131,7 @@ pub(crate) fn convert_bytes_read(
|
||||||
Ok(process.bytes_read(input))
|
Ok(process.bytes_read(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Getting details from input bytes", skip(input))]
|
#[tracing::instrument(skip(input))]
|
||||||
pub(crate) async fn details_bytes(
|
pub(crate) async fn details_bytes(
|
||||||
input: Bytes,
|
input: Bytes,
|
||||||
hint: Option<ValidInputType>,
|
hint: Option<ValidInputType>,
|
||||||
|
@ -290,7 +282,6 @@ fn parse_details(s: std::borrow::Cow<'_, str>) -> Result<Details, Error> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Getting input type from bytes", skip(input))]
|
|
||||||
pub(crate) async fn input_type_bytes(input: Bytes) -> Result<ValidInputType, Error> {
|
pub(crate) async fn input_type_bytes(input: Bytes) -> Result<ValidInputType, Error> {
|
||||||
details_bytes(input, None).await?.validate_input()
|
details_bytes(input, None).await?.validate_input()
|
||||||
}
|
}
|
||||||
|
@ -308,7 +299,6 @@ fn process_image(args: Vec<String>, format: ImageFormat) -> std::io::Result<Proc
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Spawning process command")]
|
|
||||||
pub(crate) fn process_image_store_read<S: Store + 'static>(
|
pub(crate) fn process_image_store_read<S: Store + 'static>(
|
||||||
store: S,
|
store: S,
|
||||||
identifier: S::Identifier,
|
identifier: S::Identifier,
|
||||||
|
@ -318,7 +308,6 @@ pub(crate) fn process_image_store_read<S: Store + 'static>(
|
||||||
Ok(process_image(args, format)?.store_read(store, identifier))
|
Ok(process_image(args, format)?.store_read(store, identifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Spawning process command", skip(async_read))]
|
|
||||||
pub(crate) fn process_image_async_read<A: AsyncRead + Unpin + 'static>(
|
pub(crate) fn process_image_async_read<A: AsyncRead + Unpin + 'static>(
|
||||||
async_read: A,
|
async_read: A,
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
|
@ -328,7 +317,7 @@ pub(crate) fn process_image_async_read<A: AsyncRead + Unpin + 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Details {
|
impl Details {
|
||||||
#[instrument(name = "Validating input type")]
|
#[tracing::instrument(level = "debug", name = "Validating input type")]
|
||||||
pub(crate) fn validate_input(&self) -> Result<ValidInputType, Error> {
|
pub(crate) fn validate_input(&self) -> Result<ValidInputType, Error> {
|
||||||
if self.width > crate::CONFIG.media.max_width
|
if self.width > crate::CONFIG.media.max_width
|
||||||
|| self.height > crate::CONFIG.media.max_height
|
|| self.height > crate::CONFIG.media.max_height
|
||||||
|
|
|
@ -958,6 +958,7 @@ async fn aliases<R: FullRepo>(
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(name = "Fetching identifier", skip(repo))]
|
||||||
async fn identifier<R: FullRepo, S: Store>(
|
async fn identifier<R: FullRepo, S: Store>(
|
||||||
query: web::Query<AliasQuery>,
|
query: web::Query<AliasQuery>,
|
||||||
repo: web::Data<R>,
|
repo: web::Data<R>,
|
||||||
|
|
|
@ -42,13 +42,11 @@ pin_project_lite::pin_project! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
#[tracing::instrument]
|
|
||||||
pub(crate) fn run(command: &str, args: &[&str]) -> std::io::Result<Self> {
|
pub(crate) fn run(command: &str, args: &[&str]) -> std::io::Result<Self> {
|
||||||
tracing::trace_span!(parent: None, "Create command")
|
tracing::trace_span!(parent: None, "Create command")
|
||||||
.in_scope(|| Self::spawn(Command::new(command).args(args)))
|
.in_scope(|| Self::spawn(Command::new(command).args(args)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub(crate) fn spawn(cmd: &mut Command) -> std::io::Result<Self> {
|
pub(crate) fn spawn(cmd: &mut Command) -> std::io::Result<Self> {
|
||||||
tracing::trace_span!(parent: None, "Spawn command").in_scope(|| {
|
tracing::trace_span!(parent: None, "Spawn command").in_scope(|| {
|
||||||
let cmd = cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
|
let cmd = cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
|
||||||
|
@ -66,37 +64,34 @@ impl Process {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(input))]
|
|
||||||
pub(crate) fn bytes_read(self, input: Bytes) -> impl AsyncRead + Unpin {
|
pub(crate) fn bytes_read(self, input: Bytes) -> impl AsyncRead + Unpin {
|
||||||
self.read_fn(move |mut stdin| {
|
self.spawn_fn(move |mut stdin| {
|
||||||
let mut input = input;
|
let mut input = input;
|
||||||
async move { stdin.write_all_buf(&mut input).await }
|
async move { stdin.write_all_buf(&mut input).await }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub(crate) fn read(self) -> impl AsyncRead + Unpin {
|
pub(crate) fn read(self) -> impl AsyncRead + Unpin {
|
||||||
self.read_fn(|_| async { Ok(()) })
|
self.spawn_fn(|_| async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pipe_async_read<A: AsyncRead + Unpin + 'static>(
|
pub(crate) fn pipe_async_read<A: AsyncRead + Unpin + 'static>(
|
||||||
self,
|
self,
|
||||||
mut async_read: A,
|
mut async_read: A,
|
||||||
) -> impl AsyncRead + Unpin {
|
) -> impl AsyncRead + Unpin {
|
||||||
self.read_fn(move |mut stdin| async move {
|
self.spawn_fn(move |mut stdin| async move {
|
||||||
tokio::io::copy(&mut async_read, &mut stdin)
|
tokio::io::copy(&mut async_read, &mut stdin)
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub(crate) fn store_read<S: Store + 'static>(
|
pub(crate) fn store_read<S: Store + 'static>(
|
||||||
self,
|
self,
|
||||||
store: S,
|
store: S,
|
||||||
identifier: S::Identifier,
|
identifier: S::Identifier,
|
||||||
) -> impl AsyncRead + Unpin {
|
) -> impl AsyncRead + Unpin {
|
||||||
self.read_fn(move |mut stdin| {
|
self.spawn_fn(move |mut stdin| {
|
||||||
let store = store;
|
let store = store;
|
||||||
let identifier = identifier;
|
let identifier = identifier;
|
||||||
|
|
||||||
|
@ -104,7 +99,8 @@ impl Process {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_fn<F, Fut>(mut self, f: F) -> impl AsyncRead + Unpin
|
#[tracing::instrument(skip(f))]
|
||||||
|
fn spawn_fn<F, Fut>(mut self, f: F) -> impl AsyncRead + Unpin
|
||||||
where
|
where
|
||||||
F: FnOnce(ChildStdin) -> Fut + 'static,
|
F: FnOnce(ChildStdin) -> Fut + 'static,
|
||||||
Fut: Future<Output = std::io::Result<()>>,
|
Fut: Future<Output = std::io::Result<()>>,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::error::{Error, UploadError};
|
use crate::error::{Error, UploadError};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
pub(crate) trait Processor {
|
pub(crate) trait Processor {
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
|
@ -88,7 +87,7 @@ impl ResizeKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
#[tracing::instrument(level = "debug")]
|
||||||
pub(crate) fn build_chain(
|
pub(crate) fn build_chain(
|
||||||
args: &[(String, String)],
|
args: &[(String, String)],
|
||||||
ext: &str,
|
ext: &str,
|
||||||
|
|
|
@ -606,7 +606,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(repo))]
|
#[tracing::instrument(level = "debug", skip(repo))]
|
||||||
async fn migrate_identifier_details<T>(
|
async fn migrate_identifier_details<T>(
|
||||||
repo: &T,
|
repo: &T,
|
||||||
old: &FileId,
|
old: &FileId,
|
||||||
|
|
|
@ -152,7 +152,7 @@ fn insert_cache_inverse(
|
||||||
|
|
||||||
bucket.insert(alias_bytes.to_vec());
|
bucket.insert(alias_bytes.to_vec());
|
||||||
|
|
||||||
tracing::info!("Inserting new {:?}", bucket);
|
tracing::trace!("Inserting new {:?}", bucket);
|
||||||
let bucket_bytes = serde_cbor::to_vec(&bucket)?;
|
let bucket_bytes = serde_cbor::to_vec(&bucket)?;
|
||||||
let new = Some(bucket_bytes);
|
let new = Some(bucket_bytes);
|
||||||
|
|
||||||
|
@ -218,10 +218,10 @@ impl CachedRepo for SledRepo {
|
||||||
bucket.remove(&alias_bytes);
|
bucket.remove(&alias_bytes);
|
||||||
|
|
||||||
if bucket.is_empty() {
|
if bucket.is_empty() {
|
||||||
tracing::info!("Removed old {:?}", bucket);
|
tracing::trace!("Removed old {:?}", bucket);
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Inserting old {:?}", bucket);
|
tracing::trace!("Inserting old {:?}", bucket);
|
||||||
Some(serde_cbor::to_vec(&bucket))
|
Some(serde_cbor::to_vec(&bucket))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -243,12 +243,12 @@ impl CachedRepo for SledRepo {
|
||||||
cache_inverse.range(..to_clean_bytes).filter_map(Result::ok)
|
cache_inverse.range(..to_clean_bytes).filter_map(Result::ok)
|
||||||
{
|
{
|
||||||
if let Ok(datetime) = serde_json::from_slice::<DateTime>(&date_bytes) {
|
if let Ok(datetime) = serde_json::from_slice::<DateTime>(&date_bytes) {
|
||||||
tracing::info!("Checking {}", datetime);
|
tracing::trace!("Checking {}", datetime);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("Invalid date bytes");
|
tracing::warn!("Invalid date bytes");
|
||||||
}
|
}
|
||||||
if let Ok(bucket) = serde_cbor::from_slice::<Bucket>(&bucket_bytes) {
|
if let Ok(bucket) = serde_cbor::from_slice::<Bucket>(&bucket_bytes) {
|
||||||
tracing::info!("Read for deletion: {:?}", bucket);
|
tracing::trace!("Read for deletion: {:?}", bucket);
|
||||||
for alias_bytes in bucket {
|
for alias_bytes in bucket {
|
||||||
// Best effort cleanup
|
// Best effort cleanup
|
||||||
let _ = cache.remove(&alias_bytes);
|
let _ = cache.remove(&alias_bytes);
|
||||||
|
@ -266,7 +266,7 @@ impl CachedRepo for SledRepo {
|
||||||
#[cfg(debug)]
|
#[cfg(debug)]
|
||||||
for date_bytes in cache_inverse.range(to_clean_bytes..).filter_map(Result::ok) {
|
for date_bytes in cache_inverse.range(to_clean_bytes..).filter_map(Result::ok) {
|
||||||
if let Ok(datetime) = serde_json::from_slice::<DateTime>(&date_bytes) {
|
if let Ok(datetime) = serde_json::from_slice::<DateTime>(&date_bytes) {
|
||||||
tracing::info!("Not cleaning for {}", datetime);
|
tracing::trace!("Not cleaning for {}", datetime);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("Invalid date bytes");
|
tracing::warn!("Invalid date bytes");
|
||||||
}
|
}
|
||||||
|
@ -468,21 +468,21 @@ impl QueueRepo for SledRepo {
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl SettingsRepo for SledRepo {
|
impl SettingsRepo for SledRepo {
|
||||||
#[tracing::instrument(skip(value))]
|
#[tracing::instrument(level = "trace", skip(value))]
|
||||||
async fn set(&self, key: &'static str, value: Self::Bytes) -> Result<(), Error> {
|
async fn set(&self, key: &'static str, value: Self::Bytes) -> Result<(), Error> {
|
||||||
b!(self.settings, settings.insert(key, value));
|
b!(self.settings, settings.insert(key, value));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn get(&self, key: &'static str) -> Result<Option<Self::Bytes>, Error> {
|
async fn get(&self, key: &'static str) -> Result<Option<Self::Bytes>, Error> {
|
||||||
let opt = b!(self.settings, settings.get(key));
|
let opt = b!(self.settings, settings.get(key));
|
||||||
|
|
||||||
Ok(opt)
|
Ok(opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn remove(&self, key: &'static str) -> Result<(), Error> {
|
async fn remove(&self, key: &'static str) -> Result<(), Error> {
|
||||||
b!(self.settings, settings.remove(key));
|
b!(self.settings, settings.remove(key));
|
||||||
|
|
||||||
|
@ -505,7 +505,7 @@ fn variant_from_key(hash: &[u8], key: &[u8]) -> Option<String> {
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl IdentifierRepo for SledRepo {
|
impl IdentifierRepo for SledRepo {
|
||||||
#[tracing::instrument(skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
||||||
async fn relate_details<I: Identifier>(
|
async fn relate_details<I: Identifier>(
|
||||||
&self,
|
&self,
|
||||||
identifier: &I,
|
identifier: &I,
|
||||||
|
@ -522,7 +522,7 @@ impl IdentifierRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
||||||
async fn details<I: Identifier>(&self, identifier: &I) -> Result<Option<Details>, Error> {
|
async fn details<I: Identifier>(&self, identifier: &I) -> Result<Option<Details>, Error> {
|
||||||
let key = identifier.to_bytes()?;
|
let key = identifier.to_bytes()?;
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ impl IdentifierRepo for SledRepo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, identifier), fields(identifier = identifier.string_repr()))]
|
||||||
async fn cleanup<I: Identifier>(&self, identifier: &I) -> Result<(), Error> {
|
async fn cleanup<I: Identifier>(&self, identifier: &I) -> Result<(), Error> {
|
||||||
let key = identifier.to_bytes()?;
|
let key = identifier.to_bytes()?;
|
||||||
|
|
||||||
|
@ -568,7 +568,7 @@ impl HashRepo for SledRepo {
|
||||||
Box::pin(from_iterator(iter, 8))
|
Box::pin(from_iterator(iter, 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn create(&self, hash: Self::Bytes) -> Result<Result<(), AlreadyExists>, Error> {
|
async fn create(&self, hash: Self::Bytes) -> Result<Result<(), AlreadyExists>, Error> {
|
||||||
let res = b!(self.hashes, {
|
let res = b!(self.hashes, {
|
||||||
let hash2 = hash.clone();
|
let hash2 = hash.clone();
|
||||||
|
@ -578,7 +578,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(res.map_err(|_| AlreadyExists))
|
Ok(res.map_err(|_| AlreadyExists))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn relate_alias(&self, hash: Self::Bytes, alias: &Alias) -> Result<(), Error> {
|
async fn relate_alias(&self, hash: Self::Bytes, alias: &Alias) -> Result<(), Error> {
|
||||||
let key = hash_alias_key(&hash, alias);
|
let key = hash_alias_key(&hash, alias);
|
||||||
let value = alias.to_bytes();
|
let value = alias.to_bytes();
|
||||||
|
@ -588,7 +588,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn remove_alias(&self, hash: Self::Bytes, alias: &Alias) -> Result<(), Error> {
|
async fn remove_alias(&self, hash: Self::Bytes, alias: &Alias) -> Result<(), Error> {
|
||||||
let key = hash_alias_key(&hash, alias);
|
let key = hash_alias_key(&hash, alias);
|
||||||
|
|
||||||
|
@ -611,7 +611,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
||||||
async fn relate_identifier<I: Identifier>(
|
async fn relate_identifier<I: Identifier>(
|
||||||
&self,
|
&self,
|
||||||
hash: Self::Bytes,
|
hash: Self::Bytes,
|
||||||
|
@ -624,7 +624,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn identifier<I: Identifier + 'static>(&self, hash: Self::Bytes) -> Result<I, Error> {
|
async fn identifier<I: Identifier + 'static>(&self, hash: Self::Bytes) -> Result<I, Error> {
|
||||||
let opt = b!(self.hash_identifiers, hash_identifiers.get(hash));
|
let opt = b!(self.hash_identifiers, hash_identifiers.get(hash));
|
||||||
|
|
||||||
|
@ -633,7 +633,7 @@ impl HashRepo for SledRepo {
|
||||||
.and_then(|ivec| I::from_bytes(ivec.to_vec()))
|
.and_then(|ivec| I::from_bytes(ivec.to_vec()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
||||||
async fn relate_variant_identifier<I: Identifier>(
|
async fn relate_variant_identifier<I: Identifier>(
|
||||||
&self,
|
&self,
|
||||||
hash: Self::Bytes,
|
hash: Self::Bytes,
|
||||||
|
@ -651,7 +651,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn variant_identifier<I: Identifier + 'static>(
|
async fn variant_identifier<I: Identifier + 'static>(
|
||||||
&self,
|
&self,
|
||||||
hash: Self::Bytes,
|
hash: Self::Bytes,
|
||||||
|
@ -693,7 +693,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn remove_variant(&self, hash: Self::Bytes, variant: String) -> Result<(), Error> {
|
async fn remove_variant(&self, hash: Self::Bytes, variant: String) -> Result<(), Error> {
|
||||||
let key = variant_key(&hash, &variant);
|
let key = variant_key(&hash, &variant);
|
||||||
|
|
||||||
|
@ -705,7 +705,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
#[tracing::instrument(level = "trace", skip(self, hash, identifier), fields(hash = hex::encode(&hash), identifier = identifier.string_repr()))]
|
||||||
async fn relate_motion_identifier<I: Identifier>(
|
async fn relate_motion_identifier<I: Identifier>(
|
||||||
&self,
|
&self,
|
||||||
hash: Self::Bytes,
|
hash: Self::Bytes,
|
||||||
|
@ -721,7 +721,7 @@ impl HashRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn motion_identifier<I: Identifier + 'static>(
|
async fn motion_identifier<I: Identifier + 'static>(
|
||||||
&self,
|
&self,
|
||||||
hash: Self::Bytes,
|
hash: Self::Bytes,
|
||||||
|
@ -785,7 +785,7 @@ impl HashRepo for SledRepo {
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl AliasRepo for SledRepo {
|
impl AliasRepo for SledRepo {
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn create(&self, alias: &Alias) -> Result<Result<(), AlreadyExists>, Error> {
|
async fn create(&self, alias: &Alias) -> Result<Result<(), AlreadyExists>, Error> {
|
||||||
let bytes = alias.to_bytes();
|
let bytes = alias.to_bytes();
|
||||||
let bytes2 = bytes.clone();
|
let bytes2 = bytes.clone();
|
||||||
|
@ -798,7 +798,7 @@ impl AliasRepo for SledRepo {
|
||||||
Ok(res.map_err(|_| AlreadyExists))
|
Ok(res.map_err(|_| AlreadyExists))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn relate_delete_token(
|
async fn relate_delete_token(
|
||||||
&self,
|
&self,
|
||||||
alias: &Alias,
|
alias: &Alias,
|
||||||
|
@ -815,7 +815,7 @@ impl AliasRepo for SledRepo {
|
||||||
Ok(res.map_err(|_| AlreadyExists))
|
Ok(res.map_err(|_| AlreadyExists))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn delete_token(&self, alias: &Alias) -> Result<DeleteToken, Error> {
|
async fn delete_token(&self, alias: &Alias) -> Result<DeleteToken, Error> {
|
||||||
let key = alias.to_bytes();
|
let key = alias.to_bytes();
|
||||||
|
|
||||||
|
@ -826,7 +826,7 @@ impl AliasRepo for SledRepo {
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, hash), fields(hash = hex::encode(&hash)))]
|
#[tracing::instrument(level = "trace", skip(self, hash), fields(hash = hex::encode(&hash)))]
|
||||||
async fn relate_hash(&self, alias: &Alias, hash: Self::Bytes) -> Result<(), Error> {
|
async fn relate_hash(&self, alias: &Alias, hash: Self::Bytes) -> Result<(), Error> {
|
||||||
let key = alias.to_bytes();
|
let key = alias.to_bytes();
|
||||||
|
|
||||||
|
@ -835,7 +835,7 @@ impl AliasRepo for SledRepo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn hash(&self, alias: &Alias) -> Result<Self::Bytes, Error> {
|
async fn hash(&self, alias: &Alias) -> Result<Self::Bytes, Error> {
|
||||||
let key = alias.to_bytes();
|
let key = alias.to_bytes();
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::{
|
||||||
use storage_path_generator::Generator;
|
use storage_path_generator::Generator;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
use tokio_util::io::StreamReader;
|
use tokio_util::io::StreamReader;
|
||||||
use tracing::{debug, error, instrument, Instrument};
|
use tracing::Instrument;
|
||||||
|
|
||||||
mod file_id;
|
mod file_id;
|
||||||
pub(crate) use file_id::FileId;
|
pub(crate) use file_id::FileId;
|
||||||
|
@ -211,7 +211,6 @@ impl FileStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try writing to a file
|
// Try writing to a file
|
||||||
#[instrument(name = "Saving file", skip(bytes), fields(path = tracing::field::debug(&path.as_ref())))]
|
|
||||||
async fn safe_save_bytes<P: AsRef<Path>>(
|
async fn safe_save_bytes<P: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
path: P,
|
||||||
|
@ -220,7 +219,6 @@ impl FileStore {
|
||||||
safe_create_parent(&path).await?;
|
safe_create_parent(&path).await?;
|
||||||
|
|
||||||
// Only write the file if it doesn't already exist
|
// Only write the file if it doesn't already exist
|
||||||
debug!("Checking if {:?} already exists", path.as_ref());
|
|
||||||
if let Err(e) = tokio::fs::metadata(&path).await {
|
if let Err(e) = tokio::fs::metadata(&path).await {
|
||||||
if e.kind() != std::io::ErrorKind::NotFound {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
|
@ -230,23 +228,18 @@ impl FileStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the file for writing
|
// Open the file for writing
|
||||||
debug!("Creating {:?}", path.as_ref());
|
|
||||||
let mut file = File::create(&path).await?;
|
let mut file = File::create(&path).await?;
|
||||||
|
|
||||||
// try writing
|
// try writing
|
||||||
debug!("Writing to {:?}", path.as_ref());
|
|
||||||
if let Err(e) = file.write_from_bytes(bytes).await {
|
if let Err(e) = file.write_from_bytes(bytes).await {
|
||||||
error!("Error writing {:?}, {}", path.as_ref(), format!("{}", e));
|
|
||||||
// remove file if writing failed before completion
|
// remove file if writing failed before completion
|
||||||
self.safe_remove_file(path).await?;
|
self.safe_remove_file(path).await?;
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
debug!("{:?} written", path.as_ref());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(input), fields(to = tracing::field::debug(&to.as_ref())))]
|
|
||||||
async fn safe_save_reader<P: AsRef<Path>>(
|
async fn safe_save_reader<P: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
to: P,
|
to: P,
|
||||||
|
@ -254,7 +247,6 @@ impl FileStore {
|
||||||
) -> Result<(), FileError> {
|
) -> Result<(), FileError> {
|
||||||
safe_create_parent(&to).await?;
|
safe_create_parent(&to).await?;
|
||||||
|
|
||||||
debug!("Checking if {:?} already exists", to.as_ref());
|
|
||||||
if let Err(e) = tokio::fs::metadata(&to).await {
|
if let Err(e) = tokio::fs::metadata(&to).await {
|
||||||
if e.kind() != std::io::ErrorKind::NotFound {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
|
@ -263,8 +255,6 @@ impl FileStore {
|
||||||
return Err(FileError::FileExists);
|
return Err(FileError::FileExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Writing stream to {:?}", to.as_ref());
|
|
||||||
|
|
||||||
let mut file = File::create(to).await?;
|
let mut file = File::create(to).await?;
|
||||||
|
|
||||||
file.write_from_async_read(input).await?;
|
file.write_from_async_read(input).await?;
|
||||||
|
@ -275,7 +265,6 @@ impl FileStore {
|
||||||
|
|
||||||
pub(crate) async fn safe_create_parent<P: AsRef<Path>>(path: P) -> Result<(), FileError> {
|
pub(crate) async fn safe_create_parent<P: AsRef<Path>>(path: P) -> Result<(), FileError> {
|
||||||
if let Some(path) = path.as_ref().parent() {
|
if let Some(path) = path.as_ref().parent() {
|
||||||
debug!("Creating directory {:?}", path);
|
|
||||||
tokio::fs::create_dir_all(path).await?;
|
tokio::fs::create_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,6 @@ impl Store for ObjectStore {
|
||||||
type Identifier = ObjectId;
|
type Identifier = ObjectId;
|
||||||
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
||||||
|
|
||||||
#[tracing::instrument(skip(reader))]
|
|
||||||
async fn save_async_read<Reader>(&self, reader: Reader) -> Result<Self::Identifier, Error>
|
async fn save_async_read<Reader>(&self, reader: Reader) -> Result<Self::Identifier, Error>
|
||||||
where
|
where
|
||||||
Reader: AsyncRead + Unpin + 'static,
|
Reader: AsyncRead + Unpin + 'static,
|
||||||
|
|
|
@ -2,12 +2,11 @@ use crate::{
|
||||||
config::{AudioCodec, ImageFormat, VideoCodec},
|
config::{AudioCodec, ImageFormat, VideoCodec},
|
||||||
either::Either,
|
either::Either,
|
||||||
error::{Error, UploadError},
|
error::{Error, UploadError},
|
||||||
ffmpeg::InputFormat,
|
ffmpeg::FileFormat,
|
||||||
magick::ValidInputType,
|
magick::ValidInputType,
|
||||||
};
|
};
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::AsyncRead;
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
struct UnvalidatedBytes {
|
struct UnvalidatedBytes {
|
||||||
bytes: Bytes,
|
bytes: Bytes,
|
||||||
|
@ -36,7 +35,7 @@ impl AsyncRead for UnvalidatedBytes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(name = "Validate media", skip(bytes))]
|
#[tracing::instrument(skip_all)]
|
||||||
pub(crate) async fn validate_bytes(
|
pub(crate) async fn validate_bytes(
|
||||||
bytes: Bytes,
|
bytes: Bytes,
|
||||||
prescribed_format: Option<ImageFormat>,
|
prescribed_format: Option<ImageFormat>,
|
||||||
|
@ -57,8 +56,8 @@ pub(crate) async fn validate_bytes(
|
||||||
return Ok((input_type, Either::left(UnvalidatedBytes::new(bytes))));
|
return Ok((input_type, Either::left(UnvalidatedBytes::new(bytes))));
|
||||||
}
|
}
|
||||||
|
|
||||||
match (prescribed_format, input_type) {
|
match (input_type.to_file_format(), prescribed_format) {
|
||||||
(_, ValidInputType::Gif) => {
|
(FileFormat::Video(video_format), _) => {
|
||||||
if !(enable_silent_video || enable_full_video) {
|
if !(enable_silent_video || enable_full_video) {
|
||||||
return Err(UploadError::SilentVideoDisabled.into());
|
return Err(UploadError::SilentVideoDisabled.into());
|
||||||
}
|
}
|
||||||
|
@ -67,25 +66,7 @@ pub(crate) async fn validate_bytes(
|
||||||
Either::right(Either::left(
|
Either::right(Either::left(
|
||||||
crate::ffmpeg::trancsocde_bytes(
|
crate::ffmpeg::trancsocde_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
InputFormat::Gif,
|
video_format,
|
||||||
false,
|
|
||||||
video_codec,
|
|
||||||
audio_codec,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
(_, ValidInputType::Mp4) => {
|
|
||||||
if !(enable_silent_video || enable_full_video) {
|
|
||||||
return Err(UploadError::SilentVideoDisabled.into());
|
|
||||||
}
|
|
||||||
Ok((
|
|
||||||
ValidInputType::from_video_codec(video_codec),
|
|
||||||
Either::right(Either::left(
|
|
||||||
crate::ffmpeg::trancsocde_bytes(
|
|
||||||
bytes,
|
|
||||||
InputFormat::Mp4,
|
|
||||||
enable_full_video,
|
enable_full_video,
|
||||||
video_codec,
|
video_codec,
|
||||||
audio_codec,
|
audio_codec,
|
||||||
|
@ -94,47 +75,17 @@ pub(crate) async fn validate_bytes(
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
(_, ValidInputType::Webm) => {
|
(FileFormat::Image(image_format), Some(format)) if image_format != format => Ok((
|
||||||
if !(enable_silent_video || enable_full_video) {
|
|
||||||
return Err(UploadError::SilentVideoDisabled.into());
|
|
||||||
}
|
|
||||||
Ok((
|
|
||||||
ValidInputType::from_video_codec(video_codec),
|
|
||||||
Either::right(Either::left(
|
|
||||||
crate::ffmpeg::trancsocde_bytes(
|
|
||||||
bytes,
|
|
||||||
InputFormat::Webm,
|
|
||||||
enable_full_video,
|
|
||||||
video_codec,
|
|
||||||
audio_codec,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
(Some(ImageFormat::Jpeg) | None, ValidInputType::Jpeg) => Ok((
|
|
||||||
ValidInputType::Jpeg,
|
|
||||||
Either::right(Either::right(Either::left(
|
|
||||||
crate::exiftool::clear_metadata_bytes_read(bytes)?,
|
|
||||||
))),
|
|
||||||
)),
|
|
||||||
(Some(ImageFormat::Png) | None, ValidInputType::Png) => Ok((
|
|
||||||
ValidInputType::Png,
|
|
||||||
Either::right(Either::right(Either::left(
|
|
||||||
crate::exiftool::clear_metadata_bytes_read(bytes)?,
|
|
||||||
))),
|
|
||||||
)),
|
|
||||||
(Some(ImageFormat::Webp) | None, ValidInputType::Webp) => Ok((
|
|
||||||
ValidInputType::Webp,
|
|
||||||
Either::right(Either::right(Either::right(Either::left(
|
|
||||||
crate::magick::clear_metadata_bytes_read(bytes)?,
|
|
||||||
)))),
|
|
||||||
)),
|
|
||||||
(Some(format), _) => Ok((
|
|
||||||
ValidInputType::from_format(format),
|
ValidInputType::from_format(format),
|
||||||
Either::right(Either::right(Either::right(Either::right(
|
Either::right(Either::right(Either::left(
|
||||||
crate::magick::convert_bytes_read(bytes, format)?,
|
crate::magick::convert_bytes_read(bytes, format)?,
|
||||||
)))),
|
))),
|
||||||
|
)),
|
||||||
|
(FileFormat::Image(image_format), _) => Ok((
|
||||||
|
ValidInputType::from_format(image_format),
|
||||||
|
Either::right(Either::right(Either::right(
|
||||||
|
crate::exiftool::clear_metadata_bytes_read(bytes)?,
|
||||||
|
))),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue