Refactor ssh remoting - make ChannelClient type private (#36514)
This PR is one step in a series of refactors to prepare for having "remote" projects that do not use SSH. The main use cases for this are WSL and dev containers. Release Notes: - N/A
This commit is contained in:
parent
82ac8a8aaa
commit
ce216432be
7 changed files with 133 additions and 146 deletions
|
@ -14895,10 +14895,7 @@ impl Editor {
|
||||||
};
|
};
|
||||||
|
|
||||||
let hide_runnables = project
|
let hide_runnables = project
|
||||||
.update(cx, |project, cx| {
|
.update(cx, |project, _| project.is_via_collab())
|
||||||
// Do not display any test indicators in non-dev server remote projects.
|
|
||||||
project.is_via_collab() && project.ssh_connection_string(cx).is_none()
|
|
||||||
})
|
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
if hide_runnables {
|
if hide_runnables {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1346,14 +1346,13 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
// ssh -> local machine handlers
|
// ssh -> local machine handlers
|
||||||
let ssh = ssh.read(cx);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &cx.entity());
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &cx.entity());
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.buffer_store);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.buffer_store);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.worktree_store);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.worktree_store);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.lsp_store);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.lsp_store);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.dap_store);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.dap_store);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.settings_observer);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.settings_observer);
|
ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.git_store);
|
||||||
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.git_store);
|
|
||||||
|
|
||||||
ssh_proto.add_entity_message_handler(Self::handle_create_buffer_for_peer);
|
ssh_proto.add_entity_message_handler(Self::handle_create_buffer_for_peer);
|
||||||
ssh_proto.add_entity_message_handler(Self::handle_update_worktree);
|
ssh_proto.add_entity_message_handler(Self::handle_update_worktree);
|
||||||
|
@ -1900,14 +1899,6 @@ impl Project {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ssh_connection_string(&self, cx: &App) -> Option<SharedString> {
|
|
||||||
if let Some(ssh_state) = &self.ssh_client {
|
|
||||||
return Some(ssh_state.read(cx).connection_string().into());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ssh_connection_state(&self, cx: &App) -> Option<remote::ConnectionState> {
|
pub fn ssh_connection_state(&self, cx: &App) -> Option<remote::ConnectionState> {
|
||||||
self.ssh_client
|
self.ssh_client
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
|
@ -26,8 +26,7 @@ use parking_lot::Mutex;
|
||||||
|
|
||||||
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
|
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
|
||||||
use rpc::{
|
use rpc::{
|
||||||
AnyProtoClient, EntityMessageSubscriber, ErrorExt, ProtoClient, ProtoMessageHandlerSet,
|
AnyProtoClient, ErrorExt, ProtoClient, ProtoMessageHandlerSet, RpcError,
|
||||||
RpcError,
|
|
||||||
proto::{self, Envelope, EnvelopedMessage, PeerId, RequestMessage, build_typed_envelope},
|
proto::{self, Envelope, EnvelopedMessage, PeerId, RequestMessage, build_typed_envelope},
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
@ -37,7 +36,6 @@ use smol::{
|
||||||
process::{self, Child, Stdio},
|
process::{self, Child, Stdio},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fmt, iter,
|
fmt, iter,
|
||||||
ops::ControlFlow,
|
ops::ControlFlow,
|
||||||
|
@ -664,6 +662,7 @@ impl ConnectionIdentifier {
|
||||||
pub fn setup() -> Self {
|
pub fn setup() -> Self {
|
||||||
Self::Setup(NEXT_ID.fetch_add(1, SeqCst))
|
Self::Setup(NEXT_ID.fetch_add(1, SeqCst))
|
||||||
}
|
}
|
||||||
|
|
||||||
// This string gets used in a socket name, and so must be relatively short.
|
// This string gets used in a socket name, and so must be relatively short.
|
||||||
// The total length of:
|
// The total length of:
|
||||||
// /home/{username}/.local/share/zed/server_state/{name}/stdout.sock
|
// /home/{username}/.local/share/zed/server_state/{name}/stdout.sock
|
||||||
|
@ -760,6 +759,15 @@ impl SshRemoteClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proto_client_from_channels(
|
||||||
|
incoming_rx: mpsc::UnboundedReceiver<Envelope>,
|
||||||
|
outgoing_tx: mpsc::UnboundedSender<Envelope>,
|
||||||
|
cx: &App,
|
||||||
|
name: &'static str,
|
||||||
|
) -> AnyProtoClient {
|
||||||
|
ChannelClient::new(incoming_rx, outgoing_tx, cx, name).into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn shutdown_processes<T: RequestMessage>(
|
pub fn shutdown_processes<T: RequestMessage>(
|
||||||
&self,
|
&self,
|
||||||
shutdown_request: Option<T>,
|
shutdown_request: Option<T>,
|
||||||
|
@ -990,64 +998,63 @@ impl SshRemoteClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.spawn(async move |cx| {
|
cx.spawn(async move |cx| {
|
||||||
let mut missed_heartbeats = 0;
|
let mut missed_heartbeats = 0;
|
||||||
|
|
||||||
let keepalive_timer = cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse();
|
let keepalive_timer = cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse();
|
||||||
futures::pin_mut!(keepalive_timer);
|
futures::pin_mut!(keepalive_timer);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
select_biased! {
|
select_biased! {
|
||||||
result = connection_activity_rx.next().fuse() => {
|
result = connection_activity_rx.next().fuse() => {
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
log::warn!("ssh heartbeat: connection activity channel has been dropped. stopping.");
|
log::warn!("ssh heartbeat: connection activity channel has been dropped. stopping.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
|
||||||
|
|
||||||
if missed_heartbeats != 0 {
|
|
||||||
missed_heartbeats = 0;
|
|
||||||
let _ =this.update(cx, |this, cx| {
|
|
||||||
this.handle_heartbeat_result(missed_heartbeats, cx)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ = keepalive_timer => {
|
|
||||||
log::debug!("Sending heartbeat to server...");
|
|
||||||
|
|
||||||
let result = select_biased! {
|
if missed_heartbeats != 0 {
|
||||||
_ = connection_activity_rx.next().fuse() => {
|
missed_heartbeats = 0;
|
||||||
Ok(())
|
let _ =this.update(cx, |this, cx| {
|
||||||
}
|
|
||||||
ping_result = client.ping(HEARTBEAT_TIMEOUT).fuse() => {
|
|
||||||
ping_result
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if result.is_err() {
|
|
||||||
missed_heartbeats += 1;
|
|
||||||
log::warn!(
|
|
||||||
"No heartbeat from server after {:?}. Missed heartbeat {} out of {}.",
|
|
||||||
HEARTBEAT_TIMEOUT,
|
|
||||||
missed_heartbeats,
|
|
||||||
MAX_MISSED_HEARTBEATS
|
|
||||||
);
|
|
||||||
} else if missed_heartbeats != 0 {
|
|
||||||
missed_heartbeats = 0;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = this.update(cx, |this, cx| {
|
|
||||||
this.handle_heartbeat_result(missed_heartbeats, cx)
|
this.handle_heartbeat_result(missed_heartbeats, cx)
|
||||||
})?;
|
})?;
|
||||||
if result.is_break() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = keepalive_timer => {
|
||||||
|
log::debug!("Sending heartbeat to server...");
|
||||||
|
|
||||||
keepalive_timer.set(cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse());
|
let result = select_biased! {
|
||||||
|
_ = connection_activity_rx.next().fuse() => {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
ping_result = client.ping(HEARTBEAT_TIMEOUT).fuse() => {
|
||||||
|
ping_result
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
missed_heartbeats += 1;
|
||||||
|
log::warn!(
|
||||||
|
"No heartbeat from server after {:?}. Missed heartbeat {} out of {}.",
|
||||||
|
HEARTBEAT_TIMEOUT,
|
||||||
|
missed_heartbeats,
|
||||||
|
MAX_MISSED_HEARTBEATS
|
||||||
|
);
|
||||||
|
} else if missed_heartbeats != 0 {
|
||||||
|
missed_heartbeats = 0;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = this.update(cx, |this, cx| {
|
||||||
|
this.handle_heartbeat_result(missed_heartbeats, cx)
|
||||||
|
})?;
|
||||||
|
if result.is_break() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keepalive_timer.set(cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse());
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,10 +1152,6 @@ impl SshRemoteClient {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_to_entity<E: 'static>(&self, remote_id: u64, entity: &Entity<E>) {
|
|
||||||
self.client.subscribe_to_entity(remote_id, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ssh_info(&self) -> Option<(SshArgs, PathStyle)> {
|
pub fn ssh_info(&self) -> Option<(SshArgs, PathStyle)> {
|
||||||
self.state
|
self.state
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -1222,7 +1225,7 @@ impl SshRemoteClient {
|
||||||
pub fn fake_server(
|
pub fn fake_server(
|
||||||
client_cx: &mut gpui::TestAppContext,
|
client_cx: &mut gpui::TestAppContext,
|
||||||
server_cx: &mut gpui::TestAppContext,
|
server_cx: &mut gpui::TestAppContext,
|
||||||
) -> (SshConnectionOptions, Arc<ChannelClient>) {
|
) -> (SshConnectionOptions, AnyProtoClient) {
|
||||||
let port = client_cx
|
let port = client_cx
|
||||||
.update(|cx| cx.default_global::<ConnectionPool>().connections.len() as u16 + 1);
|
.update(|cx| cx.default_global::<ConnectionPool>().connections.len() as u16 + 1);
|
||||||
let opts = SshConnectionOptions {
|
let opts = SshConnectionOptions {
|
||||||
|
@ -1255,7 +1258,7 @@ impl SshRemoteClient {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
(opts, server_client)
|
(opts, server_client.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
@ -2269,7 +2272,7 @@ impl SshRemoteConnection {
|
||||||
|
|
||||||
type ResponseChannels = Mutex<HashMap<MessageId, oneshot::Sender<(Envelope, oneshot::Sender<()>)>>>;
|
type ResponseChannels = Mutex<HashMap<MessageId, oneshot::Sender<(Envelope, oneshot::Sender<()>)>>>;
|
||||||
|
|
||||||
pub struct ChannelClient {
|
struct ChannelClient {
|
||||||
next_message_id: AtomicU32,
|
next_message_id: AtomicU32,
|
||||||
outgoing_tx: Mutex<mpsc::UnboundedSender<Envelope>>,
|
outgoing_tx: Mutex<mpsc::UnboundedSender<Envelope>>,
|
||||||
buffer: Mutex<VecDeque<Envelope>>,
|
buffer: Mutex<VecDeque<Envelope>>,
|
||||||
|
@ -2281,7 +2284,7 @@ pub struct ChannelClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelClient {
|
impl ChannelClient {
|
||||||
pub fn new(
|
fn new(
|
||||||
incoming_rx: mpsc::UnboundedReceiver<Envelope>,
|
incoming_rx: mpsc::UnboundedReceiver<Envelope>,
|
||||||
outgoing_tx: mpsc::UnboundedSender<Envelope>,
|
outgoing_tx: mpsc::UnboundedSender<Envelope>,
|
||||||
cx: &App,
|
cx: &App,
|
||||||
|
@ -2402,7 +2405,7 @@ impl ChannelClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reconnect(
|
fn reconnect(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
incoming_rx: UnboundedReceiver<Envelope>,
|
incoming_rx: UnboundedReceiver<Envelope>,
|
||||||
outgoing_tx: UnboundedSender<Envelope>,
|
outgoing_tx: UnboundedSender<Envelope>,
|
||||||
|
@ -2412,26 +2415,7 @@ impl ChannelClient {
|
||||||
*self.task.lock() = Self::start_handling_messages(Arc::downgrade(self), incoming_rx, cx);
|
*self.task.lock() = Self::start_handling_messages(Arc::downgrade(self), incoming_rx, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_to_entity<E: 'static>(&self, remote_id: u64, entity: &Entity<E>) {
|
fn request<T: RequestMessage>(
|
||||||
let id = (TypeId::of::<E>(), remote_id);
|
|
||||||
|
|
||||||
let mut message_handlers = self.message_handlers.lock();
|
|
||||||
if message_handlers
|
|
||||||
.entities_by_type_and_remote_id
|
|
||||||
.contains_key(&id)
|
|
||||||
{
|
|
||||||
panic!("already subscribed to entity");
|
|
||||||
}
|
|
||||||
|
|
||||||
message_handlers.entities_by_type_and_remote_id.insert(
|
|
||||||
id,
|
|
||||||
EntityMessageSubscriber::Entity {
|
|
||||||
handle: entity.downgrade().into(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request<T: RequestMessage>(
|
|
||||||
&self,
|
&self,
|
||||||
payload: T,
|
payload: T,
|
||||||
) -> impl 'static + Future<Output = Result<T::Response>> {
|
) -> impl 'static + Future<Output = Result<T::Response>> {
|
||||||
|
@ -2453,7 +2437,7 @@ impl ChannelClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resync(&self, timeout: Duration) -> Result<()> {
|
async fn resync(&self, timeout: Duration) -> Result<()> {
|
||||||
smol::future::or(
|
smol::future::or(
|
||||||
async {
|
async {
|
||||||
self.request_internal(proto::FlushBufferedMessages {}, false)
|
self.request_internal(proto::FlushBufferedMessages {}, false)
|
||||||
|
@ -2475,7 +2459,7 @@ impl ChannelClient {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ping(&self, timeout: Duration) -> Result<()> {
|
async fn ping(&self, timeout: Duration) -> Result<()> {
|
||||||
smol::future::or(
|
smol::future::or(
|
||||||
async {
|
async {
|
||||||
self.request(proto::Ping {}).await?;
|
self.request(proto::Ping {}).await?;
|
||||||
|
|
|
@ -19,7 +19,6 @@ use project::{
|
||||||
task_store::TaskStore,
|
task_store::TaskStore,
|
||||||
worktree_store::WorktreeStore,
|
worktree_store::WorktreeStore,
|
||||||
};
|
};
|
||||||
use remote::ssh_session::ChannelClient;
|
|
||||||
use rpc::{
|
use rpc::{
|
||||||
AnyProtoClient, TypedEnvelope,
|
AnyProtoClient, TypedEnvelope,
|
||||||
proto::{self, SSH_PEER_ID, SSH_PROJECT_ID},
|
proto::{self, SSH_PEER_ID, SSH_PROJECT_ID},
|
||||||
|
@ -50,7 +49,7 @@ pub struct HeadlessProject {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HeadlessAppState {
|
pub struct HeadlessAppState {
|
||||||
pub session: Arc<ChannelClient>,
|
pub session: AnyProtoClient,
|
||||||
pub fs: Arc<dyn Fs>,
|
pub fs: Arc<dyn Fs>,
|
||||||
pub http_client: Arc<dyn HttpClient>,
|
pub http_client: Arc<dyn HttpClient>,
|
||||||
pub node_runtime: NodeRuntime,
|
pub node_runtime: NodeRuntime,
|
||||||
|
@ -81,7 +80,7 @@ impl HeadlessProject {
|
||||||
|
|
||||||
let worktree_store = cx.new(|cx| {
|
let worktree_store = cx.new(|cx| {
|
||||||
let mut store = WorktreeStore::local(true, fs.clone());
|
let mut store = WorktreeStore::local(true, fs.clone());
|
||||||
store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
store
|
store
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,7 +98,7 @@ impl HeadlessProject {
|
||||||
|
|
||||||
let buffer_store = cx.new(|cx| {
|
let buffer_store = cx.new(|cx| {
|
||||||
let mut buffer_store = BufferStore::local(worktree_store.clone(), cx);
|
let mut buffer_store = BufferStore::local(worktree_store.clone(), cx);
|
||||||
buffer_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
buffer_store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
buffer_store
|
buffer_store
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,7 +116,7 @@ impl HeadlessProject {
|
||||||
breakpoint_store.clone(),
|
breakpoint_store.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
dap_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
dap_store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
dap_store
|
dap_store
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -129,7 +128,7 @@ impl HeadlessProject {
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
store
|
store
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -152,7 +151,7 @@ impl HeadlessProject {
|
||||||
environment.clone(),
|
environment.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
task_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
task_store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
task_store
|
task_store
|
||||||
});
|
});
|
||||||
let settings_observer = cx.new(|cx| {
|
let settings_observer = cx.new(|cx| {
|
||||||
|
@ -162,7 +161,7 @@ impl HeadlessProject {
|
||||||
task_store.clone(),
|
task_store.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
observer.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
observer.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
observer
|
observer
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -183,7 +182,7 @@ impl HeadlessProject {
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
lsp_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
lsp_store.shared(SSH_PROJECT_ID, session.clone(), cx);
|
||||||
lsp_store
|
lsp_store
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -210,8 +209,6 @@ impl HeadlessProject {
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
let client: AnyProtoClient = session.clone().into();
|
|
||||||
|
|
||||||
// local_machine -> ssh handlers
|
// local_machine -> ssh handlers
|
||||||
session.subscribe_to_entity(SSH_PROJECT_ID, &worktree_store);
|
session.subscribe_to_entity(SSH_PROJECT_ID, &worktree_store);
|
||||||
session.subscribe_to_entity(SSH_PROJECT_ID, &buffer_store);
|
session.subscribe_to_entity(SSH_PROJECT_ID, &buffer_store);
|
||||||
|
@ -223,44 +220,45 @@ impl HeadlessProject {
|
||||||
session.subscribe_to_entity(SSH_PROJECT_ID, &settings_observer);
|
session.subscribe_to_entity(SSH_PROJECT_ID, &settings_observer);
|
||||||
session.subscribe_to_entity(SSH_PROJECT_ID, &git_store);
|
session.subscribe_to_entity(SSH_PROJECT_ID, &git_store);
|
||||||
|
|
||||||
client.add_request_handler(cx.weak_entity(), Self::handle_list_remote_directory);
|
session.add_request_handler(cx.weak_entity(), Self::handle_list_remote_directory);
|
||||||
client.add_request_handler(cx.weak_entity(), Self::handle_get_path_metadata);
|
session.add_request_handler(cx.weak_entity(), Self::handle_get_path_metadata);
|
||||||
client.add_request_handler(cx.weak_entity(), Self::handle_shutdown_remote_server);
|
session.add_request_handler(cx.weak_entity(), Self::handle_shutdown_remote_server);
|
||||||
client.add_request_handler(cx.weak_entity(), Self::handle_ping);
|
session.add_request_handler(cx.weak_entity(), Self::handle_ping);
|
||||||
|
|
||||||
client.add_entity_request_handler(Self::handle_add_worktree);
|
session.add_entity_request_handler(Self::handle_add_worktree);
|
||||||
client.add_request_handler(cx.weak_entity(), Self::handle_remove_worktree);
|
session.add_request_handler(cx.weak_entity(), Self::handle_remove_worktree);
|
||||||
|
|
||||||
client.add_entity_request_handler(Self::handle_open_buffer_by_path);
|
session.add_entity_request_handler(Self::handle_open_buffer_by_path);
|
||||||
client.add_entity_request_handler(Self::handle_open_new_buffer);
|
session.add_entity_request_handler(Self::handle_open_new_buffer);
|
||||||
client.add_entity_request_handler(Self::handle_find_search_candidates);
|
session.add_entity_request_handler(Self::handle_find_search_candidates);
|
||||||
client.add_entity_request_handler(Self::handle_open_server_settings);
|
session.add_entity_request_handler(Self::handle_open_server_settings);
|
||||||
|
|
||||||
client.add_entity_request_handler(BufferStore::handle_update_buffer);
|
session.add_entity_request_handler(BufferStore::handle_update_buffer);
|
||||||
client.add_entity_message_handler(BufferStore::handle_close_buffer);
|
session.add_entity_message_handler(BufferStore::handle_close_buffer);
|
||||||
|
|
||||||
client.add_request_handler(
|
session.add_request_handler(
|
||||||
extensions.clone().downgrade(),
|
extensions.clone().downgrade(),
|
||||||
HeadlessExtensionStore::handle_sync_extensions,
|
HeadlessExtensionStore::handle_sync_extensions,
|
||||||
);
|
);
|
||||||
client.add_request_handler(
|
session.add_request_handler(
|
||||||
extensions.clone().downgrade(),
|
extensions.clone().downgrade(),
|
||||||
HeadlessExtensionStore::handle_install_extension,
|
HeadlessExtensionStore::handle_install_extension,
|
||||||
);
|
);
|
||||||
|
|
||||||
BufferStore::init(&client);
|
BufferStore::init(&session);
|
||||||
WorktreeStore::init(&client);
|
WorktreeStore::init(&session);
|
||||||
SettingsObserver::init(&client);
|
SettingsObserver::init(&session);
|
||||||
LspStore::init(&client);
|
LspStore::init(&session);
|
||||||
TaskStore::init(Some(&client));
|
TaskStore::init(Some(&session));
|
||||||
ToolchainStore::init(&client);
|
ToolchainStore::init(&session);
|
||||||
DapStore::init(&client, cx);
|
DapStore::init(&session, cx);
|
||||||
// todo(debugger): Re init breakpoint store when we set it up for collab
|
// todo(debugger): Re init breakpoint store when we set it up for collab
|
||||||
// BreakpointStore::init(&client);
|
// BreakpointStore::init(&client);
|
||||||
GitStore::init(&client);
|
GitStore::init(&session);
|
||||||
|
|
||||||
HeadlessProject {
|
HeadlessProject {
|
||||||
session: client,
|
next_entry_id: Default::default(),
|
||||||
|
session,
|
||||||
settings_observer,
|
settings_observer,
|
||||||
fs,
|
fs,
|
||||||
worktree_store,
|
worktree_store,
|
||||||
|
@ -268,7 +266,6 @@ impl HeadlessProject {
|
||||||
lsp_store,
|
lsp_store,
|
||||||
task_store,
|
task_store,
|
||||||
dap_store,
|
dap_store,
|
||||||
next_entry_id: Default::default(),
|
|
||||||
languages,
|
languages,
|
||||||
extensions,
|
extensions,
|
||||||
git_store,
|
git_store,
|
||||||
|
|
|
@ -19,11 +19,11 @@ use project::project_settings::ProjectSettings;
|
||||||
|
|
||||||
use proto::CrashReport;
|
use proto::CrashReport;
|
||||||
use release_channel::{AppVersion, RELEASE_CHANNEL, ReleaseChannel};
|
use release_channel::{AppVersion, RELEASE_CHANNEL, ReleaseChannel};
|
||||||
use remote::proxy::ProxyLaunchError;
|
use remote::SshRemoteClient;
|
||||||
use remote::ssh_session::ChannelClient;
|
|
||||||
use remote::{
|
use remote::{
|
||||||
json_log::LogRecord,
|
json_log::LogRecord,
|
||||||
protocol::{read_message, write_message},
|
protocol::{read_message, write_message},
|
||||||
|
proxy::ProxyLaunchError,
|
||||||
};
|
};
|
||||||
use reqwest_client::ReqwestClient;
|
use reqwest_client::ReqwestClient;
|
||||||
use rpc::proto::{self, Envelope, SSH_PROJECT_ID};
|
use rpc::proto::{self, Envelope, SSH_PROJECT_ID};
|
||||||
|
@ -199,8 +199,7 @@ fn init_panic_hook(session_id: String) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_crash_files_requests(project: &Entity<HeadlessProject>, client: &Arc<ChannelClient>) {
|
fn handle_crash_files_requests(project: &Entity<HeadlessProject>, client: &AnyProtoClient) {
|
||||||
let client: AnyProtoClient = client.clone().into();
|
|
||||||
client.add_request_handler(
|
client.add_request_handler(
|
||||||
project.downgrade(),
|
project.downgrade(),
|
||||||
|_, _: TypedEnvelope<proto::GetCrashFiles>, _cx| async move {
|
|_, _: TypedEnvelope<proto::GetCrashFiles>, _cx| async move {
|
||||||
|
@ -276,7 +275,7 @@ fn start_server(
|
||||||
listeners: ServerListeners,
|
listeners: ServerListeners,
|
||||||
log_rx: Receiver<Vec<u8>>,
|
log_rx: Receiver<Vec<u8>>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Arc<ChannelClient> {
|
) -> AnyProtoClient {
|
||||||
// This is the server idle timeout. If no connection comes in this timeout, the server will shut down.
|
// This is the server idle timeout. If no connection comes in this timeout, the server will shut down.
|
||||||
const IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10 * 60);
|
const IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10 * 60);
|
||||||
|
|
||||||
|
@ -395,7 +394,7 @@ fn start_server(
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
ChannelClient::new(incoming_rx, outgoing_tx, cx, "server")
|
SshRemoteClient::proto_client_from_channels(incoming_rx, outgoing_tx, cx, "server")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_paths() -> anyhow::Result<()> {
|
fn init_paths() -> anyhow::Result<()> {
|
||||||
|
@ -792,7 +791,7 @@ async fn write_size_prefixed_buffer<S: AsyncWrite + Unpin>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_settings(
|
fn initialize_settings(
|
||||||
session: Arc<ChannelClient>,
|
session: AnyProtoClient,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> watch::Receiver<Option<NodeBinaryOptions>> {
|
) -> watch::Receiver<Option<NodeBinaryOptions>> {
|
||||||
|
|
|
@ -315,4 +315,23 @@ impl AnyProtoClient {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe_to_entity<E: 'static>(&self, remote_id: u64, entity: &Entity<E>) {
|
||||||
|
let id = (TypeId::of::<E>(), remote_id);
|
||||||
|
|
||||||
|
let mut message_handlers = self.0.message_handler_set().lock();
|
||||||
|
if message_handlers
|
||||||
|
.entities_by_type_and_remote_id
|
||||||
|
.contains_key(&id)
|
||||||
|
{
|
||||||
|
panic!("already subscribed to entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
message_handlers.entities_by_type_and_remote_id.insert(
|
||||||
|
id,
|
||||||
|
EntityMessageSubscriber::Entity {
|
||||||
|
handle: entity.downgrade().into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,9 +148,9 @@ pub fn toggle_modal(
|
||||||
) -> Task<()> {
|
) -> Task<()> {
|
||||||
let task_store = workspace.project().read(cx).task_store().clone();
|
let task_store = workspace.project().read(cx).task_store().clone();
|
||||||
let workspace_handle = workspace.weak_handle();
|
let workspace_handle = workspace.weak_handle();
|
||||||
let can_open_modal = workspace.project().update(cx, |project, cx| {
|
let can_open_modal = workspace
|
||||||
project.is_local() || project.ssh_connection_string(cx).is_some() || project.is_via_ssh()
|
.project()
|
||||||
});
|
.read_with(cx, |project, _| !project.is_via_collab());
|
||||||
if can_open_modal {
|
if can_open_modal {
|
||||||
let task_contexts = task_contexts(workspace, window, cx);
|
let task_contexts = task_contexts(workspace, window, cx);
|
||||||
cx.spawn_in(window, async move |workspace, cx| {
|
cx.spawn_in(window, async move |workspace, cx| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue