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
9pub 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 let userdata = builder.userdata.clone().unwrap();
39 rocket = rocket.manage(userdata.clone());
40
41 for export in &builder.exports {
43 rocket = rocket.mount(export.base(), export.routes());
44 }
45
46 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 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 for export in &builder.exports {
70 rocket = export.build(rocket, userdata.clone())?;
71 }
72
73 let mut rocket = rocket.ignite().await.err_tostring()?;
75 for export in &builder.exports {
76 rocket = export.ignite(rocket, userdata.clone())?;
77 }
78
79 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}