Merge pull request #919 from zed-industries/remove-async-std

Antonio Scandurra created

Remove remaining `async-std` dependencies from `collab`

Change summary

Cargo.lock                               | 440 +++----------------------
crates/auto_update/Cargo.toml            |   2 
crates/auto_update/src/auto_update.rs    |  37 +-
crates/client/Cargo.toml                 |   3 
crates/client/src/channel.rs             |   3 
crates/client/src/client.rs              |  23 
crates/client/src/http.rs                |  51 ++
crates/client/src/test.rs                |  21 
crates/client/src/user.rs                |  27 
crates/collab/Cargo.toml                 |   2 
crates/collab/src/bin/seed.rs            |   6 
crates/collab/src/db.rs                  | 244 +++++++-------
crates/gpui/src/executor.rs              |   6 
crates/util/Cargo.toml                   |   1 
crates/util/src/lib.rs                   |  30 -
crates/workspace/src/workspace.rs        |   4 
crates/zed/Cargo.toml                    |   2 
crates/zed/src/languages/c.rs            |  16 
crates/zed/src/languages/installation.rs |  37 +-
crates/zed/src/languages/rust.rs         |  14 
20 files changed, 322 insertions(+), 647 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -23,60 +23,6 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 
-[[package]]
-name = "aead"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "aes"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
-dependencies = [
- "aes-soft",
- "aesni",
- "cipher 0.2.5",
-]
-
-[[package]]
-name = "aes-gcm"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da"
-dependencies = [
- "aead",
- "aes",
- "cipher 0.2.5",
- "ctr",
- "ghash",
- "subtle",
-]
-
-[[package]]
-name = "aes-soft"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
-dependencies = [
- "cipher 0.2.5",
- "opaque-debug",
-]
-
-[[package]]
-name = "aesni"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
-dependencies = [
- "cipher 0.2.5",
- "opaque-debug",
-]
-
 [[package]]
 name = "ahash"
 version = "0.7.4"
@@ -205,22 +151,6 @@ dependencies = [
  "futures-lite",
 ]
 
-[[package]]
-name = "async-global-executor"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6"
-dependencies = [
- "async-channel",
- "async-executor",
- "async-io",
- "async-mutex",
- "blocking",
- "futures-lite",
- "num_cpus",
- "once_cell",
-]
-
 [[package]]
 name = "async-io"
 version = "1.3.1"
@@ -250,15 +180,6 @@ dependencies = [
  "event-listener",
 ]
 
-[[package]]
-name = "async-mutex"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
-dependencies = [
- "event-listener",
-]
-
 [[package]]
 name = "async-net"
 version = "1.5.0"
@@ -307,45 +228,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "async-rustls"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c86f33abd5a4f3e2d6d9251a9e0c6a7e52eb1113caf893dae8429bf4a53f378"
-dependencies = [
- "futures-lite",
- "rustls",
- "webpki",
-]
-
-[[package]]
-name = "async-std"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341"
-dependencies = [
- "async-channel",
- "async-global-executor",
- "async-io",
- "async-lock",
- "async-process",
- "crossbeam-utils 0.8.2",
- "futures-channel",
- "futures-core",
- "futures-io",
- "futures-lite",
- "gloo-timers",
- "kv-log-macro",
- "log",
- "memchr",
- "num_cpus",
- "once_cell",
- "pin-project-lite 0.2.8",
- "pin-utils",
- "slab",
- "wasm-bindgen-futures",
-]
-
 [[package]]
 name = "async-task"
 version = "4.0.3"
