diff --git a/Cargo.lock b/Cargo.lock index 80aef66..293c078 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -98,6 +104,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossterm" version = "0.27.0" @@ -145,6 +160,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -241,6 +267,17 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -272,6 +309,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "0.8.11" @@ -343,6 +389,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "postfix-log-viewer" version = "0.1.0" @@ -350,6 +402,7 @@ dependencies = [ "anyhow", "chrono", "crossterm", + "flate2", "lazy_static", "log", "ratatui", @@ -615,6 +668,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index fc90de7..bb40b5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ anyhow = "1.0.71" log = "0.4.17" simplelog = "0.12.1" lazy_static = "1.4.0" +flate2 = { version = "1.0.26", features = ["zlib"] } [features] default = [] diff --git a/src/main.rs b/src/main.rs index f55f285..edeaa0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,9 @@ use crossterm::{ terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use ratatui::{backend::CrosstermBackend, Terminal}; -use std::{env, fs, io, time::Duration}; +use std::{env, fs, io, io::Read, path::Path, time::Duration}; use ui::App; +use anyhow::anyhow; fn run_app( terminal: &mut Terminal>, @@ -35,19 +36,44 @@ fn run_app( } } +fn read_file_content(file_path: &str) -> anyhow::Result { + let path = Path::new(file_path); + let file = fs::File::open(path) + .with_context(|| format!("Failed to open file: {}", file_path))?; + + // Check if the file is gzipped by its extension + if let Some(ext) = path.extension().and_then(|s| s.to_str()) { + if ext.eq_ignore_ascii_case("gz") || ext.eq_ignore_ascii_case("gzip") { + let mut decoder = flate2::read::GzDecoder::new(file); + let mut content = String::new(); + decoder.read_to_string(&mut content) + .with_context(|| format!("Failed to decompress gzip file: {}", file_path))?; + return Ok(content); + } + } + + // If not gzipped or no extension, read as plain text + let mut content = String::new(); + let mut file = file; + file.read_to_string(&mut content) + .with_context(|| format!("Failed to read file: {}", file_path))?; + + Ok(content) +} + fn main() -> Result<()> { // Parse command line arguments let args: Vec = env::args().collect(); if args.len() < 2 { - eprintln!("Usage: {} [additional-files...]", args[0]); + eprintln!("Usage: {} [additional-files...]", args[0]); std::process::exit(1); } // Process all log files let mut all_sessions = Vec::new(); for filename in &args[1..] { - // Read and parse the log file with its path for better timestamp handling - let log_content = fs::read_to_string(filename) + // Read file content (handles both plain and gzipped files) + let log_content = read_file_content(filename) .with_context(|| format!("Failed to read file: {}", filename))?; // Parse the log file with the file path for better timestamp handling