remote projects per user (#10594)

Release Notes:

- Made remote projects per-user instead of per-channel. If you'd like to
be part of the remote development alpha, please email hi@zed.dev.

---------

Co-authored-by: Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com>
Co-authored-by: Bennet <bennetbo@gmx.de>
Co-authored-by: Nate Butler <1714999+iamnbutler@users.noreply.github.com>
Co-authored-by: Nate Butler <iamnbutler@gmail.com>
This commit is contained in:
Conrad Irwin 2024-04-23 15:33:09 -06:00 committed by GitHub
parent 8ae4c3277f
commit e0c83a1d32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 2807 additions and 1625 deletions

View file

@ -1,20 +1,25 @@
use anyhow::Result;
use client::{user::UserStore, Client, ClientSettings, RemoteProjectId};
use client::RemoteProjectId;
use client::{user::UserStore, Client, ClientSettings};
use fs::Fs;
use futures::Future;
use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, Task, WeakModel};
use gpui::{
AppContext, AsyncAppContext, BorrowAppContext, Context, Global, Model, ModelContext, Task,
WeakModel,
};
use language::LanguageRegistry;
use node_runtime::NodeRuntime;
use postage::stream::Stream;
use project::Project;
use rpc::{proto, TypedEnvelope};
use settings::Settings;
use project::{Project, WorktreeSettings};
use rpc::{proto, ErrorCode, TypedEnvelope};
use settings::{Settings, SettingsStore};
use std::{collections::HashMap, sync::Arc};
use util::{ResultExt, TryFutureExt};
pub struct DevServer {
client: Arc<Client>,
app_state: AppState,
remote_shutdown: bool,
projects: HashMap<RemoteProjectId, Model<Project>>,
_subscriptions: Vec<client::Subscription>,
_maintain_connection: Task<Option<()>>,
@ -35,6 +40,15 @@ pub fn init(client: Arc<Client>, app_state: AppState, cx: &mut AppContext) {
let dev_server = cx.new_model(|cx| DevServer::new(client.clone(), app_state, cx));
cx.set_global(GlobalDevServer(dev_server.clone()));
// Dev server cannot have any private files for now
cx.update_global(|store: &mut SettingsStore, _| {
let old_settings = store.get::<WorktreeSettings>(None);
store.override_global(WorktreeSettings {
private_files: Some(vec![]),
..old_settings.clone()
});
});
// Set up a handler when the dev server is shut down by the user pressing Ctrl-C
let (tx, rx) = futures::channel::oneshot::channel();
set_ctrlc_handler(move || tx.send(()).log_err().unwrap()).log_err();
@ -53,7 +67,7 @@ pub fn init(client: Arc<Client>, app_state: AppState, cx: &mut AppContext) {
log::info!("Connected to {}", server_url);
}
Err(e) => {
log::error!("Error connecting to {}: {}", server_url, e);
log::error!("Error connecting to '{}': {}", server_url, e);
cx.update(|cx| cx.quit()).log_err();
}
}
@ -89,19 +103,31 @@ impl DevServer {
DevServer {
_subscriptions: vec![
client.add_message_handler(cx.weak_model(), Self::handle_dev_server_instructions)
client.add_message_handler(cx.weak_model(), Self::handle_dev_server_instructions),
client.add_request_handler(
cx.weak_model(),
Self::handle_validate_remote_project_request,
),
client.add_message_handler(cx.weak_model(), Self::handle_shutdown),
],
_maintain_connection: maintain_connection,
projects: Default::default(),
remote_shutdown: false,
app_state,
client,
}
}
fn app_will_quit(&mut self, _: &mut ModelContext<Self>) -> impl Future<Output = ()> {
let request = self.client.request(proto::ShutdownDevServer {});
let request = if self.remote_shutdown {
None
} else {
Some(self.client.request(proto::ShutdownDevServer {}))
};
async move {
request.await.log_err();
if let Some(request) = request {
request.await.log_err();
}
}
}
@ -148,6 +174,35 @@ impl DevServer {
Ok(())
}
async fn handle_validate_remote_project_request(
this: Model<Self>,
envelope: TypedEnvelope<proto::ValidateRemoteProjectRequest>,
_: Arc<Client>,
cx: AsyncAppContext,
) -> Result<proto::Ack> {
let path = std::path::Path::new(&envelope.payload.path);
let fs = cx.read_model(&this, |this, _| this.app_state.fs.clone())?;
let path_exists = fs.is_dir(path).await;
if !path_exists {
return Err(anyhow::anyhow!(ErrorCode::RemoteProjectPathDoesNotExist))?;
}
Ok(proto::Ack {})
}
async fn handle_shutdown(
this: Model<Self>,
_envelope: TypedEnvelope<proto::ShutdownDevServer>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<()> {
this.update(&mut cx, |this, cx| {
this.remote_shutdown = true;
cx.quit();
})
}
fn unshare_project(
&mut self,
remote_project_id: &RemoteProjectId,