Move ChannelList, UserStore into client crate

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

Cargo.lock                     |  4 +++
crates/client/Cargo.toml       |  4 +++
crates/client/src/channel.rs   | 16 ++++++++------
crates/client/src/http.rs      |  0 
crates/client/src/lib.rs       |  6 +++++
crates/client/src/test.rs      | 38 ++++++++++++++++++++++++++++++++--
crates/client/src/user.rs      | 10 +++++---
crates/server/src/rpc.rs       |  8 +++---
crates/zed/Cargo.toml          |  2 
crates/zed/src/chat_panel.rs   |  6 ++--
crates/zed/src/lib.rs          |  8 +-----
crates/zed/src/main.rs         |  8 +++---
crates/zed/src/people_panel.rs |  7 +----
crates/zed/src/test.rs         | 39 +----------------------------------
crates/zed/src/workspace.rs    |  3 -
15 files changed, 83 insertions(+), 76 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1028,7 +1028,9 @@ dependencies = [
  "anyhow",
  "async-recursion",
  "async-tungstenite",
+ "futures",
  "gpui",
+ "image 0.23.14",
  "lazy_static",
  "log",
  "parking_lot",
@@ -1036,8 +1038,10 @@ dependencies = [
  "rand 0.8.3",
  "rpc",
  "smol",
+ "sum_tree",
  "surf",
  "thiserror",
+ "time 0.3.2",
  "tiny_http",
  "util",
 ]

crates/client/Cargo.toml 🔗

@@ -10,10 +10,13 @@ test-support = []
 gpui = { path = "../gpui" }
 util = { path = "../util" }
 rpc = { path = "../rpc" }
+sum_tree = { path = "../sum_tree" }
 
 anyhow = "1.0.38"
 async-recursion = "0.3"
 async-tungstenite = { version = "0.14", features = ["async-tls"] }
+futures = "0.3"
+image = "0.23"
 lazy_static = "1.4.0"
 log = "0.4"
 parking_lot = "0.11.1"
@@ -22,4 +25,5 @@ rand = "0.8.3"
 smol = "1.2.5"
 surf = "2.2"
 thiserror = "1.0.29"
+time = "0.3"
 tiny_http = "0.8"

crates/zed/src/channel.rs → crates/client/src/channel.rs 🔗

@@ -1,6 +1,9 @@
-use crate::user::{User, UserStore};
+use super::{
+    proto,
+    user::{User, UserStore},
+    Client, Status, Subscription, TypedEnvelope,
+};
 use anyhow::{anyhow, Context, Result};
-use client::{proto, Client, TypedEnvelope};
 use gpui::{
     AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
 };
@@ -38,7 +41,7 @@ pub struct Channel {
     user_store: ModelHandle<UserStore>,
     rpc: Arc<Client>,
     rng: StdRng,
-    _subscription: client::Subscription,
+    _subscription: Subscription,
 }
 
 #[derive(Clone, Debug)]
@@ -91,7 +94,7 @@ impl ChannelList {
                 let mut status = rpc.status();
                 while let Some((status, this)) = status.recv().await.zip(this.upgrade(&cx)) {
                     match status {
-                        client::Status::Connected { .. } => {
+                        Status::Connected { .. } => {
                             let response = rpc
                                 .request(proto::GetChannels {})
                                 .await
@@ -115,7 +118,7 @@ impl ChannelList {
                                 cx.notify();
                             });
                         }
-                        client::Status::SignedOut { .. } => {
+                        Status::SignedOut { .. } => {
                             this.update(&mut cx, |this, cx| {
                                 this.available_channels = None;
                                 this.channels.clear();
@@ -589,8 +592,7 @@ impl<'a> sum_tree::Dimension<'a, ChannelMessageSummary> for Count {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::test::FakeHttpClient;
-    use client::test::FakeServer;
+    use crate::test::{FakeHttpClient, FakeServer};
     use gpui::TestAppContext;
     use surf::http::Response;
 

crates/client/src/lib.rs 🔗

@@ -1,6 +1,10 @@
 #[cfg(any(test, feature = "test-support"))]
 pub mod test;
 
+pub mod channel;
+pub mod http;
+pub mod user;
+
 use anyhow::{anyhow, Context, Result};
 use async_recursion::async_recursion;
 use async_tungstenite::tungstenite::{
@@ -26,7 +30,9 @@ use surf::Url;
 use thiserror::Error;
 use util::ResultExt;
 
+pub use channel::*;
 pub use rpc::*;
+pub use user::*;
 
 lazy_static! {
     static ref ZED_SERVER_URL: String =

crates/client/src/test.rs 🔗

@@ -1,11 +1,13 @@
-use super::*;
-use std::sync::atomic::Ordering::SeqCst;
-
 use super::Client;
+use super::*;
+use crate::http::{HttpClient, Request, Response, ServerResponse};
+use futures::{future::BoxFuture, Future};
 use gpui::TestAppContext;
 use parking_lot::Mutex;
 use postage::{mpsc, prelude::Stream};
 use rpc::{proto, ConnectionId, Peer, Receipt, TypedEnvelope};
+use std::fmt;
+use std::sync::atomic::Ordering::SeqCst;
 use std::sync::{
     atomic::{AtomicBool, AtomicUsize},
     Arc,
@@ -154,3 +156,33 @@ impl FakeServer {
         self.connection_id.lock().expect("not connected")
     }
 }
+
+pub struct FakeHttpClient {
+    handler:
+        Box<dyn 'static + Send + Sync + Fn(Request) -> BoxFuture<'static, Result<ServerResponse>>>,
+}
+
+impl FakeHttpClient {
+    pub fn new<Fut, F>(handler: F) -> Arc<dyn HttpClient>
+    where
+        Fut: 'static + Send + Future<Output = Result<ServerResponse>>,
+        F: 'static + Send + Sync + Fn(Request) -> Fut,
+    {
+        Arc::new(Self {
+            handler: Box::new(move |req| Box::pin(handler(req))),
+        })
+    }
+}
+
+impl fmt::Debug for FakeHttpClient {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("FakeHttpClient").finish()
+    }
+}
+
+impl HttpClient for FakeHttpClient {
+    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response>> {
+        let future = (self.handler)(req);
+        Box::pin(async move { future.await.map(Into::into) })
+    }
+}

crates/zed/src/user.rs → crates/client/src/user.rs 🔗

@@ -1,6 +1,8 @@
-use crate::http::{HttpClient, Method, Request, Url};
+use super::{
+    http::{HttpClient, Method, Request, Url},
+    proto, Client, Status, TypedEnvelope,
+};
 use anyhow::{anyhow, Context, Result};
-use client::{proto, Client, TypedEnvelope};
 use futures::future;
 use gpui::{AsyncAppContext, Entity, ImageData, ModelContext, ModelHandle, Task};
 use postage::{prelude::Stream, sink::Sink, watch};
@@ -79,7 +81,7 @@ impl UserStore {
                 let mut status = rpc.status();
                 while let Some(status) = status.recv().await {
                     match status {
-                        client::Status::Connected { .. } => {
+                        Status::Connected { .. } => {
                             if let Some((this, user_id)) = this.upgrade(&cx).zip(rpc.user_id()) {
                                 let user = this
                                     .update(&mut cx, |this, cx| this.fetch_user(user_id, cx))
@@ -88,7 +90,7 @@ impl UserStore {
                                 current_user_tx.send(user).await.ok();
                             }
                         }
-                        client::Status::SignedOut => {
+                        Status::SignedOut => {
                             current_user_tx.send(None).await.ok();
                         }
                         _ => {}

crates/server/src/rpc.rs 🔗

@@ -977,14 +977,14 @@ mod tests {
     };
     use zed::{
         buffer::LanguageRegistry,
-        channel::{Channel, ChannelDetails, ChannelList},
-        client::{self, Client, Credentials, EstablishConnectionError},
+        client::{
+            self, test::FakeHttpClient, Channel, ChannelDetails, ChannelList, Client, Credentials,
+            EstablishConnectionError, UserStore,
+        },
         editor::{Editor, EditorSettings, Insert},
         fs::{FakeFs, Fs as _},
         people_panel::JoinWorktree,
         project::{ProjectPath, Worktree},
-        test::FakeHttpClient,
-        user::UserStore,
         workspace::Workspace,
     };
 

crates/zed/Cargo.toml 🔗

@@ -68,7 +68,7 @@ smol = "1.2.5"
 surf = "2.2"
 tempdir = { version = "0.3.7", optional = true }
 thiserror = "1.0.29"
-time = { version = "0.3" }
+time = "0.3"
 tiny_http = "0.8"
 toml = "0.5"
 tree-sitter = "0.19.5"

crates/zed/src/chat_panel.rs 🔗

@@ -1,8 +1,8 @@
-use crate::{
+use crate::{theme, Settings};
+use client::{
     channel::{Channel, ChannelEvent, ChannelList, ChannelMessage},
-    theme, Settings,
+    Client,
 };
-use client::Client;
 use editor::{Editor, EditorSettings};
 use gpui::{
     action,

crates/zed/src/lib.rs 🔗

@@ -1,8 +1,6 @@
 pub mod assets;
-pub mod channel;
 pub mod chat_panel;
 pub mod file_finder;
-pub mod http;
 pub mod language;
 pub mod menus;
 pub mod people_panel;
@@ -12,12 +10,10 @@ pub mod settings;
 pub mod test;
 pub mod theme;
 pub mod theme_selector;
-pub mod user;
 pub mod workspace;
 
 pub use buffer;
 use buffer::LanguageRegistry;
-use channel::ChannelList;
 pub use client;
 pub use editor;
 use gpui::{action, keymap::Binding, ModelHandle};
@@ -41,9 +37,9 @@ pub struct AppState {
     pub languages: Arc<LanguageRegistry>,
     pub themes: Arc<settings::ThemeRegistry>,
     pub client: Arc<client::Client>,
-    pub user_store: ModelHandle<user::UserStore>,
+    pub user_store: ModelHandle<client::UserStore>,
     pub fs: Arc<dyn fs::Fs>,
-    pub channel_list: ModelHandle<ChannelList>,
+    pub channel_list: ModelHandle<client::ChannelList>,
 }
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {

crates/zed/src/main.rs 🔗

@@ -10,11 +10,11 @@ use std::{fs, path::PathBuf, sync::Arc};
 use zed::{
     self,
     assets::Assets,
-    channel::ChannelList,
-    chat_panel, client, editor, file_finder,
+    chat_panel, client,
+    client::{http, ChannelList, UserStore},
+    editor, file_finder,
     fs::RealFs,
-    http, language, menus, project_panel, settings, theme_selector,
-    user::UserStore,
+    language, menus, project_panel, settings, theme_selector,
     workspace::{self, OpenNew, OpenParams, OpenPaths},
     AppState,
 };

crates/zed/src/people_panel.rs 🔗

@@ -1,8 +1,5 @@
-use crate::{
-    theme::Theme,
-    user::{Collaborator, UserStore},
-    Settings,
-};
+use crate::{theme::Theme, Settings};
+use client::{Collaborator, UserStore};
 use gpui::{
     action,
     elements::*,

crates/zed/src/test.rs 🔗

@@ -1,20 +1,15 @@
 use crate::{
     assets::Assets,
-    channel::ChannelList,
-    http::{HttpClient, Request, Response, ServerResponse},
     language,
     settings::{self, ThemeRegistry},
-    user::UserStore,
     AppState,
 };
-use anyhow::Result;
 use buffer::LanguageRegistry;
-use client::Client;
-use futures::{future::BoxFuture, Future};
+use client::{http::ServerResponse, test::FakeHttpClient, ChannelList, Client, UserStore};
 use gpui::MutableAppContext;
 use parking_lot::Mutex;
 use project::fs::FakeFs;
-use std::{fmt, sync::Arc};
+use std::sync::Arc;
 
 #[cfg(test)]
 #[ctor::ctor]
@@ -41,33 +36,3 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
         fs: Arc::new(FakeFs::new()),
     })
 }
-
-pub struct FakeHttpClient {
-    handler:
-        Box<dyn 'static + Send + Sync + Fn(Request) -> BoxFuture<'static, Result<ServerResponse>>>,
-}
-
-impl FakeHttpClient {
-    pub fn new<Fut, F>(handler: F) -> Arc<dyn HttpClient>
-    where
-        Fut: 'static + Send + Future<Output = Result<ServerResponse>>,
-        F: 'static + Send + Sync + Fn(Request) -> Fut,
-    {
-        Arc::new(Self {
-            handler: Box::new(move |req| Box::pin(handler(req))),
-        })
-    }
-}
-
-impl fmt::Debug for FakeHttpClient {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("FakeHttpClient").finish()
-    }
-}
-
-impl HttpClient for FakeHttpClient {
-    fn send<'a>(&'a self, req: Request) -> BoxFuture<'a, Result<Response>> {
-        let future = (self.handler)(req);
-        Box::pin(async move { future.await.map(Into::into) })
-    }
-}

crates/zed/src/workspace.rs 🔗

@@ -10,7 +10,6 @@ use crate::{
     project::{Project, ProjectPath},
     project_panel::ProjectPanel,
     settings::Settings,
-    user,
     workspace::sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus},
     AppState, Authenticate,
 };
@@ -357,7 +356,7 @@ impl Clone for Box<dyn ItemHandle> {
 pub struct Workspace {
     pub settings: watch::Receiver<Settings>,
     client: Arc<Client>,
-    user_store: ModelHandle<user::UserStore>,
+    user_store: ModelHandle<client::UserStore>,
     fs: Arc<dyn Fs>,
     modal: Option<AnyViewHandle>,
     center: PaneGroup,