Give a meaningful distinction for format in details

This commit is contained in:
asonix 2023-08-31 16:26:45 -05:00
parent dce0827099
commit 8fb90a6f69
3 changed files with 85 additions and 30 deletions

View file

@ -17,8 +17,30 @@ pub(crate) struct HumanDate {
pub(crate) timestamp: time::OffsetDateTime, pub(crate) timestamp: time::OffsetDateTime,
} }
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[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)]
pub(crate) struct Details { pub(crate) struct Details {
pub(crate) inner: DetailsInner,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct DetailsInner {
width: u16, width: u16,
height: u16, height: u16,
frames: Option<u32>, frames: Option<u32>,
@ -28,12 +50,39 @@ pub(crate) struct Details {
} }
impl Details { impl Details {
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,
},
}
}
pub(crate) fn is_video(&self) -> bool { pub(crate) fn is_video(&self) -> bool {
self.content_type.type_() == "video" self.inner.content_type.type_() == "video"
} }
pub(crate) fn created_at(&self) -> time::OffsetDateTime { pub(crate) fn created_at(&self) -> time::OffsetDateTime {
self.created_at.timestamp self.inner.created_at.timestamp
} }
pub(crate) async fn from_bytes(timeout: u64, input: web::Bytes) -> Result<Self, Error> { pub(crate) async fn from_bytes(timeout: u64, input: web::Bytes) -> Result<Self, Error> {
@ -74,19 +123,19 @@ impl Details {
} }
pub(crate) fn internal_format(&self) -> InternalFormat { pub(crate) fn internal_format(&self) -> InternalFormat {
self.format self.inner.format
} }
pub(crate) fn media_type(&self) -> mime::Mime { pub(crate) fn media_type(&self) -> mime::Mime {
(*self.content_type).clone() (*self.inner.content_type).clone()
} }
pub(crate) fn system_time(&self) -> std::time::SystemTime { pub(crate) fn system_time(&self) -> std::time::SystemTime {
self.created_at.into() self.inner.created_at.into()
} }
pub(crate) fn video_format(&self) -> Option<InternalVideoFormat> { pub(crate) fn video_format(&self) -> Option<InternalVideoFormat> {
match self.format { match self.inner.format {
InternalFormat::Video(format) => Some(format), InternalFormat::Video(format) => Some(format),
_ => None, _ => None,
} }
@ -100,12 +149,14 @@ impl Details {
created_at: HumanDate, created_at: HumanDate,
) -> Self { ) -> Self {
Self { Self {
width, inner: DetailsInner {
height, width,
frames, height,
content_type: Serde::new(format.media_type()), frames,
created_at, content_type: Serde::new(format.media_type()),
format, created_at,
format,
},
} }
} }
@ -116,14 +167,16 @@ impl Details {
frames: Option<u32>, frames: Option<u32>,
) -> Self { ) -> Self {
Self { Self {
width, inner: DetailsInner {
height, width,
frames, height,
content_type: Serde::new(format.media_type()), frames,
created_at: HumanDate { content_type: Serde::new(format.media_type()),
timestamp: OffsetDateTime::now_utc(), created_at: HumanDate {
timestamp: OffsetDateTime::now_utc(),
},
format,
}, },
format,
} }
} }
} }

View file

@ -34,7 +34,7 @@ use actix_web::{
http::header::{CacheControl, CacheDirective, LastModified, Range, ACCEPT_RANGES}, http::header::{CacheControl, CacheDirective, LastModified, Range, ACCEPT_RANGES},
web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer,
}; };
use details::HumanDate; use details::{ApiDetails, HumanDate};
use futures_core::Stream; use futures_core::Stream;
use metrics_exporter_prometheus::PrometheusBuilder; use metrics_exporter_prometheus::PrometheusBuilder;
use middleware::Metrics; use middleware::Metrics;
@ -296,7 +296,7 @@ async fn handle_upload<S: Store + 'static>(
files.push(serde_json::json!({ files.push(serde_json::json!({
"file": alias.to_string(), "file": alias.to_string(),
"delete_token": delete_token.to_string(), "delete_token": delete_token.to_string(),
"details": details, "details": details.into_api_details(),
})); }));
} }
} }
@ -446,7 +446,7 @@ async fn claim_upload<S: Store + 'static>(
"files": [{ "files": [{
"file": alias.to_string(), "file": alias.to_string(),
"delete_token": token.to_string(), "delete_token": token.to_string(),
"details": details, "details": details.into_api_details(),
}] }]
}))) })))
} }
@ -543,7 +543,7 @@ async fn do_download_inline<S: Store + 'static>(
"files": [{ "files": [{
"file": alias.to_string(), "file": alias.to_string(),
"delete_token": delete_token.to_string(), "delete_token": delete_token.to_string(),
"details": details, "details": details.into_api_details(),
}] }]
}))) })))
} }
@ -603,7 +603,7 @@ struct PageJson {
struct HashJson { struct HashJson {
hex: String, hex: String,
aliases: Vec<String>, aliases: Vec<String>,
details: Option<Details>, details: Option<ApiDetails>,
} }
/// Get a page of hashes /// Get a page of hashes
@ -637,7 +637,9 @@ async fn page(
let identifier = repo.identifier(hash.clone()).await?; let identifier = repo.identifier(hash.clone()).await?;
let details = if let Some(identifier) = identifier { let details = if let Some(identifier) = identifier {
repo.details(&identifier).await? repo.details(&identifier)
.await?
.map(|d| d.into_api_details())
} else { } else {
None None
}; };
@ -769,7 +771,7 @@ async fn process_details<S: Store>(
let details = details.ok_or(UploadError::NoFiles)?; let details = details.ok_or(UploadError::NoFiles)?;
Ok(HttpResponse::Ok().json(&details)) Ok(HttpResponse::Ok().json(&details.into_api_details()))
} }
async fn not_found_hash(repo: &ArcRepo) -> Result<Option<(Alias, Hash)>, Error> { async fn not_found_hash(repo: &ArcRepo) -> Result<Option<(Alias, Hash)>, Error> {
@ -1105,7 +1107,7 @@ async fn do_details<S: Store + 'static>(
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let details = ensure_details(&repo, &store, &config, &alias).await?; let details = ensure_details(&repo, &store, &config, &alias).await?;
Ok(HttpResponse::Ok().json(&details)) Ok(HttpResponse::Ok().json(&details.into_api_details()))
} }
/// Serve files based on alias query /// Serve files based on alias query

View file

@ -932,7 +932,7 @@ impl DetailsRepo for SledRepo {
details: &Details, details: &Details,
) -> Result<(), StoreError> { ) -> Result<(), StoreError> {
let key = identifier.to_bytes()?; let key = identifier.to_bytes()?;
let details = serde_json::to_vec(&details) let details = serde_json::to_vec(&details.inner)
.map_err(SledError::from) .map_err(SledError::from)
.map_err(RepoError::from)?; .map_err(RepoError::from)?;
@ -950,7 +950,7 @@ impl DetailsRepo for SledRepo {
let opt = b!(self.identifier_details, identifier_details.get(key)); let opt = b!(self.identifier_details, identifier_details.get(key));
opt.map(|ivec| serde_json::from_slice(&ivec)) opt.map(|ivec| serde_json::from_slice(&ivec).map(|inner| Details { inner }))
.transpose() .transpose()
.map_err(SledError::from) .map_err(SledError::from)
.map_err(RepoError::from) .map_err(RepoError::from)