75 lines
2.2 KiB
Rust
75 lines
2.2 KiB
Rust
|
use crate::connections::s3_connection;
|
||
|
use crate::controllers::HttpResult;
|
||
|
use crate::models::PhotoID;
|
||
|
use crate::services::photos_service;
|
||
|
use actix_web::http::header;
|
||
|
use actix_web::{web, HttpRequest, HttpResponse};
|
||
|
use std::ops::Add;
|
||
|
use std::time::{Duration, UNIX_EPOCH};
|
||
|
|
||
|
#[derive(serde::Deserialize)]
|
||
|
pub struct PhotoIdPath {
|
||
|
id: String,
|
||
|
}
|
||
|
|
||
|
pub async fn get_full_size(id: web::Path<PhotoIdPath>, req: HttpRequest) -> HttpResult {
|
||
|
get_photo(&id, true, req).await
|
||
|
}
|
||
|
|
||
|
pub async fn get_thumbnail(id: web::Path<PhotoIdPath>, req: HttpRequest) -> HttpResult {
|
||
|
get_photo(&id, false, req).await
|
||
|
}
|
||
|
|
||
|
async fn get_photo(id: &PhotoIdPath, full_size: bool, req: HttpRequest) -> HttpResult {
|
||
|
let id = match PhotoID::from_signed_hash(&id.id) {
|
||
|
None => {
|
||
|
return Ok(HttpResponse::Unauthorized().body("Invalid hash"));
|
||
|
}
|
||
|
Some(p) => p,
|
||
|
};
|
||
|
|
||
|
let photo = photos_service::get_by_id(id).await?;
|
||
|
|
||
|
let (hash, content_type) = match full_size {
|
||
|
true => (photo.sha512.as_str(), photo.mime_type.as_str()),
|
||
|
false => (photo.thumb_sha512.as_str(), "application/png"),
|
||
|
};
|
||
|
|
||
|
// Check if an upload is un-necessary
|
||
|
if let Some(c) = req.headers().get(header::IF_NONE_MATCH) {
|
||
|
if c.to_str().unwrap_or("") == hash {
|
||
|
return Ok(HttpResponse::NotModified().finish());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if let Some(c) = req.headers().get(header::IF_MODIFIED_SINCE) {
|
||
|
let date_str = c.to_str().unwrap_or("");
|
||
|
if let Ok(date) = httpdate::parse_http_date(date_str) {
|
||
|
if date
|
||
|
.add(Duration::from_secs(1))
|
||
|
.duration_since(UNIX_EPOCH)
|
||
|
.unwrap()
|
||
|
.as_secs()
|
||
|
>= photo.time_create as u64
|
||
|
{
|
||
|
return Ok(HttpResponse::NotModified().finish());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let bytes = s3_connection::get_file(&match full_size {
|
||
|
true => photo.photo_path(),
|
||
|
false => photo.thumbnail_path(),
|
||
|
})
|
||
|
.await?;
|
||
|
|
||
|
Ok(HttpResponse::Ok()
|
||
|
.content_type(content_type)
|
||
|
.insert_header(("etag", hash))
|
||
|
.insert_header((
|
||
|
"last-modified",
|
||
|
httpdate::fmt_http_date(UNIX_EPOCH + Duration::from_secs(photo.time_create as u64)),
|
||
|
))
|
||
|
.body(bytes))
|
||
|
}
|