Search code examples
rustrust-tokio

Implementation of `Send` is not general enough


I'm having issues starting a Salvo+rustls web server inside of a tokio::spawn. I'm getting the error implementation of 'Send' is not general enough

use std::fs;

use salvo::{
    conn::rustls::{Keycert, RustlsConfig},
    prelude::*,
};
use tokio::task::JoinHandle;

pub fn start_web_server() -> JoinHandle<()> {
    tokio::spawn(async move {
        let listener = TcpListener::new("0.0.0.0:7878");
        let cert_bytes = fs::read("server.crt").unwrap();
        let key_bytes = fs::read("server.key").unwrap();
        let rustls_config = RustlsConfig::new(Keycert::new().cert(cert_bytes).key(key_bytes));
        let acceptor = listener.rustls(rustls_config).bind().await;
        let router = Router::new();
        Server::new(acceptor).serve(router).await;
    })
}

The error I'm getting

error: implementation of `Send` is not general enough
  --> crates/core/src/web_server.rs:10:5
   |
10 | /     tokio::spawn(async move {
11 | |         let listener = TcpListener::new("0.0.0.0:7878");
12 | |         let cert_bytes = fs::read("server.crt").unwrap();
13 | |         let key_bytes = fs::read("server.key").unwrap();
...  |
17 | |         Server::new(acceptor).serve(router).await;
18 | |     })
   | |______^ implementation of `Send` is not general enough
   |
   = note: `Send` would have to be implemented for the type `&runtime::io::registration::Registration`
   = note: ...but `Send` is actually implemented for the type `&'0 runtime::io::registration::Registration`, for some specific lifetime `'0`
> rustc --version
rustc 1.80.1 (3f5fd8dd4 2024-08-06)

The best I could find is an issue is Rust here https://github.com/rust-lang/rust/issues/96865 but I can't figure out the right Rust syntax to make the error go away.


Solution

  • You can run it as local task in new thread. If you do so, then nothing will require Send.

    use std::fs;
    
    use crate::error::Result;
    use salvo::{
        conn::rustls::{Keycert, RustlsConfig},
        prelude::*,
    };
    use tokio::task::JoinHandle;
    
    pub fn start_web_server() -> JoinHandle<Result<()>> {
        std::thread::spawn(|| {
            tokio::task::spawn_local(async move {
                let listener = TcpListener::new("0.0.0.0:7878");
                let cert_bytes = fs::read("server.crt")?;
                let key_bytes = fs::read("server.key")?;
                let rustls_config = RustlsConfig::new(Keycert::new().cert(cert_bytes).key(key_bytes));
                let acceptor = listener.rustls(rustls_config).bind().await;
                let router = Router::new();
                Server::new(acceptor).serve(router).await;
                Ok(())
            })
        })
    }