73 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			73 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::{HttpRequest, HttpResponse, web};
 | |
| 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)
 | |
|         && 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)
 | |
|             && 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))
 | |
| }
 |