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}