diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..ef366d7 Binary files /dev/null and b/.DS_Store differ diff --git a/Cargo.lock b/Cargo.lock index b8121d5..44f244d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,11 +51,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -74,9 +80,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -113,9 +119,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -163,18 +169,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -232,9 +238,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -376,15 +382,15 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http", "indexmap", "slab", @@ -395,9 +401,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" @@ -489,9 +495,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" dependencies = [ "bytes", "futures-channel", @@ -541,6 +547,16 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "indicatif-log-bridge" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2963046f28a204e3e3fd7e754fd90a6235da05b5378f24707ff0ec9513725ce3" +dependencies = [ + "indicatif", + "log", +] + [[package]] name = "inotify" version = "0.9.6" @@ -563,9 +579,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -630,15 +646,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -682,11 +698,14 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" name = "minecraft_addon_controller" version = "0.1.0" dependencies = [ + "async-trait", "async-watcher", "bytes", "console", "futures-util", "indicatif", + "indicatif-log-bridge", + "lazy_static", "log", "md-5", "pretty_env_logger", @@ -703,9 +722,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -835,9 +854,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -918,9 +937,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -1027,9 +1046,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" @@ -1056,15 +1075,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1092,11 +1111,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -1105,9 +1124,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -1115,18 +1134,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.199" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", @@ -1135,9 +1154,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1146,9 +1165,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -1213,9 +1232,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1223,9 +1242,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -1282,18 +1301,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", @@ -1370,9 +1389,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", @@ -1382,18 +1401,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap", "serde", @@ -1415,7 +1434,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -1436,7 +1454,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1854,9 +1871,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 6616316..0d4c1c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-trait = "0.1.80" async-watcher = "0.2.1" bytes = "1.6.0" console = "0.15.8" futures-util = "0.3.30" indicatif = { version = "0.17.8", features = ["tokio"] } +indicatif-log-bridge = "0.2.2" +lazy_static = "1.4.0" log = "0.4.21" md-5 = "0.10.6" pretty_env_logger = "0.5.0" diff --git a/README.md b/README.md index e9d5010..6675315 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ # Что реализуется -- [x] Обновление, загрузка плагинов. -- [x] Обновление, загрузка ядра. +- [x] Обновление, загрузка плагинов +- [x] Обновление, загрузка ядра - [x] Чтение конфигурационных файлов +- [x] Загрузка языкового файла - [ ] Запуск minecraft - [ ] Бекапы - [ ] Загрузка конфигурационных файлов через git @@ -41,9 +42,10 @@ # What is implemented -- [x] Update, load plugins. -- [x] Updating, loading kernels. +- [x] Update, load plugins +- [x] Updating, loading kernels - [x] Reading configuration files +- [x] Load language file - [ ] Running minecraft - [ ] Backups - [ ] Uploading configuration files via git @@ -67,7 +69,7 @@ There is a start, but we need to realize the loading of cores. ## Mods -- Modrinth +- Modrinth (soon) - CurseForge (not implemented) ## Cores diff --git a/language.toml b/language.toml new file mode 100644 index 0000000..614c3e0 --- /dev/null +++ b/language.toml @@ -0,0 +1,22 @@ +calculate_hash = "Calculate hash..." +delete_exist_version = "Delete exist version!" +doest_need_to_update = "Does't need to update!" +done = "Done!" +download_file = "Download file..." +file_downloaded = "File downloaded!" +restart = "Restart..." +saving_file = "Saving file..." +start_new_iteration = "Start new iteration!" +stop_iteration = "Stop iteration!" +waiting_new_iteration = "Waiting new iteration..." +write_to_lock = "Write to lock!" +find_changes_in_settings = "Find some changes in settings!" +settings_changed = "Settings changed" +settings_has_rewrited = "Settings has rewrited" +settings_same = "Settings same" +intro = "MAC ready to work!" +init_work = "Generating link..." +finding_version = "Finding version..." +make_link = "Make link..." +start_remove_nonexist = "Start remove nonexist" +remove_nonexist = "Remove nonexist" diff --git a/language_ru-example.toml b/language_ru-example.toml new file mode 100644 index 0000000..d05af7b --- /dev/null +++ b/language_ru-example.toml @@ -0,0 +1,22 @@ +calculate_hash = "Вычисление хеша..." +delete_exist_version = "Удаление существующей версии!" +doest_need_to_update = "Не требует обновления!" +done = "Готово!" +download_file = "Загрузка файла..." +file_downloaded = "Файл загружен!" +restart = "Перезапуск..." +saving_file = "Сохранение файла..." +start_new_iteration = "Начало новой итерации!" +stop_iteration = "Остановка итерации!" +waiting_new_iteration = "Ожидание новой итерации..." +write_to_lock = "Логирование файла!" +find_changes_in_settings = "Найдены изменения в настройках!" +settings_changed = "Настройки изменены" +settings_has_rewrited = "Настройки перезаписаны" +settings_same = "Настройки те же" +intro = "МАК готов к работе!" +init_work = "Генерация ссылки..." +finding_version = "Поиск версии..." +make_link = "Создание ссылки..." +start_remove_nonexist = "Удаление не логируемых файлов" +remove_nonexist = "Удаление не существующего:" diff --git a/settings.toml b/settings.toml index 5b8c584..4dbd0da 100644 --- a/settings.toml +++ b/settings.toml @@ -1,8 +1,8 @@ [core] provider = "paper" -version = "1.20.6" +version = "1.20.4" +[plugins] [plugins.simple-voice-chat] [plugins.chunky] -[plugins.nbtapi] -[plugins.chunkyborder] +[plugins.discordsrv] diff --git a/settings_example.toml b/settings_example.toml index acca95e..4a22c6c 100644 --- a/settings_example.toml +++ b/settings_example.toml @@ -1,27 +1,27 @@ # 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) +provider = "paper" # [vanilla, paper, folia, purpur, fabric, waterfall, velocity] +version = "1.20.6" # Or Latest (latest -> get error) force_update = true # Optional [plugins.name] # name be used only in kebab-case -source = "modrinth" # [hangar, modrinth] => modrinth by default -version = "ffdfdsd" # numbers of this version. -channel = "release" # [release, beta, alpha] => release -freeze = false # false || true => false by default +source = "modrinth" # [hangar, modrinth] => modrinth by default +version = "ffdfdsd" # numbers of this version. +channel = "release" # [release, beta, alpha] => release +freeze = false # false || true => false by default force_update = false # false || true => false by default # Optional -[mods.name] # name be used only in kebab-case -source = "modrinth" # [hangar, modrinth] => modrinth by default -version = "ffdfdsd" # numbers of this version. -channel = "release" # [release, beta, alpha] => release -freeze = false # false || true => false by default +[mods.name] # name be used only in kebab-case ^Not implemented!!! +source = "modrinth" # [hangar, modrinth] => modrinth by default +version = "ffdfdsd" # numbers of this version. +channel = "release" # [release, beta, alpha] => release +freeze = false # false || true => false by default 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 -duraction = 300 # Optional, value of duraction between manager checker iterations (in seconds) +source = "git@github.com:Username/Super-Config.git" # Optional, require for key ^Not implemented!!! +key = "MySuperMegaKey" # Optional, don't work without link ^Not implemented!!! +duraction = 300 # Optional, value of duraction between manager check iterations (in seconds) => 300 by default diff --git a/src/dictionary/mod.rs b/src/dictionary/mod.rs new file mode 100644 index 0000000..a178bd8 --- /dev/null +++ b/src/dictionary/mod.rs @@ -0,0 +1 @@ +pub mod pb_messages; diff --git a/src/dictionary/pb_messages.rs b/src/dictionary/pb_messages.rs new file mode 100644 index 0000000..3d714f3 --- /dev/null +++ b/src/dictionary/pb_messages.rs @@ -0,0 +1,71 @@ +use serde::{Deserialize, Serialize}; + +use crate::tr::load::Load; + +#[derive(Deserialize, Serialize)] +pub struct PbMessages { + pub calculate_hash: String, + pub delete_exist_version: String, + pub doest_need_to_update: String, + pub done: String, + pub download_file: String, + pub file_downloaded: String, + pub restart: String, + pub saving_file: String, + pub start_new_iteration: String, + pub stop_iteration: String, + pub waiting_new_iteration: String, + pub write_to_lock: String, + // Config + pub find_changes_in_settings: String, + pub settings_changed: String, + pub settings_has_rewrited: String, + pub settings_same: String, + // Intro + pub intro: String, + // Models messages + pub init_work: String, + pub finding_version: String, + pub make_link: String, + // Remove nonexist + pub start_remove_nonexist: String, + pub remove_nonexist: String, +} + +impl Default for PbMessages { + fn default() -> Self { + Self { + restart: "Restart...".into(), + stop_iteration: "Stop iteration!".into(), + start_new_iteration: "Start new iteration!".into(), + waiting_new_iteration: "Waiting new iteration...".into(), + doest_need_to_update: "Does't need to update!".into(), + delete_exist_version: "Delete exist version!".into(), + download_file: "Download file...".into(), + saving_file: "Saving file...".into(), + write_to_lock: "Write to lock!".into(), + done: "Done!".into(), + file_downloaded: "File downloaded!".into(), + calculate_hash: "Calculate hash...".into(), + find_changes_in_settings: "Find some changes in settings!".into(), + settings_changed: "Settings changed".into(), + settings_has_rewrited: "Settings has rewrited".into(), + settings_same: "Settings same".into(), + intro: "MAC ready to work!".into(), + init_work: "Generating link...".into(), + finding_version: "Finding version...".into(), + make_link: "Make link...".into(), + start_remove_nonexist: "Start remove nonexist".into(), + remove_nonexist: "Remove nonexist".into(), + } + } +} +impl PbMessages { + pub fn remove_if_nonexist(&self, name: &str) -> String { + format!("{}: {}", self.remove_nonexist, name) + } +} + +impl Load for PbMessages { + const PATH: &'static str = "language.toml"; +} diff --git a/src/errors/error.rs b/src/errors/error.rs index a467dc4..65922b8 100644 --- a/src/errors/error.rs +++ b/src/errors/error.rs @@ -4,8 +4,8 @@ use crate::mananger::messages::Messages; #[derive(Error, Debug)] pub enum CompareHashError { - #[error("Хэш не совпадает")] - HashNotCompare(), + #[error("Хэш не совпадает: expect => {0}, value => {1}")] + HashNotCompare(String, String), #[error("Конвертация Sha1 проведена не успешно : {0}")] SHA1(std::io::Error), #[error("Конвертация Sha256 проведена не успешно : {0}")] @@ -18,22 +18,20 @@ pub enum CompareHashError { #[derive(Error, Debug)] pub enum Error { - #[error("Проблема с обработкой запроса: {0}")] + #[error("Reqwest error: {0}")] Reqwest(#[from] reqwest::Error), - #[error("Проблема с обработкой хэша: {0}")] + #[error("Hash corrupted: {0}")] CompareHash(CompareHashError), - // #[error("Проблема с скачиванием файла: {0}")] - // Download(String), - #[error("Ошибка ввода/вывода: {0}")] + #[error("IO error: {0}")] Io(#[from] std::io::Error), - #[error("{0}")] + #[error("TOML parse error{0}")] TomlParse(String), - #[error("Ошибка сериализация TOML: {0}")] + #[error("Serialization of TOML error: {0}")] TomlSerialize(#[from] toml::ser::Error), - #[error("Не удалось найти: {0}")] + #[error("Not found: {0}")] NotFound(String), - #[error("Ошибка: {0}")] - Any(#[from] Box), + // #[error("Any error: {0}")] + // Any(#[from] Box), #[error("Task join error: {0}")] JoinError(#[from] tokio::task::JoinError), #[error("Indicatif template error: {0}")] @@ -48,18 +46,20 @@ impl From for Error { 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..]; // Удаляем первые три символа + let third_part: String = parts[3] + .trim() + .chars() + .filter(|x| *x != '^' || *x != '\\') + .collect(); format!( " Where => {} ||| What => {} ||| why => {} ", parts[0].trim(), parts[2].trim(), - trimmed_third_part + third_part ) } else { - value.to_string() // Если не удалось разделить на нужное количество частей, вернем исходную строку + value.to_string() }; Error::TomlParse(message) @@ -83,13 +83,6 @@ macro_rules! not_found_path { }; } -// #[macro_export] -// macro_rules! download_error { -// ($($arg:tt)*) => { -// Err(Error::Download(format!($($arg)*))) -// }; -// } - #[macro_export] macro_rules! not_found_build_error { ($arg:tt) => { @@ -116,3 +109,12 @@ macro_rules! not_found_plugin_error { ))) }; } +#[macro_export] +macro_rules! not_found_plugin_link_error { + ($arg:tt) => { + Err(Error::NotFound(format!( + "Not found link in for plugin: ->{}<-", + $arg + ))) + }; +} diff --git a/src/lock/ext.rs b/src/lock/ext.rs index 9eb93cf..82981fa 100644 --- a/src/lock/ext.rs +++ b/src/lock/ext.rs @@ -6,7 +6,8 @@ pub struct ExtensionMeta { path: String, } impl ExtensionMeta { - pub fn new(build: String, path: String) -> Self { + pub fn new(build: String, path: &str, name: &str) -> Self { + let path = format!("{}{}.jar", path, name); Self { build, path } } diff --git a/src/lock/mod.rs b/src/lock/mod.rs index 50c9ddf..858f42c 100644 --- a/src/lock/mod.rs +++ b/src/lock/mod.rs @@ -1,18 +1,28 @@ pub mod core; pub mod ext; +use indicatif::ProgressBar; +use log::debug; use serde::{Deserialize, Serialize}; -use tokio::sync::RwLockReadGuard; +use tokio::sync::RwLock; use self::core::CoreMeta; use self::ext::ExtensionMeta; -use crate::errors::error::Result; use crate::settings::Settings; +use crate::tr::delete::Delete; use crate::{ settings::core::Core, tr::{load::Load, save::Save}, }; -use std::{collections::HashMap, fs}; +use std::collections::HashMap; +use std::sync::Arc; + +use crate::dictionary::pb_messages::PbMessages; +use lazy_static::lazy_static; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} #[derive(Default, Serialize, Deserialize, Clone)] pub struct Lock { @@ -36,35 +46,44 @@ impl Lock { pub fn set_core(&mut self, value: Core, build: String) { self.core = value.to_meta(build); } - pub fn remove_plugin(&mut self, key: &str) -> Result<()> { - self.plugins.remove(key) + pub async fn remove_plugin(&mut self, key: &str) { + self.plugins.remove(key).await } - pub fn remove_mod(&mut self, key: &str) -> Result<()> { - self.mods.remove(key) + pub async fn remove_mod(&mut self, key: &str) { + self.mods.remove(key).await } //delete and make the current core the default - pub fn remove_core(&mut self) -> Result<()> { - fs::remove_file(self.core().path())?; + pub async fn remove_core(&mut self) { + //remove self.core = CoreMeta::default(); - Ok(()) } - 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() { - for key in plugin_keys { - if !e.items().contains_key(&key) { - self.remove_plugin(key.as_str())?; + pub async fn remove_nonexistent( + &mut self, + settings: Arc>, + pb: Arc, + ) { + debug!( + "fn() remove_nonexistent => keys list: {:#?}", + &self.plugins().0 + ); + pb.set_message(&DICT.start_remove_nonexist); + if let Some(settings_plugins) = settings.read().await.plugins() { + let lock_list = self.plugins().get_list().clone(); + for (key, _) in lock_list { + if !settings_plugins.items().contains_key(&key) { + pb.set_message(DICT.remove_if_nonexist(&key)); + debug!("{}", DICT.remove_if_nonexist(&key)); + self.remove_plugin(&key).await } } } // TODO: add remover for mods - Ok(()) } } #[derive(Default, Serialize, Deserialize, Clone)] pub struct ExtensionMetaList(HashMap); + impl ExtensionMetaList { pub fn get(&self, key: &str) -> Option<&ExtensionMeta> { self.0.get(key) @@ -72,17 +91,18 @@ impl ExtensionMetaList { pub fn insert(&mut self, key: String, value: ExtensionMeta) { self.0.insert(key, value); } - pub fn remove(&mut self, key: &str) -> Result<()> { - let value = self.0.remove(key); - match value { - Some(e) => Ok(fs::remove_file(e.path())?), - None => Ok(()), + // make it traited + pub async fn remove(&mut self, key: &str) { + if let Some(e) = self.0.remove(key) { + self.delete(e.path()).await } } - pub fn update(&mut self, key: String, value: ExtensionMeta) -> Result<()> { - self.remove(&key)?; + pub async fn update(&mut self, key: String, value: ExtensionMeta) { + self.remove(&key).await; self.insert(key, value); - Ok(()) + } + pub fn get_list(&self) -> &HashMap { + &self.0 } } @@ -92,3 +112,4 @@ impl Save for Lock { impl Load for Lock { const PATH: &'static str = "./lock.toml"; } +impl Delete for ExtensionMetaList {} diff --git a/src/main.rs b/src/main.rs index f3a8cf6..422cac1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +pub mod dictionary; pub mod errors; pub mod lock; pub mod mananger; @@ -10,8 +11,5 @@ use crate::errors::error::Result; #[tokio::main] async fn main() -> Result<()> { - pretty_env_logger::formatted_builder() - .filter_level(log::LevelFilter::Info) - .init(); mananger::run().await } diff --git a/src/mananger/download.rs b/src/mananger/download.rs index 8bd8210..7d04ac0 100644 --- a/src/mananger/download.rs +++ b/src/mananger/download.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use std::time::Duration; use indicatif::MultiProgress; +use log::error; use tokio::sync::{Mutex, RwLock}; use tokio::time::sleep; use tokio_util::sync::CancellationToken; @@ -22,8 +23,8 @@ pub async fn download( .additions() .unwrap_or(&Additions::default()) .duraction() - .unwrap_or(300f64); - let cooldown = Duration::from_secs_f64(duraction); + .unwrap_or(300); + let cooldown = Duration::from_secs(duraction); loop { '_core_scope: { let lock = Arc::clone(&lock); @@ -50,6 +51,10 @@ pub async fn download( mpb, ) .await + .map_err(|e| { + error!("Plugin scope error {:#?}", &e); + e + }) } else { Ok(()) } diff --git a/src/mananger/manage.rs b/src/mananger/manage.rs index e43b6c8..49819ad 100644 --- a/src/mananger/manage.rs +++ b/src/mananger/manage.rs @@ -1,13 +1,20 @@ +use crate::tr::load::Load; use std::sync::Arc; use indicatif::MultiProgress; use tokio::sync::{mpsc::Receiver, Mutex, RwLock}; use tokio_util::sync::CancellationToken; +use crate::dictionary::pb_messages::PbMessages; use crate::errors::error::Result; use crate::mananger::download::download; use crate::mananger::messages::Messages; use crate::{lock::Lock, settings::Settings}; +use lazy_static::lazy_static; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} pub async fn manage( mut rx: Receiver, @@ -23,26 +30,26 @@ pub async fn manage( tokio::select! { Some(e) = rx.recv() => match e { Messages::Restart(pb) => { - pb.set_message("Рестарт!"); + pb.set_message(&DICT.restart); let key = Arc::clone(&key); - pb.set_message("Стопаем текущюю задачу!"); + pb.set_message(&DICT.stop_iteration); key.cancel(); mpb.clear()?; if key.is_cancelled() { - pb.set_message("Начинаем новую!"); + pb.set_message(&DICT.start_new_iteration); tokio::spawn(download(settings.clone(), lock.clone(), mpb.clone(), key)); } else { - pb.set_message("Ну... она стоит"); + pb.set_message(&DICT.waiting_new_iteration); } pb.finish_and_clear(); } Messages::Stop(pb) => { - pb.finish_with_message("Остановка!"); + pb.finish_with_message(&DICT.stop_iteration); key.cancelled().await; } Messages::Start(pb) => { let key = Arc::clone(&key); - pb.finish_with_message("Начинаем новую!"); + pb.finish_with_message(&DICT.start_new_iteration); tokio::spawn(download(settings.clone(), lock.clone(), mpb.clone(), key)); pb.finish_and_clear(); } diff --git a/src/mananger/mod.rs b/src/mananger/mod.rs index 174725d..6436bb5 100644 --- a/src/mananger/mod.rs +++ b/src/mananger/mod.rs @@ -4,28 +4,46 @@ pub mod messages; mod watch_changer; use std::sync::Arc; +use std::time::Duration; +use self::watch_changer::watch_changes; +use crate::dictionary::pb_messages::PbMessages; use crate::errors::error::Result; +use crate::settings::extensions::plugin::Plugin; +use crate::tr::save::Save; +use crate::{lock, settings, tr}; use indicatif::{MultiProgress, ProgressBar}; +use indicatif_log_bridge::LogWrapper; +use lazy_static::lazy_static; use lock::Lock; use log::warn; use manage::manage; use settings::Settings; +use tokio::fs::{self, File}; +use tokio::io::AsyncWriteExt; +use tokio::time::sleep; use tokio::{ sync::{mpsc, Mutex, RwLock}, try_join, }; use tr::load::Load; -use crate::{lock, settings, tr}; - -use self::watch_changer::watch_changes; +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} pub async fn run() -> Result<()> { + let logger = pretty_env_logger::formatted_builder() + .filter_level(log::LevelFilter::Info) + .build(); let (mpb, lock, settings) = init().await?; - // + let mpb_cloned = mpb.as_ref().clone(); + LogWrapper::new(mpb_cloned, logger).try_init().unwrap(); + // Init It! let pb = mpb.add(ProgressBar::new_spinner()); - pb.finish_with_message("Init Minecraft Addon Controller"); + pb.set_message(&DICT.intro); + sleep(Duration::from_secs(1)).await; + pb.finish_and_clear(); // let (tx, rx) = mpsc::channel(20); @@ -50,11 +68,43 @@ pub async fn run() -> Result<()> { } async fn init() -> Result<(Arc, Arc>, Arc>)> { + '_plugin_folder_scope: { + if fs::read_dir(Plugin::PATH).await.is_err() { + fs::create_dir(Plugin::PATH).await? + } + } + '_default_settings_scope: { + let path = ::PATH; + if File::open(path).await.is_err() { + let default = Settings::default(); + warn!("Create default config file"); + let mut file = File::create(path).await?; + let toml_defefault = toml::to_string_pretty(&default)?; + file.write_all(toml_defefault.as_bytes()).await?; + } + } + '_default_lock_scope: { + let path = ::PATH; + if File::open(path).await.is_err() { + let default = Lock::default(); + warn!("Create default Lock file"); + let mut file = File::create(path).await?; + let toml_defefault = toml::to_string_pretty(&default)?; + file.write_all(toml_defefault.as_bytes()).await?; + } + } + '_default_language_scope: { + let path = ::PATH; + if File::open(path).await.is_err() { + let default = PbMessages::default(); + warn!("Create default language file"); + let mut file = File::create(path).await?; + let toml_defefault = toml::to_string_pretty(&default)?; + file.write_all(toml_defefault.as_bytes()).await?; + } + } 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 lock: Arc> = Arc::new(Mutex::new(Lock::load().await?)); 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 index c2f02b9..d4d8c55 100644 --- a/src/mananger/watch_changer.rs +++ b/src/mananger/watch_changer.rs @@ -4,6 +4,7 @@ use std::time::Duration; use async_watcher::notify::RecursiveMode; use async_watcher::AsyncDebouncer; use indicatif::{MultiProgress, ProgressBar}; +use log::debug; use tokio::sync::mpsc::Sender; use tokio::sync::{Mutex, RwLock}; @@ -12,6 +13,12 @@ use crate::mananger::messages::Messages; use crate::tr::load::Load; use crate::{lock::Lock, settings::Settings}; +use crate::dictionary::pb_messages::PbMessages; +use lazy_static::lazy_static; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} /// Load downloader module. /// Always check config file. /// Use `token` for canceling minecraft task @@ -19,7 +26,7 @@ pub async fn watch_changes( settings: Arc>, lock: Arc>, mpb: Arc, - dw_tx: Sender, + manager_tx: Sender, ) -> Result<()> { const CONFIG_PATH: &str = "settings.toml"; // initialize the debouncer @@ -31,36 +38,43 @@ pub async fn watch_changes( .watch(CONFIG_PATH.as_ref(), RecursiveMode::NonRecursive) .unwrap(); + let pb = Arc::new(mpb.add(ProgressBar::new_spinner())); // Check lock { - lock.lock() - .await - .remove_nonexistent(settings.read().await)?; + debug!("Start remove_nonexistent"); + let pb = Arc::clone(&pb); + let settings = Arc::clone(&settings); + lock.lock().await.remove_nonexistent(settings, pb).await; } - let pb = Arc::new(mpb.add(ProgressBar::new_spinner())); // Send start to downloader { - dw_tx.send(Messages::Start(Arc::clone(&pb))).await?; + debug!("Start downloader (message)"); + let pb = Arc::clone(&pb); + manager_tx.send(Messages::Start(pb)).await?; } // wait for events while rx.recv().await.is_some() { + debug!("find iteration"); let pb = Arc::clone(&pb); - pb.set_message("Find some changes in config!"); - let settings = Arc::clone(&settings); + pb.set_message(&DICT.find_changes_in_settings); let settings_new = Settings::load().await?; + let settings = Arc::clone(&settings); if *settings.read().await != settings_new { - pb.set_message("настройки другие"); + pb.set_message(&DICT.settings_changed); *settings.write().await = settings_new; { - lock.lock() - .await - .remove_nonexistent(settings.read().await)?; + debug!("Start remove_nonexistent"); + let pb = Arc::clone(&pb); + lock.lock().await.remove_nonexistent(settings, pb).await; } - pb.set_message("настройки перезаписали"); - dw_tx.send(Messages::Restart(pb)).await?; + debug!("Start downloader (message)"); + pb.set_message(&DICT.settings_has_rewrited); + manager_tx.send(Messages::Restart(pb)).await?; } else { - pb.set_message("настройки теже"); + debug!("Nothing to update (config)"); + pb.set_message(&DICT.settings_same); + pb.finish_and_clear(); } } Ok(()) diff --git a/src/models/cores/paper.rs b/src/models/cores/paper.rs index 0334d2d..b29f6a6 100644 --- a/src/models/cores/paper.rs +++ b/src/models/cores/paper.rs @@ -1,6 +1,14 @@ use indicatif::ProgressBar; use serde::{Deserialize, Serialize}; +use crate::dictionary::pb_messages::PbMessages; +use crate::tr::load::Load; +use lazy_static::lazy_static; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} + use crate::{ errors::error::{Error, Result}, not_found_build_error, not_found_version_error, @@ -50,13 +58,13 @@ impl ModelCore for T { async fn get_link(core: &Core, pb: &ProgressBar) -> Result<(String, ChooseHash, String)> { let core_name = Self::CORE_NAME; // Start work - pb.set_message("Init work"); + pb.set_message(&DICT.init_work); //get data from core let build = core.build(); let version = core.version(); //find link and version - pb.set_message("Finding version"); + pb.set_message(&DICT.finding_version); let version = find_version(version, core_name).await?; let verlink = format!( @@ -64,7 +72,7 @@ impl ModelCore for T { core_name, version ); - pb.set_message("Make link"); + pb.set_message(&DICT.make_link); let build_list: BuildList = reqwest::get(verlink).await?.json().await?; let build_list = build_list.builds.as_slice(); diff --git a/src/models/extensions/modrinth.rs b/src/models/extensions/modrinth.rs index cd2ddd9..a3525c6 100644 --- a/src/models/extensions/modrinth.rs +++ b/src/models/extensions/modrinth.rs @@ -1,9 +1,10 @@ -use log::debug; +use log::trace; use serde::Deserialize; use serde::Serialize; use crate::errors::error::{Error, Result}; use crate::not_found_plugin_error; +use crate::not_found_plugin_link_error; use crate::settings::extensions::plugin::Plugin; use crate::tr::hash::ChooseHash; use crate::tr::model::extension::ModelExtensions; @@ -17,9 +18,9 @@ pub struct ModrinthData { //Always change ich version id: String, //Stable token. - project_id: String, + // project_id: String, files: Vec, - dependencies: Vec, + // dependencies: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -50,38 +51,57 @@ impl ModelExtensions for ModrinthData { game_version: &str, loader: &str, ) -> Result<(Self::Link, ChooseHash, Self::Version)> { - let link: String = { - // TODO: Make normal params! - match game_version { - "Latest" => { - let channel = ext.channel().get_str().await; - let link = format!("https://api.modrinth.com/v2/project/{}/version?&loaders=[\"{}\"]&featured=true&version_type={}", name, loader, channel); - debug!("Plugin: {} -> Link: {}", name, link); - link + let channel = ext.channel().get_str().await.to_string(); + let link = format!("https://api.modrinth.com/v2/project/{}/version", name); + + let loader = { + if loader.to_lowercase() == "purpur" { + "paper" + } else { + loader + } + }; + let query = { + match game_version.to_lowercase().as_str() { + "latest" => { + vec![ + // ("game_version", format!("[\"{}\"]", game_version)), + ("loaders", format!("[\"{}\"]", loader)), + ("featured", true.to_string()), + ("version_type", channel), + ] } + _ => { - let channel = ext.channel().get_str().await; - let link = format!("https://api.modrinth.com/v2/project/{}/version?game_versions=[\"{}\"]&loaders=[\"{}\"]&featured=true&version_type={}", name, game_version, loader, channel); - debug!("Plugin: {} -> Link: {}", name, link); - link + vec![ + ("game_version", format!("[\"{}\"]", game_version)), + ("loaders", format!("[\"{}\"]", loader)), + ("featured", true.to_string()), + ("version_type", channel), + ] } } }; - let modrinth_data: Vec = reqwest::get(link).await?.json().await?; + trace!("query: {:#?}", &query); + let client = reqwest::Client::builder() + .user_agent("TOwInOK/Minecraft-Dependency-Controller (TOwInOK@nothub.ru) TestPoligon") + .build()?; + + let modrinth_data: Vec = + client.get(&link).query(&query).send().await?.json().await?; let modrinth_data = match modrinth_data.first() { Some(e) => Ok(e), None => not_found_plugin_error!(name), }?; - Ok(modrinth_data - .files - .first() - .map(|x| { - ( - x.url.to_string(), - ChooseHash::SHA1(x.hashes.sha1.to_string()), - modrinth_data.id.to_owned(), - ) - }) - .unwrap()) + match modrinth_data.files.first().map(|x| { + ( + x.url.to_string(), + ChooseHash::SHA1(x.hashes.sha1.to_string()), + modrinth_data.id.to_owned(), + ) + }) { + Some(e) => Ok(e), + None => not_found_plugin_link_error!(name), + } } } diff --git a/src/settings/additions.rs b/src/settings/additions.rs index 15a6bfe..82c309f 100644 --- a/src/settings/additions.rs +++ b/src/settings/additions.rs @@ -10,15 +10,15 @@ pub struct Additions { key: Option, // duraction of delay between download intervals #[serde(default = "duraction_default")] - duraction: Option, + duraction: Option, } -fn duraction_default() -> Option { - Some(300f64) +fn duraction_default() -> Option { + Some(300) } impl Additions { - pub fn new(source: Option, key: Option, duraction: Option) -> Self { + pub fn new(source: Option, key: Option, duraction: Option) -> Self { Self { source, key, @@ -34,7 +34,7 @@ impl Additions { self.key.as_ref() } - pub fn duraction(&self) -> Option { + pub fn duraction(&self) -> Option { self.duraction } } diff --git a/src/settings/core.rs b/src/settings/core.rs index 7b1f0b0..7530df7 100644 --- a/src/settings/core.rs +++ b/src/settings/core.rs @@ -1,24 +1,29 @@ -use std::sync::Arc; -use std::time::Duration; +use crate::tr::load::Load; +use std::{sync::Arc, time::Duration}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use log::debug; +use lazy_static::lazy_static; +use log::{debug, trace}; use serde::{Deserialize, Serialize}; -use tokio::sync::Mutex; -use tokio::time::sleep; - -use crate::errors::error::Result; -use crate::lock::core::CoreMeta; -use crate::lock::Lock; -use crate::models::cores::folia::Folia; -use crate::models::cores::paper::Paper; -use crate::models::cores::purpur::Purpur; -use crate::models::cores::vanilla::Vanilla; -use crate::models::cores::velocity::Velocity; -use crate::models::cores::waterfall::Waterfall; -use crate::tr::hash::ChooseHash; -use crate::tr::model::core::ModelCore; -use crate::tr::{download::Download, save::Save}; +use tokio::{sync::Mutex, time::sleep}; + +use crate::{ + dictionary::pb_messages::PbMessages, + errors::error::Result, + lock::{core::CoreMeta, Lock}, + models::cores::{ + folia::Folia, paper::Paper, purpur::Purpur, vanilla::Vanilla, velocity::Velocity, + waterfall::Waterfall, + }, + pb, + tr::{ + delete::Delete, download::Download, hash::ChooseHash, model::core::ModelCore, save::Save, + }, +}; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} #[derive(Deserialize, Serialize, Debug, Default, PartialEq, Clone)] pub struct Core { @@ -26,6 +31,7 @@ pub struct Core { #[serde(default)] provider: Provider, // Версия ядра + // Change to Enum! #[serde(default = "version")] version: String, // Версия билда ядра @@ -91,31 +97,48 @@ 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}", - )?); - pb.set_prefix(self.provider.as_str()); - // Check meta + let pb = pb!(mpb, self.provider.as_str()); let (link, hash, build) = self.get_link(&pb).await?; - + trace!("link: {}, hash: {}", &link, &hash); if let Some(e) = lock.lock().await.core().build() { - debug!("lock build: {} / build: {}", &e, &build); + trace!("lock build: {} / build: {}", &e, &build); if *e == build && (!self.force_update || self.freeze) { - pb.set_message("Does't need to update"); + pb.set_message(&DICT.doest_need_to_update); sleep(Duration::from_secs(1)).await; pb.finish_and_clear(); return Ok(()); } } + pb.set_message(&DICT.download_file); let file = Core::get_file(link, hash, &pb).await?; - pb.set_message("Saving file"); + debug!("file: => {} | got", self.provider().as_str()); + debug!("file: => {} | saving", self.provider().as_str()); + + pb.set_message(&DICT.delete_exist_version); + { + self.delete(lock.lock().await.core().path()).await; + } + + pb.set_message(&DICT.saving_file); Core::save_bytes(file, self.provider().as_str()).await?; - *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; + + debug!("file: => {} | saved", self.provider().as_str()); + debug!("Data: => {} | start locking", self.provider().as_str()); + + pb.set_message(&DICT.write_to_lock); + { + let mut lock = lock.lock().await; + *lock.core_mut() = self.clone().to_meta(build); + lock.save().await?; + } + + debug!( + "Data: => {} | written into lock file", + self.provider().as_str() + ); + + pb.set_message(&DICT.done); pb.finish_and_clear(); Ok(()) } @@ -141,10 +164,10 @@ pub enum Provider { Vanilla, // done Paper, // done Folia, // done - Purpur, // in work, good api + Purpur, // done, good api Fabric, // in work, api with out hash //https://meta.fabricmc.net/v2/versions/game <- version check /v2/versions/intermediary give only stable - // or https://meta.fabricmc.net/v1/versions/game/1.14.4. Если нет версии, ответ пуст. + // or https://meta.fabricmc.net/v1/versions/game/1.14.4. If version is empty, response is empty. Forge, //no api NeoForge, //worst api Waterfall, // done @@ -171,3 +194,4 @@ impl Download for Core {} impl Save for Core { const PATH: &'static str = "./"; } +impl Delete for Core {} diff --git a/src/settings/extensions/plugin.rs b/src/settings/extensions/plugin.rs index 3a7860c..b3338a7 100644 --- a/src/settings/extensions/plugin.rs +++ b/src/settings/extensions/plugin.rs @@ -2,8 +2,12 @@ use serde::{Deserialize, Serialize}; use crate::errors::error::Result; use crate::models::extensions::modrinth::ModrinthData; +use crate::tr::download::Download; use crate::tr::hash::ChooseHash; use crate::tr::model::extension::ModelExtensions; +use crate::tr::save::Save; + +const PATH: &str = "./plugins/"; #[derive(Deserialize, Serialize, Debug, PartialEq, Default, Clone)] pub struct Plugin { @@ -86,3 +90,8 @@ impl Channels { } } } + +impl Download for Plugin {} +impl Save for Plugin { + const PATH: &'static str = PATH; +} diff --git a/src/settings/extensions/plugins.rs b/src/settings/extensions/plugins.rs index 369f2e7..c1ab3d9 100644 --- a/src/settings/extensions/plugins.rs +++ b/src/settings/extensions/plugins.rs @@ -1,22 +1,27 @@ +use crate::tr::load::Load; use std::collections::HashMap; use std::sync::Arc; -use std::time::Duration; use futures_util::future::join_all; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use lazy_static::lazy_static; +use log::debug; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use tokio::task::JoinHandle; -use tokio::time::sleep; +use super::plugin::Plugin; +use crate::dictionary::pb_messages::PbMessages; use crate::errors::error::Result; use crate::lock::ext::ExtensionMeta; use crate::lock::Lock; +use crate::pb; +use crate::tr::hash::ChooseHash; use crate::tr::{download::Download, save::Save}; -use super::plugin::Plugin; - -const PATH: &str = "./plugins/"; +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} #[derive(Deserialize, Serialize, Debug, Default, PartialEq)] pub struct Plugins(HashMap); @@ -37,68 +42,88 @@ impl Plugins { lock: Arc>, mpb: Arc, ) -> Result<()> { + let link_list = self.check_plugins(game_version, loader, mpb, &lock).await?; + let handler_list = make_handle_list(link_list, lock)?; + join_all(handler_list).await; + Ok(()) + } + + /// Check lock extensions with config extesions + async fn check_plugins( + &self, + game_version: &str, + loader: &str, + mpb: Arc, + lock: &Arc>, + ) -> Result> { let mut link_list = Vec::new(); - let mut handler_list: Vec>> = Vec::new(); - // Make link_list - // Check plugins in List - for (name, plugin) in self.0.clone() { + for (name, plugin) in self.0.iter() { + debug!("check extension: {}", &name); // Get link - let (link, hash, build) = plugin.get_link(&name, game_version, loader).await?; - // PB init - let pb = mpb.add(ProgressBar::new_spinner()); - // PB style - pb.set_style( - ProgressStyle::with_template( - "Package:: {prefix:.blue} >>>{spinner:.green} {msg:.blue} > eta: {eta:.blue}", - ) - .unwrap(), - ); - pb.set_prefix(name.clone()); + let (link, hash, build) = plugin.get_link(name, game_version, loader).await?; + debug!("got a link to the extesion: {}", &name); + let pb = pb!(mpb, name); + debug!("check meta: {}", &name); // Check meta - if let Some(plugin_meta) = lock.lock().await.plugins().get(&name) { + if let Some(plugin_meta) = lock.lock().await.plugins().get(name) { let local_build = plugin_meta.build(); // Need to download? if *local_build == build && !plugin.force_update() || plugin.freeze() { - pb.set_message("Does't need to update"); - sleep(Duration::from_secs(1)).await; + debug!("Does't need to update: {}", &name); + pb.set_message(&DICT.doest_need_to_update); pb.finish_and_clear(); continue; } } + debug!("add link to list: {}", &name); link_list.push((link, hash, build, name.to_owned(), pb)) } - // Make handler_list - for (link, hash, build, name, pb) in link_list { - let lock = Arc::clone(&lock); - - handler_list.push(tokio::spawn(async move { - // get file - let file = Plugin::get_file(link, hash, &pb).await?; - pb.set_message("Remove exist version"); - // 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.lock().await.plugins_mut().insert(name.to_string(), { - ExtensionMeta::new(build, format!("{}{}.jar", PATH, name)) - }); - lock.lock().await.save().await?; - pb.set_message("Done"); - sleep(Duration::from_secs(1)).await; - pb.finish_and_clear(); - Ok(()) - })); - } - join_all(handler_list).await; - Ok(()) + Ok(link_list) } } -impl Download for Plugin {} -impl Save for Plugin { - const PATH: &'static str = PATH; +/// Create list with futures to download +fn make_handle_list( + link_list: Vec<(String, ChooseHash, String, String, ProgressBar)>, + lock: Arc>, +) -> Result>>> { + let mut handler_list: Vec>> = Vec::new(); + for (link, hash, build, name, pb) in link_list { + let lock = Arc::clone(&lock); + handler_list.push(tokio::spawn(async move { + // get file + let file = Plugin::get_file(link, hash, &pb).await?; + + debug!("Remove exist version of {}", &name); + { + pb.set_message(&DICT.delete_exist_version); + lock.lock().await.remove_plugin(&name).await; + } + debug!("Saving {}", &name); + + pb.set_message(&DICT.saving_file); + Plugin::save_bytes(file, &name).await?; + + debug!("Write data to lock file {}", &name); + + pb.set_message(&DICT.write_to_lock); + { + lock.lock() + .await + .plugins_mut() + .update(name.to_string(), { + ExtensionMeta::new(build, Plugin::PATH, &name) + }) + .await; + } + debug!("Save meta data to lock of {}", &name); + + lock.lock().await.save().await?; + pb.set_message(&DICT.done); + + pb.finish_and_clear(); + Ok(()) + })); + } + Ok(handler_list) } diff --git a/src/tr/delete.rs b/src/tr/delete.rs new file mode 100644 index 0000000..29747f6 --- /dev/null +++ b/src/tr/delete.rs @@ -0,0 +1,18 @@ +use async_trait::async_trait; +use log::warn; +use tokio::fs; + +#[async_trait] +pub trait Delete { + /// Delete file from the file system + async fn delete(&self, path: &str) { + if !path.is_empty() { + match fs::remove_file(path).await { + Ok(_) => {} + Err(e) => { + warn!("IO error: {}, with path: {}", e, path) + } + }; + } + } +} diff --git a/src/tr/download.rs b/src/tr/download.rs index 7a2b135..fa3ef36 100644 --- a/src/tr/download.rs +++ b/src/tr/download.rs @@ -1,38 +1,61 @@ +use super::hash::ChooseHash; use crate::errors::error::Result; +use async_trait::async_trait; use bytes::{Bytes, BytesMut}; use futures_util::StreamExt; use indicatif::ProgressBar; -use super::hash::ChooseHash; +use crate::dictionary::pb_messages::PbMessages; +use crate::tr::load::Load; +use lazy_static::lazy_static; + +lazy_static! { + static ref DICT: PbMessages = PbMessages::load_sync().unwrap(); +} + +#[async_trait] pub trait Download { - fn get_file( - link: String, - hash: ChooseHash, - pb: &ProgressBar, - ) -> impl std::future::Future> + Send { - async move { - // make reqwest - let response = reqwest::get(link).await?; - // know size of file - let size = response.content_length().unwrap_or(0); - pb.set_length(size); + async fn get_file(link: String, hash: ChooseHash, pb: &ProgressBar) -> Result { + // make reqwest + let response = reqwest::get(link).await?; + // know size of file + let size = response.content_length().unwrap_or(0); + pb.set_length(size); - pb.set_message("Download..."); + pb.set_message(&DICT.download_file); - let mut size_upload = 0_u64; - let mut content = BytesMut::new(); - let mut a = response.bytes_stream(); - while let Some(chunk) = a.next().await { - let chunk = chunk?; - size_upload += chunk.len() as u64; - pb.set_position(size_upload); - content.extend_from_slice(&chunk) - } - pb.set_message("Calculate hash..."); - hash.calculate_hash(&*content).await?; - // End - pb.set_message("Downloaded!"); - Ok(content.freeze()) + let mut size_upload = 0_u64; + let mut content = BytesMut::new(); + let mut a = response.bytes_stream(); + while let Some(chunk) = a.next().await { + let chunk = chunk?; + size_upload += chunk.len() as u64; + pb.set_position(size_upload); + content.extend_from_slice(&chunk) } + pb.set_message(&DICT.calculate_hash); + hash.calculate_hash(&*content).await?; + // End + pb.set_message(&DICT.file_downloaded); + Ok(content.freeze()) } } + +/// Make progress bar with template +/// +/// ` Package:: {PackageName} >>>{spinner} {msg} > eta: {eta} ` +#[macro_export] +macro_rules! pb { + ($mpb:expr, $name:expr) => {{ + let name = $name.to_string(); + 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_prefix(name.clone()); + pb + }}; +} diff --git a/src/tr/hash.rs b/src/tr/hash.rs index 1bc3d65..cbdc635 100644 --- a/src/tr/hash.rs +++ b/src/tr/hash.rs @@ -22,7 +22,7 @@ impl ChooseHash { match self { ChooseHash::SHA1(e) => { let mut hashed = ::new(); - let mut buffer = Vec::::new(); + let mut buffer = [0; 32]; while let Ok(n) = reader.read(&mut buffer).await { if n == 0 { break; @@ -33,12 +33,15 @@ impl ChooseHash { if e.eq(&format!("{:x}", result)) { Ok(()) } else { - Err(Error::CompareHash(CompareHashError::HashNotCompare())) + Err(Error::CompareHash(CompareHashError::HashNotCompare( + e.to_owned(), + format!("{:x}", result), + ))) } } ChooseHash::SHA256(e) => { let mut hashed = ::new(); - let mut buffer = Vec::::new(); + let mut buffer = [0; 32]; while let Ok(n) = reader.read(&mut buffer).await { if n == 0 { break; @@ -49,12 +52,15 @@ impl ChooseHash { if e.eq(&format!("{:x}", result)) { Ok(()) } else { - Err(Error::CompareHash(CompareHashError::HashNotCompare())) + Err(Error::CompareHash(CompareHashError::HashNotCompare( + e.to_owned(), + format!("{:x}", result), + ))) } } ChooseHash::MD5(e) => { let mut hashed = ::new(); - let mut buffer = Vec::::new(); + let mut buffer = [0; 32]; while let Ok(n) = reader.read(&mut buffer).await { if n == 0 { break; @@ -65,7 +71,10 @@ impl ChooseHash { if e.eq(&format!("{:x}", result)) { Ok(()) } else { - Err(Error::CompareHash(CompareHashError::HashNotCompare())) + Err(Error::CompareHash(CompareHashError::HashNotCompare( + e.to_owned(), + format!("{:x}", result), + ))) } } ChooseHash::None => Ok(()), diff --git a/src/tr/load.rs b/src/tr/load.rs index 52a83eb..53c4075 100644 --- a/src/tr/load.rs +++ b/src/tr/load.rs @@ -1,20 +1,36 @@ use crate::errors::error::Result; +use async_trait::async_trait; +use log::debug; use serde::Deserialize; -use tokio::fs; +use tokio::fs::{self}; /// Загружаем с диска нужную нам структуру +#[async_trait] pub trait Load { const PATH: &'static str; - fn load() -> impl std::future::Future> + Send + + async fn load() -> Result where for<'de> Self: Deserialize<'de>, { - async move { - // Читаем с диска - let file = fs::read_to_string(Self::PATH).await?; - // Преобразуем в структуру - let item: Self = toml::from_str(&file)?; - // Выдача результата - Ok(item) - } + // Читаем с диска + debug!("Load file: {:#?}", Self::PATH); + let file = fs::read_to_string(Self::PATH).await?; + // Преобразуем в структуру + let item: Self = toml::from_str(&file)?; + // Выдача результата + Ok(item) + } + fn load_sync() -> Result + where + for<'de> Self: Deserialize<'de>, + { + // Читаем с диска + debug!("Load file: {:#?}", Self::PATH); + + let file = std::fs::read_to_string(Self::PATH)?; + // Преобразуем в структуру + let item: Self = toml::from_str(&file)?; + // Выдача результата + Ok(item) } } diff --git a/src/tr/mod.rs b/src/tr/mod.rs index 421c002..df944d2 100644 --- a/src/tr/mod.rs +++ b/src/tr/mod.rs @@ -1,3 +1,4 @@ +pub mod delete; pub mod download; pub mod hash; pub mod load; diff --git a/src/tr/save.rs b/src/tr/save.rs index 57fc1aa..80c33f6 100644 --- a/src/tr/save.rs +++ b/src/tr/save.rs @@ -1,57 +1,51 @@ use crate::errors::error::{Error, Result}; use crate::not_found_path; +use async_trait::async_trait; use bytes::Bytes; +use log::debug; use std::path::Path; use tokio::fs::File; use tokio::io::AsyncWriteExt; /// Сохраняем структуру на диск +#[async_trait] pub trait Save { const PATH: &'static str; // Save data into file. - fn save(&self) -> impl std::future::Future> + Send + async fn save(&self) -> Result<()> where Self: serde::ser::Serialize + Sync, { - async move { - { - // Сериализуем в понятный человеку томл - let toml_content = toml::to_string_pretty(&self)?; + // Сериализуем в понятный человеку томл + let toml_content = toml::to_string_pretty(&self)?; + debug!("Save content: {}", Self::PATH); + // Откроем для записи + let mut file = File::create(Self::PATH).await?; - // Откроем для записи - let mut file = File::create(Self::PATH).await?; + // Запишем файл + file.write_all(toml_content.as_bytes()).await?; - // Запишем файл - file.write_all(toml_content.as_bytes()).await?; - - Ok(()) - } - } + Ok(()) } // Create file by data - fn save_bytes( - bytes: Bytes, - name: &str, - ) -> impl std::future::Future> + Send { - async move { - { - // Конвертируем &str в Path - let path_to_dir = Path::new(Self::PATH); - // Проверить путь на исправность - if !path_to_dir.exists() { - return not_found_path!(Self::PATH); - } - // Добавляем имя к пути - let path_to_file = path_to_dir.join(format!("{}.jar", name)); + async fn save_bytes(bytes: Bytes, name: &str) -> Result<()> { + // Конвертируем &str в Path + let path_to_dir = Path::new(Self::PATH); + // Проверить путь на исправность + if !path_to_dir.exists() { + return not_found_path!(Self::PATH); + } + debug!("path to dir: {:#?}", path_to_dir.to_str()); + // Добавляем имя к пути + let path_to_file = path_to_dir.join(format!("{}.jar", name)); - // Откроем для записи - let mut file = File::create(path_to_file).await?; + debug!("path to file: {:#?}", path_to_file.to_str()); + // Откроем для записи + let mut file = File::create(path_to_file).await?; - // Запишем файл - file.write_all(&bytes).await?; + // Запишем файл + file.write_all(&bytes).await?; - Ok(()) - } - } + Ok(()) } }