diff options
-rw-r--r-- | Cargo.lock | 153 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | README.md | 39 | ||||
-rw-r--r-- | ezau-sample.toml | 11 | ||||
-rw-r--r-- | src/config.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 64 |
6 files changed, 48 insertions, 224 deletions
@@ -304,7 +304,7 @@ dependencies = [ "arrayvec", "cc", "cfg-if 1.0.0", - "constant_time_eq 0.3.0", + "constant_time_eq", ] [[package]] @@ -408,10 +408,6 @@ name = "cc" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" -dependencies = [ - "jobserver", - "libc", -] [[package]] name = "cfg-if" @@ -549,12 +545,6 @@ checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" [[package]] name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" @@ -759,15 +749,6 @@ dependencies = [ ] [[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -932,7 +913,7 @@ dependencies = [ "num-derive", "num-traits", "thiserror", - "zip 0.5.13", + "zip", ] [[package]] @@ -983,7 +964,6 @@ dependencies = [ "tokio", "toml 0.5.11", "url", - "zip 0.6.6", ] [[package]] @@ -1656,15 +1636,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "jobserver" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" -dependencies = [ - "libc", -] - -[[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1962,7 +1933,7 @@ dependencies = [ "hmac", "itertools 0.12.1", "matrix-sdk-common", - "pbkdf2 0.12.2", + "pbkdf2", "rand 0.8.5", "rmp-serde", "ruma", @@ -2040,7 +2011,7 @@ dependencies = [ "displaydoc", "getrandom 0.2.15", "hmac", - "pbkdf2 0.12.2", + "pbkdf2", "rand 0.8.5", "rmp-serde", "serde", @@ -2198,12 +2169,6 @@ dependencies = [ ] [[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] name = "num-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2323,17 +2288,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2341,18 +2295,6 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" @@ -2438,12 +2380,6 @@ dependencies = [ ] [[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3215,17 +3151,6 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3431,25 +3356,6 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] name = "tinyvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4303,54 +4209,5 @@ dependencies = [ "crc32fast", "flate2", "thiserror", - "time 0.1.45", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time 0.3.36", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.12+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" -dependencies = [ - "cc", - "pkg-config", + "time", ] @@ -23,7 +23,6 @@ serde = { version = "1.0.136", features = ["derive"] } chrono = "0.4.19" notify = "4.0.17" regex = "1.5.5" -zip = "0.6.1" toml = "0.5.8" itertools = "0.10.3" # Optional features for IM integration @@ -1,17 +1,19 @@ -EVTC Zipper And Uploader -======================== +EVTC (Zipper And) Uploader +========================== ![MIT license](https://img.shields.io/badge/license-MIT-green) ![Rustlang](https://img.shields.io/badge/language-Rust-green) -`ezau` is a tool which watches a directory for new EVTC log files and can zip them, upload them to [dps.report](https://dps.report) and post a message to a Discord channel. +`ezau` is a tool which watches a directory for new EVTC log files, uploads them to [dps.report](https://dps.report) and posts the link to a Discord or Matrix channel. Motivation ---------- -EVTC logs generated by arcpds can get quite big, so having them zipped is a huge space saving (80-90%). -Though while arcdps itself works fine on Linux/Wine, the built-in zip functionality relies on PowerShell and is not available outside of Windows 10. -As such, `ezau` can be used to automatically zip newly created log files in order to save disk space. -In addition to that, `ezau` can also optionally upload new logs to dps.report, and post a link to the uploaded report to a Discord channel. +The zipping functionality of arcdps used to be limited to Windows. +As a result, Linux users ended up with huge unzipped evtc log files. +`ezau` zipped those for you, and optionally also uploaded them to dps.report. + +However, with new versions of arcdps, the logs are always zipped and this functionality works even on Linux. +As such, `ezau` is simply a log uploader now (but `eu` is even worse of a name than `ezau`). `ezau` was inspired by [`evtc-watch`](https://gitlab.com/networkjanitor/evtc-watch/-/blob/master/evtc-watch) from Xyoz, with the difference that the file watching logic is included in the Rust part. This makes it cross-platform and fixes some bugs that were present in the `inotifywait` version. @@ -57,9 +59,17 @@ A full example configuration is provided here or alternatively as `ezau-sample.t ```toml # Whether logs should be uploaded. -# If this is false, ezau will only zip new logs and do no further processing. +# For legacy reasons, uploading can be disabled, but you probably want to set +# it to true (otherwise, ezau has no purpose). # (mandatory) -upload = false +upload = true + +# Where to upload the logs. +# By default, ezau will attempt to upload to https://dps.report/uploadContent, +# but depending on service availability you might want to use a different domain, +# like b.dps.report instead. +# (optional) +dps_report_upload_url = "https://dps.report/uploadContent" # Whether logs with an unknown boss should be uploaded. # By default, ezau only uploads logs with bosses known to evtclib. @@ -77,12 +87,6 @@ minimum_duration = 0 # (optional) retries = 0 -# Zip freshly created (unzipped) logs. -# Deactivate this if you use arcDPS's built-in zip functionality to prevent any -# weird interactions. -# (optional) -zip = true - # Discord messaging section. # If this section is missing, ezau will not do Discord notifications for log uploads. # Mandatory keys in this section are only mandatory if the section is present, as the whole Discord functionality is optional. @@ -121,9 +125,10 @@ room_id = ["!room123456:homeserver.org"] Usage ----- -`ezau watch <dirname>`: Watch the given directory for new log files, zip them and optionally upload them. +`ezau watch <dirname>`: Watch the given directory for new log files and upload them, posting a link to Discord/Matrix. -`ezau upload <filename>`: Upload a single log and do a Discord notification. +`ezau upload <filename>`: Upload a single log. +Prints the URL to the console, and (if configured) posts it to Discord/Matrix. Note that this bypasses the `upload`/`upload_unknown` settings. See `ezau help` and `ezau help <subcommand>` for more information. diff --git a/ezau-sample.toml b/ezau-sample.toml index 512511c..84319a0 100644 --- a/ezau-sample.toml +++ b/ezau-sample.toml @@ -1,7 +1,8 @@ # Whether logs should be uploaded. -# If this is false, ezau will only zip new logs and do no further processing. +# For legacy reasons, uploading can be disabled, but you probably want to set +# it to true (otherwise, ezau has no purpose). # (mandatory) -upload = false +upload = true # Where to upload the logs. # By default, ezau will attempt to upload to https://dps.report/uploadContent, @@ -26,12 +27,6 @@ minimum_duration = 0 # (optional) retries = 0 -# Zip freshly created (unzipped) logs. -# Deactivate this if you use arcDPS's built-in zip functionality to prevent any -# weird interactions. -# (optional) -zip = true - # Discord messaging section. # If this section is missing, ezau will not do Discord notifications for log uploads. # Mandatory keys in this section are only mandatory if the section is present, as the whole Discord functionality is optional. diff --git a/src/config.rs b/src/config.rs index ad2ee22..8b9211c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,6 +23,8 @@ pub struct Config { pub retries: u32, /// Whether ezau should zip non-zipped logs. #[serde(default = "default_zip")] + // We don't use this anymore, but we keep it so old configs can be parsed and we can properly + // inform the user. pub zip: bool, /// Option Discord information for bot postings. pub discord: Option<Discord>, @@ -63,7 +65,7 @@ pub fn load<P: AsRef<Path>>(path: P) -> Result<Config> { } fn default_zip() -> bool { - true + false } fn default_dps_report_upload_url() -> String { diff --git a/src/main.rs b/src/main.rs index 6352bff..b0ddd44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,17 @@ use std::{ - fs::{self, File}, - io::{BufReader, BufWriter, Read, Write}, path::{Path, PathBuf}, sync::mpsc::channel, thread, time::Duration, }; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; use clap::Parser; use evtclib::{Compression, Encounter, Log}; use log::{debug, error, info, warn}; use notify::{self, DebouncedEvent, RecursiveMode, Watcher}; use regex::Regex; use serde::Deserialize; -use zip::{CompressionMethod, ZipArchive, ZipWriter}; mod categories; use categories::Categorizable; @@ -48,7 +45,7 @@ enum SubCommand { /// Use the watch mode to automatically handle new logs. /// -/// This watches the given directory for new files and then zips and uploads them. +/// This watches the given directory for new files and then uploads them. #[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)] struct Watch { /// The directory to watch. @@ -104,8 +101,7 @@ fn inner_main(opts: &Opts) -> Result<()> { } fn watch(watch: &Watch, config: &Config) -> Result<()> { - let raw_evtc_re = Regex::new(r"\d{8}-\d{6}(\.evtc)?$").unwrap(); - let zip_evtc_re = Regex::new(r"(\.zip|\.zevtc)$").unwrap(); + let zip_evtc_re = Regex::new(r"(\.evtc\.zip|\.zevtc)$").unwrap(); let (tx, rx) = channel(); let mut watcher = notify::watcher(tx, Duration::from_secs(WATCH_DELAY_SECONDS))?; @@ -118,54 +114,13 @@ fn watch(watch: &Watch, config: &Config) -> Result<()> { debug!("Event: {:?}", event); if let DebouncedEvent::Create(path) = event { let path_str = path.to_str().unwrap(); - // Check if we need to zip it first. - if config.zip && raw_evtc_re.is_match(path_str) { - info!("Zipping up {}", path_str); - zip_file(&path)?; - } else if zip_evtc_re.is_match(path_str) { + if zip_evtc_re.is_match(path_str) { handle_file(config, &path)?; } } } } -fn zip_file(filepath: &Path) -> Result<()> { - let evtc_content = fs::read(filepath)?; - - let filename = filepath - .file_name() - .ok_or_else(|| anyhow!("Path does not have a file name"))? - .to_str() - .ok_or_else(|| anyhow!("Filename is invalid utf-8"))?; - let outname = filepath.with_extension("zevtc"); - let outfile = BufWriter::new(File::create(&outname)?); - let mut zip = ZipWriter::new(outfile); - let options = - zip::write::FileOptions::default().compression_method(CompressionMethod::Deflated); - - zip.start_file(filename, options)?; - zip.write_all(&evtc_content)?; - zip.finish()?.flush()?; - - if !verify_zip(filepath, &outname)? { - warn!("ZIP content mismatch, keeping original file"); - return Ok(()); - } - - fs::remove_file(filepath)?; - Ok(()) -} - -fn verify_zip(original: &Path, zip_path: &Path) -> Result<bool> { - let expected_content = fs::read(original)?; - let mut archive = ZipArchive::new(BufReader::new(File::open(zip_path)?))?; - let mut inner = archive.by_index(0)?; - let mut actual_content = Vec::new(); - inner.read_to_end(&mut actual_content)?; - - Ok(expected_content == actual_content) -} - fn handle_file(config: &Config, filename: &Path) -> Result<()> { if !config.upload { return Ok(()); @@ -257,6 +212,17 @@ fn upload_log(file: &Path, url: &str) -> Result<String> { } fn sanity_check(config: &Config, opts: &Opts) -> Result<()> { + if config.zip { + warn!( + "You have zipping enabled, but zipping is no longer part of ezau. \ + Arcdps automatically zips logs now." + ); + } + if matches!(opts.subcmd, SubCommand::Watch(_)) + && !config.upload + { + bail!("Watching but not uploading. What am I even doing here?"); + } if matches!(opts.subcmd, SubCommand::Watch(_)) && config.discord.is_none() && config.matrix.is_none() |