2023-09-02 23:30:45 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-10-01 00:38:11 +00:00
|
|
|
use crate::{
|
2023-08-31 01:37:54 +00:00
|
|
|
bytes_stream::BytesStream,
|
|
|
|
discover::Discovery,
|
2022-10-01 00:38:11 +00:00
|
|
|
error::Error,
|
2023-07-13 03:12:21 +00:00
|
|
|
formats::{InternalFormat, InternalVideoFormat},
|
2022-10-01 00:38:11 +00:00
|
|
|
serde_str::Serde,
|
|
|
|
store::Store,
|
2023-08-31 01:37:54 +00:00
|
|
|
stream::IntoStreamer,
|
2022-10-01 00:38:11 +00:00
|
|
|
};
|
2022-03-24 22:09:15 +00:00
|
|
|
use actix_web::web;
|
2023-07-13 03:12:21 +00:00
|
|
|
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
2022-03-24 22:09:15 +00:00
|
|
|
|
2022-04-08 18:36:06 +00:00
|
|
|
#[derive(Copy, Clone, Debug, serde::Deserialize, serde::Serialize)]
|
2023-08-29 17:59:36 +00:00
|
|
|
#[serde(transparent)]
|
|
|
|
pub(crate) struct HumanDate {
|
|
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
|
|
pub(crate) timestamp: time::OffsetDateTime,
|
2022-04-08 18:36:06 +00:00
|
|
|
}
|
|
|
|
|
2023-08-31 21:26:45 +00:00
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
|
|
enum ApiFormat {
|
|
|
|
Image,
|
|
|
|
Animation,
|
|
|
|
Video,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
|
|
pub(crate) struct ApiDetails {
|
|
|
|
width: u16,
|
|
|
|
height: u16,
|
|
|
|
frames: Option<u32>,
|
|
|
|
content_type: Serde<mime::Mime>,
|
|
|
|
created_at: HumanDate,
|
|
|
|
format: ApiFormat,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
2022-03-24 22:09:15 +00:00
|
|
|
pub(crate) struct Details {
|
2023-08-31 21:26:45 +00:00
|
|
|
pub(crate) inner: DetailsInner,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
|
|
|
pub(crate) struct DetailsInner {
|
2023-07-13 18:48:59 +00:00
|
|
|
width: u16,
|
|
|
|
height: u16,
|
|
|
|
frames: Option<u32>,
|
2022-03-24 22:09:15 +00:00
|
|
|
content_type: Serde<mime::Mime>,
|
2023-08-29 17:59:36 +00:00
|
|
|
created_at: HumanDate,
|
2023-08-16 17:36:18 +00:00
|
|
|
format: InternalFormat,
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Details {
|
2023-08-31 21:26:45 +00:00
|
|
|
pub(crate) fn into_api_details(self) -> ApiDetails {
|
|
|
|
let Details {
|
|
|
|
inner:
|
|
|
|
DetailsInner {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
|
|
|
content_type,
|
|
|
|
created_at,
|
|
|
|
format,
|
|
|
|
},
|
|
|
|
} = self;
|
|
|
|
|
|
|
|
ApiDetails {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
|
|
|
content_type,
|
|
|
|
created_at,
|
|
|
|
format: match format {
|
|
|
|
InternalFormat::Image(_) => ApiFormat::Image,
|
|
|
|
InternalFormat::Animation(_) => ApiFormat::Animation,
|
|
|
|
InternalFormat::Video(_) => ApiFormat::Video,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 18:48:59 +00:00
|
|
|
pub(crate) fn is_video(&self) -> bool {
|
2023-08-31 21:26:45 +00:00
|
|
|
self.inner.content_type.type_() == "video"
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 23:43:24 +00:00
|
|
|
pub(crate) fn created_at(&self) -> time::OffsetDateTime {
|
2023-08-31 21:26:45 +00:00
|
|
|
self.inner.created_at.timestamp
|
2023-08-28 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
2023-08-05 17:41:06 +00:00
|
|
|
pub(crate) async fn from_bytes(timeout: u64, input: web::Bytes) -> Result<Self, Error> {
|
2023-08-31 01:37:54 +00:00
|
|
|
let Discovery {
|
|
|
|
input,
|
2023-07-13 18:48:59 +00:00
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
2023-08-31 01:37:54 +00:00
|
|
|
} = crate::discover::discover_bytes(timeout, input).await?;
|
2023-07-13 18:48:59 +00:00
|
|
|
|
2023-08-31 01:37:54 +00:00
|
|
|
Ok(Details::from_parts(
|
|
|
|
input.internal_format(),
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
|
|
|
))
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
2023-07-17 03:07:42 +00:00
|
|
|
pub(crate) async fn from_store<S: Store>(
|
2023-07-13 18:48:59 +00:00
|
|
|
store: &S,
|
2023-09-02 23:30:45 +00:00
|
|
|
identifier: &Arc<str>,
|
2023-08-05 17:41:06 +00:00
|
|
|
timeout: u64,
|
2022-03-27 01:45:12 +00:00
|
|
|
) -> Result<Self, Error> {
|
2023-08-31 01:37:54 +00:00
|
|
|
let mut buf = BytesStream::new();
|
|
|
|
|
|
|
|
let mut stream = store
|
|
|
|
.to_stream(identifier, None, None)
|
|
|
|
.await?
|
|
|
|
.into_streamer();
|
|
|
|
|
|
|
|
while let Some(res) = stream.next().await {
|
|
|
|
buf.add_bytes(res?);
|
|
|
|
}
|
|
|
|
|
|
|
|
let bytes = buf.into_bytes();
|
2023-07-13 18:48:59 +00:00
|
|
|
|
2023-08-31 01:37:54 +00:00
|
|
|
Self::from_bytes(timeout, bytes).await
|
2023-07-13 18:48:59 +00:00
|
|
|
}
|
|
|
|
|
2023-08-16 17:36:18 +00:00
|
|
|
pub(crate) fn internal_format(&self) -> InternalFormat {
|
2023-08-31 21:26:45 +00:00
|
|
|
self.inner.format
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
2023-07-14 19:53:37 +00:00
|
|
|
pub(crate) fn media_type(&self) -> mime::Mime {
|
2023-08-31 21:26:45 +00:00
|
|
|
(*self.inner.content_type).clone()
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn system_time(&self) -> std::time::SystemTime {
|
2023-08-31 21:26:45 +00:00
|
|
|
self.inner.created_at.into()
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
2022-10-01 00:38:11 +00:00
|
|
|
|
2023-07-13 18:48:59 +00:00
|
|
|
pub(crate) fn video_format(&self) -> Option<InternalVideoFormat> {
|
2023-08-31 21:26:45 +00:00
|
|
|
match self.inner.format {
|
2023-08-16 17:36:18 +00:00
|
|
|
InternalFormat::Video(format) => Some(format),
|
|
|
|
_ => None,
|
2022-10-01 00:38:11 +00:00
|
|
|
}
|
2023-08-16 17:36:18 +00:00
|
|
|
}
|
2022-10-01 00:38:11 +00:00
|
|
|
|
2023-08-16 17:36:18 +00:00
|
|
|
pub(crate) fn from_parts_full(
|
|
|
|
format: InternalFormat,
|
|
|
|
width: u16,
|
|
|
|
height: u16,
|
|
|
|
frames: Option<u32>,
|
2023-08-29 17:59:36 +00:00
|
|
|
created_at: HumanDate,
|
2023-08-16 17:36:18 +00:00
|
|
|
) -> Self {
|
|
|
|
Self {
|
2023-08-31 21:26:45 +00:00
|
|
|
inner: DetailsInner {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
|
|
|
content_type: Serde::new(format.media_type()),
|
|
|
|
created_at,
|
|
|
|
format,
|
|
|
|
},
|
2022-10-01 00:38:11 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-13 03:12:21 +00:00
|
|
|
|
|
|
|
pub(crate) fn from_parts(
|
|
|
|
format: InternalFormat,
|
|
|
|
width: u16,
|
|
|
|
height: u16,
|
|
|
|
frames: Option<u32>,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
2023-08-31 21:26:45 +00:00
|
|
|
inner: DetailsInner {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
frames,
|
|
|
|
content_type: Serde::new(format.media_type()),
|
|
|
|
created_at: HumanDate {
|
|
|
|
timestamp: OffsetDateTime::now_utc(),
|
|
|
|
},
|
|
|
|
format,
|
2023-08-29 17:59:36 +00:00
|
|
|
},
|
2023-07-13 03:12:21 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-24 22:09:15 +00:00
|
|
|
}
|
2022-04-08 18:36:06 +00:00
|
|
|
|
2023-08-29 17:59:36 +00:00
|
|
|
impl From<HumanDate> for std::time::SystemTime {
|
|
|
|
fn from(HumanDate { timestamp }: HumanDate) -> Self {
|
|
|
|
timestamp.into()
|
2022-04-08 18:36:06 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-08 22:35:57 +00:00
|
|
|
|
2023-08-29 17:59:36 +00:00
|
|
|
impl std::fmt::Display for HumanDate {
|
2023-07-08 22:35:57 +00:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2023-08-29 17:59:36 +00:00
|
|
|
let s = self
|
|
|
|
.timestamp
|
|
|
|
.format(&Rfc3339)
|
|
|
|
.map_err(|_| std::fmt::Error)?;
|
2023-07-08 22:35:57 +00:00
|
|
|
|
2023-08-29 17:59:36 +00:00
|
|
|
f.write_str(&s)
|
2023-07-08 22:35:57 +00:00
|
|
|
}
|
|
|
|
}
|