move voice states to global

This commit is contained in:
Zomatree
2024-04-09 22:36:48 +01:00
parent ad0dcad497
commit ae87bc0b67
6 changed files with 62 additions and 60 deletions

View File

@@ -1,15 +1,15 @@
use std::collections::HashSet; use std::collections::HashSet;
use revolt_database::{ use revolt_database::{
events::client::{ChannelVoiceState, EventV1, ReadyServer, UserVoiceState}, util::permissions::DatabasePermissionQuery, Channel, Database, Member, events::client::EventV1, util::permissions::DatabasePermissionQuery, Channel, Database, Member,
MemberCompositeKey, Presence, RelationshipStatus, MemberCompositeKey, Presence, RelationshipStatus,
}; };
use revolt_models::v0; use revolt_models::v0;
use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_presence::filter_online; use revolt_presence::filter_online;
use revolt_result::Result; use revolt_result::{create_error, Result};
use redis_kiss::{get_connection, AsyncCommands}; use redis_kiss::{get_connection, AsyncCommands, Conn};
use super::state::{Cache, State}; use super::state::{Cache, State};
@@ -127,11 +127,18 @@ impl State {
// Filter server channels by permission. // Filter server channels by permission.
let channels = self.cache.filter_accessible_channels(db, channels).await; let channels = self.cache.filter_accessible_channels(db, channels).await;
let mut voice_states = Vec::new();
let mut conn = get_connection().await.unwrap();
// Append known user IDs from DMs. // Append known user IDs from DMs.
for channel in &channels { for channel in &channels {
match channel { match channel {
Channel::DirectMessage { recipients, .. } | Channel::Group { recipients, .. } => { Channel::DirectMessage { id, recipients, .. } | Channel::Group { id, recipients, .. } => {
user_ids.extend(&mut recipients.clone().into_iter()); user_ids.extend(&mut recipients.clone().into_iter());
if let Ok(Some(voice_state)) = self.fetch_voice_state(&mut conn, id).await {
voice_states.push(voice_state)
}
} }
_ => {} _ => {}
} }
@@ -199,32 +206,21 @@ impl State {
self.insert_subscription(channel.id().to_string()); self.insert_subscription(channel.id().to_string());
} }
let mut conn = get_connection().await.unwrap(); for server in &servers {
let mut new_servers = Vec::with_capacity(servers.len());
for server in servers {
let mut voice_states = vec![];
for channel in &server.channels { for channel in &server.channels {
let members = conn.smembers::<_, Vec<String>>(format!("vc-members-{channel}")).await.unwrap(); if let Ok(Some(voice_state)) = self.fetch_voice_state(&mut conn, channel).await {
voice_states.push(voice_state)
if !members.is_empty() {
voice_states.push(ChannelVoiceState {
id: channel.clone(),
participants: members.into_iter().map(|id| UserVoiceState { id }).collect()
})
} }
} }
new_servers.push(ReadyServer { server: server.into(), voice_states })
} }
Ok(EventV1::Ready { Ok(EventV1::Ready {
users, users,
servers: new_servers, servers: servers.into_iter().map(Into::into).collect(),
channels: channels.into_iter().map(Into::into).collect(), channels: channels.into_iter().map(Into::into).collect(),
members: members.into_iter().map(Into::into).collect(), members: members.into_iter().map(Into::into).collect(),
emojis: emojis.into_iter().map(Into::into).collect(), emojis: emojis.into_iter().map(Into::into).collect(),
voice_states
}) })
} }
@@ -571,4 +567,19 @@ impl State {
true true
} }
async fn fetch_voice_state(&self, conn: &mut Conn, channel: &str) -> Result<Option<v0::ChannelVoiceState>> {
let members = conn.smembers::<_, Vec<String>>(format!("vc-members-{channel}"))
.await
.map_err(|_| create_error!(InternalError))?;
if !members.is_empty() {
Ok(Some(v0::ChannelVoiceState {
id: channel.to_string(),
participants: members.into_iter().map(|id| v0::UserVoiceState { id }).collect()
}))
} else {
Ok(None)
}
}
} }

View File

