mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
update
This commit is contained in:
@@ -3,6 +3,10 @@ name = "bichon-server"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["embed-web"]
|
||||
embed-web = ["dep:rust-embed"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
bichon-core = { path = "../core", features = ["web-api"] }
|
||||
@@ -17,7 +21,7 @@ poem-openapi = { version = "5.1.16", features = [
|
||||
"swagger-ui",
|
||||
"email",
|
||||
] }
|
||||
rust-embed = "8.11.0"
|
||||
rust-embed = { version = "8.11.0", optional = true }
|
||||
email_address.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
//
|
||||
// Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com)
|
||||
//
|
||||
// This file is part of the Bichon Email Archiving Project
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#[cfg(feature = "embed-web")]
|
||||
mod inner {
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../../web/dist/"]
|
||||
pub struct FrontEndAssets;
|
||||
}
|
||||
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../../web/dist/"]
|
||||
pub struct FrontEndAssets;
|
||||
#[cfg(feature = "embed-web")]
|
||||
pub use inner::FrontEndAssets;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::common::auth::ApiGuard;
|
||||
use crate::common::error::ErrorCapture;
|
||||
use crate::common::log::Tracing;
|
||||
use crate::common::tls::rustls_config;
|
||||
@@ -29,25 +30,31 @@ use bichon_core::error::BichonResult;
|
||||
use bichon_core::raise_error;
|
||||
use bichon_core::settings::cli::SETTINGS;
|
||||
|
||||
use super::error::ApiErrorResponse;
|
||||
use crate::common::auth::ApiGuard;
|
||||
use api::create_openapi_service;
|
||||
use assets::FrontEndAssets;
|
||||
use http::{HeaderValue, Method};
|
||||
use poem::endpoint::EmbeddedFilesEndpoint;
|
||||
use http::Method;
|
||||
use poem::listener::{Listener, TcpListener};
|
||||
use poem::middleware::{CatchPanic, Compression, Cors, SetHeader};
|
||||
use poem::{get, handler, post, Endpoint, EndpointExt, IntoResponse, Route, Server};
|
||||
use poem::middleware::{CatchPanic, Compression, Cors};
|
||||
use poem::{get, post, Endpoint, EndpointExt, Route, Server};
|
||||
use public::oauth2::oauth2_callback;
|
||||
use std::collections::HashSet;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(feature = "embed-web")]
|
||||
use {
|
||||
assets::FrontEndAssets,
|
||||
http::HeaderValue,
|
||||
poem::{handler, endpoint::EmbeddedFilesEndpoint, IntoResponse},
|
||||
poem::middleware::SetHeader,
|
||||
};
|
||||
|
||||
pub mod api;
|
||||
pub mod assets;
|
||||
pub mod public;
|
||||
|
||||
pub type ApiResult<T, E = ApiErrorResponse> = std::result::Result<T, E>;
|
||||
|
||||
use super::error::ApiErrorResponse;
|
||||
|
||||
/// Build the community route tree. Pro/Enterprise servers can call this
|
||||
/// and then add their own routes before passing the tree to the server.
|
||||
pub fn build_routes() -> impl Endpoint {
|
||||
@@ -95,13 +102,6 @@ pub fn build_routes() -> impl Endpoint {
|
||||
.expose_headers(vec!["Accept"])
|
||||
.max_age(SETTINGS.bichon_cors_max_age);
|
||||
|
||||
let cache_static = || {
|
||||
SetHeader::new().overriding(
|
||||
http::header::CACHE_CONTROL,
|
||||
HeaderValue::from_static("max-age=86400"),
|
||||
)
|
||||
};
|
||||
|
||||
let app_logic = Route::new()
|
||||
.nest("/api-docs/swagger", swagger)
|
||||
.nest("/api-docs/redoc", redoc)
|
||||
@@ -112,12 +112,9 @@ pub fn build_routes() -> impl Endpoint {
|
||||
.nest("/oauth2/callback", get(oauth2_callback))
|
||||
.nest("/api/status", get(get_status))
|
||||
.nest("/api/login", post(login))
|
||||
.nest_no_strip("/api/v1", open_api_route)
|
||||
.nest_no_strip(
|
||||
"/assets",
|
||||
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
||||
)
|
||||
.at("/*", serve_index_with_base);
|
||||
.nest_no_strip("/api/v1", open_api_route);
|
||||
|
||||
let app_logic = add_web_assets(app_logic);
|
||||
|
||||
Route::new()
|
||||
.nest(&SETTINGS.bichon_base_url, app_logic)
|
||||
@@ -126,6 +123,52 @@ pub fn build_routes() -> impl Endpoint {
|
||||
.with(CatchPanic::new())
|
||||
}
|
||||
|
||||
#[cfg(feature = "embed-web")]
|
||||
fn add_web_assets(route: Route) -> impl Endpoint {
|
||||
let cache_static = || {
|
||||
SetHeader::new().overriding(
|
||||
http::header::CACHE_CONTROL,
|
||||
HeaderValue::from_static("max-age=86400"),
|
||||
)
|
||||
};
|
||||
|
||||
route
|
||||
.nest_no_strip(
|
||||
"/assets",
|
||||
EmbeddedFilesEndpoint::<FrontEndAssets>::new().with(cache_static()),
|
||||
)
|
||||
.at("/*", serve_index_with_base)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "embed-web"))]
|
||||
fn add_web_assets(route: Route) -> Route {
|
||||
route
|
||||
}
|
||||
|
||||
#[cfg(feature = "embed-web")]
|
||||
#[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)
|
||||
}
|
||||
|
||||
pub async fn start_http_server() -> BichonResult<()> {
|
||||
let listener = TcpListener::bind((
|
||||
SETTINGS.bichon_bind_ip.clone().unwrap_or("0.0.0.0".into()),
|
||||
@@ -160,26 +203,3 @@ 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user