Skip to content

Commit

Permalink
talkers (#8158)
Browse files Browse the repository at this point in the history
Release Notes:

- Added an "Unmute" action for guests in calls. This lets them use the
mic, but not edit projects.
  • Loading branch information
ConradIrwin authored Feb 22, 2024
1 parent fa2c92d commit c6826a6
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 67 deletions.
23 changes: 17 additions & 6 deletions crates/call/src/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl Room {
cx.spawn(|this, mut cx| async move {
connect.await?;
this.update(&mut cx, |this, cx| {
if !this.read_only() {
if this.can_use_microphone() {
if let Some(live_kit) = &this.live_kit {
if !live_kit.muted_by_user && !live_kit.deafened {
return this.share_microphone(cx);
Expand Down Expand Up @@ -1322,11 +1322,6 @@ impl Room {
})
}

pub fn read_only(&self) -> bool {
!(self.local_participant().role == proto::ChannelRole::Member
|| self.local_participant().role == proto::ChannelRole::Admin)
}

pub fn is_speaking(&self) -> bool {
self.live_kit
.as_ref()
Expand All @@ -1337,6 +1332,22 @@ impl Room {
self.live_kit.as_ref().map(|live_kit| live_kit.deafened)
}

pub fn can_use_microphone(&self) -> bool {
use proto::ChannelRole::*;
match self.local_participant.role {
Admin | Member | Talker => true,
Guest | Banned => false,
}
}

pub fn can_share_projects(&self) -> bool {
use proto::ChannelRole::*;
match self.local_participant.role {
Admin | Member => true,
Guest | Banned | Talker => false,
}
}

#[track_caller]
pub fn share_microphone(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
if self.status.is_offline() {
Expand Down
3 changes: 2 additions & 1 deletion crates/channel/src/channel_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ impl ChannelMembership {
proto::ChannelRole::Admin => 0,
proto::ChannelRole::Member => 1,
proto::ChannelRole::Banned => 2,
proto::ChannelRole::Guest => 3,
proto::ChannelRole::Talker => 3,
proto::ChannelRole::Guest => 4,
},
kind_order: match self.kind {
proto::channel_member::Kind::Member => 0,
Expand Down
29 changes: 18 additions & 11 deletions crates/collab/src/db/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,12 @@ pub enum ChannelRole {
#[sea_orm(string_value = "member")]
#[default]
Member,
/// Talker can read, but not write.
/// They can use microphones and the channel chat
#[sea_orm(string_value = "talker")]
Talker,
/// Guest can read, but not write.
/// (thought they can use the channel chat)
/// They can not use microphones but can use the chat.
#[sea_orm(string_value = "guest")]
Guest,
/// Banned may not read.
Expand All @@ -114,8 +118,9 @@ impl ChannelRole {
pub fn should_override(&self, other: Self) -> bool {
use ChannelRole::*;
match self {
Admin => matches!(other, Member | Banned | Guest),
Member => matches!(other, Banned | Guest),
Admin => matches!(other, Member | Banned | Talker | Guest),
Member => matches!(other, Banned | Talker | Guest),
Talker => matches!(other, Guest),
Banned => matches!(other, Guest),
Guest => false,
}
Expand All @@ -134,7 +139,7 @@ impl ChannelRole {
use ChannelRole::*;
match self {
Admin | Member => true,
Guest => visibility == ChannelVisibility::Public,
Guest | Talker => visibility == ChannelVisibility::Public,
Banned => false,
}
}
Expand All @@ -144,24 +149,24 @@ impl ChannelRole {
use ChannelRole::*;
match self {
Admin | Member => true,
Guest | Banned => false,
Guest | Talker | Banned => false,
}
}

/// True if the role only allows access to public descendant channels
pub fn can_only_see_public_descendants(&self) -> bool {
use ChannelRole::*;
match self {
Guest => true,
Guest | Talker => true,
Admin | Member | Banned => false,
}
}

/// True if the role can share screen/microphone/projects into rooms.
pub fn can_publish_to_rooms(&self) -> bool {
pub fn can_use_microphone(&self) -> bool {
use ChannelRole::*;
match self {
Admin | Member => true,
Admin | Member | Talker => true,
Guest | Banned => false,
}
}
Expand All @@ -171,15 +176,15 @@ impl ChannelRole {
use ChannelRole::*;
match self {
Admin | Member => true,
Guest | Banned => false,
Talker | Guest | Banned => false,
}
}

/// True if the role can read shared projects.
pub fn can_read_projects(&self) -> bool {
use ChannelRole::*;
match self {
Admin | Member | Guest => true,
Admin | Member | Guest | Talker => true,
Banned => false,
}
}
Expand All @@ -188,7 +193,7 @@ impl ChannelRole {
use ChannelRole::*;
match self {
Admin | Member => true,
Banned | Guest => false,
Banned | Guest | Talker => false,
}
}
}
Expand All @@ -198,6 +203,7 @@ impl From<proto::ChannelRole> for ChannelRole {
match value {
proto::ChannelRole::Admin => ChannelRole::Admin,
proto::ChannelRole::Member => ChannelRole::Member,
proto::ChannelRole::Talker => ChannelRole::Talker,
proto::ChannelRole::Guest => ChannelRole::Guest,
proto::ChannelRole::Banned => ChannelRole::Banned,
}
Expand All @@ -209,6 +215,7 @@ impl Into<proto::ChannelRole> for ChannelRole {
match self {
ChannelRole::Admin => proto::ChannelRole::Admin,
ChannelRole::Member => proto::ChannelRole::Member,
ChannelRole::Talker => proto::ChannelRole::Talker,
ChannelRole::Guest => proto::ChannelRole::Guest,
ChannelRole::Banned => proto::ChannelRole::Banned,
}
Expand Down
13 changes: 9 additions & 4 deletions crates/collab/src/db/queries/channels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ impl Database {
match role {
Some(ChannelRole::Admin) => Ok(role.unwrap()),
Some(ChannelRole::Member)
| Some(ChannelRole::Talker)
| Some(ChannelRole::Banned)
| Some(ChannelRole::Guest)
| None => Err(anyhow!(
Expand All @@ -813,7 +814,10 @@ impl Database {
let channel_role = self.channel_role_for_user(channel, user_id, tx).await?;
match channel_role {
Some(ChannelRole::Admin) | Some(ChannelRole::Member) => Ok(channel_role.unwrap()),
Some(ChannelRole::Banned) | Some(ChannelRole::Guest) | None => Err(anyhow!(
Some(ChannelRole::Banned)
| Some(ChannelRole::Guest)
| Some(ChannelRole::Talker)
| None => Err(anyhow!(
"user is not a channel member or channel does not exist"
))?,
}
Expand All @@ -828,9 +832,10 @@ impl Database {
) -> Result<ChannelRole> {
let role = self.channel_role_for_user(channel, user_id, tx).await?;
match role {
Some(ChannelRole::Admin) | Some(ChannelRole::Member) | Some(ChannelRole::Guest) => {
Ok(role.unwrap())
}
Some(ChannelRole::Admin)
| Some(ChannelRole::Member)
| Some(ChannelRole::Guest)
| Some(ChannelRole::Talker) => Ok(role.unwrap()),
Some(ChannelRole::Banned) | None => Err(anyhow!(
"user is not a channel participant or channel does not exist"
))?,
Expand Down
2 changes: 1 addition & 1 deletion crates/collab/src/db/queries/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Database {
if !participant
.role
.unwrap_or(ChannelRole::Member)
.can_publish_to_rooms()
.can_edit_projects()
{
return Err(anyhow!("guests cannot share projects"))?;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/collab/src/db/queries/rooms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl Database {

let called_user_role = match caller.role.unwrap_or(ChannelRole::Member) {
ChannelRole::Admin | ChannelRole::Member => ChannelRole::Member,
ChannelRole::Guest => ChannelRole::Guest,
ChannelRole::Guest | ChannelRole::Talker => ChannelRole::Guest,
ChannelRole::Banned => return Err(anyhow!("banned users cannot invite").into()),
};

Expand Down
53 changes: 37 additions & 16 deletions crates/collab/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use axum::{
Extension, Router, TypedHeader,
};
use collections::{HashMap, HashSet};
pub use connection_pool::ConnectionPool;
pub use connection_pool::{ConnectionPool, ZedVersion};
use futures::{
channel::oneshot,
future::{self, BoxFuture},
Expand Down Expand Up @@ -558,6 +558,7 @@ impl Server {
connection: Connection,
address: String,
user: User,
zed_version: ZedVersion,
impersonator: Option<User>,
mut send_connection_id: Option<oneshot::Sender<ConnectionId>>,
executor: Executor,
Expand Down Expand Up @@ -599,7 +600,7 @@ impl Server {

{
let mut pool = this.connection_pool.lock();
pool.add_connection(connection_id, user_id, user.admin);
pool.add_connection(connection_id, user_id, user.admin, zed_version);
this.peer.send(connection_id, build_initial_contacts_update(contacts, &pool))?;
this.peer.send(connection_id, build_update_user_channels(&channels_for_user))?;
this.peer.send(connection_id, build_channels_update(
Expand Down Expand Up @@ -879,17 +880,20 @@ pub async fn handle_websocket_request(
.into_response();
}

// the first version of zed that sent this header was 0.121.x
if let Some(version) = app_version_header.map(|header| header.0 .0) {
// 0.123.0 was a nightly version with incompatible collab changes
// that were reverted.
if version == "0.123.0".parse().unwrap() {
return (
StatusCode::UPGRADE_REQUIRED,
"client must be upgraded".to_string(),
)
.into_response();
}
let Some(version) = app_version_header.map(|header| ZedVersion(header.0 .0)) else {
return (
StatusCode::UPGRADE_REQUIRED,
"no version header found".to_string(),
)
.into_response();
};

if !version.is_supported() {
return (
StatusCode::UPGRADE_REQUIRED,
"client must be upgraded".to_string(),
)
.into_response();
}

let socket_address = socket_address.to_string();
Expand All @@ -906,6 +910,7 @@ pub async fn handle_websocket_request(
connection,
socket_address,
user,
version,
impersonator.0,
None,
Executor::Production,
Expand Down Expand Up @@ -1311,20 +1316,36 @@ async fn set_room_participant_role(
response: Response<proto::SetRoomParticipantRole>,
session: Session,
) -> Result<()> {
let user_id = UserId::from_proto(request.user_id);
let role = ChannelRole::from(request.role());

if role == ChannelRole::Talker {
let pool = session.connection_pool().await;

for connection in pool.user_connections(user_id) {
if !connection.zed_version.supports_talker_role() {
Err(anyhow!(
"This user is on zed {} which does not support unmute",
connection.zed_version
))?;
}
}
}

let (live_kit_room, can_publish) = {
let room = session
.db()
.await
.set_room_participant_role(
session.user_id,
RoomId::from_proto(request.room_id),
UserId::from_proto(request.user_id),
ChannelRole::from(request.role()),
user_id,
role,
)
.await?;

let live_kit_room = room.live_kit_room.clone();
let can_publish = ChannelRole::from(request.role()).can_publish_to_rooms();
let can_publish = ChannelRole::from(request.role()).can_use_microphone();
room_updated(&room, &session.peer);
(live_kit_room, can_publish)
};
Expand Down
Loading

0 comments on commit c6826a6

Please sign in to comment.