use crate::command::{Command, Response};
use crate::error::PixelflutErrorKind;
use crate::{Color, Pixel, PixelBuffer, PixelflutResult};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::{TcpStream, ToSocketAddrs};
pub struct PixelflutClient {
stream: BufReader<TcpStream>,
write_buf: PixelBuffer,
}
impl PixelflutClient {
pub async fn connect(addr: impl ToSocketAddrs) -> PixelflutResult<PixelflutClient> {
let stream = TcpStream::connect(addr).await?;
Ok(PixelflutClient {
stream: BufReader::new(stream),
write_buf: PixelBuffer::new(),
})
}
async fn write_command(&mut self, command: &Command) -> PixelflutResult<()> {
self.flush().await?;
self.stream
.write_all(format!("{}\n", command).as_bytes())
.await?;
Ok(())
}
async fn read_command(&mut self) -> PixelflutResult<Response> {
let mut line = String::new();
let _bytes_read = self.stream.read_line(&mut line).await?;
let response = line.trim_end().parse()?;
Ok(response)
}
pub async fn set(&mut self, x: u32, y: u32, color: impl Into<Color>) -> PixelflutResult<()> {
let pixel = Pixel::new((x, y).into(), color.into());
if self.write_buf.is_capacity_reached() {
self.flush().await?;
}
self.write_buf.write_pixel(&pixel);
Ok(())
}
pub async fn dimensions(&mut self) -> PixelflutResult<(u32, u32)> {
self.write_command(&Command::Size).await?;
let response = self.read_command().await?;
Ok(match response {
Response::Size { w, h } => (w, h),
_ => return Err(PixelflutErrorKind::State.into()),
})
}
pub async fn write_buffer(&mut self, buffer: &PixelBuffer) -> PixelflutResult<()> {
self.flush().await?;
self.stream.write_all(buffer.as_slice()).await?;
Ok(())
}
pub async fn flush(&mut self) -> PixelflutResult<()> {
if !self.write_buf.is_empty() {
self.stream.write_all(self.write_buf.as_slice()).await?;
}
self.write_buf.clear();
Ok(())
}
}