From 91c80d0f916f839bba93df95c663f3d73d1f101e Mon Sep 17 00:00:00 2001 From: D0RYU Date: Sat, 26 Apr 2025 11:52:46 -0400 Subject: [PATCH] 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