The smokesignal.events web application
1use anyhow::Result;
2use axum::{
3 body::Body,
4 extract::{Path, State},
5 response::{IntoResponse, Response},
6};
7use http::{StatusCode, header};
8
9use crate::http::{context::WebContext, errors::WebError};
10
11/// GET /content/{cid} - Handle content requests.
12/// Gets content from content storage and returns it as a response.
13pub(crate) async fn handle_content(
14 State(web_context): State<WebContext>,
15 Path(cid): Path<String>,
16) -> Result<impl IntoResponse, WebError> {
17 tracing::info!(?cid, "cid");
18 let exists = match web_context.content_storage.content_exists(&cid).await {
19 Ok(exists) => exists,
20 Err(_) => return Ok((StatusCode::INTERNAL_SERVER_ERROR).into_response()),
21 };
22
23 tracing::info!(?exists, "exists");
24
25 if !exists {
26 return Ok((StatusCode::NOT_FOUND).into_response());
27 }
28
29 // Read the content data
30 let content_data = match web_context.content_storage.read_content(&cid).await {
31 Ok(data) => data,
32 Err(_) => return Ok((StatusCode::INTERNAL_SERVER_ERROR).into_response()),
33 };
34
35 // Detect content type from the original path extension
36 let content_type = if cid.ends_with(".png") {
37 "image/png"
38 } else if cid.ends_with(".jpg") || cid.ends_with(".jpeg") {
39 "image/jpeg"
40 } else {
41 "application/octet-stream"
42 };
43
44 // Return the content with appropriate headers
45 Ok(Response::builder()
46 .status(StatusCode::OK)
47 .header(header::CONTENT_TYPE, content_type)
48 .header(header::CACHE_CONTROL, "public, max-age=86400") // Cache for 1 day
49 .body(Body::from(content_data))
50 .unwrap()
51 .into_response())
52}