elvwlc

2 commits
Updated 2026-06-10 17:49:22
src
src/client.rs
use crate::proto::{
    WlCallbackDone, WlDisplayError, WlDisplaySync, WlMsg, WlOpCode, WlUnknowHeader,
};
use elvwf::{self as wf, Wired};
use std::{
    io::{Read, Write},
    os::unix::net::UnixStream,
    path::Path,
};

#[derive(Debug)]
pub struct WlClient {
    stream: UnixStream,
    buffer: Box<[u8]>,
    write_cursor: usize,

    read_cursor: usize,
    read_length: usize,

    next_id: u32,
}

#[derive(Debug)]
pub enum Error {
    IO(std::io::Error),
    Msg(wf::Error),
    Header(wf::header::Error),
}

impl From<std::io::Error> for Error {
    fn from(value: std::io::Error) -> Self {
        Self::IO(value)
    }
}

impl From<wf::header::Error> for Error {
    fn from(value: wf::header::Error) -> Self {
        Self::Header(value)
    }
}

impl From<wf::Error> for Error {
    fn from(value: wf::Error) -> Self {
        Self::Msg(value)
    }
}

impl WlClient {
    pub const ID: u32 = 1;

    pub fn new(path: impl AsRef<Path>, capacity: usize) -> Result<Self, Error> {
        Ok(Self {
            stream: UnixStream::connect(path)?,
            buffer: Box::from(vec![0u8; 1024]),
            write_cursor: 0,
            read_cursor: 0,
            read_length: 0,
            next_id: 2,
        })
    }

    pub fn next(&mut self) -> u32 {
        let next_id = self.next_id;
        self.next_id += 1;
        next_id
    }

    pub fn request<'a, T: WlOpCode + Wired<'a>>(&mut self, request: WlMsg<T>) -> Result<(), Error> {
        let buf = &mut &mut self.buffer[self.write_cursor..];
        let start = buf.len();

        wf::msg::encode_value(buf, request)?;

        let len = start - buf.len();
        self.write_cursor += len;

        Ok(())
    }

    pub fn flush(&mut self) -> Result<(), Error> {
        self.stream.write_all(&self.buffer[..self.write_cursor])?;
        self.write_cursor = 0;

        Ok(())
    }

    pub fn pump(&mut self) -> Result<(), Error> {
        let new_callback = self.next();
        self.request(WlMsg::new(Self::ID, WlDisplaySync { new_callback }))?;
        self.flush()?;

        self.read_cursor = 0;
        self.read_length = 0;
        let buf = &mut &mut self.buffer[..];

        loop {
            self.stream.read_exact(&mut buf[..8])?;
            let h = wf::msg::decode_value::<WlUnknowHeader>(&mut &buf[..8], 8)?;
            self.stream.read_exact(&mut buf[8..h.len as usize])?;

            if h.id == new_callback && h.op == WlCallbackDone::OP_CODE as u16 {
                break Ok(());
            }

            if h.id == Self::ID && h.op == WlDisplayError::OP_CODE as u16 {
                let error =
                    wf::msg::decode_value::<WlMsg<WlDisplayError>>(&mut &buf[..h.len as usize], 8)?;

                eprintln!(
                    "[ERROR] ({}): {}",
                    error.payload().code,
                    error.payload().message
                );
                break Ok(());
            }

            *buf = &mut buf[h.len as usize..];
            self.read_length += h.len as usize;
        }
    }

    pub fn read<'a, T: WlOpCode + Wired<'a>>(&'a mut self) -> Result<Option<WlMsg<T>>, Error> {
        if self.read_cursor == self.read_length {
            return Ok(None);
        }

        let buf = &mut &self.buffer[self.read_cursor..self.read_length];
        let start = buf.len();

        let msg = wf::msg::decode_value::<WlMsg<T>>(buf, 8)?;
        self.read_cursor += start - buf.len();

        Ok(Some(msg))
    }
}