diff --git a/Cargo.lock b/Cargo.lock index 72090f8..c61a504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1256,9 +1256,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -1586,6 +1586,7 @@ dependencies = [ "chrono", "futures", "futures-core", + "memchr", "planetwars-rules", "rand 0.6.5", "serde", diff --git a/planetwars-matchrunner/Cargo.toml b/planetwars-matchrunner/Cargo.toml index 10d1c99..4a0e05e 100644 --- a/planetwars-matchrunner/Cargo.toml +++ b/planetwars-matchrunner/Cargo.toml @@ -18,6 +18,7 @@ chrono = { version = "0.4", features = ["serde"] } bollard = { git = "https://github.com/fussybeaver/bollard", rev = "c5d87a4934c70a04f9c649fedb241dbd4943c927" } bytes = "1.1" async-trait = "0.1" +memchr = "2.5.0" [dev-dependencies] tempfile = "3" \ No newline at end of file diff --git a/planetwars-matchrunner/src/docker_runner.rs b/planetwars-matchrunner/src/docker_runner.rs index a4415ca..04d7ecb 100644 --- a/planetwars-matchrunner/src/docker_runner.rs +++ b/planetwars-matchrunner/src/docker_runner.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex}; use async_trait::async_trait; use bollard::container::{self, AttachContainerOptions, AttachContainerResults, LogOutput}; use bollard::Docker; -use bytes::Bytes; +use bytes::{Bytes, BytesMut}; use futures::{Stream, StreamExt}; use tokio::io::{AsyncWrite, AsyncWriteExt}; use tokio::sync::mpsc; @@ -168,6 +168,8 @@ fn run_docker_bot( event_bus, match_logger, rx, + + stdout_buf: BytesMut::new(), }; let join_handle = tokio::spawn(bot_runner.run()); @@ -198,6 +200,9 @@ pub struct DockerBotRunner { rx: mpsc::UnboundedReceiver, match_logger: MatchLogger, player_id: u32, + + stdout_buf: BytesMut, + // stderr_buf: BytesMut, } impl DockerBotRunner { @@ -243,8 +248,11 @@ impl DockerBotRunner { let log_output = item.expect("failed to get log output"); match log_output { LogOutput::StdOut { message } => { - // TODO: this is not correct (buffering and such) - return Ok(message); + self.stdout_buf.extend_from_slice(&message); + if let Some(split_idx) = memchr::memchr(b'\n', &self.stdout_buf) { + let line = self.stdout_buf.split_to(split_idx+1); + return Ok(line.freeze()) + } } LogOutput::StdErr { mut message } => { // TODO diff --git a/planetwars-matchrunner/tests/test_matchrunner.rs b/planetwars-matchrunner/tests/test_matchrunner.rs index 43afd85..c2b324c 100644 --- a/planetwars-matchrunner/tests/test_matchrunner.rs +++ b/planetwars-matchrunner/tests/test_matchrunner.rs @@ -148,3 +148,20 @@ async fn docker_runner_crash() { }) .await; } + +#[tokio::test] +async fn test_long_line() { + let bot_spec = simple_python_docker_bot_spec("./bots", "echo_bot.py"); + let len = 10 * 2_usize.pow(20); // 10 megabytes - hopefully large enough to cause buffering + let buf = std::iter::repeat(b'a').take(len).collect::>(); + with_bot_match_ctx(bot_spec, |ctx| { + async move { + let resp = ctx.request(1, buf, Duration::from_millis(200)).await; + + let resp_bytes = resp.expect("unexpected error"); + assert_eq!(resp_bytes.len(), len + 1); + } + .boxed() + }) + .await; +}