Make joining a channel as a guest always succeed
This commit is contained in:
parent
f6f9b5c8cb
commit
4e7b35c917
7 changed files with 371 additions and 172 deletions
|
@ -88,6 +88,84 @@ impl Database {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn join_channel_internal(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
user_id: UserId,
|
||||
connection: ConnectionId,
|
||||
environment: &str,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<(JoinRoom, bool)> {
|
||||
let mut joined = false;
|
||||
|
||||
let channel = channel::Entity::find()
|
||||
.filter(channel::Column::Id.eq(channel_id))
|
||||
.one(&*tx)
|
||||
.await?;
|
||||
|
||||
let mut role = self
|
||||
.channel_role_for_user(channel_id, user_id, &*tx)
|
||||
.await?;
|
||||
|
||||
if role.is_none() {
|
||||
if channel.as_ref().map(|c| c.visibility) == Some(ChannelVisibility::Public) {
|
||||
channel_member::Entity::insert(channel_member::ActiveModel {
|
||||
id: ActiveValue::NotSet,
|
||||
channel_id: ActiveValue::Set(channel_id),
|
||||
user_id: ActiveValue::Set(user_id),
|
||||
accepted: ActiveValue::Set(true),
|
||||
role: ActiveValue::Set(ChannelRole::Guest),
|
||||
})
|
||||
.on_conflict(
|
||||
OnConflict::columns([
|
||||
channel_member::Column::UserId,
|
||||
channel_member::Column::ChannelId,
|
||||
])
|
||||
.update_columns([channel_member::Column::Accepted])
|
||||
.to_owned(),
|
||||
)
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
|
||||
debug_assert!(
|
||||
self.channel_role_for_user(channel_id, user_id, &*tx)
|
||||
.await?
|
||||
== Some(ChannelRole::Guest)
|
||||
);
|
||||
|
||||
role = Some(ChannelRole::Guest);
|
||||
joined = true;
|
||||
}
|
||||
}
|
||||
|
||||
if channel.is_none() || role.is_none() || role == Some(ChannelRole::Banned) {
|
||||
Err(anyhow!("no such channel, or not allowed"))?
|
||||
}
|
||||
|
||||
let live_kit_room = format!("channel-{}", nanoid::nanoid!(30));
|
||||
let room_id = self
|
||||
.get_or_create_channel_room(channel_id, &live_kit_room, environment, &*tx)
|
||||
.await?;
|
||||
|
||||
self.join_channel_room_internal(channel_id, room_id, user_id, connection, &*tx)
|
||||
.await
|
||||
.map(|jr| (jr, joined))
|
||||
}
|
||||
|
||||
pub async fn join_channel(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
user_id: UserId,
|
||||
connection: ConnectionId,
|
||||
environment: &str,
|
||||
) -> Result<(JoinRoom, bool)> {
|
||||
self.transaction(move |tx| async move {
|
||||
self.join_channel_internal(channel_id, user_id, connection, environment, &*tx)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn set_channel_visibility(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
|
@ -981,38 +1059,39 @@ impl Database {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn get_or_create_channel_room(
|
||||
pub(crate) async fn get_or_create_channel_room(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
live_kit_room: &str,
|
||||
enviroment: &str,
|
||||
environment: &str,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<RoomId> {
|
||||
self.transaction(|tx| async move {
|
||||
let tx = tx;
|
||||
let room = room::Entity::find()
|
||||
.filter(room::Column::ChannelId.eq(channel_id))
|
||||
.one(&*tx)
|
||||
.await?;
|
||||
|
||||
let room = room::Entity::find()
|
||||
.filter(room::Column::ChannelId.eq(channel_id))
|
||||
.one(&*tx)
|
||||
.await?;
|
||||
let room_id = if let Some(room) = room {
|
||||
if let Some(env) = room.enviroment {
|
||||
if &env != environment {
|
||||
Err(anyhow!("must join using the {} release", env))?;
|
||||
}
|
||||
}
|
||||
room.id
|
||||
} else {
|
||||
let result = room::Entity::insert(room::ActiveModel {
|
||||
channel_id: ActiveValue::Set(Some(channel_id)),
|
||||
live_kit_room: ActiveValue::Set(live_kit_room.to_string()),
|
||||
enviroment: ActiveValue::Set(Some(environment.to_string())),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
|
||||
let room_id = if let Some(room) = room {
|
||||
room.id
|
||||
} else {
|
||||
let result = room::Entity::insert(room::ActiveModel {
|
||||
channel_id: ActiveValue::Set(Some(channel_id)),
|
||||
live_kit_room: ActiveValue::Set(live_kit_room.to_string()),
|
||||
enviroment: ActiveValue::Set(Some(enviroment.to_string())),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
result.last_insert_id
|
||||
};
|
||||
|
||||
result.last_insert_id
|
||||
};
|
||||
|
||||
Ok(room_id)
|
||||
})
|
||||
.await
|
||||
Ok(room_id)
|
||||
}
|
||||
|
||||
// Insert an edge from the given channel to the given other channel.
|
||||
|
|
|
@ -300,99 +300,139 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
enum QueryParticipantIndices {
|
||||
ParticipantIndex,
|
||||
if channel_id.is_some() {
|
||||
Err(anyhow!("tried to join channel call directly"))?
|
||||
}
|
||||
let existing_participant_indices: Vec<i32> = room_participant::Entity::find()
|
||||
.filter(
|
||||
room_participant::Column::RoomId
|
||||
.eq(room_id)
|
||||
.and(room_participant::Column::ParticipantIndex.is_not_null()),
|
||||
)
|
||||
.select_only()
|
||||
.column(room_participant::Column::ParticipantIndex)
|
||||
.into_values::<_, QueryParticipantIndices>()
|
||||
.all(&*tx)
|
||||
|
||||
let participant_index = self
|
||||
.get_next_participant_index_internal(room_id, &*tx)
|
||||
.await?;
|
||||
|
||||
let mut participant_index = 0;
|
||||
while existing_participant_indices.contains(&participant_index) {
|
||||
participant_index += 1;
|
||||
}
|
||||
|
||||
if let Some(channel_id) = channel_id {
|
||||
self.check_user_is_channel_member(channel_id, user_id, &*tx)
|
||||
.await?;
|
||||
|
||||
room_participant::Entity::insert_many([room_participant::ActiveModel {
|
||||
room_id: ActiveValue::set(room_id),
|
||||
user_id: ActiveValue::set(user_id),
|
||||
let result = room_participant::Entity::update_many()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(room_participant::Column::RoomId.eq(room_id))
|
||||
.add(room_participant::Column::UserId.eq(user_id))
|
||||
.add(room_participant::Column::AnsweringConnectionId.is_null()),
|
||||
)
|
||||
.set(room_participant::ActiveModel {
|
||||
participant_index: ActiveValue::Set(Some(participant_index)),
|
||||
answering_connection_id: ActiveValue::set(Some(connection.id as i32)),
|
||||
answering_connection_server_id: ActiveValue::set(Some(ServerId(
|
||||
connection.owner_id as i32,
|
||||
))),
|
||||
answering_connection_lost: ActiveValue::set(false),
|
||||
calling_user_id: ActiveValue::set(user_id),
|
||||
calling_connection_id: ActiveValue::set(connection.id as i32),
|
||||
calling_connection_server_id: ActiveValue::set(Some(ServerId(
|
||||
connection.owner_id as i32,
|
||||
))),
|
||||
participant_index: ActiveValue::Set(Some(participant_index)),
|
||||
..Default::default()
|
||||
}])
|
||||
.on_conflict(
|
||||
OnConflict::columns([room_participant::Column::UserId])
|
||||
.update_columns([
|
||||
room_participant::Column::AnsweringConnectionId,
|
||||
room_participant::Column::AnsweringConnectionServerId,
|
||||
room_participant::Column::AnsweringConnectionLost,
|
||||
room_participant::Column::ParticipantIndex,
|
||||
])
|
||||
.to_owned(),
|
||||
)
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
} else {
|
||||
let result = room_participant::Entity::update_many()
|
||||
.filter(
|
||||
Condition::all()
|
||||
.add(room_participant::Column::RoomId.eq(room_id))
|
||||
.add(room_participant::Column::UserId.eq(user_id))
|
||||
.add(room_participant::Column::AnsweringConnectionId.is_null()),
|
||||
)
|
||||
.set(room_participant::ActiveModel {
|
||||
participant_index: ActiveValue::Set(Some(participant_index)),
|
||||
answering_connection_id: ActiveValue::set(Some(connection.id as i32)),
|
||||
answering_connection_server_id: ActiveValue::set(Some(ServerId(
|
||||
connection.owner_id as i32,
|
||||
))),
|
||||
answering_connection_lost: ActiveValue::set(false),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
if result.rows_affected == 0 {
|
||||
Err(anyhow!("room does not exist or was already joined"))?;
|
||||
}
|
||||
if result.rows_affected == 0 {
|
||||
Err(anyhow!("room does not exist or was already joined"))?;
|
||||
}
|
||||
|
||||
let room = self.get_room(room_id, &tx).await?;
|
||||
let channel_members = if let Some(channel_id) = channel_id {
|
||||
self.get_channel_participants_internal(channel_id, &tx)
|
||||
.await?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
Ok(JoinRoom {
|
||||
room,
|
||||
channel_id,
|
||||
channel_members,
|
||||
channel_id: None,
|
||||
channel_members: vec![],
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_next_participant_index_internal(
|
||||
&self,
|
||||
room_id: RoomId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<i32> {
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
enum QueryParticipantIndices {
|
||||
ParticipantIndex,
|
||||
}
|
||||
let existing_participant_indices: Vec<i32> = room_participant::Entity::find()
|
||||
.filter(
|
||||
room_participant::Column::RoomId
|
||||
.eq(room_id)
|
||||
.and(room_participant::Column::ParticipantIndex.is_not_null()),
|
||||
)
|
||||
.select_only()
|
||||
.column(room_participant::Column::ParticipantIndex)
|
||||
.into_values::<_, QueryParticipantIndices>()
|
||||
.all(&*tx)
|
||||
.await?;
|
||||
|
||||
let mut participant_index = 0;
|
||||
while existing_participant_indices.contains(&participant_index) {
|
||||
participant_index += 1;
|
||||
}
|
||||
|
||||
Ok(participant_index)
|
||||
}
|
||||
|
||||
pub async fn channel_id_for_room(&self, room_id: RoomId) -> Result<Option<ChannelId>> {
|
||||
self.transaction(|tx| async move {
|
||||
let room: Option<room::Model> = room::Entity::find()
|
||||
.filter(room::Column::Id.eq(room_id))
|
||||
.one(&*tx)
|
||||
.await?;
|
||||
|
||||
Ok(room.and_then(|room| room.channel_id))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn join_channel_room_internal(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
room_id: RoomId,
|
||||
user_id: UserId,
|
||||
connection: ConnectionId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<JoinRoom> {
|
||||
let participant_index = self
|
||||
.get_next_participant_index_internal(room_id, &*tx)
|
||||
.await?;
|
||||
|
||||
room_participant::Entity::insert_many([room_participant::ActiveModel {
|
||||
room_id: ActiveValue::set(room_id),
|
||||
user_id: ActiveValue::set(user_id),
|
||||
answering_connection_id: ActiveValue::set(Some(connection.id as i32)),
|
||||
answering_connection_server_id: ActiveValue::set(Some(ServerId(
|
||||
connection.owner_id as i32,
|
||||
))),
|
||||
answering_connection_lost: ActiveValue::set(false),
|
||||
calling_user_id: ActiveValue::set(user_id),
|
||||
calling_connection_id: ActiveValue::set(connection.id as i32),
|
||||
calling_connection_server_id: ActiveValue::set(Some(ServerId(
|
||||
connection.owner_id as i32,
|
||||
))),
|
||||
participant_index: ActiveValue::Set(Some(participant_index)),
|
||||
..Default::default()
|
||||
}])
|
||||
.on_conflict(
|
||||
OnConflict::columns([room_participant::Column::UserId])
|
||||
.update_columns([
|
||||
room_participant::Column::AnsweringConnectionId,
|
||||
room_participant::Column::AnsweringConnectionServerId,
|
||||
room_participant::Column::AnsweringConnectionLost,
|
||||
room_participant::Column::ParticipantIndex,
|
||||
])
|
||||
.to_owned(),
|
||||
)
|
||||
.exec(&*tx)
|
||||
.await?;
|
||||
|
||||
let room = self.get_room(room_id, &tx).await?;
|
||||
let channel_members = self
|
||||
.get_channel_participants_internal(channel_id, &tx)
|
||||
.await?;
|
||||
Ok(JoinRoom {
|
||||
room,
|
||||
channel_id: Some(channel_id),
|
||||
channel_members,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn rejoin_room(
|
||||
&self,
|
||||
rejoin_room: proto::RejoinRoom,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue