use crate::{ rpc::Client, user::{User, UserStore}, util::TryFutureExt, }; use anyhow::Result; use gpui::{Entity, ModelContext, Task}; use postage::prelude::Stream; use smol::future::FutureExt; use std::{collections::HashSet, sync::Arc, time::Duration}; use zrpc::proto; pub struct Presence { collaborators: Vec, user_store: Arc, rpc: Arc, _maintain_people: Task<()>, } #[derive(Debug)] struct Collaborator { user: Arc, worktrees: Vec, } #[derive(Debug)] struct CollaboratorWorktree { root_name: String, is_shared: bool, participants: Vec>, } impl Presence { pub fn new(user_store: Arc, rpc: Arc, cx: &mut ModelContext) -> Self { let _maintain_collaborators = cx.spawn_weak(|this, mut cx| { let user_store = user_store.clone(); let foreground = cx.foreground(); async move { let mut current_user = user_store.watch_current_user(); loop { let timer = foreground.timer(Duration::from_secs(2)); let next_current_user = async { current_user.recv().await; }; next_current_user.race(timer).await; if current_user.borrow().is_some() { if let Some(this) = cx.read(|cx| this.upgrade(cx)) { this.update(&mut cx, |this, cx| this.refresh(cx)) .log_err() .await; } } } } }); Self { collaborators: Vec::new(), user_store, rpc, _maintain_people: _maintain_collaborators, } } fn refresh(&self, cx: &mut ModelContext) -> Task> { cx.spawn(|this, mut cx| { let rpc = self.rpc.clone(); let user_store = self.user_store.clone(); async move { let response = rpc.request(proto::GetCollaborators {}).await?; let mut user_ids = HashSet::new(); for collaborator in &response.collaborators { user_ids.insert(collaborator.user_id); user_ids.extend( collaborator .worktrees .iter() .flat_map(|w| &w.participants) .copied(), ); } user_store .load_users(user_ids.into_iter().collect()) .await?; let mut collaborators = Vec::new(); for collaborator in response.collaborators { collaborators.push(Collaborator::from_proto(collaborator, &user_store).await?); } this.update(&mut cx, |this, cx| { this.collaborators = collaborators; cx.notify(); }); Ok(()) } }) } } pub enum Event {} impl Entity for Presence { type Event = Event; } impl Collaborator { async fn from_proto( collaborator: proto::Collaborator, user_store: &Arc, ) -> Result { let user = user_store.fetch_user(collaborator.user_id).await?; let mut worktrees = Vec::new(); for worktree in collaborator.worktrees { let mut participants = Vec::new(); for participant_id in worktree.participants { participants.push(user_store.fetch_user(participant_id).await?); } worktrees.push(CollaboratorWorktree { root_name: worktree.root_name, is_shared: worktree.is_shared, participants, }); } Ok(Self { user, worktrees }) } }