@@ -2,10 +2,7 @@ use authifier::AuthifierEvent;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use revolt_models::v0::{ use revolt_models::v0::{
AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, AppendMessage, Channel, ChannelVoiceState, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, Report, Server, User, UserSettings, UserVoiceState, Webhook
FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember,
PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, Report, Server, User,
UserSettings, Webhook
}; };
use revolt_result::Error; use revolt_result::Error;
@@ -39,25 +36,6 @@ pub enum ErrorEvent {
APIError(Error), APIError(Error),
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserVoiceState {
pub id: String
// TODO - muted, etc
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ChannelVoiceState {
pub id: String,
pub participants: Vec<UserVoiceState>
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReadyServer {
#[serde(flatten)]
pub server: Server,
pub voice_states: Vec<ChannelVoiceState>
}
/// Protocol Events /// Protocol Events
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")] #[serde(tag = "type")]
@@ -70,10 +48,11 @@ pub enum EventV1 {
/// Basic data to cache /// Basic data to cache
Ready { Ready {
users: Vec<User>, users: Vec<User>,
servers: Vec<ReadyServer>, servers: Vec<Server>,
channels: Vec<Channel>, channels: Vec<Channel>,
members: Vec<Member>, members: Vec<Member>,
emojis: Vec<Emoji>, emojis: Vec<Emoji>,
voice_states: Vec<ChannelVoiceState>
}, },
/// Ping response /// Ping response
@@ -248,7 +227,7 @@ pub enum EventV1 {
/// Voice events /// Voice events
VoiceChannelJoin { VoiceChannelJoin {
id: String, id: String,
user: String, state: UserVoiceState,
}, },
VoiceChannelLeave { VoiceChannelLeave {
id: String, id: String,

View File

@@ -1,4 +1,4 @@
use super::File; use super::{File, UserVoiceState};
use revolt_permissions::{Override, OverrideField}; use revolt_permissions::{Override, OverrideField};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@@ -306,10 +306,18 @@ auto_derived!(
} }
/// Voice server token response /// Voice server token response
pub struct LegacyCreateVoiceUserResponse { pub struct CreateVoiceUserResponse {
/// Token for authenticating with the voice server /// Token for authenticating with the voice server
token: String, pub token: String,
} }
/// Voice state for a channel
pub struct ChannelVoiceState {
pub id: String,
/// The states of the users who are connected to the channel
pub participants: Vec<UserVoiceState>
}
); );
impl Channel { impl Channel {

View File

@@ -270,6 +270,13 @@ auto_derived!(
/// Username and discriminator combo separated by # /// Username and discriminator combo separated by #
pub username: String, pub username: String,
} }
/// Voice State information for a user
pub struct UserVoiceState {
pub id: String
// TODO - muted, etc
}
); );
pub trait CheckRelationship { pub trait CheckRelationship {

View File

@@ -2,27 +2,19 @@ use std::borrow::Cow;
use revolt_config::config; use revolt_config::config;
use revolt_models::v0; use revolt_models::v0;
use revolt_database::{events::client::EventV1, util::{permissions::perms, reference::Reference}, Channel, Database, User}; use revolt_database::{util::{permissions::perms, reference::Reference}, Channel, Database, User};
use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use livekit_api::{access_token::{AccessToken, VideoGrants}, services::room::{CreateRoomOptions, RoomClient}}; use livekit_api::{access_token::{AccessToken, VideoGrants}, services::room::{CreateRoomOptions, RoomClient}};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
/// # Voice Server Token Response
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct CreateVoiceUserResponse {
/// Token for authenticating with the voice server
token: String,
}
/// # Join Call /// # Join Call
/// ///
/// Asks the voice server for a token to join the call. /// Asks the voice server for a token to join the call.
#[openapi(tag = "Voice")] #[openapi(tag = "Voice")]
#[post("/<target>/join_call")] #[post("/<target>/join_call")]
pub async fn call(db: &State<Database>, rooms: &State<RoomClient>, user: User, target: Reference) -> Result<Json<CreateVoiceUserResponse>> { 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 channel = target.as_channel(db).await?;
let mut permissions = perms(db, &user).channel(&channel); let mut permissions = perms(db, &user).channel(&channel);
@@ -71,5 +63,5 @@ pub async fn call(db: &State<Database>, rooms: &State<RoomClient>, user: User, t
log::info!("created room {room:?}"); log::info!("created room {room:?}");
Ok(Json(CreateVoiceUserResponse { token })) Ok(Json(v0::CreateVoiceUserResponse { token }))
} }

View File

@@ -3,6 +3,7 @@ use std::env;
use redis_kiss::{get_connection, AsyncCommands}; use redis_kiss::{get_connection, AsyncCommands};
use revolt_database::events::client::EventV1; use revolt_database::events::client::EventV1;
use revolt_models::v0::UserVoiceState;
use rocket::{build, post, routes, serde::json::Json, Config}; use rocket::{build, post, routes, serde::json::Json, Config};
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
use livekit_protocol::WebhookEvent; use livekit_protocol::WebhookEvent;
@@ -47,9 +48,13 @@ async fn ingress(body: Json<WebhookEvent>) -> Result<EmptyResponse> {
redis.sadd::<_, _, u64>(format!("vc-members-{}", channel_id), user_id).await.unwrap(); redis.sadd::<_, _, u64>(format!("vc-members-{}", channel_id), user_id).await.unwrap();
redis.set::<_, _, String>(format!("vc-{}", user_id), &channel_id).await.unwrap(); redis.set::<_, _, String>(format!("vc-{}", user_id), &channel_id).await.unwrap();
let voice_state = UserVoiceState {
id: user_id.clone()
};
EventV1::VoiceChannelJoin { EventV1::VoiceChannelJoin {
id: channel_id.clone(), id: channel_id.clone(),
user: user_id.clone() state: voice_state
} }
.p(channel_id.clone()) .p(channel_id.clone())
.await .await