1+ // Copyright (C) 2025 Matías Salinas ([email protected] ) 2+ //
3+ // Licensed under the Apache License, Version 2.0 (the "License");
4+ // you may not use this file except in compliance with the License.
5+ // You may obtain a copy of the License at
6+ //
7+ // http://www.apache.org/licenses/LICENSE-2.0
8+ //
9+ // Unless required by applicable law or agreed to in writing, software
10+ // distributed under the License is distributed on an "AS IS" BASIS,
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ // See the License for the specific language governing permissions and
13+ // limitations under the License.
14+
115use axum:: {
216 extract:: Path ,
317 http:: { header, Response , StatusCode } ,
@@ -7,23 +21,24 @@ use mime_guess::from_path;
721use rust_embed:: RustEmbed ;
822
923#[ derive( RustEmbed ) ]
10- #[ folder = "ui/dist/cb-admin/" ] // Ruta relativa al Cargo.toml
24+ #[ folder = "ui/dist/cb-admin/" ]
1125pub struct EmbeddedAssets ;
1226
13- /// Servidor de archivos embebidos para `/cb-admin/*path`
14- /// Soporta rutas como:
15- /// - `/cb-admin`
16- /// - `/cb-admin/`
17- /// - `/cb-admin/index.html`
18- /// - `/cb-admin/cache` -> `cache/index.html`
19- /// - `/cb-admin/cache/` -> `cache/index.html`
27+
2028pub async fn embedded_ui_handler ( Path ( path) : Path < String > ) -> impl IntoResponse {
2129 tracing:: info!( "📦 UI embedded request for: {}" , path) ;
2230
23- // Elimina "/" inicial para estandarizar
2431 let clean_path = path. trim_start_matches ( '/' ) ;
2532
26- // Lógica para resolver correctamente rutas tipo `/cb-admin/cache`
33+ /// Determines the appropriate asset path to serve based on the provided `clean_path`.
34+ ///
35+ /// - If `clean_path` is empty, defaults to `"index.html"`.
36+ /// - If an asset exists for `clean_path`, uses it directly.
37+ /// - Otherwise, checks if an asset exists for `"{clean_path}/index.html"` and uses it if available.
38+ /// - If none of the above, falls back to using `clean_path` as is.
39+ ///
40+ /// This logic ensures that directory requests are resolved to their `index.html`
41+ /// and that only existing embedded assets are served.
2742 let resolved_path = if clean_path. is_empty ( ) {
2843 "index.html" . to_string ( )
2944 } else if EmbeddedAssets :: get ( clean_path) . is_some ( ) {
@@ -33,29 +48,32 @@ pub async fn embedded_ui_handler(Path(path): Path<String>) -> impl IntoResponse
3348 if EmbeddedAssets :: get ( & with_index) . is_some ( ) {
3449 with_index
3550 } else {
36- clean_path. to_string ( ) // Intento final (puede fallar)
51+ clean_path. to_string ( )
3752 }
3853 } ;
3954
40- // Buscar el archivo embebido
4155 match EmbeddedAssets :: get ( & resolved_path) {
4256 Some ( content) => {
57+ /// Determines the MIME type of the file at the given `resolved_path`.
58+ /// If the MIME type cannot be determined, defaults to `application/octet-stream`.
59+ ///
60+ /// # Returns
61+ ///
62+ /// A [`mime::Mime`] representing the file's MIME type.
4363 let mime = from_path ( & resolved_path) . first_or_octet_stream ( ) ;
4464 Response :: builder ( )
4565 . header ( header:: CONTENT_TYPE , mime. as_ref ( ) )
4666 . body ( axum:: body:: Body :: from ( content. data . into_owned ( ) ) )
4767 . unwrap ( )
4868 }
4969 None => {
50- // Fallback a index.html para SPA si existe
5170 if let Some ( index) = EmbeddedAssets :: get ( "index.html" ) {
5271 return Response :: builder ( )
5372 . header ( header:: CONTENT_TYPE , "text/html" )
5473 . body ( axum:: body:: Body :: from ( index. data . into_owned ( ) ) )
5574 . unwrap ( ) ;
5675 }
5776
58- // Si ni siquiera hay index, error 404
5977 Response :: builder ( )
6078 . status ( StatusCode :: NOT_FOUND )
6179 . body ( axum:: body:: Body :: from ( "404 Not Found" ) )
@@ -64,7 +82,6 @@ pub async fn embedded_ui_handler(Path(path): Path<String>) -> impl IntoResponse
6482 }
6583}
6684
67- /// Sirve el archivo `index.html` directamente para rutas `/cb-admin` o `/cb-admin/`
6885pub async fn embedded_ui_index ( ) -> impl IntoResponse {
6986 match EmbeddedAssets :: get ( "index.html" ) {
7087 Some ( content) => Response :: builder ( )
0 commit comments