diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 94552a3c7c..7888aa9354 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -1,6 +1,7 @@ #[cfg(any(test, feature = "test-support"))] pub mod test; +mod cloud; mod proxy; pub mod telemetry; pub mod user; @@ -52,6 +53,7 @@ use tokio::net::TcpStream; use url::Url; use util::{ConnectionResult, ResultExt}; +pub use cloud::*; pub use rpc::*; pub use telemetry_events::Event; pub use user::*; @@ -593,6 +595,10 @@ impl Client { self.http.clone() } + pub fn cloud_client(&self) -> Arc { + self.cloud_client.clone() + } + pub fn set_id(&self, id: u64) -> &Self { self.id.store(id, Ordering::SeqCst); self diff --git a/crates/client/src/cloud.rs b/crates/client/src/cloud.rs new file mode 100644 index 0000000000..39c9d04887 --- /dev/null +++ b/crates/client/src/cloud.rs @@ -0,0 +1,3 @@ +mod user_store; + +pub use user_store::*; diff --git a/crates/client/src/cloud/user_store.rs b/crates/client/src/cloud/user_store.rs new file mode 100644 index 0000000000..025bf79b5e --- /dev/null +++ b/crates/client/src/cloud/user_store.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; +use std::time::Duration; + +use anyhow::Context as _; +use cloud_api_client::{AuthenticatedUser, CloudApiClient}; +use gpui::{Context, Task}; +use util::{ResultExt as _, maybe}; + +pub struct CloudUserStore { + authenticated_user: Option, + _fetch_authenticated_user_task: Task<()>, +} + +impl CloudUserStore { + pub fn new(cloud_client: Arc, cx: &mut Context) -> Self { + Self { + authenticated_user: None, + _fetch_authenticated_user_task: cx.spawn(async move |this, cx| { + maybe!(async move { + loop { + if cloud_client.has_credentials() { + break; + } + + cx.background_executor() + .timer(Duration::from_millis(100)) + .await; + } + + let response = cloud_client.get_authenticated_user().await?; + this.update(cx, |this, _cx| { + this.authenticated_user = Some(response.user); + }) + }) + .await + .context("failed to fetch authenticated user") + .log_err(); + }), + } + } +} diff --git a/crates/cloud_api_client/src/cloud_api_client.rs b/crates/cloud_api_client/src/cloud_api_client.rs index b11e954468..b92136b02f 100644 --- a/crates/cloud_api_client/src/cloud_api_client.rs +++ b/crates/cloud_api_client/src/cloud_api_client.rs @@ -24,6 +24,10 @@ impl CloudApiClient { } } + pub fn has_credentials(&self) -> bool { + self.credentials.read().is_some() + } + pub fn set_credentials(&self, user_id: u32, access_token: String) { *self.credentials.write() = Some(Credentials { user_id, @@ -43,7 +47,7 @@ impl CloudApiClient { )) } - pub async fn get_authenticated_user(&self) -> Result { + pub async fn get_authenticated_user(&self) -> Result { let request = Request::builder() .method(Method::GET) .uri( @@ -69,8 +73,7 @@ impl CloudApiClient { let mut body = String::new(); response.body_mut().read_to_string(&mut body).await?; - let response: GetAuthenticatedUserResponse = serde_json::from_str(&body)?; - Ok(response.user) + Ok(serde_json::from_str(&body)?) } } diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index 5192db16a7..ab6bf1b912 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -8,6 +8,7 @@ use crate::{ use anyhow::anyhow; use call::ActiveCall; use channel::{ChannelBuffer, ChannelStore}; +use client::CloudUserStore; use client::{ self, ChannelId, Client, Connection, Credentials, EstablishConnectionError, UserStore, proto::PeerId, @@ -281,12 +282,14 @@ impl TestServer { .register_hosting_provider(Arc::new(git_hosting_providers::Github::public_instance())); let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let cloud_user_store = cx.new(|cx| CloudUserStore::new(client.cloud_client(), cx)); let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); let language_registry = Arc::new(LanguageRegistry::test(cx.executor())); let session = cx.new(|cx| AppSession::new(Session::test(), cx)); let app_state = Arc::new(workspace::AppState { client: client.clone(), user_store: user_store.clone(), + cloud_user_store, workspace_store, languages: language_registry, fs: fs.clone(), diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e58014e7b8..5271141620 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -15,6 +15,7 @@ mod toast_layer; mod toolbar; mod workspace_settings; +use client::CloudUserStore; pub use toast_layer::{ToastAction, ToastLayer, ToastView}; use anyhow::{Context as _, Result, anyhow}; @@ -839,6 +840,7 @@ pub struct AppState { pub languages: Arc, pub client: Arc, pub user_store: Entity, + pub cloud_user_store: Entity, pub workspace_store: Entity, pub fs: Arc, pub build_window_options: fn(Option, &mut App) -> WindowOptions, @@ -911,6 +913,7 @@ impl AppState { let client = Client::new(clock, http_client.clone(), cx); let session = cx.new(|cx| AppSession::new(Session::test(), cx)); let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let cloud_user_store = cx.new(|cx| CloudUserStore::new(client.cloud_client(), cx)); let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); theme::init(theme::LoadThemes::JustBase, cx); @@ -922,6 +925,7 @@ impl AppState { fs, languages, user_store, + cloud_user_store, workspace_store, node_runtime: NodeRuntime::unavailable(), build_window_options: |_, _| Default::default(), @@ -5689,6 +5693,7 @@ impl Workspace { let client = project.read(cx).client(); let user_store = project.read(cx).user_store(); + let cloud_user_store = cx.new(|cx| CloudUserStore::new(client.cloud_client(), cx)); let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); let session = cx.new(|cx| AppSession::new(Session::test(), cx)); @@ -5696,6 +5701,7 @@ impl Workspace { let app_state = Arc::new(AppState { languages: project.read(cx).languages().clone(), workspace_store, + cloud_user_store, client, user_store, fs: project.read(cx).fs().clone(), diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index d0b9c53397..1fd9fd3d97 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -5,7 +5,7 @@ use agent_ui::AgentPanel; use anyhow::{Context as _, Result}; use clap::{Parser, command}; use cli::FORCE_CLI_MODE_ENV_VAR_NAME; -use client::{Client, ProxySettings, UserStore, parse_zed_link}; +use client::{Client, CloudUserStore, ProxySettings, UserStore, parse_zed_link}; use collab_ui::channel_view::ChannelView; use collections::HashMap; use db::kvp::{GLOBAL_KEY_VALUE_STORE, KEY_VALUE_STORE}; @@ -457,6 +457,7 @@ pub fn main() { language::init(cx); languages::init(languages.clone(), node_runtime.clone(), cx); let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); + let cloud_user_store = cx.new(|cx| CloudUserStore::new(client.cloud_client(), cx)); let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx)); language_extension::init( @@ -516,6 +517,7 @@ pub fn main() { languages: languages.clone(), client: client.clone(), user_store: user_store.clone(), + cloud_user_store, fs: fs.clone(), build_window_options, workspace_store,