From 2dde29699499c3b4586c27e07dd59f77d2833b9d Mon Sep 17 00:00:00 2001 From: Yuto Liyosa Date: Mon, 13 May 2024 12:51:00 +0330 Subject: [PATCH] Initial commit --- .github/workflows/release.yml | 22 ++ .gitignore | 1 + Cargo.lock | 578 ++++++++++++++++++++++++++++++++++ Cargo.toml | 11 + README.md | 45 +++ assets/nekobar_01.png | Bin 0 -> 26157 bytes src/main.rs | 134 ++++++++ 7 files changed, 791 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 assets/nekobar_01.png create mode 100644 src/main.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..78cfc0f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +on: + release: + types: [created] + +jobs: + release: + permissions: write-all + name: release ${{ matrix.target }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: [x86_64-unknown-linux-musl] + steps: + - uses: actions/checkout@master + - name: Compile and release + uses: rust-build/rust-build.action@v1.4.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + RUSTTARGET: ${{ matrix.target }} + EXTRA_FILES: "README.md" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..daa8284 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,578 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "clashctl-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869f6575816b2745c16d9e017d605f6f3775c9bcd02a9759bee60dcaf1511709" +dependencies = [ + "cfg-if", + "log", + "serde", + "serde_json", + "thiserror", + "ureq", + "url", + "urlencoding", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "nekobar" +version = "0.1.0" +dependencies = [ + "bytesize", + "clap", + "clashctl-core", + "dirs", + "serde_json", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "ureq" +version = "2.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" +dependencies = [ + "base64", + "log", + "once_cell", + "url", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c5aec24 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "nekobar" +version = "0.1.0" +edition = "2021" + +[dependencies] +clashctl-core = "0.4.2" +clap = { version = "4.5.4", features = ["derive"] } +bytesize = "1.3.0" +serde_json = "1.0.117" +dirs = "5.0.1" diff --git a/README.md b/README.md new file mode 100644 index 0000000..8fa0a7e --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Nekobar + +A simple NekoBox status bar module for Waybar. + +![Nekobar](./assets/nekobar_01.png) + +## Features + +- Active profile name +- Tooltip + - Connection count + - Download speed + - Upload speed + - Max download speed + - Max upload speed + - Total download + - Total upload + +## Installation + +1. Compile using `cargo build --release`, or download the binary from the [releases](https://github.com/MrYuto/nekobar/releases/latest) page. +2. Enable NekoBox Clash API from `Preferences > Basic Settings > Core > Core Options > Enable Clash API`. +3. Enable remember last profile from `Program > Remember last profile` + +## Waybar config + +```json + "custom/nekobar": { + "tooltip": true, + "exec": "/path/to/nekobar", + "return-type": "json", + } +``` + +## Usage + +```sh +Usage: nekobar [OPTIONS] + +Options: + -p, --port Clash API port [default: 9090] + -i, --interval Update interval in seconds [default: 1] + -h, --help Print help + -V, --version Print version +``` \ No newline at end of file diff --git a/assets/nekobar_01.png b/assets/nekobar_01.png new file mode 100644 index 0000000000000000000000000000000000000000..a33dceb3e13821b0c105937975d7c3e9a35d24ee GIT binary patch literal 26157 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 String { + ByteSize(value) + .to_string_as(false) + .to_lowercase() + .replace(" ", "") +} + +fn print(text: String, tooltip: String) { + let data = json!({ + "alt": "", + "class": "", + "percentage": 0, + "text": text, + "tooltip": tooltip, + }); + + println!("{data}"); +} + +fn main() { + let args = Cli::parse(); + let nekoray_config_dir = dirs::config_dir().unwrap().join("nekoray/config/"); + let url = format!("http://127.0.0.1:{}", args.port); + let clash = ClashBuilder::new(url).unwrap().build(); + let mut max_up = 0; + let mut max_down = 0; + let mut last = Instant::now(); + + loop { + if let Ok(traffics) = clash.get_traffic() { + let nekobox_config: serde_json::Value = serde_json::from_str( + read_to_string(nekoray_config_dir.join("groups/nekobox.json")) + .expect("Failed to read nekobox.json") + .as_str(), + ) + .unwrap(); + + let remember_id = nekobox_config + .get("remember_id") + .expect("remember_id is missing from nekobox.json") + .as_u64() + .unwrap(); + + let nekoray_profile: serde_json::Value = serde_json::from_str( + read_to_string(nekoray_config_dir.join(format!("profiles/{remember_id}.json"))) + .expect("Failed to read the profile") + .as_str(), + ) + .unwrap(); + + let profile_name = nekoray_profile + .get("bean") + .unwrap() + .get("name") + .unwrap() + .as_str() + .unwrap(); + + for traffic in traffics { + match traffic { + Ok(traffic) => { + let now: Instant = Instant::now(); + + if traffic.up > max_up { + max_up = traffic.up + } + + if traffic.down > max_down { + max_down = traffic.down + } + + if now.duration_since(last).as_secs() < args.interval { + continue; + } else { + last = now + } + + let current_upload = format_byte(traffic.up) + "/s"; + let current_download = format_byte(traffic.down) + "/s"; + let max_upload = format_byte(max_up) + "/s"; + let max_download = format_byte(max_down) + "/s"; + let mut total_upload = String::new(); + let mut total_download = String::new(); + let mut connection_count = String::new(); + + if let Ok(conn) = clash.get_connections() { + connection_count = conn.connections.len().to_string(); + total_upload = format_byte(conn.upload_total); + total_download = format_byte(conn.download_total); + } + + let speed_text = format!(" {current_download}  {current_upload}"); + let max_speed_text = format!("Max:  {max_download}  {max_upload}"); + let total_text = format!("Total:  {total_download}  {total_upload}"); + + print( + format!("{profile_name}"), + format!( + " {connection_count} {speed_text}\n{max_speed_text}\n{total_text}" + ), + ) + } + + Err(_) => break, + } + } + + print(String::new(), String::new()) + } + + sleep(Duration::from_secs(5)) + } +}