Skip to content

Commit

Permalink
refactor(api): [#180] Axum API, proxy context
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jun 16, 2023
1 parent 032b57f commit 0af2cb7
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 2 deletions.
47 changes: 47 additions & 0 deletions src/web/api/v1/contexts/proxy/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! API handlers for the the [`proxy`](crate::web::api::v1::contexts::proxy) API
//! context.
use std::sync::Arc;

use axum::extract::{Path, State};
use axum::response::Response;

use super::responses::png_image;
use crate::cache::image::manager::Error;
use crate::common::AppData;
use crate::ui::proxy::map_error_to_image;
use crate::web::api::v1::extractors::bearer_token::Extract;

/// Get the remote image. It uses the cached image if available.
#[allow(clippy::unused_async)]
pub async fn get_proxy_image_handler(
State(app_data): State<Arc<AppData>>,
Extract(maybe_bearer_token): Extract,
Path(url): Path<String>,
) -> Response {
if maybe_bearer_token.is_none() {
return png_image(map_error_to_image(&Error::Unauthenticated));
}

let Ok(user_id) = app_data.auth.get_user_id_from_bearer_token(&maybe_bearer_token).await else { return png_image(map_error_to_image(&Error::Unauthenticated)) };

// code-review: Handling status codes in the frontend other tan OK is quite a pain.
// Return OK for now.

// todo: it also work for other image types but we are always returning the
// same content type: `image/png`. If we only support PNG images we should
// change the documentation and return an error for other image types.

// Get image URL from URL path parameter.
let image_url = urlencoding::decode(&url).unwrap_or_default().into_owned();

match app_data.proxy_service.get_image_by_url(&image_url, &user_id).await {
Ok(image_bytes) => {
// Returns the cached image.
png_image(image_bytes)
}
Err(e) => {
// Returns an error image.
png_image(map_error_to_image(&e))
}
}
}
3 changes: 3 additions & 0 deletions src/web/api/v1/contexts/proxy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@
//! --output mandelbrotset.jpg \
//! http://0.0.0.0:3000/v1/proxy/image/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F2%2F21%2FMandel_zoom_00_mandelbrot_set.jpg%2F1280px-Mandel_zoom_00_mandelbrot_set.jpg
//! ```
pub mod handlers;
pub mod responses;
pub mod routes;
8 changes: 8 additions & 0 deletions src/web/api/v1/contexts/proxy/responses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use axum::response::{IntoResponse, Response};
use bytes::Bytes;
use hyper::{header, StatusCode};

#[must_use]
pub fn png_image(bytes: Bytes) -> Response {
(StatusCode::OK, [(header::CONTENT_TYPE, "image/png")], bytes).into_response()
}
15 changes: 15 additions & 0 deletions src/web/api/v1/contexts/proxy/routes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! API routes for the [`proxy`](crate::web::api::v1::contexts::proxy) API context.
//!
//! Refer to the [API endpoint documentation](crate::web::api::v1::contexts::proxy).
use std::sync::Arc;

use axum::routing::get;
use axum::Router;

use super::handlers::get_proxy_image_handler;
use crate::common::AppData;

/// Routes for the [`about`](crate::web::api::v1::contexts::about) API context.
pub fn router(app_data: Arc<AppData>) -> Router {
Router::new().route("/image/:url", get(get_proxy_image_handler).with_state(app_data))
}
5 changes: 3 additions & 2 deletions src/web/api/v1/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use axum::Router;

use super::contexts::about::handlers::about_page_handler;
//use tower_http::cors::CorsLayer;
use super::contexts::{about, settings, tag, torrent};
use super::contexts::{about, proxy, settings, tag, torrent};
use super::contexts::{category, user};
use crate::common::AppData;

Expand All @@ -25,7 +25,8 @@ pub fn router(app_data: Arc<AppData>) -> Router {
.nest("/tags", tag::routes::router_for_multiple_resources(app_data.clone()))
.nest("/settings", settings::routes::router(app_data.clone()))
.nest("/torrent", torrent::routes::router_for_single_resources(app_data.clone()))
.nest("/torrents", torrent::routes::router_for_multiple_resources(app_data.clone()));
.nest("/torrents", torrent::routes::router_for_multiple_resources(app_data.clone()))
.nest("/proxy", proxy::routes::router(app_data.clone()));

Router::new()
.route("/", get(about_page_handler).with_state(app_data))
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/contexts/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod about;
pub mod category;
pub mod proxy;
pub mod root;
pub mod settings;
pub mod tag;
Expand Down
6 changes: 6 additions & 0 deletions tests/e2e/contexts/proxy/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! API contract for `proxy` context.

mod with_axum_implementation {

// todo
}
1 change: 1 addition & 0 deletions tests/e2e/contexts/proxy/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod contract;

0 comments on commit 0af2cb7

Please sign in to comment.