novax_grpcs/
lib.rs

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        // server start
64        let _ = ctrlc_h.await;
65        Ok(())
66    }
67
68}