Skip to main content

nestforge_http/
factory.rs

1use std::net::SocketAddr;
2
3use anyhow::Result;
4use axum::Router;
5use nestforge_core::{Container, ModuleDefinition};
6use tower_http::trace::TraceLayer;
7
8/*
9NestForgeFactory = app bootstrapper.
10
11This is the NestFactory.create(AppModule) vibe.
12
13Now it:
14- builds DI container
15- asks the module to register providers
16- asks the module for controllers
17- merges controller routers into one app router
18*/
19pub struct NestForgeFactory<M: ModuleDefinition> {
20    _marker: std::marker::PhantomData<M>,
21    container: Container,
22}
23
24impl<M: ModuleDefinition> NestForgeFactory<M> {
25    pub fn create() -> Result<Self> {
26        let container = Container::new();
27
28        /* Let the module register providers/services into DI */
29        M::register(&container)?;
30
31        Ok(Self {
32            _marker: std::marker::PhantomData,
33            container,
34        })
35    }
36
37    pub async fn listen(self, port: u16) -> Result<()> {
38        /*
39        Build a router that EXPECTS Container state.
40        We don't attach the actual state yet.
41        */
42        let mut app: Router<Container> = Router::new();
43
44        /*
45        Mount all controller routers (they are also Router<Container>)
46        */
47        for controller_router in M::controllers() {
48            app = app.merge(controller_router);
49        }
50
51        /*
52        Now attach the real Container state.
53        After this, the router becomes ready to run.
54        */
55        let app = app
56            .with_state(self.container.clone())
57            .layer(TraceLayer::new_for_http());
58
59        let addr = SocketAddr::from(([127, 0, 0, 1], port));
60        let listener = tokio::net::TcpListener::bind(addr).await?;
61
62        println!("🦀 NestForge running on http://{}", addr);
63
64        axum::serve(listener, app).await?;
65        Ok(())
66    }
67}