@@ -431,13 +313,13 @@ dependencies = [
  "anyhow",
  "client",
  "gpui",
+ "isahc",
  "lazy_static",
  "log",
  "serde",
  "serde_json",
  "settings",
  "smol",
- "surf",
  "tempdir",
  "theme",
  "workspace",
@@ -465,7 +347,7 @@ dependencies = [
  "axum-core",
  "base64 0.13.0",
  "bitflags",
- "bytes 1.0.1",
+ "bytes",
  "futures-util",
  "headers",
  "http",
@@ -497,7 +379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3ddbd16eabff8b45f21b98671fddcc93daaa7ac4c84f8473693437226040de5"
 dependencies = [
  "async-trait",
- "bytes 1.0.1",
+ "bytes",
  "futures-util",
  "http",
  "http-body",
@@ -679,12 +561,6 @@ version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
 
-[[package]]
-name = "bytes"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
-
 [[package]]
 name = "bytes"
 version = "1.0.1"
@@ -697,6 +573,12 @@ version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
 
+[[package]]
+name = "castaway"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6"
+
 [[package]]
 name = "cc"
 version = "1.0.67"
@@ -761,15 +643,6 @@ version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
 
-[[package]]
-name = "cipher"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
-dependencies = [
- "generic-array",
-]
-
 [[package]]
 name = "cipher"
 version = "0.3.0"
@@ -859,6 +732,7 @@ dependencies = [
  "futures",
  "gpui",
  "image",
+ "isahc",
  "lazy_static",
  "log",
  "parking_lot",
@@ -867,10 +741,10 @@ dependencies = [
  "rpc",
  "smol",
  "sum_tree",
- "surf",
  "thiserror",
  "time 0.3.7",
  "tiny_http",
+ "url",
  "util",
 ]
 
@@ -1019,23 +893,6 @@ dependencies = [
  "workspace",
 ]
 
-[[package]]
-name = "cookie"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
-dependencies = [
- "aes-gcm",
- "base64 0.13.0",
- "hkdf",
- "hmac 0.10.1",
- "percent-encoding",
- "rand 0.8.3",
- "sha2 0.9.5",
- "time 0.2.27",
- "version_check",
-]
-
 [[package]]
 name = "core-foundation"
 version = "0.9.1"
@@ -1112,12 +969,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "cpuid-bool"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba"
-
 [[package]]
 name = "crc"
 version = "1.8.1"
@@ -1254,15 +1105,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "ctr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f"
-dependencies = [
- "cipher 0.2.5",
-]
-
 [[package]]
 name = "curl"
 version = "0.4.42"
@@ -1294,22 +1136,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "dashmap"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
-dependencies = [
- "cfg-if 1.0.0",
- "num_cpus",
-]
-
-[[package]]
-name = "data-encoding"
-version = "2.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
-
 [[package]]
 name = "data-url"
 version = "0.1.0"
@@ -1657,17 +1483,6 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
 
-[[package]]
-name = "flume"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132"
-dependencies = [
- "futures-core",
- "futures-sink",
- "spinning_top",
-]
-
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -1959,16 +1774,6 @@ dependencies = [
  "wasi 0.10.0+wasi-snapshot-preview1",
 ]
 
-[[package]]
-name = "ghash"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375"
-dependencies = [
- "opaque-debug",
- "polyval",
-]
-
 [[package]]
 name = "gif"
 version = "0.11.2"
@@ -2004,19 +1809,6 @@ dependencies = [
  "regex",
 ]
 
-[[package]]
-name = "gloo-timers"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
-dependencies = [
- "futures-channel",
- "futures-core",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
 [[package]]
 name = "go_to_line"
 version = "0.1.0"
@@ -2123,7 +1915,7 @@ checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d"
 dependencies = [
  "base64 0.13.0",
  "bitflags",
- "bytes 1.0.1",
+ "bytes",
  "headers-core",
  "http",
  "httpdate",
@@ -2170,16 +1962,6 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
-[[package]]
-name = "hkdf"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f"
-dependencies = [
- "digest 0.9.0",
- "hmac 0.10.1",
-]
-
 [[package]]
 name = "hmac"
 version = "0.10.1"
@@ -2206,7 +1988,7 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "fnv",
  "itoa 1.0.1",
 ]
@@ -2226,54 +2008,17 @@ version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "http",
  "pin-project-lite 0.2.8",
 ]
 
-[[package]]
-name = "http-client"
-version = "6.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce318d86a47d18d1db645c979214f809a6cd625202ad334ef75ca813b30dac80"
-dependencies = [
- "async-std",
- "async-trait",
- "cfg-if 1.0.0",
- "dashmap",
- "http-types",
- "isahc",
- "log",
-]
-
 [[package]]
 name = "http-range-header"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
 
-[[package]]
-name = "http-types"
-version = "2.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad077d89137cd3debdce53c66714dc536525ef43fe075d41ddc0a8ac11f85957"
-dependencies = [
- "anyhow",
- "async-channel",
- "async-std",
- "base64 0.13.0",
- "cookie",
- "futures-lite",
- "infer",
- "pin-project-lite 0.2.8",
- "rand 0.7.3",
- "serde",
- "serde_json",
- "serde_qs",
- "serde_urlencoded",
- "url",
-]
-
 [[package]]
 name = "httparse"
 version = "1.7.0"
@@ -2298,7 +2043,7 @@ version = "0.14.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "futures-channel",
  "futures-core",
  "futures-util",
@@ -2382,12 +2127,6 @@ dependencies = [
  "unindent",
 ]
 
-[[package]]
-name = "infer"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
-
 [[package]]
 name = "instant"
 version = "0.1.9"
@@ -2427,19 +2166,23 @@ dependencies = [
 
 [[package]]
 name = "isahc"
-version = "0.9.14"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a"
+checksum = "437f8808009c031df3c1d532c8fd7e3d73239dfe522ebf0b94b5e34d5d01044b"
 dependencies = [
- "bytes 0.5.6",
+ "async-channel",
+ "castaway",
  "crossbeam-utils 0.8.2",
  "curl",
  "curl-sys",
- "flume",
+ "encoding_rs",
+ "event-listener",
  "futures-lite",
  "http",
  "log",
+ "mime",
  "once_cell",
+ "polling",
  "slab",
  "sluice",
  "tracing",
@@ -2857,16 +2600,6 @@ version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
 
-[[package]]
-name = "mime_guess"
-version = "2.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
-dependencies = [
- "mime",
- "unicase",
-]
-
 [[package]]
 name = "miniz_oxide"
 version = "0.3.7"
@@ -3404,17 +3137,6 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6cce106fd2646acbe31a0e4006f75779d535c26a44f153ada196e9edcfc6d944"
 
-[[package]]
-name = "polyval"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd"
-dependencies = [
- "cpuid-bool",
- "opaque-debug",
- "universal-hash",
-]
-
 [[package]]
 name = "postage"
 version = "0.4.1"
@@ -3557,7 +3279,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "prost-derive",
 ]
 
@@ -3567,7 +3289,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "heck 0.3.3",
  "itertools",
  "log",
@@ -3598,7 +3320,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "prost",
 ]
 
@@ -4018,7 +3740,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1c7c5f10864beba947e1a1b43f3ef46c8cc58d1c2ae549fa471713e8ff60787a"
 dependencies = [
- "cipher 0.3.0",
+ "cipher",
 ]
 
 [[package]]
@@ -4209,18 +3931,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "serde_qs"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5af82de3c6549b001bec34961ff2d6a54339a87bab37ce901b693401f27de6cb"
-dependencies = [
- "data-encoding",
- "percent-encoding",
- "serde",
- "thiserror",
-]
-
 [[package]]
 name = "serde_repr"
 version = "0.1.7"
@@ -4492,15 +4202,6 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 
-[[package]]
-name = "spinning_top"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c"
-dependencies = [
- "lock_api",
-]
-
 [[package]]
 name = "sqlformat"
 version = "0.1.6"
@@ -4535,7 +4236,7 @@ dependencies = [
  "base64 0.13.0",
  "bitflags",
  "byteorder",
- "bytes 1.0.1",
+ "bytes",
  "crc",
  "crossbeam-channel 0.5.0",
  "crossbeam-queue",
@@ -4568,6 +4269,7 @@ dependencies = [
  "stringprep",
  "thiserror",
  "time 0.2.27",
+ "tokio-stream",
  "url",
  "uuid",
  "webpki",
@@ -4601,8 +4303,9 @@ version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8199b421ecf3493ee9ef3e7bc90c904844cfb2ea7ea2f57347a93f52bfd3e057"
 dependencies = [
- "async-rustls",
- "async-std",
+ "once_cell",
+ "tokio",
+ "tokio-rustls",
 ]
 
 [[package]]
@@ -4708,28 +4411,6 @@ dependencies = [
  "rand 0.8.3",
 ]
 
-[[package]]
-name = "surf"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a154d33ca6b5e1fe6fd1c760e5a5cc1202425f6cca2e13229f16a69009f6328"
-dependencies = [
- "async-std",
- "async-trait",
- "cfg-if 1.0.0",
- "encoding_rs",
- "futures-util",
- "http-client",
- "http-types",
- "log",
- "mime_guess",
- "once_cell",
- "pin-project-lite 0.2.8",
- "serde",
- "serde_json",
- "web-sys",
-]
-
 [[package]]
 name = "sval"
 version = "1.0.0-alpha.5"
@@ -5054,7 +4735,7 @@ version = "1.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "libc",
  "memchr",
  "mio 0.7.14",
@@ -5078,6 +4759,28 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "tokio-rustls"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
+dependencies = [
+ "rustls",
+ "tokio",
+ "webpki",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
+dependencies = [
+ "futures-core",
+ "pin-project-lite 0.2.8",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-tungstenite"
 version = "0.17.1"
@@ -5096,7 +4799,7 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
 dependencies = [
- "bytes 1.0.1",
+ "bytes",
  "futures-core",
  "futures-sink",
  "pin-project-lite 0.2.8",
@@ -5136,7 +4839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8"
 dependencies = [
  "bitflags",
- "bytes 1.0.1",
+ "bytes",
  "futures-core",
  "futures-util",
  "http",
@@ -5306,7 +5009,7 @@ checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1"
 dependencies = [
  "base64 0.13.0",
  "byteorder",
- "bytes 1.0.1",
+ "bytes",
  "http",
  "httparse",
  "log",
@@ -5325,7 +5028,7 @@ checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5"
 dependencies = [
  "base64 0.13.0",
  "byteorder",
- "bytes 1.0.1",
+ "bytes",
  "http",
  "httparse",
  "log",
@@ -5429,16 +5132,6 @@ version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
 
-[[package]]
-name = "universal-hash"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
-dependencies = [
- "generic-array",
- "subtle",
-]
-
 [[package]]
 name = "untrusted"
 version = "0.7.1"
@@ -5500,7 +5193,6 @@ dependencies = [
  "log",
  "rand 0.8.3",
  "serde_json",
- "surf",
  "tempdir",
 ]
 
@@ -5633,18 +5325,6 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1"
-dependencies = [
- "cfg-if 1.0.0",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.74"
@@ -5890,6 +5570,7 @@ dependencies = [
  "ignore",
  "image",
  "indexmap",
+ "isahc",
  "journal",
  "language",
  "lazy_static",
@@ -5918,7 +5599,6 @@ dependencies = [
  "smallvec",
  "smol",
  "sum_tree",
- "surf",
  "tempdir",
  "text",
  "theme",

crates/auto_update/Cargo.toml 🔗

@@ -14,10 +14,10 @@ settings = { path = "../settings" }
 theme = { path = "../theme" }
 workspace = { path = "../workspace" }
 anyhow = "1.0.38"
+isahc = "1.7"
 lazy_static = "1.4"
 log = "0.4"
 serde = { version = "1", features = ["derive"] }
 serde_json = { version = "1.0.64", features = ["preserve_order"] }
 smol = "1.2.5"
-surf = "2.2"
 tempdir = "0.3.7"

crates/auto_update/src/auto_update.rs 🔗

@@ -1,5 +1,6 @@
-use anyhow::{anyhow, Result};
-use client::http::{self, HttpClient};
+use anyhow::{anyhow, Context, Result};
+use client::http::HttpClient;
+
 use gpui::{
     actions,
     elements::{Empty, MouseEventHandler, Text},
@@ -12,7 +13,6 @@ use serde::Deserialize;
 use settings::Settings;
 use smol::{fs::File, io::AsyncReadExt, process::Command};
 use std::{env, ffi::OsString, path::PathBuf, sync::Arc, time::Duration};
-use surf::Request;
 use workspace::{ItemHandle, StatusItemView};
 
 const POLL_INTERVAL: Duration = Duration::from_secs(60 * 60);
@@ -52,7 +52,7 @@ pub struct AutoUpdateIndicator {
 #[derive(Deserialize)]
 struct JsonRelease {
     version: String,
-    url: http::Url,
+    url: String,
 }
 
 impl Entity for AutoUpdater {
@@ -134,17 +134,22 @@ impl AutoUpdater {
             )
         });
         let mut response = client
-            .send(Request::new(
-                http::Method::Get,
-                http::Url::parse(&format!(
-                    "{server_url}/api/releases/latest?token={ACCESS_TOKEN}&asset=Zed.dmg"
-                ))?,
-            ))
+            .get(
+                &format!("{server_url}/api/releases/latest?token={ACCESS_TOKEN}&asset=Zed.dmg"),
+                Default::default(),
+                true,
+            )
             .await?;
-        let release = response
-            .body_json::<JsonRelease>()
+
+        let mut body = Vec::new();
+        response
+            .body_mut()
+            .read_to_end(&mut body)
             .await
-            .map_err(|err| anyhow!("error deserializing release {:?}", err))?;
+            .context("error reading release")?;
+        let release: JsonRelease =
+            serde_json::from_slice(body.as_slice()).context("error deserializing release")?;
+
         let latest_version = release.version.parse::<AppVersion>()?;
         if latest_version <= current_version {
             this.update(&mut cx, |this, cx| {
@@ -169,10 +174,8 @@ impl AutoUpdater {
             .map_or_else(|| cx.platform().app_path(), Ok)?;
 
         let mut dmg_file = File::create(&dmg_path).await?;
-        let response = client
-            .send(Request::new(http::Method::Get, release.url))
-            .await?;
-        smol::io::copy(response.bytes(), &mut dmg_file).await?;
+        let mut response = client.get(&release.url, Default::default(), true).await?;
+        smol::io::copy(response.body_mut(), &mut dmg_file).await?;
         log::info!("downloaded update. path:{:?}", dmg_path);
 
         this.update(&mut cx, |this, cx| {

crates/client/Cargo.toml 🔗

@@ -20,16 +20,17 @@ async-recursion = "0.3"
 async-tungstenite = { version = "0.16", features = ["async-tls"] }
 futures = "0.3"
 image = "0.23"
+isahc = "1.7"
 lazy_static = "1.4.0"
 log = { version = "0.4.16", features = ["kv_unstable_serde"] }
 parking_lot = "0.11.1"
 postage = { version = "0.4.1", features = ["futures-traits"] }
 rand = "0.8.3"
 smol = "1.2.5"
-surf = "2.2"
 thiserror = "1.0.29"
 time = "0.3"
 tiny_http = "0.8"
+url = "2.2"
 
 [dev-dependencies]
 gpui = { path = "../gpui", features = ["test-support"] }

crates/client/src/channel.rs 🔗

@@ -594,14 +594,13 @@ mod tests {
     use super::*;
     use crate::test::{FakeHttpClient, FakeServer};
     use gpui::TestAppContext;
-    use surf::http::Response;
 
     #[gpui::test]
     async fn test_channel_messages(cx: &mut TestAppContext) {
         cx.foreground().forbid_parking();
 
         let user_id = 5;
-        let http_client = FakeHttpClient::new(|_| async move { Ok(Response::new(404)) });
+        let http_client = FakeHttpClient::with_404_response();
         let mut client = Client::new(http_client.clone());
         let server = FakeServer::for_client(user_id, &mut client, &cx).await;
 

crates/client/src/client.rs 🔗

@@ -34,8 +34,8 @@ use std::{
     },
     time::{Duration, Instant},
 };
-use surf::{http::Method, Url};
 use thiserror::Error;
+use url::Url;
 use util::{ResultExt, TryFutureExt};
 
 pub use channel::*;
@@ -89,9 +89,11 @@ pub enum EstablishConnectionError {
     #[error("{0}")]
     Other(#[from] anyhow::Error),
     #[error("{0}")]
+    Http(#[from] http::Error),
+    #[error("{0}")]
     Io(#[from] std::io::Error),
     #[error("{0}")]
-    Http(#[from] async_tungstenite::tungstenite::http::Error),
+    Websocket(#[from] async_tungstenite::tungstenite::http::Error),
 }
 
 impl From<WebsocketError> for EstablishConnectionError {
@@ -779,30 +781,27 @@ impl Client {
         let http = self.http.clone();
         cx.background().spawn(async move {
             let mut rpc_url = format!("{}/rpc", *ZED_SERVER_URL);
-            let rpc_request = surf::Request::new(
-                Method::Get,
-                surf::Url::parse(&rpc_url).context("invalid ZED_SERVER_URL")?,
-            );
-            let rpc_response = http.send(rpc_request).await?;
-
+            let rpc_response = http.get(&rpc_url, Default::default(), false).await?;
             if rpc_response.status().is_redirection() {
                 rpc_url = rpc_response
-                    .header("Location")
+                    .headers()
+                    .get("Location")
                     .ok_or_else(|| anyhow!("missing location header in /rpc response"))?
-                    .as_str()
+                    .to_str()
+                    .map_err(|error| EstablishConnectionError::other(error))?
                     .to_string();
             }
             // Until we switch the zed.dev domain to point to the new Next.js app, there
             // will be no redirect required, and the app will connect directly to
             // wss://zed.dev/rpc.
-            else if rpc_response.status() != surf::StatusCode::UpgradeRequired {
+            else if rpc_response.status() != StatusCode::UPGRADE_REQUIRED {
                 Err(anyhow!(
                     "unexpected /rpc response status {}",
                     rpc_response.status()
                 ))?
             }
 
-            let mut rpc_url = surf::Url::parse(&rpc_url).context("invalid rpc url")?;
+            let mut rpc_url = Url::parse(&rpc_url).context("invalid rpc url")?;
             let rpc_host = rpc_url
                 .host_str()
                 .zip(rpc_url.port_or_known_default())

crates/client/src/http.rs 🔗

@@ -1,26 +1,49 @@
 pub use anyhow::{anyhow, Result};
 use futures::future::BoxFuture;
-use std::sync::Arc;
-pub use surf::{
-    http::{Method, Response as ServerResponse},
-    Request, Response, Url,
+use isahc::{
+    config::{Configurable, RedirectPolicy},
+    AsyncBody,
+};
+pub use isahc::{
+    http::{Method, Uri},
+    Error,
 };
+use std::sync::Arc;
+pub use url::Url;
+
+pub type Request = isahc::Request<AsyncBody>;
+pub type Response = isahc::Response<AsyncBody>;
 
 pub trait HttpClient: Send + Sync {
-    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response>>;
+    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, Error>>;
+
+    fn get<'a>(
+        &'a self,
+        uri: &str,
+        body: AsyncBody,
+        follow_redirects: bool,
+    ) -> BoxFuture<'a, Result<Response, Error>> {
+        self.send(
+            isahc::Request::builder()
+                .redirect_policy(if follow_redirects {
+                    RedirectPolicy::Follow
+                } else {
+                    RedirectPolicy::None
+                })
+                .method(Method::GET)
+                .uri(uri)
+                .body(body)
+                .unwrap(),
+        )
+    }
 }
 
 pub fn client() -> Arc<dyn HttpClient> {
-    Arc::new(surf::client())
+    Arc::new(isahc::HttpClient::builder().build().unwrap())
 }
 
-impl HttpClient for surf::Client {
-    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response>> {
-        Box::pin(async move {
-            Ok(self
-                .send(req)
-                .await
-                .map_err(|e| anyhow!("http request failed: {}", e))?)
-        })
+impl HttpClient for isahc::HttpClient {
+    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, Error>> {
+        Box::pin(async move { self.send_async(req).await })
     }
 }

crates/client/src/test.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{
-    http::{HttpClient, Request, Response, ServerResponse},
+    http::{self, HttpClient, Request, Response},
     Client, Connection, Credentials, EstablishConnectionError, UserStore,
 };
 use anyhow::{anyhow, Result};
@@ -176,14 +176,18 @@ impl FakeServer {
 }
 
 pub struct FakeHttpClient {
-    handler:
-        Box<dyn 'static + Send + Sync + Fn(Request) -> BoxFuture<'static, Result<ServerResponse>>>,
+    handler: Box<
+        dyn 'static
+            + Send
+            + Sync
+            + Fn(Request) -> BoxFuture<'static, Result<Response, http::Error>>,
+    >,
 }
 
 impl FakeHttpClient {
     pub fn new<Fut, F>(handler: F) -> Arc<dyn HttpClient>
     where
-        Fut: 'static + Send + Future<Output = Result<ServerResponse>>,
+        Fut: 'static + Send + Future<Output = Result<Response, http::Error>>,
         F: 'static + Send + Sync + Fn(Request) -> Fut,
     {
         Arc::new(Self {
@@ -192,7 +196,12 @@ impl FakeHttpClient {
     }
 
     pub fn with_404_response() -> Arc<dyn HttpClient> {
-        Self::new(|_| async move { Ok(ServerResponse::new(404)) })
+        Self::new(|_| async move {
+            Ok(isahc::Response::builder()
+                .status(404)
+                .body(Default::default())
+                .unwrap())
+        })
     }
 }
 
@@ -203,7 +212,7 @@ impl fmt::Debug for FakeHttpClient {
 }
 
 impl HttpClient for FakeHttpClient {
-    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response>> {
+    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response, crate::http::Error>> {
         let future = (self.handler)(req);
         Box::pin(async move { future.await.map(Into::into) })
     }

crates/client/src/user.rs 🔗

@@ -1,9 +1,6 @@
-use super::{
-    http::{HttpClient, Method, Request, Url},
-    proto, Client, Status, TypedEnvelope,
-};
-use anyhow::{anyhow, Context, Result};
-use futures::future;
+use super::{http::HttpClient, proto, Client, Status, TypedEnvelope};
+use anyhow::{anyhow, Result};
+use futures::{future, AsyncReadExt};
 use gpui::{AsyncAppContext, Entity, ImageData, ModelContext, ModelHandle, Task};
 use postage::{prelude::Stream, sink::Sink, watch};
 use std::{
@@ -255,22 +252,22 @@ impl Contact {
 }
 
 async fn fetch_avatar(http: &dyn HttpClient, url: &str) -> Result<Arc<ImageData>> {
-    let url = Url::parse(url).with_context(|| format!("failed to parse avatar url {:?}", url))?;
-    let mut request = Request::new(Method::Get, url);
-    request.middleware(surf::middleware::Redirect::default());
-
     let mut response = http
-        .send(request)
+        .get(url, Default::default(), true)
         .await
         .map_err(|e| anyhow!("failed to send user avatar request: {}", e))?;
+
     if !response.status().is_success() {
         return Err(anyhow!("avatar request failed {:?}", response.status()));
     }
-    let bytes = response
-        .body_bytes()
+
+    let mut body = Vec::new();
+    response
+        .body_mut()
+        .read_to_end(&mut body)
         .await
         .map_err(|e| anyhow!("failed to read user avatar response body: {}", e))?;
-    let format = image::guess_format(&bytes)?;
-    let image = image::load_from_memory_with_format(&bytes, format)?.into_bgra8();
+    let format = image::guess_format(&body)?;
+    let image = image::load_from_memory_with_format(&body, format)?.into_bgra8();
     Ok(ImageData::new(image))
 }

crates/collab/Cargo.toml 🔗

@@ -43,7 +43,7 @@ toml = "0.5.8"
 
 [dependencies.sqlx]
 version = "0.5.2"
-features = ["runtime-async-std-rustls", "postgres", "time", "uuid"]
+features = ["runtime-tokio-rustls", "postgres", "time", "uuid"]
 
 [dev-dependencies]
 collections = { path = "../collections", features = ["test-support"] }

crates/collab/src/bin/seed.rs 🔗

@@ -1,4 +1,4 @@
-use db::{Db, UserId};
+use db::{Db, PostgresDb, UserId};
 use rand::prelude::*;
 use time::{Duration, OffsetDateTime};
 
@@ -6,11 +6,11 @@ use time::{Duration, OffsetDateTime};
 #[path = "../db.rs"]
 mod db;
 
-#[async_std::main]
+#[tokio::main]
 async fn main() {
     let mut rng = StdRng::from_entropy();
     let database_url = std::env::var("DATABASE_URL").expect("missing DATABASE_URL env var");
-    let db = Db::new(&database_url, 5)
+    let db = PostgresDb::new(&database_url, 5)
         .await
         .expect("failed to connect to postgres database");
 

crates/collab/src/db.rs 🔗

@@ -57,7 +57,7 @@ pub trait Db: Send + Sync {
         before_id: Option<MessageId>,
     ) -> Result<Vec<ChannelMessage>>;
     #[cfg(test)]
-    async fn teardown(&self, name: &str, url: &str);
+    async fn teardown(&self, url: &str);
 }
 
 pub struct PostgresDb {
@@ -68,7 +68,7 @@ impl PostgresDb {
     pub async fn new(url: &str, max_connections: u32) -> Result<Self> {
         let pool = DbOptions::new()
             .max_connections(max_connections)
-            .connect(url)
+            .connect(&url)
             .await
             .context("failed to connect to postgres database")?;
         Ok(Self { pool })
@@ -81,11 +81,11 @@ impl Db for PostgresDb {
 
     async fn create_user(&self, github_login: &str, admin: bool) -> Result<UserId> {
         let query = "
-                INSERT INTO users (github_login, admin)
-                VALUES ($1, $2)
-                ON CONFLICT (github_login) DO UPDATE SET github_login = excluded.github_login
-                RETURNING id
-            ";
+            INSERT INTO users (github_login, admin)
+            VALUES ($1, $2)
+            ON CONFLICT (github_login) DO UPDATE SET github_login = excluded.github_login
+            RETURNING id
+        ";
         Ok(sqlx::query_scalar(query)
             .bind(github_login)
             .bind(admin)
@@ -107,11 +107,10 @@ impl Db for PostgresDb {
     async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
         let ids = ids.into_iter().map(|id| id.0).collect::<Vec<_>>();
         let query = "
-                SELECT users.*
-                FROM users
-                WHERE users.id = ANY ($1)
-            ";
-
+            SELECT users.*
+            FROM users
+            WHERE users.id = ANY ($1)
+        ";
         Ok(sqlx::query_as(query)
             .bind(&ids)
             .fetch_all(&self.pool)
@@ -160,18 +159,18 @@ impl Db for PostgresDb {
         max_access_token_count: usize,
     ) -> Result<()> {
         let insert_query = "
-                INSERT INTO access_tokens (user_id, hash)
-                VALUES ($1, $2);
-            ";
+            INSERT INTO access_tokens (user_id, hash)
+            VALUES ($1, $2);
+        ";
         let cleanup_query = "
-                DELETE FROM access_tokens
-                WHERE id IN (
-                    SELECT id from access_tokens
-                    WHERE user_id = $1
-                    ORDER BY id DESC
-                    OFFSET $3
-                )
-            ";
+            DELETE FROM access_tokens
+            WHERE id IN (
+                SELECT id from access_tokens
+                WHERE user_id = $1
+                ORDER BY id DESC
+                OFFSET $3
+            )
+        ";
 
         let mut tx = self.pool.begin().await?;
         sqlx::query(insert_query)
@@ -190,11 +189,11 @@ impl Db for PostgresDb {
 
     async fn get_access_token_hashes(&self, user_id: UserId) -> Result<Vec<String>> {
         let query = "
-                SELECT hash
-                FROM access_tokens
-                WHERE user_id = $1
-                ORDER BY id DESC
-            ";
+            SELECT hash
+            FROM access_tokens
+            WHERE user_id = $1
+            ORDER BY id DESC
+        ";
         Ok(sqlx::query_scalar(query)
             .bind(user_id.0)
             .fetch_all(&self.pool)
@@ -207,10 +206,10 @@ impl Db for PostgresDb {
     #[cfg(any(test, feature = "seed-support"))]
     async fn find_org_by_slug(&self, slug: &str) -> Result<Option<Org>> {
         let query = "
-                SELECT *
-                FROM orgs
-                WHERE slug = $1
-            ";
+            SELECT *
+            FROM orgs
+            WHERE slug = $1
+        ";
         Ok(sqlx::query_as(query)
             .bind(slug)
             .fetch_optional(&self.pool)
@@ -220,10 +219,10 @@ impl Db for PostgresDb {
     #[cfg(any(test, feature = "seed-support"))]
     async fn create_org(&self, name: &str, slug: &str) -> Result<OrgId> {
         let query = "
-                INSERT INTO orgs (name, slug)
-                VALUES ($1, $2)
-                RETURNING id
-            ";
+            INSERT INTO orgs (name, slug)
+            VALUES ($1, $2)
+            RETURNING id
+        ";
         Ok(sqlx::query_scalar(query)
             .bind(name)
             .bind(slug)
@@ -235,10 +234,10 @@ impl Db for PostgresDb {
     #[cfg(any(test, feature = "seed-support"))]
     async fn add_org_member(&self, org_id: OrgId, user_id: UserId, is_admin: bool) -> Result<()> {
         let query = "
-                INSERT INTO org_memberships (org_id, user_id, admin)
-                VALUES ($1, $2, $3)
-                ON CONFLICT DO NOTHING
-            ";
+            INSERT INTO org_memberships (org_id, user_id, admin)
+            VALUES ($1, $2, $3)
+            ON CONFLICT DO NOTHING
+        ";
         Ok(sqlx::query(query)
             .bind(org_id.0)
             .bind(user_id.0)
@@ -253,10 +252,10 @@ impl Db for PostgresDb {
     #[cfg(any(test, feature = "seed-support"))]
     async fn create_org_channel(&self, org_id: OrgId, name: &str) -> Result<ChannelId> {
         let query = "
-                INSERT INTO channels (owner_id, owner_is_user, name)
-                VALUES ($1, false, $2)
-                RETURNING id
-            ";
+            INSERT INTO channels (owner_id, owner_is_user, name)
+            VALUES ($1, false, $2)
+            RETURNING id
+        ";
         Ok(sqlx::query_scalar(query)
             .bind(org_id.0)
             .bind(name)
@@ -269,12 +268,12 @@ impl Db for PostgresDb {
     #[cfg(any(test, feature = "seed-support"))]
     async fn get_org_channels(&self, org_id: OrgId) -> Result<Vec<Channel>> {
         let query = "
-                SELECT *
-                FROM channels
-                WHERE
-                    channels.owner_is_user = false AND
-                    channels.owner_id = $1
-            ";
+            SELECT *
+            FROM channels
+            WHERE
+                channels.owner_is_user = false AND
+                channels.owner_id = $1
+        ";
         Ok(sqlx::query_as(query)
             .bind(org_id.0)
             .fetch_all(&self.pool)
@@ -283,14 +282,14 @@ impl Db for PostgresDb {
 
     async fn get_accessible_channels(&self, user_id: UserId) -> Result<Vec<Channel>> {
         let query = "
-                SELECT
-                    channels.*
-                FROM
-                    channel_memberships, channels
-                WHERE
-                    channel_memberships.user_id = $1 AND
-                    channel_memberships.channel_id = channels.id
-            ";
+            SELECT
+                channels.*
+            FROM
+                channel_memberships, channels
+            WHERE
+                channel_memberships.user_id = $1 AND
+                channel_memberships.channel_id = channels.id
+        ";
         Ok(sqlx::query_as(query)
             .bind(user_id.0)
             .fetch_all(&self.pool)
@@ -303,11 +302,11 @@ impl Db for PostgresDb {
         channel_id: ChannelId,
     ) -> Result<bool> {
         let query = "
-                SELECT id
-                FROM channel_memberships
-                WHERE user_id = $1 AND channel_id = $2
-                LIMIT 1
-            ";
+            SELECT id
+            FROM channel_memberships
+            WHERE user_id = $1 AND channel_id = $2
+            LIMIT 1
+        ";
         Ok(sqlx::query_scalar::<_, i32>(query)
             .bind(user_id.0)
             .bind(channel_id.0)
@@ -324,10 +323,10 @@ impl Db for PostgresDb {
         is_admin: bool,
     ) -> Result<()> {
         let query = "
-                INSERT INTO channel_memberships (channel_id, user_id, admin)
-                VALUES ($1, $2, $3)
-                ON CONFLICT DO NOTHING
-            ";
+            INSERT INTO channel_memberships (channel_id, user_id, admin)
+            VALUES ($1, $2, $3)
+            ON CONFLICT DO NOTHING
+        ";
         Ok(sqlx::query(query)
             .bind(channel_id.0)
             .bind(user_id.0)
@@ -348,11 +347,11 @@ impl Db for PostgresDb {
         nonce: u128,
     ) -> Result<MessageId> {
         let query = "
-                INSERT INTO channel_messages (channel_id, sender_id, body, sent_at, nonce)
-                VALUES ($1, $2, $3, $4, $5)
-                ON CONFLICT (nonce) DO UPDATE SET nonce = excluded.nonce
-                RETURNING id
-            ";
+            INSERT INTO channel_messages (channel_id, sender_id, body, sent_at, nonce)
+            VALUES ($1, $2, $3, $4, $5)
+            ON CONFLICT (nonce) DO UPDATE SET nonce = excluded.nonce
+            RETURNING id
+        ";
         Ok(sqlx::query_scalar(query)
             .bind(channel_id.0)
             .bind(sender_id.0)
@@ -371,19 +370,19 @@ impl Db for PostgresDb {
         before_id: Option<MessageId>,
     ) -> Result<Vec<ChannelMessage>> {
         let query = r#"
-                SELECT * FROM (
-                    SELECT
-                        id, channel_id, sender_id, body, sent_at AT TIME ZONE 'UTC' as sent_at, nonce
-                    FROM
-                        channel_messages
-                    WHERE
-                        channel_id = $1 AND
-                        id < $2
-                    ORDER BY id DESC
-                    LIMIT $3
-                ) as recent_messages
-                ORDER BY id ASC
-            "#;
+            SELECT * FROM (
+                SELECT
+                    id, channel_id, sender_id, body, sent_at AT TIME ZONE 'UTC' as sent_at, nonce
+                FROM
+                    channel_messages
+                WHERE
+                    channel_id = $1 AND
+                    id < $2
+                ORDER BY id DESC
+                LIMIT $3
+            ) as recent_messages
+            ORDER BY id ASC
+        "#;
         Ok(sqlx::query_as(query)
             .bind(channel_id.0)
             .bind(before_id.unwrap_or(MessageId::MAX))
@@ -393,19 +392,15 @@ impl Db for PostgresDb {
     }
 
     #[cfg(test)]
-    async fn teardown(&self, name: &str, url: &str) {
+    async fn teardown(&self, url: &str) {
         use util::ResultExt;
 
         let query = "
-                SELECT pg_terminate_backend(pg_stat_activity.pid)
-                FROM pg_stat_activity
-                WHERE pg_stat_activity.datname = '{}' AND pid <> pg_backend_pid();
-            ";
-        sqlx::query(query)
-            .bind(name)
-            .execute(&self.pool)
-            .await
-            .log_err();
+            SELECT pg_terminate_backend(pg_stat_activity.pid)
+            FROM pg_stat_activity
+            WHERE pg_stat_activity.datname = current_database() AND pid <> pg_backend_pid();
+        ";
+        sqlx::query(query).execute(&self.pool).await.log_err();
         self.pool.close().await;
         <sqlx::Postgres as sqlx::migrate::MigrateDatabase>::drop_database(url)
             .await
@@ -480,7 +475,7 @@ pub mod tests {
     use super::*;
     use anyhow::anyhow;
     use collections::BTreeMap;
-    use gpui::{executor::Background, TestAppContext};
+    use gpui::executor::Background;
     use lazy_static::lazy_static;
     use parking_lot::Mutex;
     use rand::prelude::*;
@@ -491,9 +486,12 @@ pub mod tests {
     use std::{path::Path, sync::Arc};
     use util::post_inc;
 
-    #[gpui::test]
-    async fn test_get_users_by_ids(cx: &mut TestAppContext) {
-        for test_db in [TestDb::postgres(), TestDb::fake(cx.background())] {
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_get_users_by_ids() {
+        for test_db in [
+            TestDb::postgres().await,
+            TestDb::fake(Arc::new(gpui::executor::Background::new())),
+        ] {
             let db = test_db.db();
 
             let user = db.create_user("user", false).await.unwrap();
@@ -531,9 +529,12 @@ pub mod tests {
         }
     }
 
-    #[gpui::test]
-    async fn test_recent_channel_messages(cx: &mut TestAppContext) {
-        for test_db in [TestDb::postgres(), TestDb::fake(cx.background())] {
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_recent_channel_messages() {
+        for test_db in [
+            TestDb::postgres().await,
+            TestDb::fake(Arc::new(gpui::executor::Background::new())),
+        ] {
             let db = test_db.db();
             let user = db.create_user("user", false).await.unwrap();
             let org = db.create_org("org", "org").await.unwrap();
@@ -567,9 +568,12 @@ pub mod tests {
         }
     }
 
-    #[gpui::test]
-    async fn test_channel_message_nonces(cx: &mut TestAppContext) {
-        for test_db in [TestDb::postgres(), TestDb::fake(cx.background())] {
+    #[tokio::test(flavor = "multi_thread")]
+    async fn test_channel_message_nonces() {
+        for test_db in [
+            TestDb::postgres().await,
+            TestDb::fake(Arc::new(gpui::executor::Background::new())),
+        ] {
             let db = test_db.db();
             let user = db.create_user("user", false).await.unwrap();
             let org = db.create_org("org", "org").await.unwrap();
@@ -598,9 +602,9 @@ pub mod tests {
         }
     }
 
-    #[gpui::test]
+    #[tokio::test(flavor = "multi_thread")]
     async fn test_create_access_tokens() {
-        let test_db = TestDb::postgres();
+        let test_db = TestDb::postgres().await;
         let db = test_db.db();
         let user = db.create_user("the-user", false).await.unwrap();
 
@@ -632,12 +636,11 @@ pub mod tests {
 
     pub struct TestDb {
         pub db: Option<Arc<dyn Db>>,
-        pub name: String,
         pub url: String,
     }
 
     impl TestDb {
-        pub fn postgres() -> Self {
+        pub async fn postgres() -> Self {
             lazy_static! {
                 static ref LOCK: Mutex<()> = Mutex::new(());
             }
@@ -647,18 +650,14 @@ pub mod tests {
             let name = format!("zed-test-{}", rng.gen::<u128>());
             let url = format!("postgres://postgres@localhost/{}", name);
             let migrations_path = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/migrations"));
-            let db = futures::executor::block_on(async {
-                Postgres::create_database(&url)
-                    .await
-                    .expect("failed to create test db");
-                let db = PostgresDb::new(&url, 5).await.unwrap();
-                let migrator = Migrator::new(migrations_path).await.unwrap();
-                migrator.run(&db.pool).await.unwrap();
-                db
-            });
+            Postgres::create_database(&url)
+                .await
+                .expect("failed to create test db");
+            let db = PostgresDb::new(&url, 5).await.unwrap();
+            let migrator = Migrator::new(migrations_path).await.unwrap();
+            migrator.run(&db.pool).await.unwrap();
             Self {
                 db: Some(Arc::new(db)),
-                name,
                 url,
             }
         }
@@ -666,8 +665,7 @@ pub mod tests {
         pub fn fake(background: Arc<Background>) -> Self {
             Self {
                 db: Some(Arc::new(FakeDb::new(background))),
-                name: "fake".to_string(),
-                url: "fake".to_string(),
+                url: Default::default(),
             }
         }
 
@@ -679,7 +677,7 @@ pub mod tests {
     impl Drop for TestDb {
         fn drop(&mut self) {
             if let Some(db) = self.db.take() {
-                futures::executor::block_on(db.teardown(&self.name, &self.url));
+                futures::executor::block_on(db.teardown(&self.url));
             }
         }
     }
@@ -960,6 +958,6 @@ pub mod tests {
             Ok(messages)
         }
 
-        async fn teardown(&self, _name: &str, _url: &str) {}
+        async fn teardown(&self, _: &str) {}
     }
 }

crates/gpui/src/executor.rs 🔗

@@ -659,7 +659,11 @@ impl Background {
                     }
                 }
             }
-            _ => panic!("this method can only be called on a deterministic executor"),
+            _ => {
+                log::info!("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+                // panic!("this method can only be called on a deterministic executor")
+            }
         }
     }
 }

crates/util/Cargo.toml 🔗

@@ -14,7 +14,6 @@ anyhow = "1.0.38"
 futures = "0.3"
 log = { version = "0.4.16", features = ["kv_unstable_serde"] }
 rand = { version = "0.8", optional = true }
-surf = "2.2"
 tempdir = { version = "0.3.7", optional = true }
 serde_json = { version = "1.0.64", features = [
     "preserve_order",

crates/util/src/lib.rs 🔗

@@ -153,33 +153,3 @@ mod tests {
         assert_eq!(vec, &[1000, 101, 21, 19, 17, 13, 9, 8]);
     }
 }
-
-// Allow surf Results to accept context like other Results do when
-// using anyhow.
-pub trait SurfResultExt {
-    fn context<C>(self, cx: C) -> Self
-    where
-        C: std::fmt::Display + Send + Sync + 'static;
-
-    fn with_context<C, F>(self, f: F) -> Self
-    where
-        C: std::fmt::Display + Send + Sync + 'static,
-        F: FnOnce() -> C;
-}
-
-impl<T> SurfResultExt for surf::Result<T> {
-    fn context<C>(self, cx: C) -> Self
-    where
-        C: std::fmt::Display + Send + Sync + 'static,
-    {
-        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(cx)))
-    }
-
-    fn with_context<C, F>(self, f: F) -> Self
-    where
-        C: std::fmt::Display + Send + Sync + 'static,
-        F: FnOnce() -> C,
-    {
-        self.map_err(|e| surf::Error::new(e.status(), e.into_inner().context(f())))
-    }
-}

crates/workspace/src/workspace.rs 🔗

@@ -623,9 +623,7 @@ impl WorkspaceParams {
 
         let fs = project::FakeFs::new(cx.background().clone());
         let languages = Arc::new(LanguageRegistry::test());
-        let http_client = client::test::FakeHttpClient::new(|_| async move {
-            Ok(client::http::ServerResponse::new(404))
-        });
+        let http_client = client::test::FakeHttpClient::with_404_response();
         let client = Client::new(http_client.clone());
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
         let project = Project::local(

crates/zed/Cargo.toml 🔗

@@ -62,6 +62,7 @@ http-auth-basic = "0.1.3"
 ignore = "0.4"
 image = "0.23"
 indexmap = "1.6.2"
+isahc = "1.7"
 lazy_static = "1.4.0"
 libc = "0.2"
 log = { version = "0.4.16", features = ["kv_unstable_serde"] }
@@ -79,7 +80,6 @@ serde_path_to_error = "0.1.4"
 simplelog = "0.9"
 smallvec = { version = "1.6", features = ["union"] }
 smol = "1.2.5"
-surf = "2.2"
 tempdir = { version = "0.3.7" }
 thiserror = "1.0.29"
 tiny_http = "0.8"

crates/zed/src/languages/c.rs 🔗

@@ -1,6 +1,6 @@
 use super::installation::{latest_github_release, GitHubLspBinaryVersion};
-use anyhow::{anyhow, Result};
-use client::http::{HttpClient, Method};
+use anyhow::{anyhow, Context, Result};
+use client::http::HttpClient;
 use futures::{future::BoxFuture, FutureExt, StreamExt};
 pub use language::*;
 use smol::fs::{self, File};
@@ -41,14 +41,10 @@ impl super::LspAdapter for CLspAdapter {
             let binary_path = version_dir.join("bin/clangd");
 
             if fs::metadata(&binary_path).await.is_err() {
-                let response = http
-                    .send(
-                        surf::RequestBuilder::new(Method::Get, version.url)
-                            .middleware(surf::middleware::Redirect::default())
-                            .build(),
-                    )
+                let mut response = http
+                    .get(&version.url, Default::default(), true)
                     .await
-                    .map_err(|err| anyhow!("error downloading release: {}", err))?;
+                    .context("error downloading release")?;
                 let mut file = File::create(&zip_path).await?;
                 if !response.status().is_success() {
                     Err(anyhow!(
@@ -56,7 +52,7 @@ impl super::LspAdapter for CLspAdapter {
                         response.status().to_string()
                     ))?;
                 }
-                futures::io::copy(response, &mut file).await?;
+                futures::io::copy(response.body_mut(), &mut file).await?;
 
                 let unzip_status = smol::process::Command::new("unzip")
                     .current_dir(&container_dir)

crates/zed/src/languages/installation.rs 🔗

@@ -1,11 +1,13 @@
 use anyhow::{anyhow, Context, Result};
-use client::http::{self, HttpClient, Method};
+use client::http::HttpClient;
+
 use serde::Deserialize;
+use smol::io::AsyncReadExt;
 use std::{path::Path, sync::Arc};
 
 pub struct GitHubLspBinaryVersion {
     pub name: String,
-    pub url: http::Url,
+    pub url: String,
 }
 
 #[derive(Deserialize)]
@@ -30,7 +32,7 @@ pub(crate) struct GithubRelease {
 #[derive(Deserialize)]
 pub(crate) struct GithubReleaseAsset {
     name: String,
-    browser_download_url: http::Url,
+    browser_download_url: String,
 }
 
 pub async fn npm_package_latest_version(name: &str) -> Result<String> {
@@ -81,23 +83,24 @@ pub async fn latest_github_release(
     http: Arc<dyn HttpClient>,
     asset_name: impl Fn(&str) -> String,
 ) -> Result<GitHubLspBinaryVersion> {
-    let release = http
-        .send(
-            surf::RequestBuilder::new(
-                Method::Get,
-                http::Url::parse(&format!(
-                    "https://api.github.com/repos/{repo_name_with_owner}/releases/latest"
-                ))
-                .unwrap(),
-            )
-            .middleware(surf::middleware::Redirect::default())
-            .build(),
+    let mut response = http
+        .get(
+            &format!("https://api.github.com/repos/{repo_name_with_owner}/releases/latest"),
+            Default::default(),
+            true,
         )
         .await
-        .map_err(|err| anyhow!("error fetching latest release: {}", err))?
-        .body_json::<GithubRelease>()
+        .context("error fetching latest release")?;
+
+    let mut body = Vec::new();
+    response
+        .body_mut()
+        .read_to_end(&mut body)
         .await
-        .map_err(|err| anyhow!("error parsing latest release: {}", err))?;
+        .context("error reading latest release")?;
+
+    let release: GithubRelease =
+        serde_json::from_slice(body.as_slice()).context("error deserializing latest release")?;
     let asset_name = asset_name(&release.name);
     let asset = release
         .assets

crates/zed/src/languages/rust.rs 🔗

@@ -1,8 +1,8 @@
 use super::installation::{latest_github_release, GitHubLspBinaryVersion};
 use anyhow::{anyhow, Result};
 use async_compression::futures::bufread::GzipDecoder;
-use client::http::{HttpClient, Method};
-use futures::{future::BoxFuture, FutureExt, StreamExt};
+use client::http::HttpClient;
+use futures::{future::BoxFuture, io::BufReader, FutureExt, StreamExt};
 pub use language::*;
 use lazy_static::lazy_static;
 use regex::Regex;
@@ -42,15 +42,11 @@ impl LspAdapter for RustLspAdapter {
             let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
 
             if fs::metadata(&destination_path).await.is_err() {
-                let response = http
-                    .send(
-                        surf::RequestBuilder::new(Method::Get, version.url)
-                            .middleware(surf::middleware::Redirect::default())
-                            .build(),
-                    )
+                let mut response = http
+                    .get(&version.url, Default::default(), true)
                     .await
                     .map_err(|err| anyhow!("error downloading release: {}", err))?;
-                let decompressed_bytes = GzipDecoder::new(response);
+                let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
                 let mut file = File::create(&destination_path).await?;
                 futures::io::copy(decompressed_bytes, &mut file).await?;
                 fs::set_permissions(