Rename ZedHttpClient for clarity (#8320)

This PR renames the `ZedHttpClient` to `HttpClientWithUrl` to make it
slightly clearer that it still is holding a `dyn HttpClient` as opposed
to being a concrete implementation.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-02-24 00:07:24 -05:00 committed by GitHub
parent 58463b2e97
commit ba4e1699ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 77 additions and 70 deletions

View file

@ -29,7 +29,7 @@ use std::{
}; };
use update_notification::UpdateNotification; use update_notification::UpdateNotification;
use util::{ use util::{
http::{HttpClient, ZedHttpClient}, http::{HttpClient, HttpClientWithUrl},
ResultExt, ResultExt,
}; };
use workspace::Workspace; use workspace::Workspace;
@ -67,7 +67,7 @@ pub enum AutoUpdateStatus {
pub struct AutoUpdater { pub struct AutoUpdater {
status: AutoUpdateStatus, status: AutoUpdateStatus,
current_version: SemanticVersion, current_version: SemanticVersion,
http_client: Arc<ZedHttpClient>, http_client: Arc<HttpClientWithUrl>,
pending_poll: Option<Task<Option<()>>>, pending_poll: Option<Task<Option<()>>>,
} }
@ -115,7 +115,7 @@ struct ReleaseNotesBody {
release_notes: String, release_notes: String,
} }
pub fn init(http_client: Arc<ZedHttpClient>, cx: &mut AppContext) { pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut AppContext) {
AutoUpdateSetting::register(cx); AutoUpdateSetting::register(cx);
cx.observe_new_views(|workspace: &mut Workspace, _cx| { cx.observe_new_views(|workspace: &mut Workspace, _cx| {
@ -181,7 +181,7 @@ pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<(
let current_version = auto_updater.current_version; let current_version = auto_updater.current_version;
let url = &auto_updater let url = &auto_updater
.http_client .http_client
.zed_url(&format!("/releases/{release_channel}/{current_version}")); .build_url(&format!("/releases/{release_channel}/{current_version}"));
cx.open_url(&url); cx.open_url(&url);
} }
@ -193,7 +193,7 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Wo
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
let client = client::Client::global(cx).http_client(); let client = client::Client::global(cx).http_client();
let url = client.zed_url(&format!( let url = client.build_url(&format!(
"/api/release_notes/{}/{}", "/api/release_notes/{}/{}",
release_channel.dev_name(), release_channel.dev_name(),
version version
@ -283,7 +283,7 @@ impl AutoUpdater {
cx.default_global::<GlobalAutoUpdate>().0.clone() cx.default_global::<GlobalAutoUpdate>().0.clone()
} }
fn new(current_version: SemanticVersion, http_client: Arc<ZedHttpClient>) -> Self { fn new(current_version: SemanticVersion, http_client: Arc<HttpClientWithUrl>) -> Self {
Self { Self {
status: AutoUpdateStatus::Idle, status: AutoUpdateStatus::Idle,
current_version, current_version,
@ -337,7 +337,7 @@ impl AutoUpdater {
(this.http_client.clone(), this.current_version) (this.http_client.clone(), this.current_version)
})?; })?;
let mut url_string = client.zed_url(&format!( let mut url_string = client.build_url(&format!(
"/api/releases/latest?asset=Zed.dmg&os={}&arch={}", "/api/releases/latest?asset=Zed.dmg&os={}&arch={}",
OS, ARCH OS, ARCH
)); ));

View file

@ -42,7 +42,7 @@ use std::{
use telemetry::Telemetry; use telemetry::Telemetry;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use util::http::{HttpClient, ZedHttpClient}; use util::http::{HttpClient, HttpClientWithUrl};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
pub use rpc::*; pub use rpc::*;
@ -153,7 +153,7 @@ impl Global for GlobalClient {}
pub struct Client { pub struct Client {
id: AtomicU64, id: AtomicU64,
peer: Arc<Peer>, peer: Arc<Peer>,
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
telemetry: Arc<Telemetry>, telemetry: Arc<Telemetry>,
state: RwLock<ClientState>, state: RwLock<ClientState>,
@ -424,7 +424,7 @@ impl settings::Settings for TelemetrySettings {
impl Client { impl Client {
pub fn new( pub fn new(
clock: Arc<dyn SystemClock>, clock: Arc<dyn SystemClock>,
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
cx: &mut AppContext, cx: &mut AppContext,
) -> Arc<Self> { ) -> Arc<Self> {
let client = Arc::new(Self { let client = Arc::new(Self {
@ -447,7 +447,7 @@ impl Client {
self.id.load(std::sync::atomic::Ordering::SeqCst) self.id.load(std::sync::atomic::Ordering::SeqCst)
} }
pub fn http_client(&self) -> Arc<ZedHttpClient> { pub fn http_client(&self) -> Arc<HttpClientWithUrl> {
self.http.clone() self.http.clone()
} }
@ -970,14 +970,14 @@ impl Client {
} }
async fn get_rpc_url( async fn get_rpc_url(
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
release_channel: Option<ReleaseChannel>, release_channel: Option<ReleaseChannel>,
) -> Result<Url> { ) -> Result<Url> {
if let Some(url) = &*ZED_RPC_URL { if let Some(url) = &*ZED_RPC_URL {
return Url::parse(url).context("invalid rpc url"); return Url::parse(url).context("invalid rpc url");
} }
let mut url = http.zed_url("/rpc"); let mut url = http.build_url("/rpc");
if let Some(preview_param) = if let Some(preview_param) =
release_channel.and_then(|channel| channel.release_query_param()) release_channel.and_then(|channel| channel.release_query_param())
{ {
@ -1110,7 +1110,7 @@ impl Client {
// Open the Zed sign-in page in the user's browser, with query parameters that indicate // Open the Zed sign-in page in the user's browser, with query parameters that indicate
// that the user is signing in from a Zed app running on the same device. // that the user is signing in from a Zed app running on the same device.
let mut url = http.zed_url(&format!( let mut url = http.build_url(&format!(
"/native_app_signin?native_app_port={}&native_app_public_key={}", "/native_app_signin?native_app_port={}&native_app_public_key={}",
port, public_key_string port, public_key_string
)); ));
@ -1145,7 +1145,7 @@ impl Client {
} }
let post_auth_url = let post_auth_url =
http.zed_url("/native_app_signin_succeeded"); http.build_url("/native_app_signin_succeeded");
req.respond( req.respond(
tiny_http::Response::empty(302).with_header( tiny_http::Response::empty(302).with_header(
tiny_http::Header::from_bytes( tiny_http::Header::from_bytes(
@ -1187,7 +1187,7 @@ impl Client {
} }
async fn authenticate_as_admin( async fn authenticate_as_admin(
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
login: String, login: String,
mut api_token: String, mut api_token: String,
) -> Result<Credentials> { ) -> Result<Credentials> {

View file

@ -20,7 +20,7 @@ use telemetry_events::{
EditEvent, EditorEvent, Event, EventRequestBody, EventWrapper, MemoryEvent, SettingEvent, EditEvent, EditorEvent, Event, EventRequestBody, EventWrapper, MemoryEvent, SettingEvent,
}; };
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use util::http::{self, HttpClient, Method, ZedHttpClient}; use util::http::{self, HttpClient, HttpClientWithUrl, Method};
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
use util::ResultExt; use util::ResultExt;
use util::TryFutureExt; use util::TryFutureExt;
@ -29,7 +29,7 @@ use self::event_coalescer::EventCoalescer;
pub struct Telemetry { pub struct Telemetry {
clock: Arc<dyn SystemClock>, clock: Arc<dyn SystemClock>,
http_client: Arc<ZedHttpClient>, http_client: Arc<HttpClientWithUrl>,
executor: BackgroundExecutor, executor: BackgroundExecutor,
state: Arc<Mutex<TelemetryState>>, state: Arc<Mutex<TelemetryState>>,
} }
@ -75,7 +75,7 @@ static ZED_CLIENT_CHECKSUM_SEED: Lazy<Option<Vec<u8>>> = Lazy::new(|| {
impl Telemetry { impl Telemetry {
pub fn new( pub fn new(
clock: Arc<dyn SystemClock>, clock: Arc<dyn SystemClock>,
client: Arc<ZedHttpClient>, client: Arc<HttpClientWithUrl>,
cx: &mut AppContext, cx: &mut AppContext,
) -> Arc<Self> { ) -> Arc<Self> {
let release_channel = let release_channel =
@ -474,7 +474,7 @@ impl Telemetry {
let request = http::Request::builder() let request = http::Request::builder()
.method(Method::POST) .method(Method::POST)
.uri(this.http_client.zed_api_url("/telemetry/events")) .uri(this.http_client.build_zed_api_url("/telemetry/events"))
.header("Content-Type", "text/plain") .header("Content-Type", "text/plain")
.header("x-zed-checksum", checksum) .header("x-zed-checksum", checksum)
.body(json_bytes.into()); .body(json_bytes.into());

View file

@ -20,7 +20,7 @@ use std::{
time::Duration, time::Duration,
}; };
use theme::{ThemeRegistry, ThemeSettings}; use theme::{ThemeRegistry, ThemeSettings};
use util::http::{AsyncBody, ZedHttpClient}; use util::http::{AsyncBody, HttpClientWithUrl};
use util::TryFutureExt; use util::TryFutureExt;
use util::{http::HttpClient, paths::EXTENSIONS_DIR, ResultExt}; use util::{http::HttpClient, paths::EXTENSIONS_DIR, ResultExt};
@ -69,7 +69,7 @@ impl ExtensionStatus {
pub struct ExtensionStore { pub struct ExtensionStore {
manifest: Arc<RwLock<Manifest>>, manifest: Arc<RwLock<Manifest>>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
http_client: Arc<ZedHttpClient>, http_client: Arc<HttpClientWithUrl>,
extensions_dir: PathBuf, extensions_dir: PathBuf,
extensions_being_installed: HashSet<Arc<str>>, extensions_being_installed: HashSet<Arc<str>>,
extensions_being_uninstalled: HashSet<Arc<str>>, extensions_being_uninstalled: HashSet<Arc<str>>,
@ -125,7 +125,7 @@ actions!(zed, [ReloadExtensions]);
pub fn init( pub fn init(
fs: Arc<fs::RealFs>, fs: Arc<fs::RealFs>,
http_client: Arc<ZedHttpClient>, http_client: Arc<HttpClientWithUrl>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
theme_registry: Arc<ThemeRegistry>, theme_registry: Arc<ThemeRegistry>,
cx: &mut AppContext, cx: &mut AppContext,
@ -157,7 +157,7 @@ impl ExtensionStore {
pub fn new( pub fn new(
extensions_dir: PathBuf, extensions_dir: PathBuf,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
http_client: Arc<ZedHttpClient>, http_client: Arc<HttpClientWithUrl>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
theme_registry: Arc<ThemeRegistry>, theme_registry: Arc<ThemeRegistry>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
@ -236,7 +236,7 @@ impl ExtensionStore {
search: Option<&str>, search: Option<&str>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<Extension>>> { ) -> Task<Result<Vec<Extension>>> {
let url = self.http_client.zed_api_url(&format!( let url = self.http_client.build_zed_api_url(&format!(
"/extensions{query}", "/extensions{query}",
query = search query = search
.map(|search| format!("?filter={search}")) .map(|search| format!("?filter={search}"))
@ -276,7 +276,7 @@ impl ExtensionStore {
log::info!("installing extension {extension_id} {version}"); log::info!("installing extension {extension_id} {version}");
let url = self let url = self
.http_client .http_client
.zed_api_url(&format!("/extensions/{extension_id}/{version}/download")); .build_zed_api_url(&format!("/extensions/{extension_id}/{version}/download"));
let extensions_dir = self.extensions_dir(); let extensions_dir = self.extensions_dir();
let http_client = self.http_client.clone(); let http_client = self.http_client.clone();

View file

@ -299,7 +299,7 @@ impl FeedbackModal {
let installation_id = telemetry.installation_id(); let installation_id = telemetry.installation_id();
let is_staff = telemetry.is_staff(); let is_staff = telemetry.is_staff();
let http_client = zed_client.http_client(); let http_client = zed_client.http_client();
let feedback_endpoint = http_client.zed_url("/api/feedback"); let feedback_endpoint = http_client.build_url("/api/feedback");
let request = FeedbackRequestBody { let request = FeedbackRequestBody {
feedback_text: &feedback_text, feedback_text: &feedback_text,
email, email,

View file

@ -14,56 +14,62 @@ use std::fmt;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
pub use url::Url; pub use url::Url;
pub struct ZedHttpClient { /// An [`HttpClient`] that has a base URL.
pub zed_host: Mutex<String>, pub struct HttpClientWithUrl {
client: Box<dyn HttpClient>, base_url: Mutex<String>,
client: Arc<dyn HttpClient>,
} }
impl ZedHttpClient { impl HttpClientWithUrl {
pub fn zed_url(&self, path: &str) -> String { /// Returns a new [`HttpClientWithUrl`] with the given base URL.
format!("{}{}", self.zed_host.lock(), path) pub fn new(base_url: impl Into<String>) -> Self {
Self {
base_url: Mutex::new(base_url.into()),
client: client(),
}
} }
pub fn zed_api_url(&self, path: &str) -> String { /// Returns the base URL.
let zed_host = self.zed_host.lock().clone(); pub fn base_url(&self) -> String {
self.base_url.lock().clone()
}
let host = match zed_host.as_ref() { /// Sets the base URL.
pub fn set_base_url(&self, base_url: impl Into<String>) {
*self.base_url.lock() = base_url.into();
}
/// Builds a URL using the given path.
pub fn build_url(&self, path: &str) -> String {
format!("{}{}", self.base_url.lock(), path)
}
/// Builds a Zed API URL using the given path.
pub fn build_zed_api_url(&self, path: &str) -> String {
let base_url = self.base_url.lock().clone();
let base_api_url = match base_url.as_ref() {
"https://zed.dev" => "https://api.zed.dev", "https://zed.dev" => "https://api.zed.dev",
"https://staging.zed.dev" => "https://api-staging.zed.dev", "https://staging.zed.dev" => "https://api-staging.zed.dev",
"http://localhost:3000" => "http://localhost:8080", "http://localhost:3000" => "http://localhost:8080",
other => other, other => other,
}; };
format!("{}{}", host, path) format!("{}{}", base_api_url, path)
} }
} }
impl HttpClient for Arc<ZedHttpClient> { impl HttpClient for Arc<HttpClientWithUrl> {
fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>> { fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>> {
self.client.send(req) self.client.send(req)
} }
} }
impl HttpClient for ZedHttpClient { impl HttpClient for HttpClientWithUrl {
fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>> { fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>> {
self.client.send(req) self.client.send(req)
} }
} }
pub fn zed_client(zed_host: &str) -> Arc<ZedHttpClient> {
Arc::new(ZedHttpClient {
zed_host: Mutex::new(zed_host.to_string()),
client: Box::new(
isahc::HttpClient::builder()
.connect_timeout(Duration::from_secs(5))
.low_speed_timeout(100, Duration::from_secs(5))
.proxy(http_proxy_from_env())
.build()
.unwrap(),
),
})
}
pub trait HttpClient: Send + Sync { pub trait HttpClient: Send + Sync {
fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>>; fn send(&self, req: Request<AsyncBody>) -> BoxFuture<Result<Response<AsyncBody>, Error>>;
@ -134,20 +140,20 @@ pub struct FakeHttpClient {
#[cfg(feature = "test-support")] #[cfg(feature = "test-support")]
impl FakeHttpClient { impl FakeHttpClient {
pub fn create<Fut, F>(handler: F) -> Arc<ZedHttpClient> pub fn create<Fut, F>(handler: F) -> Arc<HttpClientWithUrl>
where where
Fut: 'static + Send + futures::Future<Output = Result<Response<AsyncBody>, Error>>, Fut: 'static + Send + futures::Future<Output = Result<Response<AsyncBody>, Error>>,
F: 'static + Send + Sync + Fn(Request<AsyncBody>) -> Fut, F: 'static + Send + Sync + Fn(Request<AsyncBody>) -> Fut,
{ {
Arc::new(ZedHttpClient { Arc::new(HttpClientWithUrl {
zed_host: Mutex::new("http://test.example".into()), base_url: Mutex::new("http://test.example".into()),
client: Box::new(Self { client: Arc::new(Self {
handler: Box::new(move |req| Box::pin(handler(req))), handler: Box::new(move |req| Box::pin(handler(req))),
}), }),
}) })
} }
pub fn with_404_response() -> Arc<ZedHttpClient> { pub fn with_404_response() -> Arc<HttpClientWithUrl> {
Self::create(|_| async move { Self::create(|_| async move {
Ok(Response::builder() Ok(Response::builder()
.status(404) .status(404)
@ -156,7 +162,7 @@ impl FakeHttpClient {
}) })
} }
pub fn with_200_response() -> Arc<ZedHttpClient> { pub fn with_200_response() -> Arc<HttpClientWithUrl> {
Self::create(|_| async move { Self::create(|_| async move {
Ok(Response::builder() Ok(Response::builder()
.status(200) .status(200)

View file

@ -46,7 +46,7 @@ use std::{
use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings}; use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
use util::{ use util::{
async_maybe, async_maybe,
http::{self, HttpClient, ZedHttpClient}, http::{HttpClient, HttpClientWithUrl},
paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR}, paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR},
ResultExt, ResultExt,
}; };
@ -140,7 +140,9 @@ fn main() {
client::init_settings(cx); client::init_settings(cx);
let clock = Arc::new(clock::RealSystemClock); let clock = Arc::new(clock::RealSystemClock);
let http = http::zed_client(&client::ClientSettings::get_global(cx).server_url); let http = Arc::new(HttpClientWithUrl::new(
&client::ClientSettings::get_global(cx).server_url,
));
let client = client::Client::new(clock, http.clone(), cx); let client = client::Client::new(clock, http.clone(), cx);
let mut languages = LanguageRegistry::new(login_shell_env_loaded); let mut languages = LanguageRegistry::new(login_shell_env_loaded);
@ -198,9 +200,8 @@ fn main() {
move |cx| { move |cx| {
languages.set_theme(cx.theme().clone()); languages.set_theme(cx.theme().clone());
let new_host = &client::ClientSettings::get_global(cx).server_url; let new_host = &client::ClientSettings::get_global(cx).server_url;
let mut host = http.zed_host.lock(); if &http.base_url() != new_host {
if &*host != new_host { http.set_base_url(new_host);
*host = new_host.clone();
if client.status().borrow().is_connected() { if client.status().borrow().is_connected() {
client.reconnect(&cx.to_async()); client.reconnect(&cx.to_async());
} }
@ -677,7 +678,7 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
})); }));
} }
fn upload_panics_and_crashes(http: Arc<ZedHttpClient>, cx: &mut AppContext) { fn upload_panics_and_crashes(http: Arc<HttpClientWithUrl>, cx: &mut AppContext) {
let telemetry_settings = *client::TelemetrySettings::get_global(cx); let telemetry_settings = *client::TelemetrySettings::get_global(cx);
cx.background_executor() cx.background_executor()
.spawn(async move { .spawn(async move {
@ -692,12 +693,12 @@ fn upload_panics_and_crashes(http: Arc<ZedHttpClient>, cx: &mut AppContext) {
.detach() .detach()
} }
/// upload panics to us (via zed.dev) /// Uploads panics via `zed.dev`.
async fn upload_previous_panics( async fn upload_previous_panics(
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
telemetry_settings: client::TelemetrySettings, telemetry_settings: client::TelemetrySettings,
) -> Result<Option<(i64, String)>> { ) -> Result<Option<(i64, String)>> {
let panic_report_url = http.zed_url("/api/panic"); let panic_report_url = http.build_url("/api/panic");
let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?; let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
let mut most_recent_panic = None; let mut most_recent_panic = None;
@ -766,7 +767,7 @@ static LAST_CRASH_UPLOADED: &'static str = "LAST_CRASH_UPLOADED";
/// upload crashes from apple's diagnostic reports to our server. /// upload crashes from apple's diagnostic reports to our server.
/// (only if telemetry is enabled) /// (only if telemetry is enabled)
async fn upload_previous_crashes( async fn upload_previous_crashes(
http: Arc<ZedHttpClient>, http: Arc<HttpClientWithUrl>,
most_recent_panic: Option<(i64, String)>, most_recent_panic: Option<(i64, String)>,
telemetry_settings: client::TelemetrySettings, telemetry_settings: client::TelemetrySettings,
) -> Result<()> { ) -> Result<()> {
@ -778,7 +779,7 @@ async fn upload_previous_crashes(
.unwrap_or("zed-2024-01-17-221900.ips".to_string()); // don't upload old crash reports from before we had this. .unwrap_or("zed-2024-01-17-221900.ips".to_string()); // don't upload old crash reports from before we had this.
let mut uploaded = last_uploaded.clone(); let mut uploaded = last_uploaded.clone();
let crash_report_url = http.zed_url("/api/crash"); let crash_report_url = http.build_url("/api/crash");
for dir in [&*CRASHES_DIR, &*CRASHES_RETIRED_DIR] { for dir in [&*CRASHES_DIR, &*CRASHES_RETIRED_DIR] {
let mut children = smol::fs::read_dir(&dir).await?; let mut children = smol::fs::read_dir(&dir).await?;