#[cfg(test)]
mod tests;
pub mod controller;
use crate::app::controller::favicon::FaviconController;
use crate::app::controller::health::HealthController;
use crate::app::controller::ready::ReadyController;
use crate::app::controller::metrics::MetricsController;
use crate::app::controller::file::initiate::FileUploadInitiateController;
use crate::app::controller::form::get_method::FormGetMethodController;
use crate::app::controller::form::multipart_enctype_post_method::FormMultipartEnctypePostMethodController;
use crate::app::controller::form::url_encoded_enctype_post_method::FormUrlEncodedEnctypePostMethodController;
use crate::app::controller::index::IndexController;
use crate::app::controller::not_found::NotFoundController;
use crate::app::controller::script::ScriptController;
use crate::app::controller::static_resource::StaticResourceController;
use crate::app::controller::style::StyleController;
use crate::application::Application;
use crate::controller::Controller;
use crate::core::New;
use crate::header::Header;
use crate::mcp::McpServer;
use crate::middleware::{Middleware, WithMiddleware};
use crate::request::Request;
use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
use crate::server::ConnectionInfo;
use crate::state::AppWithState;
struct ControllerEntry {
is_matching: fn(&Request, &ConnectionInfo) -> bool,
process: fn(&Request, Response, &ConnectionInfo) -> Response,
}
fn entry<C: Controller>() -> ControllerEntry {
ControllerEntry {
is_matching: C::is_matching,
process: C::process,
}
}
#[derive(Copy, Clone)]
pub struct App {}
impl New for App {
fn new() -> Self {
App{}
}
}
impl Application for App {
fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
let header_list = Header::get_header_list(request);
let response = Response::get_response(
STATUS_CODE_REASON_PHRASE.n501_not_implemented,
Some(header_list),
None,
);
let controllers = [
entry::<IndexController>(),
entry::<StyleController>(),
entry::<ScriptController>(),
entry::<FileUploadInitiateController>(),
entry::<FormUrlEncodedEnctypePostMethodController>(),
entry::<FormGetMethodController>(),
entry::<FormMultipartEnctypePostMethodController>(),
entry::<HealthController>(),
entry::<ReadyController>(),
entry::<MetricsController>(),
entry::<FaviconController>(),
entry::<StaticResourceController>(),
entry::<NotFoundController>(),
];
for c in &controllers {
if (c.is_matching)(request, connection) {
return Ok((c.process)(request, response, connection));
}
}
Ok(response)
}
}
impl App {
pub fn handle_request(request: Request) -> (Response, Request) {
use crate::server::Address;
let conn = ConnectionInfo {
client: Address { ip: "127.0.0.1".to_string(), port: 0 },
server: Address { ip: "127.0.0.1".to_string(), port: 7878 },
request_size: 16000,
};
let app = App::new();
let response = app.execute(&request, &conn).unwrap_or_else(|_| {
let header_list = Header::get_header_list(&request);
Response::get_response(
STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
Some(header_list),
None,
)
});
(response, request)
}
pub fn with_state<S: Send + Sync + 'static>(state: S) -> AppWithState<S> {
AppWithState::new(state)
}
pub fn wrap<M: Middleware + 'static>(self, layer: M) -> WithMiddleware<App> {
WithMiddleware::new(self).wrap(layer)
}
pub fn mcp(self, name: impl Into<String>, version: impl Into<String>) -> McpServer {
McpServer::new(name, version).wrap(self)
}
#[cfg(feature = "http2")]
pub fn with_async_state<S: Send + Sync + 'static>(state: S) -> crate::async_state::AsyncAppWithState<S> {
crate::async_state::AsyncAppWithState::new(state)
}
}