init
This commit is contained in:
@@ -3,10 +3,10 @@ use crate::permissions::ChannelPermission;
|
||||
use crate::repositories::Repositories;
|
||||
use event_bus::EventBus;
|
||||
use parking_lot::RwLock;
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||
|
||||
/// In-memory index of the users that can receive events for each channel.
|
||||
#[derive(Debug, Default)]
|
||||
@@ -16,6 +16,58 @@ pub struct RealtimeRegistry {
|
||||
}
|
||||
|
||||
impl RealtimeRegistry {
|
||||
/// Rebuilds one channel audience after a committed structural change.
|
||||
pub async fn refresh_channel(
|
||||
&self,
|
||||
repositories: &Repositories,
|
||||
channel_id: Uuid,
|
||||
) -> anyhow::Result<()> {
|
||||
let channel = channel::Entity::find_by_id(channel_id)
|
||||
.one(&repositories.channel.context.db)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow::anyhow!("Channel not found"))?;
|
||||
|
||||
if channel.channel_type == channel::ChannelType::DM {
|
||||
let users = channel_user::Entity::find()
|
||||
.filter(channel_user::Column::ChannelId.eq(channel_id))
|
||||
.all(&repositories.channel.context.db)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|member| member.user_id);
|
||||
self.set_channel_users(channel_id, users);
|
||||
} else {
|
||||
let permissions = repositories.computed_permission.get_all().await?;
|
||||
self.set_channel_users(
|
||||
channel_id,
|
||||
permissions.into_iter().filter_map(|permission| {
|
||||
(permission.scope_type == PermissionScopeType::Channel
|
||||
&& permission.resource_id == channel_id
|
||||
&& ChannelPermission::from_bits_retain(permission.permissions as u64)
|
||||
.contains(ChannelPermission::READ_CHANNEL))
|
||||
.then_some(permission.user_id)
|
||||
}),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn refresh_user(&self, repositories: &Repositories, user_id: Uuid) -> anyhow::Result<()> {
|
||||
let channels = repositories
|
||||
.computed_permission
|
||||
.get_all()
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|permission| {
|
||||
permission.user_id == user_id
|
||||
&& permission.scope_type == PermissionScopeType::Channel
|
||||
&& ChannelPermission::from_bits_retain(permission.permissions as u64)
|
||||
.contains(ChannelPermission::READ_CHANNEL)
|
||||
})
|
||||
.map(|permission| permission.resource_id);
|
||||
self.set_user_channels(user_id, channels);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, repositories: &Repositories) -> anyhow::Result<()> {
|
||||
let permissions = repositories.computed_permission.get_all().await?;
|
||||
let mut channel_users = HashMap::<Uuid, HashSet<Uuid>>::new();
|
||||
@@ -51,8 +103,14 @@ impl RealtimeRegistry {
|
||||
.all(&repositories.channel.context.db)
|
||||
.await?;
|
||||
for member in members {
|
||||
channel_users.entry(member.channel_id).or_default().insert(member.user_id);
|
||||
user_channels.entry(member.user_id).or_default().insert(member.channel_id);
|
||||
channel_users
|
||||
.entry(member.channel_id)
|
||||
.or_default()
|
||||
.insert(member.user_id);
|
||||
user_channels
|
||||
.entry(member.user_id)
|
||||
.or_default()
|
||||
.insert(member.channel_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +131,17 @@ impl RealtimeRegistry {
|
||||
let users: HashSet<_> = users.into_iter().collect();
|
||||
let old = {
|
||||
let mut by_channel = self.channel_users.write();
|
||||
by_channel.insert(channel_id, users.clone()).unwrap_or_default()
|
||||
by_channel
|
||||
.insert(channel_id, users.clone())
|
||||
.unwrap_or_default()
|
||||
};
|
||||
let mut by_user = self.user_channels.write();
|
||||
for user_id in old.difference(&users) {
|
||||
if let Some(channels) = by_user.get_mut(user_id) {
|
||||
channels.remove(&channel_id);
|
||||
if channels.is_empty() { by_user.remove(user_id); }
|
||||
if channels.is_empty() {
|
||||
by_user.remove(user_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for user_id in users {
|
||||
@@ -148,21 +210,36 @@ impl RealtimeRegistry {
|
||||
move |repositories, (_channel_id, user_id, _permissions): (Uuid, Uuid, u64)| {
|
||||
let registry = Arc::clone(®istry);
|
||||
async move {
|
||||
match repositories.computed_permission.get_all().await {
|
||||
Ok(all) => registry.set_user_channels(
|
||||
user_id,
|
||||
all.into_iter()
|
||||
.filter(|p| {
|
||||
p.user_id == user_id
|
||||
&& p.scope_type == PermissionScopeType::Channel
|
||||
&& ChannelPermission::from_bits_retain(p.permissions as u64)
|
||||
.contains(ChannelPermission::READ_CHANNEL)
|
||||
})
|
||||
.map(|p| p.resource_id),
|
||||
),
|
||||
Err(error) => {
|
||||
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry")
|
||||
}
|
||||
if let Err(error) = registry.refresh_user(&repositories, user_id).await {
|
||||
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry")
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let registry = Arc::clone(self);
|
||||
event_bus.on_async_with(
|
||||
"channel_user_permission_created",
|
||||
repositories.clone(),
|
||||
move |repositories, (_channel_id, user_id, _permissions): (Uuid, Uuid, u64)| {
|
||||
let registry = Arc::clone(®istry);
|
||||
async move {
|
||||
if let Err(error) = registry.refresh_user(&repositories, user_id).await {
|
||||
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry")
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let registry = Arc::clone(self);
|
||||
event_bus.on_async_with(
|
||||
"channel_user_permission_deleted",
|
||||
repositories.clone(),
|
||||
move |repositories, (_channel_id, user_id): (Uuid, Uuid)| {
|
||||
let registry = Arc::clone(®istry);
|
||||
async move {
|
||||
if let Err(error) = registry.refresh_user(&repositories, user_id).await {
|
||||
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry")
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -176,18 +253,8 @@ impl RealtimeRegistry {
|
||||
move |repositories, (_server_id, user_id): (Uuid, Uuid)| {
|
||||
let registry = Arc::clone(®istry);
|
||||
async move {
|
||||
if let Ok(all) = repositories.computed_permission.get_all().await {
|
||||
registry.set_user_channels(
|
||||
user_id,
|
||||
all.into_iter()
|
||||
.filter(|p| {
|
||||
p.user_id == user_id
|
||||
&& p.scope_type == PermissionScopeType::Channel
|
||||
&& ChannelPermission::from_bits_retain(p.permissions as u64)
|
||||
.contains(ChannelPermission::READ_CHANNEL)
|
||||
})
|
||||
.map(|p| p.resource_id),
|
||||
);
|
||||
if let Err(error) = registry.refresh_user(&repositories, user_id).await {
|
||||
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry")
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -210,8 +277,22 @@ mod tests {
|
||||
registry.set_channel_users(channel_id, [first, second]);
|
||||
|
||||
assert_eq!(registry.users_for_channel(channel_id).len(), 2);
|
||||
assert!(registry.user_channels.read().get(&first).unwrap().contains(&channel_id));
|
||||
assert!(registry.user_channels.read().get(&second).unwrap().contains(&channel_id));
|
||||
assert!(
|
||||
registry
|
||||
.user_channels
|
||||
.read()
|
||||
.get(&first)
|
||||
.unwrap()
|
||||
.contains(&channel_id)
|
||||
);
|
||||
assert!(
|
||||
registry
|
||||
.user_channels
|
||||
.read()
|
||||
.get(&second)
|
||||
.unwrap()
|
||||
.contains(&channel_id)
|
||||
);
|
||||
|
||||
registry.set_channel_users(channel_id, [second]);
|
||||
assert!(!registry.user_channels.read().contains_key(&first));
|
||||
|
||||
Reference in New Issue
Block a user