diff --git a/CHANGELOG.md b/CHANGELOG.md index e332700..1b2740c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## [1.1.0] - 2024-10-21 + +### Changed + +- Fix message out-of-order issue in Proxy plugin. +- Upgrade some risky dependencies. +- Simplify error handling logic. + ## [1.0.20] - 2024-09-23 ### Changed diff --git a/Cargo.lock b/Cargo.lock index f3e3377..e01404c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" @@ -23,32 +23,22 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check 0.9.4", -] - -[[package]] -name = "ahash" -version = "0.8.3" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "getrandom", "once_cell", - "version_check 0.9.4", + "version_check", + "zerocopy", ] [[package]] @@ -68,47 +58,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.12" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -116,26 +107,24 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] -name = "arc-swap" -version = "1.6.0" +name = "arbitrary" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] [[package]] -name = "async-trait" -version = "0.1.77" +name = "arc-swap" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "atomic-waker" @@ -145,51 +134,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -dependencies = [ - "byteorder", - "safemem", -] - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", + "windows-targets 0.52.6", ] [[package]] @@ -198,12 +159,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -240,100 +195,53 @@ dependencies = [ "wyz", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] name = "bson" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aeb8bae494e49dbc330dd23cf78f6f7accee22f640ce3ab17841badaa4ce232" +checksum = "068208f2b6fcfa27a7f1ee37488d2bb8ba2640f68f5475d08e1d9130696aba59" dependencies = [ - "ahash 0.7.6", + "ahash", "base64 0.13.1", "bitvec", "hex", - "indexmap 1.9.3", + "indexmap", "js-sys", - "lazy_static", - "rand 0.8.5", + "once_cell", + "rand", "serde", "serde_bytes", "serde_json", - "time 0.3.22", + "time", "uuid", ] [[package]] name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "byte-tools" -version = "0.3.1" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "0.4.12" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "bzip2" -version = "0.3.3" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" -dependencies = [ - "bzip2-sys", - "libc", -] +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bzip2" @@ -358,21 +266,15 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.13" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "jobserver", "libc", "shlex", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -381,9 +283,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -405,9 +307,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -415,48 +317,39 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim", ] [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "cloudabi" -version = "0.0.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codepage" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0e9222c0cdf2c6ac27d73f664f9520266fa911c3106329d359f8861cb8bde9" +checksum = "48f68d061bc2828ae826206326e61251aca94c1e4a5305cf52d9138639c918b4" dependencies = [ "encoding_rs", ] @@ -474,125 +367,86 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const-oid" -version = "0.9.3" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" -version = "0.6.4" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "core-foundation-sys 0.6.2", + "core-foundation-sys", "libc", ] [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ - "core-foundation-sys 0.8.4", + "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" +name = "crc" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ - "autocfg 1.1.0", - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard", + "crc-catalog", ] [[package]] -name = "crossbeam-queue" -version = "0.2.3" +name = "crc-catalog" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crossbeam-utils" -version = "0.7.2" +name = "crc32fast" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "autocfg 1.1.0", - "cfg-if 0.1.10", - "lazy_static", + "cfg-if", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -600,7 +454,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] @@ -615,9 +469,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.6" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -625,40 +479,61 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.6" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.50", + "strsim", + "syn 2.0.79", ] [[package]] name = "darling_macro" -version = "0.20.6" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.50", + "syn 2.0.79", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "der" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -671,18 +546,14 @@ dependencies = [ ] [[package]] -name = "destructure_traitobject" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" - -[[package]] -name = "digest" -version = "0.8.1" +name = "derive_arbitrary" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "generic-array 0.12.4", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] @@ -691,62 +562,53 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", ] [[package]] -name = "encoding_rs" -version = "0.8.32" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] -name = "equivalent" -version = "1.0.0" +name = "encoding_rs" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] [[package]] -name = "errno" -version = "0.3.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fastrand" -version = "1.9.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "faux" @@ -767,15 +629,15 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", "uuid", ] [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -808,31 +670,9 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "percent-encoding 2.3.1", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", + "percent-encoding", ] -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "funty" version = "2.0.0" @@ -841,19 +681,12 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - -[[package]] -name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -862,9 +695,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -872,55 +705,44 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -934,15 +756,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -950,7 +763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", - "version_check 0.9.4", + "version_check", ] [[package]] @@ -964,20 +777,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -992,35 +805,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", - "bytes 1.7.1", + "bytes", "fnv", "futures-core", "futures-sink", "http", - "indexmap 2.2.3", + "indexmap", "slab", - "tokio 1.39.3", + "tokio", "tokio-util", "tracing", ] [[package]] name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1040,7 +847,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -1049,7 +856,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ - "bytes 1.7.1", + "bytes", "fnv", "itoa", ] @@ -1060,7 +867,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes 1.7.1", + "bytes", "http", ] @@ -1070,7 +877,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ - "bytes 1.7.1", + "bytes", "futures-util", "http", "http-body", @@ -1079,34 +886,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.10.16" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -dependencies = [ - "base64 0.9.3", - "httparse", - "language-tags", - "log 0.3.9", - "mime 0.2.6", - "num_cpus", - "time 0.1.45", - "traitobject", - "typeable", - "unicase", - "url 1.7.2", -] +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "hyper" @@ -1114,7 +896,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ - "bytes 1.7.1", + "bytes", "futures-channel", "futures-util", "h2", @@ -1123,24 +905,24 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "smallvec 1.13.2", - "tokio 1.39.3", + "smallvec", + "tokio", "want", ] [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", - "hyper 1.4.1", + "hyper", "hyper-util", "rustls", "rustls-pki-types", - "tokio 1.39.3", + "tokio", "tokio-rustls", "tower-service", ] @@ -1151,48 +933,47 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "bytes 1.7.1", + "bytes", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "native-tls", - "tokio 1.39.3", + "tokio", "tokio-native-tls", "tower-service", ] [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ - "bytes 1.7.1", + "bytes", "futures-channel", "futures-util", "http", "http-body", - "hyper 1.4.1", + "hyper", "pin-project-lite", "socket2", - "tokio 1.39.3", - "tower", + "tokio", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", - "core-foundation-sys 0.8.4", + "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1212,43 +993,22 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.1.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg 1.1.0", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" -version = "2.2.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown", ] [[package]] @@ -1257,26 +1017,17 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", + "generic-array", ] [[package]] name = "io-kit-sys" -version = "0.1.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" dependencies = [ - "core-foundation-sys 0.6.2", - "mach 0.2.3", + "core-foundation-sys", + "mach2", ] [[package]] @@ -1291,25 +1042,22 @@ dependencies = [ ] [[package]] -name = "iovec" -version = "0.1.4" +name = "ipnet" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] -name = "ipnet" -version = "2.8.0" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.7" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0aa48fab2893d8a49caa94082ae8488f4e1050d73b367881dcd2198f4199fd8" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" @@ -1322,36 +1070,20 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" - [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -1360,28 +1092,22 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a396bb213c2d09ed6c5495fd082c991b6ab39c9daf4fff59e6727f85c73e4c5" dependencies = [ - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", - "tokio 1.39.3", + "tokio", ] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" @@ -1391,43 +1117,31 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ - "autocfg 1.1.0", + "autocfg", "scopeguard", ] [[package]] -name = "log" -version = "0.3.9" +name = "lockfree-object-pool" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.20", -] +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "serde", ] @@ -1440,60 +1154,47 @@ checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" [[package]] name = "log4rs" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" dependencies = [ "anyhow", "arc-swap", "chrono", "derivative", "fnv", - "humantime", "libc", - "log 0.4.20", + "log", "log-mdc", - "parking_lot 0.12.1", + "once_cell", + "parking_lot", + "rand", "serde", - "serde-value", "serde_json", - "serde_yaml", "thiserror", "thread-id", - "typemap-ors", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "mach" -version = "0.2.3" +name = "lzma-rs" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" dependencies = [ - "libc", + "byteorder", + "crc", ] [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "md5" version = "0.7.0" @@ -1502,27 +1203,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.5.6" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -dependencies = [ - "log 0.3.9", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -1538,30 +1221,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log 0.4.20", - "miow", - "net2", - "slab", - "winapi 0.2.8", + "adler2", ] [[package]] @@ -1572,52 +1236,18 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio 0.6.23", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "msdos_time" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" -dependencies = [ - "time 0.1.45", - "winapi 0.3.9", -] - [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", - "log 0.4.20", + "log", "openssl", "openssl-probe", "openssl-sys", @@ -1627,17 +1257,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "nom" version = "7.1.3" @@ -1654,7 +1273,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1669,57 +1288,52 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", - "smallvec 1.13.2", + "rand", + "smallvec", "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg 1.1.0", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ - "autocfg 1.1.0", + "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.1.0", + "autocfg", "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.31.1" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -1730,30 +1344,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a95602f5a6eec5b15394516448c0b6fc2f2ef4ca2a9ab2951a91a18cec516bf0" dependencies = [ - "ahash 0.8.3", + "ahash", "lazy_static", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", + "bitflags 2.6.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -1769,7 +1380,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] @@ -1780,18 +1391,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.26.0+1.1.1u" +version = "300.3.2+3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -1800,91 +1411,43 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-float" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" -dependencies = [ - "num-traits", -] - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.3", - "rustc_version", -] - [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "lock_api 0.4.10", - "parking_lot_core 0.9.8", + "lock_api", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.6.3" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 0.1.10", - "cloudabi", + "cfg-if", "libc", - "redox_syscall 0.1.57", - "rustc_version", - "smallvec 0.6.14", - "winapi 0.3.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall 0.3.5", - "smallvec 1.13.2", - "windows-targets 0.48.1", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.10.7", + "digest", "hmac", - "password-hash", - "sha2", ] [[package]] @@ -1896,38 +1459,12 @@ dependencies = [ "base64ct", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1963,27 +1500,36 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] -name = "podio" -version = "0.1.7" +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b18befed8bc2b61abc79a457295e7e838417326da1586050b919414073977f19" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2000,14 +1546,14 @@ dependencies = [ "flate2", "hex", "lazy_static", - "rustix 0.36.15", + "rustix 0.36.17", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2018,25 +1564,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi 0.3.9", -] - [[package]] name = "rand" version = "0.8.5" @@ -2044,18 +1571,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -2065,24 +1582,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.6.4" @@ -2092,99 +1594,13 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.9", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.9", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] @@ -2194,7 +1610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", - "bytes 1.7.1", + "bytes", "encoding_rs", "futures-channel", "futures-core", @@ -2203,17 +1619,17 @@ dependencies = [ "http", "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-tls", "hyper-util", "ipnet", "js-sys", - "log 0.4.20", - "mime 0.3.17", + "log", + "mime", "native-tls", "once_cell", - "percent-encoding 2.3.1", + "percent-encoding", "pin-project-lite", "rustls-pemfile", "serde", @@ -2221,11 +1637,11 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "system-configuration", - "tokio 1.39.3", + "tokio", "tokio-native-tls", "tokio-util", "tower-service", - "url 2.5.0", + "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", @@ -2240,19 +1656,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", "getrandom", "libc", - "spin 0.9.8", + "spin", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "ringbuffer" -version = "0.13.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e4fbb37fd18bd949f42583141d650fcdce49dbf759264e4dd3a5df0bc15dc6" +checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53" [[package]] name = "rsa" @@ -2261,13 +1677,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", - "digest 0.10.7", + "digest", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", - "rand_core 0.6.4", + "rand_core", "signature", "spki", "subtle", @@ -2276,24 +1692,15 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc_version" -version = "0.2.3" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.36.15" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -2305,23 +1712,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.22" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "errno", - "io-lifetimes", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "rustls-pki-types", @@ -2342,15 +1748,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -2359,116 +1765,86 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "safemem" -version = "0.3.3" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.59.0", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.1" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.3", - "core-foundation-sys 0.8.4", + "bitflags 2.6.0", + "core-foundation 0.9.4", + "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ - "core-foundation-sys 0.8.4", + "core-foundation-sys", "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.2.3", + "indexmap", "itoa", + "memchr", "ryu", "serde", ] @@ -2485,50 +1861,15 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" -dependencies = [ - "indexmap 1.9.3", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug", -] - [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -2539,39 +1880,36 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", + "digest", + "rand_core", ] [[package]] -name = "slab" -version = "0.4.8" +name = "simd-adler32" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg 1.1.0", -] +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] -name = "smallvec" -version = "0.6.14" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "maybe-uninit", + "autocfg", ] [[package]] @@ -2582,16 +1920,16 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smbios-lib" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7585696daa0d95717d4ff4dc78a5d2e4e8091d85bafe92f28397de5190d7b00d" +checksum = "48c18320ad3d997a100cb948fc020111936c530eddfde947f467083730e39e72" dependencies = [ - "core-foundation 0.6.4", - "core-foundation-sys 0.6.2", + "core-foundation 0.10.0", + "core-foundation-sys", "getopts", "io-kit-sys", "libc", - "mach 0.3.2", + "mach2", "serde", "serde_json", ] @@ -2606,12 +1944,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -2630,21 +1962,15 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2659,9 +1985,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -2684,7 +2010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", - "core-foundation 0.9.3", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2694,7 +2020,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ - "core-foundation-sys 0.8.4", + "core-foundation-sys", "libc", ] @@ -2706,34 +2032,31 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tat_agent" -version = "1.0.20" +version = "1.1.0" dependencies = [ "anyhow", - "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bson", - "bytes 1.7.1", - "cfg-if 1.0.0", + "bytes", + "cfg-if", "chrono", "clap", "codepage-strings", "daemonize", "faux", - "futures 0.1.31", - "futures 0.3.30", + "futures", "glob", "hmac", "leaky-bucket", "libc", - "log 0.4.20", + "log", "log4rs", "md5", "nom", "ntapi", - "once_cell", "openssl", "procfs", - "rand 0.8.5", + "rand", "reqwest", "ringbuffer", "rsa", @@ -2742,81 +2065,71 @@ dependencies = [ "serde_json", "sha1", "smbios-lib", - "tokio 0.1.22", - "tokio 1.39.3", + "tokio", + "tokio-stream", + "tokio-tungstenite", "unix_mode", - "unzip", - "url 2.5.0", + "url", "urlencoding", "users", - "websocket", - "winapi 0.3.9", + "winapi", + "zip", "zip-extract", ] [[package]] name = "tempfile" -version = "3.6.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ - "autocfg 1.1.0", - "cfg-if 1.0.0", + "cfg-if", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.37.22", - "windows-sys 0.48.0", + "once_cell", + "rustix 0.38.37", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] -name = "thread-id" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73" -dependencies = [ - "libc", - "redox_syscall 0.2.16", - "winapi 0.3.9", -] - -[[package]] -name = "time" -version = "0.1.45" +name = "thread-id" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", ] [[package]] name = "time" -version = "0.3.22" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -2824,24 +2137,25 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2854,39 +2168,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "mio 0.6.23", - "num_cpus", - "tokio-codec", - "tokio-current-thread", - "tokio-executor", - "tokio-fs", - "tokio-io", - "tokio-reactor", - "tokio-sync", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "tokio-udp", - "tokio-uds", -] - -[[package]] -name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", - "bytes 1.7.1", + "bytes", "libc", - "mio 1.0.2", - "parking_lot 0.12.1", + "mio", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2894,59 +2183,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "tokio-io", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -dependencies = [ - "futures 0.1.31", - "tokio-executor", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", -] - -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -dependencies = [ - "futures 0.1.31", - "tokio-io", - "tokio-threadpool", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "log 0.4.20", -] - [[package]] name = "tokio-macros" version = "2.4.0" @@ -2955,7 +2191,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", ] [[package]] @@ -2965,26 +2201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.39.3", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "lazy_static", - "log 0.4.20", - "mio 0.6.23", - "num_cpus", - "parking_lot 0.9.0", - "slab", - "tokio-executor", - "tokio-io", - "tokio-sync", + "tokio", ] [[package]] @@ -2995,255 +2212,135 @@ checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", - "tokio 1.39.3", -] - -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -dependencies = [ - "fnv", - "futures 0.1.31", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "iovec", - "mio 0.6.23", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "lazy_static", - "log 0.4.20", - "num_cpus", - "slab", - "tokio-executor", + "tokio", ] [[package]] -name = "tokio-timer" -version = "0.2.13" +name = "tokio-stream" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "slab", - "tokio-executor", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "tokio-tls" -version = "0.2.1" +name = "tokio-tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ - "futures 0.1.31", + "futures-util", + "log", "native-tls", - "tokio-io", -] - -[[package]] -name = "tokio-udp" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "log 0.4.20", - "mio 0.6.23", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-uds" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "iovec", - "libc", - "log 0.4.20", - "mio 0.6.23", - "mio-uds", - "tokio-codec", - "tokio-io", - "tokio-reactor", + "tokio", + "tokio-native-tls", + "tungstenite", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ - "bytes 1.7.1", + "bytes", "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.39.3", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio 1.39.3", - "tower-layer", - "tower-service", + "tokio", ] -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" - -[[package]] -name = "transformation-pipeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1d17c634c5196b37a2680f31627ab35b9e84e5f7f1abd13731c3fbd71dea36" - [[package]] name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typeable" -version = "0.1.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "typemap-ors" -version = "1.0.0" +name = "tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ - "unsafe-any-ors", + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "native-tls", + "rand", + "sha1", + "thiserror", + "utf-8", ] [[package]] name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicase" -version = "1.4.2" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -dependencies = [ - "version_check 0.1.5", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unix_mode" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35abed4630bb800f02451a7428205d1f37b8e125001471bfab259beee6a587ed" - -[[package]] -name = "unsafe-any-ors" -version = "1.0.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" -dependencies = [ - "destructure_traitobject", -] +checksum = "b55eedc365f81a3c32aea49baf23fa965e3cd85bcc28fb8045708c7388d124ef" [[package]] name = "untrusted" @@ -3251,37 +2348,15 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "unzip" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e59a2baae95b4b60ecd5a1ba39e9654b09b09bf813989c70f52c957c213dfd" -dependencies = [ - "time 0.1.45", - "transformation-pipeline", - "zip 0.2.8", -] - -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna 0.5.0", - "percent-encoding 2.3.1", + "idna", + "percent-encoding", ] [[package]] @@ -3297,20 +2372,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" dependencies = [ "libc", - "log 0.4.20", + "log", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.4.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -3324,15 +2405,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - -[[package]] -name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -3343,12 +2418,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3357,36 +2426,37 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", - "log 0.4.20", + "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -3394,9 +2464,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3404,28 +2474,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -3436,61 +2506,14 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "websocket" -version = "0.26.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacab060eea423e4036820ddd28f3f9003b2c4d8048cbda985e5a14e18038d" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "hyper 0.10.16", - "native-tls", - "rand 0.6.5", - "tokio-codec", - "tokio-io", - "tokio-reactor", - "tokio-tcp", - "tokio-tls", - "unicase", - "url 1.7.2", - "websocket-base", -] - -[[package]] -name = "websocket-base" -version = "0.26.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49aec794b07318993d1db16156d5a9c750120597a5ee40c6b928d416186cb138" -dependencies = [ - "base64 0.10.1", - "bitflags 1.3.2", - "byteorder", - "bytes 0.4.12", - "futures 0.1.31", - "native-tls", - "rand 0.6.5", - "sha-1", - "tokio-codec", - "tokio-io", - "tokio-tcp", - "tokio-tls", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -3501,12 +2524,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -3520,12 +2537,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.52.6", ] [[package]] @@ -3558,21 +2575,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -3588,7 +2590,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -3600,6 +2602,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3617,17 +2628,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -3654,9 +2665,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" @@ -3672,9 +2683,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" @@ -3690,9 +2701,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" @@ -3714,9 +2725,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" @@ -3732,9 +2743,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" @@ -3750,9 +2761,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" @@ -3768,9 +2779,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" @@ -3779,31 +2790,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "wyz" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "tap", ] [[package]] -name = "wyz" -version = "0.5.1" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "tap", + "byteorder", + "zerocopy-derive", ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "linked-hash-map", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] @@ -3811,74 +2824,98 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] [[package]] -name = "zip" -version = "0.2.8" +name = "zeroize_derive" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7341988e4535c60882d5e5f0b7ad0a9a56b080ade8bdb5527cb512f7b2180e0" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "bzip2 0.3.3", - "flate2", - "msdos_time", - "podio", - "time 0.1.45", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] name = "zip" -version = "0.6.6" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" dependencies = [ "aes", - "byteorder", - "bzip2 0.4.4", + "arbitrary", + "bzip2", "constant_time_eq", "crc32fast", - "crossbeam-utils 0.8.19", + "crossbeam-utils", + "deflate64", + "displaydoc", "flate2", "hmac", + "indexmap", + "lzma-rs", + "memchr", "pbkdf2", + "rand", "sha1", + "thiserror", + "time", + "zeroize", + "zopfli", "zstd", ] [[package]] name = "zip-extract" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e109e5a291403b4c1e514d39f8a22d3f98d257e691a52bb1f16051bb1ffed63e" +checksum = "25a8c9e90f27d1435088a7b540b6cc8ae6ee525d992a695f16012d2f365b3d3c" dependencies = [ - "log 0.4.20", + "log", "thiserror", - "zip 0.6.6", + "zip", +] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", ] [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index d772142..eb2a089 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,52 +1,61 @@ [package] name = "tat_agent" -version = "1.0.20" +version = "1.1.0" edition = "2018" [dependencies] -tokio = { version = "1.39.3", features = ["full"] } -tokio01 = { version = "0.1.22", package = "tokio" } -futures01 = { version = "0.1", package = "futures" } -reqwest = { version = "0.12", features = ["blocking", "json", "stream"] } -websocket = "0.26.2" +tokio = { version = "1.40.0", features = [ + "test-util", + "rt-multi-thread", + "process", + "macros", +] } +reqwest = { version = "0.12", features = ["json", "stream"] } +tokio-stream = "0.1.16" +tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } bytes = "1.7.1" -futures = "0.3.28" +futures = { version = "0.3.31", default-features = false, features = [ + "std", + "async-await", +] } serde_json = "1.0.57" serde_bytes = "0.11.7" serde = { version = "1.0.115", features = ["derive"] } url = "2.1.1" clap = { version = "4.0.29", features = ["derive"] } log = "0.4.11" -log4rs = "1.2.0" +log4rs = { version = "1.3.0", default-features = false, features = [ + "all_components", +] } libc = "0.2.77" rand = "0.8.5" -base64 = "0.21.2" +base64 = "0.22.1" chrono = "0.4.18" md5 = "0.7.0" -unzip = "0.1.0" -async-trait = "0.1.50" +zip = "2.2.0" cfg-if = "1.0" -faux = "0.1.9" urlencoding = "2.1.2" -bson = "2.4.0" +bson = "2.13.0" glob = "0.3.0" -ringbuffer = "0.13.0" +ringbuffer = "0.15.0" smbios-lib = "0.9.0" -rsa = "0.9.2" +rsa = "0.9.6" hmac = "0.12.1" sha1 = { version = "0.10.5", default-features = false, features = ["oid"] } -once_cell = "1.16.0" -anyhow = "1.0.71" +anyhow = "1.0.89" leaky-bucket = "1.1.2" [target.'cfg(unix)'.dependencies] daemonize = "0.5.0" users = { version = "0.11.0" } -openssl = { version = '0.10.35', features = ["vendored"] } +openssl = { version = '0.10.66', features = ["vendored"] } procfs = "0.15.1" unix_mode = "0.1.3" + [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = [ + "std", + "sysinfoapi", "winsvc", "winbase", "winnt", @@ -75,7 +84,10 @@ winapi = { version = "0.3.9", features = [ codepage-strings = "1.0.2" ntapi = "0.4.1" nom = "7.1.1" -zip-extract = "0.1.2" +zip-extract = "0.2.1" [build-dependencies] -reqwest = { version = "0.12"} +reqwest = { version = "0.12", features = ["blocking"] } + +[dev-dependencies] +faux = "0.1.9" diff --git a/Dockerfile.multi-stage b/Dockerfile.multi-stage index a1fda26..1bf3897 100644 --- a/Dockerfile.multi-stage +++ b/Dockerfile.multi-stage @@ -1,4 +1,4 @@ -FROM rust:1.74 AS builder +FROM rust:1.81 AS builder WORKDIR /agent diff --git a/LICENSE b/LICENSE index e5a33df..ab76236 100644 --- a/LICENSE +++ b/LICENSE @@ -1,246 +1,211 @@ -MIT License --------------------------------------------------------------------- -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of -the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -TATAgent-腾讯云自动化助手客户端组件 is licensed under the MIT License except for the third-party components listed below. -Copyright (C) 2021-2023 THL A29 Limited, a Tencent company. All rights reserved. -The below software in this distribution may have been modified by THL A29 Limited (“Tencent Modifications”). -All Tencent Modifications are Copyright (C) 2021-2023 THL A29 Limited. - - -Other dependencies and licenses: - - -Open Source Software Licensed under the Apache License Version 2.0: --------------------------------------------------------------------- -1. openssl -Copyright 2011-2017 Google Inc. -2013 Jack Lloyd -2013-2014 Steven Fackler - -2. time -Copyright 2021 Jacob Pratt et al. +The TATAgent-腾讯云自动化助手客户端组件 project is built on and with the aid of the following open source projects. Credits are given to these projects. -3. unix-mode -Copyright 2020 Google LLC - -Terms of the Apache License Version 2.0: +Open Source Software Licensed under the MIT License: -------------------------------------------------------------------- -Apache License +1. tokio +Copyright (c) Tokio Contributors -Version 2.0, January 2004 +2. futures +Copyright (c) 2016 Alex Crichton +Copyright (c) 2017 The Tokio Authors -http://www.apache.org/licenses/ +3. reqwest +Copyright (c) 2016 Sean McArthur -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1. Definitions. +4. serde_json +Copyright (c) "Erick Tryzelaar ", "David Tolnay " -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. +5. serde +Copyright (c) "Erick Tryzelaar ", "David Tolnay " -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. +6. url +Copyright (c) 2013-2016 The rust-url developers -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. +7. clap +Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. +8. log +Copyright (c) 2014 The Rust Project Developers -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. +9. log4rs +Copyright (c) 2015-2016 Steven Fackler -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. +10. daemonize +Copyright (c) daemonize original author and authors -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. +11. libc +Copyright (c) 2014-2020 The Rust Project Developers -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." +12. rand +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. +13. base64 +Copyright (c) 2015 Alice Maz -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. +14. chrono +Copyright (c) 2014--2017, Kang Seonghoon and +contributors. -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +15. md5 +Copyright 2015–2019 The md5 Developers -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +16. bytes +Copyright (c) 2018 Carl Lerche -You must give any other recipients of the Work or Derivative Works a copy of this License; and +17. users +Copyright (c) 2019 Benjamin Sago -You must cause any modified files to carry prominent notices stating that You changed the files; and +18. tokio-stream +Copyright (c) Tokio Contributors -You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +19. tokio-tungstenite +Copyright (c) 2017 Daniel Abramov +Copyright (c) 2017 Alexey Galakhov -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. +20. serde_bytes +Copyright (c) 2014 The Rust Project Developers -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +21. zip +Copyright (c) 2014 Mathijs van de Nes -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. +22. cfg-if +Copyright (c) 2014 Alex Crichton -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. +23. urlencoding +© 2016 Bertram Truong +© 2021 Kornel Lesiński -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. +24. bson +Copyright (c) 2015 Y. T. CHUNG -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. +25. glob +Copyright (c) 2014 The Rust Project Developers -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. +26. ringbuffer +Copyright (c) 2022 Victor Roest and Jonathan Dönszelmann -END OF TERMS AND CONDITIONS +27. smbios-lib +Copyright (c) 2021 jrgerber +28. rsa +Copyright (c) rsa original author and authors +29. hmac +Copyright (c) 2017 Artyom Pavlov -Open Source Software Licensed under the MIT License: --------------------------------------------------------------------- -1. tokio (v0.2.22) -Copyright (c) 2019 Tokio Contributors +30. sha1 +Copyright (c) 2006-2009 Graydon Hoare +Copyright (c) 2009-2013 Mozilla Foundation +Copyright (c) 2016 Artyom Pavlov -2. tokio (v0.1.22) -Copyright (c) 2019 Tokio Contributors +31. anyhow +Copyright (c) anyhow original author and authors -3. futures (v0.3) -Copyright (c) 2016 Alex Crichton -Copyright (c) 2017 The Tokio Authors +32. leaky-bucket +Copyright (c) 2019 John-John Tedro -4. futures (v0.1) -Copyright (c) 2016 Alex Crichton +33. procfs +Copyright (c) 2015 The procfs Developers -5. reqwest -Copyright (c) 2016 Sean McArthur +34. winapi +Copyright (c) 2015-2018 The winapi-rs Developers -6. serde_json -Copyright (c) "Erick Tryzelaar ", "David Tolnay " +35. codepage-strings +Copyright © 2021 Bart Massey -7. serde -Copyright (c) "Erick Tryzelaar ", "David Tolnay " +36. ntapi +Copyright (c) ntapi original author and authors -8. url -Copyright (c) 2013-2016 The rust-url developers +37. nom +Copyright (c) 2014-2019 Geoffroy Couprie -9. clap -Copyright (c) 2015-2016 Kevin B. Knapp +38. zip-extract +Copyright (c) 2020 MCOfficer -10. tokio-test -Copyright (c) 2019 Tokio Contributors +39. faux +Copyright (c) 2020 Andres Medina -11. log -Copyright (c) 2014 The Rust Project Developers -12. log4rs -Copyright (c) 2015-2016 Steven Fackler +Terms of the MIT License: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -13. daemonize -Copyright (c) 2016 Fedor Gogolev +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -14. websocket -Copyright (c) 2014 Rust Websockets Developers +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -15. libc -Copyright (c) 2014-2020 The Rust Project Developers -16. bytes -Copyright (c) 2018 Carl Lerche -17. unzip -Copyright (c) “Ryan Leonard (http://ryanleonard.us)” +Open Source Software Licensed under the Apache License Version 2.0: +-------------------------------------------------------------------- +1. openssl +Copyright 2011-2017 Google Inc. + 2013 Jack Lloyd + 2013-2014 Steven Fackler +Source code of this software can be obtained from: https://docs.rs/crate/openssl/0.10.35/source/ -18. hyper -Copyright (c) 2014-2018 Sean McArthur +2. unix_mode +Copyright (c) unix_mode original author and authors +Source code of this software can be obtained from: https://docs.rs/crate/unix_mode/0.1.3/source/ -19. users -Copyright (c) 2019 Benjamin Sago -20. rand -Copyright 2018 Developers of the Rand project -Copyright (c) 2014 The Rust Project Developers +Terms of the Apache License Version 2.0: +-------------------------------------------------------------------- +Apache License -21. base64 -Copyright (c) 2015 Alice Maz +Version 2.0, January 2004 -22. chrono -Copyright (c) 2014--2017, Kang Seonghoon and -contributors. +http://www.apache.org/licenses/ -23. md5 -Copyright 2015–2019 The md5 Developers +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1. Definitions. -24. encoding -Copyright (c) 2013, Kang Seonghoon +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. -25. cfg-if -Copyright (c) 2014 Alex Crichton +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. -26. procfs -Copyright (c) 2015 The procfs Developers +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. -27. winapi -Copyright (c) 2015-2018 The winapi-rs Developers +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. -28. faux -Copyright (c) 2020 Andres Medina +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. -29. rust-crypto -Copyright (c) 2006-2009 Graydon Hoare -Copyright (c) 2009-2013 Mozilla Foundation +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. -30. urlencoding -Copyright (c) 2016 Bertram Truong +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). -31. hex -Copyright (c) 2013-2014 The Rust Project Developers -Copyright (c) 2015-2020 The rust-hex Developers +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. -32. derive_more -Copyright (c) 2016 Jelte Fennema +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." -33. ntapi -Copyright (c) ntapi authors +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. -34. field-offset -Copyright (c) field-offset authors +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. -35. winpty -Copyright (c) 2011-2016 Ryan Prichard +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. -36. bash-preexec -Copyright (c) 2017 Ryan Caloras and contributors +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: -37. serde_bytes -Copyright (c) 2014 The Rust Project Developers +You must give any other recipients of the Work or Derivative Works a copy of this License; and -38. bson-rust -Copyright (c) 2015 Y. T. CHUNG +You must cause any modified files to carry prominent notices stating that You changed the files; and -39. glob -Copyright (c) 2014 The Rust Project Developers +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and -40. nom -Copyright (c) 2014-2019 Geoffroy Couprie +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. -41. ringbuffer -Copyright (c) 2022 Victor Roest and Jonathan Dönszelmann +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. -Terms of the MIT License: --------------------------------------------------------------------- -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. -Open Source Software Licensed under the MIT and Apache License Version 2.0: --------------------------------------------------------------------- -1. once_cell -Copyright once_cell authors and contributrs +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. -The terms of the MIT and Apache v2 license are included in this text file. +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README-ZH.md b/README-ZH.md index 72c2310..8c252f7 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -12,23 +12,13 @@ ## 编译 -执行以下命令编译: - -- Linux 系统: - -```shell -cargo build --release --bin tat_agent -``` - -- Windows 系统: - -注意:在 Windows 系统下,rust 的版本**必须高于 1.70**,如果版本过低,可以通过以下命令更新版本: +注意:rust 的版本**必须高于 1.80**,如果版本过低,可以通过以下命令更新版本: ```powershell rustup update ``` -然后运行: +然后执行以下命令编译: ```powershell cargo build --release --bin tat_agent diff --git a/README.md b/README.md index b06cb46..217d552 100644 --- a/README.md +++ b/README.md @@ -12,23 +12,13 @@ For more information, please visit . ## Compile -Run the following command to compile: - -- Linux - -```shell -cargo build --release --bin tat_agent -``` - -- Windows - -Note: In Windows OS, the version of rust must be **higher than 1.70**, If the version is too low, you can update the version with the following command: +The version of rust must be **higher than 1.80**, If the version is too low, you can update the version with the following command: ```powershell rustup update ``` -Then run: +Then run the following command to compile:: ```powershell cargo build --release --bin tat_agent diff --git a/src/common/config.rs b/src/common/config.rs index 757e97c..f876e0c 100644 --- a/src/common/config.rs +++ b/src/common/config.rs @@ -1,11 +1,12 @@ -use base64::{engine::general_purpose::STANDARD, Engine}; -use serde::{Deserialize, Serialize}; -use std::error::Error; +use crate::common::utils::update_file_permission; + use std::fs::{self, File}; use std::io::{ErrorKind, Read, Write}; use std::sync::atomic::{AtomicBool, Ordering}; -use crate::common::utils::update_file_permission; +use anyhow::Result; +use base64::{engine::general_purpose::STANDARD, Engine}; +use serde::{Deserialize, Serialize}; const CONFIG_DAT: &str = "config.dat"; const REGISTER_FILE: &str = "register.dat"; @@ -56,27 +57,20 @@ pub fn get_ws_url() -> Option { pub fn get_register_info() -> Option { static NEED_CHECK: AtomicBool = AtomicBool::new(true); - match load_config().ok().and_then(|config| config.register) { - Some(info) => Some(info), - None => match get_register_info_old() { - Some(info) => { - if save_register_info(info.clone()).is_ok() { - let _ = fs::remove_file(REGISTER_FILE); - }; - Some(info) + let ret = load_config().ok().and_then(|cfg| cfg.register).or_else(|| { + get_register_info_old().inspect(|info| { + if save_register_info(info.clone()).is_ok() { + let _ = fs::remove_file(REGISTER_FILE); } - None => None, - }, + }) + }); + if ret.is_some() && NEED_CHECK.fetch_and(false, Ordering::SeqCst) { + update_file_permission(CONFIG_DAT) } - .and_then(|x| { - if NEED_CHECK.fetch_and(false, Ordering::SeqCst) { - update_file_permission(CONFIG_DAT) - } - Some(x) - }) + ret } -pub fn save_register_info(info: RegisterInfo) -> Result<(), Box> { +pub fn save_register_info(info: RegisterInfo) -> Result<()> { let mut config = load_config()?; config.register = Some(info); save_config(&config) @@ -89,16 +83,11 @@ fn get_register_info_old() -> Option { return Some(record); } -fn load_config() -> Result> { +fn load_config() -> Result { let mut file = match File::open(CONFIG_DAT) { Ok(file) => file, - Err(e) => { - if e.kind() == ErrorKind::NotFound { - return Ok(Config::default()); - } else { - return Err(Box::new(e)); - } - } + Err(e) if e.kind() == ErrorKind::NotFound => return Ok(Config::default()), + e => e?, }; let mut contents = String::new(); @@ -107,7 +96,7 @@ fn load_config() -> Result> { Ok(config) } -fn save_config(config: &Config) -> Result<(), Box> { +fn save_config(config: &Config) -> Result<()> { let json_str = serde_json::to_string(config)?; let mut file = File::create(CONFIG_DAT)?; file.write_all(json_str.as_bytes())?; diff --git a/src/common/evbus.rs b/src/common/evbus.rs index 7bdba52..5217f80 100644 --- a/src/common/evbus.rs +++ b/src/common/evbus.rs @@ -8,13 +8,12 @@ use log::debug; const SLOT_DEFAULT: &str = "event_slot_default"; type Handler = Box) + Sync + Send + 'static>; -#[derive(Clone)] pub struct EventBus { - event_slots: Arc>>, - slot_queues: Arc>>>, - event_handlers: Arc>>, - dispatch_count: Arc, - receive_count: Arc, + event_slots: RwLock>, + slot_queues: RwLock>>, + event_handlers: RwLock>, + dispatch_count: AtomicU64, + receive_count: AtomicU64, } struct Event { @@ -23,14 +22,14 @@ struct Event { } struct EventQueue { - queue: Arc>>, + queue: Mutex>, signal: Condvar, } impl EventQueue { fn new() -> Self { EventQueue { - queue: Arc::new(Mutex::new(LinkedList::new())), + queue: Mutex::new(LinkedList::new()), signal: Condvar::new(), } } @@ -61,15 +60,15 @@ impl EventQueue { impl EventBus { pub fn new() -> Self { EventBus { - event_slots: Arc::new(RwLock::new(HashMap::new())), - event_handlers: Arc::new(RwLock::new(HashMap::new())), - slot_queues: Arc::new(RwLock::new(HashMap::new())), - dispatch_count: Arc::new(AtomicU64::new(0)), - receive_count: Arc::new(AtomicU64::new(0)), + event_slots: RwLock::new(HashMap::new()), + event_handlers: RwLock::new(HashMap::new()), + slot_queues: RwLock::new(HashMap::new()), + dispatch_count: AtomicU64::new(0), + receive_count: AtomicU64::new(0), } } - pub fn slot_register(&self, slot: &str, event: &str, func: F) -> &Self + pub fn slot_register(self: &Arc, slot: &str, event: &str, func: F) -> &Arc where F: Fn(Vec) + 'static + Sync + Send, { @@ -92,33 +91,31 @@ impl EventBus { let queue = Arc::new(EventQueue::new()); slot_queues.insert(slot.to_string(), queue.clone()); - let self_0 = self.clone(); - let receive_count = self.receive_count.clone(); - //create thread for queue - let _ = std::thread::Builder::new() - .name(slot.to_string()) - .spawn(move || loop { + let _ = std::thread::Builder::new().name(slot.to_string()).spawn({ + let eb = self.clone(); + move || loop { let event = queue.pull_event(); - if let Some(handler) = self_0 + if let Some(handler) = eb .event_handlers .read() .expect("event_handlers lock failed") - .get(event.name.as_str()) + .get(&event.name) { - let count = receive_count.fetch_add(1, SeqCst); + let count = eb.receive_count.fetch_add(1, SeqCst); debug!("receive_count: {}", count); handler(event.msg); } - }); + } + }); self } - pub fn register(&self, event: &str, func: F) -> &Self + pub fn register(self: &Arc, event: &str, func: F) -> &Arc where F: Fn(Vec) + 'static + Sync + Send, { - return self.slot_register(SLOT_DEFAULT, event, func); + self.slot_register(SLOT_DEFAULT, event, func) } pub fn dispatch(&self, event: &str, msg: Vec) { diff --git a/src/common/logger.rs b/src/common/logger.rs index 982ce8f..d76bf47 100644 --- a/src/common/logger.rs +++ b/src/common/logger.rs @@ -1,6 +1,10 @@ use crate::common::utils::update_file_permission; use crate::common::Opts; -use log::{debug, info, Record}; + +use std::fs::{create_dir_all, OpenOptions}; + +use anyhow::Result; +use log::{debug, Record}; use log4rs::append::console::{ConsoleAppender, Target}; use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller; use log4rs::append::rolling_file::policy::compound::roll::Roll; @@ -12,7 +16,6 @@ use log4rs::config::{Appender, Config, Root}; use log4rs::encode::pattern::PatternEncoder; use log4rs::filter::threshold::ThresholdFilter; use log4rs::filter::{Filter, Response}; -use std::fs::{create_dir_all, OpenOptions}; const LOG_PATTERN: &str = "{d}|{f}:{L}|{l}|{m}{n}"; const LOG_FILE_NAME: &str = "log/tat_agent.log"; @@ -21,7 +24,6 @@ const LOG_FILE_SIZE: u64 = 10 * 1024 * 1024; const LOG_FILE_BASE_INDEX: u32 = 0; const MAX_LOG_FILE_COUNT: u32 = 2; const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info; -const LOG_LEVEL_DEBUG: log::LevelFilter = log::LevelFilter::Debug; pub fn init() { let log_level = LOG_LEVEL; @@ -93,7 +95,7 @@ impl CompoundPolicy { } impl Policy for CompoundPolicy { - fn process(&self, log: &mut LogFile) -> anyhow::Result<()> { + fn process(&self, log: &mut LogFile) -> Result<()> { if self.trigger.trigger(log)? { log.roll(); self.roller.roll(log.path())?; @@ -105,10 +107,17 @@ impl Policy for CompoundPolicy { } Ok(()) } + + fn is_pre_process(&self) -> bool { + self.trigger.is_pre_process() + } } -#[allow(dead_code)] +#[cfg(test)] pub fn init_test_log() { + use log::info; + const LOG_LEVEL_DEBUG: log::LevelFilter = log::LevelFilter::Debug; + let stdout: ConsoleAppender = ConsoleAppender::builder() .encoder(Box::new(PatternEncoder::new(LOG_PATTERN))) .build(); @@ -116,9 +125,6 @@ pub fn init_test_log() { .appender(Appender::builder().build("stdout", Box::new(stdout))) .build(Root::builder().appender("stdout").build(LOG_LEVEL_DEBUG)) .unwrap(); - match log4rs::init_config(log_config) { - Ok(_) => (), - Err(why) => info!("init test log failed: {}", why), - }; + let _ = log4rs::init_config(log_config); info!("logger init succ"); } diff --git a/src/common/option.rs b/src/common/option.rs index 4ec024d..54a610f 100644 --- a/src/common/option.rs +++ b/src/common/option.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, OnceLock}; +use std::sync::LazyLock; use clap::{Parser, Subcommand}; @@ -38,9 +38,8 @@ pub enum EnumCommands { } impl Opts { - pub fn get_opts() -> Arc { - static INS: OnceLock> = OnceLock::new(); - let ins = INS.get_or_init(|| Arc::new(Opts::parse())); - ins.clone() + pub fn get_opts() -> &'static Opts { + static INS: LazyLock = LazyLock::new(|| Opts::parse()); + &INS } } diff --git a/src/conpty/file.rs b/src/conpty/file.rs index 027a223..8f809d9 100644 --- a/src/conpty/file.rs +++ b/src/conpty/file.rs @@ -1,5 +1,7 @@ +use super::gather::Gather; use super::handler::{BsonHandler, Handler}; use crate::common::evbus::EventBus; +use crate::conpty::handler::HandlerExt; use crate::network::types::ws_msg::{ CreateFileReq, CreateFileResp, DeleteFileReq, DeleteFileResp, FileExistResp, FileExistsReq, FileInfoReq, FileInfoResp, ListPathReq, ListPathResp, PtyBinErrMsg, ReadFileReq, ReadFileResp, @@ -13,7 +15,7 @@ use std::path::Path; use std::sync::Arc; use std::time::SystemTime; -use async_trait::async_trait; +use anyhow::Result; use glob::Pattern; use log::info; use tokio::fs::{metadata, remove_dir_all, remove_file, OpenOptions}; @@ -54,29 +56,28 @@ const WS_MSG_TYPE_PTY_FILE_INFO: &str = "PtyFileInfo"; pub fn register_file_handlers(event_bus: &Arc) { event_bus .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_CREATE_FILE, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_DELETE_FILE, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_LIST_PATH, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_FILE_EXIST, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_FILE_INFO, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_WRITE_FILE, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_READ_FILE, move |msg| { - BsonHandler::::dispatch(msg, true) + Gather::dispatch::>(msg, true); }); } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let d = &self.request.data; @@ -110,14 +111,14 @@ impl Handler for BsonHandler { // create file as user let plugin = &self.channel.as_ref().unwrap().plugin.component; let create_result = plugin.execute(&|| { - create_dir_all(parent_path).map_err(|e| e.to_string())?; + create_dir_all(parent_path)?; if d.is_dir { - create_dir(&d.path).map_err(|e| e.to_string())?; + create_dir(&d.path)?; } else { - File::create(&d.path).map_err(|e| e.to_string())?; + File::create(&d.path)?; } #[cfg(unix)] - set_permissions(&d.path, Permissions::from_mode(d.mode)).map_err(|e| e.to_string())?; + set_permissions(&d.path, Permissions::from_mode(d.mode))?; Ok(Vec::new()) }); @@ -128,7 +129,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let path = &self.request.data.path; @@ -158,7 +158,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let path = &self.request.data.path; @@ -172,7 +171,7 @@ impl Handler for BsonHandler { Err(e) => return self.reply(PtyBinErrMsg::new(e)).await, }; - let files = match list_path(path, pattern.clone(), show_hidden) { + let files = match list_path(path, &pattern, show_hidden) { Ok(files) => files, Err(e) => return self.reply(PtyBinErrMsg::new(e)).await, }; @@ -194,7 +193,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let path = &self.request.data.path; @@ -204,7 +202,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let path = &self.request.data.path; @@ -216,7 +213,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let data = &self.request.data; @@ -249,7 +245,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let data = &self.request.data; @@ -311,7 +306,7 @@ fn get_win32_ready_drives() -> Vec { } //windows path format: /d:/work -fn list_path(path: &str, filter: Pattern, show_hidden: bool) -> Result, String> { +fn list_path(path: &str, filter: &Pattern, show_hidden: bool) -> Result> { let mut files = Vec::::new(); let mut path = path.to_string(); @@ -333,7 +328,7 @@ fn list_path(path: &str, filter: Pattern, show_hidden: bool) -> Result, - pub stop_counter: Arc, - pub sessions: RwLock>>, - pub ws_seq_num: AtomicU64, + event_bus: Arc, + stop_counter: Arc, + sessions: RwLock>>, + ws_seq_num: AtomicU64, limiter: RwLock, runtime: Runtime, } -static GATHER: OnceCell = OnceCell::new(); +static GATHER: OnceLock = OnceLock::new(); pub fn run(event_bus: &Arc, running_task_num: &Arc) { GATHER.get_or_init(|| { @@ -56,16 +57,22 @@ impl Gather { GATHER.get().expect("runtime") } - pub fn runtime() -> &'static Runtime { - &Gather::instance().runtime + pub fn sync_dispatch(msg: Vec, need_channel: bool) { + let rt = &Gather::instance().runtime; + rt.block_on(T::dispatch(msg, need_channel)); } - pub async fn add_session(session_id: &str, session: Arc) -> Result<(), String> { + pub fn dispatch(msg: Vec, need_channel: bool) { + let rt = &Gather::instance().runtime; + rt.spawn(async move { T::dispatch(msg, need_channel).await }); + } + + pub async fn add_session(session_id: &str, session: Arc) -> Result<()> { let gather = Gather::instance(); let mut sessions = gather.sessions.write().await; if sessions.contains_key(session_id) { error!("duplicate add_session: {session_id}"); - Err(format!("session `{session_id}` already start"))? + Err(anyhow!("session `{session_id}` already start"))? } sessions.insert(session_id.to_owned(), session.clone()); diff --git a/src/conpty/handler.rs b/src/conpty/handler.rs index 2d6271f..a361b20 100644 --- a/src/conpty/handler.rs +++ b/src/conpty/handler.rs @@ -1,18 +1,22 @@ use super::{gather::Gather, session::Channel}; use crate::network::types::ws_msg::{PtyBinBase, PtyBinErrMsg, PtyError, PtyJsonBase, WsMsg}; -use std::io::Cursor; use std::sync::Arc; +use std::{future::Future, io::Cursor}; -use async_trait::async_trait; use bson::Document; use log::error; use serde::{de::DeserializeOwned, Serialize}; use serde_json::Value; -#[async_trait] pub trait Handler { - async fn process(self); + fn process(self) -> impl Future + Send; +} + +pub trait HandlerExt: Handler { + fn id(&self) -> String; + fn dispatch(msg: Vec, need_channel: bool) -> impl Future + Send; + async fn reply(&self, data: M); } pub struct BsonHandler { @@ -21,15 +25,16 @@ pub struct BsonHandler { pub op_type: String, } -impl BsonHandler +impl HandlerExt for BsonHandler where - T: DeserializeOwned + Default + Sync + Send + 'static, + T: DeserializeOwned + Default + Send + Sync, + Self: Handler, { - pub fn id(&self) -> String { + fn id(&self) -> String { format!("{}:{}", self.request.session_id, self.request.channel_id) } - pub fn dispatch(msg: Vec, channel_required: bool) + async fn dispatch(msg: Vec, need_channel: bool) where Self: Handler, { @@ -49,9 +54,6 @@ where return error!("BsonHandler::dispatch {} msg.data is None", msg.r#type); }; - let session_id = req.session_id.clone(); - let channel_id = req.channel_id.clone(); - // Compatible with legacy front-end code // If no channel_id is provided, use empty string as channel_id. // if session_id.is_empty() || channel_id.is_empty() { @@ -64,55 +66,49 @@ where op_type: op, }; - Gather::runtime().spawn(async move { - if let Some(session) = Gather::get_session(&session_id).await { - if let Some(channel) = session.get_channel(&channel_id).await { - handler.channel = Some(channel); - } - } + let session_id = &handler.request.session_id; + let channel_id = &handler.request.channel_id; - if channel_required && handler.channel.is_none() { - error!("BsonHandler::dispatch channel `{}` not found", handler.id()); - return handler.reply(PtyBinErrMsg::new("Channel not found")).await; + if let Some(session) = Gather::get_session(session_id).await { + if let Some(channel) = session.get_channel(channel_id).await { + handler.channel = Some(channel); } + } - handler.process().await - }); - } + if need_channel && handler.channel.is_none() { + error!("BsonHandler::dispatch channel `{}` not found", handler.id()); + return handler.reply(PtyBinErrMsg::new("Channel not found")).await; + } - pub async fn reply(&self, data: M) { - Self::reply_with(&self.request, &self.op_type, data).await + handler.process().await } - async fn reply_with(req: &PtyBinBase, op: &str, data: M) { - let session_id = req.session_id.clone(); - let channel_id = req.channel_id.clone(); - let custom_data = req.custom_data.clone(); + async fn reply(&self, data: M) { let msg = PtyBinBase { - session_id, - channel_id, - custom_data, + session_id: self.request.session_id.clone(), + channel_id: self.request.channel_id.clone(), + custom_data: self.request.custom_data.clone(), data, }; - Gather::reply_bson_msg(op, msg).await + Gather::reply_bson_msg(&self.op_type, msg).await } } -// #[derive(Clone)] pub struct JsonHandler { pub channel: Option>, pub request: PtyJsonBase, } -impl JsonHandler +impl HandlerExt for JsonHandler where - T: DeserializeOwned + Default + Sync + Send + 'static, + T: DeserializeOwned + Default + Send + Sync, + Self: Handler, { - pub fn id(&self) -> String { + fn id(&self) -> String { format!("{}:{}", self.request.session_id, self.request.channel_id) } - pub fn dispatch(msg: Vec, channel_required: bool) + async fn dispatch(msg: Vec, need_channel: bool) where Self: Handler, { @@ -149,23 +145,21 @@ where request, }; - Gather::runtime().spawn(async move { - if let Some(session) = Gather::get_session(&session_id).await { - if let Some(channel) = session.get_channel(&channel_id).await { - handler.channel = Some(channel); - } + if let Some(session) = Gather::get_session(&session_id).await { + if let Some(channel) = session.get_channel(&channel_id).await { + handler.channel = Some(channel); } + } - if channel_required && handler.channel.is_none() { - error!("JsonHandler::dispatch channel `{}` not found", handler.id()); - return handler.reply(PtyError::new("Channel not found")).await; - } + if need_channel && handler.channel.is_none() { + error!("JsonHandler::dispatch channel `{}` not found", handler.id()); + return handler.reply(PtyError::new("Channel not found")).await; + } - handler.process().await - }); + handler.process().await } - pub async fn reply(&self, data: M) { + async fn reply(&self, data: M) { let msg_type = get_msg_type(&data); let body = PtyJsonBase { session_id: self.request.session_id.clone(), diff --git a/src/conpty/proxy.rs b/src/conpty/proxy.rs index 87de71b..3301ebf 100644 --- a/src/conpty/proxy.rs +++ b/src/conpty/proxy.rs @@ -2,20 +2,19 @@ use super::gather::Gather; use super::handler::{BsonHandler, Handler}; use super::session::{PluginCtrl, PluginData}; use crate::common::evbus::EventBus; +use crate::conpty::handler::HandlerExt; use crate::conpty::session::{Channel, Plugin, PluginComp, Session}; use crate::network::types::ws_msg::{ ProxyClose, ProxyData, ProxyNew, ProxyReady, PtyBinBase, PtyBinErrMsg, }; use std::sync::Arc; -use std::time::Duration; -use async_trait::async_trait; use log::{error, info}; use serde::Serialize; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; use tokio::net::TcpStream; +use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use tokio::sync::Mutex; use tokio::time::Instant; @@ -30,64 +29,66 @@ const PROXY_BUF_SIZE: usize = 2048; pub fn register_proxy_handlers(event_bus: &Arc) { event_bus .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_PROXY_NEW, move |msg| { - BsonHandler::::dispatch(msg, false); + Gather::dispatch::>(msg, false); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_PROXY_DATA, move |msg| { - BsonHandler::::dispatch(msg, true); + Gather::sync_dispatch::>(msg, true); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_PROXY_CLOSE, move |msg| { - BsonHandler::::dispatch(msg, false); + Gather::dispatch::>(msg, false); }); } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let req = &self.request; let proxy_id = req.data.proxy_id.clone(); info!("=>proxy_new `{}`, channel `{}`", proxy_id, self.id()); + let session_id = req.session_id.clone(); let channel_id = match self.channel.as_ref() { Some(ch) if ch.plugin.try_get_proxy().is_some() => { error!("duplicate proxy_new `{proxy_id}`"); - return self - .reply(PtyBinErrMsg::new(format!("proxy already start"))) - .await; + let e = "proxy already start"; + return self.reply(PtyBinErrMsg::new(e)).await; } // Compatible with legacy front-end code // If no channel_id is provided, use proxy_id as channel_id. _ if req.channel_id.is_empty() => proxy_id.clone(), Some(_) => { error!("channel `{}` already start", self.id()); - return self - .reply(PtyBinErrMsg::new(format!("channel already start"))) - .await; + let e = "channel already start"; + return self.reply(PtyBinErrMsg::new(e)).await; } None => req.channel_id.clone(), }; let dest = format!("127.0.0.1:{}", req.data.port); - let r = TcpStream::connect(&dest).await; - let Ok(stream) = r.map_err(|e| info!("proxy `{proxy_id}` connect failed: {e}")) else { - return; + let stream = match TcpStream::connect(&dest).await { + Ok(s) => Mutex::new(s), + Err(e) => { + info!("proxy `{proxy_id}` connect failed: {e}"); + return self.reply(PtyBinErrMsg::new(e)).await; + } }; - let (reader, writer) = stream.into_split(); + let (tx, rx) = unbounded_channel(); let proxy = Proxy { proxy_id: proxy_id.clone(), - reader: Mutex::new(reader), - writer: Mutex::new(writer), + stream, + rx: Mutex::new(rx), + tx, }; let plugin = Plugin { component: PluginComp::Proxy(proxy), data: req.into(), controller: PluginCtrl::new(PROXY_REMOVE_INTERVAL), }; - let channel = Arc::new(Channel::new(&req.session_id, &channel_id, plugin)); - let session = match Gather::get_session(&req.session_id).await { + let channel = Arc::new(Channel::new(&session_id, &channel_id, plugin)); + let session = match Gather::get_session(&session_id).await { Some(s) => s, None => { - let s = Arc::new(Session::new(&req.session_id)); - let _ = Gather::add_session(&req.session_id, s.clone()).await; + let s = Arc::new(Session::new(&session_id)); + let _ = Gather::add_session(&session_id, s.clone()).await; s } }; @@ -97,8 +98,8 @@ impl Handler for BsonHandler { } let data = PtyBinBase { - session_id: req.session_id.clone(), - channel_id: req.channel_id.clone(), + session_id, + channel_id, custom_data: "".to_owned(), data: ProxyReady { proxy_id }, }; @@ -106,11 +107,10 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { - let req = &self.request; - let proxy_id = &req.data.proxy_id; + let req = self.request; + let proxy_id = req.data.proxy_id.clone(); // info!("=>proxy_data `{}`, channel `{}`", proxy_id, self.id()); let mut ch = self.channel.unwrap().clone(); @@ -118,7 +118,7 @@ impl Handler for BsonHandler { // If no channel_id is provided, use proxy_id as channel_id. if req.channel_id.is_empty() { if let Some(session) = Gather::get_session(&req.session_id).await { - if let Some(channel) = session.get_channel(proxy_id).await { + if let Some(channel) = session.get_channel(&proxy_id).await { ch = channel.clone(); } } @@ -128,16 +128,12 @@ impl Handler for BsonHandler { }; let _ = proxy - .writer - .lock() - .await - .write_all(&req.data.data) - .await - .map_err(|err| error!("proxy_data `{}` write failed: {}", proxy_id, err)); + .tx + .send(req.data.data) + .inspect_err(|err| error!("proxy_data `{}` send failed: {}", proxy_id, err)); } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let req = &self.request; @@ -158,8 +154,9 @@ impl Handler for BsonHandler { pub struct Proxy { pub proxy_id: String, - reader: Mutex, - writer: Mutex, + stream: Mutex, + rx: Mutex>>, + tx: UnboundedSender>, } impl Proxy { @@ -167,14 +164,11 @@ impl Proxy { let mut buffer = [0u8; PROXY_BUF_SIZE]; let mut size = 0; let mut count = 0; - let mut stopper_rx = ctrl - .stopper - .get_receiver() - .await - .expect("get_receiver failed"); - let mut reader = self.reader.lock().await; - // Upon initialization, set the last reply time to an instant before the timer was created. - let mut last_reply = Instant::now() - Duration::from_secs(PROXY_REMOVE_INTERVAL); + let mut stopper_rx = ctrl.stopper.get_receiver().await.unwrap(); + let mut stream = self.stream.lock().await; + let (mut reader, mut writer) = stream.split(); + let mut proxy_rx = self.rx.lock().await; + let mut last_reply = Instant::now(); info!("Proxy `{}` start loop for proxy responses", id); loop { @@ -193,6 +187,12 @@ impl Proxy { } Err(e) => break error!("Proxy `{}` read failed: {}", id, e), }, + recv = proxy_rx.recv() => if let Some(v) = recv { + let _ = writer + .write_all(&v) + .await + .inspect_err(|err| error!("Proxy `{}` write failed: {}", id, err)); + }, _ = &mut stopper_rx => break info!("Proxy `{}` stopped", id), _ = ctrl.timer.timeout() => if ctrl.timer.is_timeout_refresh(last_reply).await { break info!("Proxy `{}` timeout", id); diff --git a/src/conpty/pty/bind.rs b/src/conpty/pty/bind.rs index 9b170a5..7252640 100644 --- a/src/conpty/pty/bind.rs +++ b/src/conpty/pty/bind.rs @@ -27,6 +27,12 @@ pub struct winpty_s { } pub type winpty_t = winpty_s; +impl winpty_t { + pub fn new() -> Self { + Self { _unused: [] } + } +} + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct winpty_spawn_config_s { diff --git a/src/conpty/pty/mod.rs b/src/conpty/pty/mod.rs index 5f6c702..79a9601 100644 --- a/src/conpty/pty/mod.rs +++ b/src/conpty/pty/mod.rs @@ -1,5 +1,5 @@ use super::gather::Gather; -use super::handler::{BsonHandler, Handler, JsonHandler}; +use super::handler::{BsonHandler, Handler, HandlerExt, JsonHandler}; use super::session::{Channel, Plugin, PluginCtrl, PluginData, Session}; use crate::common::evbus::EventBus; use crate::common::utils::get_current_username; @@ -16,7 +16,7 @@ use std::pin::Pin; use std::sync::Arc; use std::time::Duration; -use async_trait::async_trait; +use anyhow::{anyhow, Context, Result}; use base64::{engine::general_purpose::STANDARD, Engine}; use log::{error, info}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -52,7 +52,6 @@ cfg_if::cfg_if! { } } -type PtyResult = Result; type PtyExecCallback = Box< dyn Fn(u32, bool, Option, Vec) -> Pin + Send>> + Send @@ -62,33 +61,32 @@ type PtyExecCallback = Box< pub fn register_pty_handlers(event_bus: &Arc) { event_bus .slot_register(SLOT_PTY_CMD, WS_MSG_TYPE_PTY_START, move |value| { - JsonHandler::::dispatch(value, false); + Gather::dispatch::>(value, false); }) .slot_register(SLOT_PTY_CMD, WS_MSG_TYPE_PTY_STOP, move |value| { - JsonHandler::::dispatch(value, false); + Gather::dispatch::>(value, false); }) .slot_register(SLOT_PTY_CMD, WS_MSG_TYPE_PTY_RESIZE, move |value| { - JsonHandler::::dispatch(value, true); + Gather::dispatch::>(value, true); }) .slot_register(SLOT_PTY_CMD, WS_MSG_TYPE_PTY_INPUT, move |value| { - JsonHandler::::dispatch(value, true); + Gather::dispatch::>(value, true); }) .slot_register(SLOT_PTY_CMD, WS_MSG_TYPE_PTY_MAX_RATE, move |value| { - JsonHandler::::dispatch(value, false); + Gather::dispatch::>(value, false); }) .slot_register(SLOT_PTY_BIN, WS_MSG_TYPE_PTY_EXEC_CMD, move |value| { - BsonHandler::::dispatch(value, true); + Gather::dispatch::>(value, true); }) .slot_register( SLOT_PTY_BIN, WS_MSG_TYPE_PTY_EXEC_CMD_STREAM, move |value| { - BsonHandler::::dispatch(value, true); + Gather::dispatch::>(value, true); }, ); } -#[async_trait] impl Handler for JsonHandler { async fn process(self) { let req = &self.request.data; @@ -102,7 +100,7 @@ impl Handler for JsonHandler { } let comp = if req.no_shell { - PluginComp::None { username } + PluginComp::Nil { username } } else { #[cfg(windows)] let pty_res = { @@ -150,7 +148,6 @@ impl Handler for JsonHandler { } } -#[async_trait] impl Handler for JsonHandler { async fn process(self) { let session_id = &self.request.session_id; @@ -168,7 +165,6 @@ impl Handler for JsonHandler { } } -#[async_trait] impl Handler for JsonHandler { async fn process(self) { info!("=>pty_resize `{}`", self.id()); @@ -184,7 +180,6 @@ impl Handler for JsonHandler { } } -#[async_trait] impl Handler for JsonHandler { async fn process(self) { // info!("=>pty_input `{}`", self.id()); @@ -208,7 +203,6 @@ impl Handler for JsonHandler { } #[cfg(windows)] -#[async_trait] impl Handler for BsonHandler { async fn process(self) { self.reply(PtyBinErrMsg::new("not support on windows")) @@ -217,36 +211,36 @@ impl Handler for BsonHandler { } #[cfg(unix)] -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let data = &self.request.data; - info!("=>exec_cmd `{}`, command: {}", self.id(), data.cmd); - let plugin = &self.channel.as_ref().unwrap().plugin.component; - let result = plugin.execute(&|| { - let mut command = Command::new("bash"); - unsafe { - command - .args(&["-c", data.cmd.as_str()]) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .pre_exec(|| { - libc::dup2(1, 2); - Ok(()) - }); - } + info!( + "=>exec_cmd `{}`, command: {}", + self.id(), + data.cmd.escape_debug() + ); - command - .output() - .map(|out| String::from_utf8_lossy(&out.stdout).as_bytes().to_vec()) - .map_err(|err| format!("err_msg: {}", err)) + let plugin = &self.channel.as_ref().unwrap().plugin.component; + let result = plugin.execute(&|| unsafe { + let output = Command::new("bash") + .args(&["-c", data.cmd.as_str()]) + .stdin(Stdio::null()) + .pre_exec(|| { + libc::dup2(1, 2); + Ok(()) + }) + .output()?; + Ok(String::from_utf8_lossy(&output.stdout).as_bytes().to_vec()) }); match result { Ok(output) => { let output = String::from_utf8_lossy(&output).to_string(); - info!("exec_cmd `{}` success, output: {}", self.id(), output); + info!( + "exec_cmd `{}` success, output: {}", + self.id(), + output.escape_debug() + ); self.reply(ExecCmdResp { output }).await } Err(err) => { @@ -257,17 +251,20 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for BsonHandler { async fn process(self) { let data = &self.request.data; - info!("=>exec_cmd_stream `{}`, command: {}", self.id(), data.cmd); + info!( + "=>exec_cmd_stream `{}`, command: {}", + self.id(), + data.cmd.escape_debug() + ); let sid = self.request.session_id.clone(); let cid = self.request.channel_id.clone(); let cdata = self.request.custom_data.clone(); let op = self.op_type.clone(); - let cb: PtyExecCallback = Box::new(move |index, is_last, exit_code, data: Vec| { + let cb: PtyExecCallback = Box::new(move |index, is_last, exit_code, data| { let msg = PtyBinBase { session_id: sid.clone(), channel_id: cid.clone(), @@ -298,7 +295,6 @@ impl Handler for BsonHandler { } } -#[async_trait] impl Handler for JsonHandler { async fn process(self) { let rate = self.request.data.rate; @@ -320,8 +316,7 @@ impl Pty { .expect("get_receiver failed"); let mut buf = [0u8; PTY_BUF_SIZE]; let mut reader = self.get_reader().await.expect("get_reader Failed"); - // Upon initialization, set the last reply time to an instant before the timer was created. - let mut last_reply = Instant::now() - Duration::from_secs(PTY_REMOVE_INTERVAL); + let mut last_reply = Instant::now(); loop { tokio::select! { @@ -366,14 +361,14 @@ pub async fn execute_stream( #[cfg(windows)] token: &File, #[cfg(windows)] pipe: File, #[cfg(windows)] username: &str, -) -> PtyResult<()> { +) -> Result<()> { let mut idx = 0u32; let mut is_last; let timeout_at = Instant::now() + Duration::from_secs(timeout); let mut buf = [0u8; PTY_EXEC_DATA_SIZE]; #[allow(unused_mut)] // Unix needs MUT, Windows does not. - let mut child = cmd.spawn().map_err(|_| "command start failed")?; + let mut child = cmd.spawn().context("command start failed")?; let pid = child.id().unwrap(); #[cfg(windows)] @@ -388,7 +383,7 @@ pub async fn execute_stream( loop { tokio::select! { len = reader.read(&mut buf) => { - let len = len.map_err(|_| "buffer read failed")?; + let len = len.context("buffer read failed")?; is_last = len == 0; if is_last { break; @@ -400,7 +395,7 @@ pub async fn execute_stream( _ = tokio::time::sleep_until(timeout_at) => { error!("work_as_user func timeout"); kill_process_group(pid); - Err("command timeout, process killed")?; + Err(anyhow!("command timeout, process killed"))?; } }; } @@ -408,19 +403,20 @@ pub async fn execute_stream( let exit_status = child .wait_with_output() .await - .map_err(|_| "wait command failed")? + .context("wait command failed")? .status; if !exit_status.success() { error!("work_as_user func exit failed: {}", exit_status); } - let exit_code = exit_status.code().ok_or("command terminated abnormally")?; + let exit_code = exit_status.code().context("command exit abnormally")?; callback(idx, is_last, Some(exit_code), Vec::new()).await; Ok(()) } #[cfg(test)] mod test { - use super::{Pty, PtyResult}; + use super::Pty; + use crate::common::logger::init_test_log; use crate::common::utils::get_current_username; use crate::conpty::pty::PtyExecCallback; use crate::conpty::session::PluginComp; @@ -431,10 +427,11 @@ mod test { use log::info; use tokio::io::{AsyncReadExt, AsyncWriteExt}; - use tokio::time::timeout; + use tokio::time::{sleep, timeout}; #[tokio::test] async fn test_pty() { + init_test_log(); let user_name = get_current_username(); #[cfg(windows)] let pty = Pty::new(&user_name, 200, 100, 0).unwrap(); @@ -473,6 +470,7 @@ mod test { info!("output: {}", output); let result = output.to_string().contains("test"); std::mem::drop(pty); + sleep(Duration::from_secs(1)).await; // yield to let pty drop assert!(result); } @@ -488,33 +486,30 @@ mod test { script: &str, timeout: Option, data_map: HashMap, Vec)>, - expect_result: PtyResult<()>, + expect_result: Result<(), String>, ) { let username = get_current_username(); - let plugin = PluginComp::None { username }; - - let cb: PtyExecCallback = Box::new( - move |idx: u32, is_last: bool, exit_code: Option, data: Vec| { - let (expect_is_last, expect_exit_code, expect_data) = data_map - .get(&idx) - .expect(&format!("idx `{idx}` not expect")); - // info!("idx:{idx}, is_last:{is_last}, exit_code:{exit_code:?}, data:{data:?}"); - assert_eq!(*expect_is_last, is_last); - assert_eq!(*expect_exit_code, exit_code); - assert_eq!(*expect_data, data); - Box::pin(async {}) - }, - ); + let plugin = PluginComp::Nil { username }; + + let cb: PtyExecCallback = Box::new(move |idx, is_last, exit_code, data| { + let (expect_is_last, expect_exit_code, expect_data) = data_map + .get(&idx) + .expect(&format!("idx `{idx}` not expect")); + assert_eq!(*expect_is_last, is_last); + assert_eq!(*expect_exit_code, exit_code); + assert_eq!(*expect_data, data); + Box::pin(async {}) + }); let cmd = init_cmd(script); let result = plugin.execute_stream(cmd, Some(cb), timeout).await; - assert_eq!(expect_result, result); + assert_eq!(expect_result, result.map_err(|e| e.to_string())); } fn test_execute_stream_data() -> Vec<( &'static str, Option, HashMap, Vec)>, - PtyResult<()>, + Result<(), String>, )> { #[cfg(unix)] let cmd_timeout = [ diff --git a/src/conpty/pty/unix.rs b/src/conpty/pty/unix.rs index f8bea56..cfbea9d 100644 --- a/src/conpty/pty/unix.rs +++ b/src/conpty/pty/unix.rs @@ -1,4 +1,4 @@ -use super::{execute_stream, PtyExecCallback, PtyResult}; +use super::{execute_stream, PtyExecCallback}; use crate::conpty::{session::PluginComp, PTY_INSPECT_READ}; use crate::executor::unix::{build_envs, prepare_cmd}; @@ -11,6 +11,7 @@ use std::os::unix::prelude::{AsRawFd, FromRawFd, RawFd}; use std::path::{Path, PathBuf}; use std::{env, io, ptr}; +use anyhow::{anyhow, Context, Result}; use libc::{self, getsid, pid_t, ttyname, uid_t, winsize, STDIN_FILENO, TIOCSCTTY}; use log::{error, info}; use tokio::fs::{metadata, File}; @@ -35,8 +36,8 @@ impl Pty { cols: u16, rows: u16, envs: HashMap, - ) -> PtyResult { - let user = get_user_by_name(user_name).ok_or(format!("user {} not exist", user_name))?; + ) -> Result { + let user = get_user_by_name(user_name).context(format!("user {} not exist", user_name))?; let shell_path = user.shell(); let shell_name = Path::new(shell_path) .file_name() @@ -73,8 +74,7 @@ impl Pty { .stderr(slave.try_clone().expect("")) .envs(local_envs.into_iter().chain(envs)) .current_dir(home_path) - .spawn() - .map_err(|e| format!("spawn error: {}", e))?; + .spawn()?; let pid = child.id().unwrap() as pid_t; let sid = unsafe { getsid(pid) }; @@ -83,7 +83,7 @@ impl Pty { let tty_name_c = ttyname(slave.as_raw_fd()); CStr::from_ptr(tty_name_c).to_string_lossy().to_string() }; - call_utmpx(&tty_name.clone(), user_name, pid, sid, &utmx_type).await; + call_utmpx(&tty_name, user_name, pid, sid, &utmx_type).await; // Kill terminal process when Pty is dropped let (send, mut recv) = channel::<()>(); @@ -107,28 +107,25 @@ impl Pty { }); } - pub async fn resize(&self, cols: u16, rows: u16) -> PtyResult<()> { + pub async fn resize(&self, cols: u16, rows: u16) -> Result<()> { let size = winsize { ws_row: rows, ws_col: cols, ws_xpixel: 0, ws_ypixel: 0, }; - - unsafe { libc::ioctl(self.master.as_raw_fd(), libc::TIOCSWINSZ, &size as *const _) == 0 } - .then_some(()) - .ok_or_else(|| io::Error::last_os_error().to_string()) + if unsafe { libc::ioctl(self.master.as_raw_fd(), libc::TIOCSWINSZ, &size) == 0 } { + return Ok(()); + } + Err(io::Error::last_os_error())? } - pub async fn get_reader(&self) -> PtyResult { + pub async fn get_reader(&self) -> Result { self.get_writer().await } - pub async fn get_writer(&self) -> PtyResult { - self.master - .try_clone() - .await - .map_err(|e| format!("error: {e}")) + pub async fn get_writer(&self) -> Result { + Ok(self.master.try_clone().await?) } pub fn get_cwd(&self) -> PathBuf { @@ -142,8 +139,8 @@ impl Pty { } impl PluginComp { - pub async fn inspect_access(&self, path: &str, access: u8) -> PtyResult<()> { - let metadata = metadata(path).await.map_err(|e| e.to_string())?; + pub async fn inspect_access(&self, path: &str, access: u8) -> Result<()> { + let metadata = metadata(path).await?; let user = self.get_user()?; let access = match access { PTY_INSPECT_READ => Access::Read, @@ -174,10 +171,10 @@ impl PluginComp { return Ok(()); } - Err("access denied")? + Err(anyhow!("access denied"))? } - pub fn execute(&self, f: &dyn Fn() -> PtyResult>) -> PtyResult> { + pub fn execute(&self, f: &dyn Fn() -> Result>) -> Result> { let user = self.get_user()?; let cwd_path = self.get_cwd(&user); @@ -195,9 +192,9 @@ impl PluginComp { let _ = stdin.write_all(&output); libc::exit(0); } - Err(err_msg) => { - //error!("[child] work_as_user func exit failed: {}", err_msg); - let _ = stdin.write_all(err_msg.as_bytes()); + Err(e) => { + //error!("[child] work_as_user func exit failed: {}", e); + let _ = stdin.write_all(e.to_string().as_bytes()); libc::exit(1); } } @@ -213,7 +210,7 @@ impl PluginComp { } let err_msg = String::from_utf8_lossy(&output).to_string(); error!("[parent] work_as_user func exit failed: {}", err_msg); - return Err(err_msg); + return Err(anyhow!(err_msg)); } } } @@ -223,7 +220,7 @@ impl PluginComp { cmd: Command, callback: Option, timeout: Option, - ) -> PtyResult<()> { + ) -> Result<()> { let user = self.get_user()?; let cwd_path = self.get_cwd(&user); let cmd = prepare_cmd(cmd, &user, cwd_path); @@ -233,13 +230,13 @@ impl PluginComp { execute_stream(cmd, &callback, timeout).await } - fn get_user(&self) -> PtyResult { + fn get_user(&self) -> Result { let user = match self { Self::Pty(pty) => pty.user.clone(), - Self::None { username } => { - get_user_by_name(username).ok_or(format!("user {} not exist", username))? + Self::Nil { username } => { + get_user_by_name(username).context(format!("user {} not exist", username))? } - _ => Err("unsupported channel plugin")?, + _ => Err(anyhow!("unsupported channel plugin"))?, }; Ok(user) } @@ -252,7 +249,7 @@ impl PluginComp { } } -fn openpty(user: User, cols: u16, rows: u16) -> PtyResult<(File, StdFile)> { +fn openpty(user: User, cols: u16, rows: u16) -> Result<(File, StdFile)> { let mut master: RawFd = -1; let mut slave: RawFd = -1; @@ -271,7 +268,7 @@ fn openpty(user: User, cols: u16, rows: u16) -> PtyResult<(File, StdFile)> { ptr::null_mut(), &mut size, ) { - return Err(format!("openpty failed: {}", io::Error::last_os_error())); + return Err(anyhow!("openpty failed: {}", io::Error::last_os_error())); }; libc::fchown(slave, user.uid(), user.primary_group_id()); @@ -308,7 +305,7 @@ async fn call_utmpx(ttyname: &str, username: &str, pid: pid_t, sid: pid_t, ut_ty } } -fn audit_setloginuid(uid: uid_t) -> std::io::Result<()> { +fn audit_setloginuid(uid: uid_t) -> io::Result<()> { info!("=>audit_setloginuid {}", uid); let loginuid = format!("{}", uid); let loginuid_path = format!("/proc/self/loginuid"); @@ -325,7 +322,7 @@ mod tests { #[tokio::test] async fn test_work_as_user() { let username = get_current_username(); - let plugin = PluginComp::None { username }; + let plugin = PluginComp::Nil { username }; let result = plugin.execute(&|| Ok("foo".to_string().into_bytes())); let foo = String::from_utf8_lossy(&result.unwrap()).to_string(); diff --git a/src/conpty/pty/windows.rs b/src/conpty/pty/windows.rs index 0e615aa..a3b4c95 100644 --- a/src/conpty/pty/windows.rs +++ b/src/conpty/pty/windows.rs @@ -5,10 +5,10 @@ use super::bind::{ winpty_spawn_config_new, winpty_t, }; use super::parser::{do_parse, AnsiItem, EscapeItem}; -use super::{execute_stream, PtyExecCallback, PtyResult}; +use super::{execute_stream, PtyExecCallback}; use crate::common::utils::{str2wsz, wsz2string}; use crate::conpty::session::PluginComp; -use crate::conpty::{gather::Gather, PTY_FLAG_ENABLE_BLOCK, PTY_INSPECT_WRITE}; +use crate::conpty::{PTY_FLAG_ENABLE_BLOCK, PTY_INSPECT_WRITE}; use crate::executor::windows::{ anon_pipe, get_user_token, kill_process_group, load_environment, prepare_cmd, }; @@ -23,6 +23,7 @@ use std::os::windows::raw::HANDLE; use std::ptr::null_mut; use std::{mem, ptr}; +use anyhow::{anyhow, bail, Result}; use log::{error, info}; use ntapi::ntpsapi::{ NtResumeProcess, NtSetInformationProcess, ProcessAccessToken, PROCESS_ACCESS_TOKEN, @@ -54,7 +55,7 @@ pub struct Pty { } impl Pty { - pub fn new(user_name: &str, cols: u16, rows: u16, flag: u32) -> PtyResult { + pub fn new(user_name: &str, cols: u16, rows: u16, flag: u32) -> Result { let (mut pty_ptr, token) = openpty(user_name, cols, rows)?; let writer = unsafe { let conin_name = winpty_conin_name(pty_ptr.as_mut()); @@ -70,7 +71,7 @@ impl Pty { ); if conin == INVALID_HANDLE_VALUE { let err = Error::last_os_error(); - Err(format!("CreateFileW error: {}", err))? + Err(anyhow!("CreateFileW error: {}", err))? } File::from_raw_handle(conin) }; @@ -83,7 +84,7 @@ impl Pty { }) } - pub async fn resize(&self, cols: u16, rows: u16) -> PtyResult<()> { + pub async fn resize(&self, cols: u16, rows: u16) -> Result<()> { unsafe { winpty_set_size( self.pty_ptr.lock().await.as_mut(), @@ -95,7 +96,7 @@ impl Pty { Ok(()) } - pub async fn get_reader(&self) -> PtyResult { + pub async fn get_reader(&self) -> Result { unsafe { let conin_name = winpty_conout_name(self.pty_ptr.lock().await.as_mut()); @@ -111,7 +112,7 @@ impl Pty { ); if !self.enable_block { - return Ok(tokioFile::from_std(File::from_raw_handle(conin))); + return Ok(tokioFile::from_raw_handle(conin)); } let input = File::from_raw_handle(conin); let (read_pipe, write_pipe) = anon_pipe(true)?; @@ -123,20 +124,17 @@ impl Pty { } } - pub async fn get_writer(&self) -> PtyResult { - self.writer - .try_clone() - .await - .map_err(|e| format!("error: {e}")) + pub async fn get_writer(&self) -> Result { + Ok(self.writer.try_clone().await?) } } impl Drop for Pty { fn drop(&mut self) { unsafe { - let mut this: Mutex> = Mutex::new(Box::from_raw(ptr::null_mut())); + let mut this = Mutex::new(Box::new(winpty_t::new())); std::mem::swap(&mut self.pty_ptr, &mut this); - Gather::runtime().spawn(async move { + tokio::spawn(async move { let process = winpty_agent_process(this.lock().await.as_mut()) as HANDLE; let pid = GetProcessId(process); kill_process_group(pid); @@ -147,7 +145,7 @@ impl Drop for Pty { } impl PluginComp { - pub async fn inspect_access(&self, path: &str, access: u8) -> PtyResult<()> { + pub async fn inspect_access(&self, path: &str, access: u8) -> Result<()> { unsafe { let desired_access = if access == PTY_INSPECT_WRITE { FILE_GENERIC_WRITE @@ -170,11 +168,11 @@ impl PluginComp { CloseHandle(handle); return Ok(()); } - return Err("access deny".to_string()); + return Err(anyhow!("access deny")); } } - pub fn execute(&self, f: &dyn Fn() -> PtyResult>) -> PtyResult> { + pub fn execute(&self, f: &dyn Fn() -> Result>) -> Result> { unsafe { let handle = self.get_token()?.as_raw_handle(); ImpersonateLoggedOnUser(handle); @@ -189,7 +187,7 @@ impl PluginComp { cmd: tokio::process::Command, callback: Option, timeout: Option, - ) -> PtyResult<()> { + ) -> Result<()> { let token = self.get_token()?; let username = self.get_username()?; let mut work_dir = wsz2string(get_cwd(token.as_raw_handle()).as_ptr()); @@ -204,19 +202,19 @@ impl PluginComp { execute_stream(cmd, &callback, timeout, &token, receiver, &username).await } - fn get_token(&self) -> PtyResult { + fn get_token(&self) -> Result { match self { - Self::Pty(pty) => pty.token.try_clone().map_err(|e| format!("error: {e}")), - Self::None { username } => get_user_token(username), - _ => Err("unsupported channel plugin")?, + Self::Pty(pty) => Ok(pty.token.try_clone()?), + Self::Nil { username } => get_user_token(username), + _ => Err(anyhow!("unsupported channel plugin"))?, } } - fn get_username(&self) -> PtyResult { + fn get_username(&self) -> Result { match self { Self::Pty(pty) => Ok(pty.user_name.clone()), - Self::None { username } => Ok(username.clone()), - _ => Err("unsupported channel plugin")?, + Self::Nil { username } => Ok(username.clone()), + _ => Err(anyhow!("unsupported channel plugin"))?, } } } @@ -337,7 +335,7 @@ fn get_cwd(token: HANDLE) -> Vec { cwd } -fn openpty(user_name: &str, cols: u16, rows: u16) -> PtyResult<(Box, File)> { +fn openpty(user_name: &str, cols: u16, rows: u16) -> Result<(Box, File)> { unsafe { let token = get_user_token(user_name)?; let mut err_ptr: *mut winpty_error_ptr_t = ptr::null_mut(); @@ -345,7 +343,7 @@ fn openpty(user_name: &str, cols: u16, rows: u16) -> PtyResult<(Box, F if config.is_null() { let err = wsz2string(winpty_error_msg(err_ptr)); winpty_error_free(err_ptr); - return Err(err); + bail!(err); } winpty_config_set_initial_size(config, cols as i32, rows as i32); @@ -355,7 +353,7 @@ fn openpty(user_name: &str, cols: u16, rows: u16) -> PtyResult<(Box, F if pty_ptr.is_null() { let err = wsz2string(winpty_error_msg(err_ptr)); winpty_error_free(err_ptr); - return Err(err); + bail!(err); } let cmdline = str2wsz("powershell.exe"); @@ -373,7 +371,7 @@ fn openpty(user_name: &str, cols: u16, rows: u16) -> PtyResult<(Box, F if spawn_config.is_null() { let err = wsz2string(winpty_error_msg(err_ptr)); winpty_error_free(err_ptr); - return Err(err); + bail!(err); } err_ptr = ptr::null_mut(); @@ -390,7 +388,7 @@ fn openpty(user_name: &str, cols: u16, rows: u16) -> PtyResult<(Box, F if !succ { let err = wsz2string(winpty_error_msg(err_ptr)); winpty_error_free(err_ptr); - return Err(err); + bail!(err); } //change process token diff --git a/src/conpty/session.rs b/src/conpty/session.rs index bcb55bb..02b654b 100644 --- a/src/conpty/session.rs +++ b/src/conpty/session.rs @@ -7,6 +7,7 @@ use crate::network::types::ws_msg::{PtyBinBase, PtyJsonBase}; use std::collections::HashMap; use std::sync::Arc; +use anyhow::{anyhow, Result}; use log::{error, info}; use tokio::sync::RwLock; @@ -35,12 +36,12 @@ impl Session { self.stopper.stop().await; } - pub async fn add_channel(&self, channel_id: &str, channel: Arc) -> Result<(), String> { + pub async fn add_channel(&self, channel_id: &str, channel: Arc) -> Result<()> { let id = format!("{}:{}", self.session_id, channel_id); let mut chs = self.channels.write().await; if chs.contains_key(channel_id) { error!("duplicate add_channel `{id}`"); - Err(format!("channel `{id}` already start"))? + Err(anyhow!("channel `{id}` already start"))? } chs.insert(channel_id.to_owned(), channel.clone()); info!("add_channel `{id}`"); @@ -90,7 +91,7 @@ impl Drop for Session { fn drop(&mut self) { let mut this: ChannelMap = Default::default(); std::mem::swap(&mut this, &mut self.channels); - Gather::runtime().spawn(async move { + tokio::spawn(async move { for ch in this.read().await.values() { ch.stop().await; } @@ -142,7 +143,7 @@ pub struct Plugin { pub enum PluginComp { Pty(Pty), Proxy(Proxy), - None { username: String }, + Nil { username: String }, } impl Plugin { @@ -150,7 +151,7 @@ impl Plugin { match &self.component { PluginComp::Pty(_) => format!("{}:{}", self.data.session_id, self.data.channel_id), PluginComp::Proxy(proxy) => proxy.proxy_id.clone(), - PluginComp::None { .. } => format!("{}:{}", self.data.session_id, self.data.channel_id), + PluginComp::Nil { .. } => format!("{}:{}", self.data.session_id, self.data.channel_id), } } @@ -159,7 +160,7 @@ impl Plugin { match &self.component { PluginComp::Pty(pty) => pty.process(&id, &self.data, &self.controller).await, PluginComp::Proxy(proxy) => proxy.process(&id, &self.data, &self.controller).await, - PluginComp::None { .. } => tokio::select! { + PluginComp::Nil { .. } => tokio::select! { _ = self.controller.stopper.get_receiver().await.expect("get_receiver failed") => (), _ = self.controller.timer.timeout() => info!("Channel `{id}` timeout"), }, diff --git a/src/daemonizer/windows.rs b/src/daemonizer/windows.rs index ced59d7..d342902 100644 --- a/src/daemonizer/windows.rs +++ b/src/daemonizer/windows.rs @@ -94,7 +94,7 @@ fn try_start_service(entry: fn()) { fn clean_update_files() { wow64_disable_exc(|| { - Command::new("cmd.exe") + let _ = Command::new("cmd.exe") .args(&[ "/C", "del", @@ -104,8 +104,7 @@ fn clean_update_files() { .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn() - .map_err(|_| error!("clean_update_files failed")) - .ok(); + .inspect_err(|_| error!("clean_update_files failed")); }) } diff --git a/src/executor/mod.rs b/src/executor/mod.rs index 1ac94cf..9cdb6d8 100644 --- a/src/executor/mod.rs +++ b/src/executor/mod.rs @@ -10,16 +10,14 @@ pub const CMD_TYPE_POWERSHELL: &str = "POWERSHELL"; cfg_if::cfg_if! { if #[cfg(unix)] { pub mod unix; - pub use unix::{UnixCommand as SystemCommand, init_cmd}; - pub use unix::{decode_output, kill_process_group}; + pub use unix::{decode_output, init_cmd, kill_process_group}; pub const TASK_STORE_PATH: &str = "/tmp/tat_agent/commands/"; pub const TASK_LOG_PATH: &str = "/tmp/tat_agent/logs/"; pub const FILE_EXECUTE_PERMISSION_MODE: u32 = 0o755; } else if #[cfg(windows)] { pub mod windows; - pub use windows::{WindowsCommand as SystemCommand, init_powershell_cmd as init_cmd}; - pub use windows::{decode_output, kill_process_group}; + pub use windows::{decode_output, init_powershell_cmd as init_cmd, kill_process_group}; pub const TASK_STORE_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\commands\\"; pub const TASK_LOG_PATH: &str = "C:\\Program Files\\qcloud\\tat_agent\\tmp\\logs\\"; diff --git a/src/executor/proc.rs b/src/executor/proc.rs index 909d855..ca87ae0 100644 --- a/src/executor/proc.rs +++ b/src/executor/proc.rs @@ -6,27 +6,29 @@ use crate::executor::{CMD_TYPE_BAT, CMD_TYPE_POWERSHELL}; use crate::network::types::UTF8_BOM_HEADER; use crate::common::utils::get_now_secs; -use crate::executor::{decode_output, kill_process_group, SystemCommand}; -use crate::network::cos::{ObjectAPI, COS}; +use crate::executor::{decode_output, kill_process_group}; +use crate::network::cos_adapter::COSAdapter; use crate::network::urls::get_meta_url; -use crate::network::{InvokeAPIAdapter, MetadataAPIAdapter}; +use crate::network::{InvokeAdapter, MetadataAdapter}; #[cfg(test)] use std::fmt::{self, Debug}; +#[cfg(windows)] +use std::os::windows::prelude::FromRawHandle; -use std::fs::{create_dir_all, File, OpenOptions}; -use std::io::Write; -use std::ops::Deref; use std::path::Path; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering::SeqCst}; use std::sync::{Arc, Mutex}; use std::time::Duration; -use async_trait::async_trait; +use anyhow::{anyhow, Context, Result}; use log::{debug, error, info, warn}; -use tokio::io::AsyncReadExt; +use tokio::fs::{create_dir_all, File, OpenOptions}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::process::Child; use tokio::time::Instant; +#[cfg(windows)] +use winapi::um::winnt::HANDLE; use super::FINISH_RESULT_TERMINATED; const BUF_SIZE: usize = 1024; @@ -36,18 +38,6 @@ const FINISH_RESULT_SUCCESS: &str = "SUCCESS"; const FINISH_RESULT_FAILED: &str = "FAILED"; const FINISH_RESULT_START_FAILED: &str = "START_FAILED"; -#[cfg(not(test))] -#[async_trait] -pub trait MyCommand: Deref { - async fn run(&mut self) -> Result<(), String>; -} - -#[cfg(test)] -#[async_trait] -pub trait MyCommand: Deref + Debug { - async fn run(&mut self) -> Result<(), String>; -} - pub fn new( cmd_path: &str, username: &str, @@ -59,29 +49,30 @@ pub fn new( cos_bucket: &str, cos_prefix: &str, task_id: &str, -) -> Result, String> { +) -> Result> { #[cfg(unix)] let is_matches = matches!(cmd_type, CMD_TYPE_SHELL); #[cfg(windows)] let is_matches = matches!(cmd_type, CMD_TYPE_POWERSHELL | CMD_TYPE_BAT); - if is_matches { - return Ok(Box::new(SystemCommand::new( - cmd_path, - username, - work_dir, - timeout, - bytes_max_report, - log_file_path, - cos_bucket, - cos_prefix, - task_id, - ))); - } - Err(format!("invalid cmd_type: {}", cmd_type)) + if !is_matches { + return Err(anyhow!("invalid cmd_type: {}", cmd_type)); + } + + Ok(Arc::new(Cmd::new( + cmd_path, + username, + work_dir, + timeout, + bytes_max_report, + log_file_path, + cos_bucket, + cos_prefix, + task_id, + ))) } -pub struct BaseCommand { +pub struct Cmd { pub cmd_path: String, pub username: String, pub work_dir: String, @@ -93,11 +84,11 @@ pub struct BaseCommand { pub bytes_dropped: AtomicU64, // it's true after finish - pub finished: Arc, + pub finished: AtomicBool, // Only read this value if self.finished==true - pub exit_code: Arc>>, + pub exit_code: Mutex>, // current output which ready to report - pub output: Arc>>, + pub output: Mutex>, // current output report index pub output_idx: AtomicU32, @@ -113,16 +104,19 @@ pub struct BaseCommand { // it's None before start, will be Some after self.run() pub pid: Mutex>, // if child has been killed by kill -9 - pub killed: Arc, + pub killed: AtomicBool, // if child is timeout - pub is_timeout: Arc, + pub is_timeout: AtomicBool, // the time command process finished - pub finish_time: Arc, + pub finish_time: AtomicU64, // err_info when command start fail pub err_info: Mutex, + + #[cfg(windows)] + pub token: std::fs::File, } -impl BaseCommand { +impl Cmd { pub fn new( cmd_path: &str, username: &str, @@ -133,9 +127,16 @@ impl BaseCommand { cos_bucket: &str, cos_prefix: &str, task_id: &str, - ) -> BaseCommand { + ) -> Self { + #[cfg(windows)] + let cmd_path = if cmd_path.ends_with(".ps1") { + cmd_path.replace(" ", "` ") + } else { + cmd_path.to_string() + }; + let timestamp = get_now_secs(); - BaseCommand { + Self { cmd_path: cmd_path.to_string(), username: username.to_string(), work_dir: work_dir.to_string(), @@ -143,9 +144,9 @@ impl BaseCommand { bytes_max_report, bytes_reported: AtomicU64::new(0), bytes_dropped: AtomicU64::new(0), - finished: Arc::new(AtomicBool::new(false)), - exit_code: Arc::new(Mutex::new(None)), - output: Arc::new(Mutex::new(Default::default())), + finished: AtomicBool::new(false), + exit_code: Mutex::new(None), + output: Mutex::new(Default::default()), output_idx: AtomicU32::new(0), log_file_path: log_file_path.to_string(), cos_bucket: cos_bucket.to_string(), @@ -154,10 +155,13 @@ impl BaseCommand { output_url: Mutex::new("".to_string()), output_err_info: Mutex::new("".to_string()), pid: Mutex::new(None), - killed: Arc::new(AtomicBool::new(false)), - is_timeout: Arc::new(AtomicBool::new(false)), - finish_time: Arc::new(AtomicU64::new(timestamp)), + killed: AtomicBool::new(false), + is_timeout: AtomicBool::new(false), + finish_time: AtomicU64::new(timestamp), err_info: Mutex::new("".to_string()), + + #[cfg(windows)] + token: unsafe { std::fs::File::from_raw_handle(0 as HANDLE) }, } } @@ -180,7 +184,7 @@ impl BaseCommand { // set as the total dropped bytes self.bytes_dropped.store(len as u64 - bytes_needed, SeqCst); } - output.write(&data[..bytes_needed]).unwrap(); + output.extend(&data[..bytes_needed]); self.bytes_reported.fetch_add(bytes_needed as u64, SeqCst); } @@ -256,8 +260,7 @@ impl BaseCommand { } pub fn err_info(&self) -> String { - let err_info = self.err_info.lock().unwrap(); - String::from(err_info.as_str()) + self.err_info.lock().unwrap().clone() } pub fn finish_time(&self) -> u64 { @@ -265,28 +268,26 @@ impl BaseCommand { } pub fn output_url(&self) -> String { - let output_url = self.output_url.lock().unwrap(); - String::from(output_url.as_str()) + self.output_url.lock().unwrap().clone() } pub fn output_err_info(&self) -> String { - let err_info = self.output_err_info.lock().unwrap(); - String::from(err_info.as_str()) + self.output_err_info.lock().unwrap().clone() } pub fn on_timeout(&self) { let pid = self.pid.lock().unwrap().unwrap(); - let killed = self.killed.clone(); - let is_timeout = self.is_timeout.clone(); + let tid = &self.task_id; + let timeout = &self.timeout; + info!("task `{tid}` timeout, timeout value: {timeout}, pid: {pid}"); - info!("process `{}` timeout, timeout value: {}", pid, self.timeout); - let ret = killed.compare_exchange(false, true, SeqCst, SeqCst); + let ret = self.killed.compare_exchange(false, true, SeqCst, SeqCst); if ret.is_err() { - return info!("pid `{}` already killed", pid); + return info!("task `{}` already killed, pid: {}", tid, pid); } - is_timeout.store(true, SeqCst); + self.is_timeout.store(true, SeqCst); kill_process_group(pid); - info!("pid `{}` killed because of timeout", pid); + info!("task `{}` killed because of timeout, pid: {}", tid, pid); } pub async fn read_output(&self, mut reader: T, mut log_file: File) @@ -322,8 +323,8 @@ impl BaseCommand { let output = &decode_output(buf); self.append_output(output); if need_cos { - if let Err(e) = log_file.write(output) { - error!("write output file failed: {:?}", e) + if let Err(e) = log_file.write(output).await { + error!("write output file failed: {}", e) } } } @@ -335,14 +336,14 @@ impl BaseCommand { } if need_cos { - let invocation_task_id = self.task_id.clone(); - self.upload_log_cos(invocation_task_id).await; + self.upload_log_cos(&self.task_id).await; } } pub async fn process_finish(&self, child: &mut Child) { let pid = child.id().unwrap(); - info!("=>process `{}` finish", pid); + let tid = &self.task_id; + info!("=>task `{}` finish, pid: {}", tid, pid); let status = child .wait() .await @@ -351,7 +352,7 @@ impl BaseCommand { match status.code() { Some(code) => exit_code.replace(code), None => { - info!("Process terminated by signal: {}", pid); + info!("task `{}` terminated by signal, pid: {}", tid, pid); exit_code.replace(-1) } }; @@ -360,44 +361,41 @@ impl BaseCommand { self.finish_time.store(now, SeqCst); } - pub fn cancel(&self) -> Result<(), String> { - let pid = *self.pid.lock().unwrap(); - match pid { - Some(pid) => { - let ret = self.killed.compare_exchange(false, true, SeqCst, SeqCst); - if ret.is_err() { - info!("pid `{}` already killed, ignore cancel request", pid); - } else { - kill_process_group(pid); - info!("pid `{}` killed because of cancel", pid); - } - Ok(()) + pub fn cancel(&self) -> Result<()> { + let tid = &self.task_id; + let pid = self + .pid + .lock() + .unwrap() + .context(format!("task `{tid}` not running, no pid to kill"))?; + + match self.killed.compare_exchange(false, true, SeqCst, SeqCst) { + Ok(_) => { + kill_process_group(pid); + info!("task `{}` killed because of cancel, pid: {}", tid, pid); } - None => Err("Process not running, no pid to kill".to_string()), + Err(_) => info!("task `{}` already killed, ignore cancel, pid: {}", tid, pid), } + Ok(()) } - pub fn store_path_check(&self) -> Result<(), String> { + pub fn store_path_check(&self) -> Result<()> { if self.cmd_path.is_empty() { - let ret = format!("start failed because script file store failed."); *self.err_info.lock().unwrap() = format!("ScriptStoreFailed: script file store failed, please check disk space or permission"); - return Err(ret); + return Err(anyhow!("start failed because script file store failed.")); } Ok(()) } - pub fn open_log_file(&self) -> Result { + pub async fn open_log_file(&self) -> Result { let parent = Path::new(&self.log_file_path).parent(); match parent { - Some(parent) => create_dir_all(parent).map_err(|e| { - format!( - "failed to open task log file `{}`, create parent dir `{}` failed: {:?}", - self.log_file_path, - parent.display(), - e - ) - })?, + Some(parent) => create_dir_all(parent).await.context(format!( + "failed to open task log file `{}`, create parent dir `{}` failed", + self.log_file_path, + parent.display(), + ))?, None => warn!("parent dir `{}` not found, skip.", self.log_file_path), } @@ -405,26 +403,28 @@ impl BaseCommand { .create(true) .write(true) .open(&self.log_file_path) - .map_err(|e| { - format!( - "failed to open task log file `{}`: {:?}", - self.log_file_path, e - ) - }) + .await + .context(format!( + "failed to open task log file `{}`", + self.log_file_path + )) } - pub async fn upload_log_cos(&self, task_id: String) { + pub async fn upload_log_cos(&self, task_id: &str) { if !self.cos_bucket.is_empty() { - let metadata = MetadataAPIAdapter::build(get_meta_url().as_str()); - let metadata_credential = metadata.tmp_credential().await; - let cos_credential = InvokeAPIAdapter::new().get_cos_credential(task_id).await; + let metadata = MetadataAdapter::build(&get_meta_url()); + let metadata_credential = metadata + .tmp_credential() + .await + .context("Get CAM role of instance failed"); + let cos_credential = InvokeAdapter::new().get_cos_credential(task_id).await; match metadata_credential.or(cos_credential) { Ok(credential) => { - let cli = COS::new( - credential.secret_id, - credential.secret_key, - credential.token, - self.cos_bucket.to_string(), + let cli = COSAdapter::new( + &credential.secret_id, + &credential.secret_key, + &credential.token, + &self.cos_bucket, ); let instance_id = metadata.instance_id().await; let invocation_id = credential.invocation_id; @@ -435,7 +435,7 @@ impl BaseCommand { .put_object_from_file(&self.log_file_path, &object_name, None) .await { - error!("pub object to cos failed: {:?}", e); + error!("pub object to cos failed: {}", e); *self.output_err_info.lock().unwrap() = format!( "Upload output file to cos failed, \ please check if {} has permission to put file to COS: \ @@ -446,22 +446,21 @@ impl BaseCommand { *self.output_url.lock().unwrap() = self.set_output_url(&invocation_id); } - Err(err) => *self.output_err_info.lock().unwrap() = err.message.to_string(), + Err(err) => *self.output_err_info.lock().unwrap() = err.to_string(), } } // delete task output file. if let Err(e) = std::fs::remove_file(&self.log_file_path) { error!( - "cleanup task output file `{}` failed: {:?}", + "cleanup task output file `{}` failed: {}", self.log_file_path, e ) } } pub fn set_output_url(&self, invocation_id: &str) -> String { - let output_err_info = self.output_err_info.lock().expect("lock failed"); - if !output_err_info.is_empty() { + if !self.output_err_info.lock().expect("lock failed").is_empty() { return "".to_string(); } @@ -493,13 +492,9 @@ impl BaseCommand { } #[cfg(test)] -impl Debug for BaseCommand { +impl Debug for Cmd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let output_clone; - { - let output = self.output.lock().expect("lock failed"); - output_clone = output.clone(); - } + let output_clone = self.output.lock().expect("lock failed").clone(); let output_debug = String::from_utf8_lossy(output_clone.as_slice()); let may_contain_binary = String::from_utf8(output_clone.clone()).is_err(); @@ -624,7 +619,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); info!("cmd running, pid: {}", cmd.pid()); @@ -649,7 +644,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; info!("cmd run ret:[{}]", ret.unwrap_err()); assert_eq!(cmd.pid(), 0); @@ -674,7 +669,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; info!("cmd run ret:[{}]", ret.unwrap_err()); assert_eq!(cmd.pid(), 0); @@ -769,7 +764,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); info!("{} running, pid:{}", filename, cmd.pid()); @@ -823,7 +818,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); info!("{} running, pid:{}", filename, cmd.pid()); @@ -890,7 +885,7 @@ mod tests { } else if #[cfg(windows)] { let filename = format!("./{}.ps1", gen_rand_str()); create_file( - format!("foreach ($i in 1..{}) {{ Write-Host 'y' -NoNewLine }};", OUTPUT_BYTE_LIMIT_EACH_REPORT + 1).as_str(), + format!("[Console]::Out.Write('A' * {})", OUTPUT_BYTE_LIMIT_EACH_REPORT + 1).as_str(), filename.as_str(), ); } @@ -908,7 +903,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); @@ -950,7 +945,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); info!("{} running, pid:{}", filename, cmd.pid()); @@ -960,6 +955,7 @@ mod tests { } let (out, idx, dropped) = cmd.next_output(); + info!("{out:?}"); let out = STANDARD.encode(out); assert_eq!(dropped, 0); @@ -1003,7 +999,7 @@ mod tests { "", "", ); - let mut cmd = ret.unwrap(); + let cmd = ret.unwrap(); let ret = cmd.run().await; assert!(ret.is_ok()); let instant = Instant::now(); diff --git a/src/executor/store.rs b/src/executor/store.rs index 98c1dba..9314d31 100644 --- a/src/executor/store.rs +++ b/src/executor/store.rs @@ -4,6 +4,7 @@ use std::fs::{create_dir_all, remove_file, File}; use std::io::prelude::*; use std::path::{Path, PathBuf}; +use anyhow::{anyhow, Context, Result}; use chrono::Local; use log::info; @@ -38,8 +39,8 @@ impl TaskFileStore { self.log_path.clone() } - fn get_suffix(&self, command_type: &String) -> &str { - return match command_type.as_str() { + fn get_suffix(&self, command_type: &str) -> &str { + return match command_type { CMD_TYPE_SHELL => SUFFIX_SHELL, CMD_TYPE_BAT => SUFFIX_BAT, CMD_TYPE_POWERSHELL => SUFFIX_PS1, @@ -76,32 +77,29 @@ impl TaskFileStore { path: &str, ignore_exists: bool, #[cfg(unix)] executable: bool, - ) -> Result { + ) -> Result { let file_path = Path::new(path); if file_path.exists() { if !ignore_exists { - return Err(format!("file `{}` already exists", path)); - } else if let Err(e) = remove_file(path) { - info!("failed to remove exist file `{}`: {}", path, e); - return Err(format!("failed to remove exist file `{}`: {}", path, e)); + return Err(anyhow!("file `{}` already exists", path)); } + remove_file(path) + .inspect_err(|e| info!("failed to remove exist file `{}`: {}", path, e))? } let dir = Path::parent(file_path) - .ok_or(format!("cannot find parent directory for `{file_path:?}`"))?; + .context(format!("cannot find parent directory for `{file_path:?}`"))?; let ret = File::create(path).or_else(|why| { info!("couldn't create file: {why}, try to create directory `{dir:?}`"); - create_dir_all(dir).map_err(|why| format!("couldn't create directory: {why}"))?; - Ok(File::create(path).map_err(|why| format!("couldn't create file: {why}"))?) + create_dir_all(dir).context("couldn't create directory")?; + Ok(File::create(path).context("couldn't create file")?) }); #[cfg(unix)] if executable { // set permissions for path recursively, to make task-xxx.sh available for non-root user. - if let Err(e) = self.set_permissions_recursively(path.as_ref()) { - info!("failed to chmod path `{}` recursively: {}", path, e); - return Err(format!("failed to chmod path `{path}` recursively: {e}")); - }; + self.set_permissions_recursively(path.as_ref()) + .inspect_err(|e| info!("failed to chmod path `{}` recursively: {}", path, e))? } ret @@ -114,18 +112,14 @@ impl TaskFileStore { use std::os::unix::fs::PermissionsExt; while path.to_str() != Some("/tmp") { - match set_permissions(path, Permissions::from_mode(FILE_EXECUTE_PERMISSION_MODE)) { - Err(e) => { - info!("failed to chmod path `{:?}`: {}", path, e); - return Err(e); - } - _ => path = path.parent().unwrap(), - }; + set_permissions(path, Permissions::from_mode(FILE_EXECUTE_PERMISSION_MODE)) + .inspect_err(|e| info!("failed to chmod path `{:?}`: {}", path, e))?; + path = path.parent().unwrap(); } Ok(()) } - pub fn store(&self, t: &InvocationNormalTask) -> Result<(String, String), String> { + pub fn store(&self, t: &InvocationNormalTask) -> Result<(String, String)> { let task_file_path = self.gen_task_file_path(t).display().to_string(); info!("save task {} to {}", &t.invocation_task_id, task_file_path); @@ -143,10 +137,8 @@ impl TaskFileStore { true, )?; let s = t.decode_command()?; - let res = file.write_all(&s); - if res.is_err() { - return Err("failed to store command in task file".to_string()); - } + file.write_all(&s) + .context("failed to store command in task file")?; Ok((task_file_path, task_log_path)) } @@ -178,7 +170,7 @@ mod tests { let workdir = format!("C:\\Program Files\\qcloud\\tat_agent"); let task = InvocationNormalTask { invocation_task_id: "100001".to_string(), - command_type: format!("SHELL"), + command_type: format!("POWERSHELL"), time_out: 30, command: format!("bHMgLWw="), username: format!("root"), @@ -218,7 +210,7 @@ mod tests { contents = Vec::from(&contents[3..]); } let command = String::from_utf8_lossy(contents.as_slice()); - assert_eq!(command, "ls -l"); + assert!(command.ends_with("ls -l")); store.remove(&task_file); let paths = read_dir(Path::new(&task_file).parent().unwrap()).unwrap(); for f in paths { diff --git a/src/executor/thread.rs b/src/executor/thread.rs index 7e276d4..c71478b 100644 --- a/src/executor/thread.rs +++ b/src/executor/thread.rs @@ -1,10 +1,10 @@ use crate::common::evbus::EventBus; use crate::common::utils::{cbs_exist, get_now_secs}; -use crate::executor::proc::{self, MyCommand}; +use crate::executor::proc::{self, Cmd}; use crate::executor::store::TaskFileStore; use crate::network::types::ws_msg::WS_MSG_TYPE_KICK; use crate::network::types::{InvocationCancelTask, InvocationNormalTask}; -use crate::network::InvokeAPIAdapter; +use crate::network::InvokeAdapter; use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; @@ -25,33 +25,29 @@ pub fn run(dispatcher: &Arc, running_task_num: &Arc) { let running_tasks = Arc::new(Mutex::new(HashMap::new())); dispatcher.register(WS_MSG_TYPE_KICK, move |source| { - let source = String::from_utf8_lossy(&source).to_string(); //from vec to string + let source = String::from_utf8_lossy(&source).to_string(); let running_task_num = running_task_num.clone(); let running_tasks = running_tasks.clone(); runtime.spawn(async move { - let adapter = InvokeAPIAdapter::new(); - let worker = Arc::new(HttpWorker::new( - adapter, - running_task_num.clone(), - running_tasks, - )); - worker.process(source).await + let adapter = InvokeAdapter::new(); + let worker = HttpWorker::new(adapter, running_task_num, running_tasks); + worker.process(&source).await }); }); } pub struct HttpWorker { - adapter: InvokeAPIAdapter, + adapter: InvokeAdapter, task_store: TaskFileStore, - running_tasks: Arc>>>>>, + running_tasks: Arc>>>, running_task_num: Arc, } impl HttpWorker { pub fn new( - adapter: InvokeAPIAdapter, + adapter: InvokeAdapter, running_task_num: Arc, - running_tasks: Arc>>>>>, + running_tasks: Arc>>>, ) -> Self { let task_store = TaskFileStore::new(); info!( @@ -66,12 +62,12 @@ impl HttpWorker { } } - pub async fn process(&self, source: String) { + pub async fn process(&self, source: &str) { info!("http thread processing message from: {}", source); for _ in 0..3 { let resp = match self.adapter.describe_tasks().await { Ok(resp) => resp, - Err(why) => return error!("describe task failed: {:?}", why), + Err(why) => return error!("describe task failed: {}", why), }; info!("describe task success: {:?}", resp); @@ -95,15 +91,11 @@ impl HttpWorker { } } - async fn read_and_report( - &self, - cmd_arc: Arc>>, - task_id: &str, - ) -> u32 { + async fn read_and_report(&self, cmd: Arc, task_id: &str) -> u32 { let mut stop_upload = false; let mut final_log_index: u32 = 0; let mut first_dropped: u64 = 0; - let mut finished = cmd_arc.lock().await.is_finished(); + let mut finished = cmd.is_finished(); loop { // total sleep max 20 * 50 ms, i.e. 1s for _ in 0..20 { @@ -111,15 +103,14 @@ impl HttpWorker { break; } sleep(Duration::from_millis(50)).await; - finished = cmd_arc.lock().await.is_finished(); + finished = cmd.is_finished(); } - let cmd = cmd_arc.lock().await; if cmd.cur_output_len() != 0 && !stop_upload { let (out, idx, dropped) = cmd.next_output(); final_log_index = idx; // print output in one line info!( - "ready to report output length:{:?}, idx:{}, dropped:{}, output_debug:{}", + "ready to report output length:{}, idx:{}, dropped:{}, output_debug:{}", out.len(), idx, dropped, @@ -182,18 +173,15 @@ impl HttpWorker { ) { info!("task execute begin: {:?}", task); let task_id = task.invocation_task_id.clone(); - let result = self.create_proc(task_file, task_log_file, task).await; - if result.is_none() { + let Some(cmd) = self.create_proc(task_file, task_log_file, task).await else { return; - } - let cmd_arc = result.unwrap(); + }; let mut final_log_index = 0; - if cmd_arc.lock().await.is_started() { - final_log_index = self.read_and_report(cmd_arc.clone(), &task_id).await; + if cmd.is_started() { + final_log_index = self.read_and_report(cmd.clone(), &task_id).await; } - let cmd = cmd_arc.lock().await; // report finish let finish_result = cmd.finish_result(); let err_info = cmd.err_info(); @@ -228,8 +216,8 @@ impl HttpWorker { &output_err_info, ) .await - .map(|_| info!("task_execute report_task_finish {} success", task_id)) - .map_err(|e| error!("report task {task_id} finish error: {e:?}")); + .inspect(|_| info!("task_execute report_task_finish {} success", task_id)) + .inspect_err(|e| error!("report task {task_id} finish error: {e}")); // process finish, remove self.running_tasks.lock().await.remove(task_id.as_str()); @@ -240,25 +228,22 @@ impl HttpWorker { let cancel_task_id = task.invocation_task_id.clone(); //mutex with create_proc let tasks = self.running_tasks.lock().await; - let task = tasks.get(cancel_task_id.as_str()); + let task = tasks.get(&cancel_task_id); if let Some(cmd_arc) = task { let cmd_arc = cmd_arc.clone(); //drop lock std::mem::drop(tasks); - let _ = cmd_arc - .lock() - .await - .cancel() - .map(|_| info!("cancel task {} success", &cancel_task_id)) - .map_err(|e| error!("task {} cancel failed, error: {}", &cancel_task_id, e)); - return; - } else { - info!("task {cancel_task_id} not found, may be not start or finished",); + return match cmd_arc.cancel() { + Ok(_) => info!("cancel task {} success", &cancel_task_id), + Err(e) => error!("task {} cancel failed, error: {}", &cancel_task_id, e), + }; } + info!("task {cancel_task_id} not found, may be not start or finished"); // report terminated let finish_time = get_now_secs(); - self.adapter + let _ = self + .adapter .report_task_finish( &cancel_task_id, FINISH_RESULT_TERMINATED, @@ -270,18 +255,15 @@ impl HttpWorker { "", ) .await - .map(|_| info!("task_cancel report_task_finish {} success", cancel_task_id)) - .map_err(|e| { - error!("report task {} terminate error: {:?}", cancel_task_id, e); - }) - .ok(); + .inspect(|_| info!("task_cancel report_task_finish {} success", cancel_task_id)) + .inspect_err(|e| error!("report task {} terminate error: {}", cancel_task_id, e)); } async fn report_task_start(&self, task_id: &str, timestamp: u64) -> bool { self.adapter .report_task_start(task_id, timestamp) .await - .map_err(|e| error!("report start error: {:?}", e)) + .inspect_err(|e| error!("report start error: {}", e)) .is_ok() } @@ -292,7 +274,7 @@ impl HttpWorker { .await { Ok(_) => info!("success upload task {}, log index: {}", task_id, idx), - Err(e) => error!("failed to upload task {} log: {:?}", task_id, e), + Err(e) => error!("failed to upload task {} log: {}", task_id, e), } } @@ -301,7 +283,7 @@ impl HttpWorker { task_file: &str, task_log_file: &str, task: &InvocationNormalTask, - ) -> Option>>> { + ) -> Option> { let task_id = task.invocation_task_id.clone(); //mutex with task_cancel let mut tasks = self.running_tasks.lock().await; @@ -337,19 +319,16 @@ impl HttpWorker { cos_bucket_prefix, &task_id, ); - if proc_result.is_err() { - return None; - } - let mut proc_res = proc_result.unwrap(); - proc_res - .run() - .await - .map_err(|e| error!("start process failed: {}", e)) - .ok(); - let cmd_arc = Arc::new(Mutex::new(proc_res)); + let cmd = proc_result.ok()?; + let _ = cmd.run().await.inspect_err(|e| { + error!( + "cmd start failed: reason: {}, cmd_path: {}, work_dir: {}, username: {}", + e, cmd.cmd_path, cmd.work_dir, cmd.username + ) + }); - tasks.insert(task_id, cmd_arc.clone()); - return Some(cmd_arc); + tasks.insert(task_id, cmd.clone()); + return Some(cmd); } } @@ -357,21 +336,23 @@ impl HttpWorker { mod tests { use crate::common::logger; use crate::common::utils::{gen_rand_str_with, get_current_username}; - use crate::executor::proc::{self, MyCommand}; + use crate::executor::proc::{self, Cmd}; use crate::executor::store::TaskFileStore; use crate::executor::thread::HttpWorker; use crate::executor::FINISH_RESULT_TERMINATED; use crate::network::types::{ - AgentError, AgentErrorCode, InvocationCancelTask, InvocationNormalTask, - ReportTaskFinishResponse, ReportTaskStartResponse, + InvocationCancelTask, InvocationNormalTask, ReportTaskFinishResponse, + ReportTaskStartResponse, }; - use crate::network::InvokeAPIAdapter; + use crate::network::InvokeAdapter; + use std::fs; use std::fs::File; use std::io::Write; use std::sync::Arc; use std::time::Duration; - use tokio::sync::Mutex; + + use anyhow::anyhow; use tokio::time::timeout; fn gen_rand_str() -> String { @@ -392,7 +373,7 @@ mod tests { fn get_http_worker() -> HttpWorker { HttpWorker { - adapter: InvokeAPIAdapter::faux(), + adapter: InvokeAdapter::faux(), task_store: TaskFileStore::new(), running_tasks: Default::default(), running_task_num: Arc::new(Default::default()), @@ -417,13 +398,12 @@ mod tests { } } - fn fake_command() -> Arc>> { + fn fake_command() -> Arc { #[cfg(unix)] let cmd_type = "SHELL"; #[cfg(windows)] let cmd_type = "POWERSHELL"; - let result = proc::new("", "", cmd_type.as_ref(), "", 10, 1024, "", "", "", ""); - Arc::new(Mutex::new(result.unwrap())) + proc::new("", "", cmd_type.as_ref(), "", 10, 1024, "", "", "", "").unwrap() } #[tokio::test] @@ -457,7 +437,8 @@ mod tests { .insert("invt-1122".to_string(), fake_command()); let task = build_invocation("invt-1111", "", 5, cmd_type.as_ref()); faux::when!(http_worker.adapter.report_task_start) - .then_return(Err(AgentError::new(AgentErrorCode::ResponseReadError, ""))); + .once() + .then_return(Err(anyhow!(""))); let result = http_worker .create_proc("/fake_path", "/fake_path", &task) .await; @@ -483,6 +464,7 @@ mod tests { let mut http_worker = get_http_worker(); let task = build_invocation("invt-1133", "", 5, cmd_type); faux::when!(http_worker.adapter.report_task_start) + .once() .then_return(Ok(ReportTaskStartResponse {})); let result = http_worker @@ -511,8 +493,8 @@ mod tests { let cmd_type = "POWERSHELL"; let task = build_invocation("invt-1133", "", 5, cmd_type); let create_fut = http_worker.create_proc("", "/fake_path", &task); - let time_out = timeout(Duration::from_secs(1), create_fut).await; - assert_eq!(time_out.is_err(), true); + let timeout = timeout(Duration::from_secs(1), create_fut).await; + assert_eq!(timeout.is_err(), true); } #[tokio::test] @@ -523,8 +505,8 @@ mod tests { invocation_task_id: "inv-xxxx".to_string(), }; let create_fut = http_worker.task_cancel(&task); - let time_out = timeout(Duration::from_secs(1), create_fut).await; - assert_eq!(time_out.is_err(), true); + let timeout = timeout(Duration::from_secs(1), create_fut).await; + assert_eq!(timeout.is_err(), true); } #[tokio::test] @@ -547,9 +529,11 @@ mod tests { let mut http_worker = get_http_worker(); let task = build_invocation("invt-test_cancel", "", 1025, cmd_type); faux::when!(http_worker.adapter.report_task_start) + .once() .then_return(Ok(ReportTaskStartResponse {})); faux::when!(http_worker.adapter.report_task_finish) + .once() .then_return(Ok(ReportTaskFinishResponse {})); let log_path = format!("./{}.log", gen_rand_str()); @@ -557,7 +541,7 @@ mod tests { .create_proc(filename.as_str(), log_path.as_str(), &task) .await .unwrap(); - assert_eq!(cmd.lock().await.is_started(), true); + assert_eq!(cmd.is_started(), true); let http_worker1 = Arc::new(http_worker); let http_worker2 = http_worker1.clone(); let cmd_clone = cmd.clone(); @@ -573,7 +557,7 @@ mod tests { http_worker2.task_cancel(&task).await; tokio::time::sleep(Duration::from_secs(1)).await; fs::remove_file(filename.as_str()).unwrap(); - let finis_result = cmd.lock().await.finish_result(); + let finis_result = cmd.finish_result(); assert_eq!(finis_result, FINISH_RESULT_TERMINATED); //need read twice } } diff --git a/src/executor/unix.rs b/src/executor/unix.rs index d2db926..9e8a1c0 100644 --- a/src/executor/unix.rs +++ b/src/executor/unix.rs @@ -1,77 +1,35 @@ -use crate::executor::proc::{BaseCommand, MyCommand}; +use crate::executor::proc::Cmd; use std::collections::HashMap; use std::fs::{read_to_string, remove_file}; -use std::ops::Deref; use std::path::Path; use std::process::Stdio; use std::sync::Arc; use std::{env, io}; -use async_trait::async_trait; +use anyhow::{anyhow, Context, Result}; use libc::{self, SIGKILL}; use log::warn; use tokio::process::{Child, Command}; use users::os::unix::UserExt; use users::{get_user_by_name, User}; -pub struct UnixCommand { - base: Arc, -} - -impl UnixCommand { - pub fn new( - cmd_path: &str, - username: &str, - work_dir: &str, - timeout: u64, - bytes_max_report: u64, - log_file_path: &str, - cos_bucket: &str, - cos_prefix: &str, - task_id: &str, - ) -> UnixCommand { - UnixCommand { - base: Arc::new(BaseCommand::new( - cmd_path, - username, - work_dir, - timeout, - bytes_max_report, - log_file_path, - cos_bucket, - cos_prefix, - task_id, - )), - } - } - - fn user_check(&self) -> Result { - let user = get_user_by_name(self.username.as_str()); - match user { - Some(user) => Ok(user), - None => { - let ret = format!( - "UnixCommand {} start failed, working_directory: {}, username: {}, user not exists", - self.cmd_path, self.work_dir, self.username - ); +impl Cmd { + fn user_check(&self) -> Result { + get_user_by_name(&self.username) + .context("user not exists") + .inspect_err(|_| { *self.err_info.lock().unwrap() = - format!("UserNotExists: user `{}` not exists", self.username); - Err(ret) - } - } + format!("UserNotExists: user `{}` not exists", self.username) + }) } - fn work_dir_check(&self) -> Result<(), String> { - if !working_directory_exists(self.work_dir.as_str()) { - let ret = format!( - "UnixCommand {} start failed, working_directory: {}, username: {}, working directory not exists", - self.cmd_path, self.work_dir, self.username - ); + fn work_dir_check(&self) -> Result<()> { + if !self.working_directory_exists() { *self.err_info.lock().unwrap() = format!( "DirectoryNotExists: working_directory `{}` not exists", self.work_dir ); - return Err(ret); + return Err(anyhow!("working directory not exists")); } Ok(()) } @@ -81,34 +39,26 @@ impl UnixCommand { prepare_cmd(cmd, &user, &self.work_dir) } - fn spawn_cmd(&self, user: User) -> Result { - let child = self.prepare_cmd(user).spawn().map_err(|e| { + fn spawn_cmd(&self, user: User) -> Result { + let child = self.prepare_cmd(user).spawn().inspect_err(|e| { *self.err_info.lock().unwrap() = e.to_string(); // remove log_file when process run failed. - if let Err(e) = remove_file(self.log_file_path.as_str()) { - warn!("remove log file failed: {:?}", e) - } - format!( - "UnixCommand {}, working_directory: {}, start failed: {}", - self.cmd_path, self.work_dir, e - ) + let _ = remove_file(self.log_file_path.as_str()) + .inspect_err(|e| warn!("remove log file failed: {}", e)); })?; *self.pid.lock().unwrap() = Some(child.id().unwrap()); Ok(child) } -} -#[async_trait] -impl MyCommand for UnixCommand { - async fn run(&mut self) -> Result<(), String> { + pub async fn run(self: &Arc) -> Result<()> { // pre check before spawn cmd self.store_path_check()?; self.work_dir_check()?; let user = self.user_check()?; - let log_file = self.open_log_file()?; + let log_file = self.open_log_file().await?; let mut child = self.spawn_cmd(user)?; - let base = self.base.clone(); + let base = self.clone(); // async read output. tokio::spawn(async move { let reader = child.stdout.take().unwrap(); @@ -117,20 +67,9 @@ impl MyCommand for UnixCommand { }); Ok(()) } -} - -#[cfg(test)] -impl std::fmt::Debug for UnixCommand { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.base.fmt(f) - } -} -impl Deref for UnixCommand { - type Target = BaseCommand; - - fn deref(&self) -> &Self::Target { - &self.base + fn working_directory_exists(&self) -> bool { + Path::new(&self.work_dir).exists() } } @@ -174,10 +113,6 @@ pub fn kill_process_group(pid: u32) { } } -fn working_directory_exists(path: &str) -> bool { - Path::new(path).exists() -} - fn redirect_stderr_to_stdout() -> Result<(), io::Error> { if unsafe { libc::dup2(1, 2) } != -1 { Ok(()) @@ -195,18 +130,15 @@ fn own_process_group() -> Result<(), io::Error> { } pub fn cmd_path(cmd: &str) -> Option { - if let Ok(path) = env::var("PATH") { - for p in path.split(":") { - let p_str = format!("{}/{}", p, cmd); - if Path::new(&p_str).exists() { - return Some(p_str); - } - } - } - None + let Ok(path) = env::var("PATH") else { + return None; + }; + path.split(":") + .map(|p| format!("{}/{}", p, cmd)) + .find(|p| Path::new(p).exists()) } -fn load_envs(content: String) -> HashMap { +fn load_envs(content: &str) -> HashMap { content .lines() .map(|l| l.trim_start()) @@ -232,7 +164,7 @@ pub fn build_envs(username: &str, home_path: &str, shell_path: &str) -> HashMap< ("MAIL", &format!("/var/spool/mail/{username}")), ("TERM", "xterm-color"), ]; - let etc_envs = load_envs(read_to_string("/etc/environment").unwrap_or("".to_owned())); + let etc_envs = load_envs(read_to_string("/etc/environment").as_deref().unwrap_or("")); envs.iter() .map(|&(k, v)| (k.to_owned(), v.to_owned())) .chain(etc_envs) @@ -259,19 +191,14 @@ mod tests { #[test] fn test_fmt_cmd() { - let cmd = UnixCommand::new("./a.sh", "root", "./", 60, 10240, "", "", "", ""); + let cmd = Cmd::new("./a.sh", "root", "./", 60, 10240, "", "", "", ""); println!("fmt cmd:{:?}", cmd); } - #[test] - fn test_working_directory_exists() { - assert_eq!(working_directory_exists("/etc"), true); - } - #[test] fn test_load_envs() { let content = "# \n B=b\n D=d=d\n C= \"x\n"; - let envs = load_envs(content.to_string()); + let envs = load_envs(content); assert!(envs.keys().len() == 3); assert!(envs.get("B").unwrap() == "b"); assert!(envs.get("D").unwrap() == "d=d"); diff --git a/src/executor/windows.rs b/src/executor/windows.rs index 96fb2b8..c671ad1 100644 --- a/src/executor/windows.rs +++ b/src/executor/windows.rs @@ -1,18 +1,17 @@ use crate::common::utils::{gen_rand_str_with, get_current_username, str2wsz, wsz2string}; use crate::daemonizer::wow64_disable_exc; -use crate::executor::proc::{BaseCommand, MyCommand}; +use crate::executor::proc::Cmd; use std::collections::HashMap; use std::fs::{remove_file, File, OpenOptions}; -use std::ops::Deref; use std::os::windows::prelude::{AsRawHandle, FromRawHandle}; use std::path::Path; use std::process::Stdio; use std::ptr::null_mut; -use std::sync::{Arc, OnceLock}; +use std::sync::{Arc, LazyLock}; use std::{mem, slice}; -use async_trait::async_trait; +use anyhow::{anyhow, Result}; use libc::{c_void, free, malloc, memcpy}; use log::{error, info, warn}; use ntapi::ntpsapi::{ @@ -53,60 +52,19 @@ use winapi::um::winnt::{ PROCESS_TERMINATE, PTOKEN_GROUPS, QUOTA_LIMITS, TOKEN_ALL_ACCESS, TOKEN_SOURCE, }; -pub struct WindowsCommand { - base: Arc, - token: File, -} - -impl WindowsCommand { - pub fn new( - cmd_path: &str, - username: &str, - work_dir: &str, - timeout: u64, - bytes_max_report: u64, - log_file_path: &str, - cos_bucket: &str, - cos_prefix: &str, - task_id: &str, - ) -> WindowsCommand { - let cmd_path = if cmd_path.ends_with(".ps1") { - String::from(cmd_path).replace(" ", "` ") - } else { - cmd_path.to_string() - }; - WindowsCommand { - base: Arc::new(BaseCommand::new( - cmd_path.as_str(), - username, - work_dir, - timeout, - bytes_max_report, - log_file_path, - cos_bucket, - cos_prefix, - task_id, - )), - token: unsafe { File::from_raw_handle(0 as HANDLE) }, - } - } - - fn work_dir_check(&self) -> Result<(), String> { +impl Cmd { + fn work_dir_check(&self) -> Result<()> { if !wow64_disable_exc(|| Path::new(self.work_dir.as_str()).exists()) { - let ret = format!( - "WindowsCommand `{}` start failed, working_directory:{}, username:{}, working directory not exists", - self.cmd_path, self.work_dir, self.username - ); *self.err_info.lock().unwrap() = format!( "DirectoryNotExists: working_directory `{}` not exists", self.work_dir ); - return Err(ret); + return Err(anyhow!("working directory not exists",)); }; Ok(()) } - fn prepare_cmd(&mut self, pipe: File) -> Result { + fn prepare_cmd(&self, pipe: File) -> Result { info!("=>prepare_cmd"); let command = if self.cmd_path.ends_with(".ps1") { info!("execute powershell command {}", self.cmd_path); @@ -116,43 +74,33 @@ impl WindowsCommand { init_bat_cmd(&self.cmd_path) }; - prepare_cmd(command, &self.username, &self.work_dir, pipe).map_err(|e| { - *self.err_info.lock().unwrap() = e.clone(); - e - }) + prepare_cmd(command, &self.username, &self.work_dir, pipe) + .inspect_err(|e| *self.err_info.lock().unwrap() = e.to_string().clone()) } - fn spawn_cmd(&mut self, pipe: File) -> Result { + fn spawn_cmd(&self, pipe: File) -> Result { //spawn suspended process - let child = self.prepare_cmd(pipe)?.spawn().map_err(|e| { + let child = self.prepare_cmd(pipe)?.spawn().inspect_err(|e| { *self.err_info.lock().unwrap() = e.to_string(); // remove log_file when process run failed. - if let Err(e) = remove_file(self.log_file_path.as_str()) { - warn!("remove log file failed: {:?}", e) - } - format!( - "WindowsCommand {}, working_directory:{}, start failed: {}", - self.cmd_path, self.work_dir, e - ) + let _ = remove_file(self.log_file_path.as_str()) + .inspect_err(|e| warn!("remove log file failed: {}", e)); })?; let pid = child.id().unwrap(); *self.pid.lock().unwrap() = Some(pid); resume_as_user(pid, &self.username, &self.token); Ok(child) } -} -#[async_trait] -impl MyCommand for WindowsCommand { - async fn run(&mut self) -> Result<(), String> { + pub async fn run(self: &Arc) -> Result<()> { info!("=>WindowsCommand::run()"); self.store_path_check()?; self.work_dir_check()?; let (our_pipe, their_pipe) = anon_pipe(true)?; - let log_file = self.open_log_file()?; + let log_file = self.open_log_file().await?; let mut child = self.spawn_cmd(their_pipe)?; - let base = self.base.clone(); + let base = self.clone(); // async read output. info!("=>WindowsCommand::tokio::spawn"); @@ -165,21 +113,6 @@ impl MyCommand for WindowsCommand { } } -#[cfg(test)] -impl std::fmt::Debug for WindowsCommand { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.base.fmt(f) - } -} - -impl Deref for WindowsCommand { - type Target = BaseCommand; - - fn deref(&self) -> &Self::Target { - &self.base - } -} - pub fn init_powershell_cmd(script: &str) -> Command { let mut cmd = Command::new("powershell"); cmd.args(&[ @@ -202,15 +135,13 @@ pub fn prepare_cmd( username: &str, work_dir: &str, pipe: File, -) -> Result { - let std_out = pipe.try_clone().map_err(|e| { - error!("prepare_cmd, clone pipe std_out failed: {}", e); - e.to_string() - })?; - let std_err = pipe.try_clone().map_err(|e| { - error!("prepare_cmd, clone pipe std_err failed: {}", e); - e.to_string() - })?; +) -> Result { + let std_out = pipe + .try_clone() + .inspect_err(|e| error!("prepare_cmd, clone pipe std_out failed: {}", e))?; + let std_err = pipe + .try_clone() + .inspect_err(|e| error!("prepare_cmd, clone pipe std_err failed: {}", e))?; cmd.stdin(Stdio::null()) .stdout(std_out) .stderr(std_err) @@ -295,7 +226,7 @@ pub fn kill_process_group(pid: u32) { } } -pub fn anon_pipe(ours_readable: bool) -> Result<(File, File), String> { +pub fn anon_pipe(ours_readable: bool) -> Result<(File, File)> { unsafe { let mut tries = 0; let mut name; @@ -335,7 +266,7 @@ pub fn anon_pipe(ours_readable: bool) -> Result<(File, File), String> { } } error!("create namepipe failed: {}", err); - return Err(format!("create namepipe failed: {}", err)); + return Err(anyhow!("create namepipe failed: {}", err)); } ours = File::from_raw_handle(handle); break; @@ -345,7 +276,7 @@ pub fn anon_pipe(ours_readable: bool) -> Result<(File, File), String> { opts.write(ours_readable); opts.read(!ours_readable); - let theirs = opts.open(Path::new(&name)).map_err(|e| e.to_string())?; + let theirs = opts.open(Path::new(&name))?; Ok((ours, theirs)) } } @@ -355,7 +286,12 @@ pub fn load_environment(token: HANDLE) -> HashMap { let mut envs = HashMap::new(); let mut environment: PVOID = null_mut(); if 0 != CreateEnvironmentBlock(&mut environment as *mut LPVOID, token, FALSE) { - let data = slice::from_raw_parts(environment as *const u16, usize::MAX); + // The total size len * mem::size_of::() of the slice must be no larger than isize::MAX + // See doc: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + let data = slice::from_raw_parts( + environment as *const u16, + isize::MAX as usize / mem::size_of::(), + ); let mut start = 0; loop { let item = wsz2string(data[start..].as_ptr()); @@ -374,7 +310,7 @@ pub fn load_environment(token: HANDLE) -> HashMap { } } -fn create_user_token(user_name: &str) -> Result { +fn create_user_token(user_name: &str) -> Result { info!("=>enter create_user_token"); unsafe { let mut tat_name = "tat".to_string(); @@ -388,7 +324,7 @@ fn create_user_token(user_name: &str) -> Result { let mut mode: LSA_OPERATIONAL_MODE = mem::zeroed(); let code = LsaRegisterLogonProcess(&mut tat_lsa as PLSA_STRING, &mut lsa_handle, &mut mode); if code != 0 { - return Err(format!("RegisterLogonProcess Failed: {}", code)); + return Err(anyhow!("RegisterLogonProcess Failed: {}", code)); } let mut pkg_name = "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0".to_string(); @@ -479,7 +415,7 @@ fn create_user_token(user_name: &str) -> Result { LsaFreeReturnBuffer(profile); } if status != 0 { - return Err(format!("LsaLogonUser Failed, {}", status)); + return Err(anyhow!("LsaLogonUser Failed, {}", status)); } let _token = File::from_raw_handle(token); @@ -495,14 +431,13 @@ fn create_user_token(user_name: &str) -> Result { return if primary_token != null_mut() { Ok(File::from_raw_handle(primary_token)) } else { - Err(format!("DuplicateTokenEx Failed, {}", GetLastError())) + Err(anyhow!("DuplicateTokenEx Failed, {}", GetLastError())) }; } } -pub fn get_user_token(user_name: &str) -> Result { - static IS_2008: OnceLock = OnceLock::new(); - let is_2008 = IS_2008.get_or_init(|| { +pub fn get_user_token(user_name: &str) -> Result { + static IS_2008: LazyLock = LazyLock::new(|| { let output = std::process::Command::new("wmic") .args(&["os", "get", "Caption"]) .stdout(Stdio::piped()) @@ -512,19 +447,18 @@ pub fn get_user_token(user_name: &str) -> Result { .escape_debug() .to_string(); info!("OS version: {}", version); - let result = version.contains("2008"); - result + version.contains("2008") }); - if get_current_username().eq_ignore_ascii_case(user_name) || *is_2008 { + if get_current_username().eq_ignore_ascii_case(user_name) || *IS_2008 { info!( "use current token, user:{}, is_2008:{}", - user_name, *is_2008 + user_name, *IS_2008 ); let mut token: HANDLE = 0 as HANDLE; unsafe { if 0 == OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &mut token) { - return Err(format!("OpenProcessToken Failed: {}", GetLastError())); + return Err(anyhow!("OpenProcessToken Failed: {}", GetLastError())); } return Ok(File::from_raw_handle(token)); } @@ -533,11 +467,11 @@ pub fn get_user_token(user_name: &str) -> Result { } pub fn decode_output(v: &[u8]) -> Vec { - static CODEPAGE: OnceLock = OnceLock::new(); - let codepage = *CODEPAGE.get_or_init(|| unsafe { GetOEMCP() } as u16); + static CODEPAGE: LazyLock = LazyLock::new(|| unsafe { GetOEMCP() } as u16); + match std::str::from_utf8(&v) { Ok(output) => output.into(), - Err(_) => codepage_strings::Coding::new(codepage) + Err(_) => codepage_strings::Coding::new(*CODEPAGE) .expect("create decoder failed") .decode(&v) .expect("output_string decode failed"), diff --git a/src/network/cos/client.rs b/src/network/cos/client.rs deleted file mode 100644 index ccdab49..0000000 --- a/src/network/cos/client.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::borrow::Cow; -use std::str; - -use chrono::prelude::*; -use reqwest::Client; -use url::Url; - -#[derive(Clone, Debug)] -pub struct COS<'a> { - secret_id: Cow<'a, str>, - secret_key: Cow<'a, str>, - token: Cow<'a, str>, - endpoint: Cow<'a, str>, - host: Cow<'a, str>, - pub client: Client, -} - -impl<'a> COS<'a> { - pub fn new(secret_id: S, secret_key: S, token: S, endpoint: S) -> Self - where - S: Into>, - { - let endpoint = endpoint.into().to_string(); - let host = Url::parse(&*endpoint.clone()).unwrap(); - let host = host.host().unwrap().to_string(); - COS { - secret_id: secret_id.into(), - secret_key: secret_key.into(), - token: token.into(), - endpoint: Cow::from(endpoint), - host: Cow::from(host), - client: Client::new(), - } - } - - pub fn endpoint(&self) -> &str { - &self.endpoint - } - - pub fn host(&self) -> &str { - &self.host - } - - pub fn secret_id(&self) -> &str { - &self.secret_id - } - - pub fn secret_key(&self) -> &str { - &self.secret_key - } - - pub fn token(&self) -> &str { - &self.token - } - - pub fn date(&self) -> String { - let now: DateTime = Utc::now(); - now.format("%a, %d %b %Y %T GMT").to_string() - } -} diff --git a/src/network/cos/errors.rs b/src/network/cos/errors.rs deleted file mode 100644 index 0dbae3f..0000000 --- a/src/network/cos/errors.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::io::Error as IoError; -use std::string::FromUtf8Error; - -use reqwest::header::InvalidHeaderName as HttpInvalidHeaderNameError; -use reqwest::header::InvalidHeaderValue as HttpInvalidHeaderValueError; -use reqwest::Error as ReqwestError; - -#[derive(Debug)] -pub enum Error { - Object(ObjectError), - Io(IoError), - String(FromUtf8Error), - Reqwest(ReqwestError), - Http(HttpError), -} - -#[derive(Debug)] -pub enum HttpError { - HttpInvalidHeaderValue(HttpInvalidHeaderValueError), - HttpInvalidHeaderName(HttpInvalidHeaderNameError), -} - -impl From for Error { - fn from(e: IoError) -> Error { - Error::Io(e) - } -} - -impl From for Error { - fn from(e: ReqwestError) -> Error { - Error::Reqwest(e) - } -} - -impl From for Error { - fn from(e: HttpInvalidHeaderValueError) -> Error { - Error::Http(HttpError::HttpInvalidHeaderValue(e)) - } -} - -impl From for Error { - fn from(e: HttpInvalidHeaderNameError) -> Error { - Error::Http(HttpError::HttpInvalidHeaderName(e)) - } -} - -impl From for Error { - fn from(e: FromUtf8Error) -> Error { - Error::String(e) - } -} - -#[derive(Debug)] -pub enum ObjectError { - PutError { msg: String }, -} diff --git a/src/network/cos/mod.rs b/src/network/cos/mod.rs deleted file mode 100644 index 284b2d9..0000000 --- a/src/network/cos/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod auth; -pub mod client; -pub mod errors; -pub mod object; -pub mod utils; - -pub use client::COS; -pub use object::ObjectAPI; diff --git a/src/network/cos/object.rs b/src/network/cos/object.rs deleted file mode 100644 index 5def3bd..0000000 --- a/src/network/cos/object.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::network::cos::auth::cos_sign; -use crate::network::cos::client::COS; -use crate::network::cos::errors::{Error, ObjectError}; -use crate::network::cos::utils::*; -use std::collections::HashMap; - -use async_trait::async_trait; -use log::info; -use reqwest::header::{HeaderMap, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, DATE, HOST}; -use reqwest::Body; -use tokio::fs::File; - -#[async_trait] -pub trait ObjectAPI { - async fn put_object_from_file( - &self, - file: &str, - object_name: &str, - headers: Option>, - ) -> Result<(), Error>; -} - -#[async_trait] -impl<'a> ObjectAPI for COS<'a> { - async fn put_object_from_file( - &self, - file: &str, - object_name: &str, - headers: Option>, - ) -> Result<(), Error> { - let object_name = object_name; - let host = self.host(); - let date = self.date(); - let mut headers = match headers.into() { - Some(h) => to_headers(h)?, - None => HeaderMap::new(), - }; - headers.insert(HOST, host.parse()?); - headers.insert(DATE, date.parse()?); - headers.insert(CONTENT_TYPE, "application/xml".parse()?); - headers.insert( - CONTENT_LENGTH, - File::open(file) - .await? - .metadata() - .await - .unwrap() - .len() - .to_string() - .parse()?, - ); - let authorization = cos_sign( - "PUT", - self.secret_id(), - self.secret_key(), - object_name, - 600, - &headers, - ); - headers.insert(AUTHORIZATION, authorization.parse()?); - headers.insert("x-cos-security-token", self.token().parse()?); - info!("{:?}", authorization); - - let body = Body::wrap_stream(FileStream(File::open(file).await?)); - let resp = self - .client - .put(&format!("{}{}", self.endpoint(), object_name)) - .headers(headers) - .body(body) - .send() - .await?; - - if resp.status().is_success() { - Ok(()) - } else { - Err(Error::Object(ObjectError::PutError { - msg: format!("can not put object, status code {}", resp.status()), - })) - } - } -} diff --git a/src/network/cos/utils.rs b/src/network/cos/utils.rs deleted file mode 100644 index 2fb3551..0000000 --- a/src/network/cos/utils.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::network::cos::errors::Error; -use std::collections::HashMap; -use std::pin::{pin, Pin}; - -use futures::task::{Context, Poll}; -use futures::{io, Future, Stream}; -use reqwest::header::{HeaderMap, HeaderName}; -use tokio::fs::File; -use tokio::io::AsyncReadExt; - -pub fn to_headers>(hashmap: HashMap) -> Result { - let mut headers = HeaderMap::new(); - for (key, val) in hashmap.iter() { - let key = key.as_ref(); - let val = val.as_ref(); - headers.insert(HeaderName::from_bytes(key.as_bytes())?, val.parse()?); - } - Ok(headers) -} - -pub struct FileStream(pub File); - -impl Stream for FileStream { - type Item = io::Result>; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let mut buf = [0u8; 1204]; - let read = pin!(self.0.read(&mut buf)); - match read.poll(cx) { - Poll::Pending => Poll::Pending, - Poll::Ready(Ok(0)) => Poll::Ready(None), - Poll::Ready(Ok(n)) => Poll::Ready(Some(Ok(buf[..n].to_vec()))), - Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))), - } - } -} diff --git a/src/network/cos/auth.rs b/src/network/cos_adapter.rs similarity index 57% rename from src/network/cos/auth.rs rename to src/network/cos_adapter.rs index 6b0bb1a..cda1ab4 100644 --- a/src/network/cos/auth.rs +++ b/src/network/cos_adapter.rs @@ -1,12 +1,89 @@ +use std::collections::HashMap; +use std::convert::TryInto; use std::iter::IntoIterator; +use std::str; -use chrono::Local; +use anyhow::{anyhow, Result}; +use chrono::{Local, Utc}; use hmac::{Hmac, Mac}; +use log::info; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +use reqwest::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, DATE, HOST}; +use reqwest::{Body, Client}; use sha1::{Digest, Sha1}; +use tokio::fs::File; +use url::Url; use urlencoding::encode; -pub fn cos_sign( +pub struct COSAdapter<'a> { + secret_id: &'a str, + secret_key: &'a str, + token: &'a str, + endpoint: &'a str, + host: String, + client: Client, +} + +impl<'a> COSAdapter<'a> { + pub fn new(secret_id: &'a str, secret_key: &'a str, token: &'a str, endpoint: &'a str) -> Self { + let host = Url::parse(&endpoint).unwrap(); + let host = host.host().unwrap().to_string(); + Self { + secret_id, + secret_key, + token, + endpoint, + host, + client: Client::new(), + } + } + + pub async fn put_object_from_file( + &self, + file: &str, + object_name: &str, + headers: Option>, + ) -> Result<()> { + let mut headers: HeaderMap = headers + .and_then(|ref h| h.try_into().ok()) + .unwrap_or_default(); + headers.insert(HOST, self.host.parse()?); + headers.insert(DATE, date().parse()?); + headers.insert(CONTENT_TYPE, "application/xml".parse()?); + headers.insert( + CONTENT_LENGTH, + File::open(file).await?.metadata().await?.len().into(), + ); + let authorization = cos_sign( + "PUT", + &self.secret_id, + &self.secret_key, + object_name, + 600, + &headers, + ); + headers.insert(AUTHORIZATION, authorization.parse()?); + headers.insert("x-cos-security-token", self.token.parse()?); + info!("{}", authorization); + + let body = Body::from(File::open(file).await?); + let resp = self + .client + .put(&format!("{}{}", self.endpoint, object_name)) + .headers(headers) + .body(body) + .send() + .await?; + + if resp.status().is_success() { + Ok(()) + } else { + Err(anyhow!("can not put object, status code {}", resp.status())) + } + } +} + +fn cos_sign( method: &str, secret_id: &str, secret_key: &str, @@ -85,6 +162,10 @@ pub fn cos_sign( format!("q-sign-algorithm=sha1&q-ak={secret_id}&q-sign-time={key_time}&q-key-time={key_time}&q-header-list={header_list}&q-url-param-list={url_param_list}&q-signature={signature}") } +fn date() -> String { + Utc::now().format("%a, %d %b %Y %T GMT").to_string() +} + trait EncodeHex { fn encode_hex(self) -> String; } diff --git a/src/network/invoke_adapter.rs b/src/network/invoke_adapter.rs index b3f1d40..5a1431b 100644 --- a/src/network/invoke_adapter.rs +++ b/src/network/invoke_adapter.rs @@ -3,9 +3,9 @@ use super::urls::{get_invoke_url, get_register_url}; use crate::common::config::RegisterInfo; use crate::common::utils::generate_rsa_key; use crate::network::types::{ - AgentError, AgentErrorCode, AgentRequest, CheckUpdateRequest, CheckUpdateResponse, - DescribeTasksRequest, DescribeTasksResponse, GetCosCredentialRequest, GetTmpCredentialResponse, - HttpMethod, RegisterInstanceRequest, RegisterInstanceResponse, ReportResourceRequest, + AgentRequest, CheckUpdateRequest, CheckUpdateResponse, DescribeTasksRequest, + DescribeTasksResponse, GetCosCredentialRequest, GetTmpCredentialResponse, + RegisterInstanceRequest, RegisterInstanceResponse, ReportResourceRequest, ReportResourceResponse, ReportTaskFinishRequest, ReportTaskFinishResponse, ReportTaskStartRequest, ReportTaskStartResponse, ServerRawResponse, UploadTaskLogRequest, UploadTaskLogResponse, ValidateInstanceRequest, ValidateInstanceResponse, @@ -15,7 +15,8 @@ use crate::sysinfo::{get_hostname, get_local_ip, get_machine_id}; use std::time::Duration; -use log::{error, info}; +use anyhow::{Context, Result}; +use log::info; use reqwest::Response; use serde::{de::DeserializeOwned, Serialize}; use serde_json::from_str; @@ -24,39 +25,37 @@ const HTTP_REQUEST_RETRIES: u64 = 2; const HTTP_REQUEST_NO_RETRIES: u64 = 0; #[cfg_attr(test, faux::create)] -pub struct InvokeAPIAdapter; +pub struct InvokeAdapter; #[cfg_attr(test, faux::methods)] -impl InvokeAPIAdapter { - pub fn new() -> InvokeAPIAdapter { - InvokeAPIAdapter +impl InvokeAdapter { + pub fn new() -> Self { + Self } pub async fn register_instance( &self, - region: &String, - register_id: &String, - register_value: &String, - ) -> Result { - let machine_id = get_machine_id().ok_or("get_machine_id failed")?; - let local_ip = get_local_ip().ok_or("get_local_ip failed")?; - let hostname = get_hostname().ok_or("get_hostname failed")?; - let (publickey, privkey) = generate_rsa_key().ok_or("generate_rsa_key failed")?; + region: &str, + register_id: &str, + register_value: &str, + ) -> Result { + let machine_id = get_machine_id().context("get_machine_id failed")?; + let local_ip = get_local_ip().context("get_local_ip failed")?; + let hostname = get_hostname().context("get_hostname failed")?; + let (publickey, privkey) = generate_rsa_key().context("generate_rsa_key failed")?; let body = RegisterInstanceRequest::new( machine_id.clone(), - register_id.clone(), - register_value.clone(), + register_id.to_owned(), + register_value.to_owned(), publickey, hostname, local_ip, ); let url = get_register_url(region); - let resp: RegisterInstanceResponse = self - .send("RegisterInstance", &url, body, HTTP_REQUEST_RETRIES) - .await - .map_err(|err| err.message)?; + let resp: RegisterInstanceResponse = + call_invoke_api("RegisterInstance", &url, body, HTTP_REQUEST_RETRIES).await?; let record = RegisterInfo { region: region.to_string(), @@ -69,9 +68,9 @@ impl InvokeAPIAdapter { Ok(record) } - pub async fn describe_tasks(&self) -> Result> { + pub async fn describe_tasks(&self) -> Result { let req = DescribeTasksRequest {}; - self.send( + call_invoke_api( "DescribeTasks", &get_invoke_url(), req, @@ -84,12 +83,12 @@ impl InvokeAPIAdapter { &self, invocation_task_id: &str, start_timestamp: u64, - ) -> Result> { + ) -> Result { let req = ReportTaskStartRequest { invocation_task_id: invocation_task_id.to_string(), time_stamp: start_timestamp, }; - self.send( + call_invoke_api( "ReportTaskStart", &get_invoke_url(), req, @@ -108,7 +107,7 @@ impl InvokeAPIAdapter { finish_timestamp: u64, output_url: &str, output_err_info: &str, - ) -> Result> { + ) -> Result { let req = ReportTaskFinishRequest { invocation_task_id: invocation_task_id.to_string(), time_stamp: finish_timestamp, @@ -119,7 +118,7 @@ impl InvokeAPIAdapter { output_url: output_url.to_string(), output_error_info: output_err_info.to_string(), }; - self.send( + call_invoke_api( "ReportTaskFinish", &get_invoke_url(), req, @@ -134,9 +133,9 @@ impl InvokeAPIAdapter { idx: u32, output: Vec, dropped: u64, - ) -> Result> { + ) -> Result { let task_log = UploadTaskLogRequest::new(task_id, idx, output, dropped); - self.send( + call_invoke_api( "UploadTaskLog", &get_invoke_url(), task_log, @@ -145,9 +144,9 @@ impl InvokeAPIAdapter { .await } - pub async fn check_update(&self) -> Result> { + pub async fn check_update(&self) -> Result { let body = CheckUpdateRequest::new(); - self.send( + call_invoke_api( "CheckUpdate", &get_invoke_url(), body, @@ -161,9 +160,9 @@ impl InvokeAPIAdapter { fd_avg: u32, mem_avg: u32, zp_cnt: u32, - ) -> Result> { + ) -> Result { let body = ReportResourceRequest::new(fd_avg, mem_avg, zp_cnt); - self.send( + call_invoke_api( "ReportResource", &get_invoke_url(), body, @@ -174,11 +173,11 @@ impl InvokeAPIAdapter { pub async fn validate_instance( &self, - hostname: String, - local_ip: String, - ) -> Result> { + hostname: &str, + local_ip: &str, + ) -> Result { let body = ValidateInstanceRequest::new(hostname, local_ip); - self.send( + call_invoke_api( "ValidateInstance", &get_invoke_url(), body, @@ -187,12 +186,9 @@ impl InvokeAPIAdapter { .await } - pub async fn get_cos_credential( - &self, - task_id: String, - ) -> Result> { + pub async fn get_cos_credential(&self, task_id: &str) -> Result { let body = GetCosCredentialRequest::new(task_id); - self.send( + call_invoke_api( "GetCosCredential", &get_invoke_url(), body, @@ -200,69 +196,29 @@ impl InvokeAPIAdapter { ) .await } +} - // parse standard formatted response to custom type - async fn send( - &self, - action: &str, - url: &str, - request: T, - retries: u64, - ) -> Result> { - let mut retry_cnt = 0; - let body = AgentRequest::new(action, request); - loop { - let reqwest_resp_result = HttpRequester::new(url) - .with_time_out(10) - .send_request::>( - HttpMethod::POST, - "/", - Some(&body), - Some(build_extra_headers()), - ) - .await; - - match reqwest_resp_result { - Ok(reqwest_resp) => return self.parse(reqwest_resp).await, - Err(ref e) => { - if retry_cnt < retries { - retry_cnt = retry_cnt + 1; - tokio::time::sleep(Duration::from_millis(500)).await; - info!("request error: {:?}, retry {}", e, retry_cnt); - continue; - } - error!("request error reached {} times", retry_cnt); - return Err(e.clone()); - } - } - } - } - - async fn parse( - &self, - reqwest_resp: Response, - ) -> Result> { - let txt = reqwest_resp.text().await.map_err(|e| { - AgentError::new( - AgentErrorCode::ResponseReadError, - &format!("failed to read response: {:?}", e), - ) - })?; - - info!("response text {:?}", txt); - let raw_resp = from_str::<'_, ServerRawResponse>(&txt).map_err(|e| { - AgentError::new( - AgentErrorCode::JsonDecodeError, - &format!("failed to parse json response: {:?}", e), - ) - })?; +async fn call_invoke_api( + action: &str, + url: &str, + request: T, + retries: u64, +) -> Result { + let body = AgentRequest::new(action, request); + let resp = HttpRequester::post(url, &body) + .timeout(10) + .headers(build_extra_headers()) + .retries(retries) + .retry_interval(Duration::from_millis(500)) + .send() + .await?; + Ok(parse(resp).await?) +} - raw_resp.into_response().map_err(|e| { - AgentError::wrap( - AgentErrorCode::ResponseEmptyError, - format!("error: {}", e.message()).as_str(), - format!("response error: {:?}", e), - ) - }) - } +// parse standard formatted response to custom type +async fn parse(reqwest_resp: Response) -> Result { + let txt = reqwest_resp.text().await?; + info!("response text {}", txt); + let raw_resp = from_str::>(&txt)?; + Ok(raw_resp.into_response()?) } diff --git a/src/network/metadata_adapter.rs b/src/network/metadata_adapter.rs index a483d2a..569cd73 100644 --- a/src/network/metadata_adapter.rs +++ b/src/network/metadata_adapter.rs @@ -1,10 +1,11 @@ -use crate::network::types::{GetTmpCredentialResponse, HttpMethod}; +use crate::network::types::GetTmpCredentialResponse; use crate::network::HttpRequester; +use anyhow::Result; use log::{error, info}; use serde_json::from_str; -pub struct MetadataAPIAdapter { +pub struct MetadataAdapter { url: String, } @@ -12,104 +13,57 @@ const CREDENTIAL_URI: &str = "/latest/meta-data/cam/security-credentials"; const INSTANCE_ID_URI: &str = "/latest/meta-data/instance-id"; const REGION_URI: &str = "/latest/meta-data/placement/region"; -impl MetadataAPIAdapter { +impl MetadataAdapter { pub fn build(url: &str) -> Self { - MetadataAPIAdapter { + Self { url: url.to_string(), } } - pub async fn tmp_credential(&self) -> Result { + pub async fn tmp_credential(&self) -> Result { let role_name = self.get_role_name().await?; - self.get_tmp_credential(role_name).await + self.get_tmp_credential(&role_name).await } pub async fn instance_id(&self) -> String { - let res = HttpRequester::new(&self.url) - .with_time_out(3) - .send_request::(HttpMethod::GET, INSTANCE_ID_URI, None, None) - .await; - let resp = match res { - Ok(resp) => resp, - Err(e) => { - error!("request error: {:?}", e); - return format!(""); - } - }; - match resp.text().await { - Ok(txt) => { - info!("response text: {:?}", txt); - txt - } - Err(e) => { - error!("failed to read response: {:?}", e); - format!("") - } - } + let url = self.url.clone() + INSTANCE_ID_URI; + Self::get(&url) + .await + .inspect(|id| info!("Metadata instance_id response: {}", id)) + .unwrap_or_default() } - pub async fn region(&self) -> Option { - let resp = HttpRequester::new(&self.url) - .with_time_out(3) - .send_request::(HttpMethod::GET, REGION_URI, None, None) - .await - .map_err(|e| error!("request region error: {:?}", e)) - .ok()?; + pub async fn region(&self) -> Result { + let url = self.url.clone() + REGION_URI; + let txt = Self::get(&url).await?; + info!("Metadata region response: {}", txt); + Ok(txt) + } - match resp.text().await { - Ok(txt) => { - info!("region text: {:?}", txt); - Some(txt) - } - Err(e) => { - error!("failed to read region: {:?}", e); - None - } - } + async fn get_role_name(&self) -> Result { + let url = self.url.clone() + CREDENTIAL_URI; + let txt = Self::get(&url).await?; + info!("Metadata get_role_name response: {}", txt); + Ok(txt) } - async fn get_role_name(&self) -> Result { - let resp = HttpRequester::new(&self.url) - .with_time_out(3) - .send_request::(HttpMethod::GET, CREDENTIAL_URI, None, None) - .await - .map_err(|e| { - error!("request error: {:?}", e); - format!("Get CAM role of instance failed.") - })?; - match resp.text().await { - Ok(txt) => { - info!("response text: {:?}", txt); - Ok(txt) - } - Err(e) => { - error!("failed to read response: {:?}", e); - Err(format!("Get CAM role of instance failed.")) - } - } + async fn get_tmp_credential(&self, role_name: &str) -> Result { + let url = self.url.clone() + CREDENTIAL_URI + "/" + role_name; + let txt = Self::get(&url).await?; + let obj = from_str::(&txt) + .inspect_err(|e| error!("failed to parse json response: {}", e))?; + Ok(obj) } - async fn get_tmp_credential( - &self, - role_name: String, - ) -> Result { - let url = format!("{}/{}", CREDENTIAL_URI, role_name); - let resp = HttpRequester::new(&self.url) - .with_time_out(3) - .send_request::(HttpMethod::GET, &*url, None, None) + async fn get(url: &str) -> Result { + let resp_text = HttpRequester::get(&url) + .timeout(3) + .send() + .await + .inspect_err(|e| error!("send request error: {}", e))? + .text() .await - .map_err(|e| { - error!("request error: {:?}", e); - format!("Get credential of CAM role failed.") - })?; - let txt = resp.text().await.map_err(|e| { - error!("failed to read response: {:?}", e); - format!("Get credential of CAM role failed.") - })?; - let raw_resp_result: Result = from_str(&txt); - raw_resp_result.or_else(|e| { - error!("failed to parse json response: {:?}", e); - Err(format!("Get credential of CAM role failed.")) - }) + .inspect_err(|e| error!("failed to read response: {}", e))?; + Ok(resp_text) } } diff --git a/src/network/mod.rs b/src/network/mod.rs index 0304053..5c63d03 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -3,6 +3,7 @@ use crate::common::utils::{gen_rand_str_with, get_now_secs}; use crate::sysinfo::{get_hostname, get_local_ip, Uname}; use std::env; +use anyhow::{Context, Result}; use base64::{engine::general_purpose::STANDARD, Engine}; use log::{error, info}; use reqwest::header::HeaderValue; @@ -11,7 +12,7 @@ use rsa::pkcs1v15::Pkcs1v15Sign; use rsa::{pkcs1::DecodeRsaPrivateKey, RsaPrivateKey}; use sha1::{Digest, Sha1}; -pub mod cos; +pub mod cos_adapter; pub mod types; pub mod urls; pub mod ws; @@ -20,8 +21,8 @@ mod invoke_adapter; mod metadata_adapter; mod requester; -pub use invoke_adapter::InvokeAPIAdapter; -pub use metadata_adapter::MetadataAPIAdapter; +pub use invoke_adapter::InvokeAdapter; +pub use metadata_adapter::MetadataAdapter; pub use requester::HttpRequester; const VPCID_HEADER: &str = "Tat-Vpcid"; @@ -85,7 +86,7 @@ fn build_extra_headers() -> HeaderMap { HeaderValue::from_str(&record.instance_id).expect("build head failed"), ); - let rand_key: String = gen_rand_str_with(32); + let rand_key = gen_rand_str_with(32); headers.insert( "RandomKey", HeaderValue::from_str(&rand_key).expect("build head failed"), @@ -116,28 +117,19 @@ fn build_extra_headers() -> HeaderMap { headers } -pub fn register( - region: &String, - register_id: &String, - register_value: &String, -) -> Result<(), String> { +pub fn register(region: &str, register_id: &str, register_value: &str) -> Result<()> { //temp runtime in current thread tokio::runtime::Builder::new_current_thread() .enable_all() .build() .expect("register runtime failed") .block_on(async move { - let adapter = InvokeAPIAdapter::new(); + let adapter = InvokeAdapter::new(); adapter .register_instance(region, register_id, register_value) .await }) - .and_then(|record| { - config::save_register_info(record).map_err(|e| { - error!("save_register_info fail {}", e); - e.to_string() - }) - }) + .and_then(|record| config::save_register_info(record).context("save_register_info failed")) } pub fn check() { @@ -148,14 +140,13 @@ pub fn check() { .block_on(async move { if let Some(record) = config::get_register_info() { info!("find register info, try validate"); - let adapter = InvokeAPIAdapter::new(); + let adapter = InvokeAdapter::new(); let local_ip = get_local_ip().expect("get_local_ip failed"); let hostname = get_hostname().expect("get_hostname failed"); - if let Err(err) = adapter.validate_instance(hostname, local_ip).await { - error!("validate_instance failed: {err:?}, work as normal instance"); - } else { - info!("validate_instance success, work as register instance"); - }; + match adapter.validate_instance(&hostname, &local_ip).await { + Ok(_) => info!("validate_instance success, work as register instance"), + Err(e) => error!("validate_instance failed: {e}, work as normal instance"), + } let _ = config::save_register_info(record); } }); diff --git a/src/network/requester.rs b/src/network/requester.rs index 6cf8be6..8ef1d52 100644 --- a/src/network/requester.rs +++ b/src/network/requester.rs @@ -1,127 +1,87 @@ -use crate::network::types::{AgentError, AgentErrorCode, HttpMethod}; -use std::fmt; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::Arc; +use std::sync::LazyLock; +use std::time::Duration; -use log::{debug, error, info}; -use once_cell::sync::Lazy; +use anyhow::{anyhow, Result}; +use log::{error, info, warn}; use reqwest::header::{self, HeaderMap, HeaderValue}; -use reqwest::{Client, ClientBuilder, Response}; +use reqwest::{Client, ClientBuilder, RequestBuilder, Response}; use serde::Serialize; -use serde_json::to_string; -const HTTP_REQUEST_TIME_OUT: u64 = 5; +const HTTP_REQUEST_TIMEOUT: u64 = 5; -static HTTP_CLIENT: Lazy> = Lazy::new(|| { - Arc::new({ - ClientBuilder::new() - .pool_max_idle_per_host(1) - .build() - .expect("failed to create http client") - }) +static HTTP_CLIENT: LazyLock = LazyLock::new(|| { + ClientBuilder::new() + .pool_max_idle_per_host(1) + .timeout(Duration::from_secs(HTTP_REQUEST_TIMEOUT)) + .build() + .expect("network: failed to create http client") }); pub struct HttpRequester { - url: String, - time_out: AtomicU64, + rb: RequestBuilder, + retries: u64, + interval: Duration, } impl HttpRequester { - pub fn new(url: &str) -> HttpRequester { - HttpRequester { - url: url.to_string(), - time_out: AtomicU64::new(HTTP_REQUEST_TIME_OUT), - } + pub fn get(url: &str) -> Self { + info!("send request to: {}", url); + Self::new(HTTP_CLIENT.get(url)) } - pub fn with_time_out(&self, time_out: u64) -> &Self { - self.time_out.store(time_out, Ordering::SeqCst); - self + pub fn post(url: &str, body: &T) -> Self { + let body = serde_json::to_string(body).expect("body serde_json failed"); + info!("send request to {}, request body: {}", url, body); + Self::new(HTTP_CLIENT.post(url).body(body)) } - pub async fn send_request( - &self, - method: HttpMethod, - path: &str, - body: Option<&T>, - extra_headers: Option>, - ) -> Result> { - let extra_headers = match extra_headers { - Some(headers) => headers, - None => HeaderMap::new(), - }; - match (method, body) { - (HttpMethod::POST, Some(b)) => self.call_post(path, b, extra_headers).await, - (HttpMethod::POST, None) => Err(AgentError::new( - AgentErrorCode::RequestEmptyError, - "empty request body", - )), - (HttpMethod::GET, _) => self.call_get(path, extra_headers).await, - } + pub fn timeout(self, timeout: u64) -> Self { + let rb = self.rb.timeout(Duration::from_secs(timeout)); + Self { rb, ..self } } - async fn call_get( - &self, - path: &str, - extra_headers: HeaderMap, - ) -> Result> { - let url = format!("{}{}", self.url, path); - info!("send request to: {}", url); - let time_out = self.time_out.load(Ordering::SeqCst); - let request_builder = HTTP_CLIENT - .get(&url) - .header(header::CONNECTION, "close") - .headers(extra_headers) - .timeout(std::time::Duration::from_secs(time_out)); - let resp_res = request_builder.send().await; - match resp_res { - Ok(resp) => { - debug!("recv response: {:?}", resp); - Ok(resp) - } - Err(err) => { - let agent_err = AgentError::wrap( - AgentErrorCode::ResponseEmptyError, - &format!("request error: {}", err), - format!("{:?}", err), - ); - error!("{:?}", agent_err); - Err(agent_err) - } - } + pub fn headers(self, headers: HeaderMap) -> Self { + let rb = self.rb.headers(headers); + Self { rb, ..self } } - async fn call_post( - &self, - path: &str, - body: &T, - extra_headers: HeaderMap, - ) -> Result> { - let url = format!("{}{}", self.url, path); - info!("send request to {}, request body: {:?}", url, body); + pub fn retries(self, retries: u64) -> Self { + Self { retries, ..self } + } - let time_out = self.time_out.load(Ordering::SeqCst); - let request_builder = HTTP_CLIENT - .post(&url) - .header(header::CONNECTION, "close") - .headers(extra_headers) - .timeout(std::time::Duration::from_secs(time_out)); + pub fn retry_interval(self, interval: Duration) -> Self { + Self { interval, ..self } + } - let resp_res = request_builder.body(to_string(&body).unwrap()).send().await; - match resp_res { - Ok(resp) => { - debug!("recv response: {:?}", resp); - Ok(resp) + pub async fn send(self) -> Result { + let rb = self.rb.header(header::CONNECTION, "close"); + if self.retries == 0 || rb.try_clone().is_none() { + if self.retries != 0 { + warn!("request body try_clone failed, only 1 attempt made") } - Err(err) => { - let agent_err = AgentError::wrap( - AgentErrorCode::ResponseEmptyError, - &format!("request error: {}", err), - format!("{:?}", err), - ); - error!("{:?}", agent_err); - Err(agent_err) + let resp = rb + .send() + .await + .inspect_err(|e| error!("request error: {}", e))?; + return Ok(resp); + } + + for i in 1..=self.retries { + let rst = rb.try_clone().unwrap().send().await; + match rst { + Ok(resp) => return Ok(resp), + Err(e) => warn!("request error: {}, attempt {} of {}", e, i, self.retries), } + tokio::time::sleep(self.interval).await; + } + Err(anyhow!("request error reached {} times", self.retries)) + } + + fn new(rb: RequestBuilder) -> Self { + Self { + rb, + retries: 0, + interval: Duration::from_millis(500), } } } diff --git a/src/network/types/error.rs b/src/network/types/error.rs deleted file mode 100644 index 672f6d2..0000000 --- a/src/network/types/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[derive(Debug, Clone)] -pub enum AgentErrorCode { - // errors in c/s communication - ResponseReadError = 100_001, - JsonDecodeError = 100_002, - ResponseEmptyError = 100_003, - UnexpectedResponseFormat = 100_004, - RequestEmptyError = 100_005, -} - -#[derive(Debug, Clone)] -pub struct AgentError { - pub code: AgentErrorCode, - pub message: String, - pub original_error: T, -} - -impl AgentError { - pub fn wrap(code: AgentErrorCode, message: &str, original_error: T) -> Self { - AgentError { - code: code, - message: String::from(message), - original_error: original_error, - } - } -} - -impl AgentError { - pub fn new(code: AgentErrorCode, message: &str) -> Self { - AgentError { - code: code, - message: String::from(message), - original_error: String::from("None"), - } - } -} diff --git a/src/network/types/http_req.rs b/src/network/types/http_msg.rs similarity index 91% rename from src/network/types/http_req.rs rename to src/network/types/http_msg.rs index 23d6719..0fcf1ed 100644 --- a/src/network/types/http_req.rs +++ b/src/network/types/http_msg.rs @@ -1,11 +1,11 @@ use super::UTF8_BOM_HEADER; use crate::executor::CMD_TYPE_POWERSHELL; -use crate::network::types::AgentErrorCode; use crate::network::AGENT_VERSION; use crate::sysinfo::Uname; use std::fmt; +use anyhow::{anyhow, Context, Result}; use base64::{engine::general_purpose::STANDARD, Engine}; use serde::{Deserialize, Serialize}; @@ -51,12 +51,6 @@ pub struct ResponseError { message: String, } -impl ResponseError { - pub fn message(&self) -> &str { - &self.message - } -} - // standard response format #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "PascalCase")] @@ -71,7 +65,7 @@ impl AgentRequest { }; AgentRequest { general_params: g, - custom_params: custom_params, + custom_params, } } } @@ -95,28 +89,16 @@ impl GeneralResponse { } impl ServerRawResponse { - pub fn into_response(self) -> Result { - if self.response.is_ok() { - match self.response.content() { - Some(content) => Ok(content), - None => Err(ResponseError { - code: format!("{:?}", AgentErrorCode::UnexpectedResponseFormat), - message: format!("cannot get response content"), - }), - } - } else { - match self.response.error() { - Some(err) => Err(err), - None => Err(ResponseError { - code: format!("{:?}", AgentErrorCode::UnexpectedResponseFormat), - message: format!("cannot get response error"), - }), - } + pub fn into_response(self) -> Result { + if !self.response.is_ok() { + let e = self.response.error().context("cannot get response error")?; + return Err(anyhow!("{}: {}", e.code, e.message)); } - } - - pub fn _into_request_id(&self) -> String { - self.response._request_id() + let resp = self + .response + .content() + .context("cannot get response content")?; + Ok(resp) } } @@ -152,10 +134,8 @@ pub struct InvocationNormalTask { } impl InvocationNormalTask { - pub fn decode_command(&self) -> Result, String> { - let mut command = STANDARD - .decode(&self.command) - .map_err(|e| format!("decode error: {:?}", e))?; + pub fn decode_command(&self) -> Result> { + let mut command = STANDARD.decode(&self.command)?; // powershell dont support utf8, but support utf8 with bom. // utf8 bom start with 0xEF, 0xBB, 0xBF, @@ -257,9 +237,9 @@ impl UploadTaskLogRequest { pub fn new(invocation_task_id: &str, index: u32, output: Vec, dropped: u64) -> Self { UploadTaskLogRequest { invocation_task_id: String::from(invocation_task_id), - index: index, + index, output: STANDARD.encode(&output), - dropped: dropped, + dropped, } } } @@ -415,10 +395,10 @@ pub struct ValidateInstanceRequest { } impl ValidateInstanceRequest { - pub fn new(hostname: String, local_ip: String) -> Self { - ValidateInstanceRequest { - hostname, - local_ip, + pub fn new(hostname: &str, local_ip: &str) -> Self { + Self { + hostname: hostname.to_owned(), + local_ip: local_ip.to_owned(), #[cfg(windows)] sys_name: "Windows".to_string(), #[cfg(unix)] @@ -463,8 +443,10 @@ pub struct GetCosCredentialRequest { } impl GetCosCredentialRequest { - pub fn new(invocation_task_id: String) -> Self { - GetCosCredentialRequest { invocation_task_id } + pub fn new(invocation_task_id: &str) -> Self { + Self { + invocation_task_id: invocation_task_id.to_owned(), + } } } @@ -647,6 +629,5 @@ mod tests { .expect("failed to read random-file"); assert_eq!(remove_file("./random-file").is_ok(), true); let _req = UploadTaskLogRequest::new("invk-123123", 0, buffer, 0); - // println!("{:?}", req); } } diff --git a/src/network/types/mod.rs b/src/network/types/mod.rs index 64c0079..568b5b9 100644 --- a/src/network/types/mod.rs +++ b/src/network/types/mod.rs @@ -1,10 +1,7 @@ -mod error; -mod http_req; +mod http_msg; pub mod ws_msg; -pub use error::AgentError; -pub use error::AgentErrorCode; -pub use http_req::{ +pub use http_msg::{ AgentRequest, CheckUpdateRequest, CheckUpdateResponse, DescribeTasksRequest, DescribeTasksResponse, GetCosCredentialRequest, GetTmpCredentialResponse, InvocationCancelTask, InvocationNormalTask, RegisterInstanceRequest, RegisterInstanceResponse, ReportResourceRequest, @@ -13,9 +10,4 @@ pub use http_req::{ UploadTaskLogResponse, ValidateInstanceRequest, ValidateInstanceResponse, }; -pub enum HttpMethod { - GET, - POST, -} - pub const UTF8_BOM_HEADER: [u8; 3] = [0xEF, 0xBB, 0xBF]; diff --git a/src/network/urls.rs b/src/network/urls.rs index 6f9d4f7..61e2cbf 100644 --- a/src/network/urls.rs +++ b/src/network/urls.rs @@ -1,18 +1,16 @@ -use self::UrlType::{InvokeApis, WsUrls}; -use super::MetadataAPIAdapter; +use self::UrlType::{Invoke, Ws}; +use super::MetadataAdapter; use crate::common::config; use crate::network::mock_enabled; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use std::sync::{Condvar, Mutex}; +use std::sync::{Condvar, LazyLock, Mutex}; use std::{net::ToSocketAddrs, sync::Arc}; use log::info; -use once_cell::sync::Lazy; +use tokio::runtime::Builder; use url::Url; -const METADATA_API_MOCK: &str = "http://mock-server:8000"; -const METADATA_API: &str = "http://metadata.tencentyun.com"; const WS_URL_MOCK: &str = "ws://notify:8086/ws"; const WS_URLS: [&'static str; 4] = [ "wss://notify.tat-tc.tencent.cn:8186/ws", @@ -20,161 +18,153 @@ const WS_URLS: [&'static str; 4] = [ "wss://notify.tat-tc.tencentyun.com:8186/ws", "wss://notify.tat.tencent-cloud.com:8186/ws", ]; -const INVOKE_API_MOCK: &str = "http://invoke"; -const INVOKE_APIS: [&'static str; 4] = [ +const INVOKE_URL_MOCK: &str = "http://invoke"; +const INVOKE_URLS: [&'static str; 4] = [ "https://invoke.tat-tc.tencent.cn", "https://invoke.tat-tc.tencent.com.cn", "https://invoke.tat-tc.tencentyun.com", "https://invoke.tat.tencent-cloud.com", ]; +const METADATA_URL_MOCK: &str = "http://mock-server:8000"; +const METADATA_URL: &str = "http://metadata.tencentyun.com"; -pub enum UrlType { - WsUrls, - InvokeApis, +enum UrlType { + Ws, + Invoke, } impl UrlType { - fn intranet_urls(&self) -> Vec<&str> { + fn get_available_url(&self, region: Option) -> String { + self.config_url() + .or_else(|| self.mock_url()) + .unwrap_or_else(|| { + let rg = region.or_else(get_register_region).unwrap_or_default(); + if rg.is_empty() || rg == get_current_region() { + // Prioritize internal network for the same region + return find_available(self.intranet_urls(), dns_resolve); + } + self.public_url(&rg) + }) + } + + fn intranet_urls(&self) -> &[&str] { match self { - WsUrls => WS_URLS.to_vec(), - InvokeApis => INVOKE_APIS.to_vec(), + Ws => &WS_URLS, + Invoke => &INVOKE_URLS, } } fn public_url(&self, region: &str) -> String { match self { - WsUrls => format!("wss://{}.notify.tat-tc.tencent.cn:8186/ws", region), - InvokeApis => format!("https://{}.invoke.tat-tc.tencent.cn", region), + Ws => format!("wss://{}.notify.tat-tc.tencent.cn:8186/ws", region), + Invoke => format!("https://{}.invoke.tat-tc.tencent.cn", region), + } + } + + fn mock_url(&self) -> Option { + match self { + _ if !mock_enabled() => None, + Ws => Some(WS_URL_MOCK.to_owned()), + Invoke => Some(INVOKE_URL_MOCK.to_owned()), + } + } + + fn config_url(&self) -> Option { + match self { + Ws => config::get_ws_url(), + Invoke => config::get_invoke_url(), } } } pub fn get_ws_url() -> String { - let result = if let Some(url) = config::get_ws_url() { - url - } else if mock_enabled() { - WS_URL_MOCK.to_string() - } else { - get_available_url(None, UrlType::WsUrls) - }; - info!("get_ws_url {}", result); - return result; + let url = Ws.get_available_url(None); + info!("get_ws_url: {}", url); + url } pub fn get_invoke_url() -> String { - let result = if let Some(url) = config::get_invoke_url() { - url - } else if mock_enabled() { - INVOKE_API_MOCK.to_string() - } else { - get_available_url(None, UrlType::InvokeApis) - }; - info!("get_invoke_url {}", result); - return result; + let url = Invoke.get_available_url(None); + info!("get_invoke_url: {}", url); + url } -fn dns_resolve(url: &str) -> Result<(), ()> { - let url = Url::parse(url).expect("parse fail"); - let host = url.host().expect("host fail").to_string(); - return match format!("{}:{}", host, 80).to_socket_addrs() { - Ok(_) => Ok(()), - Err(_) => Err(()), - }; +pub fn get_register_url(region: &str) -> String { + let url = Invoke.get_available_url(Some(region.to_owned())); + info!("get_register_url: {}", url); + return url; } -fn find_available_url(urls: Vec<&str>, resolver: F) -> String -where - F: Fn(&str) -> Result<(), ()>, -{ - static IDX: AtomicUsize = AtomicUsize::new(0); - let idx = IDX.load(SeqCst); - let mut cur = idx; - for _ in 0..urls.len() { - if resolver(urls[cur]).is_ok() { - if cur != idx && cur != IDX.swap(cur, SeqCst) { - info!("cache index was changed to {}", cur); - } - return urls[cur].to_string(); - } - cur = (cur + 1) % urls.len(); +pub fn get_meta_url() -> String { + if mock_enabled() { + return METADATA_URL_MOCK.to_string(); } - urls[idx].to_string() + METADATA_URL.to_string() } -fn get_register_region() -> Option { - if let Some(info) = config::get_register_info() { - return Some(info.region); - } - None +fn dns_resolve(url: &str) -> bool { + let url = Url::parse(url).expect("parse failed"); + let host = url.host().expect("host failed").to_string(); + format!("{}:{}", host, 80).to_socket_addrs().is_ok() } -pub fn get_meta_url() -> String { - if mock_enabled() { - return METADATA_API_MOCK.to_string(); - } else { - return METADATA_API.to_string(); +fn find_available(urls: &[&str], resolver: impl Fn(&str) -> bool) -> String { + static IDX: AtomicUsize = AtomicUsize::new(0); + let idx = IDX.load(SeqCst); + // starts from the current idx, wraps around to the beginning of urls + let mut iter = urls.iter().enumerate().cycle().skip(idx).take(urls.len()); + match iter.find(|(_, url)| resolver(url)) { + Some((cur, url)) if cur != idx && cur != IDX.swap(cur, SeqCst) => { + info!("cache index was changed to {}", cur); + url.to_string() + } + _ => urls[idx].to_string(), } } -pub fn get_register_url(region: &str) -> String { - let result = if let Some(url) = config::get_invoke_url() { - url - } else if mock_enabled() { - INVOKE_API_MOCK.to_string() - } else { - get_available_url(Some(region), UrlType::InvokeApis) - }; - info!("get_register_url {}", result); - return result; +fn get_register_region() -> Option { + config::get_register_info().map(|info| info.region) } -pub fn get_current_region() -> String { - static REGION: Lazy> = Lazy::new(|| { +fn get_current_region() -> String { + static REGION: LazyLock = LazyLock::new(|| { let region: Arc> = Arc::new(Mutex::new("".to_string())); let convar: Arc = Arc::new(Condvar::new()); - let region_0 = region.clone(); - let convar_0 = convar.clone(); - // Run the following code in a new thread, as it may be called inside or outside the tokio runtime. // Creating a tokio runtime multiple times will result in an error due to multiple runtime creation. - std::thread::spawn(move || { - *region_0.lock().expect("lock fail") = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("register runtime failed") - .block_on(async { - MetadataAPIAdapter::build(&get_meta_url()) - .region() - .await - .unwrap_or_default() - }); - - convar_0.notify_one() + std::thread::spawn({ + let region = region.clone(); + let convar = convar.clone(); + move || { + *region.lock().expect("lock failed") = Builder::new_current_thread() + .enable_all() + .build() + .expect("register runtime failed") + .block_on(async { + MetadataAdapter::build(&get_meta_url()) + .region() + .await + .unwrap_or_default() + }); + + convar.notify_one() + } }); - let mut guard = region.lock().expect("lock fail"); - guard = convar.wait(guard).expect("wait fail"); - Arc::new(guard.to_string()) - }); - info!("=>get_current_region: {}", REGION.to_string()); - REGION.to_string() -} + let mut guard = region.lock().expect("lock failed"); + guard = convar.wait(guard).expect("wait failed"); + guard.clone() + }); -pub fn get_available_url(region: Option<&str>, url_type: UrlType) -> String { - let region = region - .map(|s| s.to_owned()) - .unwrap_or_else(|| get_register_region().unwrap_or_default()); - if region.is_empty() || region == get_current_region() { - return find_available_url(url_type.intranet_urls(), dns_resolve); - } - url_type.public_url(®ion) + info!("=>get_current_region: {}", *REGION); + REGION.clone() } #[cfg(test)] mod test { - use super::{INVOKE_APIS, WS_URLS}; - use crate::network::urls::find_available_url; + use super::{INVOKE_URLS, WS_URLS}; + use crate::network::urls::find_available; use std::sync::atomic::AtomicU8; use std::sync::atomic::Ordering::SeqCst; use std::sync::Arc; @@ -185,41 +175,33 @@ mod test { let count_1 = resolve_1_cnt.clone(); let resolve_1 = |url: &str| { count_1.fetch_add(1, SeqCst); - if url.contains("tencentyun.com") { - return Ok(()); - } else { - Err(()) - } + url.contains("tencentyun.com") }; let resolve_2_cnt = Arc::new(AtomicU8::new(0)); let count_2 = resolve_2_cnt.clone(); let resolve_2 = |url: &str| { count_2.fetch_add(1, SeqCst); - if url.contains("tencent.com.cn") { - return Ok(()); - } else { - Err(()) - } + url.contains("tencent.com.cn") }; let resolve_3_cnt = Arc::new(AtomicU8::new(0)); let count_3 = resolve_3_cnt.clone(); let resolve_3 = |_url: &str| { count_3.fetch_add(1, SeqCst); - Err(()) + false }; - let url = find_available_url(Vec::from(WS_URLS), resolve_1); + let url = find_available(&WS_URLS, resolve_1); assert_eq!(url, "wss://notify.tat-tc.tencentyun.com:8186/ws"); assert_eq!(resolve_1_cnt.load(SeqCst), 3); - let url = find_available_url(Vec::from(INVOKE_APIS), resolve_2); + let url = find_available(&INVOKE_URLS, resolve_2); assert_eq!(url, "https://invoke.tat-tc.tencent.com.cn"); assert_eq!(resolve_2_cnt.load(SeqCst), 4); //use last ok, count eq urls len - let url = find_available_url(Vec::from(INVOKE_APIS), resolve_3); + let url = find_available(&INVOKE_URLS, resolve_3); assert_eq!(url, "https://invoke.tat-tc.tencent.com.cn"); assert_eq!(resolve_3_cnt.load(SeqCst), 4); } diff --git a/src/network/ws.rs b/src/network/ws.rs index ad86951..0390b80 100644 --- a/src/network/ws.rs +++ b/src/network/ws.rs @@ -1,340 +1,210 @@ use std::cmp::min; -use std::io::Cursor; -use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}; -use std::sync::{Arc, RwLock}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst}; +use std::sync::Arc; use std::time::Duration; -use std::{thread, time}; use bson::Document; -use futures01::future::Future; -use futures01::sync::mpsc::{self, UnboundedSender}; -use futures01::Stream; - -use log::{debug, error, info}; -use once_cell::sync::OnceCell; -use serde_json::{self, Value}; -use tokio01::runtime::current_thread::Runtime; -use tokio01::timer::Interval; -use websocket::header::Headers; -use websocket::r#async::Server; -use websocket::result::WebSocketError; -use websocket::{ClientBuilder, CloseData, OwnedMessage}; - -use crate::common::evbus::EventBus; -use crate::common::Opts; -use crate::network::build_extra_headers; -use crate::network::types::ws_msg::WsMsg; -use crate::network::urls::get_ws_url; - +use futures::{stream_select, Stream, StreamExt}; +use log::{error, info}; +use rand::{thread_rng, Rng}; +use serde_json::Value; +use tokio::net::TcpListener; +use tokio::sync::mpsc::unbounded_channel; +use tokio::time::{interval, sleep}; +use tokio_stream::wrappers::{IntervalStream, UnboundedReceiverStream}; +use tokio_tungstenite::tungstenite::client::IntoClientRequest; +use tokio_tungstenite::tungstenite::handshake::client::Request; +use tokio_tungstenite::tungstenite::protocol::{frame::coding::CloseCode, CloseFrame}; +use tokio_tungstenite::tungstenite::Error; +use tokio_tungstenite::tungstenite::Message::{self, *}; +use tokio_tungstenite::{accept_async, connect_async}; + +use super::{build_extra_headers, urls::get_ws_url}; +use crate::common::{evbus::EventBus, Opts}; + +use super::types::ws_msg::{WS_MSG_TYPE_CHECK_UPDATE, WS_MSG_TYPE_KICK}; use crate::conpty::{WS_BIN_MSG, WS_TXT_MSG}; -use crate::network::types::ws_msg::{WS_MSG_TYPE_CHECK_UPDATE, WS_MSG_TYPE_KICK}; -const WS_MSG_TYPE_ACK: &str = "ack"; const WS_PASSIVE_CLOSE: &str = "cli_passive_close"; -const WS_PASSIVE_CLOSE_CODE: u16 = 3001; const WS_ACTIVE_CLOSE: &str = "cli_active_close"; -const WS_ACTIVE_CLOSE_CODE: u16 = 3002; const MAX_PING_FROM_LAST_PONG: usize = 3; -const WS_RECONNECT_INTERVAL_BASE: u64 = 3; -const WS_RECONNECT_RANDOM_MAX: u64 = 512; -const WS_RECONNECT_RANDOM_MIN: u64 = 4; -const WS_RECONNECT_RANDOM_TIMES: u64 = 4; -const ONTIME_PING_INTERVAL: u64 = 2 * 60; +const BASE_DELAY: u64 = 8; +const MIN_DELAY: u64 = 3; +const MAX_DELAY: u64 = 512; + +type WsRes = Result; -#[derive(Clone)] struct WsContext { - msg_sender: Arc>>>, + receiver: Option>, event_bus: Arc, - ping_cnt_from_last_pong: Arc, - close_sent: Arc, + ping_cnt_from_last_pong: AtomicUsize, + close_sent: AtomicBool, } -pub fn run(dispatcher: &Arc) { - let context = WsContext::new(&dispatcher); +#[tokio::main] +pub async fn run(event_bus: &Arc) { if Opts::get_opts().server_mode { - context.work_as_server(); - } else { - context.work_as_client(); + return work_as_server(&event_bus).await; } -} -impl WsContext { - pub fn new(event_bus: &Arc) -> Self { - let context = WsContext { - msg_sender: Arc::new(RwLock::new(None)), - ping_cnt_from_last_pong: Arc::new(AtomicUsize::new(0)), - close_sent: Arc::new(AtomicBool::new(false)), - event_bus: event_bus.clone(), + let mut retry_count = 0u32; + loop { + match work_as_client(&event_bus).await { + Ok(_) => retry_count = 0, + Err(_) => retry_count += 1, }; - //pty message to server - let wsctx_0 = context.clone(); - event_bus.register(WS_TXT_MSG, move |data: Vec| { - let data = String::from_utf8_lossy(&data).to_string(); - if let Some(sender) = wsctx_0.msg_sender.read().unwrap().as_ref() { - sender.unbounded_send(OwnedMessage::Text(data)).ok(); - } - }); - - let wsctx_1 = context.clone(); - event_bus.register(WS_BIN_MSG, move |data: Vec| { - if let Some(sender) = wsctx_1.msg_sender.read().unwrap().as_ref() { - sender.unbounded_send(OwnedMessage::Binary(data)).ok(); - } - }); - return context; + exponential_backoff_with_jitter(retry_count).await; } +} - fn work_as_client(&self) { - let mut runtime = Runtime::new().expect("ws tokio runtime build fail"); - let mut random_range = WS_RECONNECT_RANDOM_MIN; - - loop { - info!("start ws connection..."); - let header = gen_ver_header(); - self.close_sent.store(false, Ordering::SeqCst); - self.ping_cnt_from_last_pong.store(0, Ordering::SeqCst); - - let ws_stream = ClientBuilder::new(&get_ws_url()) - .expect("ws cli builder fail") - .custom_headers(&header) - .async_connect(None); - - let runner = ws_stream - .map_err(|e| { - error!("ws connect fail:{:?}", e); - e - }) - .and_then(|(duplex, _)| { - info!("ws connection established"); - random_range = WS_RECONNECT_RANDOM_MIN; - //dispatch kick msg on ws connected - self.event_bus - .dispatch(WS_MSG_TYPE_KICK, "ws".to_string().into_bytes()); - - let (msg_sender, msg_receiver) = mpsc::unbounded::(); - self.msg_sender.write().unwrap().replace(msg_sender); +async fn work_as_client(event_bus: &Arc) -> Result<(), Error> { + info!("ws: start connection..."); + let mut ctx = WsContext::new(event_bus.clone()); + let req = gen_handshake_request().expect("ws: gen_handshake_request failed"); + let (ws_stream, _) = connect_async(req) + .await + .inspect_err(|e| error!("ws: connect failed, {e}"))?; + info!("ws: connection established"); + let (sink, stream) = ws_stream.split(); + + ctx.event_bus.dispatch(WS_MSG_TYPE_KICK, Vec::from("ws")); + let select = stream_select!( + ctx.receiver.take().unwrap().boxed(), + ctx.ping_check().boxed(), + stream.filter_map(|m| async { ctx.handle_msg(m) }).boxed(), + ); + let _ = select + .forward(sink) + .await + .inspect_err(|e| error!("ws: connection ended with error, {e}")); + Ok(()) +} - let (sink, stream) = duplex.split(); - stream - .filter_map(|msg| self.handle_server_msg(msg)) - .select(msg_receiver.map_err(|_| WebSocketError::NoDataAvailable)) - .select(self.make_ping_check()) - .forward(sink) - .map_err(|e| { - error!("ws connection ended with an error:{:?}", e); - e - }) - }) - .map(|_| { - info!("ws connection finished"); - }); +async fn work_as_server(event_bus: &Arc) { + info!("ws: work as server..."); + let listener = TcpListener::bind("0.0.0.0:3333") + .await + .expect("ws server: TcpListener::bind failed"); + + while let Ok((tcp_stream, _)) = listener.accept().await { + let mut ctx = WsContext::new(event_bus.clone()); + let (sink, stream) = match accept_async(tcp_stream).await { + Ok(ws) => ws.split(), + Err(e) => return error!("ws server: connect failed, {e}"), + }; + let select = stream_select!( + ctx.receiver.take().unwrap().boxed(), + stream.filter_map(|m| async { ctx.handle_msg(m) }).boxed(), + ); + let _ = select + .forward(sink) + .await + .inspect_err(|e| error!("ws server: connection ended with error, {e}")); + } +} - let _ = runtime.block_on(runner); - self.msg_sender.write().unwrap().take(); +async fn exponential_backoff_with_jitter(retry_count: u32) { + let exponential_max = BASE_DELAY * 2u64.pow(retry_count); + let max_delay = min(exponential_max, MAX_DELAY); + let jitter = thread_rng().gen_range(MIN_DELAY..max_delay); + info!("Retrying in {} seconds...", jitter); + sleep(Duration::from_secs(jitter)).await; +} - /*round 1: wait(WS_RECONNECT_INTERVAL_BASE + random(0, BASE + MIN)) - ... - round n: wait(WS_RECONNECT_INTERVAL_BASE + random(0, max(BASE + MIN*4^n, MAX))) - */ - let wait_time = WS_RECONNECT_INTERVAL_BASE + rand::random::() % random_range; - thread::sleep(time::Duration::from_secs(wait_time)); - random_range = min( - random_range * WS_RECONNECT_RANDOM_TIMES, - WS_RECONNECT_RANDOM_MAX, - ); - } - } +fn gen_handshake_request() -> Result { + let mut rq = get_ws_url().into_client_request()?; + rq.headers_mut().extend(build_extra_headers()); + Ok(rq) +} - fn handle_server_msg(&self, msg: OwnedMessage) -> Option { - //info!("ws recv msg: {:?}", msg); - match msg { - OwnedMessage::Ping(data) => Some(OwnedMessage::Pong(data)), - OwnedMessage::Pong(_) => { - self.ping_cnt_from_last_pong.store(0, Ordering::SeqCst); - None +impl WsContext { + fn new(event_bus: Arc) -> Self { + let (tx, rx) = unbounded_channel::(); + //pty message to server + event_bus.register(WS_TXT_MSG, { + let tx = tx.clone(); + move |data| { + let data = String::from_utf8_lossy(&data).to_string(); + let _ = tx.send(Ok(Text(data))); } - OwnedMessage::Text(msg) => self.handle_ws_text_msg(msg), - OwnedMessage::Binary(msg) => self.handle_ws_bin_msg(msg), - OwnedMessage::Close(_) => { - self.close_sent.store(true, Ordering::SeqCst); - Some(OwnedMessage::Close(Some(CloseData { - status_code: WS_PASSIVE_CLOSE_CODE, - reason: WS_PASSIVE_CLOSE.to_string(), - }))) + }); + event_bus.register(WS_BIN_MSG, { + let tx = tx.clone(); + move |data| { + let _ = tx.send(Ok(Binary(data))); } + }); + + WsContext { + receiver: Some(UnboundedReceiverStream::new(rx)), + ping_cnt_from_last_pong: AtomicUsize::new(0), + close_sent: AtomicBool::new(false), + event_bus: event_bus.clone(), } } - fn handle_ws_text_msg(&self, msg: String) -> Option { - let msg_json: Value = serde_json::from_str(msg.as_str()).ok()?; - let msg_type = msg_json.get("Type")?.as_str()?; - match msg_type { - WS_MSG_TYPE_KICK => self.handle_kick_msg(), - WS_MSG_TYPE_CHECK_UPDATE => self.handle_check_update_msg(), - _ => { - self.event_bus.dispatch(msg_type, msg.into_bytes()); - None - } - }; - None - } + fn handle_msg(&self, msg: WsRes) -> Option { + let msg = msg.inspect_err(|e| error!("ws: receive error, {e}")).ok()?; - fn handle_ws_bin_msg(&self, msg: Vec) -> Option { - if let Ok(doc) = Document::from_reader(&mut Cursor::new(&msg[..])) { - if let Ok(msg_type) = doc.get_str("Type") { - self.event_bus.dispatch(msg_type, msg) - }; + // handle + match &msg { + Text(msg) => self.on_text(msg), + Binary(msg) => self.on_binary(msg), + Pong(_) => self.ping_cnt_from_last_pong.store(0, SeqCst), + Close(_) => self.close_sent.store(true, SeqCst), + _ => (), } - None - } - - fn handle_kick_msg(&self) -> Option { - info!("kick_sender sent to notify fetch task, kick_source ws"); - self.event_bus - .dispatch(WS_MSG_TYPE_KICK, "ws".to_string().into_bytes()); - let ack_msg = WsMsg:: { - r#type: WS_MSG_TYPE_ACK.to_string(), - seq: 0, - data: None, - }; - let ret = serde_json::to_string(&ack_msg); - match ret { - Ok(ws_rsp) => Some(OwnedMessage::Text(ws_rsp)), - Err(e) => { - error!("ws rsp json encode fail:{:?}", e); - None - } + // response + match msg { + Ping(v) => Some(Pong(v)), + Close(_) => Some(Close(Some(CloseFrame { + reason: WS_PASSIVE_CLOSE.into(), + code: CloseCode::Normal, + }))), + _ => None, } + .map(|r| Ok(r)) } - fn handle_check_update_msg(&self) -> Option { - info!("kick_sender sent to notify check update, kick_source ws"); - self.event_bus - .dispatch(WS_MSG_TYPE_CHECK_UPDATE, "ws".to_string().into_bytes()); - - let ack_msg = WsMsg:: { - r#type: WS_MSG_TYPE_ACK.to_string(), - seq: 0, - data: None, + fn on_text(&self, mut msg: &str) { + let Ok(json) = serde_json::from_str::(msg) else { + return; }; - - let ret = serde_json::to_string(&ack_msg); - match ret { - Ok(ws_rsp) => Some(OwnedMessage::Text(ws_rsp)), - Err(e) => { - error!("ws rsp json encode fail:{:?}", e); - None - } + let Some(Some(msg_type)) = json.get("Type").map(Value::as_str) else { + return; + }; + if matches!(msg_type, WS_MSG_TYPE_KICK | WS_MSG_TYPE_CHECK_UPDATE) { + info!("ws: receive `{msg_type}`"); + msg = "ws"; } + self.event_bus.dispatch(msg_type, Vec::from(msg)); } - fn make_ping_check(&self) -> Box> { - let self_0 = self.clone(); - let self_1 = self.clone(); - let count = Arc::new(AtomicU64::new(0)); - let stream = Interval::new_interval(Duration::from_secs(1)) - .then(move |_| { - if self_0.close_sent.load(Ordering::SeqCst) { - error!("ping_check close_sent is true"); - return Err(WebSocketError::NoDataAvailable); - } - Ok(()) - }) - .filter(move |_| { - let old = count.fetch_add(1, Ordering::SeqCst); - old % ONTIME_PING_INTERVAL == 0 - }) - .and_then(move |_| { - let cnt = self_1 - .ping_cnt_from_last_pong - .fetch_add(1, Ordering::SeqCst); - if cnt >= MAX_PING_FROM_LAST_PONG { - error!("ping_check err, cnt >= MAX_PING_FROM_LAST_PONG"); - self_1.close_sent.store(true, Ordering::SeqCst); - Ok(OwnedMessage::Close(Some(CloseData { - status_code: WS_ACTIVE_CLOSE_CODE, - reason: WS_ACTIVE_CLOSE.to_string(), - }))) - } else { - Ok(OwnedMessage::Ping("".to_string().into_bytes())) - } - }); - Box::new(stream) - } - - fn work_as_server(&self) { - info!("work as server"); - static SERVER_CONTEXT: OnceCell> = OnceCell::new(); - let _ = SERVER_CONTEXT.set(Arc::new(self.clone())); - let mut runtime = tokio01::runtime::Builder::new().build().unwrap(); - - let server = - Server::bind("0.0.0.0:3333", &tokio01::reactor::Handle::default()).expect("bind fail"); - - let f = server - .incoming() - .map_err(|err| { - error!("incoming error {:?}", err); - err - }) - .for_each(move |(upgrade, addr)| { - info!("get a connection from: {}", addr); - let self_ = SERVER_CONTEXT.get().expect("get server").clone(); - let f = upgrade.accept().and_then(move |(s, _)| { - let (sink, stream) = s.split(); - let (msg_sender, msg_receiver) = mpsc::unbounded::(); - self_ - .msg_sender - .write() - .expect("get sender lock fail") - .replace(msg_sender); - let self_ = self_.clone(); - stream - .filter_map(move |msg| self_.handle_server_msg(msg)) - .select(msg_receiver.map_err(|_| WebSocketError::NoDataAvailable)) - .forward(sink) - }); - - tokio01::spawn( - f.map_err(move |e| println!("{}: '{:?}'", addr, e)) - .map(move |_| println!("{} closed.", addr)), - ); - Ok(()) - }); - runtime.block_on(f).unwrap(); - } -} - -fn gen_ver_header() -> Headers { - let mut headers = Headers::new(); - let header_maps = build_extra_headers(); - for (opt_key, value) in header_maps.into_iter() { - if let Some(key) = opt_key { - headers.append_raw(key.to_string(), value.as_bytes().to_vec()) - } + fn on_binary(&self, msg: &[u8]) { + let Ok(bson) = Document::from_reader(msg) else { + return; + }; + let Ok(msg_type) = bson.get_str("Type") else { + return; + }; + self.event_bus.dispatch(msg_type, msg.to_vec()); } - debug!("ws header:{:?}", headers); - headers -} - -// handle the message from WebSocket server -#[cfg(test)] -mod tests { - use super::*; - use crate::{common::logger::init_test_log, network::mock_enabled}; - use log::info; - - #[test] - fn _test_ws_cus_header() { - init_test_log(); - let header = gen_ver_header(); - if mock_enabled() { - assert_eq!(4, header.len()); - } else { - assert_eq!(2, header.len()); - } - - info!("header:{:?}", header); + fn ping_check<'a>(&'a self) -> impl Stream + 'a { + IntervalStream::new(interval(Duration::from_secs(2 * 60))).map(move |_| { + if self.close_sent.load(SeqCst) { + return Err(Error::ConnectionClosed); + } + let cnt = self.ping_cnt_from_last_pong.fetch_add(1, SeqCst); + if cnt >= MAX_PING_FROM_LAST_PONG { + error!("ws: ping_check error, max ping count reached since last pong"); + self.close_sent.store(true, SeqCst); + return Ok(Close(Some(CloseFrame { + reason: WS_ACTIVE_CLOSE.into(), + code: CloseCode::Away, + }))); + } + Ok(Ping(Vec::new())) + }) } } diff --git a/src/ontime/leak_check.rs b/src/ontime/leak_check.rs index 3833131..6f7cd38 100644 --- a/src/ontime/leak_check.rs +++ b/src/ontime/leak_check.rs @@ -1,11 +1,10 @@ -use crate::network::InvokeAPIAdapter; +use crate::network::InvokeAdapter; use crate::ontime::self_update::try_restart_agent; use std::sync::atomic::Ordering::SeqCst; -use std::sync::{atomic::AtomicU64, Mutex}; +use std::sync::{atomic::AtomicU64, LazyLock, Mutex}; use log::{error, info, warn}; -use once_cell::sync::Lazy; -use ringbuffer::{AllocRingBuffer, RingBufferExt, RingBufferWrite}; +use ringbuffer::{AllocRingBuffer, RingBuffer}; use tokio::runtime::Builder; cfg_if::cfg_if! { @@ -31,10 +30,10 @@ pub fn check_resource_leak() { static CHECK_CNT: AtomicU64 = AtomicU64::new(0); static FD_CNT: AtomicU64 = AtomicU64::new(0); static MEM_CNT: AtomicU64 = AtomicU64::new(0); - static MEM_RES_RF: Lazy>> = - Lazy::new(|| Mutex::new(AllocRingBuffer::with_capacity(64))); - static FD_RF: Lazy>> = - Lazy::new(|| Mutex::new(AllocRingBuffer::with_capacity(64))); + static MEM_RES_RF: LazyLock>> = + LazyLock::new(|| Mutex::new(AllocRingBuffer::new(64))); + static FD_RF: LazyLock>> = + LazyLock::new(|| Mutex::new(AllocRingBuffer::new(64))); let check_cnt = CHECK_CNT.fetch_add(1, SeqCst); let handle_cnt = get_handle_cnt(); @@ -54,7 +53,7 @@ pub fn check_resource_leak() { mem_res_rf.to_vec() ); if let Err(e) = try_restart_agent() { - error!("try restart agent failed: {:?}", e) + error!("try restart agent failed: {}", e) } // should not comes here, because agent should has been killed when called `try_restart_agent`. @@ -75,7 +74,7 @@ pub fn check_resource_leak() { #[cfg(windows)] let zp_cnt = 0 as u32; - let adapter = InvokeAPIAdapter::new(); + let adapter = InvokeAdapter::new(); let requester = adapter.report_resource(fd_avg, mem_avg, zp_cnt); info!( "ReportResource mem {} handle {} zp_cnt {}", @@ -151,7 +150,7 @@ fn get_zoom_process() -> u32 { } let mut ppid: Option = None; - let mut state: String = "".to_string(); + let mut state = "".to_string(); if let Ok(file) = File::open(status_path) { let mut reader = std::io::BufReader::new(file); loop { @@ -184,12 +183,11 @@ fn get_zoom_process() -> u32 { #[cfg(test)] mod tests { - use super::*; - use crate::common::logger::init_test_log; - #[cfg(unix)] #[test] fn test_get_zoom_prcesss() { + use super::*; + use crate::common::logger::init_test_log; use std::process::Command; init_test_log(); let mut nz = get_zoom_process(); @@ -202,80 +200,4 @@ mod tests { nz = get_zoom_process(); assert_eq!(0, nz); } - - #[test] - fn test_get_handle_cnt() { - init_test_log(); - let fd_cnt_1 = get_handle_cnt(); - let file = std::fs::File::create("test_fd_cnt").unwrap(); - let fd_cnt_2 = get_handle_cnt(); - assert_eq!(1, fd_cnt_2 - fd_cnt_1); - std::mem::drop(file); - let _ = std::fs::remove_file("test_fd_cnt"); - let fd_cnt_3 = get_handle_cnt(); - assert_eq!(fd_cnt_3, fd_cnt_1); - } - - #[cfg(unix)] - #[test] - fn test_get_mem_size() { - use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE}; - use std::ptr::null_mut; - let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as usize; - let mem_size_1 = get_mem_size(); - - unsafe { - //do not free _ptr, just for debug - let _ptr = libc::mmap( - null_mut(), - page_size - 100, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0, - ) as *mut u32; - *_ptr = 1024; //load in mem - } - - let mem_size_2 = get_mem_size(); - assert_eq!(mem_size_1 + page_size as u64, mem_size_2); - unsafe { - //do not free _ptr, just for debug - let _ptr = libc::mmap( - null_mut(), - page_size - 100, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0, - ) as *mut u32; - } - - let mem_size_3 = get_mem_size(); - assert_eq!(mem_size_2 + page_size as u64, mem_size_3) - } - - #[cfg(windows)] - #[test] - fn test_get_mem_size() { - use std::ptr::null_mut; - use winapi::um::memoryapi::VirtualAlloc; - use winapi::um::sysinfoapi::GetSystemInfo; - use winapi::um::sysinfoapi::SYSTEM_INFO; - use winapi::um::winnt::{MEM_COMMIT, PAGE_READWRITE}; - - let mut info: SYSTEM_INFO = unsafe { mem::zeroed() }; - unsafe { - GetSystemInfo(&mut info); - } - - let size = get_mem_size(); - unsafe { - VirtualAlloc(null_mut(), 4000, MEM_COMMIT, PAGE_READWRITE); - } - - let size1 = get_mem_size(); - assert_eq!(size + info.dwPageSize as u64, size1); - print!(""); - } } diff --git a/src/ontime/self_update.rs b/src/ontime/self_update.rs index 212b686..a1fe26d 100644 --- a/src/ontime/self_update.rs +++ b/src/ontime/self_update.rs @@ -1,15 +1,16 @@ -use crate::network::types::{AgentError, CheckUpdateResponse, HttpMethod}; -use crate::network::{HttpRequester, InvokeAPIAdapter}; +use crate::network::types::CheckUpdateResponse; +use crate::network::{HttpRequester, InvokeAdapter}; use std::fs::{create_dir_all, File}; use std::io::{self, Write}; use std::process::Command; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use anyhow::{anyhow, Context, Result}; use bytes::Bytes; use log::{debug, error, info, warn}; use tokio::runtime::{Builder, Runtime}; -use unzip::{Unzipper, UnzipperStats}; +use zip::ZipArchive; const SELF_UPDATE_FILENAME: &str = "agent_update.zip"; const UPDATE_FILE_UNZIP_DIR: &str = "agent_update_unzip"; @@ -34,17 +35,17 @@ cfg_if::cfg_if! { pub fn try_update(self_updating: Arc, need_restart: Arc) { let rt_res = Builder::new_current_thread().enable_all().build(); if let Err(e) = rt_res { - warn!("runtime for try update build failed: {e:?}, will retry later"); + warn!("runtime for try update build failed: {e}, will retry later"); self_updating.store(false, Ordering::SeqCst); return; } let mut rt = rt_res.unwrap(); - let adapter = InvokeAPIAdapter::new(); + let adapter = InvokeAdapter::new(); let check_update_rsp = check_update(&mut rt, &adapter); if let Err(e) = check_update_rsp { - warn!("check update http request failed: {:?}", e); + warn!("check update http request failed: {}", e); self_updating.store(false, Ordering::SeqCst); return; } @@ -65,9 +66,9 @@ pub fn try_update(self_updating: Arc, need_restart: Arc) info!("new agent version found:{check_update_rsp:?}, going to download"); let download_ret = download_file( &mut rt, - check_update_rsp.download_url().clone().unwrap(), - SELF_UPDATE_PATH.to_string(), - SELF_UPDATE_FILENAME.to_string(), + check_update_rsp.download_url().as_ref().unwrap(), + SELF_UPDATE_PATH, + SELF_UPDATE_FILENAME, ); if let Err(e) = download_ret { error!("download new agent failed: {}", e); @@ -76,7 +77,7 @@ pub fn try_update(self_updating: Arc, need_restart: Arc) } let download_content = download_ret.unwrap(); - let md5_check_pass = md5_check(&download_content, check_update_rsp.md5().clone().unwrap()); + let md5_check_pass = md5_check(&download_content, check_update_rsp.md5().as_ref().unwrap()); if md5_check_pass { info!("download file md5 matched with remote"); } else { @@ -118,7 +119,7 @@ pub fn try_update(self_updating: Arc, need_restart: Arc) } info!( "try run agent --version succ ret: '{}'", - try_run_ret.unwrap() + try_run_ret.unwrap().escape_debug() ); let update_script_ret = @@ -132,63 +133,52 @@ pub fn try_update(self_updating: Arc, need_restart: Arc) need_restart.store(true, Ordering::SeqCst); } -fn check_update( - rt: &mut Runtime, - adapter: &InvokeAPIAdapter, -) -> Result> { - let req = adapter.check_update(); - let rsp = rt.block_on(req); - rsp +fn check_update(rt: &mut Runtime, adapter: &InvokeAdapter) -> Result { + let req_fut = adapter.check_update(); + rt.block_on(req_fut) } -fn download_file( - rt: &mut Runtime, - url: String, - path: String, - filename: String, -) -> Result { - create_dir_all(path.clone()) - .map_err(|e| format!("path `{}` create failed because: {}", path, e))?; +fn download_file(rt: &mut Runtime, url: &str, path: &str, filename: &str) -> Result { + create_dir_all(&path).context(format!("path `{}` create failed", path))?; let filepath = format!("{}/{}", path, filename); - let mut file = - File::create(filepath).map_err(|e| format!("download file create failed: {}", e))?; + let mut file = File::create(filepath).context("download file create failed")?; - let req = HttpRequester::new(&url); - req.with_time_out(UPDATE_DOWNLOAD_TIMEOUT); + let req_fut = HttpRequester::get(&url) + .timeout(UPDATE_DOWNLOAD_TIMEOUT) + .send(); - let req = req.send_request::(HttpMethod::GET, "", None, None); let rsp = rt - .block_on(req) - .map_err(|e| format!("self update download failed: {:?}", e))?; + .block_on(req_fut) + .context("self update download failed")?; let bytes = rt .block_on(rsp.bytes()) - .map_err(|e| format!("self update download bytes return failed: {}", e))?; + .context("self update download bytes return failed")?; file.write_all(bytes.as_ref()) - .map_err(|e| format!("self update file write failed: {}", e))?; + .context("self update file write failed")?; file.sync_all() - .map_err(|e| format!("self update file sync disk failed: {}", e))?; + .context("self update file sync disk failed")?; info!("self update download success"); Ok(bytes) } -fn md5_check(download_content: &Bytes, md5: String) -> bool { +fn md5_check(download_content: &Bytes, md5: &str) -> bool { let digest = md5::compute(download_content); let digest = format!("{:x}", digest); debug!("download file md5: {}, remote md5: {}", digest, md5); - digest.eq_ignore_ascii_case(md5.as_str()) + digest.eq_ignore_ascii_case(md5) } -fn unzip_file(path: &str, zip_filename: &str, unzip_dir: &str) -> Result { +fn unzip_file(path: &str, zip_filename: &str, unzip_dir: &str) -> Result<()> { let zip_file = format!("{}/{}", path, zip_filename); let file = File::open(zip_file)?; let abs_unzip_dir = format!("{}/{}", path, unzip_dir); - let unzipper = Unzipper::new(file, abs_unzip_dir); - unzipper.unzip() + ZipArchive::new(file)?.extract(abs_unzip_dir)?; + Ok(()) } #[cfg(unix)] @@ -199,10 +189,10 @@ fn batch_set_execute_permission( agent_filename: &str, ) -> io::Result<()> { let script = format!("{}/{}/{}", path, unzip_dir, script_filename); - set_execute_permission(script)?; + set_execute_permission(&script)?; let agent = format!("{}/{}/{}", path, unzip_dir, agent_filename); - set_execute_permission(agent) + set_execute_permission(&agent) } #[cfg(windows)] @@ -212,42 +202,33 @@ fn batch_set_execute_permission(_: &str, _: &str, _: &str, _: &str) -> io::Resul } #[cfg(unix)] -fn set_execute_permission(abs_filename: String) -> io::Result<()> { +fn set_execute_permission(abs_filename: &str) -> io::Result<()> { set_permissions( abs_filename, Permissions::from_mode(FILE_EXECUTE_PERMISSION_MODE), ) } -fn try_run_agent(path: &str, unzip_dir: &str, agent_filename: &str) -> Result { +fn try_run_agent(path: &str, unzip_dir: &str, agent_filename: &str) -> Result { let agent = format!("{}{}/{}", path, unzip_dir, agent_filename); - let out = Command::new(agent) - .arg("--version") - .output() - .map_err(|e| format!("agent run ret: {:?}", e))?; + let out = Command::new(agent).arg("--version").output()?; - let out = String::from_utf8(out.stdout) - .map_err(|e| format!("version output contains non-utf8 char: {e:?}, invalid agent"))?; - - let out_v: Vec<&str> = out.split(' ').collect(); - if out_v.len() != 2 || out_v[0] != AGENT_FILENAME { - return Err(format!("version output invalid: {}", out)); + let version = String::from_utf8(out.stdout).context("agent version contains invalid char")?; + let v = version.split(' ').collect::>(); + if v.len() != 2 || v[0] != AGENT_FILENAME { + return Err(anyhow!("version output invalid: {}", version)); } - Ok(out) + Ok(version) } -fn run_self_update_script( - path: &str, - unzip_dir: &str, - script_filename: &str, -) -> Result<(), String> { +fn run_self_update_script(path: &str, unzip_dir: &str, script_filename: &str) -> Result<()> { let script = format!("{}{}/{}", path, unzip_dir, script_filename); #[cfg(unix)] let cmd = Command::new("sh").arg("-c").arg(script).output(); #[cfg(windows)] let cmd = wow64_disable_exc(move || Command::new(script.clone()).output()); - let out = cmd.map_err(|e| format!("self update run ret: {:?}", e))?; + let out = cmd.context("self update failed")?; let stdout = String::from_utf8_lossy(out.stdout.as_slice()); let stderr = String::from_utf8_lossy(out.stderr.as_slice()); debug!("stdout of self update script:[{}]", stdout); @@ -256,26 +237,24 @@ fn run_self_update_script( out.status .success() .then_some(()) - .ok_or(format!("ret code: {:?}", out.status.code())) + .context(format!("exit code: {:?}", out.status.code())) } -pub fn try_restart_agent() -> Result<(), String> { - cfg_if::cfg_if! { - if #[cfg(unix)] { - let script = format!("{}{}/{}", SELF_UPDATE_PATH, UPDATE_FILE_UNZIP_DIR, INSTALL_SCRIPT); - set_execute_permission(script.clone()).map_err(|e|format!("set execute permission failed: {:?}", e))?; - let cmd = Command::new("sh") - .args(&["-c", format!("{} restart", script).as_str()]) - .output(); - } else if #[cfg(windows)] { - let cmd = wow64_disable_exc(move ||{ - Command::new("cmd.exe") - .args(&["/C", "sc stop tatsvc & sc start tatsvc"]) - .output()}); - } - } +pub fn try_restart_agent() -> Result<()> { + #[cfg(unix)] + let cmd = { + let path = format!("{SELF_UPDATE_PATH}{UPDATE_FILE_UNZIP_DIR}/{INSTALL_SCRIPT}"); + set_execute_permission(&path).context("set execute permission failed")?; + let script = format!("{path} restart"); + Command::new("sh").args(&["-c", &script]).output() + }; + #[cfg(windows)] + let cmd = wow64_disable_exc(move || { + let script = "sc stop tatsvc & sc start tatsvc"; + Command::new("cmd.exe").args(&["/C", script]).output() + }); - let out = cmd.map_err(|e| format!("run cmd failed: {:?}", e))?; + let out = cmd.context("try restart agent failed")?; let stdout = String::from_utf8_lossy(out.stdout.as_slice()); let stderr = String::from_utf8_lossy(out.stderr.as_slice()); debug!("stdout of try restart agent:[{}]", stdout); @@ -284,7 +263,7 @@ pub fn try_restart_agent() -> Result<(), String> { out.status .success() .then_some(()) - .ok_or(format!("ret code: {:?}", out.status.code())) + .context(format!("exit code: {:?}", out.status.code())) } #[cfg(test)] diff --git a/src/ontime/thread.rs b/src/ontime/thread.rs index 02e26ed..a48be49 100644 --- a/src/ontime/thread.rs +++ b/src/ontime/thread.rs @@ -10,9 +10,7 @@ use std::time::{Duration, SystemTime}; use log::{debug, info, warn}; -use crate::network::types::ws_msg::{WS_MSG_TYPE_CHECK_UPDATE, WS_MSG_TYPE_KICK}; -const ONTIME_KICK_SOURCE: &str = "ONTIME_KICK"; -const ONTIME_KICK_INTERVAL: u64 = 3600 * 24; +use crate::network::types::ws_msg::WS_MSG_TYPE_CHECK_UPDATE; const ONTIME_UPDATE_INTERVAL: u64 = 2 * 60 * 60; const ONTIME_THREAD_INTERVAL: u64 = 1; const ONTIME_CHECK_TASK_NUM: u64 = 10; @@ -28,8 +26,6 @@ pub fn run( let ret = thread::spawn(move || { let mut instant_leak = SystemTime::now(); - let mut instant_kick = SystemTime::now(); - let mut instant_update = SystemTime::now() - Duration::from_secs(ONTIME_UPDATE_INTERVAL - 10); @@ -44,8 +40,6 @@ pub fn run( loop { //leakage check check_resource_leakage(&mut instant_leak); - // inter-thread channel communication, very fast - check_ontime_kick(&mut instant_kick, dispatcher.clone()); // do self update in a new thread, will not block current thread check_ontime_update(&mut instant_update, &self_updating, &need_restart); // check running tasks number and need_restart flag to do graceful restart when no running tasks @@ -61,13 +55,14 @@ fn register_update_handlers( self_updating: &Arc, need_restart: &Arc, ) { - let self_updating_clone = self_updating.clone(); - let need_restart_clone = need_restart.clone(); - dispatcher.register(WS_MSG_TYPE_CHECK_UPDATE, move |_source: Vec| { - if self_updating_clone.fetch_or(true, Ordering::SeqCst) { - return; + dispatcher.register(WS_MSG_TYPE_CHECK_UPDATE, { + let self_updating = self_updating.clone(); + let need_restart = need_restart.clone(); + move |_| { + if !self_updating.fetch_or(true, Ordering::SeqCst) { + try_update(self_updating.clone(), need_restart.clone()); + } } - try_update(self_updating_clone.clone(), need_restart_clone.clone()); }); } @@ -77,7 +72,7 @@ fn check_interval_elapsed(instant_time: &mut SystemTime, secs: u64) -> bool { Ok(duration) if duration < interval => return false, // interval not reach, do nothing Ok(_) => (), Err(e) => { - warn!("get systemTime error: {:?}", e); + warn!("get systemTime error: {}", e); return false; } } @@ -87,16 +82,6 @@ fn check_interval_elapsed(instant_time: &mut SystemTime, secs: u64) -> bool { return true; } -fn check_ontime_kick(instant_kick: &mut SystemTime, dispatcher: Arc) { - if !check_interval_elapsed(instant_kick, ONTIME_KICK_INTERVAL) { - return; - } - dispatcher.dispatch( - WS_MSG_TYPE_KICK, - ONTIME_KICK_SOURCE.to_string().into_bytes(), - ); -} - fn check_ontime_update( instant_update: &mut SystemTime, self_updating: &Arc, @@ -111,14 +96,11 @@ fn check_ontime_update( } info!("start check self update"); - let self_updating_clone = self_updating.clone(); - let need_restart_clone = need_restart.clone(); - thread::Builder::new() - .name("update".to_string()) - .spawn(move || { - try_update(self_updating_clone, need_restart_clone); - }) - .ok(); + let _ = thread::Builder::new().name("update".to_string()).spawn({ + let self_updating = self_updating.clone(); + let need_restart = need_restart.clone(); + move || try_update(self_updating, need_restart) + }); } fn check_running_task_num( @@ -140,7 +122,7 @@ fn check_running_task_num( ); if let Err(e) = try_restart_agent() { - warn!("try restart agent failed: {:?}", e) + warn!("try restart agent failed: {}", e) } // should not comes here, because agent should has been killed when called `try_restart_agent`. diff --git a/src/sysinfo/mod.rs b/src/sysinfo/mod.rs index 648bf85..a102422 100644 --- a/src/sysinfo/mod.rs +++ b/src/sysinfo/mod.rs @@ -14,7 +14,6 @@ pub use self::windows::get_hostname; pub struct Uname { pub sys_name: String, - pub node_name: String, pub release: String, pub version: String, pub machine: String, diff --git a/src/sysinfo/unix.rs b/src/sysinfo/unix.rs index 96d5f47..feb765a 100644 --- a/src/sysinfo/unix.rs +++ b/src/sysinfo/unix.rs @@ -26,7 +26,6 @@ impl From for Uname { fn from(x: utsname) -> Self { let uname = Uname { sys_name: parse(&x.sysname), - node_name: parse(&x.nodename), release: parse(&x.release), version: parse(&x.version), machine: parse(&x.machine), diff --git a/src/sysinfo/windows.rs b/src/sysinfo/windows.rs index 0e53707..85f0f9f 100644 --- a/src/sysinfo/windows.rs +++ b/src/sysinfo/windows.rs @@ -7,7 +7,6 @@ impl Uname { pub fn new() -> io::Result { let uname = Uname { sys_name: String::from("Windows"), - node_name: String::from("unknown"), release: String::from("unknown"), version: String::from("unknown"), // TODO: need optimized with real arch.