diff --git a/Cargo.lock b/Cargo.lock index 3e1e4be..80d66e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,14 @@ name = "adler32" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "aho-corasick" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.10.2" @@ -144,6 +152,11 @@ name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.34" @@ -154,6 +167,14 @@ name = "lzw" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.35" @@ -200,6 +221,7 @@ dependencies = [ "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -255,6 +277,23 @@ dependencies = [ "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scoped_threadpool" version = "0.1.8" @@ -288,16 +327,43 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.2" @@ -319,6 +385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" +"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" @@ -337,8 +404,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum inflate 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10ec05638adf7c5c788bc0cfa608cd479a13572beda20feb4898fe1d85d2c64b" "checksum jpeg-decoder 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2805ccb10ffe4d10e06ef68a158ff94c255211ecbae848fbde2146b098f93ce7" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe" @@ -350,13 +419,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" "checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" +"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" "checksum scoped_threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4ea459fe3ceff01e09534847c49860891d3ff1c12b4eb7731b67f2778fb60190" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "890b38836c01d72fdb636d15c9cfc52ec7fd783b330abc93cd1686f4308dfccc" "checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc" "checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668" diff --git a/Cargo.toml b/Cargo.toml index e251118..9b6f62a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ authors = ["Tim Visée "] bufstream = "0.1" clap = "2.29" image = "0.18" +regex = "0.2" diff --git a/TODO.md b/TODO.md index 4386826..030f8ae 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,10 @@ # TODO - Don't draw pixels outside screen. +- Add alpha support. - Do not draw invisible (alpha) pixels. - Read size from screen. - Instantly update images in painter threads, not just when the stopped drawing. - Process all images at start. - Combine many pixel messages to improve performance. +- Create a small listening server, to benchmark throughput. diff --git a/src/pix/canvas.rs b/src/pix/canvas.rs index 9e7cf03..2268fb7 100644 --- a/src/pix/canvas.rs +++ b/src/pix/canvas.rs @@ -1,5 +1,3 @@ -use std::io::Error; -use std::net::TcpStream; use std::sync::mpsc; use std::sync::mpsc::{Sender, Receiver}; use std::thread; @@ -83,19 +81,16 @@ impl Canvas { // Create the painter thread let thread = thread::spawn(move || { - // Create a new stream - let stream = create_stream(host) - .expect("failed to open stream to pixelflut"); - // Create a new client - let client = Client::new(stream); + let client = Client::connect(host) + .expect("failed to open stream to pixelflut"); // Create a painter let mut painter = Painter::new( client, area, offset, - None + None, ); // Do some work @@ -129,12 +124,3 @@ impl Canvas { } } } - - - -/// Create a stream to talk to the pixelflut server. -/// -/// The stream is returned as result. -fn create_stream(host: String) -> Result { - TcpStream::connect(host) -} diff --git a/src/pix/client.rs b/src/pix/client.rs index ae67811..e53e506 100644 --- a/src/pix/client.rs +++ b/src/pix/client.rs @@ -1,13 +1,24 @@ extern crate bufstream; +extern crate regex; -use std::io::Error; +use std::io::{Error, ErrorKind}; use std::io::prelude::*; use std::net::TcpStream; use self::bufstream::BufStream; +use self::regex::Regex; use color::Color; +// The default buffer size for reading the client stream. +// - Big enough so we don't have to expand +// - Small enough to not take up to much memory +const CMD_READ_BUFFER_SIZE: usize = 32; + +// The response format of the screen size from a pixelflut server. +const PIX_SERVER_SIZE_REGEX: &'static str = + r"^(?i)\s*SIZE\s*([[:digit:]])+\s*([[:digit:]])+\s*$"; + /// A pixelflut client. @@ -29,6 +40,16 @@ impl Client { } } + /// Create a new client instane from the given host, and connect to it. + pub fn connect(host: String) -> Result { + // Create a new stream, and instantiate the client + Ok( + Client::new( + create_stream(host)? + ) + ) + } + /// Write a pixel to the given stream. pub fn write_pixel(&mut self, x: u32, y: u32, color: &Color) -> Result<(), Error> { // Write the command to set a pixel @@ -37,16 +58,27 @@ impl Client { ) } - // /// Read the size of the screen. - // fn read_screen_size(&mut self) { - // // Read the screen size - // let size = self - // .write_read_command("SIZE".into()) - // .expect("Failed to read screen size"); - // - // // TODO: Remove this after debugging - // println!("Read size: {}", size); - // } + /// Read the size of the screen. + pub fn read_screen_size(&mut self) -> Result<(u32, u32), Error> { + // Read the screen size + let data = self + .write_read_command("SIZE".into()) + .expect("Failed to read screen size"); + + // Build a regex to parse the screen size + let re = Regex::new(PIX_SERVER_SIZE_REGEX).unwrap(); + + // Find captures in the data, return the result + match re.captures(&data) { + Some(matches) => Ok(( + matches[1].parse::().expect("Failed to parse screen width, received malformed data"), + matches[2].parse::().expect("Failed to parse screen height, received malformed data"), + )), + None => Err( + Error::new(ErrorKind::Other, "Failed to parse screen size, received malformed data") + ), + } + } /// Write the given command to the given stream. fn write_command(&mut self, cmd: String) -> Result<(), Error> { @@ -58,18 +90,29 @@ impl Client { Ok(()) } - // /// Write the given command to the given stream, and read the output. - // fn write_read_command(&mut self, cmd: String) -> Result { - // // Write the command - // self.write_command(cmd); - // - // // Read the output - // let mut buffer = String::with_capacity(CMD_READ_BUFFER_SIZE); - // println!("Reading line..."); - // self.stream.read_line(&mut buffer)?; - // println!("Done reading"); - // - // // Return the read string - // Ok(buffer) - // } + /// Write the given command to the given stream, and read the output. + fn write_read_command(&mut self, cmd: String) -> Result { + // Write the command + self.write_command(cmd); + + // Flush the pipe, ensure the command is actually sent + self.stream.flush()?; + + // Read the output + // TODO: this operation may get stuck (?) if nothing is received from the server + let mut buffer = String::with_capacity(CMD_READ_BUFFER_SIZE); + self.stream.read_line(&mut buffer)?; + + // Return the read string + Ok(buffer) + } +} + + + +/// Create a stream to talk to the pixelflut server. +/// +/// The stream is returned as result. +fn create_stream(host: String) -> Result { + TcpStream::connect(host) }