diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 93862f31377..c8df4ebde23 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -243,6 +243,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-vec" version = "0.6.3" @@ -342,15 +348,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "chrono" -version = "0.4.43" +name = "chacha20" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ - "iana-time-zone", - "num-traits", - "serde", - "windows-link", + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", ] [[package]] @@ -403,11 +408,9 @@ checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" name = "code-cli" version = "0.1.0" dependencies = [ - "async-trait", - "base64", + "base64 0.21.7", "bytes", "cfg-if", - "chrono", "clap", "clap_lex 0.7.7", "console", @@ -418,16 +421,18 @@ dependencies = [ "flate2", "futures", "gethostname", + "http", + "http-body-util", "hyper", + "hyper-util", "indicatif", + "jiff", "keyring", - "lazy_static", "libc", "log", "open", - "opentelemetry", "pin-project", - "rand 0.9.3", + "rand 0.10.1", "regex", "reqwest", "rmp-serde", @@ -439,7 +444,7 @@ dependencies = [ "sysinfo", "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-util", "tunnels", @@ -525,6 +530,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -534,15 +548,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -803,12 +808,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -1016,35 +1015,11 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core 0.10.1", "wasip2", "wasip3", ] -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.13.0", - "slab", - "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.15.5" @@ -1101,23 +1076,34 @@ dependencies = [ [[package]] name = "http" -version = "0.2.12" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -1135,63 +1121,64 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.32" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ + "atomic-waker", "bytes", "futures-channel", "futures-core", - "futures-util", - "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.10", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", + "http-body-util", "hyper", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", ] [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.5.10", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", ] [[package]] @@ -1302,16 +1289,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.13.0" @@ -1373,6 +1350,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-docker" version = "0.2.0" @@ -1404,6 +1391,30 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "jiff" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "js-sys" version = "0.3.85" @@ -1442,9 +1453,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.181" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libredox" @@ -1565,9 +1576,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", @@ -1936,51 +1947,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" -dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk", -] - -[[package]] -name = "opentelemetry_api" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" -dependencies = [ - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "once_cell", - "opentelemetry_api", - "percent-encoding", - "rand 0.8.5", - "thiserror", - "tokio", - "tokio-stream", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -2138,6 +2104,15 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -2232,14 +2207,25 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.1", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -2297,6 +2283,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_hc" version = "0.2.0" @@ -2332,7 +2324,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2366,44 +2358,42 @@ checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" -version = "0.11.27" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-tls", - "ipnet", + "hyper-util", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-util", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg 0.50.0", ] [[package]] @@ -2449,7 +2439,7 @@ dependencies = [ "sha1", "sha2", "subtle", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-util", ] @@ -2484,7 +2474,7 @@ dependencies = [ "russh-cryptovec", "serde", "sha2", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "yasna", @@ -2531,12 +2521,12 @@ dependencies = [ ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-pki-types" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ - "base64", + "zeroize", ] [[package]] @@ -2545,12 +2535,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - [[package]] name = "schannel" version = "0.1.28" @@ -2684,18 +2668,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha1" version = "0.10.6" @@ -2703,7 +2675,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -2714,7 +2686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -2786,12 +2758,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2842,9 +2814,12 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -2873,20 +2848,20 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -2922,7 +2897,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", ] [[package]] @@ -2936,6 +2920,17 @@ dependencies = [ "syn 2.0.115", ] +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "time" version = "0.3.47" @@ -2967,9 +2962,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -2977,7 +2972,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2 0.6.3", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -2985,9 +2980,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -3017,9 +3012,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -3049,7 +3044,7 @@ version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap 2.13.0", + "indexmap", "serde_core", "serde_spanned", "toml_datetime 0.7.5+spec-1.1.0", @@ -3079,7 +3074,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.13.0", + "indexmap", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -3099,6 +3094,45 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.10.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[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.3" @@ -3144,48 +3178,45 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ - "byteorder", "bytes", "data-encoding", "http", "httparse", "log", "native-tls", - "rand 0.8.5", + "rand 0.9.4", "sha1", - "thiserror", - "url", - "utf-8", + "thiserror 2.0.18", ] [[package]] name = "tunnels" version = "0.1.0" -source = "git+https://github.com/microsoft/dev-tunnels?rev=8cae9b2a24c65c6c1958f5a0e77d72b23b5c6c30#8cae9b2a24c65c6c1958f5a0e77d72b23b5c6c30" dependencies = [ "async-trait", - "chrono", - "futures", + "futures-util", + "http-body-util", "hyper", + "hyper-util", + "jiff", "log", "os_info", + "percent-encoding", "rand 0.8.5", "reqwest", "russh", "russh-keys", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-tungstenite", "tokio-util", - "tungstenite", "url", - "urlencoding", "uuid", "winreg 0.8.0", ] @@ -3237,18 +3268,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3406,16 +3425,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.0", + "indexmap", "wasm-encoder", "wasmparser", ] [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -3432,7 +3451,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags 2.10.0", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap", "semver", ] @@ -3478,47 +3497,23 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.115", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.115", -] - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -3564,15 +3559,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3606,30 +3592,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3642,12 +3611,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3660,12 +3623,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3678,24 +3635,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3708,12 +3653,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3726,12 +3665,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3744,12 +3677,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3762,12 +3689,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.5.40" @@ -3840,7 +3761,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.13.0", + "indexmap", "prettyplease", "syn 2.0.115", "wasm-metadata", @@ -3871,7 +3792,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags 2.10.0", - "indexmap 2.13.0", + "indexmap", "log", "serde", "serde_derive", @@ -3890,7 +3811,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.0", + "indexmap", "log", "semver", "serde", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0389746bbec..c89eb27f57c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,34 +15,35 @@ name = "code" futures = "0.3.28" clap = { version = "4.3.0", features = ["derive", "env"] } open = "4.1.0" -reqwest = { version = "0.11.22", default-features = false, features = ["json", "stream", "native-tls"] } -tokio = { version = "1.38.2", features = ["full"] } +reqwest = { version = "0.13", default-features = false, features = ["json", "stream", "native-tls"] } +tokio = { version = "1.52", features = ["full"] } tokio-util = { version = "0.7.8", features = ["compat", "codec"] } flate2 = { version = "1.0.26", default-features = false, features = ["zlib"] } zip = { version = "0.6.6", default-features = false, features = ["time", "deflate-zlib"] } regex = "1.8.3" -lazy_static = "1.4.0" sysinfo = { version = "0.29.0", default-features = false } serde = { version = "1.0.163", features = ["derive"] } serde_json = "1.0.96" rmp-serde = "1.1.1" uuid = { version = "1.4", features = ["serde", "v4"] } dirs = "5.0.1" -rand = "0.9.3" -opentelemetry = { version = "0.19.0", features = ["rt-tokio"] } +rand = "0.10" serde_bytes = "0.11.9" -chrono = { version = "0.4.26", features = ["serde", "std", "clock"], default-features = false } +jiff = { version = "0.2", default-features = false, features = ["std", "serde"] } +http = "1" gethostname = "0.4.3" libc = "0.2.144" -tunnels = { git = "https://github.com/microsoft/dev-tunnels", rev = "8cae9b2a24c65c6c1958f5a0e77d72b23b5c6c30", default-features = false, features = ["connections"] } +# tunnels = { git = "https://github.com/microsoft/dev-tunnels", rev = "8cae9b2a24c65c6c1958f5a0e77d72b23b5c6c30", default-features = false, features = ["connections"] } +tunnels = { path = "C:\\Users\\conno\\Github\\dev-tunnels\\rs", default-features = false, features = ["connections"] } keyring = { version = "2.0.3", default-features = false, features = ["linux-secret-service-rt-tokio-crypto-openssl", "platform-windows", "platform-macos", "linux-keyutils"] } dialoguer = "0.10.4" -hyper = { version = "0.14.26", features = ["server", "http1", "runtime"] } +hyper = { version = "1", features = ["server", "http1", "client"] } +hyper-util = { version = "0.1", features = ["tokio"] } +http-body-util = "0.1" indicatif = "0.17.4" tempfile = "3.5.0" clap_lex = "0.7.0" url = "2.5.4" -async-trait = "0.1.68" log = "0.4.18" const_format = "0.2.31" sha2 = "0.10.6" diff --git a/cli/src/async_pipe.rs b/cli/src/async_pipe.rs index 78aed6fe3e7..efa8a770082 100644 --- a/cli/src/async_pipe.rs +++ b/cli/src/async_pipe.rs @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ use crate::{constants::APPLICATION_NAME, util::errors::CodeError}; -use async_trait::async_trait; +use std::future::Future; use std::path::{Path, PathBuf}; use std::pin::Pin; use std::task::{Context, Poll}; @@ -176,57 +176,6 @@ cfg_if::cfg_if! { } } -impl AsyncPipeListener { - pub fn into_pollable(self) -> PollableAsyncListener { - PollableAsyncListener { - listener: Some(self), - write_fut: tokio_util::sync::ReusableBoxFuture::new(make_accept_fut(None)), - } - } -} - -pub struct PollableAsyncListener { - listener: Option, - write_fut: tokio_util::sync::ReusableBoxFuture< - 'static, - (AsyncPipeListener, Result), - >, -} - -async fn make_accept_fut( - data: Option, -) -> (AsyncPipeListener, Result) { - match data { - Some(mut l) => { - let c = l.accept().await; - (l, c) - } - None => unreachable!("this future should not be pollable in this state"), - } -} - -impl hyper::server::accept::Accept for PollableAsyncListener { - type Conn = AsyncPipe; - type Error = CodeError; - - fn poll_accept( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - if let Some(l) = self.listener.take() { - self.write_fut.set(make_accept_fut(Some(l))) - } - - match self.write_fut.poll(cx) { - Poll::Ready((l, cnx)) => { - self.listener = Some(l); - Poll::Ready(Some(cnx)) - } - Poll::Pending => Poll::Pending, - } - } -} - /// Gets a random name for a pipe/socket on the platform pub fn get_socket_name() -> PathBuf { cfg_if::cfg_if! { @@ -243,28 +192,29 @@ pub type AcceptedRW = ( Box, ); -#[async_trait] pub trait AsyncRWAccepter { - async fn accept_rw(&mut self) -> Result; + fn accept_rw(&mut self) -> Pin> + Send + '_>>; } -#[async_trait] impl AsyncRWAccepter for AsyncPipeListener { - async fn accept_rw(&mut self) -> Result { - let pipe = self.accept().await?; - let (read, write) = socket_stream_split(pipe); - Ok((Box::new(read), Box::new(write))) + fn accept_rw(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { + let pipe = self.accept().await?; + let (read, write) = socket_stream_split(pipe); + Ok((Box::new(read) as Box, Box::new(write) as Box)) + }) } } -#[async_trait] impl AsyncRWAccepter for TcpListener { - async fn accept_rw(&mut self) -> Result { - let (stream, _) = self - .accept() - .await - .map_err(CodeError::AsyncPipeListenerFailed)?; - let (read, write) = tokio::io::split(stream); - Ok((Box::new(read), Box::new(write))) + fn accept_rw(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { + let (stream, _) = self + .accept() + .await + .map_err(CodeError::AsyncPipeListenerFailed)?; + let (read, write) = tokio::io::split(stream); + Ok((Box::new(read) as Box, Box::new(write) as Box)) + }) } } diff --git a/cli/src/auth.rs b/cli/src/auth.rs index d4d62a8bf10..cd8492065b2 100644 --- a/cli/src/auth.rs +++ b/cli/src/auth.rs @@ -10,18 +10,20 @@ use crate::{ trace, util::{ errors::{ - wrap, AnyError, CodeError, OAuthError, RefreshTokenNotAvailableError, StatusError, + wrap, AnyError, OAuthError, RefreshTokenNotAvailableError, StatusError, WrappedError, }, input::prompt_options, }, warning, }; -use async_trait::async_trait; -use chrono::{DateTime, Utc}; -use gethostname::gethostname; +use jiff::{SignedDuration, Timestamp}; +#[cfg(target_os = "linux")] +use crate::util::errors::CodeError; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc, thread}; +use std::{cell::Cell, fmt::Display, future::Future, path::PathBuf, pin::Pin, sync::Arc}; +#[cfg(target_os = "linux")] +use std::thread; use tokio::time::sleep; use tunnels::{ contracts::PROD_FIRST_PARTY_APP_ID, @@ -110,7 +112,7 @@ pub struct StoredCredential { #[serde(rename = "r")] refresh_token: Option, #[serde(rename = "e")] - expires_at: Option>, + expires_at: Option, } const GH_USER_ENDPOINT: &str = "https://api.github.com/user"; @@ -132,7 +134,7 @@ impl StoredCredential { match self.provider { AuthProvider::Microsoft => self .expires_at - .map(|e| Utc::now() + chrono::Duration::minutes(5) > e) + .map(|e| Timestamp::now() + SignedDuration::from_secs(5 * 60) > e) .unwrap_or(false), // Make an auth request to Github. Mark the credential as expired @@ -166,7 +168,7 @@ impl StoredCredential { refresh_token: auth.refresh_token, expires_at: auth .expires_in - .map(|e| Utc::now() + chrono::Duration::seconds(e)), + .map(|e| Timestamp::now() + SignedDuration::from_secs(e)), } } } @@ -226,10 +228,12 @@ const CONTINUE_MARKER: &str = ""; /// Implementation that wraps the KeyringStorage on Linux to avoid /// https://github.com/hwchen/keyring-rs/issues/132 +#[cfg(target_os = "linux")] struct ThreadKeyringStorage { s: Option, } +#[cfg(target_os = "linux")] impl ThreadKeyringStorage { fn thread_op(&mut self, f: Fn) -> Result where @@ -262,6 +266,7 @@ impl ThreadKeyringStorage { } } +#[cfg(target_os = "linux")] impl Default for ThreadKeyringStorage { fn default() -> Self { Self { @@ -270,6 +275,7 @@ impl Default for ThreadKeyringStorage { } } +#[cfg(target_os = "linux")] impl StorageImplementation for ThreadKeyringStorage { fn read(&mut self) -> Result, AnyError> { self.thread_op(|s| s.read()) @@ -494,7 +500,7 @@ impl Auth { // soon in order to get the real expiry time. expires_at: refresh_token .as_ref() - .map(|_| Utc::now() + chrono::Duration::minutes(5)), + .map(|_| Timestamp::now() + SignedDuration::from_secs(5 * 60)), refresh_token, }, None => self.do_device_code_flow_with_provider(provider).await?, @@ -718,7 +724,8 @@ impl Auth { } let init_code_json = init_code.json::().await?; - let expires_at = Utc::now() + chrono::Duration::seconds(init_code_json.expires_in); + let expires_at = + Timestamp::now() + SignedDuration::from_secs(init_code_json.expires_in); match &init_code_json.message { Some(m) => self.log.result(m), @@ -735,7 +742,7 @@ impl Auth { ); let mut interval_s = 5; - while Utc::now() < expires_at { + while Timestamp::now() < expires_at { sleep(std::time::Duration::from_secs(interval_s)).await; match self.do_grant(provider, body.clone()).await { @@ -772,7 +779,19 @@ impl Auth { min_refresh } else { match credential.expires_at { - Some(d) => ((d - Utc::now()) * 2 / 3).to_std().unwrap_or(min_refresh), + Some(d) => { + let dur = d.duration_since(Timestamp::now()); + let nanos = dur.as_nanos() * 2 / 3; + let scaled = SignedDuration::new( + (nanos / 1_000_000_000) as i64, + (nanos % 1_000_000_000) as i32, + ); + if scaled.is_negative() { + min_refresh + } else { + scaled.unsigned_abs() + } + } None => default_refresh, } }; @@ -807,18 +826,25 @@ impl Auth { } } -#[async_trait] impl AuthorizationProvider for Auth { - async fn get_authorization(&self) -> Result { - self.get_tunnel_authentication() - .await - .map_err(|e| HttpError::AuthorizationError(e.to_string())) + fn get_authorization( + &self, + ) -> Pin> + Send + '_>> { + Box::pin(async move { + self.get_tunnel_authentication() + .await + .map_err(|e| HttpError::AuthorizationError(e.to_string())) + }) } } -lazy_static::lazy_static! { - static ref HOSTNAME: Vec = gethostname().to_string_lossy().bytes().collect(); -} +#[cfg(feature = "vscode-encrypt")] +static HOSTNAME: std::sync::LazyLock> = std::sync::LazyLock::new(|| { + gethostname::gethostname() + .to_string_lossy() + .bytes() + .collect() +}); #[cfg(feature = "vscode-encrypt")] fn encrypt(value: &str) -> String { diff --git a/cli/src/bin/code/main.rs b/cli/src/bin/code/main.rs index 6c301ca9502..fda5fc36145 100644 --- a/cli/src/bin/code/main.rs +++ b/cli/src/bin/code/main.rs @@ -19,8 +19,6 @@ use cli::{ }, }; use legacy_args::try_parse_legacy; -use opentelemetry::sdk::trace::TracerProvider as SdkTracerProvider; -use opentelemetry::trace::TracerProvider; #[tokio::main] async fn main() -> Result<(), std::convert::Infallible> { @@ -143,8 +141,7 @@ fn make_logger(core: &args::CliCore) -> log::Logger { core.global_options.log.unwrap_or(log::Level::Info) }; - let tracer = SdkTracerProvider::builder().build().tracer("codecli"); - let mut log = log::Logger::new(tracer, log_level); + let mut log = log::Logger::new(log_level); if let Some(f) = &core.global_options.log_to_file { log = log .with_sink(log::FileLogSink::new(log_level, f).expect("expected to make file logger")) diff --git a/cli/src/commands/agent_host.rs b/cli/src/commands/agent_host.rs index bfa0644b2ec..d3c4a11ee77 100644 --- a/cli/src/commands/agent_host.rs +++ b/cli/src/commands/agent_host.rs @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use std::convert::Infallible; use std::fs; use std::io::{Read, Write}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use hyper::service::{make_service_fn, service_fn}; -use hyper::Server; +use hyper::server::conn::http1; +use hyper::service::service_fn; +use hyper_util::rt::TokioIo; +use tokio::net::TcpListener; use crate::log; use crate::tunnels::agent_host::{handle_request, AgentHostConfig, AgentHostManager}; @@ -88,8 +89,8 @@ pub async fn agent_host(ctx: CommandContext, mut args: AgentHostArgs) -> Result< Some(h) => SocketAddr::new(h.parse().map_err(CodeError::InvalidHostAddress)?, args.port), None => SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), args.port), }; - let builder = Server::try_bind(&addr).map_err(CodeError::CouldNotListenOnInterface)?; - let bound_addr = builder.local_addr(); + let listener = TcpListener::bind(addr).await.map_err(CodeError::CouldNotListenOnInterface)?; + let bound_addr = listener.local_addr().map_err(CodeError::CouldNotListenOnInterface)?; let mut url = format!("ws://{bound_addr}"); if let Some(ct) = &args.connection_token { @@ -98,25 +99,33 @@ pub async fn agent_host(ctx: CommandContext, mut args: AgentHostArgs) -> Result< ctx.log .result(format!("Agent host proxy listening on {url}")); - let manager_for_svc = manager.clone(); - let make_svc = move || { - let mgr = manager_for_svc.clone(); - let service = service_fn(move |req| { - let mgr = mgr.clone(); - async move { handle_request(mgr, req).await } - }); - async move { Ok::<_, Infallible>(service) } - }; + loop { + tokio::select! { + result = listener.accept() => { + let (stream, _) = match result { + Ok(r) => r, + Err(_) => continue, + }; + let mgr = manager.clone(); + tokio::spawn(async move { + let svc = service_fn(move |req| { + let mgr = mgr.clone(); + async move { handle_request(mgr, req).await } + }); + if let Err(e) = http1::Builder::new() + .serve_connection(TokioIo::new(stream), svc) + .with_upgrades() + .await + { + let _ = e; // connection closed + } + }); + } + _ = shutdown.wait() => break, + } + } - let server_future = builder - .serve(make_service_fn(|_| make_svc())) - .with_graceful_shutdown(async { - let _ = shutdown.wait().await; - }); - - let r = server_future.await; manager.kill_running_server().await; - r.map_err(CodeError::CouldNotListenOnInterface)?; Ok(0) } diff --git a/cli/src/commands/serve_web.rs b/cli/src/commands/serve_web.rs index d3a9a88a87d..58fdbabf9d1 100644 --- a/cli/src/commands/serve_web.rs +++ b/cli/src/commands/serve_web.rs @@ -12,8 +12,14 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use hyper::service::{make_service_fn, service_fn}; -use hyper::{Body, Request, Response, Server}; +use ::http::{Request, Response}; +use http_body_util::BodyExt; +use hyper::body::Incoming; +use hyper::server::conn::http1; +use hyper::service::service_fn; +use hyper_util::rt::TokioIo; +use tokio::net::TcpListener; +use crate::util::http::{HyperBody, full_body, empty_body}; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::{pin, time}; @@ -100,30 +106,33 @@ pub async fn serve_web(ctx: CommandContext, mut args: ServeWebArgs) -> Result(service) } - }; let mut shutdown = ShutdownRequest::create_rx([ShutdownRequest::CtrlC]); - let r = if let Some(s) = args.socket_path { + if let Some(s) = args.socket_path { let s = PathBuf::from(&s); - let socket = listen_socket_rw_stream(&s).await?; + let mut socket = listen_socket_rw_stream(&s).await?; ctx.log .result(format!("Web UI available on {}", s.display())); - let r = Server::builder(socket.into_pollable()) - .serve(make_service_fn(|_| make_svc())) - .with_graceful_shutdown(async { - let _ = shutdown.wait().await; - }) - .await; + loop { + tokio::select! { + result = socket.accept() => { + let conn = match result { + Ok(c) => c, + Err(_) => continue, + }; + let ctx = HandleContext { cm: cm.clone(), log: cm.log.clone(), server_secret_key: key.clone() }; + tokio::spawn(async move { + let svc = service_fn(move |req| handle(ctx.clone(), req)); + let _ = http1::Builder::new() + .serve_connection(TokioIo::new(conn), svc) + .with_upgrades() + .await; + }); + } + _ = shutdown.wait() => break, + } + } let _ = std::fs::remove_file(&s); // cleanup - r } else { let addr: SocketAddr = match &args.host { Some(h) => { @@ -131,10 +140,10 @@ pub async fn serve_web(ctx: CommandContext, mut args: ServeWebArgs) -> Result SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), args.port), }; - let builder = Server::try_bind(&addr).map_err(CodeError::CouldNotListenOnInterface)?; + let listener = TcpListener::bind(addr).await.map_err(CodeError::CouldNotListenOnInterface)?; // Get the actual bound address (important when port 0 is used for random port assignment) - let bound_addr = builder.local_addr(); + let bound_addr = listener.local_addr().map_err(CodeError::CouldNotListenOnInterface)?; let mut listening = format!("Web UI available at http://{bound_addr}"); if let Some(base) = args.server_base_path { if !base.starts_with('/') { @@ -147,16 +156,27 @@ pub async fn serve_web(ctx: CommandContext, mut args: ServeWebArgs) -> Result { + let (stream, _) = match result { + Ok(r) => r, + Err(_) => continue, + }; + let ctx = HandleContext { cm: cm.clone(), log: cm.log.clone(), server_secret_key: key.clone() }; + tokio::spawn(async move { + let svc = service_fn(move |req| handle(ctx.clone(), req)); + let _ = http1::Builder::new() + .serve_connection(TokioIo::new(stream), svc) + .with_upgrades() + .await; + }); + } + _ = shutdown.wait() => break, + } + } }; - r.map_err(CodeError::CouldNotListenOnInterface)?; - Ok(0) } @@ -168,7 +188,7 @@ struct HandleContext { } /// Handler function for an inbound request -async fn handle(ctx: HandleContext, req: Request) -> Result, Infallible> { +async fn handle(ctx: HandleContext, req: Request) -> Result, Infallible> { let client_key_half = get_client_key_half(&req); let path = req.uri().path(); @@ -185,7 +205,7 @@ async fn handle(ctx: HandleContext, req: Request) -> Result Ok(res) } -async fn handle_proxied(ctx: &HandleContext, req: Request) -> Response { +async fn handle_proxied(ctx: &HandleContext, req: Request) -> Response { let release = if let Some((r, _)) = get_release_from_path(req.uri().path(), ctx.cm.platform) { r } else { @@ -200,7 +220,7 @@ async fn handle_proxied(ctx: &HandleContext, req: Request) -> Response { - if req.headers().contains_key(hyper::header::UPGRADE) { + if req.headers().contains_key(::http::header::UPGRADE) { forward_ws_req_to_server(ctx.log.clone(), rw, req).await } else { forward_http_req_to_server(rw, req).await @@ -211,7 +231,7 @@ async fn handle_proxied(ctx: &HandleContext, req: Request) -> Response) -> Response { +fn handle_secret_mint(ctx: &HandleContext, req: Request) -> Response { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); @@ -227,18 +247,18 @@ fn handle_secret_mint(ctx: &HandleContext, req: Request) -> Response /// and maintains the http-only cookie the client will use for cookies. fn append_secret_headers( base_path: &str, - res: &mut Response, + res: &mut Response, client_key_half: &SecretKeyPart, ) { let headers = res.headers_mut(); headers.append( - hyper::header::SET_COOKIE, + ::http::header::SET_COOKIE, format!("{PATH_COOKIE_NAME}={base_path}{SECRET_KEY_MINT_PATH}; SameSite=Strict; Path=/",) .parse() .unwrap(), ); headers.append( - hyper::header::SET_COOKIE, + ::http::header::SET_COOKIE, format!( "{}={}; SameSite=Strict; HttpOnly; Max-Age=2592000; Path=/", SECRET_KEY_COOKIE_NAME, @@ -284,20 +304,20 @@ fn get_release_from_path(path: &str, platform: Platform) -> Option<(Release, Str /// Proxies the standard HTTP request to the async pipe, returning the piped response async fn forward_http_req_to_server( (rw, handle): (AsyncPipe, ConnectionHandle), - req: Request, -) -> Response { + req: Request, +) -> Response { let (mut request_sender, connection) = - match hyper::client::conn::Builder::new().handshake(rw).await { + match hyper::client::conn::http1::handshake(TokioIo::new(rw)).await { Ok(r) => r, Err(e) => return response::connection_err(e), }; tokio::spawn(connection); - let res = request_sender - .send_request(req) - .await - .unwrap_or_else(response::connection_err); + let res = match request_sender.send_request(req).await { + Ok(res) => res.map(|b| b.boxed()), + Err(e) => response::connection_err(e), + }; // technically, we should buffer the body into memory since it may not be // read at this point, but because the keepalive time is very large @@ -312,11 +332,11 @@ async fn forward_http_req_to_server( async fn forward_ws_req_to_server( log: log::Logger, (rw, handle): (AsyncPipe, ConnectionHandle), - mut req: Request, -) -> Response { + mut req: Request, +) -> Response { // splicing of client and servers inspired by https://github.com/hyperium/hyper/blob/fece9f7f50431cf9533cfe7106b53a77b48db699/examples/upgrades.rs let (mut request_sender, connection) = - match hyper::client::conn::Builder::new().handshake(rw).await { + match hyper::client::conn::http1::handshake(TokioIo::new(rw)).await { Ok(r) => r, Err(e) => return response::connection_err(e), }; @@ -328,19 +348,22 @@ async fn forward_ws_req_to_server( proxied_req = proxied_req.header(k, v); } - let mut res = request_sender - .send_request(proxied_req.body(Body::empty()).unwrap()) + let mut res = match request_sender + .send_request(proxied_req.body(http_body_util::Empty::::new()).unwrap()) .await - .unwrap_or_else(response::connection_err); + { + Ok(r) => r, + Err(e) => return response::connection_err(e), + }; - let mut proxied_res = Response::new(Body::empty()); + let mut proxied_res = Response::new(empty_body()); *proxied_res.status_mut() = res.status(); for (k, v) in res.headers() { proxied_res.headers_mut().insert(k, v.clone()); } // only start upgrade at this point in case the server decides to deny socket - if res.status() == hyper::StatusCode::SWITCHING_PROTOCOLS { + if res.status() == ::http::StatusCode::SWITCHING_PROTOCOLS { tokio::spawn(async move { let (s_req, s_res) = tokio::join!(hyper::upgrade::on(&mut req), hyper::upgrade::on(&mut res)); @@ -352,8 +375,10 @@ async fn forward_ws_req_to_server( ), (Err(e1), _) => debug!(log, "client ({}) websocket upgrade failed", e1), (_, Err(e2)) => debug!(log, "server ({}) websocket upgrade failed", e2), - (Ok(mut s_req), Ok(mut s_res)) => { + (Ok(s_req), Ok(s_res)) => { trace!(log, "websocket upgrade succeeded"); + let mut s_req = TokioIo::new(s_req); + let mut s_res = TokioIo::new(s_res); let r = tokio::io::copy_bidirectional(&mut s_req, &mut s_res).await; trace!(log, "websocket closed (error: {:?})", r.err()); } @@ -372,8 +397,8 @@ fn is_commit_hash(s: &str) -> bool { } /// Gets a cookie from the request by name. -fn extract_cookie(req: &Request, name: &str) -> Option { - for h in req.headers().get_all(hyper::header::COOKIE) { +fn extract_cookie(req: &Request, name: &str) -> Option { + for h in req.headers().get_all(::http::header::COOKIE) { if let Ok(str) = h.to_str() { for pair in str.split("; ") { let i = match pair.find('=') { @@ -432,7 +457,7 @@ fn get_server_key_half(paths: &LauncherPaths) -> SecretKeyPart { } /// Gets the client's half of the secret key. -fn get_client_key_half(req: &Request) -> SecretKeyPart { +fn get_client_key_half(req: &Request) -> SecretKeyPart { if let Some(c) = extract_cookie(req, SECRET_KEY_COOKIE_NAME) { if let Ok(sk) = SecretKeyPart::decode(&c) { return sk; @@ -450,33 +475,33 @@ mod response { use super::*; - pub fn connection_err(err: hyper::Error) -> Response { + pub fn connection_err(err: hyper::Error) -> Response { Response::builder() .status(503) - .body(Body::from(format!("Error connecting to server: {err:?}"))) + .body(full_body(format!("Error connecting to server: {err:?}"))) .unwrap() } - pub fn code_err(err: CodeError) -> Response { + pub fn code_err(err: CodeError) -> Response { Response::builder() .status(500) - .body(Body::from(format!("Error serving request: {err}"))) + .body(full_body(format!("Error serving request: {err}"))) .unwrap() } - pub fn wait_for_download() -> Response { + pub fn wait_for_download() -> Response { Response::builder() .status(202) .header("Content-Type", "text/html") // todo: get latest - .body(Body::from(concatcp!("The latest version of the ", QUALITYLESS_SERVER_NAME, " is downloading, please wait a moment...", ))) + .body(full_body(concatcp!("The latest version of the ", QUALITYLESS_SERVER_NAME, " is downloading, please wait a moment...", ))) .unwrap() } - pub fn secret_key(hash: Vec) -> Response { + pub fn secret_key(hash: Vec) -> Response { Response::builder() .status(200) .header("Content-Type", "application/octet-stream") // todo: get latest - .body(Body::from(hash)) + .body(full_body(hash)) .unwrap() } } @@ -634,7 +659,7 @@ impl ConnectionManager { let target_kind = TargetKind::Web; let quality = VSCODE_CLI_QUALITY - .ok_or_else(|| CodeError::UpdatesNotConfigured("no configured quality")) + .ok_or(CodeError::UpdatesNotConfigured("no configured quality")) .and_then(|q| { Quality::try_from(q).map_err(|_| CodeError::UpdatesNotConfigured("unknown quality")) })?; diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs index 8f99f8d37d6..3a9fa375f99 100644 --- a/cli/src/commands/tunnels.rs +++ b/cli/src/commands/tunnels.rs @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use async_trait::async_trait; use base64::{engine::general_purpose as b64, Engine as _}; use futures::{stream::FuturesUnordered, StreamExt}; use serde::Serialize; @@ -118,7 +117,6 @@ impl TunnelServiceContainer { } } -#[async_trait] impl ServiceContainer for TunnelServiceContainer { async fn run_service( &mut self, @@ -639,7 +637,7 @@ async fn serve_with_csa( let mut server = make_singleton_server(log_broadcast.clone(), log.clone(), server, shutdown.clone()); - let platform = spanf!(log, log.span("prereq"), PreReqChecker::new().verify())?; + let platform = PreReqChecker::new().verify().await?; let _lock = app_mutex_name.map(AppMutex::new); let auth = Auth::new(&paths, log.clone()); diff --git a/cli/src/constants.rs b/cli/src/constants.rs index 9e2b066d741..f6979db0157 100644 --- a/cli/src/constants.rs +++ b/cli/src/constants.rs @@ -7,7 +7,7 @@ use serde::Deserialize; use std::{collections::HashMap, io::IsTerminal}; use const_format::concatcp; -use lazy_static::lazy_static; +use std::sync::LazyLock; use crate::options::Quality; @@ -107,27 +107,25 @@ pub struct ServerQualityInfo { pub server_application_name: String, } -lazy_static! { - pub static ref TUNNEL_SERVICE_USER_AGENT: String = - match std::env::var(TUNNEL_SERVICE_USER_AGENT_ENV_VAR) { - Ok(ua) if !ua.is_empty() => format!("{} {}", ua, get_default_user_agent()), - _ => get_default_user_agent(), - }; +pub static TUNNEL_SERVICE_USER_AGENT: LazyLock = + LazyLock::new(|| match std::env::var(TUNNEL_SERVICE_USER_AGENT_ENV_VAR) { + Ok(ua) if !ua.is_empty() => format!("{} {}", ua, get_default_user_agent()), + _ => get_default_user_agent(), + }); - /// Map of qualities to the server name - pub static ref SERVER_NAME_MAP: Option> = - option_env!("VSCODE_CLI_TUNNEL_SERVER_QUALITIES").and_then(|s| serde_json::from_str(s).unwrap()); +/// Map of qualities to the server name +pub static SERVER_NAME_MAP: LazyLock>> = + LazyLock::new(|| option_env!("VSCODE_CLI_TUNNEL_SERVER_QUALITIES").and_then(|s| serde_json::from_str(s).unwrap())); - /// Whether i/o interactions are allowed in the current CLI. - pub static ref IS_A_TTY: bool = std::io::stdin().is_terminal(); +/// Whether i/o interactions are allowed in the current CLI. +pub static IS_A_TTY: LazyLock = LazyLock::new(|| std::io::stdin().is_terminal()); - /// Whether i/o interactions are allowed in the current CLI. - pub static ref COLORS_ENABLED: bool = *IS_A_TTY && std::env::var(NO_COLOR_ENV).is_err(); +/// Whether i/o interactions are allowed in the current CLI. +pub static COLORS_ENABLED: LazyLock = LazyLock::new(|| *IS_A_TTY && std::env::var(NO_COLOR_ENV).is_err()); - /// Whether i/o interactions are allowed in the current CLI. - pub static ref IS_INTERACTIVE_CLI: bool = *IS_A_TTY && std::env::var(NONINTERACTIVE_VAR).is_err(); +/// Whether i/o interactions are allowed in the current CLI. +pub static IS_INTERACTIVE_CLI: LazyLock = LazyLock::new(|| *IS_A_TTY && std::env::var(NONINTERACTIVE_VAR).is_err()); - /// Map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}` - pub static ref WIN32_APP_IDS: Option> = - option_env!("VSCODE_CLI_WIN32_APP_IDS").map(|s| s.split(',').map(|s| s.to_string()).collect()); -} +/// Map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}` +pub static WIN32_APP_IDS: LazyLock>> = + LazyLock::new(|| option_env!("VSCODE_CLI_WIN32_APP_IDS").map(|s| s.split(',').map(|s| s.to_string()).collect())); diff --git a/cli/src/desktop/version_manager.rs b/cli/src/desktop/version_manager.rs index e9cd1a10450..5eb3ea60490 100644 --- a/cli/src/desktop/version_manager.rs +++ b/cli/src/desktop/version_manager.rs @@ -9,8 +9,8 @@ use std::{ path::{Path, PathBuf}, }; -use lazy_static::lazy_static; use regex::Regex; +use std::sync::LazyLock; use serde::{Deserialize, Serialize}; use crate::{ @@ -33,9 +33,7 @@ pub enum RequestedVersion { Path(String), } -lazy_static! { - static ref COMMIT_RE: Regex = Regex::new(r"(?i)^[0-9a-f]{40}$").unwrap(); -} +static COMMIT_RE: LazyLock = LazyLock::new(|| Regex::new(r"(?i)^[0-9a-f]{40}$").unwrap()); impl RequestedVersion { pub fn get_command(&self) -> String { diff --git a/cli/src/lib.rs b/cli/src/lib.rs index b2e23cb4d69..86002533794 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +#![allow(async_fn_in_trait)] // todo: we should reduce the exported surface area over time as things are // moved into a common CLI diff --git a/cli/src/log.rs b/cli/src/log.rs index f58f49b2176..3b2bca5ce17 100644 --- a/cli/src/log.rs +++ b/cli/src/log.rs @@ -3,11 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use chrono::Local; -use opentelemetry::{ - sdk::trace::{Tracer, TracerProvider}, - trace::{SpanBuilder, Tracer as TraitTracer, TracerProvider as TracerProviderTrait}, -}; +use jiff::Zoned; use serde::{Deserialize, Serialize}; use std::fmt; use std::{ @@ -103,7 +99,6 @@ pub fn new_rpc_prefix() -> String { // Base logger implementation #[derive(Clone)] pub struct Logger { - tracer: Arc, sink: Vec>, prefix: Option, } @@ -199,28 +194,18 @@ impl LogSink for FileLogSink { impl Logger { pub fn test() -> Self { Self { - tracer: Arc::new(TracerProvider::builder().build().tracer("codeclitest")), sink: vec![], prefix: None, } } - pub fn new(tracer: Tracer, level: Level) -> Self { + pub fn new(level: Level) -> Self { Self { - tracer: Arc::new(tracer), sink: vec![Box::new(StdioLogSink { level })], prefix: None, } } - pub fn span(&self, name: &str) -> SpanBuilder { - self.tracer.span_builder(format!("serverlauncher/{name}")) - } - - pub fn tracer(&self) -> &Tracer { - &self.tracer - } - pub fn emit(&self, level: Level, message: &str) { let prefix = self.prefix.as_deref().unwrap_or(""); for sink in &self.sink { @@ -305,8 +290,8 @@ impl crate::util::io::ReportCopyProgress for DownloadLogger<'_> { } fn format(level: Level, prefix: &str, message: &str, use_colors: bool) -> String { - let current = Local::now(); - let timestamp = current.format("%Y-%m-%d %H:%M:%S").to_string(); + let current = Zoned::now(); + let timestamp = current.strftime("%Y-%m-%d %H:%M:%S").to_string(); let name = level.name().unwrap(); @@ -421,42 +406,3 @@ macro_rules! warning { $logger.emit(log::Level::Warn, &format!($($fmt),+)) }; } - -#[macro_export] -macro_rules! span { - ($logger:expr, $span:expr, $func:expr) => {{ - use opentelemetry::trace::TraceContextExt; - - let span = $span.start($logger.tracer()); - let cx = opentelemetry::Context::current_with_span(span); - let guard = cx.clone().attach(); - let t = $func; - - if let Err(e) = &t { - cx.span().record_error(e); - } - - std::mem::drop(guard); - - t - }}; -} - -#[macro_export] -macro_rules! spanf { - ($logger:expr, $span:expr, $func:expr) => {{ - use opentelemetry::trace::{FutureExt, TraceContextExt}; - - let span = $span.start($logger.tracer()); - let cx = opentelemetry::Context::current_with_span(span); - let t = $func.with_context(cx.clone()).await; - - if let Err(e) = &t { - cx.span().record_error(e); - } - - cx.span().end(); - - t - }}; -} diff --git a/cli/src/self_update.rs b/cli/src/self_update.rs index 45d661e5af9..21d6d6c7566 100644 --- a/cli/src/self_update.rs +++ b/cli/src/self_update.rs @@ -30,15 +30,15 @@ static OLD_UPDATE_EXTENSION: &str = "Updating CLI"; impl<'a> SelfUpdate<'a> { pub fn new(update_service: &'a UpdateService) -> Result { let commit = VSCODE_CLI_COMMIT - .ok_or_else(|| CodeError::UpdatesNotConfigured("unknown build commit"))?; + .ok_or(CodeError::UpdatesNotConfigured("unknown build commit"))?; let quality = VSCODE_CLI_QUALITY - .ok_or_else(|| CodeError::UpdatesNotConfigured("no configured quality")) + .ok_or(CodeError::UpdatesNotConfigured("no configured quality")) .and_then(|q| { Quality::try_from(q).map_err(|_| CodeError::UpdatesNotConfigured("unknown quality")) })?; - let platform = Platform::env_default().ok_or_else(|| { + let platform = Platform::env_default().ok_or({ CodeError::UpdatesNotConfigured("Unknown platform, please report this error") })?; diff --git a/cli/src/tunnels/agent_host.rs b/cli/src/tunnels/agent_host.rs index 9d1f240c509..46786ba4f5a 100644 --- a/cli/src/tunnels/agent_host.rs +++ b/cli/src/tunnels/agent_host.rs @@ -8,11 +8,15 @@ use std::path::PathBuf; use std::sync::Arc; use std::time::{Duration, Instant}; -use hyper::{Body, Request, Response}; +use hyper::body::Incoming; +use ::http::{Request, Response}; +use http_body_util::BodyExt; +use hyper_util::rt::TokioIo; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::sync::Mutex; use crate::async_pipe::{get_socket_name, get_socket_rw_stream, AsyncPipe}; +use crate::util::http::{HyperBody, full_body, empty_body}; use crate::constants::VSCODE_CLI_QUALITY; use crate::download_cache::DownloadCache; use crate::log; @@ -318,7 +322,7 @@ impl AgentHostManager { } let quality = VSCODE_CLI_QUALITY - .ok_or_else(|| CodeError::UpdatesNotConfigured("no configured quality")) + .ok_or(CodeError::UpdatesNotConfigured("no configured quality")) .and_then(|q| { Quality::try_from(q).map_err(|_| CodeError::UpdatesNotConfigured("unknown quality")) })?; @@ -389,7 +393,7 @@ impl AgentHostManager { let now = Instant::now(); let quality = VSCODE_CLI_QUALITY - .ok_or_else(|| CodeError::UpdatesNotConfigured("no configured quality")) + .ok_or(CodeError::UpdatesNotConfigured("no configured quality")) .and_then(|q| { Quality::try_from(q).map_err(|_| CodeError::UpdatesNotConfigured("unknown quality")) })?; @@ -472,20 +476,20 @@ impl AgentHostManager { /// Proxies an incoming HTTP/WebSocket request to the agent host's Unix socket. pub async fn handle_request( manager: Arc, - req: Request, -) -> Result, Infallible> { + req: Request, +) -> Result, Infallible> { let socket_path = match manager.ensure_server().await { Ok(p) => p, Err(e) => { error!(manager.log, "Error starting agent host: {:?}", e); return Ok(Response::builder() .status(503) - .body(Body::from(format!("Error starting agent host: {e:?}"))) + .body(full_body(format!("Error starting agent host: {e:?}"))) .unwrap()); } }; - let is_upgrade = req.headers().contains_key(hyper::header::UPGRADE); + let is_upgrade = req.headers().contains_key(::http::header::UPGRADE); let rw = match get_socket_rw_stream(&socket_path).await { Ok(rw) => rw, @@ -496,7 +500,7 @@ pub async fn handle_request( ); return Ok(Response::builder() .status(503) - .body(Body::from(format!("Error connecting to agent host: {e:?}"))) + .body(full_body(format!("Error connecting to agent host: {e:?}"))) .unwrap()); } }; @@ -509,25 +513,25 @@ pub async fn handle_request( } /// Proxies a standard HTTP request through the socket. -async fn forward_http_to_server(rw: AsyncPipe, req: Request) -> Response { +async fn forward_http_to_server(rw: AsyncPipe, req: Request) -> Response { let (mut request_sender, connection) = - match hyper::client::conn::Builder::new().handshake(rw).await { + match hyper::client::conn::http1::handshake(TokioIo::new(rw)).await { Ok(r) => r, Err(e) => return connection_err(e), }; tokio::spawn(connection); - request_sender - .send_request(req) - .await - .unwrap_or_else(connection_err) + match request_sender.send_request(req).await { + Ok(res) => res.map(|b| b.boxed()), + Err(e) => connection_err(e), + } } /// Proxies a WebSocket upgrade request through the socket. -async fn forward_ws_to_server(rw: AsyncPipe, mut req: Request) -> Response { +async fn forward_ws_to_server(rw: AsyncPipe, mut req: Request) -> Response { let (mut request_sender, connection) = - match hyper::client::conn::Builder::new().handshake(rw).await { + match hyper::client::conn::http1::handshake(TokioIo::new(rw)).await { Ok(r) => r, Err(e) => return connection_err(e), }; @@ -539,23 +543,28 @@ async fn forward_ws_to_server(rw: AsyncPipe, mut req: Request) -> Response proxied_req = proxied_req.header(k, v); } - let mut res = request_sender - .send_request(proxied_req.body(Body::empty()).unwrap()) + let mut res = match request_sender + .send_request(proxied_req.body(http_body_util::Empty::::new()).unwrap()) .await - .unwrap_or_else(connection_err); + { + Ok(r) => r, + Err(e) => return connection_err(e), + }; - let mut proxied_res = Response::new(Body::empty()); + let mut proxied_res = Response::new(empty_body()); *proxied_res.status_mut() = res.status(); for (k, v) in res.headers() { proxied_res.headers_mut().insert(k, v.clone()); } - if res.status() == hyper::StatusCode::SWITCHING_PROTOCOLS { + if res.status() == ::http::StatusCode::SWITCHING_PROTOCOLS { tokio::spawn(async move { let (s_req, s_res) = tokio::join!(hyper::upgrade::on(&mut req), hyper::upgrade::on(&mut res)); - if let (Ok(mut s_req), Ok(mut s_res)) = (s_req, s_res) { + if let (Ok(s_req), Ok(s_res)) = (s_req, s_res) { + let mut s_req = TokioIo::new(s_req); + let mut s_res = TokioIo::new(s_res); let _ = tokio::io::copy_bidirectional(&mut s_req, &mut s_res).await; } }); @@ -564,10 +573,10 @@ async fn forward_ws_to_server(rw: AsyncPipe, mut req: Request) -> Response proxied_res } -fn connection_err(err: hyper::Error) -> Response { +fn connection_err(err: hyper::Error) -> Response { Response::builder() .status(503) - .body(Body::from(format!( + .body(full_body(format!( "Error connecting to agent host: {err:?}" ))) .unwrap() diff --git a/cli/src/tunnels/code_server.rs b/cli/src/tunnels/code_server.rs index ffabbad19c4..6f4e6f6dbce 100644 --- a/cli/src/tunnels/code_server.rs +++ b/cli/src/tunnels/code_server.rs @@ -8,6 +8,7 @@ use crate::constants::{ APPLICATION_NAME, EDITOR_WEB_URL, QUALITYLESS_PRODUCT_NAME, QUALITYLESS_SERVER_NAME, }; use crate::download_cache::DownloadCache; +use crate::log; use crate::options::{Quality, TelemetryLevel}; use crate::state::LauncherPaths; use crate::tunnels::paths::{get_server_folder_name, SERVER_FOLDER_NAME}; @@ -23,9 +24,6 @@ use crate::util::http::{self, BoxedHttp}; use crate::util::io::SilentCopyProgress; use crate::util::machine::process_exists; use crate::util::prereqs::skip_requirements_check; -use crate::log; -use lazy_static::lazy_static; -use opentelemetry::KeyValue; use regex::Regex; use serde::Deserialize; use std::fs; @@ -33,6 +31,7 @@ use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::sync::LazyLock; use std::time::Duration; use tokio::fs::remove_file; use tokio::io::{AsyncBufReadExt, BufReader}; @@ -40,11 +39,10 @@ use tokio::process::{Child, Command}; use tokio::sync::oneshot::Receiver; use tokio::time::{interval, timeout}; -lazy_static! { - static ref LISTENING_PORT_RE: Regex = - Regex::new(r"Extension host agent listening on (.+)").unwrap(); - static ref WEB_UI_RE: Regex = Regex::new(r"Web UI available at (.+)").unwrap(); -} +static LISTENING_PORT_RE: LazyLock = + LazyLock::new(|| Regex::new(r"Extension host agent listening on (.+)").unwrap()); +static WEB_UI_RE: LazyLock = + LazyLock::new(|| Regex::new(r"Web UI available at (.+)").unwrap()); #[derive(Clone, Debug, Default)] pub struct CodeServerArgs { @@ -551,14 +549,7 @@ impl<'a> ServerBuilder<'a> { } pub async fn listen_on_socket(&self, socket: &Path) -> Result { - Ok(spanf!( - self.logger, - self.logger.span("server.start").with_attributes(vec! { - KeyValue::new("commit_id", self.server_params.release.commit.to_string()), - KeyValue::new("quality", format!("{}", self.server_params.release.quality)), - }), - self._listen_on_socket(socket) - )?) + self._listen_on_socket(socket).await } async fn _listen_on_socket(&self, socket: &Path) -> Result { @@ -612,10 +603,8 @@ impl<'a> ServerBuilder<'a> { let cmd = cmd.creation_flags( winapi::um::winbase::CREATE_NO_WINDOW | winapi::um::winbase::CREATE_NEW_PROCESS_GROUP - | get_should_use_breakaway_from_job() - .await - .then_some(winapi::um::winbase::CREATE_BREAKAWAY_FROM_JOB) - .unwrap_or_default(), + | if get_should_use_breakaway_from_job() + .await { winapi::um::winbase::CREATE_BREAKAWAY_FROM_JOB } else { Default::default() }, ); let child = cmd diff --git a/cli/src/tunnels/control_server.rs b/cli/src/tunnels/control_server.rs index 614c05efd90..a9372b5471f 100644 --- a/cli/src/tunnels/control_server.rs +++ b/cli/src/tunnels/control_server.rs @@ -28,8 +28,6 @@ use crate::util::sync::{new_barrier, Barrier, BarrierOpener}; use futures::stream::FuturesUnordered; use futures::FutureExt; -use opentelemetry::trace::SpanKind; -use opentelemetry::KeyValue; use std::collections::HashMap; use std::path::PathBuf; use std::process::Stdio; @@ -40,7 +38,6 @@ use tokio_util::codec::Decoder; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; -use std::time::Instant; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader, DuplexStream}; use tokio::sync::{mpsc, Mutex}; @@ -282,8 +279,8 @@ pub async fn serve( let mgr = mgr.clone(); async move { handle_agent_host_request(mgr, req).await } }); - if let Err(e) = hyper::server::conn::Http::new() - .serve_connection(rw, svc) + if let Err(e) = hyper::server::conn::http1::Builder::new() + .serve_connection(hyper_util::rt::TokioIo::new(rw), svc) .with_upgrades() .await { @@ -311,33 +308,17 @@ pub async fn serve( let own_forwarding = forwarding.handle(); tokio::spawn(async move { - use opentelemetry::trace::{FutureExt, TraceContextExt}; - - let span = own_log.span("server.socket").with_kind(SpanKind::Consumer).start(own_log.tracer()); - let cx = opentelemetry::Context::current_with_span(span); - let serve_at = Instant::now(); - debug!(own_log, "Serving new connection"); let (writehalf, readhalf) = socket.into_split(); - let stats = process_socket(readhalf, writehalf, own_tx, Some(own_forwarding), ServeStreamParams { + let _stats = process_socket(readhalf, writehalf, own_tx, Some(own_forwarding), ServeStreamParams { log: own_log, launcher_paths: own_paths, code_server_args: own_code_server_args, platform, exit_barrier: own_exit, requires_auth: AuthRequired::None, - }).with_context(cx.clone()).await; - - cx.span().add_event( - "socket.bandwidth", - vec![ - KeyValue::new("tx", stats.tx as f64), - KeyValue::new("rx", stats.rx as f64), - KeyValue::new("duration_ms", serve_at.elapsed().as_millis() as f64), - ], - ); - cx.span().end(); + }).await; }); } } @@ -375,8 +356,8 @@ pub async fn serve_stream( } pub struct SocketStats { - rx: usize, - tx: usize, + pub rx: usize, + pub tx: usize, } #[allow(clippy::too_many_arguments)] @@ -1190,7 +1171,9 @@ async fn handle_call_server_http( code_server: Option, params: CallServerHttpParams, ) -> Result { - use hyper::{body, client::conn::Builder, Body, Request}; + use ::http::Request; + use http_body_util::{BodyExt, Full}; + use hyper_util::rt::TokioIo; // We use Hyper directly here since reqwest doesn't support sockets/pipes. // See https://github.com/seanmonstar/reqwest/issues/39 @@ -1202,8 +1185,7 @@ async fn handle_call_server_http( let rw = get_socket_rw_stream(socket).await?; - let (mut request_sender, connection) = Builder::new() - .handshake(rw) + let (mut request_sender, connection) = hyper::client::conn::http1::handshake(TokioIo::new(rw)) .await .map_err(|e| wrap(e, "error establishing connection"))?; @@ -1219,7 +1201,7 @@ async fn handle_call_server_http( request_builder = request_builder.header(k, v); } let request = request_builder - .body(Body::from(params.body.unwrap_or_default())) + .body(Full::new(bytes::Bytes::from(params.body.unwrap_or_default()))) .map_err(|e| wrap(e, "invalid request"))?; let response = request_sender @@ -1227,17 +1209,19 @@ async fn handle_call_server_http( .await .map_err(|e| wrap(e, "error sending request"))?; + let (parts, body) = response.into_parts(); + let body_bytes = body.collect() + .await + .map_err(|e| wrap(e, "error reading response body"))? + .to_bytes(); + Ok(CallServerHttpResult { - status: response.status().as_u16(), - headers: response - .headers() - .into_iter() + status: parts.status.as_u16(), + headers: parts.headers + .iter() .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())) .collect(), - body: body::to_bytes(response) - .await - .map_err(|e| wrap(e, "error reading response body"))? - .to_vec(), + body: body_bytes.to_vec(), }) } diff --git a/cli/src/tunnels/dev_tunnels.rs b/cli/src/tunnels/dev_tunnels.rs index bc043cd62af..2facd45c183 100644 --- a/cli/src/tunnels/dev_tunnels.rs +++ b/cli/src/tunnels/dev_tunnels.rs @@ -5,22 +5,20 @@ use super::protocol::{self, PortPrivacy, PortProtocol}; use crate::auth; use crate::constants::{IS_INTERACTIVE_CLI, PROTOCOL_VERSION_TAG, TUNNEL_SERVICE_USER_AGENT}; +use crate::log; use crate::state::{LauncherPaths, PersistedState}; use crate::util::errors::{ wrap, AnyError, CodeError, DevTunnelError, InvalidTunnelName, TunnelCreationFailed, WrappedError, }; use crate::util::input::prompt_placeholder; -use crate::log; -use async_trait::async_trait; use futures::future::BoxFuture; use futures::{FutureExt, TryFutureExt}; -use lazy_static::lazy_static; use rand::prelude::IteratorRandom; use regex::Regex; -use reqwest::StatusCode; use serde::{Deserialize, Serialize}; -use std::sync::{Arc, Mutex}; +use std::future::Future; +use std::sync::{Arc, LazyLock, Mutex}; use std::time::Duration; use tokio::sync::{mpsc, watch}; use tunnels::connections::{ForwardedPortConnection, RelayTunnelHost}; @@ -91,10 +89,10 @@ impl PersistedTunnel { } } -#[async_trait] +#[allow(clippy::manual_async_fn)] trait AccessTokenProvider: Send + Sync { /// Gets the current access token. - async fn refresh_token(&self) -> Result; + fn refresh_token(&self) -> impl Future> + Send; /// Maintains the stored credential by refreshing it against the service /// to ensure its stays current. Returns a future that should be polled and @@ -111,10 +109,10 @@ impl StaticAccessTokenProvider { } } -#[async_trait] +#[allow(clippy::manual_async_fn)] impl AccessTokenProvider for StaticAccessTokenProvider { - async fn refresh_token(&self) -> Result { - Ok(self.0.clone()) + fn refresh_token(&self) -> impl Future> + Send { + async move { Ok(self.0.clone()) } } fn keep_alive(&self) -> BoxFuture<'static, Result<(), AnyError>> { @@ -149,30 +147,31 @@ impl LookupAccessTokenProvider { } } -#[async_trait] +#[allow(clippy::manual_async_fn)] impl AccessTokenProvider for LookupAccessTokenProvider { - async fn refresh_token(&self) -> Result { - if let Some(token) = self.initial_token.lock().unwrap().take() { - return Ok(token); - } + fn refresh_token(&self) -> impl Future> + Send { + async move { + if let Some(token) = self.initial_token.lock().unwrap().take() { + return Ok(token); + } - let tunnel_lookup = spanf!( - self.log, - self.log.span("dev-tunnel.tag.get"), - self.client.get_tunnel( - &self.locator, - &TunnelRequestOptions { - token_scopes: vec!["host".to_string()], - ..Default::default() - } - ) - ); + let tunnel_lookup = self + .client + .get_tunnel( + &self.locator, + &TunnelRequestOptions { + token_scopes: vec!["host".to_string()], + ..Default::default() + }, + ) + .await; - trace!(self.log, "Successfully refreshed access token"); + trace!(self.log, "Successfully refreshed access token"); - match tunnel_lookup { - Ok(tunnel) => Ok(get_host_token_from_tunnel(&tunnel)), - Err(e) => Err(wrap(e, "failed to lookup tunnel for host token")), + match tunnel_lookup { + Ok(tunnel) => Ok(get_host_token_from_tunnel(&tunnel)), + Err(e) => Err(wrap(e, "failed to lookup tunnel for host token")), + } } } @@ -297,13 +296,12 @@ fn is_valid_name(name: &str) -> Result<(), InvalidTunnelName> { Ok(()) } -lazy_static! { - static ref HOST_TUNNEL_REQUEST_OPTIONS: TunnelRequestOptions = TunnelRequestOptions { +static HOST_TUNNEL_REQUEST_OPTIONS: LazyLock = + LazyLock::new(|| TunnelRequestOptions { include_ports: true, token_scopes: vec!["host".to_string()], ..Default::default() - }; -} + }); /// Structure optionally passed into `start_existing_tunnel` to forward an existing tunnel. #[derive(Clone, Debug)] @@ -366,13 +364,10 @@ impl DevTunnels { } }; - spanf!( - self.log, - self.log.span("dev-tunnel.delete"), - self.client - .delete_tunnel(&tunnel.into_locator(), NO_REQUEST_OPTIONS) - ) - .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; + self.client + .delete_tunnel(&tunnel.into_locator(), NO_REQUEST_OPTIONS) + .await + .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; self.launcher_tunnel.save(None)?; Ok(()) @@ -420,12 +415,11 @@ impl DevTunnels { full_tunnel.labels = desired_tags; - let updated_tunnel = spanf!( - self.log, - self.log.span("dev-tunnel.tag.update"), - self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS) - ) - .map_err(|e| wrap(e, "failed to rename tunnel"))?; + let updated_tunnel = self + .client + .update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS) + .await + .map_err(|e| wrap(e, "failed to rename tunnel"))?; persisted.name = name; self.launcher_tunnel.save(Some(persisted.clone()))?; @@ -442,17 +436,12 @@ impl DevTunnels { create_with_new_name: Option<&str>, options: &TunnelRequestOptions, ) -> Result<(Tunnel, PersistedTunnel, /* is_new */ bool), AnyError> { - let tunnel_lookup = spanf!( - self.log, - self.log.span("dev-tunnel.tag.get"), - self.client.get_tunnel(&persisted.locator(), options) - ); + let tunnel_lookup = self.client.get_tunnel(&persisted.locator(), options).await; match tunnel_lookup { Ok(ft) => Ok((ft, persisted, false)), Err(HttpError::ResponseError(e)) - if e.status_code == StatusCode::NOT_FOUND - || e.status_code == StatusCode::FORBIDDEN => + if e.status_code.as_u16() == 404 || e.status_code.as_u16() == 403 => { let (persisted, tunnel) = self .create_tunnel(create_with_new_name.unwrap_or(&persisted.name), options) @@ -520,12 +509,9 @@ impl DevTunnels { port_to_delete.port_number, NO_REQUEST_OPTIONS, ); - spanf!( - self.log, - self.log.span("dev-tunnel.port.delete"), - output_fut - ) - .map_err(|e| wrap(e, "failed to delete port"))?; + output_fut + .await + .map_err(|e| wrap(e, "failed to delete port"))?; } // cleanup any old trailing tunnel endpoints @@ -536,7 +522,7 @@ impl DevTunnels { NO_REQUEST_OPTIONS, ); - spanf!(self.log, self.log.span("dev-tunnel.endpoint.prune"), fut) + fut.await .map_err(|e| wrap(e, "failed to prune tunnel endpoint"))?; } @@ -570,30 +556,25 @@ impl DevTunnels { let loc = TunnelLocator::try_from(&e).unwrap(); info!(self.log, "Adopting existing tunnel (ID={:?})", loc); - spanf!( - self.log, - self.log.span("dev-tunnel.tag.get"), - self.client.get_tunnel(&loc, &HOST_TUNNEL_REQUEST_OPTIONS) - ) - .map_err(|e| wrap(e, "failed to lookup tunnel"))? + self.client + .get_tunnel(&loc, &HOST_TUNNEL_REQUEST_OPTIONS) + .await + .map_err(|e| wrap(e, "failed to lookup tunnel"))? } None => loop { - let result = spanf!( - self.log, - self.log.span("dev-tunnel.create"), - self.client.create_tunnel( + let result = self + .client + .create_tunnel( Tunnel { labels: self.get_labels(name), ..Default::default() }, - options + options, ) - ); + .await; match result { - Err(HttpError::ResponseError(e)) - if e.status_code == StatusCode::TOO_MANY_REQUESTS => - { + Err(HttpError::ResponseError(e)) if e.status_code.as_u16() == 429 => { if let Some(d) = e.get_details() { let detail = d.detail.unwrap_or_else(|| "unknown".to_string()); if detail.contains(TUNNEL_COUNT_LIMIT_NAME) @@ -672,11 +653,7 @@ impl DevTunnels { ..Default::default() }; - let result = spanf!( - self.log, - self.log.span("dev-tunnel.protocol-tag-update"), - client.update_tunnel(&tunnel_update, options) - ); + let result = client.update_tunnel(&tunnel_update, options).await; result.map_err(|e| wrap(e, "tunnel tag update failed").into()) } @@ -699,13 +676,10 @@ impl DevTunnels { match recyclable { Some(tunnel) => { trace!(self.log, "Recycling tunnel ID {:?}", tunnel.tunnel_id); - spanf!( - self.log, - self.log.span("dev-tunnel.delete"), - self.client - .delete_tunnel(&tunnel.try_into().unwrap(), NO_REQUEST_OPTIONS) - ) - .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; + self.client + .delete_tunnel(&tunnel.try_into().unwrap(), NO_REQUEST_OPTIONS) + .await + .map_err(|e| wrap(e, "failed to execute `tunnel delete`"))?; Ok(true) } None => { @@ -719,24 +693,22 @@ impl DevTunnels { &mut self, tags: &[&'static str], ) -> Result, AnyError> { - let tunnels = spanf!( - self.log, - self.log.span("dev-tunnel.listall"), - self.client.list_all_tunnels(&TunnelRequestOptions { + let tunnels = self + .client + .list_all_tunnels(&TunnelRequestOptions { labels: tags.iter().map(|t| t.to_string()).collect(), ..Default::default() }) - ) - .map_err(|e| wrap(e, "error listing current tunnels"))?; + .await + .map_err(|e| wrap(e, "error listing current tunnels"))?; Ok(tunnels) } async fn get_existing_tunnel_with_name(&self, name: &str) -> Result, AnyError> { - let existing: Vec = spanf!( - self.log, - self.log.span("dev-tunnel.rename.search"), - self.client.list_all_tunnels(&TunnelRequestOptions { + let existing: Vec = self + .client + .list_all_tunnels(&TunnelRequestOptions { labels: vec![self.tag.to_string(), name.to_string()], require_all_labels: true, limit: 1, @@ -744,8 +716,8 @@ impl DevTunnels { token_scopes: vec!["host".to_string()], ..Default::default() }) - ) - .map_err(|e| wrap(e, "failed to list existing tunnels"))?; + .await + .map_err(|e| wrap(e, "failed to list existing tunnels"))?; Ok(existing.into_iter().next()) } @@ -871,11 +843,7 @@ impl DevTunnels { ) -> Result { let mut manager = ActiveTunnelManager::new(self.log.clone(), client, locator, access_token); - let endpoint_result = spanf!( - self.log, - self.log.span("dev-tunnel.serve.callback"), - manager.get_endpoint() - ); + let endpoint_result = manager.get_endpoint().await; let endpoint = match endpoint_result { Ok(endpoint) => endpoint, @@ -903,13 +871,13 @@ impl StatusLock { fn succeed(&self) { let mut status = self.0.lock().unwrap(); status.tunnel = protocol::singleton::TunnelState::Connected; - status.last_connected_at = Some(chrono::Utc::now()); + status.last_connected_at = Some(jiff::Timestamp::now()); } fn fail(&self, reason: String) { let mut status = self.0.lock().unwrap(); if let protocol::singleton::TunnelState::Connected = status.tunnel { - status.last_disconnected_at = Some(chrono::Utc::now()); + status.last_disconnected_at = Some(jiff::Timestamp::now()); status.tunnel = protocol::singleton::TunnelState::Disconnected; } status.last_fail_reason = Some(reason); diff --git a/cli/src/tunnels/legal.rs b/cli/src/tunnels/legal.rs index 35316af4fde..225cf08f406 100644 --- a/cli/src/tunnels/legal.rs +++ b/cli/src/tunnels/legal.rs @@ -6,13 +6,11 @@ use crate::constants::IS_INTERACTIVE_CLI; use crate::state::{LauncherPaths, PersistedState}; use crate::util::errors::{AnyError, CodeError}; use crate::util::input::prompt_yn; -use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; +use std::sync::LazyLock; -lazy_static! { - static ref LICENSE_TEXT: Option> = - option_env!("VSCODE_CLI_SERVER_LICENSE").and_then(|s| serde_json::from_str(s).unwrap()); -} +static LICENSE_TEXT: LazyLock>> = + LazyLock::new(|| option_env!("VSCODE_CLI_SERVER_LICENSE").and_then(|s| serde_json::from_str(s).unwrap())); const LICENSE_PROMPT: Option<&'static str> = option_env!("VSCODE_CLI_REMOTE_LICENSE_PROMPT"); diff --git a/cli/src/tunnels/protocol.rs b/cli/src/tunnels/protocol.rs index 0c6329f3043..482845965d1 100644 --- a/cli/src/tunnels/protocol.rs +++ b/cli/src/tunnels/protocol.rs @@ -353,7 +353,7 @@ pub mod forward_singleton { pub mod singleton { use crate::log; - use chrono::{DateTime, Utc}; + use jiff::Timestamp; use serde::{Deserialize, Serialize}; pub const METHOD_RESTART: &str = "restart"; @@ -385,17 +385,17 @@ pub mod singleton { #[derive(Serialize, Deserialize, Clone)] pub struct Status { - pub started_at: DateTime, + pub started_at: Timestamp, pub tunnel: TunnelState, - pub last_connected_at: Option>, - pub last_disconnected_at: Option>, + pub last_connected_at: Option, + pub last_disconnected_at: Option, pub last_fail_reason: Option, } impl Default for Status { fn default() -> Self { Self { - started_at: Utc::now(), + started_at: Timestamp::now(), tunnel: TunnelState::Disconnected, last_connected_at: None, last_disconnected_at: None, diff --git a/cli/src/tunnels/service.rs b/cli/src/tunnels/service.rs index 66bdf7a8e63..e8b752253ab 100644 --- a/cli/src/tunnels/service.rs +++ b/cli/src/tunnels/service.rs @@ -5,8 +5,6 @@ use std::path::{Path, PathBuf}; -use async_trait::async_trait; - use crate::log; use crate::state::LauncherPaths; use crate::util::errors::{wrap, AnyError}; @@ -14,7 +12,6 @@ use crate::util::io::{tailf, TailEvent}; pub const SERVICE_LOG_FILE_NAME: &str = "tunnel-service.log"; -#[async_trait] pub trait ServiceContainer: Send { async fn run_service( &mut self, @@ -23,7 +20,6 @@ pub trait ServiceContainer: Send { ) -> Result<(), AnyError>; } -#[async_trait] pub trait ServiceManager { /// Registers the current executable as a service to run with the given set /// of arguments. diff --git a/cli/src/tunnels/service_linux.rs b/cli/src/tunnels/service_linux.rs index 0a3e2df6ea2..4de6ba24d83 100644 --- a/cli/src/tunnels/service_linux.rs +++ b/cli/src/tunnels/service_linux.rs @@ -10,7 +10,6 @@ use std::{ process::Command, }; -use async_trait::async_trait; use zbus::{dbus_proxy, zvariant, Connection}; use crate::{ @@ -66,7 +65,6 @@ impl SystemdService { } } -#[async_trait] impl ServiceManager for SystemdService { async fn register( &self, diff --git a/cli/src/tunnels/service_macos.rs b/cli/src/tunnels/service_macos.rs index 2a51681de1d..938c71e9ead 100644 --- a/cli/src/tunnels/service_macos.rs +++ b/cli/src/tunnels/service_macos.rs @@ -9,8 +9,6 @@ use std::{ path::{Path, PathBuf}, }; -use async_trait::async_trait; - use crate::{ constants::APPLICATION_NAME, log, @@ -37,7 +35,6 @@ impl LaunchdService { } } -#[async_trait] impl ServiceManager for LaunchdService { async fn register( &self, diff --git a/cli/src/tunnels/service_windows.rs b/cli/src/tunnels/service_windows.rs index 395a707f351..e88943569a5 100644 --- a/cli/src/tunnels/service_windows.rs +++ b/cli/src/tunnels/service_windows.rs @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use async_trait::async_trait; use shell_escape::windows::escape as shell_escape; use std::os::windows::process::CommandExt; use std::{path::PathBuf, process::Stdio}; @@ -46,7 +45,6 @@ impl WindowsService { } } -#[async_trait] impl CliServiceManager for WindowsService { async fn register(&self, exe: std::path::PathBuf, args: &[&str]) -> Result<(), AnyError> { let key = WindowsService::open_key()?; diff --git a/cli/src/update_service.rs b/cli/src/update_service.rs index de977b736b2..1070dac00c4 100644 --- a/cli/src/update_service.rs +++ b/cli/src/update_service.rs @@ -64,7 +64,7 @@ fn get_update_endpoint() -> Result { } VSCODE_CLI_UPDATE_ENDPOINT .map(|s| s.to_string()) - .ok_or_else(|| CodeError::UpdatesNotConfigured("no service url")) + .ok_or(CodeError::UpdatesNotConfigured("no service url")) } impl UpdateService { @@ -91,11 +91,7 @@ impl UpdateService { quality_download_segment(quality), ); - let mut response = spanf!( - self.log, - self.log.span("server.version.resolve"), - self.client.make_request("GET", download_url) - )?; + let mut response = self.client.make_request("GET", download_url).await?; if !response.status_code.is_success() { return Err(response.into_err().await.into()); @@ -131,11 +127,7 @@ impl UpdateService { quality_download_segment(quality), ); - let mut response = spanf!( - self.log, - self.log.span("server.version.resolve"), - self.client.make_request("GET", download_url) - )?; + let mut response = self.client.make_request("GET", download_url).await?; if !response.status_code.is_success() { return Err(response.into_err().await.into()); diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs index b7ed029bb98..b8dd84a3f9f 100644 --- a/cli/src/util/errors.rs +++ b/cli/src/util/errors.rs @@ -493,7 +493,7 @@ pub enum CodeError { #[error("could not parse `host`: {0}")] InvalidHostAddress(std::net::AddrParseError), #[error("could not start server on the given host/port: {0}")] - CouldNotListenOnInterface(hyper::Error), + CouldNotListenOnInterface(std::io::Error), #[error( "Run this command again with --accept-server-license-terms to indicate your agreement." )] diff --git a/cli/src/util/http.rs b/cli/src/util/http.rs index 9658ec1fcbd..223d1689116 100644 --- a/cli/src/util/http.rs +++ b/cli/src/util/http.rs @@ -7,16 +7,16 @@ use crate::{ log, util::errors::{self, WrappedError}, }; -use async_trait::async_trait; +use bytes::Bytes; use core::panic; use futures::stream::TryStreamExt; -use hyper::{ - header::{HeaderName, CONTENT_LENGTH}, - http::HeaderValue, +use http::{ + header::{HeaderName, HeaderValue, CONTENT_LENGTH}, HeaderMap, StatusCode, }; +use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full}; use serde::de::DeserializeOwned; -use std::{io, pin::Pin, str::FromStr, sync::Arc, task::Poll}; +use std::{future::Future, io, pin::Pin, str::FromStr, sync::Arc, task::Poll}; use tokio::{ fs, io::{AsyncRead, AsyncReadExt}, @@ -29,6 +29,19 @@ use super::{ io::{copy_async_progress, ReadBuffer, ReportCopyProgress}, }; +/// Boxed body type used across the HTTP layer. +pub type HyperBody = BoxBody; + +/// Creates a body from some data (string, bytes, etc.) +pub fn full_body(data: impl Into) -> HyperBody { + Full::new(data.into()).map_err(|never| match never {}).boxed() +} + +/// Creates an empty body. +pub fn empty_body() -> HyperBody { + Empty::::new().map_err(|never| match never {}).boxed() +} + pub async fn download_into_file( filename: &std::path::Path, progress: T, @@ -119,13 +132,12 @@ impl SimpleResponse { /// the request library on the server (i.e. `reqwest`) but it can also be used /// to make update/download requests on the client rather than the server, /// similar to SSH's `remote.SSH.localServerDownload` setting. -#[async_trait] pub trait SimpleHttp { - async fn make_request( + fn make_request( &self, method: &'static str, url: String, - ) -> Result; + ) -> Pin> + Send + '_>>; } pub type BoxedHttp = Arc; @@ -157,29 +169,30 @@ impl Default for ReqwestSimpleHttp { } } -#[async_trait] impl SimpleHttp for ReqwestSimpleHttp { - async fn make_request( + fn make_request( &self, method: &'static str, url: String, - ) -> Result { - let res = self - .client - .request(reqwest::Method::try_from(method).unwrap(), &url) - .send() - .await?; + ) -> Pin> + Send + '_>> { + Box::pin(async move { + let res = self + .client + .request(reqwest::Method::try_from(method).unwrap(), &url) + .send() + .await?; - Ok(SimpleResponse { - status_code: res.status(), - headers: res.headers().clone(), - url: Some(res.url().clone()), - read: Box::pin( - res.bytes_stream() - .map_err(futures::io::Error::other) - .into_async_read() - .compat(), - ), + Ok(SimpleResponse { + status_code: res.status(), + headers: res.headers().clone(), + url: Some(res.url().clone()), + read: Box::pin( + res.bytes_stream() + .map_err(futures::io::Error::other) + .into_async_read() + .compat(), + ), + }) }) } } @@ -243,13 +256,13 @@ impl DelegatedSimpleHttp { } } -#[async_trait] impl SimpleHttp for DelegatedSimpleHttp { - async fn make_request( + fn make_request( &self, method: &'static str, url: String, - ) -> Result { + ) -> Pin> + Send + '_>> { + Box::pin(async move { trace!(self.log, "making delegated request to {}", url); let (tx, mut rx) = mpsc::unbounded_channel(); let sent = self @@ -298,6 +311,7 @@ impl SimpleHttp for DelegatedSimpleHttp { Some(_) => panic!("expected initresponse as first message from delegated http"), None => Ok(SimpleResponse::generic_error(&url)), // sender shut down } + }) } } @@ -357,20 +371,21 @@ impl FallbackSimpleHttp { } } -#[async_trait] impl SimpleHttp for FallbackSimpleHttp { - async fn make_request( + fn make_request( &self, method: &'static str, url: String, - ) -> Result { - let r1 = self.native.make_request(method, url.clone()).await; - if let Ok(res) = r1 { - if !res.status_code.is_server_error() { - return Ok(res); + ) -> Pin> + Send + '_>> { + Box::pin(async move { + let r1 = self.native.make_request(method, url.clone()).await; + if let Ok(res) = r1 { + if !res.status_code.is_server_error() { + return Ok(res); + } } - } - self.delegated.make_request(method, url).await + self.delegated.make_request(method, url).await + }) } } diff --git a/cli/src/util/prereqs.rs b/cli/src/util/prereqs.rs index 44c859772e3..7c14d2d45b0 100644 --- a/cli/src/util/prereqs.rs +++ b/cli/src/util/prereqs.rs @@ -6,31 +6,29 @@ use std::cmp::Ordering; use crate::constants::QUALITYLESS_SERVER_NAME; use crate::update_service::Platform; -use lazy_static::lazy_static; use regex::bytes::Regex as BinRegex; use regex::Regex; +use std::sync::LazyLock; use tokio::fs; use super::errors::CodeError; -lazy_static! { - static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap(); - static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*\s(\d+)\.(\d+)(?:\.(\d+))?\s").unwrap(); - static ref GENERIC_VERSION_RE: Regex = Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap(); - static ref LIBSTD_CXX_VERSION_RE: BinRegex = - BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap(); - static ref MIN_LDD_VERSION: SimpleSemver = SimpleSemver::new(2, 28, 0); -} +static LDCONFIG_STDC_RE: LazyLock = LazyLock::new(|| Regex::new(r"libstdc\+\+.* => (.+)").unwrap()); +static LDD_VERSION_RE: LazyLock = LazyLock::new(|| BinRegex::new(r"^ldd.*\s(\d+)\.(\d+)(?:\.(\d+))?\s").unwrap()); +static GENERIC_VERSION_RE: LazyLock = LazyLock::new(|| Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap()); +#[cfg(target_os = "linux")] +static LIBSTD_CXX_VERSION_RE: LazyLock = + LazyLock::new(|| BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap()); +#[cfg(target_os = "linux")] +static MIN_LDD_VERSION: LazyLock = LazyLock::new(|| SimpleSemver::new(2, 28, 0)); +#[cfg(target_os = "linux")] #[cfg(target_arch = "arm")] -lazy_static! { - static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 26); -} +static MIN_CXX_VERSION: LazyLock = LazyLock::new(|| SimpleSemver::new(3, 4, 26)); +#[cfg(target_os = "linux")] #[cfg(not(target_arch = "arm"))] -lazy_static! { - static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 25); -} +static MIN_CXX_VERSION: LazyLock = LazyLock::new(|| SimpleSemver::new(3, 4, 25)); const NIXOS_TEST_PATH: &str = "/etc/NIXOS"; diff --git a/cli/src/util/sync.rs b/cli/src/util/sync.rs index 67c777b75ed..3eba4e6b1a2 100644 --- a/cli/src/util/sync.rs +++ b/cli/src/util/sync.rs @@ -2,8 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use async_trait::async_trait; -use std::{marker::PhantomData, sync::Arc}; +use std::{future::Future, marker::PhantomData, pin::Pin, sync::Arc}; use tokio::sync::{ broadcast, mpsc, watch::{self, error::RecvError}, @@ -35,10 +34,9 @@ where } } -#[async_trait] impl Receivable for Barrier { - async fn recv_msg(&mut self) -> Option { - self.wait().await.ok() + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { self.wait().await.ok() }) } } @@ -70,37 +68,35 @@ where } /// Type that can receive messages in an async way. -#[async_trait] pub trait Receivable { - async fn recv_msg(&mut self) -> Option; + fn recv_msg(&mut self) -> Pin> + Send + '_>>; } // todo: ideally we would use an Arc in the broadcast::Receiver to avoid having // to clone bytes everywhere, requires updating rpc consumers as well. -#[async_trait] impl Receivable for broadcast::Receiver { - async fn recv_msg(&mut self) -> Option { - loop { - match self.recv().await { - Ok(v) => return Some(v), - Err(broadcast::error::RecvError::Lagged(_)) => continue, - Err(broadcast::error::RecvError::Closed) => return None, + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { + loop { + match self.recv().await { + Ok(v) => return Some(v), + Err(broadcast::error::RecvError::Lagged(_)) => continue, + Err(broadcast::error::RecvError::Closed) => return None, + } } - } + }) } } -#[async_trait] impl Receivable for mpsc::UnboundedReceiver { - async fn recv_msg(&mut self) -> Option { - self.recv().await + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { self.recv().await }) } } -#[async_trait] impl Receivable for () { - async fn recv_msg(&mut self) -> Option { - futures::future::pending().await + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { futures::future::pending().await }) } } @@ -120,21 +116,22 @@ impl, B: Receivable> ConcatReceivable { } } -#[async_trait] impl, B: Send + Receivable> Receivable for ConcatReceivable { - async fn recv_msg(&mut self) -> Option { - if let Some(left) = &mut self.left { - match left.recv_msg().await { - Some(v) => return Some(v), - None => { - self.left = None; + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { + if let Some(left) = &mut self.left { + match left.recv_msg().await { + Some(v) => return Some(v), + None => { + self.left = None; + } } } - } - return self.right.recv_msg().await; + return self.right.recv_msg().await; + }) } } @@ -154,30 +151,31 @@ impl, B: Receivable> MergedReceivable { } } -#[async_trait] impl, B: Send + Receivable> Receivable for MergedReceivable { - async fn recv_msg(&mut self) -> Option { - loop { - match (&mut self.left, &mut self.right) { - (Some(left), Some(right)) => { - tokio::select! { - left = left.recv_msg() => match left { - Some(v) => return Some(v), - None => { self.left = None; continue; }, - }, - right = right.recv_msg() => match right { - Some(v) => return Some(v), - None => { self.right = None; continue; }, - }, + fn recv_msg(&mut self) -> Pin> + Send + '_>> { + Box::pin(async move { + loop { + match (&mut self.left, &mut self.right) { + (Some(left), Some(right)) => { + tokio::select! { + left = left.recv_msg() => match left { + Some(v) => return Some(v), + None => { self.left = None; continue; }, + }, + right = right.recv_msg() => match right { + Some(v) => return Some(v), + None => { self.right = None; continue; }, + }, + } } + (Some(a), None) => break a.recv_msg().await, + (None, Some(b)) => break b.recv_msg().await, + (None, None) => break None, } - (Some(a), None) => break a.recv_msg().await, - (None, Some(b)) => break b.recv_msg().await, - (None, None) => break None, } - } + }) } }