diff --git a/Cargo.lock b/Cargo.lock index f489620..b8121d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,31 @@ dependencies = [ "memchr", ] +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-watcher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cb0d902fdf0ed6b7b4c199a4cd1fedfb095004a47aeb0fc7580372b373e1fb" +dependencies = [ + "async-trait", + "notify", + "serde", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "autocfg" version = "1.2.0" @@ -136,6 +161,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-common" version = "0.1.6" @@ -206,6 +246,18 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -236,6 +288,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -480,6 +541,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "instant" version = "0.1.12" @@ -521,6 +602,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -581,6 +682,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" name = "minecraft_addon_controller" version = "0.1.0" dependencies = [ + "async-watcher", "bytes", "console", "futures-util", @@ -595,6 +697,7 @@ dependencies = [ "sha2", "thiserror", "tokio", + "tokio-util", "toml", ] @@ -614,6 +717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.48.0", ] @@ -636,6 +740,24 @@ dependencies = [ "tempfile", ] +[[package]] +name = "notify" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" +dependencies = [ + "bitflags 1.3.2", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "mio", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -729,7 +851,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets 0.52.5", ] @@ -812,6 +934,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -935,6 +1066,15 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.23" @@ -1217,16 +1357,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -1299,9 +1438,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1373,6 +1524,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1486,6 +1647,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1504,6 +1674,21 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -1535,6 +1720,12 @@ dependencies = [ "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -1547,6 +1738,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -1559,6 +1756,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -1577,6 +1780,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -1589,6 +1798,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -1601,6 +1816,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -1613,6 +1834,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index 12053d3..6616316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-watcher = "0.2.1" bytes = "1.6.0" console = "0.15.8" futures-util = "0.3.30" @@ -20,4 +21,5 @@ sha1 = "0.10.6" sha2 = "0.10.8" thiserror = "1.0.59" tokio = { version = "1.37.0", features = ["full"] } +tokio-util = "0.7.11" toml = "0.8.12" diff --git a/settings.toml b/settings.toml index e61c404..5b8c584 100644 --- a/settings.toml +++ b/settings.toml @@ -6,4 +6,3 @@ version = "1.20.6" [plugins.chunky] [plugins.nbtapi] [plugins.chunkyborder] -[plugins.lifestealz] \ No newline at end of file diff --git a/settings_example.toml b/settings_example.toml index 825d55c..acca95e 100644 --- a/settings_example.toml +++ b/settings_example.toml @@ -1,4 +1,4 @@ -# Require +# Require [core] # just core, nothing here to change :) provider = "paper" # [vanilla, paper, folia, purpur, fabric, waterfall, velocity] version = "1.20.6" # Or Latest (latest -> get error) @@ -23,4 +23,5 @@ force_update = false # false || true => false by default # Optional [additions] source = "git@github.com:Username/Super-Config.git" # Optional, require for key -key = "MySuperMegaKey" # Optional, don't work without link \ No newline at end of file +key = "MySuperMegaKey" # Optional, don't work without link +duraction = 300 # Optional, value of duraction between manager checker iterations (in seconds) diff --git a/src/errors/error.rs b/src/errors/error.rs index 9cf4698..a467dc4 100644 --- a/src/errors/error.rs +++ b/src/errors/error.rs @@ -1,5 +1,7 @@ use thiserror::Error; +use crate::mananger::messages::Messages; + #[derive(Error, Debug)] pub enum CompareHashError { #[error("Хэш не совпадает")] @@ -24,17 +26,46 @@ pub enum Error { // Download(String), #[error("Ошибка ввода/вывода: {0}")] Io(#[from] std::io::Error), - #[error("Ошибка парсинга TOML: {0}")] - TomlParse(#[from] toml::de::Error), + #[error("{0}")] + TomlParse(String), #[error("Ошибка сериализация TOML: {0}")] TomlSerialize(#[from] toml::ser::Error), #[error("Не удалось найти: {0}")] NotFound(String), - // #[error("Ошибка: {0}")] - // Any(#[from] Box), + #[error("Ошибка: {0}")] + Any(#[from] Box), + #[error("Task join error: {0}")] + JoinError(#[from] tokio::task::JoinError), + #[error("Indicatif template error: {0}")] + IndicatifTemplate(#[from] indicatif::style::TemplateError), + #[error("Indicatif template error: {0}")] + SendMessage(#[from] tokio::sync::mpsc::error::SendError), } pub type Result = std::result::Result; +impl From for Error { + fn from(value: toml::de::Error) -> Self { + let value = value.to_string(); + let parts: Vec<&str> = value.split('|').collect(); + + // Проверяем, что индексы существуют и выбираем только нужные + let message = if parts.len() >= 4 { + let third_part = parts[3].trim(); + let trimmed_third_part = &third_part[2..]; // Удаляем первые три символа + format!( + " Where => {} ||| What => {} ||| why => {} ", + parts[0].trim(), + parts[2].trim(), + trimmed_third_part + ) + } else { + value.to_string() // Если не удалось разделить на нужное количество частей, вернем исходную строку + }; + + Error::TomlParse(message) + } +} + #[macro_export] macro_rules! not_found { ($msg:expr) => { diff --git a/src/lock/mod.rs b/src/lock/mod.rs index 2cfa7b2..50c9ddf 100644 --- a/src/lock/mod.rs +++ b/src/lock/mod.rs @@ -2,6 +2,7 @@ pub mod core; pub mod ext; use serde::{Deserialize, Serialize}; +use tokio::sync::RwLockReadGuard; use self::core::CoreMeta; use self::ext::ExtensionMeta; @@ -47,7 +48,7 @@ impl Lock { self.core = CoreMeta::default(); Ok(()) } - pub fn remove_nonexistent(&mut self, settings: &Settings) -> Result<()> { + pub fn remove_nonexistent(&mut self, settings: RwLockReadGuard) -> Result<()> { let plugin_keys: Vec = self.plugins().0.keys().cloned().collect(); // TODO: let mods_keys if let Some(e) = settings.plugins() { diff --git a/src/main.rs b/src/main.rs index 9f2b4d4..f3a8cf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,74 +1,17 @@ pub mod errors; pub mod lock; +pub mod mananger; pub mod models; pub mod query; pub mod settings; pub mod tr; -use std::sync::Arc; - use crate::errors::error::Result; -use indicatif::{MultiProgress, ProgressBar}; -use lock::Lock; -use log::warn; -use settings::Settings; -use tokio::sync::Mutex; -use tr::load::Load; #[tokio::main] async fn main() -> Result<()> { pretty_env_logger::formatted_builder() .filter_level(log::LevelFilter::Info) .init(); - // Init - let (mpb, lock, settings) = init().await; - // - let pb = mpb.add(ProgressBar::new_spinner()); - pb.finish_with_message("Init Minecraft Addon Controller"); - // - lock.lock().await.remove_nonexistent(&settings)?; - '_c: { - let lock = Arc::clone(&lock); - let settings = Arc::clone(&settings); - let mpb = Arc::clone(&mpb); - download(settings, lock, mpb).await?; - } - Ok(()) -} - -async fn download( - settings: Arc, - lock: Arc>, - mpb: Arc, -) -> Result<()> { - '_core_scope: { - let lock = Arc::clone(&lock); - let mpb = Arc::clone(&mpb); - settings.core().download(lock, mpb).await?; - } - '_plugins_scope: { - let lock = Arc::clone(&lock); - let mpb = Arc::clone(&mpb); - if let Some(plugins) = settings.plugins() { - plugins - .download_all( - settings.core().provider().as_str(), - settings.core().version(), - lock, - mpb, - ) - .await?; - } - } - Ok(()) -} - -async fn init() -> (Arc, Arc>, Arc) { - let mpb: Arc = Arc::new(MultiProgress::new()); - let lock: Arc> = Arc::new(Mutex::new(Lock::load().await.unwrap_or({ - warn!("Use default Lock"); - Lock::default() - }))); - let settings: Arc = Arc::new(Settings::load().await.unwrap()); - (mpb, lock, settings) + mananger::run().await } diff --git a/src/mananger/download.rs b/src/mananger/download.rs new file mode 100644 index 0000000..8bd8210 --- /dev/null +++ b/src/mananger/download.rs @@ -0,0 +1,63 @@ +use std::sync::Arc; +use std::time::Duration; + +use indicatif::MultiProgress; +use tokio::sync::{Mutex, RwLock}; +use tokio::time::sleep; +use tokio_util::sync::CancellationToken; + +use crate::errors::error::Result; +use crate::settings::additions::Additions; +use crate::{lock::Lock, settings::Settings}; + +pub async fn download( + settings: Arc>, + lock: Arc>, + mpb: Arc, + key: Arc, +) -> Result<()> { + let duraction = settings + .read() + .await + .additions() + .unwrap_or(&Additions::default()) + .duraction() + .unwrap_or(300f64); + let cooldown = Duration::from_secs_f64(duraction); + loop { + '_core_scope: { + let lock = Arc::clone(&lock); + let settings = Arc::clone(&settings); + let mpb = Arc::clone(&mpb); + tokio::spawn(async move { + let settings = settings.read().await; + settings.core().download(lock, mpb).await + }); + } + '_plugins_scope: { + let lock = Arc::clone(&lock); + let settings = Arc::clone(&settings); + let mpb = Arc::clone(&mpb); + + tokio::spawn(async move { + let settings = settings.read().await; + if let Some(plugins) = settings.plugins() { + plugins + .download_all( + settings.core().provider().as_str(), + settings.core().version(), + lock, + mpb, + ) + .await + } else { + Ok(()) + } + }); + }; + tokio::select! { + _ = sleep(cooldown) => {}, + _ = key.cancelled() => {break Ok(())}, + } + } +} diff --git a/src/mananger/manage.rs b/src/mananger/manage.rs new file mode 100644 index 0000000..e43b6c8 --- /dev/null +++ b/src/mananger/manage.rs @@ -0,0 +1,52 @@ +use std::sync::Arc; + +use indicatif::MultiProgress; +use tokio::sync::{mpsc::Receiver, Mutex, RwLock}; +use tokio_util::sync::CancellationToken; + +use crate::errors::error::Result; +use crate::mananger::download::download; +use crate::mananger::messages::Messages; +use crate::{lock::Lock, settings::Settings}; + +pub async fn manage( + mut rx: Receiver, + lock: Arc>, + settings: Arc>, + mpb: Arc, +) -> Result<()> { + loop { + let lock = Arc::clone(&lock); + let settings = Arc::clone(&settings); + let mpb = Arc::clone(&mpb); + let key = Arc::new(CancellationToken::new()); + tokio::select! { + Some(e) = rx.recv() => match e { + Messages::Restart(pb) => { + pb.set_message("Рестарт!"); + let key = Arc::clone(&key); + pb.set_message("Стопаем текущюю задачу!"); + key.cancel(); + mpb.clear()?; + if key.is_cancelled() { + pb.set_message("Начинаем новую!"); + tokio::spawn(download(settings.clone(), lock.clone(), mpb.clone(), key)); + } else { + pb.set_message("Ну... она стоит"); + } + pb.finish_and_clear(); + } + Messages::Stop(pb) => { + pb.finish_with_message("Остановка!"); + key.cancelled().await; + } + Messages::Start(pb) => { + let key = Arc::clone(&key); + pb.finish_with_message("Начинаем новую!"); + tokio::spawn(download(settings.clone(), lock.clone(), mpb.clone(), key)); + pb.finish_and_clear(); + } + }, + } + } +} diff --git a/src/mananger/messages.rs b/src/mananger/messages.rs new file mode 100644 index 0000000..1d2deb8 --- /dev/null +++ b/src/mananger/messages.rs @@ -0,0 +1,9 @@ +use std::sync::Arc; + +use indicatif::ProgressBar; + +pub enum Messages { + Restart(Arc), + Stop(Arc), + Start(Arc), +} diff --git a/src/mananger/mod.rs b/src/mananger/mod.rs new file mode 100644 index 0000000..174725d --- /dev/null +++ b/src/mananger/mod.rs @@ -0,0 +1,60 @@ +mod download; +mod manage; +pub mod messages; +mod watch_changer; + +use std::sync::Arc; + +use crate::errors::error::Result; +use indicatif::{MultiProgress, ProgressBar}; +use lock::Lock; +use log::warn; +use manage::manage; +use settings::Settings; +use tokio::{ + sync::{mpsc, Mutex, RwLock}, + try_join, +}; +use tr::load::Load; + +use crate::{lock, settings, tr}; + +use self::watch_changer::watch_changes; + +pub async fn run() -> Result<()> { + let (mpb, lock, settings) = init().await?; + // + let pb = mpb.add(ProgressBar::new_spinner()); + pb.finish_with_message("Init Minecraft Addon Controller"); + // + let (tx, rx) = mpsc::channel(20); + + let manage = { + let settings_m = Arc::clone(&settings); + let lock = Arc::clone(&lock); + let mpb_m = Arc::clone(&mpb); + manage(rx, lock, settings_m, mpb_m) + }; + let watch_changes = { + let settings_w = Arc::clone(&settings); + let lock = Arc::clone(&lock); + let mpb_w = Arc::clone(&mpb); + watch_changes(settings_w, lock, mpb_w, tx) + }; + + let a = try_join!(manage, watch_changes); + match a { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} + +async fn init() -> Result<(Arc, Arc>, Arc>)> { + let mpb: Arc = Arc::new(MultiProgress::new()); + let lock: Arc> = Arc::new(Mutex::new(Lock::load().await.unwrap_or({ + warn!("Use default Lock"); + Lock::default() + }))); + let settings = Arc::new(RwLock::new(Settings::load().await?)); + Ok((mpb, lock, settings)) +} diff --git a/src/mananger/watch_changer.rs b/src/mananger/watch_changer.rs new file mode 100644 index 0000000..c2f02b9 --- /dev/null +++ b/src/mananger/watch_changer.rs @@ -0,0 +1,67 @@ +use std::sync::Arc; +use std::time::Duration; + +use async_watcher::notify::RecursiveMode; +use async_watcher::AsyncDebouncer; +use indicatif::{MultiProgress, ProgressBar}; +use tokio::sync::mpsc::Sender; +use tokio::sync::{Mutex, RwLock}; + +use crate::errors::error::Result; +use crate::mananger::messages::Messages; +use crate::tr::load::Load; +use crate::{lock::Lock, settings::Settings}; + +/// Load downloader module. +/// Always check config file. +/// Use `token` for canceling minecraft task +pub async fn watch_changes( + settings: Arc>, + lock: Arc>, + mpb: Arc, + dw_tx: Sender, +) -> Result<()> { + const CONFIG_PATH: &str = "settings.toml"; + // initialize the debouncer + let (mut tx, mut rx) = AsyncDebouncer::new_with_channel(Duration::from_millis(200), None) + .await + .unwrap(); + // register path to watch + tx.watcher() + .watch(CONFIG_PATH.as_ref(), RecursiveMode::NonRecursive) + .unwrap(); + + // Check lock + { + lock.lock() + .await + .remove_nonexistent(settings.read().await)?; + } + let pb = Arc::new(mpb.add(ProgressBar::new_spinner())); + // Send start to downloader + { + dw_tx.send(Messages::Start(Arc::clone(&pb))).await?; + } + + // wait for events + while rx.recv().await.is_some() { + let pb = Arc::clone(&pb); + pb.set_message("Find some changes in config!"); + let settings = Arc::clone(&settings); + let settings_new = Settings::load().await?; + if *settings.read().await != settings_new { + pb.set_message("настройки другие"); + *settings.write().await = settings_new; + { + lock.lock() + .await + .remove_nonexistent(settings.read().await)?; + } + pb.set_message("настройки перезаписали"); + dw_tx.send(Messages::Restart(pb)).await?; + } else { + pb.set_message("настройки теже"); + } + } + Ok(()) +} diff --git a/src/settings/additions.rs b/src/settings/additions.rs index 5c984a1..15a6bfe 100644 --- a/src/settings/additions.rs +++ b/src/settings/additions.rs @@ -8,10 +8,33 @@ pub struct Additions { // git key #[serde(default)] key: Option, + // duraction of delay between download intervals + #[serde(default = "duraction_default")] + duraction: Option, +} + +fn duraction_default() -> Option { + Some(300f64) } impl Additions { - pub fn new(source: Option, key: Option) -> Self { - Self { source, key } + pub fn new(source: Option, key: Option, duraction: Option) -> Self { + Self { + source, + key, + duraction, + } + } + + pub fn source(&self) -> Option<&String> { + self.source.as_ref() + } + + pub fn key(&self) -> Option<&String> { + self.key.as_ref() + } + + pub fn duraction(&self) -> Option { + self.duraction } } diff --git a/src/settings/core.rs b/src/settings/core.rs index 46fd3c8..7b1f0b0 100644 --- a/src/settings/core.rs +++ b/src/settings/core.rs @@ -1,9 +1,11 @@ use std::sync::Arc; +use std::time::Duration; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use log::debug; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; +use tokio::time::sleep; use crate::errors::error::Result; use crate::lock::core::CoreMeta; @@ -90,32 +92,32 @@ impl Core { /// Скачиваем `Core` и сохраняем его по стандартному пути. pub async fn download(&self, lock: Arc>, mpb: Arc) -> Result<()> { let pb = mpb.add(ProgressBar::new_spinner()); - pb.set_style( - ProgressStyle::with_template( - "Package:: {prefix:.blue} >>>{spinner:.green} {msg:.blue} > eta: {eta:.blue}", - ) - .unwrap(), - ); + pb.set_style(ProgressStyle::with_template( + "Package:: {prefix:.blue} >>>{spinner:.green} {msg:.blue} > eta: {eta:.blue}", + )?); pb.set_prefix(self.provider.as_str()); // Check meta let (link, hash, build) = self.get_link(&pb).await?; - let mut lock = lock.lock().await; - if let Some(e) = lock.core().build() { + if let Some(e) = lock.lock().await.core().build() { debug!("lock build: {} / build: {}", &e, &build); if *e == build && (!self.force_update || self.freeze) { - pb.finish_with_message("Does't need to update"); + pb.set_message("Does't need to update"); + sleep(Duration::from_secs(1)).await; + pb.finish_and_clear(); return Ok(()); } } let file = Core::get_file(link, hash, &pb).await?; pb.set_message("Saving file"); Core::save_bytes(file, self.provider().as_str()).await?; - *lock.core_mut() = self.clone().to_meta(build); - let res = lock.save().await; - pb.finish_with_message("Done"); - res + *lock.lock().await.core_mut() = self.clone().to_meta(build); + lock.lock().await.save().await?; + pb.set_message("Done"); + sleep(Duration::from_secs(1)).await; + pb.finish_and_clear(); + Ok(()) } async fn get_link(&self, pb: &ProgressBar) -> Result<(String, ChooseHash, String)> { match self.provider { diff --git a/src/settings/extensions/mode.rs b/src/settings/extensions/mode.rs index 1b4694c..39ad5fe 100644 --- a/src/settings/extensions/mode.rs +++ b/src/settings/extensions/mode.rs @@ -1,4 +1,4 @@ use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Serialize, Debug, Default, PartialEq)] +#[derive(Deserialize, Serialize, Debug, Default, PartialEq, Clone)] pub struct Mode {} diff --git a/src/settings/extensions/plugins.rs b/src/settings/extensions/plugins.rs index 619b73c..369f2e7 100644 --- a/src/settings/extensions/plugins.rs +++ b/src/settings/extensions/plugins.rs @@ -1,11 +1,13 @@ use std::collections::HashMap; use std::sync::Arc; +use std::time::Duration; use futures_util::future::join_all; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use tokio::task::JoinHandle; +use tokio::time::sleep; use crate::errors::error::Result; use crate::lock::ext::ExtensionMeta; @@ -57,7 +59,9 @@ impl Plugins { let local_build = plugin_meta.build(); // Need to download? if *local_build == build && !plugin.force_update() || plugin.freeze() { - pb.finish_with_message("Does't need to update"); + pb.set_message("Does't need to update"); + sleep(Duration::from_secs(1)).await; + pb.finish_and_clear(); continue; } } @@ -68,23 +72,24 @@ impl Plugins { let lock = Arc::clone(&lock); handler_list.push(tokio::spawn(async move { - // get lock - let mut lock = lock.lock().await; // get file let file = Plugin::get_file(link, hash, &pb).await?; pb.set_message("Remove exist version"); - //delete prevision item - lock.remove_plugin(&name)?; + // delete prevision item + // get lock + lock.lock().await.remove_plugin(&name)?; pb.set_message("Saving..."); // save on disk Plugin::save_bytes(file, name.as_str()).await?; pb.set_message("Logging..."); //save in lock - lock.plugins_mut().insert(name.to_string(), { + lock.lock().await.plugins_mut().insert(name.to_string(), { ExtensionMeta::new(build, format!("{}{}.jar", PATH, name)) }); - lock.save().await?; - pb.finish_with_message("Done"); + lock.lock().await.save().await?; + pb.set_message("Done"); + sleep(Duration::from_secs(1)).await; + pb.finish_and_clear(); Ok(()) })); }