call.rs

  1mod participant;
  2pub mod room;
  3
  4use anyhow::{anyhow, Result};
  5use client::{incoming_call::IncomingCall, Client, UserStore};
  6use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Subscription, Task};
  7pub use participant::ParticipantLocation;
  8use project::Project;
  9pub use room::Room;
 10use std::sync::Arc;
 11
 12pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
 13    let active_call = cx.add_model(|_| ActiveCall::new(client, user_store));
 14    cx.set_global(active_call);
 15}
 16
 17pub struct ActiveCall {
 18    room: Option<(ModelHandle<Room>, Vec<Subscription>)>,
 19    client: Arc<Client>,
 20    user_store: ModelHandle<UserStore>,
 21}
 22
 23impl Entity for ActiveCall {
 24    type Event = room::Event;
 25}
 26
 27impl ActiveCall {
 28    fn new(client: Arc<Client>, user_store: ModelHandle<UserStore>) -> Self {
 29        Self {
 30            room: None,
 31            client,
 32            user_store,
 33        }
 34    }
 35
 36    pub fn global(cx: &AppContext) -> ModelHandle<Self> {
 37        cx.global::<ModelHandle<Self>>().clone()
 38    }
 39
 40    pub fn invite(
 41        &mut self,
 42        recipient_user_id: u64,
 43        initial_project: Option<ModelHandle<Project>>,
 44        cx: &mut ModelContext<Self>,
 45    ) -> Task<Result<()>> {
 46        let room = self.room.as_ref().map(|(room, _)| room.clone());
 47        let client = self.client.clone();
 48        let user_store = self.user_store.clone();
 49        cx.spawn(|this, mut cx| async move {
 50            let room = if let Some(room) = room {
 51                room
 52            } else {
 53                cx.update(|cx| Room::create(client, user_store, cx)).await?
 54            };
 55
 56            let initial_project_id = if let Some(initial_project) = initial_project {
 57                let room_id = room.read_with(&cx, |room, _| room.id());
 58                Some(
 59                    initial_project
 60                        .update(&mut cx, |project, cx| project.share(room_id, cx))
 61                        .await?,
 62                )
 63            } else {
 64                None
 65            };
 66
 67            this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx));
 68            room.update(&mut cx, |room, cx| {
 69                room.call(recipient_user_id, initial_project_id, cx)
 70            })
 71            .await?;
 72
 73            Ok(())
 74        })
 75    }
 76
 77    pub fn join(&mut self, call: &IncomingCall, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 78        if self.room.is_some() {
 79            return Task::ready(Err(anyhow!("cannot join while on another call")));
 80        }
 81
 82        let join = Room::join(call, self.client.clone(), self.user_store.clone(), cx);
 83        cx.spawn(|this, mut cx| async move {
 84            let room = join.await?;
 85            this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx));
 86            Ok(())
 87        })
 88    }
 89
 90    fn set_room(&mut self, room: Option<ModelHandle<Room>>, cx: &mut ModelContext<Self>) {
 91        if room.as_ref() != self.room.as_ref().map(|room| &room.0) {
 92            if let Some(room) = room {
 93                let subscriptions = vec![
 94                    cx.observe(&room, |_, _, cx| cx.notify()),
 95                    cx.subscribe(&room, |_, _, event, cx| cx.emit(event.clone())),
 96                ];
 97                self.room = Some((room, subscriptions));
 98            } else {
 99                self.room = None;
100            }
101            cx.notify();
102        }
103    }
104
105    pub fn room(&self) -> Option<&ModelHandle<Room>> {
106        self.room.as_ref().map(|(room, _)| room)
107    }
108}