68 lines
2.5 KiB
Rust
68 lines
2.5 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use revolt_config::config;
|
|
use revolt_models::v0;
|
|
use revolt_database::{util::{permissions::perms, reference::Reference}, Channel, Database, User};
|
|
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
|
use revolt_result::{create_error, Result};
|
|
|
|
use livekit_api::{access_token::{AccessToken, VideoGrants}, services::room::{CreateRoomOptions, RoomClient}};
|
|
use rocket::{serde::json::Json, State};
|
|
|
|
/// # Join Call
|
|
///
|
|
/// Asks the voice server for a token to join the call.
|
|
#[openapi(tag = "Voice")]
|
|
#[post("/<target>/join_call")]
|
|
pub async fn call(db: &State<Database>, rooms: &State<RoomClient>, user: User, target: Reference) -> Result<Json<v0::CreateVoiceUserResponse>> {
|
|
let channel = target.as_channel(db).await?;
|
|
|
|
let mut permissions = perms(db, &user).channel(&channel);
|
|
|
|
calculate_channel_permissions(&mut permissions)
|
|
.await
|
|
.throw_if_lacking_channel_permission(ChannelPermission::Connect)?;
|
|
|
|
if user.current_voice_channel().await?.is_some() {
|
|
return Err(create_error!(AlreadyInVoiceChannel))
|
|
}
|
|
|
|
let config = config().await;
|
|
|
|
if config.api.livekit.url.is_empty() {
|
|
return Err(create_error!(LiveKitUnavailable));
|
|
};
|
|
|
|
let voice = match &channel {
|
|
Channel::DirectMessage { .. } | Channel::VoiceChannel { .. } => Cow::Owned(v0::VoiceInformation::default()),
|
|
Channel::TextChannel { voice: Some(voice), .. } => Cow::Borrowed(voice),
|
|
_ => return Err(create_error!(CannotJoinCall))
|
|
};
|
|
|
|
let token = AccessToken::with_api_key(&config.api.livekit.key, &config.api.livekit.secret)
|
|
.with_name(&format!("{}#{}", user.username, user.discriminator))
|
|
.with_identity(&user.id)
|
|
.with_metadata(&serde_json::to_string(&user).map_err(|_| create_error!(InternalError))?)
|
|
.with_grants(VideoGrants {
|
|
room_join: true,
|
|
room: channel.id().to_string(),
|
|
..Default::default()
|
|
})
|
|
.to_jwt()
|
|
.inspect_err(|e| log::error!("{e:?}"))
|
|
.map_err(|_| create_error!(InternalError))?;
|
|
|
|
let room = rooms.create_room(&channel.id(), CreateRoomOptions {
|
|
max_participants: voice.max_users.unwrap_or(u32::MAX),
|
|
empty_timeout: 5 * 60, // 5 minutes
|
|
..Default::default()
|
|
})
|
|
.await
|
|
.inspect_err(|e| log::error!("{e:?}"))
|
|
.map_err(|_| create_error!(InternalError))?;
|
|
|
|
log::info!("created room {room:?}");
|
|
|
|
Ok(Json(v0::CreateVoiceUserResponse { token }))
|
|
}
|