# Manager Crate ## Overview `Manager` is a scalable, async-driven system that handles requests and communication between different components using a pub/sub model in Rust. It is built on top of the `Rocket` framework for HTTP server handling and utilizes the Tokio runtime for asynchronous tasks. This crate allows you to create handlers that process requests and handle messages via a message bus, making it highly modular and easy to extend. ## Features - **Dynamic Handler Registration**: Register new handlers dynamically that can process requests and publish messages. - **Pub/Sub Messaging**: Implement publish/subscribe messaging between different services or components. - **Concurrency Control**: Uses a semaphore to limit to `nr` request at the time from http request. The handlers inside the service can replicate as many times as they are configured. - **Graceful Shutdown**: Includes an HTTP shutdown mechanism for controlled termination of the service. - **Asynchronous Processing**: All handlers and requests are processed asynchronously using Tokio's async runtime. - **Shared state**: All handlers can access a shared state given by variable shared_state. ## Prerequisites Before you begin, ensure you have met the following requirements: - Rust version >= 1.56 (due to the use of the `async_trait` crate and async/await syntax). ## Installation To use this crate in your project, add the following dependencies to your `Cargo.toml` file: ```toml [dependencies] async-trait = "0.1" futures = "0.3.30" ``` ## How to Use ### Define a Handler To create a custom handler, you need to implement the `Base` trait. The `Base` trait requires two functions: - `run`: Handles the actual business logic of processing incoming messages. - `create`: Handles the creation of the struct It also gives two ways to communicate between handlers: - `publish`: Publishes messages to other components via the `MultiBus` and awaits the response. - `dispatch`: Dispatches messages to another service or handler. ```rust use async_trait::async_trait; use std::sync::Arc; use manager_handlers::multibus::{MultiBus}; use manager_handlers::manager::{StateType, SharedState}; pub struct MyHandler; #[async_trait] impl Base for MyHandler { async fn run(&self, src: String, data: String, communication_line: Arc, shared_state: Arc) -> Result> { // Your business logic goes here // Example of publish: let response = self.publish(data, "handler_1".to_string(), "handler_2".to_string(), communication_line.clone()).await; // Example of dispatch: self.dispatch(data, "handler_2".to_string(), communication_line.clone()).await; // Example of inserting primitive type: shared_state.insert(&"matei".to_string(), StateType::Int(43)).await; // Example of inserting sync function: let shared_function: Arc String + Sync + Send> = Arc::new(|input: String| -> String { println!("Hello, {}!", input); input + " pesto" }); shared_state.insert(&"sync_func".to_string(), StateType::FunctionSync(shared_function.clone())).await; // Example of inserting async function: let shared_async_function: Arc BoxFuture<'static, String> + Send + Sync> = Arc::new(|input: String| async move { println!("Got in the async function"); sleep(Duration::from_secs(5)).await; "Done".to_string() }.boxed()); shared_state.insert(&"async_func".to_string(), StateType::FunctionAsync(shared_async_function.clone())).await; Ok("Handled successfully".to_string()) } fn new() -> Self { MyHandler {} } } ``` ### Create and Start the Manager The `Manager` is responsible for initializing all the handlers and launching the HTTP server. Add your custom handlers to the manager using `add_handler`. You can configure the number of replicas a handler can have. IMPORTANT: There will always answer only one request at a time from outside (http), but between handlers the number of replicas will determine how many requests can be handled. ```rust use manager_handlers::manager::Manager; #[tokio::main] async fn main() { let mut manager = Manager::new(); // Register custom handlers manager.add_handler::("my_handler", 2); // Start the manager manager.start().await; } ``` ### HTTP Endpoints This crate provides a couple of HTTP endpoints that allow interaction with the system. 1. **POST `/shutdown`**: Shuts down the server gracefully. Example: ```bash curl -X POST http://localhost:8080/shutdown ``` 2. **POST `/handler_name`**: Sends a request to a registered handler with a string body. You can after that process into a JSON. Example: ```bash curl -X POST http://localhost:8080/my_handler -d "{\"key\": \"value\"}" -H "Content-Type: text/plain" ``` ## Error Handling Errors during request processing or message dispatching are handled gracefully, and appropriate error messages are returned via JSON. If a handler encounters an error, it logs the issue and returns an error message. ### Example Error Response ```json { "status": "Error", "message": "An error occurred while processing the request." } ``` ## License This crate is open-sourced under the MIT license.