1

I am have modified a websocket server example from smol to pass a string to the listen function.

I am getting an error:

main.rs(79, 17): this return type evaluates to the `'static` lifetime...
main.rs(62, 8): ...can't outlive the lifetime `'_` as defined on the function body at 62:8
main.rs(62, 5): Error originated from macro here``

I believe it is because it is getting passed to an async function. Is there a better explanation for what is happening and is there a way to solve it?

Here is modified version:

Cargo.toml

[dependencies]
num_cpus = "1.13.0"
smol = "*"
anyhow = "*"
async-tungstenite = "*"
futures = "0.3.4"
tungstenite = "0.11.0"
async-native-tls = "0.3.3"
native-tls = "0.2.4"

main.rs

use std::net::{TcpListener, TcpStream};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;

use anyhow::{Context as _, Result};
use async_tungstenite::WebSocketStream;
use futures::prelude::*;
use smol::{Async, Task};
use tungstenite::Message;

/// Echoes messages from the client back to it.
async fn echo(mut stream: WsStream, s: &mut String) -> Result<()> {
    let msg = stream.next().await.context("expected a message")??;
    stream.send(Message::text(msg.to_string())).await?;
    s.push_str(" world!");
    Ok(())
}

/// Listens for incoming connections and serves them.
async fn listen(listener: Async<TcpListener>, s: &mut String) -> Result<()> {
    let host = format!("ws://{}", listener.get_ref().local_addr()?);
    println!("Listening on {}", host);

    loop {
        // Accept the next connection.
        let (stream, _) = listener.accept().await?;
        println!("Accepted client: {}", stream.get_ref().peer_addr()?);

        let stream = WsStream::Plain(async_tungstenite::accept_async(stream).await?);
        Task::spawn(echo(stream, s)).unwrap().detach();
    }
}

fn main() -> Result<()> {
    let mut s: String = String::from("Hello");

    // Create an executor thread pool.
    for _ in 0..num_cpus::get().max(1) {
        thread::spawn(|| smol::run(future::pending::<()>()));
    }

    // Start WS and WSS servers.
    smol::block_on(async {
        let ws = listen(Async::<TcpListener>::bind("127.0.0.1:9000")?, &mut s);
        ws.await?;
        Ok(())
    })
}

/// A WebSocket or WebSocket+TLS connection.
enum WsStream {
    /// A plain WebSocket connection.
    Plain(WebSocketStream<Async<TcpStream>>),
}

impl Sink<Message> for WsStream {
    type Error = tungstenite::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_ready(cx),
        }
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).start_send(item),
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_flush(cx),
        }
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_close(cx),
        }
    }
}

impl Stream for WsStream {
    type Item = tungstenite::Result<Message>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_next(cx),
        }
    }
}
0

1 Answer 1

1

The lifetime of the borrow of s when calling s needs to be as long as future returned by echo as it is stored in it. However Task::spawn takes a future with 'static lifetime, so that is longer than s going back it of scope at the end of the loop. You probably need an Arc<Mutex<String>> to make this work.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.