From ccf226f3503590be92809ee9aa4330442504201c Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Thu, 3 Oct 2024 22:47:20 +0200 Subject: [PATCH 1/6] refactor: the syncUnsafeCell is now in the grid --- Cargo.lock | 2 +- src/grid.rs | 22 ++++++++++++---------- src/main.rs | 32 ++++++++++++++------------------ 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcccc56..8150480 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" diff --git a/src/grid.rs b/src/grid.rs index b3d5f04..93f8c29 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,13 +1,15 @@ +use std::cell::SyncUnsafeCell; + pub trait Grid { fn get(&self, x: I, y: I) -> Option<&V>; fn get_unchecked(&self, x: I, y: I) -> &V; - fn set(&mut self, x: I, y: I, value: V); + fn set(&self, x: I, y: I, value: V); } pub struct FlutGrid { size_x: usize, size_y: usize, - cells: Vec, + cells: SyncUnsafeCell>, } impl FlutGrid { @@ -19,7 +21,7 @@ impl FlutGrid { return FlutGrid { size_x, size_y, - cells: vec, + cells: vec.into(), }; } } @@ -39,20 +41,20 @@ impl Grid for FlutGrid { fn get(&self, x: u16, y: u16) -> Option<&T> { match self.index(x, y) { None => None, - Some(idx) => Some(&self.cells[idx]), + Some(idx) => Some(unsafe { &(*self.cells.get())[idx] }), } } - fn set(&mut self, x: u16, y: u16, value: T) { + fn set(&self, x: u16, y: u16, value: T) { match self.index(x, y) { None => (), - Some(idx) => self.cells[idx] = value, + Some(idx) => unsafe { (*self.cells.get())[idx] = value }, } } fn get_unchecked(&self, x: u16, y: u16) -> &T { let idx = y as usize * self.size_x + x as usize; - return &self.cells[idx]; + return unsafe { &(*self.cells.get())[idx] }; } } @@ -66,7 +68,7 @@ mod tests { async fn test_grid_init_values() { let grid = FlutGrid::init(3, 3, 0); - assert_eq!(grid.cells, vec![0, 0, 0, 0, 0, 0, 0, 0, 0]) + assert_eq!(grid.cells.into_inner(), vec![0, 0, 0, 0, 0, 0, 0, 0, 0]) } #[tokio::test] @@ -82,7 +84,7 @@ mod tests { let mut grid = FlutGrid::init(3, 3, 0); grid.set(1, 1, 255); grid.set(2, 1, 256); - assert_eq!(grid.cells, vec![0, 0, 0, 0, 255, 256, 0, 0, 0]) + assert_eq!(grid.cells.into_inner(), vec![0, 0, 0, 0, 255, 256, 0, 0, 0]) } #[tokio::test] @@ -90,7 +92,7 @@ mod tests { let mut grid = FlutGrid::init(3, 3, 0); grid.set(1, 1, 255); grid.set(3, 1, 256); - assert_eq!(grid.cells, vec![0, 0, 0, 0, 255, 0, 0, 0, 0]) + assert_eq!(grid.cells.into_inner(), vec![0, 0, 0, 0, 255, 0, 0, 0, 0]) } #[tokio::test] diff --git a/src/main.rs b/src/main.rs index c46b5ed..8622342 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use std::{ time::Duration, }; -use grid::Grid; +use grid::{FlutGrid, Grid}; use tokio::{ io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, net::TcpListener, @@ -35,15 +35,15 @@ const GRID_LENGTH: usize = 1; static COUNTER: AtomicU64 = AtomicU64::new(0); -fn set_pixel_rgba(grids: &mut [grid::FlutGrid], canvas: u8, x: u16, y: u16, rgb: u32) { - match grids.get_mut(canvas as usize) { +fn set_pixel_rgba(grids: &[grid::FlutGrid], canvas: u8, x: u16, y: u16, rgb: u32) { + match grids.get(canvas as usize) { Some(grid) => grid.set(x, y, rgb), None => (), } } -fn get_pixel(grids: &mut [grid::FlutGrid], canvas: u8, x: u16, y: u16) -> Option<&u32> { - match grids.get_mut(canvas as usize) { +fn get_pixel(grids: &[grid::FlutGrid], canvas: u8, x: u16, y: u16) -> Option<&u32> { + match grids.get(canvas as usize) { Some(grid) => return grid.get(x, y), None => return None, } @@ -59,7 +59,7 @@ async fn process_lock< >( reader: &mut R, _writer: &mut W, - grids: &mut [grid::FlutGrid; GRID_LENGTH], + grids: &[grid::FlutGrid; GRID_LENGTH], ) -> io::Result<()> { let amount = reader.read_u16_le().await?; let command = reader.read_u8().await?; @@ -101,7 +101,7 @@ async fn process_lock< }) .map(|z| z) .collect::>(); - match grids.get_mut(aa[0] as usize) { + match grids.get(aa[0] as usize) { Some(grid) => { grid.set( u16::from_le_bytes([aa[1], aa[2]]), @@ -131,7 +131,7 @@ async fn process_msg< >( reader: &mut R, writer: &mut W, - grids: &mut [grid::FlutGrid; GRID_LENGTH], + grids: &[grid::FlutGrid; GRID_LENGTH], ) -> io::Result<()> { let fst = reader.read_u8().await; match fst { @@ -189,7 +189,7 @@ async fn rgb_bin_read( async fn set_px_rgb_bin( reader: &mut R, - grids: &mut [grid::FlutGrid; GRID_LENGTH], + grids: &[grid::FlutGrid; GRID_LENGTH], ) -> io::Result<()> { let (canvas, x, y, r, g, b) = rgb_bin_read(reader).await?; let rgb = u32::from_be_bytes([r, g, b, 0xff]); @@ -201,7 +201,7 @@ async fn set_px_rgb_bin( async fn process_socket( reader: R, writer: W, - grids: &mut [grid::FlutGrid; GRID_LENGTH], + grids: &[grid::FlutGrid; GRID_LENGTH], ) -> io::Result<()> where W: AsyncWriteExt + std::marker::Unpin, @@ -235,16 +235,13 @@ async fn listen_handle() { #[tokio::main] async fn main() -> io::Result<()> { - println!("Start initialisation"); - let grids = [grid::FlutGrid::init(800, 600, 0xff00ffff)]; - assert_eq!(grids.len(), GRID_LENGTH); - let asuc = Arc::new(SyncUnsafeCell::new(grids)); println!("created grids"); + let grids: Arc<[FlutGrid; GRID_LENGTH]> = + [grid::FlutGrid::init(800, 600, 0xff00ffff)].into(); let flut_listener = TcpListener::bind("0.0.0.0:7791").await?; println!("bound flut listener"); - let img_grids = unsafe { asuc.get().as_ref().unwrap() }; let web_listener = TcpListener::bind("0.0.0.0:7792").await?; println!("bound web listener"); @@ -252,11 +249,10 @@ async fn main() -> io::Result<()> { loop { let (mut socket, _) = flut_listener.accept().await?; - let asuc = asuc.clone(); + let grids = grids.clone(); let _ = tokio::spawn(async move { - let grids = unsafe { asuc.get().as_mut().unwrap() }; let (reader, writer) = socket.split(); - match process_socket(reader, writer, grids).await { + match process_socket(reader, writer, &grids).await { Ok(()) => return Ok(()), Err(err) => return Err(err), } From 9350e6bc630dacffc2c41f8231b5884b4c0f536c Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Fri, 4 Oct 2024 19:30:15 +0200 Subject: [PATCH 2/6] feat: WOWA, ik workie :3 --- Cargo.lock | 26 +++ Cargo.toml | 3 + src/binary_protocol.rs | 234 ++++++++++++++++++++++ src/grid.rs | 26 ++- src/main.rs | 442 +++++++++++++++++++---------------------- src/text_protocol.rs | 234 ++++++++++++++++++++++ 6 files changed, 718 insertions(+), 247 deletions(-) create mode 100644 src/binary_protocol.rs create mode 100644 src/text_protocol.rs diff --git a/Cargo.lock b/Cargo.lock index 8150480..24b0829 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,23 @@ dependencies = [ "syn", ] +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi_radix10" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6970a22a33d6a8f862aac371bac48505a1bfaa230ecb268c7b86fa4ac6e7121" + [[package]] name = "autocfg" version = "1.3.0" @@ -88,7 +105,10 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "flurry" version = "0.1.0" dependencies = [ + "async-trait", + "atoi_radix10", "bytes", + "hex", "tokio", "tokio-test", ] @@ -111,6 +131,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "libc" version = "0.2.155" diff --git a/Cargo.toml b/Cargo.toml index 36083d6..82031fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] +async-trait = "0.1.83" +atoi_radix10 = "0.0.1" bytes = "1.6.0" +hex = "0.4.3" tokio = { version = "1.38", features = ["full"] } tokio-test = "*" diff --git a/src/binary_protocol.rs b/src/binary_protocol.rs new file mode 100644 index 0000000..78c369a --- /dev/null +++ b/src/binary_protocol.rs @@ -0,0 +1,234 @@ +use std::io::{self, Error, ErrorKind}; + +use atoi_radix10::parse_from_str; +use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt}; + +use crate::{ + increment_counter, Canvas, Color, Command, Coordinate, Parser, Protocol, Responder, Response, + MEEHHEH, +}; + +const SIZE_BIN: u8 = 115; +const HELP_BIN: u8 = 104; +const LOCK: u8 = 0; +const GET_PX_BIN: u8 = 32; +const SET_PX_RGB_BIN: u8 = 128; +const SET_PX_RGBA_BIN: u8 = 129; +const SET_PX_W_BIN: u8 = 130; + +const SET_PX_RGB_BIN_LENGTH: usize = 8; +pub struct BinaryParser {} + +impl BinaryParser { + pub fn new() -> BinaryParser { + return BinaryParser {}; + } +} + +impl Parser for BinaryParser { + async fn parse(&self, reader: &mut R) -> io::Result { + let fst = reader.read_u8().await; + match fst { + Ok(i) => match i { + HELP_BIN => return Ok(Command::Help), + SIZE_BIN => { + let canvas = reader.read_u8().await?; + return Ok(Command::Size(canvas)); + } + GET_PX_BIN => { + let canvas = reader.read_u8().await?; + let x = reader.read_u16_le().await?; + let y = reader.read_u16_le().await?; + return Ok(Command::GetPixel(canvas, x, y)); + } + SET_PX_W_BIN => { + let canvas = reader.read_u8().await?; + let x = reader.read_u16_le().await?; + let y = reader.read_u16_le().await?; + let w = reader.read_u8().await?; + return Ok(Command::SetPixel(canvas, x, y, Color::W8(w))); + } + SET_PX_RGB_BIN => { + let canvas = reader.read_u8().await?; + let x = reader.read_u16_le().await?; + let y = reader.read_u16_le().await?; + let r = reader.read_u8().await?; + let g = reader.read_u8().await?; + let b = reader.read_u8().await?; + return Ok(Command::SetPixel(canvas, x, y, Color::RGB24(r, g, b))); + } + SET_PX_RGBA_BIN => { + let canvas = reader.read_u8().await?; + let x = reader.read_u16_le().await?; + let y = reader.read_u16_le().await?; + let r = reader.read_u8().await?; + let g = reader.read_u8().await?; + let b = reader.read_u8().await?; + let a = reader.read_u8().await?; + return Ok(Command::SetPixel(canvas, x, y, Color::RGBA32(r, g, b, a))); + } + _ => { + eprintln!("received illegal command: {}", i); + return Err(Error::from(ErrorKind::InvalidInput)); + } + }, + Err(err) => { + eprintln!("{}", err); + return Err(err); + } + } + } +} + +impl MEEHHEH for BinaryParser { + fn change_canvas(&mut self, _canvas: Canvas) -> io::Result<()> { + return Err(Error::from(ErrorKind::Unsupported)); + } +} + +impl Responder for BinaryParser { + async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()> { + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::grid::FlutGrid; + use tokio::io::BufReader; + use tokio_test::assert_ok; + + #[tokio::test] + async fn test_bin_help_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new().read(&[HELP_BIN]).build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::Help) + } + + #[tokio::test] + async fn test_bin_size_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new().read(&[SIZE_BIN, 3]).build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::Size(3)) + } + + #[tokio::test] + async fn test_bin_px_set_w_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new() + .read(&[SET_PX_W_BIN, 0x01, 0x69, 0x42, 0x42, 0x69, 0x82]) + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(1, 0x4269, 0x6942, Color::W8(0x82)) + ) + } + + #[tokio::test] + async fn test_bin_px_set_rgb_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new() + .read(&[ + SET_PX_RGB_BIN, + 0x01, + 0x69, + 0x42, + 0x42, + 0x69, + 0x82, + 0x00, + 0xff, + ]) + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(1, 0x4269, 0x6942, Color::RGB24(0x82, 0x00, 0xff)) + ) + } + + #[tokio::test] + async fn test_bin_px_set_rgba_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new() + .read(&[ + SET_PX_RGBA_BIN, + 0x01, + 0x69, + 0x42, + 0x42, + 0x69, + 0x82, + 0x00, + 0xff, + 0xa0, + ]) + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(1, 0x4269, 0x6942, Color::RGBA32(0x82, 0x00, 0xff, 0xa0)) + ) + } + + #[tokio::test] + async fn test_bin_px_get_parse() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new() + .read(&[GET_PX_BIN, 0x03, 0x69, 0x42, 0x42, 0x69]) + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::GetPixel(3, 0x4269, 0x6942)) + } + + #[tokio::test] + async fn test_bin_parse_multiple() { + let parser = BinaryParser::new(); + let reader = tokio_test::io::Builder::new() + .read(&[ + SET_PX_RGB_BIN, + 0x01, + 0x69, + 0x42, + 0x42, + 0x69, + 0x82, + 0x00, + 0xff, + ]) + .read(&[ + SET_PX_RGBA_BIN, + 0x01, + 0x69, + 0x42, + 0x42, + 0x69, + 0x82, + 0x00, + 0xff, + 0xa0, + ]) + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + let thingy2 = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(1, 0x4269, 0x6942, Color::RGB24(0x82, 0x00, 0xff)) + ); + assert_eq!( + thingy2.unwrap(), + Command::SetPixel(1, 0x4269, 0x6942, Color::RGBA32(0x82, 0x00, 0xff, 0xa0)) + ); + } +} diff --git a/src/grid.rs b/src/grid.rs index 93f8c29..5580f7f 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,5 +1,7 @@ use std::cell::SyncUnsafeCell; +use crate::{Coordinate, Response}; + pub trait Grid { fn get(&self, x: I, y: I) -> Option<&V>; fn get_unchecked(&self, x: I, y: I) -> &V; @@ -24,10 +26,14 @@ impl FlutGrid { cells: vec.into(), }; } + + pub fn get_size(&self) -> (usize, usize) { + return (self.size_x, self.size_y); + } } impl FlutGrid { - fn index(&self, x: u16, y: u16) -> Option { + fn index(&self, x: Coordinate, y: Coordinate) -> Option { let x = x as usize; let y = y as usize; if x >= self.size_x || y >= self.size_y { @@ -37,22 +43,22 @@ impl FlutGrid { } } -impl Grid for FlutGrid { - fn get(&self, x: u16, y: u16) -> Option<&T> { +impl Grid for FlutGrid { + fn get(&self, x: Coordinate, y: Coordinate) -> Option<&T> { match self.index(x, y) { None => None, Some(idx) => Some(unsafe { &(*self.cells.get())[idx] }), } } - fn set(&self, x: u16, y: u16, value: T) { + fn set(&self, x: Coordinate, y: Coordinate, value: T) { match self.index(x, y) { None => (), Some(idx) => unsafe { (*self.cells.get())[idx] = value }, } } - fn get_unchecked(&self, x: u16, y: u16) -> &T { + fn get_unchecked(&self, x: Coordinate, y: Coordinate) -> &T { let idx = y as usize * self.size_x + x as usize; return unsafe { &(*self.cells.get())[idx] }; } @@ -81,7 +87,7 @@ mod tests { #[tokio::test] async fn test_grid_set() { - let mut grid = FlutGrid::init(3, 3, 0); + let grid = FlutGrid::init(3, 3, 0); grid.set(1, 1, 255); grid.set(2, 1, 256); assert_eq!(grid.cells.into_inner(), vec![0, 0, 0, 0, 255, 256, 0, 0, 0]) @@ -89,7 +95,7 @@ mod tests { #[tokio::test] async fn test_grid_set_out_of_range() { - let mut grid = FlutGrid::init(3, 3, 0); + let grid = FlutGrid::init(3, 3, 0); grid.set(1, 1, 255); grid.set(3, 1, 256); assert_eq!(grid.cells.into_inner(), vec![0, 0, 0, 0, 255, 0, 0, 0, 0]) @@ -97,14 +103,14 @@ mod tests { #[tokio::test] async fn test_grid_get() { - let mut grid = FlutGrid::init(3, 3, 0); + let grid = FlutGrid::init(3, 3, 0); grid.set(1, 2, 222); assert_eq!(grid.get(1, 2), Some(&222)); } #[tokio::test] async fn test_grid_get_out_of_range() { - let mut grid = FlutGrid::init(3, 3, 0); + let grid = FlutGrid::init(3, 3, 0); grid.set(3, 1, 256); assert_eq!(grid.get(3, 1), None); assert_eq!(grid.get(1, 2), Some(&0)); @@ -117,7 +123,7 @@ mod tests { #[bench] fn bench_set(b: &mut Bencher) { - let mut grid = FlutGrid::init(800, 600, 0 as u32); + let grid = FlutGrid::init(800, 600, 0 as u32); b.iter(|| { let x = test::black_box(293); let y = test::black_box(222); diff --git a/src/main.rs b/src/main.rs index 8622342..0d93fa4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ #![feature(test)] #![feature(sync_unsafe_cell)] +mod binary_protocol; mod grid; +mod text_protocol; use std::{ cell::SyncUnsafeCell, @@ -11,38 +13,50 @@ use std::{ time::Duration, }; +use binary_protocol::BinaryParser; use grid::{FlutGrid, Grid}; +use text_protocol::TextParser; use tokio::{ - io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, + io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, net::TcpListener, }; extern crate test; -const HELP_TEXT: u8 = 72; -const SIZE_TEXT: u8 = 83; -const PX_TEXT: u8 = 80; -const SIZE_BIN: u8 = 115; -const HELP_BIN: u8 = 104; -const LOCK: u8 = 0; -const GET_PX_BIN: u8 = 32; -const SET_PX_RGB_BIN: u8 = 128; -const SET_PX_RGBA_BIN: u8 = 129; -const SET_PX_W_BIN: u8 = 130; - -const SET_PX_RGB_BIN_LENGTH: usize = 8; +const HELP_TEXT: &[u8] = b"Flurry is a pixelflut implementation, this means you can use commands to get and set pixels in the canvas +SIZE returns the size of the canvas +PX {x} {y} returns the color of the pixel at {x}, {y} +If you include a color in hex format you set a pixel instead +PX {x} {y} {RGB} sets the color of the pixel at {x}, {y} to the rgb value +PX {x} {y} {RGBA} blends the pixel at {x}, {y} with the rgb value weighted by the a +PX {x} {y} {W} sets the color of the pixel at {x}, {y} to the grayscale value +"; const GRID_LENGTH: usize = 1; static COUNTER: AtomicU64 = AtomicU64::new(0); -fn set_pixel_rgba(grids: &[grid::FlutGrid], canvas: u8, x: u16, y: u16, rgb: u32) { +type Canvas = u8; +type Coordinate = u16; + +fn set_pixel_rgba( + grids: &[grid::FlutGrid], + canvas: Canvas, + x: Coordinate, + y: Coordinate, + rgb: u32, +) { match grids.get(canvas as usize) { Some(grid) => grid.set(x, y, rgb), None => (), } } -fn get_pixel(grids: &[grid::FlutGrid], canvas: u8, x: u16, y: u16) -> Option<&u32> { +fn get_pixel( + grids: &[grid::FlutGrid], + canvas: Canvas, + x: Coordinate, + y: Coordinate, +) -> Option<&u32> { match grids.get(canvas as usize) { Some(grid) => return grid.get(x, y), None => return None, @@ -53,175 +67,52 @@ fn increment_counter() { COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } -async fn process_lock< - R: AsyncReadExt + std::marker::Unpin, - W: AsyncWriteExt + std::marker::Unpin, ->( - reader: &mut R, - _writer: &mut W, - grids: &[grid::FlutGrid; GRID_LENGTH], -) -> io::Result<()> { - let amount = reader.read_u16_le().await?; - let command = reader.read_u8().await?; - let lockmask = reader.read_u16().await?; - let mut buf = vec![0; lockmask.count_ones() as usize]; - let statics = reader.read_exact(&mut buf).await?; - - match command { - GET_PX_BIN => todo!("GET pixel lock"), - SET_PX_RGB_BIN => { - let per = SET_PX_RGB_BIN_LENGTH - statics; - let mut j = 0; - let mut a; - let static_buf: Vec> = (0..SET_PX_RGB_BIN_LENGTH) - .map(|i| match lockmask >> (15 - i) & 1 { - 1 => { - let b = Some(buf[j]); - - j += 1; - return b; - } - 0 => None, - k => panic!("WTF, how is {} not 0 or 1", k), - }) - .collect(); - let mut mod_buf: Vec = vec![0; per]; - for _ in 0..amount { - a = 0; - let _ = reader.read_exact(&mut mod_buf).await?; - let aa = static_buf - .iter() - .map(|x| *match x { - Some(val) => val, - None => { - let b = mod_buf[a]; - a += 1; - return b; - } - }) - .map(|z| z) - .collect::>(); - match grids.get(aa[0] as usize) { - Some(grid) => { - grid.set( - u16::from_le_bytes([aa[1], aa[2]]), - u16::from_le_bytes([aa[3], aa[4]]), - u32::from_be_bytes([aa[5], aa[6], aa[7], 0xff]), - ); - increment_counter() - } - None => (), - } - } - } - SET_PX_RGBA_BIN => todo!("Set rgba lock"), - SET_PX_W_BIN => todo!("set w lock"), - _ => { - eprintln!("not a cmd"); - return Err(Error::from(ErrorKind::InvalidInput)); - } - } - - return Ok(()); +#[derive(Debug, PartialEq)] +enum Color { + RGB24(u8, u8, u8), + RGBA32(u8, u8, u8, u8), + W8(u8), } -async fn process_msg< - R: AsyncReadExt + std::marker::Unpin, - W: AsyncWriteExt + std::marker::Unpin, ->( - reader: &mut R, - writer: &mut W, - grids: &[grid::FlutGrid; GRID_LENGTH], -) -> io::Result<()> { - let fst = reader.read_u8().await; - match fst { - Ok(i) => match i { - HELP_TEXT => todo!("HELP command check and message"), - SIZE_TEXT => todo!("SIZE command check and message"), - PX_TEXT => todo!("PX command handling"), - HELP_BIN => todo!("HELP command message"), - SIZE_BIN => todo!("SIZE command check and message"), - LOCK => process_lock(reader, writer, grids).await, - GET_PX_BIN => { - let canvas = reader.read_u8().await?; - let x = reader.read_u16_le().await?; - let y = reader.read_u16_le().await?; - match get_pixel(grids, canvas, x, y) { - None => (), - Some(color) => { - let towrite = &once(GET_PX_BIN) - .chain(once(canvas)) - .chain(x.to_le_bytes()) - .chain(y.to_le_bytes()) - .chain(color.to_be_bytes().into_iter().take(3)) - .collect::>(); - writer.write_all(towrite).await?; - } - } - return Ok(()); - } - SET_PX_RGB_BIN => set_px_rgb_bin(reader, grids).await, - SET_PX_RGBA_BIN => todo!("SET rgba"), - SET_PX_W_BIN => todo!("SET w"), - _ => { - eprintln!("received illegal command: {}", i); - return Err(Error::from(ErrorKind::InvalidInput)); - } - }, - Err(err) => { - eprintln!("{}", err); - return Err(err); - } - } +#[derive(Debug, PartialEq)] +enum Protocol { + Text, + Binary, } -async fn rgb_bin_read( - reader: &mut R, -) -> io::Result<(u8, u16, u16, u8, u8, u8)> { - let canvas = reader.read_u8().await?; - let x = reader.read_u16_le().await?; - let y = reader.read_u16_le().await?; - let r = reader.read_u8().await?; - let g = reader.read_u8().await?; - let b = reader.read_u8().await?; - return Ok((canvas, x, y, r, g, b)); +#[derive(Debug, PartialEq)] +enum Command { + Help, + Size(Canvas), + GetPixel(Canvas, Coordinate, Coordinate), + SetPixel(Canvas, Coordinate, Coordinate, Color), + ChangeCanvas(Canvas), + ChangeProtocol(Protocol), } -async fn set_px_rgb_bin( - reader: &mut R, - grids: &[grid::FlutGrid; GRID_LENGTH], -) -> io::Result<()> { - let (canvas, x, y, r, g, b) = rgb_bin_read(reader).await?; - let rgb = u32::from_be_bytes([r, g, b, 0xff]); - set_pixel_rgba(grids, canvas, x, y, rgb); - increment_counter(); - return Ok(()); +#[derive(Debug, PartialEq)] +enum Response { + Help, + Size(Coordinate, Coordinate), + GetPixel(Coordinate, Coordinate, [u8; 3]), } -async fn process_socket( - reader: R, - writer: W, - grids: &[grid::FlutGrid; GRID_LENGTH], -) -> io::Result<()> +trait Parser +where + R: std::marker::Unpin + tokio::io::AsyncBufRead, +{ + async fn parse(&self, reader: &mut R) -> io::Result; +} + +trait MEEHHEH { + fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()>; +} + +trait Responder where W: AsyncWriteExt + std::marker::Unpin, - R: AsyncReadExt + std::marker::Unpin, { - let mut reader = BufReader::new(reader); - let mut writer = BufWriter::new(writer); - loop { - match process_msg(&mut reader, &mut writer, grids).await { - Ok(()) => {} - Err(err) if err.kind() == ErrorKind::UnexpectedEof => { - let _ = writer.flush().await; - return Ok(()); - } - Err(e) => { - eprintln!("error with kind {}", e.kind()); - return Err(e); - } - } - } + async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()>; } async fn listen_handle() { @@ -233,6 +124,144 @@ async fn listen_handle() { } } +macro_rules! build_parser_type_enum { + ($($name:ident: $t:ty,)*) => { + + enum ParserTypes { + $($name($t),)* + } + + macro_rules! match_parser { + ($pident:ident: $parser:expr => $f:expr) => ( + match &mut $parser { + $( + ParserTypes::$name($pident) => $f, + )* + } + ) + } + }; +} + +build_parser_type_enum! { + TextParser: TextParser, + BinaryParser: BinaryParser, +} + +struct FlutClient +where + R: AsyncReadExt + std::marker::Unpin, + W: AsyncWriteExt + std::marker::Unpin, +{ + reader: BufReader, + writer: BufWriter, + grids: Arc<[FlutGrid]>, + parser: ParserTypes, +} + +impl FlutClient +where + R: AsyncReadExt + std::marker::Unpin, + W: AsyncWriteExt + std::marker::Unpin, +{ + async fn help_command(&mut self) -> io::Result<()> { + println!("HELP wanted"); + match_parser!(parser: self.parser => parser.unparse(Response::Help, &mut self.writer).await?); + + self.writer.flush().await?; + return Ok(()); + } + + async fn size_command(&mut self, canvas: Canvas) -> io::Result<()> { + let (x, y) = self.grids[canvas as usize].get_size(); + match_parser!(parser: self.parser => parser.unparse(Response::Size(x as Coordinate, y as Coordinate), &mut self.writer).await?); + + self.writer.flush().await?; + return Ok(()); + } + + async fn get_pixel_command( + &mut self, + canvas: Canvas, + x: Coordinate, + y: Coordinate, + ) -> io::Result<()> { + let color = match get_pixel(&self.grids, canvas, x, y) { + None => return Err(Error::from(ErrorKind::InvalidInput)), + Some(color) => color.to_be_bytes(), + }; + match_parser!(parser: self.parser => parser.unparse(Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await); + + self.writer.flush().await?; + return Ok(()); + } + + async fn set_pixel_command( + &mut self, + canvas: Canvas, + x: Coordinate, + y: Coordinate, + color: Color, + ) -> io::Result<()> { + let c: u32 = match color { + Color::RGB24(r, g, b) => u32::from_be_bytes([r, g, b, 0xff]), + Color::RGBA32(r, g, b, a) => u32::from_be_bytes([r, g, b, a]), + Color::W8(w) => u32::from_be_bytes([w, w, w, 0xff]), + }; + println!("setting pixel {},{} to {}", x, y, c); + set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c); + return Ok(()); + } + + async fn change_canvas_command(&mut self, canvas: Canvas) -> io::Result<()> { + match_parser!(parser: self.parser => parser.change_canvas(canvas)) + } + + async fn change_protocol(&mut self, protocol: Protocol) -> io::Result<()> { + match protocol { + Protocol::Text => self.parser = ParserTypes::TextParser(TextParser::new(0)), + Protocol::Binary => self.parser = ParserTypes::BinaryParser(BinaryParser::new()), + } + return Ok(()); + } + + pub fn new(reader: R, writer: W, grids: Arc<[grid::FlutGrid]>) -> FlutClient { + return FlutClient { + reader: BufReader::new(reader), + writer: BufWriter::new(writer), + grids, + parser: ParserTypes::TextParser(TextParser::new(0)), + }; + } + + pub async fn process_socket(&mut self) -> io::Result<()> { + loop { + let parsed = match &self.parser { + ParserTypes::TextParser(parser) => parser.parse(&mut self.reader).await, + ParserTypes::BinaryParser(parser) => parser.parse(&mut self.reader).await, + }; + + match parsed { + Ok(Command::Help) => self.help_command().await?, + Ok(Command::Size(canvas)) => self.size_command(canvas).await?, + Ok(Command::GetPixel(canvas, x, y)) => self.get_pixel_command(canvas, x, y).await?, + Ok(Command::SetPixel(canvas, x, y, color)) => { + self.set_pixel_command(canvas, x, y, color).await? + } + Ok(Command::ChangeCanvas(canvas)) => self.change_canvas_command(canvas).await?, + Ok(Command::ChangeProtocol(protocol)) => self.change_protocol(protocol).await?, + + Err(err) if err.kind() == ErrorKind::UnexpectedEof => { + return Ok(()); + } + Err(e) => { + return Err(e); + } + } + } + } +} + #[tokio::main] async fn main() -> io::Result<()> { println!("created grids"); @@ -242,9 +271,6 @@ async fn main() -> io::Result<()> { let flut_listener = TcpListener::bind("0.0.0.0:7791").await?; println!("bound flut listener"); - let web_listener = TcpListener::bind("0.0.0.0:7792").await?; - - println!("bound web listener"); let _ = tokio::spawn(listen_handle()); loop { @@ -252,7 +278,9 @@ async fn main() -> io::Result<()> { let grids = grids.clone(); let _ = tokio::spawn(async move { let (reader, writer) = socket.split(); - match process_socket(reader, writer, &grids).await { + let mut connection = FlutClient::new(reader, writer, grids); + let resp = connection.process_socket().await; + match resp { Ok(()) => return Ok(()), Err(err) => return Err(err), } @@ -265,64 +293,4 @@ mod tests { use super::*; use crate::grid::FlutGrid; use tokio_test::assert_ok; - - #[tokio::test] - async fn test_set_rgb_bin() { - let mut grids = [FlutGrid::init(800, 600, 0xFF00FF)]; - let reader = tokio_test::io::Builder::new() - .read(&[SET_PX_RGB_BIN, 0, 16, 0, 32, 0, 0, 0, 0]) - .read(&[SET_PX_RGB_BIN, 0, 16, 0, 33, 0, 2, 3, 5]) - .build(); - let writer = tokio_test::io::Builder::new().build(); - assert_ok!(process_socket(reader, writer, &mut grids).await); - assert_eq!(grids[0].get(16, 32), Some(&0x000000ff)); - assert_eq!(grids[0].get(16, 33), Some(&0x020305ff)); - } - - #[tokio::test] - async fn test_set_rgb_lock() { - let mut grids = [FlutGrid::init(800, 600, 0xFF00FF)]; - let reader = tokio_test::io::Builder::new() - .read(&[ - LOCK, - 3, - 0, - SET_PX_RGB_BIN, - 0b1011_1110, - 0b0000_0000, - 0, - 0, - 0, - 0, - 2, - 3, - ]) - .read(&[100, 4]) - .read(&[101, 5]) - .read(&[102, 6]) - .build(); - let writer = tokio_test::io::Builder::new().build(); - assert_ok!(process_socket(reader, writer, &mut grids).await); - - assert_eq!(grids[0].get(100, 0), Some(&0x020304ff)); - assert_eq!(grids[0].get(101, 0), Some(&0x020305ff)); - assert_eq!(grids[0].get(102, 0), Some(&0x020306ff)); - } - - #[tokio::test] - async fn test_get_rgb_bin() { - let mut grids = [FlutGrid::init(800, 600, 0xFF00F0FF)]; - let reader = tokio_test::io::Builder::new() - .read(&[GET_PX_BIN, 0, 15, 0, 21, 0]) - .read(&[GET_PX_BIN, 0, 16, 0, 21, 0]) - .read(&[GET_PX_BIN, 0, 17, 0, 21, 0]) - .build(); - let writer = tokio_test::io::Builder::new() - .write(&[GET_PX_BIN, 0, 15, 0, 21, 0, 0xff, 0x00, 0xf0]) - .write(&[GET_PX_BIN, 0, 16, 0, 21, 0, 0xff, 0x00, 0xf0]) - .write(&[GET_PX_BIN, 0, 17, 0, 21, 0, 0xff, 0x00, 0xf0]) - .build(); - assert_ok!(process_socket(reader, writer, &mut grids).await); - assert_eq!(grids[0].get(15, 21), Some(&0xff00f0ff)); - } } diff --git a/src/text_protocol.rs b/src/text_protocol.rs new file mode 100644 index 0000000..d0f3a55 --- /dev/null +++ b/src/text_protocol.rs @@ -0,0 +1,234 @@ +use std::io::{self, Error, ErrorKind}; + +use atoi_radix10::parse_from_str; +use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncWriteExt}; + +use crate::{ + Canvas, Color, Command, Coordinate, Parser, Protocol, Responder, Response, GRID_LENGTH, + HELP_TEXT, MEEHHEH, +}; + +pub struct TextParser { + canvas: Canvas, +} + +fn parse_coordinate(string: &str) -> io::Result { + match parse_from_str(string) { + Ok(coord) => return Ok(coord), + Err(_) => return Err(Error::from(ErrorKind::InvalidInput)), + } +} + +fn parse_color(color: &str) -> io::Result { + if let Ok(bytes) = hex::decode(color) { + match bytes.len() { + 1 => return Ok(Color::W8(bytes[0])), + 3 => return Ok(Color::RGB24(bytes[0], bytes[1], bytes[2])), + 4 => return Ok(Color::RGBA32(bytes[0], bytes[1], bytes[2], bytes[3])), + _ => return Err(Error::from(ErrorKind::InvalidInput)), + } + } + return Err(Error::from(ErrorKind::InvalidInput)); +} + +impl TextParser { + pub fn new(canvas: Canvas) -> TextParser { + return TextParser { canvas }; + } + + fn parse_pixel(&self, line: &str) -> io::Result { + let mut split = line.trim().split(' '); + + let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + let x_coordinate = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + let y_coordinate = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + if let (Ok(horizontal), Ok(vertical)) = (x_coordinate.parse(), y_coordinate.parse()) { + match split.next() { + None => return Ok(Command::GetPixel(self.canvas, horizontal, vertical)), + Some(color) => match parse_color(color) { + Ok(color) => { + return Ok(Command::SetPixel(self.canvas, horizontal, vertical, color)) + } + Err(err) => return Err(err), + }, + } + } else { + return Err(Error::from(ErrorKind::InvalidInput)); + } + } + fn parse_canvas(&self, line: &str) -> io::Result { + let mut split = line.trim().split(' '); + + let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + let canvas = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + println!("{:?}", canvas); + if let Ok(canvas) = canvas.parse() { + return Ok(Command::ChangeCanvas(canvas)); + } else { + return Err(Error::from(ErrorKind::InvalidInput)); + } + } + fn parse_protocol(&self, line: &str) -> io::Result { + let mut split = line.trim().split(' '); + + let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + let protocol = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; + match protocol { + "binary" => return Ok(Command::ChangeProtocol(Protocol::Binary)), + "text" => return Ok(Command::ChangeProtocol(Protocol::Text)), + _ => return Err(Error::from(ErrorKind::InvalidInput)), + } + } +} + +impl Parser for TextParser { + async fn parse(&self, reader: &mut R) -> io::Result { + let mut line = "".to_string(); + if let Ok(_) = reader.read_line(&mut line).await { + println!("{:?}", line); + if line.starts_with("HELP") { + return Ok(Command::Help); + } else if line.starts_with("SIZE") { + return Ok(Command::Size(self.canvas)); + } else if line.starts_with("PX ") { + return self.parse_pixel(&line); + } else if line.starts_with("CANVAS ") { + return self.parse_canvas(&line); + } else if line.starts_with("PROTOCOL ") { + return self.parse_protocol(&line); + } + } + return Err(Error::from(ErrorKind::InvalidInput)); + } +} + +impl MEEHHEH for TextParser { + fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()> { + if (canvas as usize) < GRID_LENGTH { + self.canvas = canvas; + return Ok(()); + } else { + return Err(Error::from(ErrorKind::InvalidInput)); + } + } +} + +impl Responder for TextParser { + async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()> { + match response { + Response::Help => writer.write_all(HELP_TEXT).await, + Response::Size(x, y) => { + writer + .write_all(format!("SIZE {} {}\n", x, y).as_bytes()) + .await + } + Response::GetPixel(x, y, color) => { + writer + .write_all(format!("PX {} {} {}\n", x, y, hex::encode_upper(color)).as_bytes()) + .await + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::grid::FlutGrid; + use tokio::io::BufReader; + use tokio_test::assert_ok; + + #[tokio::test] + async fn test_help_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new().read(b"HELP\n").build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::Help) + } + + #[tokio::test] + async fn test_size_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new().read(b"SIZE\n").build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::Size(0)) + } + + #[tokio::test] + async fn test_canvas_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new().read(b"CANVAS 12\n").build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::ChangeCanvas(12)) + } + + #[tokio::test] + async fn test_px_set_w_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new() + .read(b"PX 28283 29991 81\n") + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(0, 28283, 29991, Color::W8(0x81)) + ) + } + + #[tokio::test] + async fn test_px_set_rgb_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new() + .read(b"PX 28283 29991 8800ff\n") + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(0, 28283, 29991, Color::RGB24(0x88, 0x00, 0xff)) + ) + } + + #[tokio::test] + async fn test_px_set_rgba_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new() + .read(b"PX 28283 29991 8800ff28\n") + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!( + thingy.unwrap(), + Command::SetPixel(0, 28283, 29991, Color::RGBA32(0x88, 0x00, 0xff, 0x28)) + ) + } + + #[tokio::test] + async fn test_px_get_parse() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new() + .read(b"PX 28283 29991\n") + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::GetPixel(0, 28283, 29991)) + } + + #[tokio::test] + async fn parse_multiple() { + let parser = TextParser::new(0); + let reader = tokio_test::io::Builder::new() + .read(b"CANVAS 12\n") + .read(b"SIZE\n") + .build(); + let mut bufreader = BufReader::new(reader); + let thingy = parser.parse(&mut bufreader).await; + let thingy2 = parser.parse(&mut bufreader).await; + assert_eq!(thingy.unwrap(), Command::ChangeCanvas(12)); + assert_eq!(thingy2.unwrap(), Command::Size(0)); + } +} From b47b2967bdf2ce06d12a706a8d5e04e9379360e5 Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Fri, 4 Oct 2024 19:34:00 +0200 Subject: [PATCH 3/6] fix: pixel counter workies now --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 0d93fa4..47f30ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -210,6 +210,7 @@ where }; println!("setting pixel {},{} to {}", x, y, c); set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c); + increment_counter(); return Ok(()); } From 063e23d6de81054d8ff98b82dbca74989ae795e2 Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Fri, 4 Oct 2024 19:52:21 +0200 Subject: [PATCH 4/6] fix: remove unessecary print --- Cargo.toml | 3 +++ src/main.rs | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 82031fe..dadd75d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,9 @@ tokio-test = "*" [profile.dev] opt-level = 1 +[profile.dev.package."*"] +opt-level = 3 + [profile.release] lto = "fat" codegen-units = 1 diff --git a/src/main.rs b/src/main.rs index 47f30ac..97f69a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -190,7 +190,7 @@ where None => return Err(Error::from(ErrorKind::InvalidInput)), Some(color) => color.to_be_bytes(), }; - match_parser!(parser: self.parser => parser.unparse(Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await); + match_parser!(parser: self.parser => parser.unparse(Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await?); self.writer.flush().await?; return Ok(()); @@ -208,7 +208,6 @@ where Color::RGBA32(r, g, b, a) => u32::from_be_bytes([r, g, b, a]), Color::W8(w) => u32::from_be_bytes([w, w, w, 0xff]), }; - println!("setting pixel {},{} to {}", x, y, c); set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c); increment_counter(); return Ok(()); From 6c0260e42f5f6c3a99d8306cddd8eb795b4792bb Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Sat, 5 Oct 2024 00:29:54 +0200 Subject: [PATCH 5/6] fix: start binary responses --- src/binary_protocol.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/binary_protocol.rs b/src/binary_protocol.rs index 78c369a..9f18a22 100644 --- a/src/binary_protocol.rs +++ b/src/binary_protocol.rs @@ -88,7 +88,23 @@ impl MEEHHEH for BinaryParser { impl Responder for BinaryParser { async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()> { - todo!() + let help_text = format!( + " +You found the binary protocol help text +you can get this by sending ({:02X}) to the server +To get the size of a canvas, send ({:02X}) (u8 canvas) to the server +To set a pixel using RGB, use ({:02X}) (u8 canvas) (x as u16_le) (y as u16_le) (u8 r) (u8 g) (u8 b) +", + HELP_BIN, SIZE_BIN, SET_PX_RGB_BIN + ); + match response { + Response::Help => writer.write_all(help_text.as_bytes()).await, + Response::Size(x, y) => { + writer.write_u16_le(x).await?; + writer.write_u16_le(y).await + } + Response::GetPixel(_, _, c) => writer.write_all(&c).await, + } } } From 1179ee4ea16c5df77139a001041ac45fa1a7f18f Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Sat, 5 Oct 2024 09:46:08 +0200 Subject: [PATCH 6/6] fix: remove spammy prints --- src/text_protocol.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/text_protocol.rs b/src/text_protocol.rs index d0f3a55..2625395 100644 --- a/src/text_protocol.rs +++ b/src/text_protocol.rs @@ -61,7 +61,6 @@ impl TextParser { let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let canvas = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; - println!("{:?}", canvas); if let Ok(canvas) = canvas.parse() { return Ok(Command::ChangeCanvas(canvas)); } else { @@ -85,7 +84,6 @@ impl Parser for TextP async fn parse(&self, reader: &mut R) -> io::Result { let mut line = "".to_string(); if let Ok(_) = reader.read_line(&mut line).await { - println!("{:?}", line); if line.starts_with("HELP") { return Ok(Command::Help); } else if line.starts_with("SIZE") {