turbulence icon indicating copy to clipboard operation
turbulence copied to clipboard

Questions about API usage

Open AngelOfSol opened this issue 4 years ago • 1 comments

So I've been trying to leverage turbulence for a game I'm writing (a networked fighting game), and I've been trying to make a lobby system to enable a better networked place experience. So far, I've been running into inconveniences while using the API, but I'm not sure if that's me not approaching the problem the correct way or not understanding the API. Here is my actual code that I've been working on for context.

My two main pain points are as follows, hopefully you have ideas on how I can address them:

  1. MessageChannels doesn't differentiate between connections (i.e. different people connecting to the same client). I've been approaching this by spawning a new MessageChannels for each connection, which seems to work just fine, but makes it a little painful when trying to read from the socket, because I have to check to make sure that the datagram I'm receiving is from the right address. It also leads me to having to setup a new task to create connections whenever a new address sends data.
  2. Not great compatibility with what I've been trying to do as an async workflow. Here is the code for my message loop:
async fn messages_loop_t(channels: ChannelList, mut messages: MessageChannels) {
    let messages = &mut messages;
    loop {
        // forwards incoming requests out
        if let Ok(value) = channels.join_request.incoming.try_recv() {
            messages.async_send(value).await.unwrap();
            messages.flush::<JoinRequest>();
        }
        if let Ok(value) = channels.join_response.incoming.try_recv() {
            messages.async_send(value).await.unwrap();
            messages.flush::<JoinResponse>();
        }

        // checks received data, and forwards it
        if let Some(value) = messages.recv::<JoinRequest>() {
            channels.join_request.outgoing.send(value).await.unwrap()
        }
        if let Some(value) = messages.recv::<JoinResponse>() {
            channels.join_response.outgoing.send(value).await.unwrap()
        }

        yield_now().await
    }
}

As you can see, I call the sync nonblocking methods of the messages object to check if theres any data to receiver, and yield_await at the end of the loop. It seems like a better approach would be selecting on the message type OR spawning a new task for each message, but neither of these are viable given that recv/send require an &mut MessageChannels. Additionally each recv Future is tied to the lifetime of the borrow, which means I can't return the future to be held around somewhere else. This code forwards each recieved data to a smol::channel, which lets me clone consumers allowing me to engage in behavior like the following:

    async fn request_join(&mut self, lobby: Self::LobbyId) -> Result<Self::LobbyId, JoinError> {
        let handle = self.handle.clone();
        let (incoming, outgoing) = {
            let mut inner = self.handle.write().await;
            let inner = inner.deref_mut();
            let connection = inner.connections.get_or_create_connection(
                lobby,
                inner.socket.clone(),
                inner.runtime.clone(),
            );
            (
                connection.channels.join_response.incoming.clone(),
                connection.send_request(JoinRequest { addr: lobby }),
            )
        };

        outgoing.await.unwrap();

        let response = incoming.recv().await.unwrap();

        match response {
            JoinResponse::Denied => Err(JoinError::Denied),
            JoinResponse::Accepted { self_addr } => {
                let mut lock = handle.write().await;
                lock.mode = Mode::Client(lobby);
                lock.self_addr = self_addr;
                Ok(lobby)
            }
        }
    }

Are there any solutions you would suggest to my issues/should I attempt to PR a design to address them? Thank you for making this really cool library either way!

AngelOfSol avatar Feb 09 '21 20:02 AngelOfSol