From 91c80d0f916f839bba93df95c663f3d73d1f101e Mon Sep 17 00:00:00 2001 From: D0RYU Date: Sat, 26 Apr 2025 11:52:46 -0400 Subject: [PATCH 1/3] feat: add telemetry subcrate --- Cargo.lock | 375 +++++++++--- Cargo.toml | 4 +- src/lib.rs | 2 +- subcrates/telemetry/Cargo.toml | 21 + subcrates/telemetry/build.rs | 33 ++ subcrates/telemetry/src/languages.json | 684 ++++++++++++++++++++++ subcrates/telemetry/src/lib.rs | 714 +++++++++++++++++++++++ subcrates/telemetry/src/main.rs | 3 + subcrates/telemetry/src/territories.json | 318 ++++++++++ 9 files changed, 2085 insertions(+), 69 deletions(-) create mode 100644 subcrates/telemetry/Cargo.toml create mode 100644 subcrates/telemetry/build.rs create mode 100644 subcrates/telemetry/src/languages.json create mode 100644 subcrates/telemetry/src/lib.rs create mode 100644 subcrates/telemetry/src/main.rs create mode 100644 subcrates/telemetry/src/territories.json diff --git a/Cargo.lock b/Cargo.lock index fb809d9..f5e5a29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", "zerocopy 0.7.35", @@ -456,9 +456,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.19" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -563,6 +563,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -576,8 +586,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", "foreign-types", "libc", ] @@ -589,7 +599,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", "libc", ] @@ -648,6 +669,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "detect-desktop-environment" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7f16599c3ba6b4ab9a3195bcd9413a7ee8d51e7651f3e9efd6a5db5315008d" + [[package]] name = "diff" version = "0.1.13" @@ -660,6 +687,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", +] + [[package]] name = "dlib" version = "0.5.2" @@ -849,9 +886,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -940,7 +977,7 @@ dependencies = [ "log", "presser", "thiserror 1.0.69", - "windows", + "windows 0.58.0", ] [[package]] @@ -1010,6 +1047,28 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hidapi" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "pkg-config", + "windows-sys 0.48.0", +] + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -1022,7 +1081,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.0", ] [[package]] @@ -1188,9 +1247,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libfuzzer-sys" @@ -1214,9 +1273,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -1317,7 +1376,22 @@ checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ "bitflags 2.9.0", "block", - "core-graphics-types", + "core-graphics-types 0.1.3", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "metal" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +dependencies = [ + "bitflags 2.9.0", + "block", + "core-graphics-types 0.2.0", "foreign-types", "log", "objc", @@ -1427,6 +1501,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1536,9 +1619,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" dependencies = [ "objc2-encode", ] @@ -1597,12 +1680,13 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "dispatch2", + "objc2 0.6.1", ] [[package]] @@ -1650,12 +1734,12 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", ] @@ -1685,13 +1769,13 @@ dependencies = [ [[package]] name = "objc2-metal" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c41bc8b0e50ea7a5304a56f25e0066f526e99641b46fd7b9ad4421dd35bff6" +checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -1709,15 +1793,15 @@ dependencies = [ [[package]] name = "objc2-quartz-core" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-metal 0.3.0", + "objc2-foundation 0.3.1", + "objc2-metal 0.3.1", ] [[package]] @@ -1950,7 +2034,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.25", ] [[package]] @@ -1980,9 +2064,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -2072,7 +2156,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2143,10 +2227,10 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-quartz-core 0.3.0", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", ] [[package]] @@ -2370,9 +2454,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -2518,15 +2602,37 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "libc", +] + +[[package]] +name = "sysinfo" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "windows 0.57.0", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -2546,6 +2652,24 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "telemetry" +version = "0.1.0" +dependencies = [ + "ash", + "chrono", + "detect-desktop-environment", + "hidapi", + "humansize", + "metal 0.32.0", + "serde", + "serde_json", + "sys-locale", + "sysinfo", + "wgpu", + "winit", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -2658,9 +2782,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" dependencies = [ "serde", "serde_spanned", @@ -2670,18 +2794,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" dependencies = [ "indexmap", "serde", @@ -3190,7 +3314,7 @@ dependencies = [ "bytemuck", "cfg-if", "cfg_aliases", - "core-graphics-types", + "core-graphics-types 0.1.3", "glow", "glutin_wgl_sys", "gpu-alloc", @@ -3202,7 +3326,7 @@ dependencies = [ "libc", "libloading", "log", - "metal", + "metal 0.31.0", "naga", "ndk-sys 0.5.0+25.2.9519653", "objc", @@ -3218,8 +3342,8 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "windows", - "windows-core", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] @@ -3267,13 +3391,35 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets 0.52.6", ] @@ -3283,13 +3429,37 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings 0.4.0", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -3301,6 +3471,28 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.58.0" @@ -3312,12 +3504,32 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -3327,16 +3539,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -3346,6 +3576,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[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" @@ -3557,7 +3796,7 @@ dependencies = [ "calloop", "cfg_aliases", "concurrent-queue", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "cursor-icon", "dpi", @@ -3596,9 +3835,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -3689,6 +3928,8 @@ dependencies = [ "bytemuck", "cgmath", "image", + "serde", + "serde_json", "smol", "terminator", "thiserror 2.0.12", @@ -3712,11 +3953,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.25", ] [[package]] @@ -3732,9 +3973,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 732a166..f29ab09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ crate-type = ["cdylib"] [workspace] resolver = "2" -members = ["subcrates/renderer", "subcrates/zlog"] +members = ["subcrates/renderer", "subcrates/telemetry", "subcrates/zlog"] [workspace.dependencies] zlog = { path = "subcrates/zlog" } @@ -55,6 +55,8 @@ vulkano = "0.35.1" wgpu = { version = "25.0.0", features = ["spirv"] } zlog.workspace = true allocator-api2 = "0.2.21" +serde_json = "1.0.140" +serde = "1.0.219" [target.aarch64-linux-android.dependencies] winit = { version = "0.30.9", features = ["android-native-activity"] } diff --git a/src/lib.rs b/src/lib.rs index d5be06a..f9a73ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1 @@ -include!("main.rs"); +include!("main.rs"); \ No newline at end of file diff --git a/subcrates/telemetry/Cargo.toml b/subcrates/telemetry/Cargo.toml new file mode 100644 index 0000000..dfb77fe --- /dev/null +++ b/subcrates/telemetry/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "telemetry" +version = "0.1.0" +edition = "2024" + +[dependencies] +ash = "0.38.0" +chrono = "0.4.40" +detect-desktop-environment = "1.2.0" +hidapi = "2.6.3" +humansize = "2.1.3" +metal = { version = "0.32.0", optional = true } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" +sys-locale = "0.3.2" +sysinfo = "0.34.2" +wgpu = "25.0.0" +winit = "0.30.9" + +[features] +metal = ["dep:metal"] diff --git a/subcrates/telemetry/build.rs b/subcrates/telemetry/build.rs new file mode 100644 index 0000000..fc44b31 --- /dev/null +++ b/subcrates/telemetry/build.rs @@ -0,0 +1,33 @@ +use std::{env, fs::File, io::Write, process::Command}; + +fn main() { + let out_dir = env::var("OUT_DIR").unwrap(); + let mut f = File::create(format!("{}/built.rs", out_dir)).unwrap(); + + let commit_hash = Command::new("git") + .args(["rev-parse", "HEAD"]) + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or_else(|| "unknown".into()); + + let commit_short_hash = Command::new("git") + .args(["rev-parse", "--short", "HEAD"]) + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or_else(|| "unknown".into()); + + writeln!( + f, + "pub const GIT_COMMIT_HASH: &str = \"{}\";", + commit_hash.trim() + ) + .unwrap(); + writeln!( + f, + "pub const GIT_COMMIT_SHORT_HASH: &str = \"{}\";", + commit_short_hash.trim() + ) + .unwrap(); +} diff --git a/subcrates/telemetry/src/languages.json b/subcrates/telemetry/src/languages.json new file mode 100644 index 0000000..6c9fc28 --- /dev/null +++ b/subcrates/telemetry/src/languages.json @@ -0,0 +1,684 @@ +{ + "aa": "Afar", + "ab": "Abkhazian", + "ace": "Acehnese", + "ach": "Acoli", + "ada": "Adangme", + "ady": "Adyghe", + "ae": "Avestan", + "aeb": "Tunisian Arabic", + "af": "Afrikaans", + "afh": "Afrihili", + "agq": "Aghem", + "ain": "Ainu", + "ak": "Akan", + "akk": "Akkadian", + "akz": "Alabama", + "ale": "Aleut", + "aln": "Gheg Albanian", + "alt": "Southern Altai", + "am": "Amharic", + "an": "Aragonese", + "ang": "Old English", + "ann": "Obolo", + "anp": "Angika", + "ar": "Arabic", + "ar-001": "Modern Standard Arabic", + "arc": "Aramaic", + "arn": "Mapuche", + "aro": "Araona", + "arp": "Arapaho", + "arq": "Algerian Arabic", + "ars": "Najdi Arabic", + "ars-alt-menu": "Arabic, Najdi", + "arw": "Arawak", + "ary": "Moroccan Arabic", + "arz": "Egyptian Arabic", + "as": "Assamese", + "asa": "Asu", + "ase": "American Sign Language", + "ast": "Asturian", + "atj": "Atikamekw", + "av": "Avaric", + "avk": "Kotava", + "awa": "Awadhi", + "ay": "Aymara", + "az": "Azerbaijani", + "az-alt-short": "Azeri", + "ba": "Bashkir", + "bal": "Baluchi", + "ban": "Balinese", + "bar": "Bavarian", + "bas": "Basaa", + "bax": "Bamun", + "bbc": "Batak Toba", + "bbj": "Ghomala", + "be": "Belarusian", + "bej": "Beja", + "bem": "Bemba", + "bew": "Betawi", + "bez": "Bena", + "bfd": "Bafut", + "bfq": "Badaga", + "bg": "Bulgarian", + "bgc": "Haryanvi", + "bgn": "Western Balochi", + "bho": "Bhojpuri", + "bi": "Bislama", + "bik": "Bikol", + "bin": "Bini", + "bjn": "Banjar", + "bkm": "Kom", + "bla": "Siksika", + "blo": "Anii", + "blt": "Tai Dam", + "bm": "Bambara", + "bn": "Bangla", + "bo": "Tibetan", + "bpy": "Bishnupriya", + "bqi": "Bakhtiari", + "br": "Breton", + "bra": "Braj", + "brh": "Brahui", + "brx": "Bodo", + "bs": "Bosnian", + "bss": "Akoose", + "bua": "Buriat", + "bug": "Buginese", + "bum": "Bulu", + "byn": "Blin", + "byv": "Medumba", + "ca": "Catalan", + "cad": "Caddo", + "car": "Carib", + "cay": "Cayuga", + "cch": "Atsam", + "ccp": "Chakma", + "ce": "Chechen", + "ceb": "Cebuano", + "cgg": "Chiga", + "ch": "Chamorro", + "chb": "Chibcha", + "chg": "Chagatai", + "chk": "Chuukese", + "chm": "Mari", + "chn": "Chinook Jargon", + "cho": "Choctaw", + "chp": "Chipewyan", + "chr": "Cherokee", + "chy": "Cheyenne", + "cic": "Chickasaw", + "ckb": "Central Kurdish", + "ckb-alt-menu": "Kurdish, Central", + "ckb-alt-variant": "Kurdish, Sorani", + "clc": "Chilcotin", + "co": "Corsican", + "cop": "Coptic", + "cps": "Capiznon", + "cr": "Cree", + "cr-alt-long": "Woods Cree", + "crg": "Michif", + "crh": "Crimean Tatar", + "crj": "Southern East Cree", + "crk": "Plains Cree", + "crl": "Northern East Cree", + "crm": "Moose Cree", + "crr": "Carolina Algonquian", + "crs": "Seselwa Creole French", + "cs": "Czech", + "csb": "Kashubian", + "csw": "Swampy Cree", + "cu": "Church Slavic", + "cv": "Chuvash", + "cy": "Welsh", + "da": "Danish", + "dak": "Dakota", + "dar": "Dargwa", + "dav": "Taita", + "de": "German", + "de-AT": "Austrian German", + "de-CH": "Swiss High German", + "del": "Delaware", + "den": "Slave", + "dgr": "Dogrib", + "din": "Dinka", + "dje": "Zarma", + "doi": "Dogri", + "dsb": "Lower Sorbian", + "dtp": "Central Dusun", + "dua": "Duala", + "dum": "Middle Dutch", + "dv": "Divehi", + "dyo": "Jola-Fonyi", + "dyu": "Dyula", + "dz": "Dzongkha", + "dzg": "Dazaga", + "ebu": "Embu", + "ee": "Ewe", + "efi": "Efik", + "egl": "Emilian", + "egy": "Ancient Egyptian", + "eka": "Ekajuk", + "el": "Greek", + "elx": "Elamite", + "en": "English", + "en-AU": "Australian English", + "en-CA": "Canadian English", + "en-GB": "British English", + "en-GB-alt-short": "UK English", + "en-US": "American English", + "en-US-alt-short": "US English", + "enm": "Middle English", + "eo": "Esperanto", + "es": "Spanish", + "es-419": "Latin American Spanish", + "es-ES": "European Spanish", + "es-MX": "Mexican Spanish", + "esu": "Central Yupik", + "et": "Estonian", + "eu": "Basque", + "ewo": "Ewondo", + "ext": "Extremaduran", + "fa": "Persian", + "fa-AF": "Dari", + "fan": "Fang", + "fat": "Fanti", + "ff": "Fula", + "fi": "Finnish", + "fil": "Filipino", + "fit": "Tornedalen Finnish", + "fj": "Fijian", + "fo": "Faroese", + "fon": "Fon", + "fr": "French", + "fr-CA": "Canadian French", + "fr-CH": "Swiss French", + "frc": "Cajun French", + "frm": "Middle French", + "fro": "Old French", + "frp": "Arpitan", + "frr": "Northern Frisian", + "frs": "Eastern Frisian", + "fur": "Friulian", + "fy": "Western Frisian", + "ga": "Irish", + "gaa": "Ga", + "gag": "Gagauz", + "gan": "Gan Chinese", + "gay": "Gayo", + "gba": "Gbaya", + "gbz": "Zoroastrian Dari", + "gd": "Scottish Gaelic", + "gez": "Geez", + "gil": "Gilbertese", + "gl": "Galician", + "glk": "Gilaki", + "gmh": "Middle High German", + "gn": "Guarani", + "goh": "Old High German", + "gon": "Gondi", + "gor": "Gorontalo", + "got": "Gothic", + "grb": "Grebo", + "grc": "Ancient Greek", + "gsw": "Swiss German", + "gu": "Gujarati", + "guc": "Wayuu", + "gur": "Frafra", + "guz": "Gusii", + "gv": "Manx", + "gwi": "Gwichʼin", + "ha": "Hausa", + "hai": "Haida", + "hak": "Hakka Chinese", + "haw": "Hawaiian", + "hax": "Southern Haida", + "he": "Hebrew", + "hi": "Hindi", + "hi-Latn": "Hindi (Latin)", + "hi-Latn-alt-variant": "Hinglish", + "hif": "Fiji Hindi", + "hil": "Hiligaynon", + "hit": "Hittite", + "hmn": "Hmong", + "hnj": "Hmong Njua", + "ho": "Hiri Motu", + "hr": "Croatian", + "hsb": "Upper Sorbian", + "hsn": "Xiang Chinese", + "ht": "Haitian Creole", + "hu": "Hungarian", + "hup": "Hupa", + "hur": "Halkomelem", + "hy": "Armenian", + "hz": "Herero", + "ia": "Interlingua", + "iba": "Iban", + "ibb": "Ibibio", + "id": "Indonesian", + "ie": "Interlingue", + "ig": "Igbo", + "ii": "Sichuan Yi", + "ik": "Inupiaq", + "ikt": "Western Canadian Inuktitut", + "ilo": "Iloko", + "inh": "Ingush", + "io": "Ido", + "is": "Icelandic", + "it": "Italian", + "iu": "Inuktitut", + "izh": "Ingrian", + "ja": "Japanese", + "jam": "Jamaican Creole English", + "jbo": "Lojban", + "jgo": "Ngomba", + "jmc": "Machame", + "jpr": "Judeo-Persian", + "jrb": "Judeo-Arabic", + "jut": "Jutish", + "jv": "Javanese", + "ka": "Georgian", + "kaa": "Kara-Kalpak", + "kab": "Kabyle", + "kac": "Kachin", + "kaj": "Jju", + "kam": "Kamba", + "kaw": "Kawi", + "kbd": "Kabardian", + "kbl": "Kanembu", + "kcg": "Tyap", + "kde": "Makonde", + "kea": "Kabuverdianu", + "ken": "Kenyang", + "kfo": "Koro", + "kg": "Kongo", + "kgp": "Kaingang", + "kha": "Khasi", + "kho": "Khotanese", + "khq": "Koyra Chiini", + "khw": "Khowar", + "ki": "Kikuyu", + "kiu": "Kirmanjki", + "kj": "Kuanyama", + "kk": "Kazakh", + "kkj": "Kako", + "kl": "Kalaallisut", + "kln": "Kalenjin", + "km": "Khmer", + "kmb": "Kimbundu", + "kn": "Kannada", + "ko": "Korean", + "koi": "Komi-Permyak", + "kok": "Konkani", + "kos": "Kosraean", + "kpe": "Kpelle", + "kr": "Kanuri", + "krc": "Karachay-Balkar", + "kri": "Krio", + "krj": "Kinaray-a", + "krl": "Karelian", + "kru": "Kurukh", + "ks": "Kashmiri", + "ksb": "Shambala", + "ksf": "Bafia", + "ksh": "Colognian", + "ku": "Kurdish", + "kum": "Kumyk", + "kut": "Kutenai", + "kv": "Komi", + "kw": "Cornish", + "kwk": "Kwakʼwala", + "kxv": "Kuvi", + "ky": "Kyrgyz", + "ky-alt-variant": "Kirghiz", + "la": "Latin", + "lad": "Ladino", + "lag": "Langi", + "lah": "Western Panjabi", + "lam": "Lamba", + "lb": "Luxembourgish", + "lez": "Lezghian", + "lfn": "Lingua Franca Nova", + "lg": "Ganda", + "li": "Limburgish", + "lij": "Ligurian", + "lil": "Lillooet", + "liv": "Livonian", + "lkt": "Lakota", + "lmo": "Lombard", + "ln": "Lingala", + "lo": "Lao", + "lol": "Mongo", + "lou": "Louisiana Creole", + "loz": "Lozi", + "lrc": "Northern Luri", + "lsm": "Saamia", + "lt": "Lithuanian", + "ltg": "Latgalian", + "lu": "Luba-Katanga", + "lua": "Luba-Lulua", + "lui": "Luiseno", + "lun": "Lunda", + "luo": "Luo", + "lus": "Mizo", + "luy": "Luyia", + "lv": "Latvian", + "lzh": "Literary Chinese", + "lzz": "Laz", + "mad": "Madurese", + "maf": "Mafa", + "mag": "Magahi", + "mai": "Maithili", + "mak": "Makasar", + "man": "Mandingo", + "mas": "Masai", + "mde": "Maba", + "mdf": "Moksha", + "mdr": "Mandar", + "men": "Mende", + "mer": "Meru", + "mfe": "Morisyen", + "mg": "Malagasy", + "mga": "Middle Irish", + "mgh": "Makhuwa-Meetto", + "mgo": "Metaʼ", + "mh": "Marshallese", + "mi": "Māori", + "mic": "Mi'kmaw", + "min": "Minangkabau", + "mk": "Macedonian", + "ml": "Malayalam", + "mn": "Mongolian", + "mnc": "Manchu", + "mni": "Manipuri", + "moe": "Innu-aimun", + "moh": "Mohawk", + "mos": "Mossi", + "mr": "Marathi", + "mrj": "Western Mari", + "ms": "Malay", + "mt": "Maltese", + "mua": "Mundang", + "mul": "Multiple languages", + "mus": "Creek", + "mus-alt-official": "Mvskoke", + "mwl": "Mirandese", + "mwr": "Marwari", + "mwv": "Mentawai", + "my": "Burmese", + "my-alt-variant": "Myanmar Language", + "mye": "Myene", + "myv": "Erzya", + "mzn": "Mazanderani", + "na": "Nauru", + "nan": "Min Nan Chinese", + "nap": "Neapolitan", + "naq": "Nama", + "nb": "Norwegian Bokmål", + "nd": "North Ndebele", + "nds": "Low German", + "nds-NL": "West Low German", + "ne": "Nepali", + "new": "Newari", + "ng": "Ndonga", + "nia": "Nias", + "niu": "Niuean", + "njo": "Ao Naga", + "nl": "Dutch", + "nl-BE": "Flemish", + "nmg": "Kwasio", + "nn": "Norwegian Nynorsk", + "nnh": "Ngiemboon", + "no": "Norwegian", + "nog": "Nogai", + "non": "Old Norse", + "nov": "Novial", + "nqo": "N’Ko", + "nr": "South Ndebele", + "nso": "Northern Sotho", + "nus": "Nuer", + "nv": "Navajo", + "nwc": "Classical Newari", + "ny": "Nyanja", + "nym": "Nyamwezi", + "nyn": "Nyankole", + "nyo": "Nyoro", + "nzi": "Nzima", + "oc": "Occitan", + "oj": "Ojibwa", + "ojb": "Northwestern Ojibwa", + "ojc": "Central Ojibwa", + "ojs": "Oji-Cree", + "ojw": "Western Ojibwa", + "oka": "Okanagan", + "om": "Oromo", + "or": "Odia", + "os": "Ossetic", + "osa": "Osage", + "ota": "Ottoman Turkish", + "pa": "Punjabi", + "pag": "Pangasinan", + "pal": "Pahlavi", + "pam": "Pampanga", + "pap": "Papiamento", + "pau": "Palauan", + "pcd": "Picard", + "pcm": "Nigerian Pidgin", + "pdc": "Pennsylvania German", + "pdt": "Plautdietsch", + "peo": "Old Persian", + "pfl": "Palatine German", + "phn": "Phoenician", + "pi": "Pali", + "pis": "Pijin", + "pl": "Polish", + "pms": "Piedmontese", + "pnt": "Pontic", + "pon": "Pohnpeian", + "pqm": "Maliseet-Passamaquoddy", + "prg": "Prussian", + "pro": "Old Provençal", + "ps": "Pashto", + "ps-alt-variant": "Pushto", + "pt": "Portuguese", + "pt-BR": "Brazilian Portuguese", + "pt-PT": "European Portuguese", + "qu": "Quechua", + "quc": "Kʼicheʼ", + "qug": "Chimborazo Highland Quichua", + "raj": "Rajasthani", + "rap": "Rapanui", + "rar": "Rarotongan", + "rgn": "Romagnol", + "rhg": "Rohingya", + "rif": "Riffian", + "rm": "Romansh", + "rn": "Rundi", + "ro": "Romanian", + "ro-MD": "Moldavian", + "rof": "Rombo", + "rom": "Romany", + "rtm": "Rotuman", + "ru": "Russian", + "rue": "Rusyn", + "rug": "Roviana", + "rup": "Aromanian", + "rw": "Kinyarwanda", + "rwk": "Rwa", + "sa": "Sanskrit", + "sad": "Sandawe", + "sah": "Yakut", + "sam": "Samaritan Aramaic", + "saq": "Samburu", + "sas": "Sasak", + "sat": "Santali", + "saz": "Saurashtra", + "sba": "Ngambay", + "sbp": "Sangu", + "sc": "Sardinian", + "scn": "Sicilian", + "sco": "Scots", + "sd": "Sindhi", + "sdc": "Sassarese Sardinian", + "sdh": "Southern Kurdish", + "se": "Northern Sami", + "se-alt-menu": "Sami, Northern", + "see": "Seneca", + "seh": "Sena", + "sei": "Seri", + "sel": "Selkup", + "ses": "Koyraboro Senni", + "sg": "Sango", + "sga": "Old Irish", + "sgs": "Samogitian", + "sh": "Serbo-Croatian", + "shi": "Tachelhit", + "shn": "Shan", + "shu": "Chadian Arabic", + "si": "Sinhala", + "sid": "Sidamo", + "sk": "Slovak", + "sl": "Slovenian", + "slh": "Southern Lushootseed", + "sli": "Lower Silesian", + "sly": "Selayar", + "sm": "Samoan", + "sma": "Southern Sami", + "sma-alt-menu": "Sami, Southern", + "smj": "Lule Sami", + "smj-alt-menu": "Sami, Lule", + "smn": "Inari Sami", + "smn-alt-menu": "Sami, Inari", + "sms": "Skolt Sami", + "sms-alt-menu": "Sami, Skolt", + "sn": "Shona", + "snk": "Soninke", + "so": "Somali", + "sog": "Sogdien", + "sq": "Albanian", + "sr": "Serbian", + "sr-ME": "Montenegrin", + "srn": "Sranan Tongo", + "srr": "Serer", + "ss": "Swati", + "ssy": "Saho", + "st": "Southern Sotho", + "stq": "Saterland Frisian", + "str": "Straits Salish", + "su": "Sundanese", + "suk": "Sukuma", + "sus": "Susu", + "sux": "Sumerian", + "sv": "Swedish", + "sw": "Swahili", + "sw-CD": "Congo Swahili", + "swb": "Comorian", + "syc": "Classical Syriac", + "syr": "Syriac", + "szl": "Silesian", + "ta": "Tamil", + "tce": "Southern Tutchone", + "tcy": "Tulu", + "te": "Telugu", + "tem": "Timne", + "teo": "Teso", + "ter": "Tereno", + "tet": "Tetum", + "tg": "Tajik", + "tgx": "Tagish", + "th": "Thai", + "tht": "Tahltan", + "ti": "Tigrinya", + "tig": "Tigre", + "tiv": "Tiv", + "tk": "Turkmen", + "tkl": "Tokelau", + "tkr": "Tsakhur", + "tl": "Tagalog", + "tlh": "Klingon", + "tli": "Tlingit", + "tly": "Talysh", + "tmh": "Tamashek", + "tn": "Tswana", + "to": "Tongan", + "tog": "Nyasa Tonga", + "tok": "Toki Pona", + "tpi": "Tok Pisin", + "tr": "Turkish", + "tru": "Turoyo", + "trv": "Taroko", + "trw": "Torwali", + "ts": "Tsonga", + "tsd": "Tsakonian", + "tsi": "Tsimshian", + "tt": "Tatar", + "ttm": "Northern Tutchone", + "ttt": "Muslim Tat", + "tum": "Tumbuka", + "tvl": "Tuvalu", + "tw": "Twi", + "twq": "Tasawaq", + "ty": "Tahitian", + "tyv": "Tuvinian", + "tzm": "Central Atlas Tamazight", + "udm": "Udmurt", + "ug": "Uyghur", + "ug-alt-variant": "Uighur", + "uga": "Ugaritic", + "uk": "Ukrainian", + "umb": "Umbundu", + "und": "Unknown language", + "ur": "Urdu", + "uz": "Uzbek", + "vai": "Vai", + "ve": "Venda", + "vec": "Venetian", + "vep": "Veps", + "vi": "Vietnamese", + "vls": "West Flemish", + "vmf": "Main-Franconian", + "vmw": "Makhuwa", + "vo": "Volapük", + "vot": "Votic", + "vro": "Võro", + "vun": "Vunjo", + "wa": "Walloon", + "wae": "Walser", + "wal": "Wolaytta", + "war": "Waray", + "was": "Washo", + "wbp": "Warlpiri", + "wo": "Wolof", + "wuu": "Wu Chinese", + "xal": "Kalmyk", + "xh": "Xhosa", + "xmf": "Mingrelian", + "xnr": "Kangri", + "xog": "Soga", + "yao": "Yao", + "yap": "Yapese", + "yav": "Yangben", + "ybb": "Yemba", + "yi": "Yiddish", + "yo": "Yoruba", + "yrl": "Nheengatu", + "yue": "Cantonese", + "yue-alt-menu": "Chinese, Cantonese", + "za": "Zhuang", + "zap": "Zapotec", + "zbl": "Blissymbols", + "zea": "Zeelandic", + "zen": "Zenaga", + "zgh": "Standard Moroccan Tamazight", + "zh": "Chinese", + "zh-alt-long": "Mandarin Chinese", + "zh-alt-menu": "Chinese, Mandarin", + "zh-Hans": "Simplified Chinese", + "zh-Hans-alt-long": "Simplified Mandarin Chinese", + "zh-Hant": "Traditional Chinese", + "zh-Hant-alt-long": "Traditional Mandarin Chinese", + "zu": "Zulu", + "zun": "Zuni", + "zxx": "No linguistic content", + "zza": "Zaza" +} \ No newline at end of file diff --git a/subcrates/telemetry/src/lib.rs b/subcrates/telemetry/src/lib.rs new file mode 100644 index 0000000..eea59e5 --- /dev/null +++ b/subcrates/telemetry/src/lib.rs @@ -0,0 +1,714 @@ +use serde::Serialize; +use serde_json::{Value, json}; + +pub mod gpu { + use serde::Serialize; + use serde_json::{Value, json}; + use wgpu; + use winit::{ + application::ApplicationHandler, + event::WindowEvent, + event_loop::{ActiveEventLoop, EventLoop}, + window::WindowId, + }; + + #[derive(Debug, Serialize)] + pub struct DriverInfo { + version: String, + name: String, + } + + #[derive(Debug, Serialize)] + pub struct AdapterInfo { + vendor: String, + model: String, + driver: DriverInfo, + vram: String, + display: DisplayInfo, + } + + #[derive(Debug, Serialize)] + pub struct GPUInfo { + supported_backends: Vec, + gpus: Vec, + } + + #[derive(Debug, Serialize, Default)] + pub struct DisplayInfo { + resolution: String, + refresh_rate: String, + } + + impl ApplicationHandler for DisplayInfo { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if let Some(monitor) = event_loop.primary_monitor() { + let size = monitor.size(); + let refresh_rate = monitor.refresh_rate_millihertz(); + + self.resolution = format!("{}x{}", size.width, size.height); + self.refresh_rate = if let Some(refresh) = refresh_rate { + format!("{} hz", refresh / 1000) + } else { + String::from("Unknown") + } + } else { + self.resolution = String::from("Unknown"); + self.refresh_rate = String::from("Unknown"); + } + + event_loop.exit(); + } + + fn window_event( + &mut self, + _event_loop: &ActiveEventLoop, + _window_id: WindowId, + _event: WindowEvent, + ) { + } + } + + mod vram { + use ash::vk::{API_VERSION_1_2, ApplicationInfo, InstanceCreateInfo, MemoryHeapFlags}; + use humansize::{DECIMAL, make_format}; + + #[cfg(not(target_os = "macos"))] + pub fn get_metal() -> u64 { + 0 + } + + #[cfg(target_os = "macos")] + pub fn get_metal() -> u64 { + use metal::Device as MetalDevice; + + let device = MetalDevice::system_default().expect("No Metal-compatible GPU found"); + device.recommended_max_working_set_size() + } + + pub fn get_vulkan(device_id: u32) -> u64 { + let entry = unsafe { ash::Entry::load().unwrap() }; + let app_info = ApplicationInfo { + p_application_name: std::ptr::null(), + application_version: 0, + p_engine_name: std::ptr::null(), + engine_version: 0, + api_version: API_VERSION_1_2, + ..Default::default() + }; + + let create_info = InstanceCreateInfo { + p_application_info: &app_info, + ..Default::default() + }; + + let instance = unsafe { entry.create_instance(&create_info, None).unwrap() }; + + let physical_devices = unsafe { instance.enumerate_physical_devices().unwrap() }; + let mut total_vram = 0; + + for device in physical_devices { + let memory_properties = + unsafe { instance.get_physical_device_memory_properties(device) }; + let device_properties = unsafe { instance.get_physical_device_properties(device) }; + + if device_id != device_properties.device_id { + continue; + } + + for heap in memory_properties.memory_heaps { + if heap.flags.contains(MemoryHeapFlags::DEVICE_LOCAL) { + total_vram += heap.size; + } + } + + break; + } + + total_vram + } + + pub fn get(vendor: u32, device_id: u32) -> String { + let formatter = make_format(DECIMAL); + + match vendor { + 0x10DE | 0x1002 | 0x8086 | 0x5143 => formatter(get_vulkan(device_id)), + 0x1010 => formatter(get_metal()), + _ => String::from("Unknown"), + } + } + } + + fn vendor_name(vendor: u32) -> &'static str { + match vendor { + 0x10DE => "NVIDIA", + 0x1002 => "AMD(Advanced Micro Devices), Inc.", + 0x8086 => "Intel(integrated electronics)", + 0x13B5 => "ARM(Advanced RISC Machines)", + 0x5143 => "Qualcomm(Quality Communications)", + 0x1010 => "Apple Inc.", + _ => "Unknown", + } + } + + pub fn get_struct() -> GPUInfo { + let mut gpu_data: Vec = Vec::new(); + let mut backends: Vec = Vec::new(); + let instance_descriptor = wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + flags: wgpu::InstanceFlags::empty(), + backend_options: Default::default(), + }; + let instance = wgpu::Instance::new(&instance_descriptor); + let event_loop = EventLoop::new().unwrap(); + let mut app = DisplayInfo::default(); + + event_loop.run_app(&mut app).unwrap(); + + for adapter in instance.enumerate_adapters(wgpu::Backends::all()) { + let info = adapter.get_info(); + + if !backends.contains(&info.backend.to_string()) { + backends.push(info.backend.to_string()); + } + if info.driver.is_empty() || info.driver_info.is_empty() { + continue; + } + + gpu_data.push(AdapterInfo { + vendor: vendor_name(info.vendor).to_string(), + model: info.name, + driver: DriverInfo { + version: info.driver_info, + name: info.driver, + }, + vram: vram::get(info.vendor, info.device), + display: DisplayInfo { + resolution: app.resolution.to_string(), + refresh_rate: app.refresh_rate.to_string(), + }, + }); + } + + GPUInfo { + supported_backends: backends, + gpus: gpu_data, + } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod cpu { + use serde::Serialize; + use serde_json::{Value, json}; + use std::collections::HashMap; + use sysinfo::{CpuRefreshKind, RefreshKind, System}; + + #[derive(Debug, Serialize)] + pub struct ProcessorInfo { + vendor: String, + brand: String, + total_system_cores: String, + threads: u16, + architecture: String, + byte_order: String, + } + + #[derive(Debug, Serialize)] + pub struct CPUInfo { + cpus: Vec, + } + + pub fn get_struct() -> CPUInfo { + let system = System::new_with_specifics( + RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()), + ); + + let mut processors = Vec::new(); + let mut processor_count: HashMap = HashMap::new(); + + for cpu in system.cpus() { + let brand = cpu.brand().trim(); + let total_cores = System::physical_core_count(); + + if processor_count.contains_key(brand) { + processor_count.get_mut(brand).unwrap().threads += 1; + continue; + } + processor_count.insert( + brand.to_string(), + ProcessorInfo { + vendor: cpu.vendor_id().trim().to_string(), + brand: brand.to_string(), + total_system_cores: if let Some(cores) = total_cores { + cores.to_string() + } else { + String::from("Unknown") + }, + threads: 1, + architecture: System::cpu_arch().trim().to_string(), + byte_order: if cfg!(target_endian = "little") { + String::from("little-endian") + } else { + String::from("big-endian") + }, + }, + ); + } + + for (_brand, info) in processor_count { + processors.push(info); + } + + CPUInfo { cpus: processors } + } + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod memory { + use humansize::{DECIMAL, make_format}; + use serde::Serialize; + use serde_json::{Value, json}; + use sysinfo::System; + + #[derive(Debug, Serialize)] + pub struct PhysicalInfo { + total: String, + used: String, + free: String, + available: String, + } + + #[derive(Debug, Serialize)] + pub struct VirtualInfo { + total: String, + used: String, + free: String, + } + + #[derive(Debug, Serialize)] + pub struct MemoryInfo { + physical: PhysicalInfo, + virtual_swap: VirtualInfo, + } + + pub fn get_struct() -> MemoryInfo { + let system = System::new_all(); + let formatter = make_format(DECIMAL); + + MemoryInfo { + physical: PhysicalInfo { + total: formatter(system.total_memory()), + used: formatter(system.used_memory()), + free: formatter(system.free_memory()), + available: formatter(system.available_memory()), + }, + virtual_swap: VirtualInfo { + total: formatter(system.total_swap()), + used: formatter(system.used_swap()), + free: formatter(system.free_swap()), + }, + } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod os { + use detect_desktop_environment::DesktopEnvironment; + use serde::Serialize; + use serde_json::{Value, json}; + use sysinfo::System; + + #[derive(Debug, Serialize)] + pub struct OSInfo { + name: String, + edition: String, + version: String, + architecture: String, + kernel: String, + de: String, + } + + pub fn get_struct() -> OSInfo { + OSInfo { + name: System::name().unwrap_or(String::from("Unknown")), + edition: System::long_os_version().unwrap_or(String::from("Unknown")), + version: System::os_version().unwrap_or(String::from("Unknown")), + architecture: if cfg!(target_pointer_width = "64") { + String::from("64 bit") + } else if cfg!(target_pointer_width = "32") { + String::from("32 bit") + } else { + String::from("16 bit") + }, + kernel: System::kernel_long_version(), + de: match DesktopEnvironment::detect() { + Some(de) => format!("{de:?}"), + None => String::from(""), + }, + } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod storage { + use humansize::{DECIMAL, make_format}; + use serde::Serialize; + use serde_json::{Value, json}; + use sysinfo::Disks; + + #[derive(Debug, Serialize)] + pub struct StorageInfo { + name: String, + mount_point: String, + kind: String, + space_left: String, + total: String, + } + + pub fn get_list() -> Vec { + let disks = Disks::new_with_refreshed_list(); + let mut drive_data = Vec::new(); + let formatter = make_format(DECIMAL); + + for disk in disks.list() { + drive_data.push(StorageInfo { + name: format!("{:?}", disk.name()).trim_matches('\"').to_string(), + mount_point: format!("{:?}", disk.mount_point()) + .replace("\\", "") + .trim_matches('\"') + .to_string(), + kind: format!("{:?}", disk.kind()), + space_left: formatter(disk.available_space()), + total: formatter(disk.total_space()), + }); + } + + drive_data + } + + pub fn get_json() -> Value { + json!(get_list()) + } +} + +pub mod network { + use serde::Serialize; + use serde_json::{Value, json}; + use sysinfo::Networks; + + #[derive(Debug, Serialize)] + pub struct NetworkInfo { + adapters: Vec, + } + + pub fn get_struct() -> NetworkInfo { + let networks = Networks::new_with_refreshed_list(); + let mut adapters = Vec::new(); + + for (interface_name, _network_data) in &networks { + adapters.push(interface_name.to_string()); + } + + NetworkInfo { adapters } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod external { + use serde::Serialize; + use serde_json::{Value, json}; + use std::{cmp::Ordering::Equal, collections::HashMap}; + use sysinfo::{System, Users}; + + #[derive(Debug, Serialize)] + pub struct SoftwareInfo { + name: String, + count: usize, + } + + #[derive(Debug, Serialize)] + pub struct ExternalInfo { + softwares: Vec, + } + + pub fn get_struct() -> ExternalInfo { + let mut system = System::new_all(); + system.refresh_all(); + + let users = &Users::new_with_refreshed_list(); + let mut grouped_processes: HashMap> = HashMap::new(); + + for process in system.processes().values() { + let name = process.name().to_str().unwrap().to_string(); + let user_id = process.user_id(); + let is_user_owned = user_id.is_some_and(|uid| { + users + .list() + .iter() + .any(|u| u.id() == uid && u.name() != "root") + }); + + if is_user_owned && !name.trim().is_empty() && !name.starts_with('[') { + grouped_processes + .entry(name) + .or_default() + .push(process.pid().as_u32() as i32); + } + } + + let mut softwares = Vec::new(); + let mut grouped_vec: Vec<_> = grouped_processes.into_iter().collect(); + grouped_vec.sort_by(|a, b| match b.1.len().cmp(&a.1.len()) { + Equal => a.0.to_lowercase().cmp(&b.0.to_lowercase()), + other => other, + }); + + for (name, pids) in grouped_vec { + softwares.push(SoftwareInfo { + name, + count: pids.len(), + }); + } + + ExternalInfo { softwares } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod devices { + use serde::Serialize; + use serde_json::{Value, json}; + extern crate hidapi; + use hidapi::HidApi; + use std::collections::HashMap; + + #[derive(Debug, Serialize)] + pub struct DeviceInfo { + manufacturer: String, + products: Vec, + } + + #[derive(Debug, Serialize)] + pub struct DevicesInfo { + devices: Vec, + } + + pub fn get_struct() -> DevicesInfo { + let api = HidApi::new().unwrap(); + let mut grouped_devices: HashMap> = HashMap::new(); + + for device in api.device_list() { + let manufacturer = device + .manufacturer_string() + .unwrap_or("Unknown") + .to_string() + .to_lowercase(); + let product = device.product_string().unwrap_or("Unknown").to_string(); + + if !manufacturer.trim().is_empty() && !product.trim().is_empty() { + let entry = grouped_devices.entry(manufacturer).or_default(); + + if !entry.contains(&product) { + entry.push(product); + } + } + } + + let mut devices = Vec::new(); + let mut grouped_vec: Vec<_> = grouped_devices.into_iter().collect(); + grouped_vec.sort_by(|a, b| a.0.to_lowercase().cmp(&b.0.to_lowercase())); + + for (manufacturer, products) in grouped_vec { + devices.push(DeviceInfo { + manufacturer, + products, + }); + } + + DevicesInfo { devices } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod meta { + use serde::Serialize; + use serde_json::{Value, from_str, json}; + use std::{collections::HashMap, fs}; + use sys_locale::get_locale; + + include!(concat!(env!("OUT_DIR"), "/built.rs")); + + #[derive(Debug, Serialize)] + pub struct MetaInfo { + version: String, + commit_hash: String, + commit_short_hash: String, + locale: String, + language: String, + territory: String, + } + + pub fn get_struct() -> MetaInfo { + let default = String::from("Unknown"); + let locale = get_locale().unwrap_or_else(|| String::from("en-US")); + let split_locale: Vec<&str> = locale.split("-").collect(); + + let language_json = fs::read_to_string("subcrates/telemetry/src/languages.json").unwrap(); + let parsed_languages = from_str::>(&language_json).unwrap(); + let language_map = parsed_languages.get(split_locale[0]).unwrap_or(&default); + + let territory_json = + fs::read_to_string("subcrates/telemetry/src/territories.json").unwrap(); + let parsed_territories = from_str::>(&territory_json).unwrap(); + let territory_map = parsed_territories.get(split_locale[1]).unwrap_or(&default); + + MetaInfo { + version: env!("CARGO_PKG_VERSION").to_string(), + commit_hash: GIT_COMMIT_HASH.to_string(), + commit_short_hash: GIT_COMMIT_SHORT_HASH.to_string(), + locale, + language: language_map.to_string(), + territory: territory_map.to_string(), + } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +pub mod uptime { + use chrono::{DateTime, Utc}; + use serde::Serialize; + use serde_json::{Value, json}; + use std::time::Duration as StdDuration; + use sysinfo::System; + + #[derive(Debug, Serialize)] + pub struct DateInfo { + zone: String, + date: String, + time: String, + } + + #[derive(Debug, Serialize)] + pub struct UptimeInfo { + boot: DateInfo, + now: DateInfo, + relative: String, + } + + pub fn format_duration(duration: StdDuration) -> String { + let mut parts = Vec::new(); + let mut remaining = duration.as_secs(); + let units = [ + (" months", 30 * 24 * 60 * 60), + (" weeks", 7 * 24 * 60 * 60), + (" days", 24 * 60 * 60), + (" hours", 60 * 60), + (" minutes", 60), + (" seconds", 1), + ]; + + for &(label, unit_secs) in &units { + match remaining / unit_secs { + 0 => continue, + value => { + parts.push(format!("{}{}", value, label)); + remaining %= unit_secs; + } + } + } + + if parts.is_empty() { + parts.push("0 seconds".to_string()); + } + + parts.join(", ") + } + + pub fn get_struct() -> UptimeInfo { + let boot_time: DateTime = + DateTime::::from_timestamp(System::boot_time() as i64, 0) + .expect("Invalid or out-of-range timestamp"); + let relative_time = StdDuration::from_secs((Utc::now() - boot_time).num_seconds() as u64); + + UptimeInfo { + boot: DateInfo { + zone: String::from("UTC"), + date: boot_time.format("%Y-%m-%d").to_string(), + time: boot_time.format("%H:%M:%S").to_string(), + }, + now: DateInfo { + zone: String::from("UTC"), + date: Utc::now().format("%Y-%m-%d").to_string(), + time: Utc::now().format("%H:%M:%S").to_string(), + }, + relative: format_duration(relative_time).to_string(), + } + } + + pub fn get_json() -> Value { + json!(get_struct()) + } +} + +#[derive(Debug, Serialize)] +pub struct TelemetryInfo { + telemetry: AllInfo, +} + +#[derive(Debug, Serialize)] +pub struct AllInfo { + gpu: gpu::GPUInfo, + cpu: cpu::CPUInfo, + memory: memory::MemoryInfo, + os: os::OSInfo, + storage: Vec, + network: network::NetworkInfo, + external: external::ExternalInfo, + devices: devices::DevicesInfo, + meta: meta::MetaInfo, + uptime: uptime::UptimeInfo, +} + +pub fn get_struct() -> TelemetryInfo { + TelemetryInfo { + telemetry: AllInfo { + gpu: gpu::get_struct(), + cpu: cpu::get_struct(), + memory: memory::get_struct(), + os: os::get_struct(), + storage: storage::get_list(), + network: network::get_struct(), + external: external::get_struct(), + devices: devices::get_struct(), + meta: meta::get_struct(), + uptime: uptime::get_struct(), + }, + } +} + +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/main.rs b/subcrates/telemetry/src/main.rs new file mode 100644 index 0000000..2806341 --- /dev/null +++ b/subcrates/telemetry/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{:#?}", telemetry::get_struct()); +} diff --git a/subcrates/telemetry/src/territories.json b/subcrates/telemetry/src/territories.json new file mode 100644 index 0000000..a062735 --- /dev/null +++ b/subcrates/telemetry/src/territories.json @@ -0,0 +1,318 @@ +{ + "001": "world", + "002": "Africa", + "003": "North America", + "005": "South America", + "009": "Oceania", + "011": "Western Africa", + "013": "Central America", + "014": "Eastern Africa", + "015": "Northern Africa", + "017": "Middle Africa", + "018": "Southern Africa", + "019": "Americas", + "021": "Northern America", + "029": "Caribbean", + "030": "Eastern Asia", + "034": "Southern Asia", + "035": "Southeast Asia", + "039": "Southern Europe", + "053": "Australasia", + "054": "Melanesia", + "057": "Micronesian Region", + "061": "Polynesia", + "142": "Asia", + "143": "Central Asia", + "145": "Western Asia", + "150": "Europe", + "151": "Eastern Europe", + "154": "Northern Europe", + "155": "Western Europe", + "202": "Sub-Saharan Africa", + "419": "Latin America", + "AC": "Ascension Island", + "AD": "Andorra", + "AE": "United Arab Emirates", + "AF": "Afghanistan", + "AG": "Antigua & Barbuda", + "AI": "Anguilla", + "AL": "Albania", + "AM": "Armenia", + "AO": "Angola", + "AQ": "Antarctica", + "AR": "Argentina", + "AS": "American Samoa", + "AT": "Austria", + "AU": "Australia", + "AW": "Aruba", + "AX": "Åland Islands", + "AZ": "Azerbaijan", + "BA": "Bosnia & Herzegovina", + "BA-alt-short": "Bosnia", + "BB": "Barbados", + "BD": "Bangladesh", + "BE": "Belgium", + "BF": "Burkina Faso", + "BG": "Bulgaria", + "BH": "Bahrain", + "BI": "Burundi", + "BJ": "Benin", + "BL": "St Barthélemy", + "BM": "Bermuda", + "BN": "Brunei", + "BO": "Bolivia", + "BQ": "Caribbean Netherlands", + "BR": "Brazil", + "BS": "Bahamas", + "BT": "Bhutan", + "BV": "Bouvet Island", + "BW": "Botswana", + "BY": "Belarus", + "BZ": "Belize", + "CA": "Canada", + "CC": "Cocos (Keeling) Islands", + "CC-alt-short": "Cocos Islands", + "CD": "Congo - Kinshasa", + "CD-alt-variant": "Congo (DRC)", + "CF": "Central African Republic", + "CG": "Congo - Brazzaville", + "CG-alt-variant": "Congo (Republic)", + "CH": "Switzerland", + "CI": "Côte d’Ivoire", + "CI-alt-variant": "Ivory Coast", + "CK": "Cook Islands", + "CL": "Chile", + "CM": "Cameroon", + "CN": "China", + "CO": "Colombia", + "CP": "Clipperton Island", + "CQ": "Sark", + "CR": "Costa Rica", + "CU": "Cuba", + "CV": "Cape Verde", + "CV-alt-variant": "Cabo Verde", + "CW": "Curaçao", + "CX": "Christmas Island", + "CY": "Cyprus", + "CZ": "Czechia", + "CZ-alt-variant": "Czech Republic", + "DE": "Germany", + "DG": "Diego Garcia", + "DJ": "Djibouti", + "DK": "Denmark", + "DM": "Dominica", + "DO": "Dominican Republic", + "DZ": "Algeria", + "EA": "Ceuta & Melilla", + "EC": "Ecuador", + "EE": "Estonia", + "EG": "Egypt", + "EH": "Western Sahara", + "ER": "Eritrea", + "ES": "Spain", + "ET": "Ethiopia", + "EU": "European Union", + "EZ": "Eurozone", + "FI": "Finland", + "FJ": "Fiji", + "FK": "Falkland Islands", + "FK-alt-variant": "Falkland Islands (Islas Malvinas)", + "FM": "Micronesia", + "FO": "Faroe Islands", + "FR": "France", + "GA": "Gabon", + "GB": "United Kingdom", + "GB-alt-short": "UK", + "GD": "Grenada", + "GE": "Georgia", + "GF": "French Guiana", + "GG": "Guernsey", + "GH": "Ghana", + "GI": "Gibraltar", + "GL": "Greenland", + "GM": "Gambia", + "GN": "Guinea", + "GP": "Guadeloupe", + "GQ": "Equatorial Guinea", + "GR": "Greece", + "GS": "South Georgia & South Sandwich Islands", + "GT": "Guatemala", + "GU": "Guam", + "GW": "Guinea-Bissau", + "GY": "Guyana", + "HK": "Hong Kong SAR China", + "HK-alt-short": "Hong Kong", + "HM": "Heard & McDonald Islands", + "HN": "Honduras", + "HR": "Croatia", + "HT": "Haiti", + "HU": "Hungary", + "IC": "Canary Islands", + "ID": "Indonesia", + "IE": "Ireland", + "IL": "Israel", + "IM": "Isle of Man", + "IN": "India", + "IO": "British Indian Ocean Territory", + "IO-alt-chagos": "Chagos Archipelago", + "IQ": "Iraq", + "IR": "Iran", + "IS": "Iceland", + "IT": "Italy", + "JE": "Jersey", + "JM": "Jamaica", + "JO": "Jordan", + "JP": "Japan", + "KE": "Kenya", + "KG": "Kyrgyzstan", + "KH": "Cambodia", + "KI": "Kiribati", + "KM": "Comoros", + "KN": "St Kitts & Nevis", + "KP": "North Korea", + "KR": "South Korea", + "KW": "Kuwait", + "KY": "Cayman Islands", + "KZ": "Kazakhstan", + "LA": "Laos", + "LB": "Lebanon", + "LC": "St Lucia", + "LI": "Liechtenstein", + "LK": "Sri Lanka", + "LR": "Liberia", + "LS": "Lesotho", + "LT": "Lithuania", + "LU": "Luxembourg", + "LV": "Latvia", + "LY": "Libya", + "MA": "Morocco", + "MC": "Monaco", + "MD": "Moldova", + "ME": "Montenegro", + "MF": "St Martin", + "MG": "Madagascar", + "MH": "Marshall Islands", + "MK": "North Macedonia", + "ML": "Mali", + "MM": "Myanmar (Burma)", + "MM-alt-short": "Myanmar", + "MN": "Mongolia", + "MO": "Macao SAR China", + "MO-alt-short": "Macao", + "MP": "Northern Mariana Islands", + "MQ": "Martinique", + "MR": "Mauritania", + "MS": "Montserrat", + "MT": "Malta", + "MU": "Mauritius", + "MV": "Maldives", + "MW": "Malawi", + "MX": "Mexico", + "MY": "Malaysia", + "MZ": "Mozambique", + "NA": "Namibia", + "NC": "New Caledonia", + "NE": "Niger", + "NF": "Norfolk Island", + "NG": "Nigeria", + "NI": "Nicaragua", + "NL": "Netherlands", + "NO": "Norway", + "NP": "Nepal", + "NR": "Nauru", + "NU": "Niue", + "NZ": "New Zealand", + "NZ-alt-variant": "Aotearoa New Zealand", + "OM": "Oman", + "PA": "Panama", + "PE": "Peru", + "PF": "French Polynesia", + "PG": "Papua New Guinea", + "PH": "Philippines", + "PK": "Pakistan", + "PL": "Poland", + "PM": "St Pierre & Miquelon", + "PN": "Pitcairn Islands", + "PN-alt-short": "Pitcairn", + "PR": "Puerto Rico", + "PS": "Palestinian Territories", + "PS-alt-short": "Palestine", + "PT": "Portugal", + "PW": "Palau", + "PY": "Paraguay", + "QA": "Qatar", + "QO": "Outlying Oceania", + "RE": "Réunion", + "RO": "Romania", + "RS": "Serbia", + "RU": "Russia", + "RW": "Rwanda", + "SA": "Saudi Arabia", + "SB": "Solomon Islands", + "SC": "Seychelles", + "SD": "Sudan", + "SE": "Sweden", + "SG": "Singapore", + "SH": "St Helena", + "SI": "Slovenia", + "SJ": "Svalbard & Jan Mayen", + "SK": "Slovakia", + "SL": "Sierra Leone", + "SM": "San Marino", + "SN": "Senegal", + "SO": "Somalia", + "SR": "Suriname", + "SS": "South Sudan", + "ST": "São Tomé & Príncipe", + "SV": "El Salvador", + "SX": "Sint Maarten", + "SY": "Syria", + "SZ": "Eswatini", + "SZ-alt-variant": "Swaziland", + "TA": "Tristan da Cunha", + "TC": "Turks & Caicos Islands", + "TD": "Chad", + "TF": "French Southern Territories", + "TG": "Togo", + "TH": "Thailand", + "TJ": "Tajikistan", + "TK": "Tokelau", + "TL": "Timor-Leste", + "TL-alt-variant": "East Timor", + "TM": "Turkmenistan", + "TN": "Tunisia", + "TO": "Tonga", + "TR": "Türkiye", + "TR-alt-variant": "Turkey", + "TT": "Trinidad & Tobago", + "TV": "Tuvalu", + "TW": "Taiwan", + "TZ": "Tanzania", + "UA": "Ukraine", + "UG": "Uganda", + "UM": "US Outlying Islands", + "UN": "United Nations", + "UN-alt-short": "UN", + "US": "United States", + "US-alt-short": "US", + "UY": "Uruguay", + "UZ": "Uzbekistan", + "VA": "Vatican City", + "VC": "St Vincent & the Grenadines", + "VE": "Venezuela", + "VG": "British Virgin Islands", + "VI": "US Virgin Islands", + "VN": "Vietnam", + "VU": "Vanuatu", + "WF": "Wallis & Futuna", + "WS": "Samoa", + "XA": "Pseudo-Accents", + "XB": "Pseudo-Bidi", + "XK": "Kosovo", + "YE": "Yemen", + "YT": "Mayotte", + "ZA": "South Africa", + "ZM": "Zambia", + "ZW": "Zimbabwe", + "ZZ": "Unknown Region" + } \ No newline at end of file -- 2.47.2 From 528d4b03a3268857a19c530cf901f5ed427baf87 Mon Sep 17 00:00:00 2001 From: D0RYU Date: Thu, 1 May 2025 19:02:59 -0400 Subject: [PATCH 2/3] removed languages.json and territories.json lib.rs is separated into src/modules now for cleaner code optimized error handling to -> (storage.rs, uptime.rs, meta.rs, memory.rs, os.rs, network.rs) optimized struct types to -> (storage.rs, uptime.rs, meta.rs, memory.rs, os.rs, network.rs) --- Cargo.lock | 132 +++- subcrates/telemetry/Cargo.toml | 7 +- subcrates/telemetry/build.rs | 14 +- subcrates/telemetry/src/languages.json | 684 ----------------- subcrates/telemetry/src/lib.rs | 698 +----------------- subcrates/telemetry/src/modules/cpu.rs | 69 ++ subcrates/telemetry/src/modules/devices.rs | 59 ++ subcrates/telemetry/src/modules/external.rs | 63 ++ .../src/modules/formatted/architecture.rs | 55 ++ .../telemetry/src/modules/formatted/bytes.rs | 38 + .../src/modules/formatted/date_time.rs | 125 ++++ .../modules/formatted/desktop_environment.rs | 59 ++ .../telemetry/src/modules/formatted/mod.rs | 7 + .../src/modules/formatted/offset_time.rs | 68 ++ .../src/modules/formatted/relative_time.rs | 40 + .../src/modules/formatted/version.rs | 38 + subcrates/telemetry/src/modules/gpu/mod.rs | 131 ++++ subcrates/telemetry/src/modules/gpu/vram.rs | 67 ++ .../src/modules/macros/custom_anyhow.rs | 11 + subcrates/telemetry/src/modules/macros/mod.rs | 1 + subcrates/telemetry/src/modules/memory.rs | 49 ++ subcrates/telemetry/src/modules/meta.rs | 33 + subcrates/telemetry/src/modules/mod.rs | 42 ++ subcrates/telemetry/src/modules/network.rs | 25 + subcrates/telemetry/src/modules/os.rs | 54 ++ subcrates/telemetry/src/modules/storage.rs | 46 ++ subcrates/telemetry/src/modules/uptime.rs | 54 ++ subcrates/telemetry/src/territories.json | 318 -------- 28 files changed, 1261 insertions(+), 1726 deletions(-) delete mode 100644 subcrates/telemetry/src/languages.json create mode 100644 subcrates/telemetry/src/modules/cpu.rs create mode 100644 subcrates/telemetry/src/modules/devices.rs create mode 100644 subcrates/telemetry/src/modules/external.rs create mode 100644 subcrates/telemetry/src/modules/formatted/architecture.rs create mode 100644 subcrates/telemetry/src/modules/formatted/bytes.rs create mode 100644 subcrates/telemetry/src/modules/formatted/date_time.rs create mode 100644 subcrates/telemetry/src/modules/formatted/desktop_environment.rs create mode 100644 subcrates/telemetry/src/modules/formatted/mod.rs create mode 100644 subcrates/telemetry/src/modules/formatted/offset_time.rs create mode 100644 subcrates/telemetry/src/modules/formatted/relative_time.rs create mode 100644 subcrates/telemetry/src/modules/formatted/version.rs create mode 100644 subcrates/telemetry/src/modules/gpu/mod.rs create mode 100644 subcrates/telemetry/src/modules/gpu/vram.rs create mode 100644 subcrates/telemetry/src/modules/macros/custom_anyhow.rs create mode 100644 subcrates/telemetry/src/modules/macros/mod.rs create mode 100644 subcrates/telemetry/src/modules/memory.rs create mode 100644 subcrates/telemetry/src/modules/meta.rs create mode 100644 subcrates/telemetry/src/modules/mod.rs create mode 100644 subcrates/telemetry/src/modules/network.rs create mode 100644 subcrates/telemetry/src/modules/os.rs create mode 100644 subcrates/telemetry/src/modules/storage.rs create mode 100644 subcrates/telemetry/src/modules/uptime.rs delete mode 100644 subcrates/telemetry/src/territories.json diff --git a/Cargo.lock b/Cargo.lock index f5e5a29..409464d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,14 +173,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", + "pin-project-lite", "slab", ] @@ -300,7 +301,7 @@ dependencies = [ "anyhow", "arrayvec", "log", - "nom", + "nom 7.1.3", "num-rational", "v_frame", ] @@ -398,9 +399,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] @@ -505,14 +506,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-link", ] @@ -1153,6 +1155,15 @@ dependencies = [ "syn", ] +[[package]] +name = "isolang" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe50d48c77760c55188549098b9a7f6e37ae980c586a24693d6b01c3b2010c3c" +dependencies = [ + "phf", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1162,6 +1173,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1495,6 +1515,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "noop_proc_macro" version = "0.3.0" @@ -1951,6 +1980,24 @@ dependencies = [ "serde", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2107,9 +2154,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.37.4" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] @@ -2179,7 +2226,7 @@ dependencies = [ "built", "cfg-if", "interpolate_name", - "itertools", + "itertools 0.12.1", "libc", "libfuzzer-sys", "log", @@ -2476,6 +2523,12 @@ dependencies = [ "quote", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2630,6 +2683,7 @@ dependencies = [ "memchr", "ntapi", "objc2-core-foundation", + "serde", "windows 0.57.0", ] @@ -2656,6 +2710,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" name = "telemetry" version = "0.1.0" dependencies = [ + "anyhow", "ash", "chrono", "detect-desktop-environment", @@ -2666,6 +2721,8 @@ dependencies = [ "serde_json", "sys-locale", "sysinfo", + "timeago", + "versions", "wgpu", "winit", ] @@ -2746,6 +2803,16 @@ dependencies = [ "weezl", ] +[[package]] +name = "timeago" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1710e589de0a76aaf295cd47a6699f6405737dbfd3cf2b75c92d000b548d0e6" +dependencies = [ + "chrono", + "isolang", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -2782,9 +2849,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -2803,9 +2870,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.25" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", @@ -2928,6 +2995,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "versions" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a7e511ce1795821207a837b7b1c8d8aca0c648810966ad200446ae58f6667f" +dependencies = [ + "itertools 0.14.0", + "nom 8.0.0", + "serde", +] + [[package]] name = "vk-parse" version = "0.15.0" @@ -2951,7 +3029,7 @@ dependencies = [ "heck 0.4.1", "indexmap", "libloading", - "nom", + "nom 7.1.3", "once_cell", "parking_lot", "proc-macro2", @@ -3079,9 +3157,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" dependencies = [ "cc", "downcast-rs", @@ -3093,9 +3171,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ "bitflags 2.9.0", "rustix", @@ -3116,9 +3194,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" dependencies = [ "rustix", "wayland-client", @@ -3127,9 +3205,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ "bitflags 2.9.0", "wayland-backend", @@ -3139,9 +3217,9 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ "bitflags 2.9.0", "wayland-backend", @@ -3152,9 +3230,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" +checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ "bitflags 2.9.0", "wayland-backend", diff --git a/subcrates/telemetry/Cargo.toml b/subcrates/telemetry/Cargo.toml index dfb77fe..81ffb9b 100644 --- a/subcrates/telemetry/Cargo.toml +++ b/subcrates/telemetry/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.0" edition = "2024" [dependencies] +anyhow = "1.0.98" ash = "0.38.0" -chrono = "0.4.40" +chrono = { version = "0.4.40", features = ["serde"] } detect-desktop-environment = "1.2.0" hidapi = "2.6.3" humansize = "2.1.3" @@ -13,7 +14,9 @@ metal = { version = "0.32.0", optional = true } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" sys-locale = "0.3.2" -sysinfo = "0.34.2" +sysinfo = { version = "0.34.2", features = ["serde"] } +timeago = "0.4.2" +versions = { version = "7.0.0", features = ["serde"] } wgpu = "25.0.0" winit = "0.30.9" diff --git a/subcrates/telemetry/build.rs b/subcrates/telemetry/build.rs index fc44b31..d012c62 100644 --- a/subcrates/telemetry/build.rs +++ b/subcrates/telemetry/build.rs @@ -11,23 +11,11 @@ fn main() { .and_then(|o| String::from_utf8(o.stdout).ok()) .unwrap_or_else(|| "unknown".into()); - let commit_short_hash = Command::new("git") - .args(["rev-parse", "--short", "HEAD"]) - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()) - .unwrap_or_else(|| "unknown".into()); - + writeln!(f, "#[allow(dead_code)]").unwrap(); writeln!( f, "pub const GIT_COMMIT_HASH: &str = \"{}\";", commit_hash.trim() ) .unwrap(); - writeln!( - f, - "pub const GIT_COMMIT_SHORT_HASH: &str = \"{}\";", - commit_short_hash.trim() - ) - .unwrap(); } diff --git a/subcrates/telemetry/src/languages.json b/subcrates/telemetry/src/languages.json deleted file mode 100644 index 6c9fc28..0000000 --- a/subcrates/telemetry/src/languages.json +++ /dev/null @@ -1,684 +0,0 @@ -{ - "aa": "Afar", - "ab": "Abkhazian", - "ace": "Acehnese", - "ach": "Acoli", - "ada": "Adangme", - "ady": "Adyghe", - "ae": "Avestan", - "aeb": "Tunisian Arabic", - "af": "Afrikaans", - "afh": "Afrihili", - "agq": "Aghem", - "ain": "Ainu", - "ak": "Akan", - "akk": "Akkadian", - "akz": "Alabama", - "ale": "Aleut", - "aln": "Gheg Albanian", - "alt": "Southern Altai", - "am": "Amharic", - "an": "Aragonese", - "ang": "Old English", - "ann": "Obolo", - "anp": "Angika", - "ar": "Arabic", - "ar-001": "Modern Standard Arabic", - "arc": "Aramaic", - "arn": "Mapuche", - "aro": "Araona", - "arp": "Arapaho", - "arq": "Algerian Arabic", - "ars": "Najdi Arabic", - "ars-alt-menu": "Arabic, Najdi", - "arw": "Arawak", - "ary": "Moroccan Arabic", - "arz": "Egyptian Arabic", - "as": "Assamese", - "asa": "Asu", - "ase": "American Sign Language", - "ast": "Asturian", - "atj": "Atikamekw", - "av": "Avaric", - "avk": "Kotava", - "awa": "Awadhi", - "ay": "Aymara", - "az": "Azerbaijani", - "az-alt-short": "Azeri", - "ba": "Bashkir", - "bal": "Baluchi", - "ban": "Balinese", - "bar": "Bavarian", - "bas": "Basaa", - "bax": "Bamun", - "bbc": "Batak Toba", - "bbj": "Ghomala", - "be": "Belarusian", - "bej": "Beja", - "bem": "Bemba", - "bew": "Betawi", - "bez": "Bena", - "bfd": "Bafut", - "bfq": "Badaga", - "bg": "Bulgarian", - "bgc": "Haryanvi", - "bgn": "Western Balochi", - "bho": "Bhojpuri", - "bi": "Bislama", - "bik": "Bikol", - "bin": "Bini", - "bjn": "Banjar", - "bkm": "Kom", - "bla": "Siksika", - "blo": "Anii", - "blt": "Tai Dam", - "bm": "Bambara", - "bn": "Bangla", - "bo": "Tibetan", - "bpy": "Bishnupriya", - "bqi": "Bakhtiari", - "br": "Breton", - "bra": "Braj", - "brh": "Brahui", - "brx": "Bodo", - "bs": "Bosnian", - "bss": "Akoose", - "bua": "Buriat", - "bug": "Buginese", - "bum": "Bulu", - "byn": "Blin", - "byv": "Medumba", - "ca": "Catalan", - "cad": "Caddo", - "car": "Carib", - "cay": "Cayuga", - "cch": "Atsam", - "ccp": "Chakma", - "ce": "Chechen", - "ceb": "Cebuano", - "cgg": "Chiga", - "ch": "Chamorro", - "chb": "Chibcha", - "chg": "Chagatai", - "chk": "Chuukese", - "chm": "Mari", - "chn": "Chinook Jargon", - "cho": "Choctaw", - "chp": "Chipewyan", - "chr": "Cherokee", - "chy": "Cheyenne", - "cic": "Chickasaw", - "ckb": "Central Kurdish", - "ckb-alt-menu": "Kurdish, Central", - "ckb-alt-variant": "Kurdish, Sorani", - "clc": "Chilcotin", - "co": "Corsican", - "cop": "Coptic", - "cps": "Capiznon", - "cr": "Cree", - "cr-alt-long": "Woods Cree", - "crg": "Michif", - "crh": "Crimean Tatar", - "crj": "Southern East Cree", - "crk": "Plains Cree", - "crl": "Northern East Cree", - "crm": "Moose Cree", - "crr": "Carolina Algonquian", - "crs": "Seselwa Creole French", - "cs": "Czech", - "csb": "Kashubian", - "csw": "Swampy Cree", - "cu": "Church Slavic", - "cv": "Chuvash", - "cy": "Welsh", - "da": "Danish", - "dak": "Dakota", - "dar": "Dargwa", - "dav": "Taita", - "de": "German", - "de-AT": "Austrian German", - "de-CH": "Swiss High German", - "del": "Delaware", - "den": "Slave", - "dgr": "Dogrib", - "din": "Dinka", - "dje": "Zarma", - "doi": "Dogri", - "dsb": "Lower Sorbian", - "dtp": "Central Dusun", - "dua": "Duala", - "dum": "Middle Dutch", - "dv": "Divehi", - "dyo": "Jola-Fonyi", - "dyu": "Dyula", - "dz": "Dzongkha", - "dzg": "Dazaga", - "ebu": "Embu", - "ee": "Ewe", - "efi": "Efik", - "egl": "Emilian", - "egy": "Ancient Egyptian", - "eka": "Ekajuk", - "el": "Greek", - "elx": "Elamite", - "en": "English", - "en-AU": "Australian English", - "en-CA": "Canadian English", - "en-GB": "British English", - "en-GB-alt-short": "UK English", - "en-US": "American English", - "en-US-alt-short": "US English", - "enm": "Middle English", - "eo": "Esperanto", - "es": "Spanish", - "es-419": "Latin American Spanish", - "es-ES": "European Spanish", - "es-MX": "Mexican Spanish", - "esu": "Central Yupik", - "et": "Estonian", - "eu": "Basque", - "ewo": "Ewondo", - "ext": "Extremaduran", - "fa": "Persian", - "fa-AF": "Dari", - "fan": "Fang", - "fat": "Fanti", - "ff": "Fula", - "fi": "Finnish", - "fil": "Filipino", - "fit": "Tornedalen Finnish", - "fj": "Fijian", - "fo": "Faroese", - "fon": "Fon", - "fr": "French", - "fr-CA": "Canadian French", - "fr-CH": "Swiss French", - "frc": "Cajun French", - "frm": "Middle French", - "fro": "Old French", - "frp": "Arpitan", - "frr": "Northern Frisian", - "frs": "Eastern Frisian", - "fur": "Friulian", - "fy": "Western Frisian", - "ga": "Irish", - "gaa": "Ga", - "gag": "Gagauz", - "gan": "Gan Chinese", - "gay": "Gayo", - "gba": "Gbaya", - "gbz": "Zoroastrian Dari", - "gd": "Scottish Gaelic", - "gez": "Geez", - "gil": "Gilbertese", - "gl": "Galician", - "glk": "Gilaki", - "gmh": "Middle High German", - "gn": "Guarani", - "goh": "Old High German", - "gon": "Gondi", - "gor": "Gorontalo", - "got": "Gothic", - "grb": "Grebo", - "grc": "Ancient Greek", - "gsw": "Swiss German", - "gu": "Gujarati", - "guc": "Wayuu", - "gur": "Frafra", - "guz": "Gusii", - "gv": "Manx", - "gwi": "Gwichʼin", - "ha": "Hausa", - "hai": "Haida", - "hak": "Hakka Chinese", - "haw": "Hawaiian", - "hax": "Southern Haida", - "he": "Hebrew", - "hi": "Hindi", - "hi-Latn": "Hindi (Latin)", - "hi-Latn-alt-variant": "Hinglish", - "hif": "Fiji Hindi", - "hil": "Hiligaynon", - "hit": "Hittite", - "hmn": "Hmong", - "hnj": "Hmong Njua", - "ho": "Hiri Motu", - "hr": "Croatian", - "hsb": "Upper Sorbian", - "hsn": "Xiang Chinese", - "ht": "Haitian Creole", - "hu": "Hungarian", - "hup": "Hupa", - "hur": "Halkomelem", - "hy": "Armenian", - "hz": "Herero", - "ia": "Interlingua", - "iba": "Iban", - "ibb": "Ibibio", - "id": "Indonesian", - "ie": "Interlingue", - "ig": "Igbo", - "ii": "Sichuan Yi", - "ik": "Inupiaq", - "ikt": "Western Canadian Inuktitut", - "ilo": "Iloko", - "inh": "Ingush", - "io": "Ido", - "is": "Icelandic", - "it": "Italian", - "iu": "Inuktitut", - "izh": "Ingrian", - "ja": "Japanese", - "jam": "Jamaican Creole English", - "jbo": "Lojban", - "jgo": "Ngomba", - "jmc": "Machame", - "jpr": "Judeo-Persian", - "jrb": "Judeo-Arabic", - "jut": "Jutish", - "jv": "Javanese", - "ka": "Georgian", - "kaa": "Kara-Kalpak", - "kab": "Kabyle", - "kac": "Kachin", - "kaj": "Jju", - "kam": "Kamba", - "kaw": "Kawi", - "kbd": "Kabardian", - "kbl": "Kanembu", - "kcg": "Tyap", - "kde": "Makonde", - "kea": "Kabuverdianu", - "ken": "Kenyang", - "kfo": "Koro", - "kg": "Kongo", - "kgp": "Kaingang", - "kha": "Khasi", - "kho": "Khotanese", - "khq": "Koyra Chiini", - "khw": "Khowar", - "ki": "Kikuyu", - "kiu": "Kirmanjki", - "kj": "Kuanyama", - "kk": "Kazakh", - "kkj": "Kako", - "kl": "Kalaallisut", - "kln": "Kalenjin", - "km": "Khmer", - "kmb": "Kimbundu", - "kn": "Kannada", - "ko": "Korean", - "koi": "Komi-Permyak", - "kok": "Konkani", - "kos": "Kosraean", - "kpe": "Kpelle", - "kr": "Kanuri", - "krc": "Karachay-Balkar", - "kri": "Krio", - "krj": "Kinaray-a", - "krl": "Karelian", - "kru": "Kurukh", - "ks": "Kashmiri", - "ksb": "Shambala", - "ksf": "Bafia", - "ksh": "Colognian", - "ku": "Kurdish", - "kum": "Kumyk", - "kut": "Kutenai", - "kv": "Komi", - "kw": "Cornish", - "kwk": "Kwakʼwala", - "kxv": "Kuvi", - "ky": "Kyrgyz", - "ky-alt-variant": "Kirghiz", - "la": "Latin", - "lad": "Ladino", - "lag": "Langi", - "lah": "Western Panjabi", - "lam": "Lamba", - "lb": "Luxembourgish", - "lez": "Lezghian", - "lfn": "Lingua Franca Nova", - "lg": "Ganda", - "li": "Limburgish", - "lij": "Ligurian", - "lil": "Lillooet", - "liv": "Livonian", - "lkt": "Lakota", - "lmo": "Lombard", - "ln": "Lingala", - "lo": "Lao", - "lol": "Mongo", - "lou": "Louisiana Creole", - "loz": "Lozi", - "lrc": "Northern Luri", - "lsm": "Saamia", - "lt": "Lithuanian", - "ltg": "Latgalian", - "lu": "Luba-Katanga", - "lua": "Luba-Lulua", - "lui": "Luiseno", - "lun": "Lunda", - "luo": "Luo", - "lus": "Mizo", - "luy": "Luyia", - "lv": "Latvian", - "lzh": "Literary Chinese", - "lzz": "Laz", - "mad": "Madurese", - "maf": "Mafa", - "mag": "Magahi", - "mai": "Maithili", - "mak": "Makasar", - "man": "Mandingo", - "mas": "Masai", - "mde": "Maba", - "mdf": "Moksha", - "mdr": "Mandar", - "men": "Mende", - "mer": "Meru", - "mfe": "Morisyen", - "mg": "Malagasy", - "mga": "Middle Irish", - "mgh": "Makhuwa-Meetto", - "mgo": "Metaʼ", - "mh": "Marshallese", - "mi": "Māori", - "mic": "Mi'kmaw", - "min": "Minangkabau", - "mk": "Macedonian", - "ml": "Malayalam", - "mn": "Mongolian", - "mnc": "Manchu", - "mni": "Manipuri", - "moe": "Innu-aimun", - "moh": "Mohawk", - "mos": "Mossi", - "mr": "Marathi", - "mrj": "Western Mari", - "ms": "Malay", - "mt": "Maltese", - "mua": "Mundang", - "mul": "Multiple languages", - "mus": "Creek", - "mus-alt-official": "Mvskoke", - "mwl": "Mirandese", - "mwr": "Marwari", - "mwv": "Mentawai", - "my": "Burmese", - "my-alt-variant": "Myanmar Language", - "mye": "Myene", - "myv": "Erzya", - "mzn": "Mazanderani", - "na": "Nauru", - "nan": "Min Nan Chinese", - "nap": "Neapolitan", - "naq": "Nama", - "nb": "Norwegian Bokmål", - "nd": "North Ndebele", - "nds": "Low German", - "nds-NL": "West Low German", - "ne": "Nepali", - "new": "Newari", - "ng": "Ndonga", - "nia": "Nias", - "niu": "Niuean", - "njo": "Ao Naga", - "nl": "Dutch", - "nl-BE": "Flemish", - "nmg": "Kwasio", - "nn": "Norwegian Nynorsk", - "nnh": "Ngiemboon", - "no": "Norwegian", - "nog": "Nogai", - "non": "Old Norse", - "nov": "Novial", - "nqo": "N’Ko", - "nr": "South Ndebele", - "nso": "Northern Sotho", - "nus": "Nuer", - "nv": "Navajo", - "nwc": "Classical Newari", - "ny": "Nyanja", - "nym": "Nyamwezi", - "nyn": "Nyankole", - "nyo": "Nyoro", - "nzi": "Nzima", - "oc": "Occitan", - "oj": "Ojibwa", - "ojb": "Northwestern Ojibwa", - "ojc": "Central Ojibwa", - "ojs": "Oji-Cree", - "ojw": "Western Ojibwa", - "oka": "Okanagan", - "om": "Oromo", - "or": "Odia", - "os": "Ossetic", - "osa": "Osage", - "ota": "Ottoman Turkish", - "pa": "Punjabi", - "pag": "Pangasinan", - "pal": "Pahlavi", - "pam": "Pampanga", - "pap": "Papiamento", - "pau": "Palauan", - "pcd": "Picard", - "pcm": "Nigerian Pidgin", - "pdc": "Pennsylvania German", - "pdt": "Plautdietsch", - "peo": "Old Persian", - "pfl": "Palatine German", - "phn": "Phoenician", - "pi": "Pali", - "pis": "Pijin", - "pl": "Polish", - "pms": "Piedmontese", - "pnt": "Pontic", - "pon": "Pohnpeian", - "pqm": "Maliseet-Passamaquoddy", - "prg": "Prussian", - "pro": "Old Provençal", - "ps": "Pashto", - "ps-alt-variant": "Pushto", - "pt": "Portuguese", - "pt-BR": "Brazilian Portuguese", - "pt-PT": "European Portuguese", - "qu": "Quechua", - "quc": "Kʼicheʼ", - "qug": "Chimborazo Highland Quichua", - "raj": "Rajasthani", - "rap": "Rapanui", - "rar": "Rarotongan", - "rgn": "Romagnol", - "rhg": "Rohingya", - "rif": "Riffian", - "rm": "Romansh", - "rn": "Rundi", - "ro": "Romanian", - "ro-MD": "Moldavian", - "rof": "Rombo", - "rom": "Romany", - "rtm": "Rotuman", - "ru": "Russian", - "rue": "Rusyn", - "rug": "Roviana", - "rup": "Aromanian", - "rw": "Kinyarwanda", - "rwk": "Rwa", - "sa": "Sanskrit", - "sad": "Sandawe", - "sah": "Yakut", - "sam": "Samaritan Aramaic", - "saq": "Samburu", - "sas": "Sasak", - "sat": "Santali", - "saz": "Saurashtra", - "sba": "Ngambay", - "sbp": "Sangu", - "sc": "Sardinian", - "scn": "Sicilian", - "sco": "Scots", - "sd": "Sindhi", - "sdc": "Sassarese Sardinian", - "sdh": "Southern Kurdish", - "se": "Northern Sami", - "se-alt-menu": "Sami, Northern", - "see": "Seneca", - "seh": "Sena", - "sei": "Seri", - "sel": "Selkup", - "ses": "Koyraboro Senni", - "sg": "Sango", - "sga": "Old Irish", - "sgs": "Samogitian", - "sh": "Serbo-Croatian", - "shi": "Tachelhit", - "shn": "Shan", - "shu": "Chadian Arabic", - "si": "Sinhala", - "sid": "Sidamo", - "sk": "Slovak", - "sl": "Slovenian", - "slh": "Southern Lushootseed", - "sli": "Lower Silesian", - "sly": "Selayar", - "sm": "Samoan", - "sma": "Southern Sami", - "sma-alt-menu": "Sami, Southern", - "smj": "Lule Sami", - "smj-alt-menu": "Sami, Lule", - "smn": "Inari Sami", - "smn-alt-menu": "Sami, Inari", - "sms": "Skolt Sami", - "sms-alt-menu": "Sami, Skolt", - "sn": "Shona", - "snk": "Soninke", - "so": "Somali", - "sog": "Sogdien", - "sq": "Albanian", - "sr": "Serbian", - "sr-ME": "Montenegrin", - "srn": "Sranan Tongo", - "srr": "Serer", - "ss": "Swati", - "ssy": "Saho", - "st": "Southern Sotho", - "stq": "Saterland Frisian", - "str": "Straits Salish", - "su": "Sundanese", - "suk": "Sukuma", - "sus": "Susu", - "sux": "Sumerian", - "sv": "Swedish", - "sw": "Swahili", - "sw-CD": "Congo Swahili", - "swb": "Comorian", - "syc": "Classical Syriac", - "syr": "Syriac", - "szl": "Silesian", - "ta": "Tamil", - "tce": "Southern Tutchone", - "tcy": "Tulu", - "te": "Telugu", - "tem": "Timne", - "teo": "Teso", - "ter": "Tereno", - "tet": "Tetum", - "tg": "Tajik", - "tgx": "Tagish", - "th": "Thai", - "tht": "Tahltan", - "ti": "Tigrinya", - "tig": "Tigre", - "tiv": "Tiv", - "tk": "Turkmen", - "tkl": "Tokelau", - "tkr": "Tsakhur", - "tl": "Tagalog", - "tlh": "Klingon", - "tli": "Tlingit", - "tly": "Talysh", - "tmh": "Tamashek", - "tn": "Tswana", - "to": "Tongan", - "tog": "Nyasa Tonga", - "tok": "Toki Pona", - "tpi": "Tok Pisin", - "tr": "Turkish", - "tru": "Turoyo", - "trv": "Taroko", - "trw": "Torwali", - "ts": "Tsonga", - "tsd": "Tsakonian", - "tsi": "Tsimshian", - "tt": "Tatar", - "ttm": "Northern Tutchone", - "ttt": "Muslim Tat", - "tum": "Tumbuka", - "tvl": "Tuvalu", - "tw": "Twi", - "twq": "Tasawaq", - "ty": "Tahitian", - "tyv": "Tuvinian", - "tzm": "Central Atlas Tamazight", - "udm": "Udmurt", - "ug": "Uyghur", - "ug-alt-variant": "Uighur", - "uga": "Ugaritic", - "uk": "Ukrainian", - "umb": "Umbundu", - "und": "Unknown language", - "ur": "Urdu", - "uz": "Uzbek", - "vai": "Vai", - "ve": "Venda", - "vec": "Venetian", - "vep": "Veps", - "vi": "Vietnamese", - "vls": "West Flemish", - "vmf": "Main-Franconian", - "vmw": "Makhuwa", - "vo": "Volapük", - "vot": "Votic", - "vro": "Võro", - "vun": "Vunjo", - "wa": "Walloon", - "wae": "Walser", - "wal": "Wolaytta", - "war": "Waray", - "was": "Washo", - "wbp": "Warlpiri", - "wo": "Wolof", - "wuu": "Wu Chinese", - "xal": "Kalmyk", - "xh": "Xhosa", - "xmf": "Mingrelian", - "xnr": "Kangri", - "xog": "Soga", - "yao": "Yao", - "yap": "Yapese", - "yav": "Yangben", - "ybb": "Yemba", - "yi": "Yiddish", - "yo": "Yoruba", - "yrl": "Nheengatu", - "yue": "Cantonese", - "yue-alt-menu": "Chinese, Cantonese", - "za": "Zhuang", - "zap": "Zapotec", - "zbl": "Blissymbols", - "zea": "Zeelandic", - "zen": "Zenaga", - "zgh": "Standard Moroccan Tamazight", - "zh": "Chinese", - "zh-alt-long": "Mandarin Chinese", - "zh-alt-menu": "Chinese, Mandarin", - "zh-Hans": "Simplified Chinese", - "zh-Hans-alt-long": "Simplified Mandarin Chinese", - "zh-Hant": "Traditional Chinese", - "zh-Hant-alt-long": "Traditional Mandarin Chinese", - "zu": "Zulu", - "zun": "Zuni", - "zxx": "No linguistic content", - "zza": "Zaza" -} \ No newline at end of file diff --git a/subcrates/telemetry/src/lib.rs b/subcrates/telemetry/src/lib.rs index eea59e5..6c1647e 100644 --- a/subcrates/telemetry/src/lib.rs +++ b/subcrates/telemetry/src/lib.rs @@ -1,677 +1,9 @@ use serde::Serialize; use serde_json::{Value, json}; - -pub mod gpu { - use serde::Serialize; - use serde_json::{Value, json}; - use wgpu; - use winit::{ - application::ApplicationHandler, - event::WindowEvent, - event_loop::{ActiveEventLoop, EventLoop}, - window::WindowId, - }; - - #[derive(Debug, Serialize)] - pub struct DriverInfo { - version: String, - name: String, - } - - #[derive(Debug, Serialize)] - pub struct AdapterInfo { - vendor: String, - model: String, - driver: DriverInfo, - vram: String, - display: DisplayInfo, - } - - #[derive(Debug, Serialize)] - pub struct GPUInfo { - supported_backends: Vec, - gpus: Vec, - } - - #[derive(Debug, Serialize, Default)] - pub struct DisplayInfo { - resolution: String, - refresh_rate: String, - } - - impl ApplicationHandler for DisplayInfo { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - if let Some(monitor) = event_loop.primary_monitor() { - let size = monitor.size(); - let refresh_rate = monitor.refresh_rate_millihertz(); - - self.resolution = format!("{}x{}", size.width, size.height); - self.refresh_rate = if let Some(refresh) = refresh_rate { - format!("{} hz", refresh / 1000) - } else { - String::from("Unknown") - } - } else { - self.resolution = String::from("Unknown"); - self.refresh_rate = String::from("Unknown"); - } - - event_loop.exit(); - } - - fn window_event( - &mut self, - _event_loop: &ActiveEventLoop, - _window_id: WindowId, - _event: WindowEvent, - ) { - } - } - - mod vram { - use ash::vk::{API_VERSION_1_2, ApplicationInfo, InstanceCreateInfo, MemoryHeapFlags}; - use humansize::{DECIMAL, make_format}; - - #[cfg(not(target_os = "macos"))] - pub fn get_metal() -> u64 { - 0 - } - - #[cfg(target_os = "macos")] - pub fn get_metal() -> u64 { - use metal::Device as MetalDevice; - - let device = MetalDevice::system_default().expect("No Metal-compatible GPU found"); - device.recommended_max_working_set_size() - } - - pub fn get_vulkan(device_id: u32) -> u64 { - let entry = unsafe { ash::Entry::load().unwrap() }; - let app_info = ApplicationInfo { - p_application_name: std::ptr::null(), - application_version: 0, - p_engine_name: std::ptr::null(), - engine_version: 0, - api_version: API_VERSION_1_2, - ..Default::default() - }; - - let create_info = InstanceCreateInfo { - p_application_info: &app_info, - ..Default::default() - }; - - let instance = unsafe { entry.create_instance(&create_info, None).unwrap() }; - - let physical_devices = unsafe { instance.enumerate_physical_devices().unwrap() }; - let mut total_vram = 0; - - for device in physical_devices { - let memory_properties = - unsafe { instance.get_physical_device_memory_properties(device) }; - let device_properties = unsafe { instance.get_physical_device_properties(device) }; - - if device_id != device_properties.device_id { - continue; - } - - for heap in memory_properties.memory_heaps { - if heap.flags.contains(MemoryHeapFlags::DEVICE_LOCAL) { - total_vram += heap.size; - } - } - - break; - } - - total_vram - } - - pub fn get(vendor: u32, device_id: u32) -> String { - let formatter = make_format(DECIMAL); - - match vendor { - 0x10DE | 0x1002 | 0x8086 | 0x5143 => formatter(get_vulkan(device_id)), - 0x1010 => formatter(get_metal()), - _ => String::from("Unknown"), - } - } - } - - fn vendor_name(vendor: u32) -> &'static str { - match vendor { - 0x10DE => "NVIDIA", - 0x1002 => "AMD(Advanced Micro Devices), Inc.", - 0x8086 => "Intel(integrated electronics)", - 0x13B5 => "ARM(Advanced RISC Machines)", - 0x5143 => "Qualcomm(Quality Communications)", - 0x1010 => "Apple Inc.", - _ => "Unknown", - } - } - - pub fn get_struct() -> GPUInfo { - let mut gpu_data: Vec = Vec::new(); - let mut backends: Vec = Vec::new(); - let instance_descriptor = wgpu::InstanceDescriptor { - backends: wgpu::Backends::all(), - flags: wgpu::InstanceFlags::empty(), - backend_options: Default::default(), - }; - let instance = wgpu::Instance::new(&instance_descriptor); - let event_loop = EventLoop::new().unwrap(); - let mut app = DisplayInfo::default(); - - event_loop.run_app(&mut app).unwrap(); - - for adapter in instance.enumerate_adapters(wgpu::Backends::all()) { - let info = adapter.get_info(); - - if !backends.contains(&info.backend.to_string()) { - backends.push(info.backend.to_string()); - } - if info.driver.is_empty() || info.driver_info.is_empty() { - continue; - } - - gpu_data.push(AdapterInfo { - vendor: vendor_name(info.vendor).to_string(), - model: info.name, - driver: DriverInfo { - version: info.driver_info, - name: info.driver, - }, - vram: vram::get(info.vendor, info.device), - display: DisplayInfo { - resolution: app.resolution.to_string(), - refresh_rate: app.refresh_rate.to_string(), - }, - }); - } - - GPUInfo { - supported_backends: backends, - gpus: gpu_data, - } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod cpu { - use serde::Serialize; - use serde_json::{Value, json}; - use std::collections::HashMap; - use sysinfo::{CpuRefreshKind, RefreshKind, System}; - - #[derive(Debug, Serialize)] - pub struct ProcessorInfo { - vendor: String, - brand: String, - total_system_cores: String, - threads: u16, - architecture: String, - byte_order: String, - } - - #[derive(Debug, Serialize)] - pub struct CPUInfo { - cpus: Vec, - } - - pub fn get_struct() -> CPUInfo { - let system = System::new_with_specifics( - RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()), - ); - - let mut processors = Vec::new(); - let mut processor_count: HashMap = HashMap::new(); - - for cpu in system.cpus() { - let brand = cpu.brand().trim(); - let total_cores = System::physical_core_count(); - - if processor_count.contains_key(brand) { - processor_count.get_mut(brand).unwrap().threads += 1; - continue; - } - processor_count.insert( - brand.to_string(), - ProcessorInfo { - vendor: cpu.vendor_id().trim().to_string(), - brand: brand.to_string(), - total_system_cores: if let Some(cores) = total_cores { - cores.to_string() - } else { - String::from("Unknown") - }, - threads: 1, - architecture: System::cpu_arch().trim().to_string(), - byte_order: if cfg!(target_endian = "little") { - String::from("little-endian") - } else { - String::from("big-endian") - }, - }, - ); - } - - for (_brand, info) in processor_count { - processors.push(info); - } - - CPUInfo { cpus: processors } - } - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod memory { - use humansize::{DECIMAL, make_format}; - use serde::Serialize; - use serde_json::{Value, json}; - use sysinfo::System; - - #[derive(Debug, Serialize)] - pub struct PhysicalInfo { - total: String, - used: String, - free: String, - available: String, - } - - #[derive(Debug, Serialize)] - pub struct VirtualInfo { - total: String, - used: String, - free: String, - } - - #[derive(Debug, Serialize)] - pub struct MemoryInfo { - physical: PhysicalInfo, - virtual_swap: VirtualInfo, - } - - pub fn get_struct() -> MemoryInfo { - let system = System::new_all(); - let formatter = make_format(DECIMAL); - - MemoryInfo { - physical: PhysicalInfo { - total: formatter(system.total_memory()), - used: formatter(system.used_memory()), - free: formatter(system.free_memory()), - available: formatter(system.available_memory()), - }, - virtual_swap: VirtualInfo { - total: formatter(system.total_swap()), - used: formatter(system.used_swap()), - free: formatter(system.free_swap()), - }, - } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod os { - use detect_desktop_environment::DesktopEnvironment; - use serde::Serialize; - use serde_json::{Value, json}; - use sysinfo::System; - - #[derive(Debug, Serialize)] - pub struct OSInfo { - name: String, - edition: String, - version: String, - architecture: String, - kernel: String, - de: String, - } - - pub fn get_struct() -> OSInfo { - OSInfo { - name: System::name().unwrap_or(String::from("Unknown")), - edition: System::long_os_version().unwrap_or(String::from("Unknown")), - version: System::os_version().unwrap_or(String::from("Unknown")), - architecture: if cfg!(target_pointer_width = "64") { - String::from("64 bit") - } else if cfg!(target_pointer_width = "32") { - String::from("32 bit") - } else { - String::from("16 bit") - }, - kernel: System::kernel_long_version(), - de: match DesktopEnvironment::detect() { - Some(de) => format!("{de:?}"), - None => String::from(""), - }, - } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod storage { - use humansize::{DECIMAL, make_format}; - use serde::Serialize; - use serde_json::{Value, json}; - use sysinfo::Disks; - - #[derive(Debug, Serialize)] - pub struct StorageInfo { - name: String, - mount_point: String, - kind: String, - space_left: String, - total: String, - } - - pub fn get_list() -> Vec { - let disks = Disks::new_with_refreshed_list(); - let mut drive_data = Vec::new(); - let formatter = make_format(DECIMAL); - - for disk in disks.list() { - drive_data.push(StorageInfo { - name: format!("{:?}", disk.name()).trim_matches('\"').to_string(), - mount_point: format!("{:?}", disk.mount_point()) - .replace("\\", "") - .trim_matches('\"') - .to_string(), - kind: format!("{:?}", disk.kind()), - space_left: formatter(disk.available_space()), - total: formatter(disk.total_space()), - }); - } - - drive_data - } - - pub fn get_json() -> Value { - json!(get_list()) - } -} - -pub mod network { - use serde::Serialize; - use serde_json::{Value, json}; - use sysinfo::Networks; - - #[derive(Debug, Serialize)] - pub struct NetworkInfo { - adapters: Vec, - } - - pub fn get_struct() -> NetworkInfo { - let networks = Networks::new_with_refreshed_list(); - let mut adapters = Vec::new(); - - for (interface_name, _network_data) in &networks { - adapters.push(interface_name.to_string()); - } - - NetworkInfo { adapters } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod external { - use serde::Serialize; - use serde_json::{Value, json}; - use std::{cmp::Ordering::Equal, collections::HashMap}; - use sysinfo::{System, Users}; - - #[derive(Debug, Serialize)] - pub struct SoftwareInfo { - name: String, - count: usize, - } - - #[derive(Debug, Serialize)] - pub struct ExternalInfo { - softwares: Vec, - } - - pub fn get_struct() -> ExternalInfo { - let mut system = System::new_all(); - system.refresh_all(); - - let users = &Users::new_with_refreshed_list(); - let mut grouped_processes: HashMap> = HashMap::new(); - - for process in system.processes().values() { - let name = process.name().to_str().unwrap().to_string(); - let user_id = process.user_id(); - let is_user_owned = user_id.is_some_and(|uid| { - users - .list() - .iter() - .any(|u| u.id() == uid && u.name() != "root") - }); - - if is_user_owned && !name.trim().is_empty() && !name.starts_with('[') { - grouped_processes - .entry(name) - .or_default() - .push(process.pid().as_u32() as i32); - } - } - - let mut softwares = Vec::new(); - let mut grouped_vec: Vec<_> = grouped_processes.into_iter().collect(); - grouped_vec.sort_by(|a, b| match b.1.len().cmp(&a.1.len()) { - Equal => a.0.to_lowercase().cmp(&b.0.to_lowercase()), - other => other, - }); - - for (name, pids) in grouped_vec { - softwares.push(SoftwareInfo { - name, - count: pids.len(), - }); - } - - ExternalInfo { softwares } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod devices { - use serde::Serialize; - use serde_json::{Value, json}; - extern crate hidapi; - use hidapi::HidApi; - use std::collections::HashMap; - - #[derive(Debug, Serialize)] - pub struct DeviceInfo { - manufacturer: String, - products: Vec, - } - - #[derive(Debug, Serialize)] - pub struct DevicesInfo { - devices: Vec, - } - - pub fn get_struct() -> DevicesInfo { - let api = HidApi::new().unwrap(); - let mut grouped_devices: HashMap> = HashMap::new(); - - for device in api.device_list() { - let manufacturer = device - .manufacturer_string() - .unwrap_or("Unknown") - .to_string() - .to_lowercase(); - let product = device.product_string().unwrap_or("Unknown").to_string(); - - if !manufacturer.trim().is_empty() && !product.trim().is_empty() { - let entry = grouped_devices.entry(manufacturer).or_default(); - - if !entry.contains(&product) { - entry.push(product); - } - } - } - - let mut devices = Vec::new(); - let mut grouped_vec: Vec<_> = grouped_devices.into_iter().collect(); - grouped_vec.sort_by(|a, b| a.0.to_lowercase().cmp(&b.0.to_lowercase())); - - for (manufacturer, products) in grouped_vec { - devices.push(DeviceInfo { - manufacturer, - products, - }); - } - - DevicesInfo { devices } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod meta { - use serde::Serialize; - use serde_json::{Value, from_str, json}; - use std::{collections::HashMap, fs}; - use sys_locale::get_locale; - - include!(concat!(env!("OUT_DIR"), "/built.rs")); - - #[derive(Debug, Serialize)] - pub struct MetaInfo { - version: String, - commit_hash: String, - commit_short_hash: String, - locale: String, - language: String, - territory: String, - } - - pub fn get_struct() -> MetaInfo { - let default = String::from("Unknown"); - let locale = get_locale().unwrap_or_else(|| String::from("en-US")); - let split_locale: Vec<&str> = locale.split("-").collect(); - - let language_json = fs::read_to_string("subcrates/telemetry/src/languages.json").unwrap(); - let parsed_languages = from_str::>(&language_json).unwrap(); - let language_map = parsed_languages.get(split_locale[0]).unwrap_or(&default); - - let territory_json = - fs::read_to_string("subcrates/telemetry/src/territories.json").unwrap(); - let parsed_territories = from_str::>(&territory_json).unwrap(); - let territory_map = parsed_territories.get(split_locale[1]).unwrap_or(&default); - - MetaInfo { - version: env!("CARGO_PKG_VERSION").to_string(), - commit_hash: GIT_COMMIT_HASH.to_string(), - commit_short_hash: GIT_COMMIT_SHORT_HASH.to_string(), - locale, - language: language_map.to_string(), - territory: territory_map.to_string(), - } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} - -pub mod uptime { - use chrono::{DateTime, Utc}; - use serde::Serialize; - use serde_json::{Value, json}; - use std::time::Duration as StdDuration; - use sysinfo::System; - - #[derive(Debug, Serialize)] - pub struct DateInfo { - zone: String, - date: String, - time: String, - } - - #[derive(Debug, Serialize)] - pub struct UptimeInfo { - boot: DateInfo, - now: DateInfo, - relative: String, - } - - pub fn format_duration(duration: StdDuration) -> String { - let mut parts = Vec::new(); - let mut remaining = duration.as_secs(); - let units = [ - (" months", 30 * 24 * 60 * 60), - (" weeks", 7 * 24 * 60 * 60), - (" days", 24 * 60 * 60), - (" hours", 60 * 60), - (" minutes", 60), - (" seconds", 1), - ]; - - for &(label, unit_secs) in &units { - match remaining / unit_secs { - 0 => continue, - value => { - parts.push(format!("{}{}", value, label)); - remaining %= unit_secs; - } - } - } - - if parts.is_empty() { - parts.push("0 seconds".to_string()); - } - - parts.join(", ") - } - - pub fn get_struct() -> UptimeInfo { - let boot_time: DateTime = - DateTime::::from_timestamp(System::boot_time() as i64, 0) - .expect("Invalid or out-of-range timestamp"); - let relative_time = StdDuration::from_secs((Utc::now() - boot_time).num_seconds() as u64); - - UptimeInfo { - boot: DateInfo { - zone: String::from("UTC"), - date: boot_time.format("%Y-%m-%d").to_string(), - time: boot_time.format("%H:%M:%S").to_string(), - }, - now: DateInfo { - zone: String::from("UTC"), - date: Utc::now().format("%Y-%m-%d").to_string(), - time: Utc::now().format("%H:%M:%S").to_string(), - }, - relative: format_duration(relative_time).to_string(), - } - } - - pub fn get_json() -> Value { - json!(get_struct()) - } -} +#[macro_use] +mod modules; +use crate::modules::{cpu, devices, external, gpu, memory, meta, network, os, storage, uptime}; +use anyhow::Result; #[derive(Debug, Serialize)] pub struct TelemetryInfo { @@ -692,23 +24,25 @@ pub struct AllInfo { uptime: uptime::UptimeInfo, } -pub fn get_struct() -> TelemetryInfo { - TelemetryInfo { +#[allow(dead_code)] +pub fn get_struct() -> Result { + Ok(TelemetryInfo { telemetry: AllInfo { gpu: gpu::get_struct(), cpu: cpu::get_struct(), memory: memory::get_struct(), - os: os::get_struct(), - storage: storage::get_list(), + os: os::get_struct()?, + storage: storage::get_list()?, network: network::get_struct(), external: external::get_struct(), - devices: devices::get_struct(), - meta: meta::get_struct(), - uptime: uptime::get_struct(), + devices: devices::get_struct()?, + meta: meta::get_struct()?, + uptime: uptime::get_struct()?, }, - } + }) } -pub fn get_json() -> Value { - json!(get_struct()) +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/cpu.rs b/subcrates/telemetry/src/modules/cpu.rs new file mode 100644 index 0000000..b40d671 --- /dev/null +++ b/subcrates/telemetry/src/modules/cpu.rs @@ -0,0 +1,69 @@ +use super::Defaults::Unknown; +use serde::Serialize; +use serde_json::{Value, json}; +use std::collections::HashMap; +use sysinfo::{CpuRefreshKind, RefreshKind, System}; + +#[derive(Debug, Serialize)] +pub struct ProcessorInfo { + vendor: String, + brand: String, + total_system_cores: String, + threads: u16, + architecture: String, + byte_order: String, +} + +#[derive(Debug, Serialize)] +pub struct CPUInfo { + cpus: Vec, +} + +#[allow(dead_code)] +pub fn get_struct() -> CPUInfo { + let system = + System::new_with_specifics(RefreshKind::nothing().with_cpu(CpuRefreshKind::everything())); + + let mut processors = Vec::new(); + let mut processor_count: HashMap = HashMap::new(); + + for cpu in system.cpus() { + let brand = cpu.brand().trim(); + let total_cores = System::physical_core_count(); + + if processor_count.contains_key(brand) { + processor_count.get_mut(brand).unwrap().threads += 1; + continue; + } + processor_count.insert( + brand.to_string(), + ProcessorInfo { + vendor: cpu.vendor_id().trim().to_string(), + brand: brand.to_string(), + total_system_cores: if let Some(cores) = total_cores { + cores.to_string() + } else { + Unknown.into() + }, + threads: 1, + architecture: System::cpu_arch().trim().to_string(), + byte_order: if cfg!(target_endian = "little") { + String::from("little-endian") + } else { + String::from("big-endian") + }, + }, + ); + } + + for (_brand, info) in processor_count { + processors.push(info); + } + + CPUInfo { cpus: processors } +} + +#[allow(dead_code)] +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/modules/devices.rs b/subcrates/telemetry/src/modules/devices.rs new file mode 100644 index 0000000..81cf169 --- /dev/null +++ b/subcrates/telemetry/src/modules/devices.rs @@ -0,0 +1,59 @@ +//use crate::custom_anyhow; +use anyhow::Result; +use serde::Serialize; +use serde_json::{Value, json}; +extern crate hidapi; +use hidapi::HidApi; +use std::collections::HashMap; + +#[derive(Debug, Serialize)] +pub struct DeviceInfo { + manufacturer: String, + products: Vec, +} + +#[derive(Debug, Serialize)] +pub struct DevicesInfo { + devices: Vec, +} + +#[allow(dead_code)] +pub fn get_struct() -> Result { + let api = HidApi::new().unwrap(); + let mut grouped_devices: HashMap> = HashMap::new(); + + for device in api.device_list() { + let manufacturer = device + .manufacturer_string() + .unwrap_or("Unknown") + .to_string() + .to_lowercase(); + let product = device.product_string().unwrap_or("Unknown").to_string(); + + if !manufacturer.trim().is_empty() && !product.trim().is_empty() { + let entry = grouped_devices.entry(manufacturer).or_default(); + + if !entry.contains(&product) { + entry.push(product); + } + } + } + + let mut devices = Vec::new(); + let mut grouped_vec: Vec<_> = grouped_devices.into_iter().collect(); + grouped_vec.sort_by(|a, b| a.0.to_lowercase().cmp(&b.0.to_lowercase())); + + for (manufacturer, products) in grouped_vec { + devices.push(DeviceInfo { + manufacturer, + products, + }); + } + + Ok(DevicesInfo { devices }) +} + +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) +} diff --git a/subcrates/telemetry/src/modules/external.rs b/subcrates/telemetry/src/modules/external.rs new file mode 100644 index 0000000..7987df8 --- /dev/null +++ b/subcrates/telemetry/src/modules/external.rs @@ -0,0 +1,63 @@ +use serde::Serialize; +use serde_json::{Value, json}; +use std::{cmp::Ordering::Equal, collections::HashMap}; +use sysinfo::{System, Users}; + +#[derive(Debug, Serialize)] +pub struct SoftwareInfo { + name: String, + count: usize, +} + +#[derive(Debug, Serialize)] +pub struct ExternalInfo { + softwares: Vec, +} + +#[allow(dead_code)] +pub fn get_struct() -> ExternalInfo { + let mut system = System::new_all(); + system.refresh_all(); + + let users = &Users::new_with_refreshed_list(); + let mut grouped_processes: HashMap> = HashMap::new(); + + for process in system.processes().values() { + let name = process.name().to_str().unwrap().to_string(); + let user_id = process.user_id(); + let is_user_owned = user_id.is_some_and(|uid| { + users + .list() + .iter() + .any(|u| u.id() == uid && u.name() != "root") + }); + + if is_user_owned && !name.trim().is_empty() && !name.starts_with('[') { + grouped_processes + .entry(name) + .or_default() + .push(process.pid().as_u32() as i32); + } + } + + let mut softwares = Vec::new(); + let mut grouped_vec: Vec<_> = grouped_processes.into_iter().collect(); + grouped_vec.sort_by(|a, b| match b.1.len().cmp(&a.1.len()) { + Equal => a.0.to_lowercase().cmp(&b.0.to_lowercase()), + other => other, + }); + + for (name, pids) in grouped_vec { + softwares.push(SoftwareInfo { + name, + count: pids.len(), + }); + } + + ExternalInfo { softwares } +} + +#[allow(dead_code)] +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/modules/formatted/architecture.rs b/subcrates/telemetry/src/modules/formatted/architecture.rs new file mode 100644 index 0000000..b875991 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/architecture.rs @@ -0,0 +1,55 @@ +use serde::Serialize; +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize)] +pub enum TargetPointerWidth { + W32Bit, + W64Bit, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct FmtOSArchitecture(pub TargetPointerWidth); + +impl FmtOSArchitecture { + pub const W32_BIT: Self = FmtOSArchitecture(TargetPointerWidth::W32Bit); + pub const W64_BIT: Self = FmtOSArchitecture(TargetPointerWidth::W64Bit); +} + +impl Display for FmtOSArchitecture { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!( + f, + "{}", + match self.0 { + TargetPointerWidth::W32Bit => "32 Bit", + TargetPointerWidth::W64Bit => "64 Bit", + } + ) + } +} + +impl Debug for FmtOSArchitecture { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtOSArchitecture { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtOSArchitecture { + type Target = TargetPointerWidth; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/subcrates/telemetry/src/modules/formatted/bytes.rs b/subcrates/telemetry/src/modules/formatted/bytes.rs new file mode 100644 index 0000000..598fc81 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/bytes.rs @@ -0,0 +1,38 @@ +use serde::Serialize; +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct FmtBytes(pub u64); + +impl Display for FmtBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + use humansize::{DECIMAL, format_size}; + write!(f, "{}", format_size(self.0, DECIMAL)) + } +} + +impl Debug for FmtBytes { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtBytes { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtBytes { + type Target = u64; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/subcrates/telemetry/src/modules/formatted/date_time.rs b/subcrates/telemetry/src/modules/formatted/date_time.rs new file mode 100644 index 0000000..8c26003 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/date_time.rs @@ -0,0 +1,125 @@ +use chrono::{DateTime, Local, TimeZone, Utc}; +use serde::Serialize; +use std::{ + fmt::{Debug, Display, Formatter, Result as FMTResult}, + ops::Deref, +}; + +#[derive(Debug, Serialize)] +pub struct DateTimeInfo { + date: String, + time: String, +} + +#[derive(Clone)] +pub struct FmtDateTime(pub DateTime); + +impl Display for FmtDateTime +where + Tz: TimeZone, + Tz::Offset: std::fmt::Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> FMTResult { + write!( + f, + "{:#?}", + DateTimeInfo { + date: self.0.format("%Y-%m-%d").to_string(), + time: self.0.format("%H:%M:%S").to_string() + } + ) + } +} + +impl Debug for FmtDateTime +where + Tz::Offset: std::fmt::Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> FMTResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtDateTime +where + DateTime: Display, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtDateTime { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Eq for FmtDateTime where DateTime: Eq {} +impl PartialEq for FmtDateTime +where + DateTime: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl PartialOrd for FmtDateTime +where + DateTime: PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for FmtDateTime +where + DateTime: Ord, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl From> for FmtDateTime { + fn from(dt: FmtDateTime) -> Self { + FmtDateTime(dt.0.with_timezone(&Local)) + } +} + +impl From> for FmtDateTime { + fn from(dt: FmtDateTime) -> Self { + FmtDateTime(dt.0.with_timezone(&Utc)) + } +} + +#[allow(dead_code)] +pub trait IntoDateTime { + fn into_utc(self) -> FmtDateTime; + fn into_local(self) -> FmtDateTime; +} + +impl IntoDateTime for FmtDateTime { + fn into_utc(self) -> FmtDateTime { + FmtDateTime(self.0.with_timezone(&Utc)) + } + fn into_local(self) -> FmtDateTime { + self + } +} + +impl IntoDateTime for FmtDateTime { + fn into_local(self) -> FmtDateTime { + FmtDateTime(self.0.with_timezone(&Local)) + } + fn into_utc(self) -> FmtDateTime { + self + } +} diff --git a/subcrates/telemetry/src/modules/formatted/desktop_environment.rs b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs new file mode 100644 index 0000000..7f636c1 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs @@ -0,0 +1,59 @@ +use detect_desktop_environment::DesktopEnvironment; +use serde::{Serialize, Serializer}; +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, +}; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct SerdeDE(pub DesktopEnvironment); + +impl Serialize for SerdeDE { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&format!("{:?}", self.0)) + } +} + +impl SerdeDE { + pub fn detect() -> Option { + DesktopEnvironment::detect().map(SerdeDE) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct FmtDE(pub SerdeDE); + +impl FmtDE { + pub fn detect() -> Option { + SerdeDE::detect().map(FmtDE) + } +} + +impl Display for FmtDE { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{:?}", self.0.0) + } +} + +impl Debug for FmtDE { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtDE { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtDE { + type Target = SerdeDE; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/subcrates/telemetry/src/modules/formatted/mod.rs b/subcrates/telemetry/src/modules/formatted/mod.rs new file mode 100644 index 0000000..38987d8 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/mod.rs @@ -0,0 +1,7 @@ +pub mod architecture; +pub mod bytes; +pub mod date_time; +pub mod desktop_environment; +pub mod offset_time; +pub mod relative_time; +pub mod version; diff --git a/subcrates/telemetry/src/modules/formatted/offset_time.rs b/subcrates/telemetry/src/modules/formatted/offset_time.rs new file mode 100644 index 0000000..36d4215 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/offset_time.rs @@ -0,0 +1,68 @@ +use chrono::{DateTime, Local, Offset}; +use serde::Serialize; +use std::{ + cmp::Ordering, + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, +}; + +#[derive(Copy, Clone)] +pub struct FmtOffsetTime(pub DateTime); + +impl Display for FmtOffsetTime { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "UTC{}", self.0.offset()) + } +} + +impl Debug for FmtOffsetTime { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtOffsetTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtOffsetTime { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Eq for FmtOffsetTime {} +impl PartialEq for FmtOffsetTime { + fn eq(&self, other: &Self) -> bool { + self.0.offset().fix() == other.0.offset().fix() + } +} + +impl PartialOrd for FmtOffsetTime { + fn partial_cmp(&self, other: &Self) -> Option { + Some( + self.0 + .offset() + .fix() + .local_minus_utc() + .cmp(&other.0.offset().fix().local_minus_utc()), + ) + } +} + +impl Ord for FmtOffsetTime { + fn cmp(&self, other: &Self) -> Ordering { + self.0 + .offset() + .fix() + .local_minus_utc() + .cmp(&other.0.offset().fix().local_minus_utc()) + } +} diff --git a/subcrates/telemetry/src/modules/formatted/relative_time.rs b/subcrates/telemetry/src/modules/formatted/relative_time.rs new file mode 100644 index 0000000..0e08c62 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/relative_time.rs @@ -0,0 +1,40 @@ +use serde::Serialize; +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, + time::Duration, +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct FmtRelativeTime(pub Duration); + +impl Display for FmtRelativeTime { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let formatter = timeago::Formatter::new(); + + write!(f, "{}", formatter.convert(self.0)) + } +} + +impl Debug for FmtRelativeTime { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtRelativeTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtRelativeTime { + type Target = Duration; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/subcrates/telemetry/src/modules/formatted/version.rs b/subcrates/telemetry/src/modules/formatted/version.rs new file mode 100644 index 0000000..ccd741e --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/version.rs @@ -0,0 +1,38 @@ +use serde::Serialize; +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::Deref, +}; +use versions::Versioning; + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct FmtVersion(pub Versioning); + +impl Display for FmtVersion { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{}", self.0) + } +} + +impl Debug for FmtVersion { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } +} + +impl Serialize for FmtVersion { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Deref for FmtVersion { + type Target = Versioning; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/subcrates/telemetry/src/modules/gpu/mod.rs b/subcrates/telemetry/src/modules/gpu/mod.rs new file mode 100644 index 0000000..af1e374 --- /dev/null +++ b/subcrates/telemetry/src/modules/gpu/mod.rs @@ -0,0 +1,131 @@ +use super::Defaults::Unknown; +use serde::Serialize; +use serde_json::{Value, json}; +use wgpu; +use winit::{ + application::ApplicationHandler, + event::WindowEvent, + event_loop::{ActiveEventLoop, EventLoop}, + window::WindowId, +}; + +mod vram; + +#[derive(Debug, Serialize)] +pub struct DriverInfo { + version: String, + name: String, +} + +#[derive(Debug, Serialize)] +pub struct AdapterInfo { + vendor: String, + model: String, + driver: DriverInfo, + vram: String, + display: DisplayInfo, +} + +#[derive(Debug, Serialize)] +pub struct GPUInfo { + supported_backends: Vec, + gpus: Vec, +} + +#[derive(Debug, Serialize, Default)] +pub struct DisplayInfo { + resolution: String, + refresh_rate: String, +} + +impl ApplicationHandler for DisplayInfo { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if let Some(monitor) = event_loop.primary_monitor() { + let size = monitor.size(); + let refresh_rate = monitor.refresh_rate_millihertz(); + + self.resolution = format!("{}x{}", size.width, size.height); + self.refresh_rate = if let Some(refresh) = refresh_rate { + format!("{} hz", refresh / 1000) + } else { + Unknown.into() + } + } else { + self.resolution = Unknown.into(); + self.refresh_rate = Unknown.into(); + } + + event_loop.exit(); + } + + fn window_event( + &mut self, + _event_loop: &ActiveEventLoop, + _window_id: WindowId, + _event: WindowEvent, + ) { + } +} + +fn vendor_name(vendor: u32) -> &'static str { + match vendor { + 0x10DE => "NVIDIA", + 0x1002 => "AMD(Advanced Micro Devices), Inc.", + 0x8086 => "Intel(integrated electronics)", + 0x13B5 => "ARM(Advanced RISC Machines)", + 0x5143 => "Qualcomm(Quality Communications)", + 0x1010 => "Apple Inc.", + _ => "Unknown", + } +} + +#[allow(dead_code)] +pub fn get_struct() -> GPUInfo { + let mut gpu_data: Vec = Vec::new(); + let mut backends: Vec = Vec::new(); + let instance_descriptor = wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + flags: wgpu::InstanceFlags::empty(), + backend_options: Default::default(), + }; + let instance = wgpu::Instance::new(&instance_descriptor); + let event_loop = EventLoop::new().unwrap(); + let mut app = DisplayInfo::default(); + + event_loop.run_app(&mut app).unwrap(); + + for adapter in instance.enumerate_adapters(wgpu::Backends::all()) { + let info = adapter.get_info(); + + if !backends.contains(&info.backend.to_string()) { + backends.push(info.backend.to_string()); + } + if info.driver.is_empty() || info.driver_info.is_empty() { + continue; + } + + gpu_data.push(AdapterInfo { + vendor: vendor_name(info.vendor).to_string(), + model: info.name, + driver: DriverInfo { + version: info.driver_info, + name: info.driver, + }, + vram: vram::get(info.vendor, info.device), + display: DisplayInfo { + resolution: app.resolution.to_string(), + refresh_rate: app.refresh_rate.to_string(), + }, + }); + } + + GPUInfo { + supported_backends: backends, + gpus: gpu_data, + } +} + +#[allow(dead_code)] +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/modules/gpu/vram.rs b/subcrates/telemetry/src/modules/gpu/vram.rs new file mode 100644 index 0000000..0fd854c --- /dev/null +++ b/subcrates/telemetry/src/modules/gpu/vram.rs @@ -0,0 +1,67 @@ +use super::super::Defaults::Unknown; +use ash::vk::{API_VERSION_1_2, ApplicationInfo, InstanceCreateInfo, MemoryHeapFlags}; +use humansize::{DECIMAL, make_format}; + +#[cfg(not(target_os = "macos"))] +pub fn get_metal() -> u64 { + 0 +} + +#[cfg(target_os = "macos")] +pub fn get_metal() -> u64 { + use metal::Device as MetalDevice; + + let device = MetalDevice::system_default().expect("No Metal-compatible GPU found"); + device.recommended_max_working_set_size() +} + +pub fn get_vulkan(device_id: u32) -> u64 { + let entry = unsafe { ash::Entry::load().unwrap() }; + let app_info = ApplicationInfo { + p_application_name: std::ptr::null(), + application_version: 0, + p_engine_name: std::ptr::null(), + engine_version: 0, + api_version: API_VERSION_1_2, + ..Default::default() + }; + + let create_info = InstanceCreateInfo { + p_application_info: &app_info, + ..Default::default() + }; + + let instance = unsafe { entry.create_instance(&create_info, None).unwrap() }; + + let physical_devices = unsafe { instance.enumerate_physical_devices().unwrap() }; + let mut total_vram = 0; + + for device in physical_devices { + let memory_properties = unsafe { instance.get_physical_device_memory_properties(device) }; + let device_properties = unsafe { instance.get_physical_device_properties(device) }; + + if device_id != device_properties.device_id { + continue; + } + + for heap in memory_properties.memory_heaps { + if heap.flags.contains(MemoryHeapFlags::DEVICE_LOCAL) { + total_vram += heap.size; + } + } + + break; + } + + total_vram +} + +pub fn get(vendor: u32, device_id: u32) -> String { + let formatter = make_format(DECIMAL); + + match vendor { + 0x10DE | 0x1002 | 0x8086 | 0x5143 => formatter(get_vulkan(device_id)), + 0x1010 => formatter(get_metal()), + _ => Unknown.into(), + } +} diff --git a/subcrates/telemetry/src/modules/macros/custom_anyhow.rs b/subcrates/telemetry/src/modules/macros/custom_anyhow.rs new file mode 100644 index 0000000..7b0ca67 --- /dev/null +++ b/subcrates/telemetry/src/modules/macros/custom_anyhow.rs @@ -0,0 +1,11 @@ +#[macro_export] +macro_rules! custom_anyhow { + ($fmt:literal $(, $arg:expr)* $(,)?) => { + ::anyhow::anyhow!( + concat!($fmt, " (file: {}, line: {})"), + $($arg,)* + file!(), + line!() + ) + }; +} diff --git a/subcrates/telemetry/src/modules/macros/mod.rs b/subcrates/telemetry/src/modules/macros/mod.rs new file mode 100644 index 0000000..ec3320c --- /dev/null +++ b/subcrates/telemetry/src/modules/macros/mod.rs @@ -0,0 +1 @@ +pub mod custom_anyhow; diff --git a/subcrates/telemetry/src/modules/memory.rs b/subcrates/telemetry/src/modules/memory.rs new file mode 100644 index 0000000..0dd39b0 --- /dev/null +++ b/subcrates/telemetry/src/modules/memory.rs @@ -0,0 +1,49 @@ +use crate::modules::FmtBytes; +use serde::Serialize; +use serde_json::{Value, json}; +use sysinfo::System; + +#[derive(Debug, Serialize)] +pub struct PhysicalInfo { + total: FmtBytes, + used: FmtBytes, + free: FmtBytes, + available: FmtBytes, +} + +#[derive(Debug, Serialize)] +pub struct VirtualInfo { + total: FmtBytes, + used: FmtBytes, + free: FmtBytes, +} + +#[derive(Debug, Serialize)] +pub struct MemoryInfo { + physical: PhysicalInfo, + virtual_swap: VirtualInfo, +} + +#[allow(dead_code)] +pub fn get_struct() -> MemoryInfo { + let system = System::new_all(); + + MemoryInfo { + physical: PhysicalInfo { + total: FmtBytes(system.total_memory()), + used: FmtBytes(system.used_memory()), + free: FmtBytes(system.free_memory()), + available: FmtBytes(system.available_memory()), + }, + virtual_swap: VirtualInfo { + total: FmtBytes(system.total_swap()), + used: FmtBytes(system.used_swap()), + free: FmtBytes(system.free_swap()), + }, + } +} + +#[allow(dead_code)] +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/modules/meta.rs b/subcrates/telemetry/src/modules/meta.rs new file mode 100644 index 0000000..c0a91f2 --- /dev/null +++ b/subcrates/telemetry/src/modules/meta.rs @@ -0,0 +1,33 @@ +use crate::{custom_anyhow, modules::FmtVersion}; +use anyhow::Result; +use serde::Serialize; +use serde_json::{Value, json}; +use sys_locale::get_locale; +use versions::Versioning; + +include!(concat!(env!("OUT_DIR"), "/built.rs")); + +#[derive(Debug, Serialize)] +pub struct MetaInfo { + version: FmtVersion, + commit_hash: String, + locale: String, +} + +#[allow(dead_code)] +pub fn get_struct() -> Result { + let locale = get_locale().unwrap_or_else(|| String::from("en-US")); + let version = Versioning::new(env!("CARGO_PKG_VERSION")) + .ok_or(custom_anyhow!("Invalid version").context("Invalid Semver version"))?; + + Ok(MetaInfo { + version: FmtVersion(version), + commit_hash: GIT_COMMIT_HASH.to_string(), + locale, + }) +} + +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) +} diff --git a/subcrates/telemetry/src/modules/mod.rs b/subcrates/telemetry/src/modules/mod.rs new file mode 100644 index 0000000..2d3ade2 --- /dev/null +++ b/subcrates/telemetry/src/modules/mod.rs @@ -0,0 +1,42 @@ +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; + +pub mod cpu; +pub mod devices; +pub mod external; +pub mod formatted; +pub mod gpu; +pub mod macros; +pub mod memory; +pub mod meta; +pub mod network; +pub mod os; +pub mod storage; +pub mod uptime; + +#[allow(unused_imports)] +pub use formatted::{ + architecture::FmtOSArchitecture, + bytes::FmtBytes, + date_time::{FmtDateTime, IntoDateTime}, + desktop_environment::FmtDE, + offset_time::FmtOffsetTime, + relative_time::FmtRelativeTime, + version::FmtVersion, +}; + +#[derive(Debug)] +pub enum Defaults { + Unknown, +} + +impl Display for Defaults { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{:?}", self) + } +} + +impl From for String { + fn from(value: Defaults) -> Self { + value.to_string() + } +} diff --git a/subcrates/telemetry/src/modules/network.rs b/subcrates/telemetry/src/modules/network.rs new file mode 100644 index 0000000..4d8dc47 --- /dev/null +++ b/subcrates/telemetry/src/modules/network.rs @@ -0,0 +1,25 @@ +use serde::Serialize; +use serde_json::{Value, json}; +use sysinfo::Networks; + +#[derive(Debug, Serialize)] +pub struct NetworkInfo { + adapters: Vec, +} + +#[allow(dead_code)] +pub fn get_struct() -> NetworkInfo { + let networks = Networks::new_with_refreshed_list(); + let mut adapters = Vec::new(); + + for (interface_name, _network_data) in &networks { + adapters.push(interface_name.to_string()); + } + + NetworkInfo { adapters } +} + +#[allow(dead_code)] +pub fn get_json() -> Value { + json!(get_struct()) +} diff --git a/subcrates/telemetry/src/modules/os.rs b/subcrates/telemetry/src/modules/os.rs new file mode 100644 index 0000000..dd3a4e2 --- /dev/null +++ b/subcrates/telemetry/src/modules/os.rs @@ -0,0 +1,54 @@ +use super::Defaults::Unknown; +use crate::{ + custom_anyhow, + modules::{FmtDE, FmtOSArchitecture}, +}; +use anyhow::Result; +use serde::Serialize; +use serde_json::{Value, json}; +use sysinfo::System; + +#[derive(Debug, Serialize)] +pub struct OSInfo { + name: String, + edition: String, + version: String, + architecture: FmtOSArchitecture, + kernel: Option, + desktop_environment: Option, +} + +#[allow(dead_code)] +pub fn get_struct() -> Result { + let architecture = if cfg!(target_pointer_width = "64") { + Ok(FmtOSArchitecture::W64_BIT) + } else if cfg!(target_pointer_width = "32") { + Ok(FmtOSArchitecture::W32_BIT) + } else { + Err(custom_anyhow!("Unsupported pointer width").context("16 bit systems are not supported")) + }?; + let kernel = if cfg!(target_os = "linux") || cfg!(target_os = "macos") { + Some(System::kernel_long_version()) + } else { + None + }; + let desktop_environment = if cfg!(target_os = "linux") { + FmtDE::detect() + } else { + None + }; + + Ok(OSInfo { + name: System::name().unwrap_or(Unknown.into()), + edition: System::long_os_version().unwrap_or(Unknown.into()), + version: System::os_version().unwrap_or(Unknown.into()), + architecture, + kernel, + desktop_environment, + }) +} + +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) +} diff --git a/subcrates/telemetry/src/modules/storage.rs b/subcrates/telemetry/src/modules/storage.rs new file mode 100644 index 0000000..62c9a23 --- /dev/null +++ b/subcrates/telemetry/src/modules/storage.rs @@ -0,0 +1,46 @@ +use crate::{custom_anyhow, modules::FmtBytes}; +use anyhow::Result; +use serde::Serialize; +use serde_json::{Value, json}; +pub use sysinfo::DiskKind; +use sysinfo::Disks; + +#[derive(Debug, Serialize)] +pub struct StorageInfo { + name: String, + mount_point: String, + disk_kind: DiskKind, + space_left: FmtBytes, + total: FmtBytes, +} + +#[allow(dead_code)] +pub fn get_list() -> Result> { + let disks = Disks::new_with_refreshed_list(); + let mut drive_data = Vec::new(); + + for disk in disks.list() { + drive_data.push(StorageInfo { + name: format!("{:?}", disk.name()).trim_matches('\"').to_string(), + mount_point: format!("{:?}", disk.mount_point()) + .replace("\\", "") + .trim_matches('\"') + .to_string(), + disk_kind: disk.kind(), + space_left: FmtBytes(disk.available_space()), + total: FmtBytes(disk.total_space()), + }); + } + + if drive_data.is_empty() { + return Err(custom_anyhow!("No storage drives found") + .context("Drive_data is empty, expected disks.list() to return non-zero at line 39")); + } + + Ok(drive_data) +} + +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_list()?)) +} diff --git a/subcrates/telemetry/src/modules/uptime.rs b/subcrates/telemetry/src/modules/uptime.rs new file mode 100644 index 0000000..1c0dbe6 --- /dev/null +++ b/subcrates/telemetry/src/modules/uptime.rs @@ -0,0 +1,54 @@ +use crate::{ + custom_anyhow, + modules::{FmtDateTime, FmtOffsetTime, FmtRelativeTime}, +}; +use anyhow::Result; +use chrono::{DateTime, Local, Utc}; +use serde::Serialize; +use serde_json::{Value, json}; +use std::time::Duration as StdDuration; +use sysinfo::System; + +#[derive(Debug, Serialize)] +struct DateInfo { + time_offset: FmtOffsetTime, + local_date_time: FmtDateTime, + utc_date_time: FmtDateTime, +} + +#[derive(Debug, Serialize)] +pub struct UptimeInfo { + boot: DateInfo, + now: DateInfo, + relative: FmtRelativeTime, +} + +#[allow(dead_code)] +pub fn get_struct() -> Result { + let boot_time_utc = DateTime::::from_timestamp(System::boot_time() as i64, 0).ok_or( + custom_anyhow!("Invalid, or out of range timestamp") + .context("Invalid timestamp: check seconds < 8_220_000_000_000"), + )?; + let boot_time_local: DateTime = boot_time_utc.with_timezone(&Local); + let relative_time = + StdDuration::from_secs((Local::now() - boot_time_local).num_seconds() as u64); + + Ok(UptimeInfo { + boot: DateInfo { + time_offset: FmtOffsetTime(Local::now()), + local_date_time: FmtDateTime(boot_time_local), + utc_date_time: FmtDateTime(boot_time_utc), + }, + now: DateInfo { + time_offset: FmtOffsetTime(Local::now()), + local_date_time: FmtDateTime(Local::now()), + utc_date_time: FmtDateTime(Utc::now()), + }, + relative: FmtRelativeTime(relative_time), + }) +} + +#[allow(dead_code)] +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) +} diff --git a/subcrates/telemetry/src/territories.json b/subcrates/telemetry/src/territories.json deleted file mode 100644 index a062735..0000000 --- a/subcrates/telemetry/src/territories.json +++ /dev/null @@ -1,318 +0,0 @@ -{ - "001": "world", - "002": "Africa", - "003": "North America", - "005": "South America", - "009": "Oceania", - "011": "Western Africa", - "013": "Central America", - "014": "Eastern Africa", - "015": "Northern Africa", - "017": "Middle Africa", - "018": "Southern Africa", - "019": "Americas", - "021": "Northern America", - "029": "Caribbean", - "030": "Eastern Asia", - "034": "Southern Asia", - "035": "Southeast Asia", - "039": "Southern Europe", - "053": "Australasia", - "054": "Melanesia", - "057": "Micronesian Region", - "061": "Polynesia", - "142": "Asia", - "143": "Central Asia", - "145": "Western Asia", - "150": "Europe", - "151": "Eastern Europe", - "154": "Northern Europe", - "155": "Western Europe", - "202": "Sub-Saharan Africa", - "419": "Latin America", - "AC": "Ascension Island", - "AD": "Andorra", - "AE": "United Arab Emirates", - "AF": "Afghanistan", - "AG": "Antigua & Barbuda", - "AI": "Anguilla", - "AL": "Albania", - "AM": "Armenia", - "AO": "Angola", - "AQ": "Antarctica", - "AR": "Argentina", - "AS": "American Samoa", - "AT": "Austria", - "AU": "Australia", - "AW": "Aruba", - "AX": "Åland Islands", - "AZ": "Azerbaijan", - "BA": "Bosnia & Herzegovina", - "BA-alt-short": "Bosnia", - "BB": "Barbados", - "BD": "Bangladesh", - "BE": "Belgium", - "BF": "Burkina Faso", - "BG": "Bulgaria", - "BH": "Bahrain", - "BI": "Burundi", - "BJ": "Benin", - "BL": "St Barthélemy", - "BM": "Bermuda", - "BN": "Brunei", - "BO": "Bolivia", - "BQ": "Caribbean Netherlands", - "BR": "Brazil", - "BS": "Bahamas", - "BT": "Bhutan", - "BV": "Bouvet Island", - "BW": "Botswana", - "BY": "Belarus", - "BZ": "Belize", - "CA": "Canada", - "CC": "Cocos (Keeling) Islands", - "CC-alt-short": "Cocos Islands", - "CD": "Congo - Kinshasa", - "CD-alt-variant": "Congo (DRC)", - "CF": "Central African Republic", - "CG": "Congo - Brazzaville", - "CG-alt-variant": "Congo (Republic)", - "CH": "Switzerland", - "CI": "Côte d’Ivoire", - "CI-alt-variant": "Ivory Coast", - "CK": "Cook Islands", - "CL": "Chile", - "CM": "Cameroon", - "CN": "China", - "CO": "Colombia", - "CP": "Clipperton Island", - "CQ": "Sark", - "CR": "Costa Rica", - "CU": "Cuba", - "CV": "Cape Verde", - "CV-alt-variant": "Cabo Verde", - "CW": "Curaçao", - "CX": "Christmas Island", - "CY": "Cyprus", - "CZ": "Czechia", - "CZ-alt-variant": "Czech Republic", - "DE": "Germany", - "DG": "Diego Garcia", - "DJ": "Djibouti", - "DK": "Denmark", - "DM": "Dominica", - "DO": "Dominican Republic", - "DZ": "Algeria", - "EA": "Ceuta & Melilla", - "EC": "Ecuador", - "EE": "Estonia", - "EG": "Egypt", - "EH": "Western Sahara", - "ER": "Eritrea", - "ES": "Spain", - "ET": "Ethiopia", - "EU": "European Union", - "EZ": "Eurozone", - "FI": "Finland", - "FJ": "Fiji", - "FK": "Falkland Islands", - "FK-alt-variant": "Falkland Islands (Islas Malvinas)", - "FM": "Micronesia", - "FO": "Faroe Islands", - "FR": "France", - "GA": "Gabon", - "GB": "United Kingdom", - "GB-alt-short": "UK", - "GD": "Grenada", - "GE": "Georgia", - "GF": "French Guiana", - "GG": "Guernsey", - "GH": "Ghana", - "GI": "Gibraltar", - "GL": "Greenland", - "GM": "Gambia", - "GN": "Guinea", - "GP": "Guadeloupe", - "GQ": "Equatorial Guinea", - "GR": "Greece", - "GS": "South Georgia & South Sandwich Islands", - "GT": "Guatemala", - "GU": "Guam", - "GW": "Guinea-Bissau", - "GY": "Guyana", - "HK": "Hong Kong SAR China", - "HK-alt-short": "Hong Kong", - "HM": "Heard & McDonald Islands", - "HN": "Honduras", - "HR": "Croatia", - "HT": "Haiti", - "HU": "Hungary", - "IC": "Canary Islands", - "ID": "Indonesia", - "IE": "Ireland", - "IL": "Israel", - "IM": "Isle of Man", - "IN": "India", - "IO": "British Indian Ocean Territory", - "IO-alt-chagos": "Chagos Archipelago", - "IQ": "Iraq", - "IR": "Iran", - "IS": "Iceland", - "IT": "Italy", - "JE": "Jersey", - "JM": "Jamaica", - "JO": "Jordan", - "JP": "Japan", - "KE": "Kenya", - "KG": "Kyrgyzstan", - "KH": "Cambodia", - "KI": "Kiribati", - "KM": "Comoros", - "KN": "St Kitts & Nevis", - "KP": "North Korea", - "KR": "South Korea", - "KW": "Kuwait", - "KY": "Cayman Islands", - "KZ": "Kazakhstan", - "LA": "Laos", - "LB": "Lebanon", - "LC": "St Lucia", - "LI": "Liechtenstein", - "LK": "Sri Lanka", - "LR": "Liberia", - "LS": "Lesotho", - "LT": "Lithuania", - "LU": "Luxembourg", - "LV": "Latvia", - "LY": "Libya", - "MA": "Morocco", - "MC": "Monaco", - "MD": "Moldova", - "ME": "Montenegro", - "MF": "St Martin", - "MG": "Madagascar", - "MH": "Marshall Islands", - "MK": "North Macedonia", - "ML": "Mali", - "MM": "Myanmar (Burma)", - "MM-alt-short": "Myanmar", - "MN": "Mongolia", - "MO": "Macao SAR China", - "MO-alt-short": "Macao", - "MP": "Northern Mariana Islands", - "MQ": "Martinique", - "MR": "Mauritania", - "MS": "Montserrat", - "MT": "Malta", - "MU": "Mauritius", - "MV": "Maldives", - "MW": "Malawi", - "MX": "Mexico", - "MY": "Malaysia", - "MZ": "Mozambique", - "NA": "Namibia", - "NC": "New Caledonia", - "NE": "Niger", - "NF": "Norfolk Island", - "NG": "Nigeria", - "NI": "Nicaragua", - "NL": "Netherlands", - "NO": "Norway", - "NP": "Nepal", - "NR": "Nauru", - "NU": "Niue", - "NZ": "New Zealand", - "NZ-alt-variant": "Aotearoa New Zealand", - "OM": "Oman", - "PA": "Panama", - "PE": "Peru", - "PF": "French Polynesia", - "PG": "Papua New Guinea", - "PH": "Philippines", - "PK": "Pakistan", - "PL": "Poland", - "PM": "St Pierre & Miquelon", - "PN": "Pitcairn Islands", - "PN-alt-short": "Pitcairn", - "PR": "Puerto Rico", - "PS": "Palestinian Territories", - "PS-alt-short": "Palestine", - "PT": "Portugal", - "PW": "Palau", - "PY": "Paraguay", - "QA": "Qatar", - "QO": "Outlying Oceania", - "RE": "Réunion", - "RO": "Romania", - "RS": "Serbia", - "RU": "Russia", - "RW": "Rwanda", - "SA": "Saudi Arabia", - "SB": "Solomon Islands", - "SC": "Seychelles", - "SD": "Sudan", - "SE": "Sweden", - "SG": "Singapore", - "SH": "St Helena", - "SI": "Slovenia", - "SJ": "Svalbard & Jan Mayen", - "SK": "Slovakia", - "SL": "Sierra Leone", - "SM": "San Marino", - "SN": "Senegal", - "SO": "Somalia", - "SR": "Suriname", - "SS": "South Sudan", - "ST": "São Tomé & Príncipe", - "SV": "El Salvador", - "SX": "Sint Maarten", - "SY": "Syria", - "SZ": "Eswatini", - "SZ-alt-variant": "Swaziland", - "TA": "Tristan da Cunha", - "TC": "Turks & Caicos Islands", - "TD": "Chad", - "TF": "French Southern Territories", - "TG": "Togo", - "TH": "Thailand", - "TJ": "Tajikistan", - "TK": "Tokelau", - "TL": "Timor-Leste", - "TL-alt-variant": "East Timor", - "TM": "Turkmenistan", - "TN": "Tunisia", - "TO": "Tonga", - "TR": "Türkiye", - "TR-alt-variant": "Turkey", - "TT": "Trinidad & Tobago", - "TV": "Tuvalu", - "TW": "Taiwan", - "TZ": "Tanzania", - "UA": "Ukraine", - "UG": "Uganda", - "UM": "US Outlying Islands", - "UN": "United Nations", - "UN-alt-short": "UN", - "US": "United States", - "US-alt-short": "US", - "UY": "Uruguay", - "UZ": "Uzbekistan", - "VA": "Vatican City", - "VC": "St Vincent & the Grenadines", - "VE": "Venezuela", - "VG": "British Virgin Islands", - "VI": "US Virgin Islands", - "VN": "Vietnam", - "VU": "Vanuatu", - "WF": "Wallis & Futuna", - "WS": "Samoa", - "XA": "Pseudo-Accents", - "XB": "Pseudo-Bidi", - "XK": "Kosovo", - "YE": "Yemen", - "YT": "Mayotte", - "ZA": "South Africa", - "ZM": "Zambia", - "ZW": "Zimbabwe", - "ZZ": "Unknown Region" - } \ No newline at end of file -- 2.47.2 From f8316f8ee421706f5e274b5d35351ea9e6f1362f Mon Sep 17 00:00:00 2001 From: D0RYU Date: Sat, 3 May 2025 01:08:55 -0400 Subject: [PATCH 3/3] refactored formatted scripts cpu struct types being worked on cpu error handling fixed moved from anyhow -> thiserror other shit i'm too tired to mention --- Cargo.lock | 77 ++++++++++++++-- src/collections/sparse_set.rs | 34 +++++-- src/lib.rs | 2 +- subcrates/telemetry/Cargo.toml | 5 +- subcrates/telemetry/src/lib.rs | 42 ++++++--- subcrates/telemetry/src/main.rs | 12 ++- subcrates/telemetry/src/modules/cpu.rs | 72 ++++++++------- subcrates/telemetry/src/modules/devices.rs | 64 ++++++------- subcrates/telemetry/src/modules/external.rs | 6 +- .../src/modules/formatted/architecture.rs | 20 ++++- .../telemetry/src/modules/formatted/bytes.rs | 38 -------- .../src/modules/formatted/date_time.rs | 25 +++++- .../modules/formatted/desktop_environment.rs | 89 ++++++++----------- .../telemetry/src/modules/formatted/mod.rs | 2 +- .../src/modules/formatted/numbers.rs | 54 +++++++++++ .../src/modules/formatted/offset_time.rs | 46 +++++----- .../src/modules/formatted/relative_time.rs | 34 ++++--- .../src/modules/formatted/version.rs | 36 ++++---- subcrates/telemetry/src/modules/gpu/mod.rs | 20 ++--- subcrates/telemetry/src/modules/gpu/vram.rs | 4 +- .../src/modules/macros/custom_anyhow.rs | 11 --- subcrates/telemetry/src/modules/macros/mod.rs | 1 - subcrates/telemetry/src/modules/memory.rs | 11 +-- subcrates/telemetry/src/modules/meta.rs | 23 +++-- subcrates/telemetry/src/modules/mod.rs | 24 +---- subcrates/telemetry/src/modules/network.rs | 10 +-- subcrates/telemetry/src/modules/os.rs | 43 +++++---- subcrates/telemetry/src/modules/storage.rs | 53 +++++------ subcrates/telemetry/src/modules/uptime.rs | 69 ++++++++------ subcrates/zlog/src/config.rs | 4 +- subcrates/zlog/src/lib.rs | 26 +++--- subcrates/zlog/src/tests.rs | 16 ++-- 32 files changed, 568 insertions(+), 405 deletions(-) delete mode 100644 subcrates/telemetry/src/modules/formatted/bytes.rs create mode 100644 subcrates/telemetry/src/modules/formatted/numbers.rs delete mode 100644 subcrates/telemetry/src/modules/macros/custom_anyhow.rs delete mode 100644 subcrates/telemetry/src/modules/macros/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 409464d..ab4c1ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,6 +555,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -671,6 +680,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "detect-desktop-environment" version = "1.2.0" @@ -1016,9 +1047,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1455,7 +1486,7 @@ dependencies = [ "petgraph", "rustc-hash", "spirv", - "strum", + "strum 0.26.3", "thiserror 2.0.12", "unicode-ident", ] @@ -2637,9 +2668,15 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", ] +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" + [[package]] name = "strum_macros" version = "0.26.4" @@ -2653,6 +2690,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.101" @@ -2710,17 +2760,20 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" name = "telemetry" version = "0.1.0" dependencies = [ - "anyhow", "ash", "chrono", + "derive_more", "detect-desktop-environment", "hidapi", "humansize", "metal 0.32.0", "serde", "serde_json", + "strum 0.27.1", + "strum_macros 0.27.1", "sys-locale", "sysinfo", + "thiserror 2.0.12", "timeago", "versions", "wgpu", @@ -2966,6 +3019,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "v_frame" version = "0.3.8" @@ -3861,9 +3920,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.9" +version = "0.30.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +checksum = "b0d05bd8908e14618c9609471db04007e644fd9cce6529756046cfc577f9155e" dependencies = [ "ahash", "android-activity", @@ -3913,9 +3972,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b" dependencies = [ "memchr", ] diff --git a/src/collections/sparse_set.rs b/src/collections/sparse_set.rs index 5e0ec84..72c7381 100644 --- a/src/collections/sparse_set.rs +++ b/src/collections/sparse_set.rs @@ -236,7 +236,10 @@ mod tests { assert_eq!(sparse_set.remove(SPARSE_PAGESIZE + 2).unwrap(), 3); assert_eq!(sparse_set.sparse[1].as_ref().unwrap().1, 2); - assert_eq!(sparse_set.keys(), [10, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1]); + assert_eq!( + sparse_set.keys(), + [10, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1] + ); assert_eq!(sparse_set.values(), [1, 2, 2, 1, 2]); assert_eq!(sparse_set.remove(SPARSE_PAGESIZE + 1).unwrap(), 2); @@ -249,25 +252,44 @@ mod tests { assert_eq!(sparse_set.keys(), [10, 11, 12]); assert_eq!(sparse_set.values(), [1, 2, 2]); - sparse_set.insert(SPARSE_PAGESIZE, 1); sparse_set.insert(SPARSE_PAGESIZE + 1, 2); sparse_set.insert(SPARSE_PAGESIZE + 2, 3); assert_eq!(sparse_set.remove(10).unwrap(), 1); assert_eq!(sparse_set.sparse[0].as_ref().unwrap().1, 2); - // swap-remove - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1]); + // swap-remove + assert_eq!( + sparse_set.keys(), + [ + SPARSE_PAGESIZE + 2, + 11, + 12, + SPARSE_PAGESIZE, + SPARSE_PAGESIZE + 1 + ] + ); assert_eq!(sparse_set.values(), [3, 2, 2, 1, 2]); assert_eq!(sparse_set.remove(11).unwrap(), 2); assert_eq!(sparse_set.sparse[0].as_ref().unwrap().1, 1); - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, 12, SPARSE_PAGESIZE]); + assert_eq!( + sparse_set.keys(), + [ + SPARSE_PAGESIZE + 2, + SPARSE_PAGESIZE + 1, + 12, + SPARSE_PAGESIZE + ] + ); assert_eq!(sparse_set.values(), [3, 2, 2, 1]); assert_eq!(sparse_set.remove(12).unwrap(), 2); assert!(sparse_set.sparse[0].is_none()); - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, SPARSE_PAGESIZE]); + assert_eq!( + sparse_set.keys(), + [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, SPARSE_PAGESIZE] + ); assert_eq!(sparse_set.values(), [3, 2, 1]); } } diff --git a/src/lib.rs b/src/lib.rs index f9a73ed..d5be06a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1 @@ -include!("main.rs"); \ No newline at end of file +include!("main.rs"); diff --git a/subcrates/telemetry/Cargo.toml b/subcrates/telemetry/Cargo.toml index 81ffb9b..7a483ae 100644 --- a/subcrates/telemetry/Cargo.toml +++ b/subcrates/telemetry/Cargo.toml @@ -4,17 +4,20 @@ version = "0.1.0" edition = "2024" [dependencies] -anyhow = "1.0.98" ash = "0.38.0" chrono = { version = "0.4.40", features = ["serde"] } +derive_more = { version = "2.0.1", features = ["add", "add_assign", "as_ref", "deref_mut", "from", "from_str", "full", "into", "mul", "mul_assign", "not", "sum", "try_from", "try_into", "try_unwrap", "unwrap"] } detect-desktop-environment = "1.2.0" hidapi = "2.6.3" humansize = "2.1.3" metal = { version = "0.32.0", optional = true } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" +strum = "0.27.1" +strum_macros = "0.27.1" sys-locale = "0.3.2" sysinfo = { version = "0.34.2", features = ["serde"] } +thiserror = "2.0.12" timeago = "0.4.2" versions = { version = "7.0.0", features = ["serde"] } wgpu = "25.0.0" diff --git a/subcrates/telemetry/src/lib.rs b/subcrates/telemetry/src/lib.rs index 6c1647e..4b1b333 100644 --- a/subcrates/telemetry/src/lib.rs +++ b/subcrates/telemetry/src/lib.rs @@ -1,35 +1,57 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; #[macro_use] mod modules; -use crate::modules::{cpu, devices, external, gpu, memory, meta, network, os, storage, uptime}; -use anyhow::Result; +pub use crate::modules::{cpu, devices, external, gpu, memory, meta, network, os, storage, uptime}; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TelemetryInfo { telemetry: AllInfo, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AllInfo { gpu: gpu::GPUInfo, - cpu: cpu::CPUInfo, + cpu: Vec, memory: memory::MemoryInfo, os: os::OSInfo, storage: Vec, network: network::NetworkInfo, external: external::ExternalInfo, - devices: devices::DevicesInfo, + devices: Vec, meta: meta::MetaInfo, uptime: uptime::UptimeInfo, } +#[derive(Debug, Error)] +pub enum TelemetryError { + // #[error("Failed to get GPU information")] + // GPUError(#[from] gpu::GPUError), + #[error("Failed to get CPU information")] + CPUError(#[from] cpu::CPUError), + #[error("Failed to get OS information")] + OSError(#[from] os::OSError), + #[error("Failed to get storage information")] + StorageError(#[from] storage::StorageError), + // #[error("Failed to get external information")] + // ExternalError(#[from] external::ExternalError), + #[error("Failed to get devices information")] + DevicesError(#[from] devices::DevicesError), + #[error("Failed to get meta information")] + MetaError(#[from] meta::MetaError), + #[error("Failed to get uptime information")] + UptimeError(#[from] uptime::UptimeError), + #[error("Failed to build JSON for TelemetryInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { +pub fn get_struct() -> Result { Ok(TelemetryInfo { telemetry: AllInfo { gpu: gpu::get_struct(), - cpu: cpu::get_struct(), + cpu: cpu::get_struct()?, memory: memory::get_struct(), os: os::get_struct()?, storage: storage::get_list()?, @@ -43,6 +65,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/main.rs b/subcrates/telemetry/src/main.rs index 2806341..37405d5 100644 --- a/subcrates/telemetry/src/main.rs +++ b/subcrates/telemetry/src/main.rs @@ -1,3 +1,13 @@ +use serde_json; + fn main() { - println!("{:#?}", telemetry::get_struct()); + //println!("{:#?}", telemetry::get_struct()); + //println!("{:#?}", telemetry::os::get_json()); + //telemetry::os::get_json(); + + match telemetry::get_struct() { + //Ok(telemetry) => println!("{:#?}", serde_json::from_value(telemetry)), + Ok(telemetry) => println!("{:#?}", telemetry), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/subcrates/telemetry/src/modules/cpu.rs b/subcrates/telemetry/src/modules/cpu.rs index b40d671..7548feb 100644 --- a/subcrates/telemetry/src/modules/cpu.rs +++ b/subcrates/telemetry/src/modules/cpu.rs @@ -1,69 +1,67 @@ -use super::Defaults::Unknown; -use serde::Serialize; +use crate::modules::{FmtCores, FmtThreads}; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use std::collections::HashMap; use sysinfo::{CpuRefreshKind, RefreshKind, System}; +use thiserror::Error; -#[derive(Debug, Serialize)] -pub struct ProcessorInfo { +#[derive(Debug, Serialize, Deserialize)] +pub struct CPUInfo { vendor: String, brand: String, - total_system_cores: String, - threads: u16, + total_system_cores: FmtCores, + threads: FmtThreads, architecture: String, byte_order: String, } -#[derive(Debug, Serialize)] -pub struct CPUInfo { - cpus: Vec, +#[derive(Debug, Error)] +pub enum CPUError { + #[error("No CPU information available")] + NoCpusFound, + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), } #[allow(dead_code)] -pub fn get_struct() -> CPUInfo { - let system = +pub fn get_struct() -> Result, CPUError> { + let mut system = System::new_with_specifics(RefreshKind::nothing().with_cpu(CpuRefreshKind::everything())); + system.refresh_cpu_all(); - let mut processors = Vec::new(); - let mut processor_count: HashMap = HashMap::new(); + let mut processor_map: HashMap = HashMap::new(); for cpu in system.cpus() { - let brand = cpu.brand().trim(); - let total_cores = System::physical_core_count(); - - if processor_count.contains_key(brand) { - processor_count.get_mut(brand).unwrap().threads += 1; - continue; - } - processor_count.insert( - brand.to_string(), - ProcessorInfo { + let brand = cpu.brand().trim().to_string(); + let entry = processor_map + .entry(brand.clone()) + .or_insert_with(|| CPUInfo { vendor: cpu.vendor_id().trim().to_string(), - brand: brand.to_string(), - total_system_cores: if let Some(cores) = total_cores { - cores.to_string() - } else { - Unknown.into() - }, - threads: 1, + brand: brand.clone(), + total_system_cores: System::physical_core_count() + .map(|cores| cores.into()) + .unwrap_or_else(|| 0.into()), + threads: 0.into(), architecture: System::cpu_arch().trim().to_string(), byte_order: if cfg!(target_endian = "little") { String::from("little-endian") } else { String::from("big-endian") }, - }, - ); + }); + + entry.threads += 1.into(); } - for (_brand, info) in processor_count { - processors.push(info); + let cpus: Vec<_> = processor_map.into_values().collect(); + if cpus.is_empty() { + return Err(CPUError::NoCpusFound); } - CPUInfo { cpus: processors } + Ok(cpus) } #[allow(dead_code)] -pub fn get_json() -> Value { - json!(get_struct()) +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/devices.rs b/subcrates/telemetry/src/modules/devices.rs index 81cf169..6a74d2f 100644 --- a/subcrates/telemetry/src/modules/devices.rs +++ b/subcrates/telemetry/src/modules/devices.rs @@ -1,59 +1,59 @@ -//use crate::custom_anyhow; -use anyhow::Result; -use serde::Serialize; +use super::UNKNOWN; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; +use thiserror::Error; extern crate hidapi; -use hidapi::HidApi; +use hidapi::{HidApi, HidError}; use std::collections::HashMap; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeviceInfo { manufacturer: String, products: Vec, } -#[derive(Debug, Serialize)] -pub struct DevicesInfo { - devices: Vec, +#[derive(Debug, Error)] +pub enum DevicesError { + #[error("Failed to initialize HID API: {0}")] + HidApiInitError(#[from] HidError), + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), } #[allow(dead_code)] -pub fn get_struct() -> Result { - let api = HidApi::new().unwrap(); - let mut grouped_devices: HashMap> = HashMap::new(); +pub fn get_struct() -> Result, DevicesError> { + let api = HidApi::new()?; + let mut grouped: HashMap> = HashMap::new(); for device in api.device_list() { let manufacturer = device .manufacturer_string() - .unwrap_or("Unknown") - .to_string() - .to_lowercase(); - let product = device.product_string().unwrap_or("Unknown").to_string(); + .unwrap_or(UNKNOWN) + .to_ascii_lowercase(); + let product = device.product_string().unwrap_or(UNKNOWN).to_string(); if !manufacturer.trim().is_empty() && !product.trim().is_empty() { - let entry = grouped_devices.entry(manufacturer).or_default(); - - if !entry.contains(&product) { - entry.push(product); - } + grouped.entry(manufacturer).or_default().push(product) } } - let mut devices = Vec::new(); - let mut grouped_vec: Vec<_> = grouped_devices.into_iter().collect(); - grouped_vec.sort_by(|a, b| a.0.to_lowercase().cmp(&b.0.to_lowercase())); + let mut sorted_devices: Vec<_> = grouped.into_iter().collect(); + sorted_devices.sort_by(|a, b| a.0.cmp(&b.0)); - for (manufacturer, products) in grouped_vec { - devices.push(DeviceInfo { - manufacturer, - products, - }); - } - - Ok(DevicesInfo { devices }) + Ok(sorted_devices + .into_iter() + .map(|(manufacturer, mut products)| { + products.sort(); // optional: sort product names + products.dedup(); // remove duplicates + DeviceInfo { + manufacturer, + products, + } + }) + .collect()) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/external.rs b/subcrates/telemetry/src/modules/external.rs index 7987df8..a89e9d5 100644 --- a/subcrates/telemetry/src/modules/external.rs +++ b/subcrates/telemetry/src/modules/external.rs @@ -1,15 +1,15 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use std::{cmp::Ordering::Equal, collections::HashMap}; use sysinfo::{System, Users}; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SoftwareInfo { name: String, count: usize, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ExternalInfo { softwares: Vec, } diff --git a/subcrates/telemetry/src/modules/formatted/architecture.rs b/subcrates/telemetry/src/modules/formatted/architecture.rs index b875991..fad7499 100644 --- a/subcrates/telemetry/src/modules/formatted/architecture.rs +++ b/subcrates/telemetry/src/modules/formatted/architecture.rs @@ -1,10 +1,10 @@ -use serde::Serialize; +use serde::{Serialize, Serializer, Deserialize, Deserializer, de::Error as DeError}; use std::{ fmt::{Debug, Display, Formatter, Result as FmtResult}, ops::Deref, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub enum TargetPointerWidth { W32Bit, W64Bit, @@ -40,12 +40,26 @@ impl Debug for FmtOSArchitecture { impl Serialize for FmtOSArchitecture { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } +impl<'de> Deserialize<'de> for FmtOSArchitecture { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "32 Bit" => Ok(FmtOSArchitecture(TargetPointerWidth::W32Bit)), + "64 Bit" => Ok(FmtOSArchitecture(TargetPointerWidth::W64Bit)), + _ => Err(DeError::custom(format!("Invalid architecture: {}", s))), + } + } +} + impl Deref for FmtOSArchitecture { type Target = TargetPointerWidth; diff --git a/subcrates/telemetry/src/modules/formatted/bytes.rs b/subcrates/telemetry/src/modules/formatted/bytes.rs deleted file mode 100644 index 598fc81..0000000 --- a/subcrates/telemetry/src/modules/formatted/bytes.rs +++ /dev/null @@ -1,38 +0,0 @@ -use serde::Serialize; -use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, -}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct FmtBytes(pub u64); - -impl Display for FmtBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - use humansize::{DECIMAL, format_size}; - write!(f, "{}", format_size(self.0, DECIMAL)) - } -} - -impl Debug for FmtBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) - } -} - -impl Serialize for FmtBytes { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deref for FmtBytes { - type Target = u64; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/subcrates/telemetry/src/modules/formatted/date_time.rs b/subcrates/telemetry/src/modules/formatted/date_time.rs index 8c26003..efd8bbe 100644 --- a/subcrates/telemetry/src/modules/formatted/date_time.rs +++ b/subcrates/telemetry/src/modules/formatted/date_time.rs @@ -1,11 +1,11 @@ use chrono::{DateTime, Local, TimeZone, Utc}; -use serde::Serialize; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ fmt::{Debug, Display, Formatter, Result as FMTResult}, ops::Deref, }; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DateTimeInfo { date: String, time: String, @@ -46,12 +46,31 @@ where { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } +impl<'de, Tz> Deserialize<'de> for FmtDateTime +where + Tz: TimeZone, + DateTime: ToString + std::str::FromStr, + as std::str::FromStr>::Err: std::fmt::Display, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // 1. Pull a String out of the deserializer + let s = String::deserialize(deserializer)?; + // 2. Parse it, mapping any parse-error into a Serde error + as std::str::FromStr>::from_str(&s) // explicit, no ambiguity + .map(FmtDateTime) + .map_err(serde::de::Error::custom) + } +} + impl Deref for FmtDateTime { type Target = DateTime; diff --git a/subcrates/telemetry/src/modules/formatted/desktop_environment.rs b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs index 7f636c1..5876441 100644 --- a/subcrates/telemetry/src/modules/formatted/desktop_environment.rs +++ b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs @@ -1,59 +1,44 @@ +use std::str::FromStr; + +use serde::{Serialize, Deserialize}; use detect_desktop_environment::DesktopEnvironment; -use serde::{Serialize, Serializer}; -use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, -}; +use strum_macros::EnumString; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SerdeDE(pub DesktopEnvironment); - -impl Serialize for SerdeDE { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&format!("{:?}", self.0)) - } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "PascalCase", ascii_case_insensitive)] +#[non_exhaustive] +pub enum FmtDE { + Cinnamon, + Cosmic, + CosmicEpoch, + Dde, + Ede, + Endless, + Enlightenment, + Gnome, + Hyprland, + Kde, + Lxde, + Lxqt, + MacOs, + Mate, + Old, + Pantheon, + Razor, + Rox, + Sway, + Tde, + Unity, + Windows, + Xfce, } -impl SerdeDE { - pub fn detect() -> Option { - DesktopEnvironment::detect().map(SerdeDE) - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct FmtDE(pub SerdeDE); - impl FmtDE { pub fn detect() -> Option { - SerdeDE::detect().map(FmtDE) + DesktopEnvironment::detect().and_then(|inner_de| { + let s = format!("{:?}", inner_de); + + FmtDE::from_str(&s).ok() + }) } -} - -impl Display for FmtDE { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{:?}", self.0.0) - } -} - -impl Debug for FmtDE { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) - } -} - -impl Serialize for FmtDE { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deref for FmtDE { - type Target = SerdeDE; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/mod.rs b/subcrates/telemetry/src/modules/formatted/mod.rs index 38987d8..3eeb56b 100644 --- a/subcrates/telemetry/src/modules/formatted/mod.rs +++ b/subcrates/telemetry/src/modules/formatted/mod.rs @@ -1,7 +1,7 @@ pub mod architecture; -pub mod bytes; pub mod date_time; pub mod desktop_environment; pub mod offset_time; pub mod relative_time; pub mod version; +pub mod numbers; \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/numbers.rs b/subcrates/telemetry/src/modules/formatted/numbers.rs new file mode 100644 index 0000000..7948537 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/numbers.rs @@ -0,0 +1,54 @@ +use derive_more::{ + Add, AddAssign, Deref, Div, DivAssign, From, Mul, MulAssign, Sub, SubAssign, +}; +use serde::{Serialize, Deserialize}; +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; + +enum DisplayKind { + Plural(&'static str, &'static str), + HumanBytes, +} + +macro_rules! define_fmt_wrapper { + ($name:ident, $ty:ty, $display_kind:expr) => { + #[derive( + Copy, Clone, PartialEq, Eq, PartialOrd, Ord, + Add, Sub, Mul, Div, + AddAssign, SubAssign, MulAssign, DivAssign, + From, Deref, Serialize, Deserialize + )] + pub struct $name(pub $ty); + + impl $name { + #[allow(dead_code)] + pub fn new(value: $ty) -> Self { + Self(value) + } + } + + impl Display for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match $display_kind { + DisplayKind::Plural(singular, plural) => { + let label = if self.0 == 1 { singular } else { plural }; + write!(f, "{} {}", self.0, label) + }, + DisplayKind::HumanBytes => { + use humansize::{format_size, DECIMAL}; + write!(f, "{}", format_size(self.0, DECIMAL)) + }, + } + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } + } + }; +} + +define_fmt_wrapper!(FmtThreads, u16, DisplayKind::Plural("Thread", "Threads")); +define_fmt_wrapper!(FmtCores, usize, DisplayKind::Plural("Core", "Cores")); +define_fmt_wrapper!(FmtBytes, u64, DisplayKind::HumanBytes); \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/offset_time.rs b/subcrates/telemetry/src/modules/formatted/offset_time.rs index 36d4215..37e4fab 100644 --- a/subcrates/telemetry/src/modules/formatted/offset_time.rs +++ b/subcrates/telemetry/src/modules/formatted/offset_time.rs @@ -1,20 +1,15 @@ use chrono::{DateTime, Local, Offset}; -use serde::Serialize; +use derive_more::{Deref, Display, From}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ cmp::Ordering, fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, }; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, From, Deref, Display)] +#[display("UTC {}", "_0.offset()")] pub struct FmtOffsetTime(pub DateTime); -impl Display for FmtOffsetTime { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "UTC{}", self.0.offset()) - } -} - impl Debug for FmtOffsetTime { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { Display::fmt(self, f) @@ -24,17 +19,28 @@ impl Debug for FmtOffsetTime { impl Serialize for FmtOffsetTime { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } -impl Deref for FmtOffsetTime { - type Target = DateTime; +impl<'de> Deserialize<'de> for FmtOffsetTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Deserialize the input as a string + let s = String::deserialize(deserializer)?; - fn deref(&self) -> &Self::Target { - &self.0 + // Attempt to parse the string into a DateTime + match DateTime::parse_from_rfc3339(&s) { + Ok(dt) => Ok(FmtOffsetTime(dt.with_timezone(&Local))), + Err(e) => Err(serde::de::Error::custom(format!( + "Failed to parse DateTime: {}", + e + ))), + } } } @@ -48,21 +54,13 @@ impl PartialEq for FmtOffsetTime { impl PartialOrd for FmtOffsetTime { fn partial_cmp(&self, other: &Self) -> Option { Some( - self.0 - .offset() - .fix() - .local_minus_utc() - .cmp(&other.0.offset().fix().local_minus_utc()), + self.0.offset().fix().local_minus_utc().cmp(&other.0.offset().fix().local_minus_utc()), ) } } impl Ord for FmtOffsetTime { fn cmp(&self, other: &Self) -> Ordering { - self.0 - .offset() - .fix() - .local_minus_utc() - .cmp(&other.0.offset().fix().local_minus_utc()) + self.0.offset().fix().local_minus_utc().cmp(&other.0.offset().fix().local_minus_utc()) } } diff --git a/subcrates/telemetry/src/modules/formatted/relative_time.rs b/subcrates/telemetry/src/modules/formatted/relative_time.rs index 0e08c62..2933fea 100644 --- a/subcrates/telemetry/src/modules/formatted/relative_time.rs +++ b/subcrates/telemetry/src/modules/formatted/relative_time.rs @@ -1,11 +1,19 @@ -use serde::Serialize; +use derive_more::{From, Deref, with_trait::Display as Display}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, + fmt::{Debug, Formatter, Result as FmtResult}, time::Duration, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive( + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + From, + Deref, +)] pub struct FmtRelativeTime(pub Duration); impl Display for FmtRelativeTime { @@ -25,16 +33,18 @@ impl Debug for FmtRelativeTime { impl Serialize for FmtRelativeTime { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { - serializer.serialize_str(&self.to_string()) + serializer.serialize_u64(self.0.as_secs()) } } -impl Deref for FmtRelativeTime { - type Target = Duration; - - fn deref(&self) -> &Self::Target { - &self.0 +impl<'de> Deserialize<'de> for FmtRelativeTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let secs = u64::deserialize(deserializer)?; + Ok(FmtRelativeTime(Duration::from_secs(secs))) } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/version.rs b/subcrates/telemetry/src/modules/formatted/version.rs index ccd741e..b83d888 100644 --- a/subcrates/telemetry/src/modules/formatted/version.rs +++ b/subcrates/telemetry/src/modules/formatted/version.rs @@ -1,38 +1,38 @@ -use serde::Serialize; +use derive_more::{Display, From, Deref, with_trait::Display as TDisplay}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, + fmt::{Debug, Formatter, Result as FmtResult}, + str::FromStr, }; use versions::Versioning; -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, From, Deref, Display)] +#[display("{_0}")] pub struct FmtVersion(pub Versioning); -impl Display for FmtVersion { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{}", self.0) - } -} - impl Debug for FmtVersion { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) + TDisplay::fmt(self, f) } } impl Serialize for FmtVersion { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } -impl Deref for FmtVersion { - type Target = Versioning; - - fn deref(&self) -> &Self::Target { - &self.0 +impl<'de> Deserialize<'de> for FmtVersion { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Versioning::from_str(&s) + .map(FmtVersion) + .map_err(serde::de::Error::custom) } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/gpu/mod.rs b/subcrates/telemetry/src/modules/gpu/mod.rs index af1e374..f1206ad 100644 --- a/subcrates/telemetry/src/modules/gpu/mod.rs +++ b/subcrates/telemetry/src/modules/gpu/mod.rs @@ -1,5 +1,5 @@ -use super::Defaults::Unknown; -use serde::Serialize; +use super::UNKNOWN; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use wgpu; use winit::{ @@ -11,13 +11,13 @@ use winit::{ mod vram; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DriverInfo { version: String, name: String, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AdapterInfo { vendor: String, model: String, @@ -26,13 +26,13 @@ pub struct AdapterInfo { display: DisplayInfo, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GPUInfo { supported_backends: Vec, gpus: Vec, } -#[derive(Debug, Serialize, Default)] +#[derive(Debug, Serialize, Deserialize, Default)] pub struct DisplayInfo { resolution: String, refresh_rate: String, @@ -48,11 +48,11 @@ impl ApplicationHandler for DisplayInfo { self.refresh_rate = if let Some(refresh) = refresh_rate { format!("{} hz", refresh / 1000) } else { - Unknown.into() + UNKNOWN.to_string() } } else { - self.resolution = Unknown.into(); - self.refresh_rate = Unknown.into(); + self.resolution = UNKNOWN.to_string(); + self.refresh_rate = UNKNOWN.to_string(); } event_loop.exit(); @@ -75,7 +75,7 @@ fn vendor_name(vendor: u32) -> &'static str { 0x13B5 => "ARM(Advanced RISC Machines)", 0x5143 => "Qualcomm(Quality Communications)", 0x1010 => "Apple Inc.", - _ => "Unknown", + _ => UNKNOWN, } } diff --git a/subcrates/telemetry/src/modules/gpu/vram.rs b/subcrates/telemetry/src/modules/gpu/vram.rs index 0fd854c..3044104 100644 --- a/subcrates/telemetry/src/modules/gpu/vram.rs +++ b/subcrates/telemetry/src/modules/gpu/vram.rs @@ -1,4 +1,4 @@ -use super::super::Defaults::Unknown; +use super::super::UNKNOWN; use ash::vk::{API_VERSION_1_2, ApplicationInfo, InstanceCreateInfo, MemoryHeapFlags}; use humansize::{DECIMAL, make_format}; @@ -62,6 +62,6 @@ pub fn get(vendor: u32, device_id: u32) -> String { match vendor { 0x10DE | 0x1002 | 0x8086 | 0x5143 => formatter(get_vulkan(device_id)), 0x1010 => formatter(get_metal()), - _ => Unknown.into(), + _ => UNKNOWN.to_string(), } } diff --git a/subcrates/telemetry/src/modules/macros/custom_anyhow.rs b/subcrates/telemetry/src/modules/macros/custom_anyhow.rs deleted file mode 100644 index 7b0ca67..0000000 --- a/subcrates/telemetry/src/modules/macros/custom_anyhow.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[macro_export] -macro_rules! custom_anyhow { - ($fmt:literal $(, $arg:expr)* $(,)?) => { - ::anyhow::anyhow!( - concat!($fmt, " (file: {}, line: {})"), - $($arg,)* - file!(), - line!() - ) - }; -} diff --git a/subcrates/telemetry/src/modules/macros/mod.rs b/subcrates/telemetry/src/modules/macros/mod.rs deleted file mode 100644 index ec3320c..0000000 --- a/subcrates/telemetry/src/modules/macros/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod custom_anyhow; diff --git a/subcrates/telemetry/src/modules/memory.rs b/subcrates/telemetry/src/modules/memory.rs index 0dd39b0..9888d3a 100644 --- a/subcrates/telemetry/src/modules/memory.rs +++ b/subcrates/telemetry/src/modules/memory.rs @@ -1,9 +1,9 @@ use crate::modules::FmtBytes; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::System; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct PhysicalInfo { total: FmtBytes, used: FmtBytes, @@ -11,14 +11,14 @@ pub struct PhysicalInfo { available: FmtBytes, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct VirtualInfo { total: FmtBytes, used: FmtBytes, free: FmtBytes, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MemoryInfo { physical: PhysicalInfo, virtual_swap: VirtualInfo, @@ -26,7 +26,8 @@ pub struct MemoryInfo { #[allow(dead_code)] pub fn get_struct() -> MemoryInfo { - let system = System::new_all(); + let mut system = System::new_all(); + system.refresh_memory(); MemoryInfo { physical: PhysicalInfo { diff --git a/subcrates/telemetry/src/modules/meta.rs b/subcrates/telemetry/src/modules/meta.rs index c0a91f2..60d94b3 100644 --- a/subcrates/telemetry/src/modules/meta.rs +++ b/subcrates/telemetry/src/modules/meta.rs @@ -1,24 +1,31 @@ -use crate::{custom_anyhow, modules::FmtVersion}; -use anyhow::Result; -use serde::Serialize; +use crate::modules::FmtVersion; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sys_locale::get_locale; +use thiserror::Error; use versions::Versioning; include!(concat!(env!("OUT_DIR"), "/built.rs")); -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MetaInfo { version: FmtVersion, commit_hash: String, locale: String, } +#[derive(Debug, Error)] +pub enum MetaError { + #[error("Invalid Semver version")] + InvalidVersion, + #[error("Failed to build JSON for MetaInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { +pub fn get_struct() -> Result { let locale = get_locale().unwrap_or_else(|| String::from("en-US")); - let version = Versioning::new(env!("CARGO_PKG_VERSION")) - .ok_or(custom_anyhow!("Invalid version").context("Invalid Semver version"))?; + let version = Versioning::new(env!("CARGO_PKG_VERSION")).ok_or(MetaError::InvalidVersion)?; Ok(MetaInfo { version: FmtVersion(version), @@ -28,6 +35,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/mod.rs b/subcrates/telemetry/src/modules/mod.rs index 2d3ade2..d714f7b 100644 --- a/subcrates/telemetry/src/modules/mod.rs +++ b/subcrates/telemetry/src/modules/mod.rs @@ -1,11 +1,8 @@ -use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; - pub mod cpu; pub mod devices; pub mod external; pub mod formatted; pub mod gpu; -pub mod macros; pub mod memory; pub mod meta; pub mod network; @@ -16,27 +13,14 @@ pub mod uptime; #[allow(unused_imports)] pub use formatted::{ architecture::FmtOSArchitecture, - bytes::FmtBytes, + numbers::FmtBytes, date_time::{FmtDateTime, IntoDateTime}, desktop_environment::FmtDE, offset_time::FmtOffsetTime, relative_time::FmtRelativeTime, version::FmtVersion, + numbers::FmtCores, + numbers::FmtThreads, }; -#[derive(Debug)] -pub enum Defaults { - Unknown, -} - -impl Display for Defaults { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{:?}", self) - } -} - -impl From for String { - fn from(value: Defaults) -> Self { - value.to_string() - } -} +pub const UNKNOWN: &str = "Unknown"; diff --git a/subcrates/telemetry/src/modules/network.rs b/subcrates/telemetry/src/modules/network.rs index 4d8dc47..02155d9 100644 --- a/subcrates/telemetry/src/modules/network.rs +++ b/subcrates/telemetry/src/modules/network.rs @@ -1,8 +1,8 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::Networks; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct NetworkInfo { adapters: Vec, } @@ -10,11 +10,7 @@ pub struct NetworkInfo { #[allow(dead_code)] pub fn get_struct() -> NetworkInfo { let networks = Networks::new_with_refreshed_list(); - let mut adapters = Vec::new(); - - for (interface_name, _network_data) in &networks { - adapters.push(interface_name.to_string()); - } + let adapters = networks.iter().map(|(name, _)| name.to_string()).collect(); NetworkInfo { adapters } } diff --git a/subcrates/telemetry/src/modules/os.rs b/subcrates/telemetry/src/modules/os.rs index dd3a4e2..8a121a7 100644 --- a/subcrates/telemetry/src/modules/os.rs +++ b/subcrates/telemetry/src/modules/os.rs @@ -1,14 +1,11 @@ -use super::Defaults::Unknown; -use crate::{ - custom_anyhow, - modules::{FmtDE, FmtOSArchitecture}, -}; -use anyhow::Result; -use serde::Serialize; +use super::UNKNOWN; +use crate::modules::{FmtDE, FmtOSArchitecture}; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::System; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct OSInfo { name: String, edition: String, @@ -18,20 +15,28 @@ pub struct OSInfo { desktop_environment: Option, } +#[derive(Debug, Error)] +pub enum OSError { + #[error("Unsupported pointer width: 16 bit systems are not supported")] + UnsupportedPointerWidth, + #[error("Failed to build JSON for OSInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { - let architecture = if cfg!(target_pointer_width = "64") { - Ok(FmtOSArchitecture::W64_BIT) - } else if cfg!(target_pointer_width = "32") { - Ok(FmtOSArchitecture::W32_BIT) - } else { - Err(custom_anyhow!("Unsupported pointer width").context("16 bit systems are not supported")) +pub fn get_struct() -> Result { + let architecture = match std::mem::size_of::() { + 8 => Ok(FmtOSArchitecture::W64_BIT), + 4 => Ok(FmtOSArchitecture::W32_BIT), + _ => Err(OSError::UnsupportedPointerWidth), }?; + let kernel = if cfg!(target_os = "linux") || cfg!(target_os = "macos") { Some(System::kernel_long_version()) } else { None }; + let desktop_environment = if cfg!(target_os = "linux") { FmtDE::detect() } else { @@ -39,9 +44,9 @@ pub fn get_struct() -> Result { }; Ok(OSInfo { - name: System::name().unwrap_or(Unknown.into()), - edition: System::long_os_version().unwrap_or(Unknown.into()), - version: System::os_version().unwrap_or(Unknown.into()), + name: System::name().unwrap_or(UNKNOWN.to_string()), + edition: System::long_os_version().unwrap_or(UNKNOWN.to_string()), + version: System::os_version().unwrap_or(UNKNOWN.to_string()), architecture, kernel, desktop_environment, @@ -49,6 +54,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/storage.rs b/subcrates/telemetry/src/modules/storage.rs index 62c9a23..625e611 100644 --- a/subcrates/telemetry/src/modules/storage.rs +++ b/subcrates/telemetry/src/modules/storage.rs @@ -1,11 +1,11 @@ -use crate::{custom_anyhow, modules::FmtBytes}; -use anyhow::Result; -use serde::Serialize; +use crate::modules::FmtBytes; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; pub use sysinfo::DiskKind; use sysinfo::Disks; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct StorageInfo { name: String, mount_point: String, @@ -14,33 +14,36 @@ pub struct StorageInfo { total: FmtBytes, } -#[allow(dead_code)] -pub fn get_list() -> Result> { - let disks = Disks::new_with_refreshed_list(); - let mut drive_data = Vec::new(); +#[derive(Debug, Error)] +pub enum StorageError { + #[error("No storage drives found")] + NoDisksFound, + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), +} - for disk in disks.list() { - drive_data.push(StorageInfo { - name: format!("{:?}", disk.name()).trim_matches('\"').to_string(), - mount_point: format!("{:?}", disk.mount_point()) - .replace("\\", "") - .trim_matches('\"') - .to_string(), +#[allow(dead_code)] +pub fn get_list() -> Result, StorageError> { + let disks = Disks::new_with_refreshed_list(); + let disk_list = disks.list(); + + if disk_list.is_empty() { + return Err(StorageError::NoDisksFound); + } + + Ok(disk_list + .iter() + .map(|disk| StorageInfo { + name: disk.name().to_string_lossy().into_owned(), + mount_point: disk.mount_point().to_string_lossy().replace('\\', ""), disk_kind: disk.kind(), space_left: FmtBytes(disk.available_space()), total: FmtBytes(disk.total_space()), - }); - } - - if drive_data.is_empty() { - return Err(custom_anyhow!("No storage drives found") - .context("Drive_data is empty, expected disks.list() to return non-zero at line 39")); - } - - Ok(drive_data) + }) + .collect()) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_list()?)) } diff --git a/subcrates/telemetry/src/modules/uptime.rs b/subcrates/telemetry/src/modules/uptime.rs index 1c0dbe6..c6bed58 100644 --- a/subcrates/telemetry/src/modules/uptime.rs +++ b/subcrates/telemetry/src/modules/uptime.rs @@ -1,54 +1,71 @@ -use crate::{ - custom_anyhow, - modules::{FmtDateTime, FmtOffsetTime, FmtRelativeTime}, -}; -use anyhow::Result; -use chrono::{DateTime, Local, Utc}; -use serde::Serialize; +use crate::modules::{FmtDateTime, FmtOffsetTime, FmtRelativeTime}; +use chrono::{DateTime, Local, Utc, TimeZone}; +use serde::{Serialize, Serializer, Deserialize}; use serde_json::{Value, json}; -use std::time::Duration as StdDuration; +use std::{ + time::Duration as StdDuration, + fmt::Display, +}; use sysinfo::System; +use thiserror::Error; -#[derive(Debug, Serialize)] +fn serialize_datetime(date: &DateTime, serializer: S) -> Result +where + S: Serializer, + Tz::Offset: Display, + Tz: TimeZone, +{ + let formatted = date.format("%+").to_string(); // Format as RFC 3339 + serializer.serialize_str(&formatted) +} + +#[derive(Debug, Serialize, Deserialize)] struct DateInfo { + #[serde(serialize_with = "serialize_datetime")] time_offset: FmtOffsetTime, + #[serde(serialize_with = "serialize_datetime")] local_date_time: FmtDateTime, + #[serde(serialize_with = "serialize_datetime")] utc_date_time: FmtDateTime, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct UptimeInfo { boot: DateInfo, now: DateInfo, relative: FmtRelativeTime, } +#[derive(Debug, Error)] +pub enum UptimeError { + #[error("Invalid or out of range timestamp: check seconds < 8_220_000_000_000")] + InvalidTimestamp, + #[error("Failed to build JSON for UptimeInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { - let boot_time_utc = DateTime::::from_timestamp(System::boot_time() as i64, 0).ok_or( - custom_anyhow!("Invalid, or out of range timestamp") - .context("Invalid timestamp: check seconds < 8_220_000_000_000"), - )?; +pub fn get_struct() -> Result { + let boot_time_utc = DateTime::::from_timestamp(System::boot_time() as i64, 0) + .ok_or(UptimeError::InvalidTimestamp)?; let boot_time_local: DateTime = boot_time_utc.with_timezone(&Local); let relative_time = StdDuration::from_secs((Local::now() - boot_time_local).num_seconds() as u64); + let make_info = |utc_dt: DateTime| DateInfo { + time_offset: FmtOffsetTime(Local::now()), + local_date_time: FmtDateTime(utc_dt.with_timezone(&Local)), + utc_date_time: FmtDateTime(utc_dt), + }; + Ok(UptimeInfo { - boot: DateInfo { - time_offset: FmtOffsetTime(Local::now()), - local_date_time: FmtDateTime(boot_time_local), - utc_date_time: FmtDateTime(boot_time_utc), - }, - now: DateInfo { - time_offset: FmtOffsetTime(Local::now()), - local_date_time: FmtDateTime(Local::now()), - utc_date_time: FmtDateTime(Utc::now()), - }, + boot: make_info(boot_time_utc), + now: make_info(Utc::now()), relative: FmtRelativeTime(relative_time), }) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/zlog/src/config.rs b/subcrates/zlog/src/config.rs index dc50fbe..b540573 100644 --- a/subcrates/zlog/src/config.rs +++ b/subcrates/zlog/src/config.rs @@ -74,7 +74,7 @@ impl LoggerConfig { self.log_json_show_message = i; self } - + pub fn log_json_show_additional_fields(mut self, i: bool) -> Self { self.log_json_show_additional_fields = i; self @@ -96,7 +96,7 @@ impl Default for LoggerConfig { log_json_show_timestamp: false, log_json_show_level: false, log_json_show_message: false, - log_json_show_additional_fields: false + log_json_show_additional_fields: false, } } } diff --git a/subcrates/zlog/src/lib.rs b/subcrates/zlog/src/lib.rs index e6b64a4..0399099 100644 --- a/subcrates/zlog/src/lib.rs +++ b/subcrates/zlog/src/lib.rs @@ -113,7 +113,7 @@ where level, message, #[cfg(feature = "json")] - additional_fields + additional_fields, }); if let LogEvent::Log(ref entry) = log_entry { @@ -212,13 +212,7 @@ impl Logger { for msg in rx { match msg { LogEvent::Log(mut entry) => { - println!( - "{}", - format_entry( - &mut entry, - &config_clone - ) - ); + println!("{}", format_entry(&mut entry, &config_clone)); } LogEvent::Shutdown => break, } @@ -298,12 +292,12 @@ fn format_entry(entry: &mut LogEntry, log_config: &LoggerConfig) -> String { if log_config.log_use_json { return format_entry_json(entry, log_config); } - + if log_config.log_to_stdout || log_config.log_to_file { return format_entry_string(entry, log_config); } else { return String::new(); - } + } } fn format_entry_string(entry: &LogEntry, log_config: &LoggerConfig) -> String { @@ -327,7 +321,10 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String let mut json_object = serde_json::Map::new(); if log_config.log_json_show_timestamp { - json_object.insert("timestamp".to_string(), Value::String(DateTime::::from(entry.timestamp).to_rfc3339())); + json_object.insert( + "timestamp".to_string(), + Value::String(DateTime::::from(entry.timestamp).to_rfc3339()), + ); } if log_config.log_json_show_level { @@ -335,7 +332,10 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String } if log_config.log_json_show_message { - json_object.insert("message".to_string(), Value::String(entry.message.to_string())); + json_object.insert( + "message".to_string(), + Value::String(entry.message.to_string()), + ); } if log_config.log_json_show_additional_fields { @@ -343,4 +343,4 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String } serde_json::to_string(&json_object).unwrap() -} \ No newline at end of file +} diff --git a/subcrates/zlog/src/tests.rs b/subcrates/zlog/src/tests.rs index 13c90ab..930b909 100644 --- a/subcrates/zlog/src/tests.rs +++ b/subcrates/zlog/src/tests.rs @@ -1,7 +1,7 @@ use pretty_assertions::assert_eq; -use tracing::Level; +use serde::{Deserialize, Serialize}; use serde_json::Map; -use serde::{Serialize, Deserialize}; +use tracing::Level; use super::*; @@ -126,9 +126,15 @@ fn test_logger_sequential_consistency_json() { for log in logger.get_logs(LogQuery::All) { let mut json_object = serde_json::Map::new(); - json_object.insert("timestamp".to_string(), Value::String(DateTime::::from(log.timestamp).to_rfc3339())); + json_object.insert( + "timestamp".to_string(), + Value::String(DateTime::::from(log.timestamp).to_rfc3339()), + ); json_object.insert("level".to_string(), Value::String(log.level.to_string())); - json_object.insert("message".to_string(), Value::String(log.message.to_string())); + json_object.insert( + "message".to_string(), + Value::String(log.message.to_string()), + ); log_json.push(json_object); } @@ -136,4 +142,4 @@ fn test_logger_sequential_consistency_json() { for log in log_json { serde_json::to_string(&log).unwrap(); } -} \ No newline at end of file +} -- 2.47.2