Merge pull request 'Setup routing for image and audio assets based on environment variables' (#107) from 35-make-asset-paths-configurable into main

Reviewed-on: LibreTunes/LibreTunes#107
Reviewed-by: Ethan Girouard <ethan@girouard.com>
This commit is contained in:
Ethan Girouard 2024-10-16 17:48:12 +00:00
commit 3cfcacc9ba
5 changed files with 41 additions and 4 deletions

View File

@ -15,3 +15,6 @@ DATABASE_URL=postgresql://libretunes:password@localhost:5432/libretunes
# POSTGRES_HOST=localhost # POSTGRES_HOST=localhost
# POSTGRES_PORT=5432 # POSTGRES_PORT=5432
# POSTGRES_DB=libretunes # POSTGRES_DB=libretunes
LIBRETUNES_AUDIO_PATH=assets/audio
LIBRETUNES_IMAGE_PATH=assets/images

View File

@ -13,8 +13,11 @@ services:
POSTGRES_USER: ${POSTGRES_USER} POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB} POSTGRES_DB: ${POSTGRES_DB}
LIBRETUNES_AUDIO_PATH: /assets/audio
LIBRETUNES_IMAGE_PATH: /assets/images
volumes: volumes:
- libretunes-audio:/site/audio - libretunes-audio:/assets/audio
- libretunes-images:/assets/images
depends_on: depends_on:
- redis - redis
- postgres - postgres

View File

@ -12,6 +12,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
use tower_http::services::ServeDir; use tower_http::services::ServeDir;
use leptos::*; use leptos::*;
use crate::app::App; use crate::app::App;
use std::str::FromStr;
pub async fn file_and_error_handler(uri: Uri, State(options): State<LeptosOptions>, req: Request<Body>) -> AxumResponse { pub async fn file_and_error_handler(uri: Uri, State(options): State<LeptosOptions>, req: Request<Body>) -> AxumResponse {
let root = options.site_root.clone(); let root = options.site_root.clone();
@ -27,6 +28,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
pub async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> { pub async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (StatusCode, String)> {
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap(); let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot` // `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root // This path is relative to the cargo root
match ServeDir::new(root).oneshot(req).await.ok() { match ServeDir::new(root).oneshot(req).await.ok() {
@ -37,4 +39,32 @@ cfg_if! { if #[cfg(feature = "ssr")] {
)), )),
} }
} }
pub enum AssetType {
Audio,
Image,
}
pub async fn get_asset_file(filename: String, asset_type: AssetType) -> Result<Response<Body>, (StatusCode, String)> {
const DEFAULT_AUDIO_PATH: &str = "assets/audio";
const DEFAULT_IMAGE_PATH: &str = "assets/images";
let root = match asset_type {
AssetType::Audio => std::env::var("LIBRETUNES_AUDIO_PATH").unwrap_or(DEFAULT_AUDIO_PATH.to_string()),
AssetType::Image => std::env::var("LIBRETUNES_IMAGE_PATH").unwrap_or(DEFAULT_IMAGE_PATH.to_string()),
};
// Create a Uri from the filename
// ServeDir expects a leading `/`
let uri = Uri::from_str(format!("/{}", filename).as_str());
match uri {
Ok(uri) => get_static_file(uri, root.as_str()).await,
Err(_) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Attempted to serve an invalid file"),
)),
}
}
}} }}

View File

@ -14,11 +14,11 @@ extern crate diesel_migrations;
#[cfg(feature = "ssr")] #[cfg(feature = "ssr")]
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
use axum::{routing::get, Router}; use axum::{routing::get, Router, extract::Path};
use leptos::*; use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes}; use leptos_axum::{generate_route_list, LeptosRoutes};
use libretunes::app::*; use libretunes::app::*;
use libretunes::fileserv::{file_and_error_handler, get_static_file}; use libretunes::fileserv::{file_and_error_handler, get_asset_file, get_static_file, AssetType};
use axum_login::tower_sessions::SessionManagerLayer; use axum_login::tower_sessions::SessionManagerLayer;
use tower_sessions_redis_store::{fred::prelude::*, RedisStore}; use tower_sessions_redis_store::{fred::prelude::*, RedisStore};
use axum_login::AuthManagerLayerBuilder; use axum_login::AuthManagerLayerBuilder;
@ -60,6 +60,8 @@ async fn main() {
let app = Router::new() let app = Router::new()
.leptos_routes(&leptos_options, routes, App) .leptos_routes(&leptos_options, routes, App)
.route("/assets/audio/:song", get(|Path(song) : Path<String>| get_asset_file(song, AssetType::Audio)))
.route("/assets/images/:image", get(|Path(image) : Path<String>| get_asset_file(image, AssetType::Image)))
.route("/assets/*uri", get(|uri| get_static_file(uri, ""))) .route("/assets/*uri", get(|uri| get_static_file(uri, "")))
.layer(auth_layer) .layer(auth_layer)
.fallback(file_and_error_handler) .fallback(file_and_error_handler)

View File

@ -49,7 +49,6 @@ impl TryInto<Song> for SongData {
track: self.track, track: self.track,
duration: self.duration, duration: self.duration,
release_date: self.release_date, release_date: self.release_date,
// TODO https://gitlab.mregirouard.com/libretunes/libretunes/-/issues/35
storage_path: self.song_path, storage_path: self.song_path,
// Note that if the source of the image_path was the album, the image_path // Note that if the source of the image_path was the album, the image_path