mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
Give a meaningful distinction for format in details
This commit is contained in:
parent
dce0827099
commit
8fb90a6f69
3 changed files with 85 additions and 30 deletions
|
@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue