qwreey_rocket/
builder.rs

1use std::{net::IpAddr, sync::Arc};
2
3use qwreey_utility_rs::{ArcRwUserdata, ErrToString};
4use rocket::{config::Ident, fairing::AdHoc, Config};
5use rocket_dyn_templates::Template;
6
7use crate::{tera_utility::add_builtin, RocketOrbit, RouteExport, RouteExportList};
8
9// Web Backend Builder
10pub struct WebBackendBuilder {
11    exports: RouteExportList,
12    port: u16,
13    address: IpAddr,
14    userdata: Option<ArcRwUserdata>,
15}
16impl Default for WebBackendBuilder {
17    fn default() -> Self {
18        Self {
19            exports: Vec::new(),
20            port: 80,
21            address: "127.0.0.1".parse::<IpAddr>().unwrap(),
22            userdata: None,
23        }
24    }
25}
26impl WebBackendBuilder {
27    pub async fn build(self) -> Result<(), String> {
28        let builder = Arc::new(self);
29        let mut rocket = rocket::build().configure(Config {
30            cli_colors: false,
31            ident: Ident::try_new("MC-Captcha").unwrap(),
32            port: builder.port,
33            address: builder.address,
34            ..Default::default()
35        });
36
37        // Append userdata
38        let userdata = builder.userdata.clone().unwrap();
39        rocket = rocket.manage(userdata.clone());
40
41        // Mount routes
42        for export in &builder.exports {
43            rocket = rocket.mount(export.base(), export.routes());
44        }
45
46        // Add template handle
47        let builder_template_clone = builder.clone();
48        let userdata_template_clone = userdata.clone();
49        rocket = rocket.attach(Template::custom(move |engines| {
50            add_builtin(&mut engines.tera);
51            for export in &builder_template_clone.exports {
52                export.tera(&mut engines.tera, userdata_template_clone.clone());
53            }
54            engines.tera.autoescape_on(vec![]);
55        }));
56
57        // Add orbit handle
58        let builder_liftoff_clone = builder.clone();
59        let userdata_liftoff_clone = userdata.clone();
60        rocket = rocket.attach(AdHoc::on_liftoff("orbit", move |orbit: &RocketOrbit| {
61            Box::pin(async move {
62                for export in &builder_liftoff_clone.exports {
63                    export.orbit(orbit, userdata_liftoff_clone.clone()).unwrap();
64                }
65            })
66        }));
67
68        // Emit build
69        for export in &builder.exports {
70            rocket = export.build(rocket, userdata.clone())?;
71        }
72
73        // Ignite
74        let mut rocket = rocket.ignite().await.err_tostring()?;
75        for export in &builder.exports {
76            rocket = export.ignite(rocket, userdata.clone())?;
77        }
78
79        // Launch & Await
80        rocket.launch().await.err_tostring()?;
81        Ok(())
82    }
83    pub fn new() -> Self {
84        Self::default()
85    }
86    pub fn port(mut self, port: Option<u16>) -> Self {
87        self.port = port.unwrap_or(Self::default().port);
88        self
89    }
90    pub fn bind(mut self, address: Option<IpAddr>) -> Self {
91        self.address = address.unwrap_or(Self::default().address);
92        self
93    }
94    pub fn userdata(mut self, userdata: ArcRwUserdata) -> Self {
95        self.userdata = Some(userdata);
96        self
97    }
98    pub fn add_export(mut self, export: impl RouteExport + 'static) -> Self {
99        self.exports.push(Box::new(export));
100        self
101    }
102    pub fn add_export_many(mut self, exports: RouteExportList) -> Self {
103        for export in exports {
104            self.exports.push(export);
105        }
106        self
107    }
108}
109
110#[macro_export]
111macro_rules! export_list {
112    [$($item:expr,)*] => {
113        vec![$(Box::new($item),)*]
114    };
115    [$($item:expr),*] => {
116        vec![$(Box::new($item),)*]
117    };
118}