Search code examples
rustunix-socketrust-tokio

How to stop my tokio thread from blocking


I am writing a client for a Unix Domain Socket, which should listen for messages from a server, I got it to work after hours of researching (it shows 1-2 messages), but after that tokio crashes with the error: Error: Kind(WouldBlock), here is my code:

use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::net::UnixStream;

#[tokio::main]
async fn main() -> io::Result<()> {
    let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
        Ok(var) => var,
        Err(VarError::NotPresent) => panic!("Is hyprland running?"),
        Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
    };

    let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");

    let stream = UnixStream::connect(socket_path).await?;

    loop {
        stream.readable().await?;

        let mut buf = [0; 4096];
        stream.try_read(&mut buf)?;
        io::stdout().lock().write_all(&buf)?;
    }
}

Could someone please help me?


Solution

  • I fully agree with @Caesar's comment.

    • don't use try_read, use read instead
    • slice the buffer to the correct size after reading
    • check for 0 bytes read, which indicates that the end of the stream was reached
    use std::env::{var, VarError};
    use std::io::{self, Write};
    use tokio::io::AsyncReadExt;
    use tokio::net::UnixStream;
    
    #[tokio::main]
    async fn main() -> io::Result<()> {
        let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
            Ok(var) => var,
            Err(VarError::NotPresent) => panic!("Is hyprland running?"),
            Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
        };
    
        let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
    
        let mut stream = UnixStream::connect(socket_path).await?;
    
        let mut buf = [0; 4096];
    
        loop {
            let num_read = stream.read(&mut buf).await?;
            if num_read == 0 {
                break;
            }
            let buf = &buf[..num_read];
            io::stdout().lock().write_all(buf)?;
        }
    
        Ok(())
    }
    

    Disclaimer: I didn't test the code because I don't have the required socket file. It compiles, though.