diff --git a/Cargo.toml b/Cargo.toml index 168ee872..1b07ae3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.0" +version = "0.1.0" edition = "2021" authors = [ @@ -24,6 +24,8 @@ categories = [ ] [dependencies] +once_cell = "1.9.0" + actix-web = "4.0.0-rc.3" sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } diff --git a/src/core/all.rs b/src/core/all.rs new file mode 100644 index 00000000..4067a838 --- /dev/null +++ b/src/core/all.rs @@ -0,0 +1,7 @@ +use crate::core::{server, state}; + +pub fn modules(cfg: &mut server::web::ServiceConfig) { + for m in state::MODULES.read().unwrap().iter() { + m.configure_module(cfg); + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs index fc3e282f..3c6040c9 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,3 +1,9 @@ pub use actix_web::dev::Server; +mod state; +pub use state::register_module; + +mod all; + +pub mod module; pub mod server; diff --git a/src/core/module/api.rs b/src/core/module/api.rs new file mode 100644 index 00000000..37c84786 --- /dev/null +++ b/src/core/module/api.rs @@ -0,0 +1,14 @@ +use crate::core::server; + +/// Modules must implement this trait. +pub trait Module: Send + Sync { + fn name(&self) -> String; + + fn description(&self) -> String { + "".to_string() + } + + #[allow(unused_variables)] + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + } +} diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs new file mode 100644 index 00000000..a8f85139 --- /dev/null +++ b/src/core/module/mod.rs @@ -0,0 +1,2 @@ +mod api; +pub use api::Module; diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 6a54d243..457bb652 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,22 +1,14 @@ -use crate::core::{server, Server}; +use crate::core::{Server, all, server}; -async fn greet() -> impl server::Responder { - "Hello!" -} +pub fn run(bootstrap: Option) -> Result { + // Call application bootstrap. + if bootstrap != None { + let _ = &(bootstrap.unwrap())(); + } -async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { - let name: String = req.match_info().get("name").unwrap_or("World").into(); - server::HttpResponse::Ok() - .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, - p { "Hello " (name) "!" } - })) -} - -pub fn run() -> Result { let server = server::HttpServer::new(|| { server::App::new() - .route("/", server::web::get().to(greet)) - .route("/{name}", server::web::get().to(greet_with_param)) + .configure(&all::modules) }) .bind("127.0.0.1:8000")? .run(); diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index a1210ce3..d39c1d4d 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -1,4 +1,4 @@ -pub use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +pub use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, web}; mod main; pub use main::run; diff --git a/src/core/state.rs b/src/core/state.rs new file mode 100644 index 00000000..6ded57b8 --- /dev/null +++ b/src/core/state.rs @@ -0,0 +1,16 @@ +use crate::Lazy; +use crate::core::module::Module; + +use std::sync::RwLock; + +// ----------------------------------------------------------------------------- +// Registered modules. +// ----------------------------------------------------------------------------- + +pub static MODULES: Lazy>> = Lazy::new(|| { + RwLock::new(vec![]) +}); + +pub fn register_module(m: &'static (dyn Module + 'static)) { + MODULES.write().unwrap().push(m); +} diff --git a/src/lib.rs b/src/lib.rs index 48a67efc..01361a13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +// Global. + +pub use once_cell::sync::Lazy; + pub mod core; pub use actix_web::main; diff --git a/src/main.rs b/src/main.rs index db2a29bc..c1545d0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,52 @@ -use pagetop::core::server; +use pagetop::core::module::Module; +use pagetop::core::{register_module, server}; + +struct Greet; +impl Module for Greet { + fn name(&self) -> String { + "Hello".to_string() + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::resource("/") + .route(server::web::get().to(greet)) + ); + } +} + +async fn greet() -> impl server::Responder { + "Hello!" +} + +struct GreetWithParam; +impl Module for GreetWithParam { + fn name(&self) -> String { + "Hello World!".to_string() + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::resource("/{name}") + .route(server::web::get().to(greet_with_param)) + ); + } +} + +async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { + let name: String = req.match_info().get("name").unwrap_or("World").into(); + server::HttpResponse::Ok() + .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, + p { "Hello " (name) "!" } + })) +} + +fn bootstrap() { + register_module(&Greet); + register_module(&GreetWithParam); +} #[pagetop::main] async fn main() -> std::io::Result<()> { - server::run()?.await + server::run(Some(bootstrap))?.await }