daoyi_cloud_common/
lib.rs

1pub use salvo::catcher::Catcher;
2pub use salvo::conn::rustls::{Keycert, RustlsConfig};
3pub use salvo::prelude::*;
4pub use salvo::server::ServerHandle;
5pub use serde::Serialize;
6pub use tokio::signal;
7pub use tracing::info;
8
9pub mod config;
10pub mod db;
11pub mod models;
12pub mod utils;
13pub mod hoops;
14pub mod routers;
15
16pub mod error;
17pub use error::AppError;
18
19pub type AppResult<T> = Result<T, AppError>;
20pub type JsonResult<T> = Result<Json<T>, AppError>;
21pub type EmptyResult = Result<Json<Empty>, AppError>;
22
23pub fn json_ok<T>(data: T) -> JsonResult<T> {
24    Ok(Json(data))
25}
26#[derive(Serialize, ToSchema, Clone, Copy, Debug)]
27pub struct Empty {}
28pub fn empty_ok() -> JsonResult<Empty> {
29    Ok(Json(Empty {}))
30}
31
32// #[tokio::main]
33// async fn main() {
34//     crate::config::init();
35//     let config = crate::config::get();
36//     crate::db::init(&config.db).await;
37// 
38//     let _guard = config.log.guard();
39//     tracing::info!("log level: {}", &config.log.filter_level);
40// 
41//     let service = Service::new(routers::root())
42//         .catcher(Catcher::default().hoop(hoops::error_404))
43//         .hoop(hoops::cors_hoop());
44//     println!("🔄 在以下位置监听 {}", &config.listen_addr);
45//     //Acme 支持,自动从 Let's Encrypt 获取 TLS 证书。例子请看 https://github.com/salvo-rs/salvo/blob/main/examples/acme-http01-quinn/src/main.rs
46//     if let Some(tls) = &config.tls {
47//         let listen_addr = &config.listen_addr;
48//         println!(
49//             "📖 Open API Page: https://{}/scalar",
50//             listen_addr.replace("0.0.0.0", "127.0.0.1")
51//         );
52//         println!(
53//             "🔑 Login Page: https://{}/login",
54//             listen_addr.replace("0.0.0.0", "127.0.0.1")
55//         );
56//         let config = RustlsConfig::new(Keycert::new().cert(tls.cert.clone()).key(tls.key.clone()));
57//         let acceptor = TcpListener::new(listen_addr).rustls(config).bind().await;
58//         let server = Server::new(acceptor);
59//         tokio::spawn(shutdown_signal(server.handle()));
60//         server.serve(service).await;
61//     } else {
62//         println!(
63//             "📖 Open API 页面: http://{}/scalar",
64//             config.listen_addr.replace("0.0.0.0", "127.0.0.1")
65//         );
66//         println!(
67//             "🔑 Login Page: http://{}/login",
68//             config.listen_addr.replace("0.0.0.0", "127.0.0.1")
69//         );
70//         let acceptor = TcpListener::new(&config.listen_addr).bind().await;
71//         let server = Server::new(acceptor);
72//         tokio::spawn(shutdown_signal(server.handle()));
73//         server.serve(service).await;
74//     }
75// }
76
77pub async fn shutdown_signal(handle: ServerHandle) {
78    let ctrl_c = async {
79        signal::ctrl_c()
80            .await
81            .expect("failed to install Ctrl+C handler");
82    };
83
84    #[cfg(unix)]
85    let terminate = async {
86        signal::unix::signal(signal::unix::SignalKind::terminate())
87            .expect("failed to install signal handler")
88            .recv()
89            .await;
90    };
91
92    #[cfg(not(unix))]
93    let terminate = std::future::pending::<()>();
94
95    tokio::select! {
96        _ = ctrl_c => info!("ctrl_c signal received"),
97        _ = terminate => info!("terminate signal received"),
98    }
99    handle.stop_graceful(std::time::Duration::from_secs(60));
100}
101
102#[cfg(test)]
103mod tests {
104    use salvo::prelude::*;
105    use salvo::test::{ResponseExt, TestClient};
106
107    use crate::config;
108
109    #[tokio::test]
110    async fn test_hello_world() {
111        config::init();
112
113        let service = Service::new(crate::routers::root());
114
115        let content = TestClient::get(format!(
116            "http://{}",
117            config::get().listen_addr.replace("0.0.0.0", "127.0.0.1")
118        ))
119        .send(&service)
120        .await
121        .take_string()
122        .await
123        .unwrap();
124        assert_eq!(content, "Hello World from salvo");
125    }
126}