mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-24 17:28:40 +00:00
Make joining on boot work
This commit is contained in:
parent
4128e2ffcb
commit
63a230f92e
5 changed files with 118 additions and 65 deletions
|
@ -18,7 +18,7 @@ use live_kit_client::{
|
|||
LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RemoteAudioTrackUpdate,
|
||||
RemoteVideoTrackUpdate,
|
||||
};
|
||||
use postage::stream::Stream;
|
||||
use postage::{sink::Sink, stream::Stream, watch};
|
||||
use project::Project;
|
||||
use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration};
|
||||
use util::{post_inc, ResultExt, TryFutureExt};
|
||||
|
@ -70,6 +70,8 @@ pub struct Room {
|
|||
user_store: ModelHandle<UserStore>,
|
||||
follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec<PeerId>>,
|
||||
subscriptions: Vec<client::Subscription>,
|
||||
room_update_completed_tx: watch::Sender<Option<()>>,
|
||||
room_update_completed_rx: watch::Receiver<Option<()>>,
|
||||
pending_room_update: Option<Task<()>>,
|
||||
maintain_connection: Option<Task<Option<()>>>,
|
||||
}
|
||||
|
@ -211,6 +213,8 @@ impl Room {
|
|||
|
||||
Audio::play_sound(Sound::Joined, cx);
|
||||
|
||||
let (room_update_completed_tx, room_update_completed_rx) = watch::channel();
|
||||
|
||||
Self {
|
||||
id,
|
||||
channel_id,
|
||||
|
@ -230,6 +234,8 @@ impl Room {
|
|||
user_store,
|
||||
follows_by_leader_id_project_id: Default::default(),
|
||||
maintain_connection: Some(maintain_connection),
|
||||
room_update_completed_tx,
|
||||
room_update_completed_rx,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -856,6 +862,7 @@ impl Room {
|
|||
});
|
||||
|
||||
this.check_invariants();
|
||||
this.room_update_completed_tx.try_send(Some(())).ok();
|
||||
cx.notify();
|
||||
});
|
||||
}));
|
||||
|
@ -864,6 +871,17 @@ impl Room {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn next_room_update(&mut self) -> impl Future<Output = ()> {
|
||||
let mut done_rx = self.room_update_completed_rx.clone();
|
||||
async move {
|
||||
while let Some(result) = done_rx.next().await {
|
||||
if result.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_video_track_updated(
|
||||
&mut self,
|
||||
change: RemoteVideoTrackUpdate,
|
||||
|
|
|
@ -798,7 +798,8 @@ impl Client {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ = status_rx.next().fuse() => {
|
||||
status = status_rx.next().fuse() => {
|
||||
dbg!(status);
|
||||
return Err(anyhow!("authentication canceled"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use drag_and_drop::DragAndDrop;
|
|||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
future::try_join_all,
|
||||
select_biased, FutureExt, StreamExt,
|
||||
FutureExt, StreamExt,
|
||||
};
|
||||
use gpui::{
|
||||
actions,
|
||||
|
@ -36,9 +36,9 @@ use gpui::{
|
|||
CursorStyle, ModifiersChangedEvent, MouseButton, PathPromptOptions, Platform, PromptLevel,
|
||||
WindowBounds, WindowOptions,
|
||||
},
|
||||
AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity,
|
||||
ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle,
|
||||
WeakViewHandle, WindowContext, WindowHandle,
|
||||
AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AnyWindowHandle, AppContext, AsyncAppContext,
|
||||
Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext,
|
||||
ViewHandle, WeakViewHandle, WindowContext, WindowHandle,
|
||||
};
|
||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
|
||||
use itertools::Itertools;
|
||||
|
@ -4156,7 +4156,7 @@ pub async fn last_opened_workspace_paths() -> Option<WorkspaceLocation> {
|
|||
|
||||
async fn join_channel_internal(
|
||||
channel_id: u64,
|
||||
app_state: Arc<AppState>,
|
||||
app_state: &Arc<AppState>,
|
||||
requesting_window: Option<WindowHandle<Workspace>>,
|
||||
active_call: &ModelHandle<ActiveCall>,
|
||||
cx: &mut AsyncAppContext,
|
||||
|
@ -4196,33 +4196,24 @@ async fn join_channel_internal(
|
|||
|
||||
let client = cx.read(|cx| active_call.read(cx).client());
|
||||
|
||||
let mut timer = cx.background().timer(Duration::from_secs(5)).fuse();
|
||||
let mut client_status = client.status();
|
||||
|
||||
// this loop will terminate within client::CONNECTION_TIMEOUT seconds.
|
||||
'outer: loop {
|
||||
select_biased! {
|
||||
_ = timer => {
|
||||
return Err(anyhow!("connecting timed out"))
|
||||
},
|
||||
status = client_status.recv().fuse() => {
|
||||
let Some(status) = status else {
|
||||
return Err(anyhow!("unexpected error reading connection status"))
|
||||
};
|
||||
let Some(status) = client_status.recv().await else {
|
||||
return Err(anyhow!("error connecting"));
|
||||
};
|
||||
|
||||
match status {
|
||||
Status::Connecting | Status::Authenticating | Status::Reconnecting | Status::Reauthenticating => continue,
|
||||
Status::Connected { .. } => break 'outer,
|
||||
Status::SignedOut => {
|
||||
if client.has_keychain_credentials(&cx) {
|
||||
client.authenticate_and_connect(true, &cx).await?;
|
||||
timer = cx.background().timer(Duration::from_secs(5)).fuse();
|
||||
} else {
|
||||
return Err(anyhow!("not signed in"))
|
||||
}
|
||||
},
|
||||
Status::UpgradeRequired => return Err(anyhow!("zed is out of date")),
|
||||
| Status::ConnectionError | Status::ConnectionLost | Status::ReconnectionError { .. } => return Err(anyhow!("zed is offline"))
|
||||
}
|
||||
match status {
|
||||
Status::Connecting
|
||||
| Status::Authenticating
|
||||
| Status::Reconnecting
|
||||
| Status::Reauthenticating => continue,
|
||||
Status::Connected { .. } => break 'outer,
|
||||
Status::SignedOut => return Err(anyhow!("not signed in")),
|
||||
Status::UpgradeRequired => return Err(anyhow!("zed is out of date")),
|
||||
Status::ConnectionError | Status::ConnectionLost | Status::ReconnectionError { .. } => {
|
||||
return Err(anyhow!("zed is offline"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4233,6 +4224,8 @@ async fn join_channel_internal(
|
|||
})
|
||||
.await?;
|
||||
|
||||
room.update(cx, |room, cx| room.next_room_update()).await;
|
||||
|
||||
let task = room.update(cx, |room, cx| {
|
||||
if let Some((project, host)) = room.most_active_project() {
|
||||
return Some(join_remote_project(project, host, app_state.clone(), cx));
|
||||
|
@ -4255,10 +4248,10 @@ pub fn join_channel(
|
|||
cx: &mut AppContext,
|
||||
) -> Task<Result<()>> {
|
||||
let active_call = ActiveCall::global(cx);
|
||||
cx.spawn(|mut cx| {
|
||||
cx.spawn(|mut cx| async move {
|
||||
let result = join_channel_internal(
|
||||
channel_id,
|
||||
app_state,
|
||||
&app_state,
|
||||
requesting_window,
|
||||
&active_call,
|
||||
&mut cx,
|
||||
|
@ -4266,7 +4259,7 @@ pub fn join_channel(
|
|||
.await;
|
||||
|
||||
// join channel succeeded, and opened a window
|
||||
if Some(true) = result {
|
||||
if matches!(result, Ok(true)) {
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
|
||||
|
@ -4275,28 +4268,53 @@ pub fn join_channel(
|
|||
}
|
||||
|
||||
// find an existing workspace to focus and show call controls
|
||||
for window in cx.windows() {
|
||||
let found = window.update(&mut cx, |cx| {
|
||||
let is_workspace = cx.root_view().clone().downcast::<Workspace>().is_some();
|
||||
if is_workspace {
|
||||
cx.activate_window();
|
||||
}
|
||||
is_workspace
|
||||
});
|
||||
let mut active_window = activate_any_workspace_window(&mut cx);
|
||||
if active_window.is_none() {
|
||||
// no open workspaces, make one to show the error in (blergh)
|
||||
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), requesting_window, cx))
|
||||
.await;
|
||||
}
|
||||
|
||||
if found.unwrap_or(false) {
|
||||
return anyhow::Ok(());
|
||||
active_window = activate_any_workspace_window(&mut cx);
|
||||
if active_window.is_none() {
|
||||
return result.map(|_| ()); // unreachable!() assuming new_local always opens a window
|
||||
}
|
||||
|
||||
if let Err(err) = result {
|
||||
let prompt = active_window.unwrap().prompt(
|
||||
PromptLevel::Critical,
|
||||
&format!("Failed to join channel: {}", err),
|
||||
&["Ok"],
|
||||
&mut cx,
|
||||
);
|
||||
if let Some(mut prompt) = prompt {
|
||||
prompt.next().await;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
// no open workspaces
|
||||
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), requesting_window, cx))
|
||||
.await;
|
||||
|
||||
return connected.map(|_| ());
|
||||
// return ok, we showed the error to the user.
|
||||
return anyhow::Ok(());
|
||||
})
|
||||
}
|
||||
|
||||
pub fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option<AnyWindowHandle> {
|
||||
for window in cx.windows() {
|
||||
let found = window.update(cx, |cx| {
|
||||
let is_workspace = cx.root_view().clone().downcast::<Workspace>().is_some();
|
||||
if is_workspace {
|
||||
cx.activate_window();
|
||||
}
|
||||
is_workspace
|
||||
});
|
||||
if found == Some(true) {
|
||||
return Some(window);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn open_paths(
|
||||
abs_paths: &[PathBuf],
|
||||
|
|
|
@ -8,7 +8,9 @@ use cli::{
|
|||
ipc::{self, IpcSender},
|
||||
CliRequest, CliResponse, IpcHandshake, FORCE_CLI_MODE_ENV_VAR_NAME,
|
||||
};
|
||||
use client::{self, TelemetrySettings, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN};
|
||||
use client::{
|
||||
self, Client, TelemetrySettings, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN,
|
||||
};
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use editor::{scroll::autoscroll::Autoscroll, Editor};
|
||||
use futures::{
|
||||
|
@ -33,7 +35,7 @@ use std::{
|
|||
fs::OpenOptions,
|
||||
io::{IsTerminal, Write as _},
|
||||
panic,
|
||||
path::{Path, PathBuf},
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
Arc, Weak,
|
||||
|
@ -222,6 +224,8 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let mut triggered_authentication = false;
|
||||
|
||||
match open_rx.try_next() {
|
||||
Ok(Some(OpenRequest::Paths { paths })) => {
|
||||
cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx))
|
||||
|
@ -231,9 +235,18 @@ fn main() {
|
|||
cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
|
||||
.detach();
|
||||
}
|
||||
Ok(Some(OpenRequest::JoinChannel { channel_id })) => cx
|
||||
.update(|cx| workspace::join_channel(channel_id, app_state.clone(), None, cx))
|
||||
.detach_and_log_err(cx),
|
||||
Ok(Some(OpenRequest::JoinChannel { channel_id })) => {
|
||||
triggered_authentication = true;
|
||||
let app_state = app_state.clone();
|
||||
let client = client.clone();
|
||||
cx.spawn(|mut cx| async move {
|
||||
// ignore errors here, we'll show a generic "not signed in"
|
||||
let _ = authenticate(client, &cx).await;
|
||||
cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx))
|
||||
.await
|
||||
})
|
||||
.detach_and_log_err(cx)
|
||||
}
|
||||
Ok(None) | Err(_) => cx
|
||||
.spawn({
|
||||
let app_state = app_state.clone();
|
||||
|
@ -266,20 +279,24 @@ fn main() {
|
|||
})
|
||||
.detach();
|
||||
|
||||
cx.spawn(|cx| async move {
|
||||
if stdout_is_a_pty() {
|
||||
if client::IMPERSONATE_LOGIN.is_some() {
|
||||
client.authenticate_and_connect(false, &cx).await?;
|
||||
}
|
||||
} else if client.has_keychain_credentials(&cx) {
|
||||
client.authenticate_and_connect(true, &cx).await?;
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
if !triggered_authentication {
|
||||
cx.spawn(|cx| async move { authenticate(client, &cx).await })
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn authenticate(client: Arc<Client>, cx: &AsyncAppContext) -> Result<()> {
|
||||
if stdout_is_a_pty() {
|
||||
if client::IMPERSONATE_LOGIN.is_some() {
|
||||
client.authenticate_and_connect(false, &cx).await?;
|
||||
}
|
||||
} else if client.has_keychain_credentials(&cx) {
|
||||
client.authenticate_and_connect(true, &cx).await?;
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
}
|
||||
|
||||
async fn installation_id() -> Result<String> {
|
||||
let legacy_key_name = "device_id";
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ impl OpenListener {
|
|||
|
||||
pub fn open_urls(&self, urls: Vec<String>) {
|
||||
self.triggered.store(true, Ordering::Release);
|
||||
dbg!(&urls);
|
||||
let request = if let Some(server_name) =
|
||||
urls.first().and_then(|url| url.strip_prefix("zed-cli://"))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue