@@ -401,7 +401,15 @@ impl AutoUpdater {
release_channel = ReleaseChannel::Nightly;
}
- let release = Self::get_latest_release(&this, "zed-remote-server", os, arch, cx).await?;
+ let release = Self::get_latest_release(
+ &this,
+ "zed-remote-server",
+ os,
+ arch,
+ Some(release_channel),
+ cx,
+ )
+ .await?;
let servers_dir = paths::remote_servers_dir();
let channel_dir = servers_dir.join(release_channel.dev_name());
@@ -423,6 +431,7 @@ impl AutoUpdater {
asset: &str,
os: &str,
arch: &str,
+ release_channel: Option<ReleaseChannel>,
cx: &mut AsyncAppContext,
) -> Result<JsonRelease> {
let client = this.read_with(cx, |this, _| this.http_client.clone())?;
@@ -430,14 +439,10 @@ impl AutoUpdater {
"/api/releases/latest?asset={}&os={}&arch={}",
asset, os, arch
));
- cx.update(|cx| {
- if let Some(param) = ReleaseChannel::try_global(cx)
- .and_then(|release_channel| release_channel.release_query_param())
- {
- url_string += "&";
- url_string += param;
- }
- })?;
+ if let Some(param) = release_channel.and_then(|c| c.release_query_param()) {
+ url_string += "&";
+ url_string += param;
+ }
let mut response = client.get(&url_string, Default::default(), true).await?;
@@ -448,17 +453,34 @@ impl AutoUpdater {
.await
.context("error reading release")?;
- serde_json::from_slice(body.as_slice()).context("error deserializing release")
+ if !response.status().is_success() {
+ Err(anyhow!(
+ "failed to fetch release: {:?}",
+ String::from_utf8_lossy(&body),
+ ))?;
+ }
+
+ serde_json::from_slice(body.as_slice()).with_context(|| {
+ format!(
+ "error deserializing release {:?}",
+ String::from_utf8_lossy(&body),
+ )
+ })
}
async fn update(this: Model<Self>, mut cx: AsyncAppContext) -> Result<()> {
- let (client, current_version) = this.update(&mut cx, |this, cx| {
+ let (client, current_version, release_channel) = this.update(&mut cx, |this, cx| {
this.status = AutoUpdateStatus::Checking;
cx.notify();
- (this.http_client.clone(), this.current_version)
+ (
+ this.http_client.clone(),
+ this.current_version,
+ ReleaseChannel::try_global(cx),
+ )
})?;
- let release = Self::get_latest_release(&this, "zed", OS, ARCH, &mut cx).await?;
+ let release =
+ Self::get_latest_release(&this, "zed", OS, ARCH, release_channel, &mut cx).await?;
let should_download = match *RELEASE_CHANNEL {
ReleaseChannel::Nightly => cx
@@ -426,7 +426,8 @@ impl SshClientState {
delegate: Arc<dyn SshClientDelegate>,
cx: &AsyncAppContext,
) -> Result<Self> {
- use smol::fs::unix::PermissionsExt as _;
+ use futures::{io::BufReader, AsyncBufReadExt as _};
+ use smol::{fs::unix::PermissionsExt as _, net::unix::UnixListener};
use util::ResultExt as _;
let url = format!("{user}@{host}");
@@ -434,15 +435,16 @@ impl SshClientState {
.prefix("zed-ssh-session")
.tempdir()?;
- // Create a TCP listener to handle requests from the askpass program.
- let listener = smol::net::TcpListener::bind("127.0.0.1:0")
- .await
- .expect("failed to find open port");
- let askpass_port = listener.local_addr().unwrap().port();
+ // Create a domain socket listener to handle requests from the askpass program.
+ let askpass_socket = temp_dir.path().join("askpass.sock");
+ let listener =
+ UnixListener::bind(&askpass_socket).context("failed to create askpass socket")?;
+
let askpass_task = cx.spawn(|mut cx| async move {
while let Ok((mut stream, _)) = listener.accept().await {
let mut buffer = Vec::new();
- if stream.read_to_end(&mut buffer).await.is_err() {
+ let mut reader = BufReader::new(&mut stream);
+ if reader.read_until(b'\0', &mut buffer).await.is_err() {
buffer.clear();
}
let password_prompt = String::from_utf8_lossy(&buffer);
@@ -458,10 +460,12 @@ impl SshClientState {
}
});
- // Create an askpass script that communicates back to this process using TCP.
+ // Create an askpass script that communicates back to this process.
let askpass_script = format!(
- "{shebang}\n echo \"$@\" | nc 127.0.0.1 {askpass_port} 2> /dev/null",
- shebang = "#!/bin/sh"
+ "{shebang}\n{print_args} | nc -U {askpass_socket} 2> /dev/null \n",
+ askpass_socket = askpass_socket.display(),
+ print_args = "printf '%s\\0' \"$@\"",
+ shebang = "#!/bin/sh",
);
let askpass_script_path = temp_dir.path().join("askpass.sh");
fs::write(&askpass_script_path, askpass_script).await?;
@@ -501,11 +505,11 @@ impl SshClientState {
}
Ok(Self {
- _master_process: master_process,
+ url,
port,
- _temp_dir: temp_dir,
socket_path,
- url,
+ _master_process: master_process,
+ _temp_dir: temp_dir,
})
}