1use tonic::transport::Certificate;
2use std::error::Error;
3use tonic::transport::server::Server;
4use tonic::service::Routes;
5use std::fs;
6use tonic::transport::Identity;
7
8pub struct KeyFiles {
9 pub ca_pem: String,
10 pub svc_pem: String,
11 pub svc_key: String,
12}
13
14pub async fn grpcs_svc<F>(
15 srv_addr: String,
16 f: F,
17 routes: Routes,
18 key_files: KeyFiles
19) -> Result<(), Box::<dyn Error> > where F: core::future::Future<Output = ()>,
20{
21 let addr: std::net::SocketAddr = srv_addr.parse()?;
22 let ca_pem = fs::read(&key_files.ca_pem)?;
23 let svc_cert = fs::read(&key_files.svc_pem)?;
24 let svc_key = fs::read(&key_files.svc_key)?;
25 let ident = Identity::from_pem(svc_cert, svc_key);
26 let ca = Certificate::from_pem(ca_pem);
27
28 let tls_cfg = tonic::transport::ServerTlsConfig::new()
29 .identity(ident)
30 .client_ca_root(ca);
31
32 match Server::builder()
33 .tls_config(tls_cfg)?
34 .add_routes(routes)
35 .serve_with_shutdown(addr, f).await
36 {
37 Ok(_) => Ok(()),
38 Err(e) => Err( e.into() )
39 }
40}
41
42pub use tonic;
43
44#[cfg(test)]
45mod test;
46
47#[cfg(test)]
48mod tests {
49 use novax_tokio::tokio as tokio;
50
51 #[tokio::test]
52 async fn should_grpcs_service_start() -> Result<(), Box<dyn std::error::Error> >{
53 let (ctrlc_h, rx) = novax_tokio::ctrl_c_handler()?;
54 let routes = super::test::sample_routes();
55 let addr = "[::1]:50065".to_string();
56 let rslt = super::grpcs_svc(addr, async move{
57 let _ = rx.await;
58 }, routes, super::KeyFiles{
59 ca_pem: "certs/ca.pem".to_string(),
60 svc_pem: "certs/server.pem".to_string(),
61 svc_key: "certs/server.key".to_string(),
62 } ).await;
63 let _ = ctrlc_h.await;
65 Ok(())
66 }
67
68}