mirror of
https://github.com/railwayapp/cli
synced 2026-04-21 14:07:23 +00:00
fix: fix connection errors when using custom system certificates and an http proxy. (#807)
When trying to use the Railway CLI behind an HTTP proxy that requires a custom certificate ( such as some VPNs ), the CLI would previously fail with a certificate error. This adds the `rustls-tls-native-roots` feature reqwest to trust the native platform's system certificate store to fix that. Railway commands that require a websocket connection were also failing to go through the proxy, because while `reqwest` automatically sends requests through the proxy `async-tungstenite` would not. This removes `async-tungstenite` in favor of `reqwest-websocket` which is simpler and uses `reqwest` to properly send the initial HTTP request through the proxy before the websocket upgrade.
This commit is contained in:
parent
6b9b52eb17
commit
d41b2e4dfb
5 changed files with 222 additions and 147 deletions
205
Cargo.lock
generated
205
Cargo.lock
generated
|
|
@ -132,9 +132,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-tungstenite"
|
||||
version = "0.28.2"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c348fb0b6d132c596eca3dcd941df48fb597aafcb07a738ec41c004b087dc99"
|
||||
checksum = "ee88b4c88ac8c9ea446ad43498955750a4bbe64c4392f21ccfe5d952865e318f"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"futures-core",
|
||||
|
|
@ -143,10 +143,6 @@ dependencies = [
|
|||
"futures-util",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
|
|
@ -241,9 +237,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.9.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
|
|
@ -385,7 +381,7 @@ version = "4.6.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
|
|
@ -486,9 +482,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
@ -606,9 +602,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
|||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
|
|
@ -661,9 +657,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
|
|
@ -1202,7 +1198,6 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1251,7 +1246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e7c65d1899521a11810501b50b898464d133e1afc96703cff57726964cfa7baf"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"core_affinity",
|
||||
"flate2",
|
||||
"flume",
|
||||
|
|
@ -1334,7 +1329,7 @@ version = "0.2.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
|
@ -1345,7 +1340,7 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
|
@ -1356,7 +1351,7 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"http 1.2.0",
|
||||
]
|
||||
|
||||
|
|
@ -1366,7 +1361,7 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body",
|
||||
|
|
@ -1387,19 +1382,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.5.2"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
|
||||
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"atomic-waker",
|
||||
"bytes 1.11.1",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"futures-core",
|
||||
"http 1.2.0",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
|
|
@ -1416,6 +1413,7 @@ dependencies = [
|
|||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
|
|
@ -1425,18 +1423,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.8",
|
||||
"socket2 0.6.1",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
|
@ -1796,9 +1795,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.76"
|
||||
version = "0.3.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -2298,7 +2297,7 @@ version = "0.11.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
|
|
@ -2316,9 +2315,9 @@ version = "0.11.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"getrandom 0.2.15",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
|
|
@ -2366,7 +2365,6 @@ dependencies = [
|
|||
"anyhow",
|
||||
"arboard",
|
||||
"async-trait",
|
||||
"async-tungstenite",
|
||||
"base64",
|
||||
"box_drawing",
|
||||
"chrono",
|
||||
|
|
@ -2405,9 +2403,10 @@ dependencies = [
|
|||
"open",
|
||||
"pastey",
|
||||
"pathdiff",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ratatui",
|
||||
"reqwest",
|
||||
"reqwest-websocket",
|
||||
"schemars",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
|
|
@ -2437,8 +2436,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2448,7 +2457,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2460,6 +2479,15 @@ dependencies = [
|
|||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.29.0"
|
||||
|
|
@ -2537,7 +2565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
|
|
@ -2555,6 +2583,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
|
|
@ -2573,6 +2602,24 @@ dependencies = [
|
|||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-websocket"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd5f79b25f7f17a62cc9337108974431a66ae5a723ac0d9fe78ac1cce2027720"
|
||||
dependencies = [
|
||||
"async-tungstenite",
|
||||
"bytes 1.11.1",
|
||||
"futures-util",
|
||||
"reqwest",
|
||||
"thiserror 2.0.9",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"tungstenite",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
|
|
@ -3288,7 +3335,7 @@ version = "1.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"libc",
|
||||
"mio 1.0.3",
|
||||
"parking_lot",
|
||||
|
|
@ -3337,8 +3384,9 @@ version = "0.7.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||
dependencies = [
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
|
|
@ -3378,9 +3426,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
|
|
@ -3398,29 +3458,26 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
|||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.24.0"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
|
||||
checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes 1.9.0",
|
||||
"bytes 1.11.1",
|
||||
"data-encoding",
|
||||
"http 1.2.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"rand 0.9.2",
|
||||
"sha1",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.9",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
|
|
@ -3574,36 +3631,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.99"
|
||||
version = "0.2.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.49"
|
||||
version = "0.4.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -3612,9 +3658,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.99"
|
||||
version = "0.2.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -3622,28 +3668,31 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.99"
|
||||
version = "0.2.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.99"
|
||||
version = "0.2.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.76"
|
||||
version = "0.3.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
|
|||
11
Cargo.toml
11
Cargo.toml
|
|
@ -27,8 +27,10 @@ serde_json = "1.0.134"
|
|||
serde_yaml = "0.9"
|
||||
reqwest = { version = "0.12.12", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
"rustls-tls-native-roots",
|
||||
"json",
|
||||
] }
|
||||
reqwest-websocket = "0.5.1"
|
||||
chrono = { version = "0.4.39", features = [
|
||||
"serde",
|
||||
"clock",
|
||||
|
|
@ -63,14 +65,7 @@ futures = { version = "0.3.31", default-features = false, features = [
|
|||
"executor"
|
||||
] }
|
||||
futures-util = "0.3"
|
||||
graphql-ws-client = { version = "0.11.1", features = [
|
||||
"client-graphql-client",
|
||||
"tungstenite",
|
||||
] }
|
||||
async-tungstenite = { version = "0.28.2", features = [
|
||||
"tokio-runtime",
|
||||
"tokio-rustls-native-certs",
|
||||
] }
|
||||
graphql-ws-client = { version = "0.11.1", features = ["client-graphql-client"] }
|
||||
crossterm = { version = "0.27.0", features = ["event-stream"] }
|
||||
http = "0.2"
|
||||
is-terminal = "0.4.13"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::{Result, bail};
|
||||
use async_tungstenite::WebSocketStream;
|
||||
use async_tungstenite::tungstenite::Message;
|
||||
use futures::SinkExt;
|
||||
use futures_util::stream::StreamExt;
|
||||
use indicatif::ProgressBar;
|
||||
use reqwest_websocket::{Message, WebSocket};
|
||||
use std::io::Write;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::{Duration, interval, timeout};
|
||||
|
|
@ -14,7 +14,7 @@ use super::connection::{SSHConnectParams, establish_connection};
|
|||
use super::messages::{ClientMessage, ClientPayload, DataPayload, ServerMessage};
|
||||
|
||||
pub struct TerminalClient {
|
||||
ws_stream: WebSocketStream<async_tungstenite::tokio::ConnectStream>,
|
||||
ws_stream: WebSocket,
|
||||
initialized: bool,
|
||||
ready: bool,
|
||||
in_command_progress: bool,
|
||||
|
|
@ -232,7 +232,7 @@ impl TerminalClient {
|
|||
|
||||
/// Sends a ping message to keep the connection alive
|
||||
async fn send_ping(&mut self) -> Result<()> {
|
||||
self.send_message(Message::Ping(vec![]))
|
||||
self.send_message(Message::Ping(Default::default()))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to send ping: {}", e))?;
|
||||
Ok(())
|
||||
|
|
@ -337,19 +337,13 @@ impl TerminalClient {
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::Close(frame) => {
|
||||
Message::Close { code, reason } => {
|
||||
if let Some(tx) = &self.ready_tx {
|
||||
let _ = tx.send(false).await;
|
||||
}
|
||||
if let Some(frame) = frame {
|
||||
bail!(
|
||||
"WebSocket closed with code {}: {}",
|
||||
frame.code,
|
||||
frame.reason
|
||||
);
|
||||
} else {
|
||||
bail!("WebSocket closed unexpectedly");
|
||||
}
|
||||
bail!(
|
||||
"WebSocket closed with code {code}: {reason}",
|
||||
);
|
||||
}
|
||||
Message::Ping(data) => {
|
||||
self.send_message(Message::Pong(data)).await?;
|
||||
|
|
@ -360,9 +354,6 @@ impl TerminalClient {
|
|||
Message::Binary(_) => {
|
||||
writeln!(writer, "Warning: Unexpected binary message received")?;
|
||||
}
|
||||
Message::Frame(_) => {
|
||||
writeln!(writer, "Warning: Unexpected raw frame received")?;
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
|
|
@ -435,12 +426,8 @@ impl TerminalClient {
|
|||
Message::Ping(data) => {
|
||||
self.send_message(Message::Pong(data)).await?;
|
||||
}
|
||||
Message::Close(frame) => {
|
||||
if let Some(frame) = frame {
|
||||
bail!("WebSocket closed with code {}: {}", frame.code, frame.reason);
|
||||
} else {
|
||||
bail!("WebSocket closed unexpectedly");
|
||||
}
|
||||
Message::Close { code, reason } => {
|
||||
bail!("WebSocket closed with code {code}: {reason}");
|
||||
}
|
||||
// Ignore other message types
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
use anyhow::{Result, bail};
|
||||
use async_tungstenite::WebSocketStream;
|
||||
use async_tungstenite::tungstenite::handshake::client::generate_key;
|
||||
use async_tungstenite::tungstenite::http::Request;
|
||||
use indicatif::ProgressBar;
|
||||
use tokio::time::{Duration, sleep, timeout};
|
||||
use tokio::time::{Duration, sleep};
|
||||
use url::Url;
|
||||
|
||||
use crate::commands::ssh::{
|
||||
|
|
@ -26,7 +23,7 @@ pub async fn establish_connection(
|
|||
params: &SSHConnectParams,
|
||||
spinner: &mut ProgressBar,
|
||||
max_attempts: Option<u32>,
|
||||
) -> Result<WebSocketStream<async_tungstenite::tokio::ConnectStream>> {
|
||||
) -> Result<reqwest_websocket::WebSocket> {
|
||||
let url = Url::parse(url)?;
|
||||
|
||||
let max_attempts = max_attempts.unwrap_or(SSH_MAX_CONNECT_ATTEMPTS);
|
||||
|
|
@ -62,20 +59,16 @@ pub async fn attempt_connection(
|
|||
url: &Url,
|
||||
token: AuthKind,
|
||||
params: &SSHConnectParams,
|
||||
) -> Result<WebSocketStream<async_tungstenite::tokio::ConnectStream>> {
|
||||
let key = generate_key();
|
||||
) -> Result<reqwest_websocket::WebSocket> {
|
||||
use reqwest_websocket::RequestBuilderExt;
|
||||
|
||||
let mut request = Request::builder()
|
||||
.uri(url.as_str())
|
||||
.header("Sec-WebSocket-Key", key)
|
||||
.header("Upgrade", "websocket")
|
||||
.header("Connection", "Upgrade")
|
||||
.header("Sec-WebSocket-Version", "13")
|
||||
.header("Host", url.host_str().unwrap_or(""))
|
||||
let mut request = reqwest::Client::default()
|
||||
.get(url.as_str())
|
||||
.header("X-Source", get_user_agent())
|
||||
.header("X-Railway-Project-Id", params.project_id.clone())
|
||||
.header("X-Railway-Service-Id", params.service_id.clone())
|
||||
.header("X-Railway-Environment-Id", params.environment_id.clone());
|
||||
.header("X-Railway-Environment-Id", params.environment_id.clone())
|
||||
.timeout(Duration::from_secs(SSH_CONNECTION_TIMEOUT_SECS));
|
||||
|
||||
if let Some(instance_id) = params.deployment_instance_id.as_ref() {
|
||||
request = request.header("X-Railway-Deployment-Instance-Id", instance_id);
|
||||
|
|
@ -89,16 +82,10 @@ pub async fn attempt_connection(
|
|||
}
|
||||
}
|
||||
|
||||
let request = request.body(())?;
|
||||
|
||||
let (ws_stream, response) = timeout(
|
||||
Duration::from_secs(SSH_CONNECTION_TIMEOUT_SECS),
|
||||
async_tungstenite::tokio::connect_async_with_config(request, None),
|
||||
)
|
||||
.await??;
|
||||
let response = request.upgrade().send().await?;
|
||||
|
||||
if response.status().as_u16() == 101 {
|
||||
Ok(ws_stream)
|
||||
Ok(response.into_websocket().await?)
|
||||
} else {
|
||||
bail!(
|
||||
"Server did not upgrade to WebSocket. Status: {}",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::commands::Configs;
|
||||
use anyhow::{Result, bail};
|
||||
use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use graphql_client::GraphQLQuery;
|
||||
use graphql_ws_client::{Client, Subscription, graphql::StreamingOperation};
|
||||
use reqwest_websocket::{RequestBuilderExt, WebSocket};
|
||||
|
||||
pub async fn subscribe_graphql<T: GraphQLQuery + Send + Sync + Unpin + 'static>(
|
||||
variables: T::Variables,
|
||||
|
|
@ -13,26 +16,80 @@ where
|
|||
{
|
||||
let configs = Configs::new()?;
|
||||
let hostname = configs.get_host();
|
||||
let mut request = format!("wss://backboard.{hostname}/graphql/v2").into_client_request()?;
|
||||
let headers = request.headers_mut();
|
||||
let client = reqwest::Client::default();
|
||||
let mut request = client
|
||||
.get(format!("wss://backboard.{hostname}/graphql/v2"))
|
||||
.timeout(Duration::from_secs(1));
|
||||
|
||||
if let Some(token) = &Configs::get_railway_token() {
|
||||
headers.insert("project-access-token", HeaderValue::from_str(token)?);
|
||||
request = request.header("project-access-token", token);
|
||||
} else if let Some(token) = configs.get_railway_auth_token() {
|
||||
headers.insert(
|
||||
"authorization",
|
||||
HeaderValue::from_str(&format!("Bearer {token}"))?,
|
||||
);
|
||||
request = request.header("authorization", format!("Bearer {token}"));
|
||||
} else {
|
||||
bail!("Not authorized");
|
||||
}
|
||||
headers.insert(
|
||||
"Sec-WebSocket-Protocol",
|
||||
HeaderValue::from_str("graphql-transport-ws").unwrap(),
|
||||
);
|
||||
};
|
||||
|
||||
let (connection, _) = async_tungstenite::tokio::connect_async(request).await?;
|
||||
let resp = request
|
||||
.upgrade()
|
||||
.protocols(["graphql-transport-ws"])
|
||||
.send()
|
||||
.await?;
|
||||
resp.error_for_status_ref()?;
|
||||
let web_socket = resp.into_websocket().await?;
|
||||
|
||||
Ok(Client::build(connection)
|
||||
Ok(Client::build(GraphQLWebSocket(web_socket))
|
||||
.subscribe(StreamingOperation::<T>::new(variables))
|
||||
.await?)
|
||||
}
|
||||
|
||||
struct GraphQLWebSocket(WebSocket);
|
||||
|
||||
impl graphql_ws_client::Connection for GraphQLWebSocket {
|
||||
fn receive(&mut self) -> impl Future<Output = Option<graphql_ws_client::Message>> + Send {
|
||||
use graphql_ws_client::Message as M2;
|
||||
use reqwest_websocket::Message as M1;
|
||||
async {
|
||||
let message = self.0.next().await?.ok()?;
|
||||
Some(match message {
|
||||
M1::Text(t) => M2::Text(t),
|
||||
M1::Binary(_) => None?,
|
||||
M1::Ping(_) => M2::Ping,
|
||||
M1::Pong(_) => M2::Pong,
|
||||
M1::Close { code, reason } => M2::Close {
|
||||
code: Some(code.into()),
|
||||
reason: Some(reason),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn send(
|
||||
&mut self,
|
||||
message: graphql_ws_client::Message,
|
||||
) -> impl Future<Output = std::result::Result<(), graphql_ws_client::Error>> + Send {
|
||||
use graphql_ws_client::{Error as E2, Message as M2};
|
||||
use reqwest_websocket::{Error as E1, Message as M1};
|
||||
async {
|
||||
let message = match message {
|
||||
M2::Text(t) => M1::Text(t),
|
||||
M2::Close { code, reason } => M1::Close {
|
||||
code: code.unwrap_or(0).into(),
|
||||
reason: reason.unwrap_or_default(),
|
||||
},
|
||||
M2::Ping => M1::Ping(Default::default()),
|
||||
M2::Pong => M1::Pong(Default::default()),
|
||||
};
|
||||
|
||||
self.0.send(message).await.map_err(|e| match e {
|
||||
E1::Handshake(handshake_error) => {
|
||||
E2::Custom("Handshake Error".into(), handshake_error.to_string())
|
||||
}
|
||||
E1::Reqwest(error) => E2::Custom("Reqwest Error".into(), error.to_string()),
|
||||
E1::Tungstenite(error) => E2::Custom("Tungstenite Error".into(), error.to_string()),
|
||||
e => E2::Send(e.to_string()),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue