qwreey_rocket/
builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::{net::IpAddr, sync::Arc};

use qwreey_utility_rs::{ArcRwUserdata, ErrToString};
use rocket::{config::Ident, fairing::AdHoc, Config};
use rocket_dyn_templates::Template;

use crate::{tera_utility::add_builtin, RocketOrbit, RouteExport, RouteExportList};

// Web Backend Builder
pub struct WebBackendBuilder {
    exports: RouteExportList,
    port: u16,
    address: IpAddr,
    userdata: Option<ArcRwUserdata>,
}
impl Default for WebBackendBuilder {
    fn default() -> Self {
        Self {
            exports: Vec::new(),
            port: 80,
            address: "127.0.0.1".parse::<IpAddr>().unwrap(),
            userdata: None,
        }
    }
}
impl WebBackendBuilder {
    pub async fn build(self) -> Result<(), String> {
        let builder = Arc::new(self);
        let mut rocket = rocket::build().configure(Config {
            cli_colors: false,
            ident: Ident::try_new("MC-Captcha").unwrap(),
            port: builder.port,
            address: builder.address,
            ..Default::default()
        });

        // Append userdata
        let userdata = builder.userdata.clone().unwrap();
        rocket = rocket.manage(userdata.clone());

        // Mount routes
        for export in &builder.exports {
            rocket = rocket.mount(export.base(), export.routes());
        }

        // Add template handle
        let builder_template_clone = builder.clone();
        let userdata_template_clone = userdata.clone();
        rocket = rocket.attach(Template::custom(move |engines| {
            add_builtin(&mut engines.tera);
            for export in &builder_template_clone.exports {
                export.tera(&mut engines.tera, userdata_template_clone.clone());
            }
            engines.tera.autoescape_on(vec![]);
        }));

        // Add orbit handle
        let builder_liftoff_clone = builder.clone();
        let userdata_liftoff_clone = userdata.clone();
        rocket = rocket.attach(AdHoc::on_liftoff("orbit", move |orbit: &RocketOrbit| {
            Box::pin(async move {
                for export in &builder_liftoff_clone.exports {
                    export.orbit(orbit, userdata_liftoff_clone.clone()).unwrap();
                }
            })
        }));

        // Emit build
        for export in &builder.exports {
            rocket = export.build(rocket, userdata.clone())?;
        }

        // Ignite
        let mut rocket = rocket.ignite().await.err_tostring()?;
        for export in &builder.exports {
            rocket = export.ignite(rocket, userdata.clone())?;
        }

        // Launch & Await
        rocket.launch().await.err_tostring()?;
        Ok(())
    }
    pub fn new() -> Self {
        Self::default()
    }
    pub fn port(mut self, port: Option<u16>) -> Self {
        self.port = port.unwrap_or(Self::default().port);
        self
    }
    pub fn bind(mut self, address: Option<IpAddr>) -> Self {
        self.address = address.unwrap_or(Self::default().address);
        self
    }
    pub fn userdata(mut self, userdata: ArcRwUserdata) -> Self {
        self.userdata = Some(userdata);
        self
    }
    pub fn add_export(mut self, export: impl RouteExport + 'static) -> Self {
        self.exports.push(Box::new(export));
        self
    }
    pub fn add_export_many(mut self, exports: RouteExportList) -> Self {
        for export in exports {
            self.exports.push(export);
        }
        self
    }
}

#[macro_export]
macro_rules! export_list {
    [$($item:expr,)*] => {
        vec![$(Box::new($item),)*]
    };
    [$($item:expr),*] => {
        vec![$(Box::new($item),)*]
    };
}