How to handle async calls in

I'm trying to learn Rust + Tokio and for that, I'm building a TCP client for a specific server. This involves long-lived connections and byte arrays being passed back and forth at random times. But when the connection is opened a handshake must be done for authentication.

I'm currently trying to implement that handshake in the new() of a struct that represents my connection, the same way I'd do it in the ctor of a class in C++ but am stuck with Tokio async methods:

fn new(session: &Session) -> Result<Connection, Box> {
let res: Result<TcpStream, Box> = session.runtime().borrow_mut().block_on(async {
let fut = TcpStream::connect(session.configuration().socket()).await?;
Ok(fut)
});

    let mut stream = res?;

    let result: Result<(), Box<dyn std::error::Error>> = session.runtime().borrow_mut().block_on(async {
        let startup = startup(session.configuration());
        stream.write_all(startup.as_ref()).await?;
        Ok(())
    });

    let mut buffer: Vec<u8> = Vec::new();
    let handle = tokio::spawn(async move {
        stream.read_to_end(&mut buffer).await;
        stream
    });

    let stream = handle.await??;

    let conn = Connection { session, stream };
    Ok(conn)
}

Is this the right way to do it? How can I move the handle from handle back into my code? Should I make the whole method async?

If you want the function to perform async operations, the function should be async. You can spawn in non-async code, but you can't wait for the spawned task to finish.

Note: You probably want Box<dyn Error + Send + Sync> rather than Box<dyn Error>.