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