mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat: Allow to host under subpath #145
This commit is contained in:
+30
-7
@@ -37,8 +37,8 @@ use http::{HeaderValue, Method};
|
||||
use poem::endpoint::EmbeddedFilesEndpoint;
|
||||
use poem::listener::{Listener, TcpListener};
|
||||
use poem::middleware::{CatchPanic, Compression, SetHeader};
|
||||
use poem::{endpoint::EmbeddedFileEndpoint, middleware::Cors, EndpointExt, Route, Server};
|
||||
use poem::{get, post};
|
||||
use poem::{get, handler, post, IntoResponse};
|
||||
use poem::{middleware::Cors, EndpointExt, Route, Server};
|
||||
use public::oauth2::oauth2_callback;
|
||||
use std::collections::HashSet;
|
||||
use std::time::Duration;
|
||||
@@ -115,7 +115,7 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
)
|
||||
};
|
||||
|
||||
let route = Route::new()
|
||||
let app_logic = Route::new()
|
||||
.nest("/api-docs/swagger", swagger)
|
||||
.nest("/api-docs/redoc", redoc)
|
||||
.nest("/api-docs/explorer", openapi_explorer)
|
||||
@@ -130,10 +130,10 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
"/assets",
|
||||
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
||||
)
|
||||
.at(
|
||||
"/*",
|
||||
EmbeddedFileEndpoint::<FrontEndAssets>::new("index.html"),
|
||||
)
|
||||
.at("/*", serve_index_with_base);
|
||||
|
||||
let route = Route::new()
|
||||
.nest(&SETTINGS.bichon_base_url, app_logic)
|
||||
.with(cors)
|
||||
.with_if(SETTINGS.bichon_http_compression_enabled, Compression::new())
|
||||
.with(CatchPanic::new());
|
||||
@@ -158,3 +158,26 @@ pub async fn start_http_server() -> BichonResult<()> {
|
||||
.await
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))
|
||||
}
|
||||
|
||||
#[handler]
|
||||
async fn serve_index_with_base() -> impl IntoResponse {
|
||||
let mut html =
|
||||
String::from_utf8_lossy(&FrontEndAssets::get("index.html").unwrap().data).to_string();
|
||||
|
||||
let raw_base = &SETTINGS.bichon_base_url;
|
||||
let base_href = if raw_base.ends_with('/') {
|
||||
raw_base.clone()
|
||||
} else {
|
||||
format!("{}/", raw_base)
|
||||
};
|
||||
|
||||
let inject_content = format!(
|
||||
r#"<base href="{}"><script>window.__BICHON_BASE__ = '{}';</script>"#,
|
||||
base_href, raw_base
|
||||
);
|
||||
|
||||
html = html.replace("<head>", &format!("<head>{}", inject_content));
|
||||
poem::Response::builder()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(html)
|
||||
}
|
||||
|
||||
@@ -74,6 +74,16 @@ pub struct Settings {
|
||||
)]
|
||||
pub bichon_public_url: String,
|
||||
|
||||
/// bichon base URL path (default: "/")
|
||||
#[clap(
|
||||
long,
|
||||
default_value = "/",
|
||||
env,
|
||||
help = "Set the base UI path for bichon (e.g., '/bichon' or '/bichon/'). Must start with /",
|
||||
value_parser = validate_base_url
|
||||
)]
|
||||
pub bichon_base_url: String,
|
||||
|
||||
/// CORS allowed origins (default: "*")
|
||||
#[clap(
|
||||
long,
|
||||
@@ -381,6 +391,18 @@ impl Settings {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_base_url(s: &str) -> Result<String, String> {
|
||||
if s == "/" {
|
||||
return Ok(s.to_string());
|
||||
}
|
||||
if !s.starts_with('/') {
|
||||
return Err(String::from(
|
||||
"Base URL must start with '/' (e.g., '/bichon')",
|
||||
));
|
||||
}
|
||||
Ok(s.to_string())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
|
||||
pub enum CompressionAlgorithm {
|
||||
#[clap(name = "none")]
|
||||
|
||||
Reference in New Issue
Block a user