Introduce call infrastructure

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-09-23 18:16:57 +02:00
parent ebb5ffcedc
commit 4a9bf8f4fe
11 changed files with 249 additions and 45 deletions

View file

@ -100,16 +100,16 @@ async fn test_share_project_in_room(
let mut incoming_calls_b = client_b
.user_store
.read_with(cx_b, |user, _| user.incoming_calls());
let user_b_joined = room_a.update(cx_a, |room, cx| {
room.invite(client_b.user_id().unwrap(), cx)
});
.update(cx_b, |user, _| user.incoming_calls());
room_a
.update(cx_a, |room, cx| room.call(client_b.user_id().unwrap(), cx))
.await
.unwrap();
let call_b = incoming_calls_b.next().await.unwrap();
let room_b = cx_b
.update(|cx| Room::join(call_b.room_id, client_b.clone(), cx))
.await
.unwrap();
user_b_joined.await.unwrap();
}
#[gpui::test(iterations = 10)]
@ -512,7 +512,7 @@ async fn test_cancel_join_request(
let user_b = client_a
.user_store
.update(cx_a, |store, cx| {
store.fetch_user(client_b.user_id().unwrap(), cx)
store.get_user(client_b.user_id().unwrap(), cx)
})
.await
.unwrap();

View file

@ -152,6 +152,7 @@ impl Server {
server
.add_request_handler(Server::ping)
.add_request_handler(Server::create_room)
.add_request_handler(Server::call)
.add_request_handler(Server::register_project)
.add_request_handler(Server::unregister_project)
.add_request_handler(Server::join_project)
@ -604,6 +605,68 @@ impl Server {
Ok(())
}
async fn call(
self: Arc<Server>,
request: TypedEnvelope<proto::Call>,
response: Response<proto::Call>,
) -> Result<()> {
let to_user_id = UserId::from_proto(request.payload.to_user_id);
let room_id = request.payload.room_id;
let (from_user_id, receiver_ids, room) =
self.store()
.await
.call(room_id, request.sender_id, to_user_id)?;
for participant in &room.participants {
self.peer
.send(
ConnectionId(participant.peer_id),
proto::RoomUpdated {
room: Some(room.clone()),
},
)
.trace_err();
}
let mut calls = receiver_ids
.into_iter()
.map(|receiver_id| {
self.peer.request(
receiver_id,
proto::IncomingCall {
room_id,
from_user_id: from_user_id.to_proto(),
participant_user_ids: room.participants.iter().map(|p| p.user_id).collect(),
},
)
})
.collect::<FuturesUnordered<_>>();
while let Some(call_response) = calls.next().await {
match call_response.as_ref() {
Ok(_) => {
response.send(proto::Ack {})?;
return Ok(());
}
Err(_) => {
call_response.trace_err();
}
}
}
let room = self.store().await.call_failed(room_id, to_user_id)?;
for participant in &room.participants {
self.peer
.send(
ConnectionId(participant.peer_id),
proto::RoomUpdated {
room: Some(room.clone()),
},
)
.trace_err();
}
Err(anyhow!("failed to ring call recipient"))?
}
async fn register_project(
self: Arc<Server>,
request: TypedEnvelope<proto::RegisterProject>,

View file

@ -351,6 +351,45 @@ impl Store {
Ok(room_id)
}
pub fn call(
&mut self,
room_id: RoomId,
from_connection_id: ConnectionId,
to_user_id: UserId,
) -> Result<(UserId, Vec<ConnectionId>, proto::Room)> {
let from_user_id = self.user_id_for_connection(from_connection_id)?;
let to_connection_ids = self.connection_ids_for_user(to_user_id).collect::<Vec<_>>();
let room = self
.rooms
.get_mut(&room_id)
.ok_or_else(|| anyhow!("no such room"))?;
anyhow::ensure!(
room.participants
.iter()
.any(|participant| participant.peer_id == from_connection_id.0),
"no such room"
);
anyhow::ensure!(
room.pending_calls_to_user_ids
.iter()
.all(|user_id| UserId::from_proto(*user_id) != to_user_id),
"cannot call the same user more than once"
);
room.pending_calls_to_user_ids.push(to_user_id.to_proto());
Ok((from_user_id, to_connection_ids, room.clone()))
}
pub fn call_failed(&mut self, room_id: RoomId, to_user_id: UserId) -> Result<proto::Room> {
let room = self
.rooms
.get_mut(&room_id)
.ok_or_else(|| anyhow!("no such room"))?;
room.pending_calls_to_user_ids
.retain(|user_id| UserId::from_proto(*user_id) != to_user_id);
Ok(room.clone())
}
pub fn register_project(
&mut self,
host_connection_id: ConnectionId,