diff --git a/Cargo.lock b/Cargo.lock index 0fd78fe..4065da3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,7 @@ dependencies = [ "futures-io", "memchr", "pin-project-lite", + "tokio", "xz2", "zstd", "zstd-safe", @@ -1040,9 +1041,9 @@ checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" dependencies = [ "fastrand", "futures-core", @@ -4285,6 +4286,7 @@ dependencies = [ name = "wurstminebot" version = "0.1.0" dependencies = [ + "async-compression", "async_zip", "chase", "chrono", diff --git a/crate/wurstminebot/Cargo.toml b/crate/wurstminebot/Cargo.toml index 75c15ce..23bad00 100644 --- a/crate/wurstminebot/Cargo.toml +++ b/crate/wurstminebot/Cargo.toml @@ -26,6 +26,10 @@ serde_json = "1" #TODO make sure enabling the arbitrary_precision feature doesn' serenity = "0.12" thiserror = "1" +[dependencies.async-compression] +version = "0.4" +features = ["gzip", "tokio"] + [dependencies.async_zip] version = "0.0.16" features = ["full"] diff --git a/crate/wurstminebot/src/log.rs b/crate/wurstminebot/src/log.rs index 92b7fa7..af0ca75 100644 --- a/crate/wurstminebot/src/log.rs +++ b/crate/wurstminebot/src/log.rs @@ -39,6 +39,7 @@ use { io::{ self, AsyncBufReadExt as _, + AsyncReadExt as _, BufReader, }, sync::RwLock, @@ -55,7 +56,10 @@ use { File, }, io_error_from_reqwest, - traits::ReqwestResponseExt as _, + traits::{ + IoResultExt as _, + ReqwestResponseExt as _, + }, }, }; @@ -285,14 +289,32 @@ impl Line { } } -fn history(http_client: reqwest::Client, world: &World) -> impl Stream> { - stream::once(fs::read_to_string(world.dir().join("logs/latest.log"))) - .err_into::() - .and_then(move |contents| { +async fn history_paths(world: &World) -> Result, Error> { + let mut logs = fs::read_dir(world.dir().join("logs")).map_ok(|entry| entry.path()).try_collect::>().await?; + logs.sort_unstable_by(|a, b| b.cmp(a)); + logs.reserve_exact(1); + logs.push(world.dir().join("server.log")); + Ok(logs) +} + +fn history(http_client: reqwest::Client, world: &World) -> impl Stream> + '_ { + stream::once(history_paths(world)) + .and_then(move |paths| { let http_client = http_client.clone(); future::ok( - stream::iter(contents.lines().rev().map(|line| line.to_owned()).collect_vec()) - .then(move |line| { + stream::iter(paths) + .then(|path| async move { + if path.extension().is_some_and(|ext| ext == "gz") { + let mut buf = String::default(); + async_compression::tokio::bufread::GzipDecoder::new(BufReader::new(File::open(&path).await?)).read_to_string(&mut buf).await.at(path)?; + Ok(buf) + } else { + fs::read_to_string(path).await + } + }) + .and_then(|contents| future::ok(stream::iter(contents.lines().rev().map(|line| line.to_owned()).collect_vec()).map(Ok))) + .try_flatten() + .and_then(move |line| { let http_client = http_client.clone(); async move { Line::parse(Arc::new(RwLock::new(FollowerState { // reset state for each line since we're going backwards