Add caching for members, rewrite part of perms.
This commit is contained in:
@@ -179,8 +179,8 @@ pub fn process_event(event: &Notification) {
|
|||||||
owner: None,
|
owner: None,
|
||||||
guild: Some(ev.id.clone()),
|
guild: Some(ev.id.clone()),
|
||||||
name: Some(ev.name.clone()),
|
name: Some(ev.name.clone()),
|
||||||
description: Some(ev.description.clone())
|
description: Some(ev.description.clone()),
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Notification::guild_channel_delete(ev) => {
|
Notification::guild_channel_delete(ev) => {
|
||||||
|
|||||||
@@ -48,9 +48,14 @@ pub struct Guild {
|
|||||||
pub default_permissions: u32,
|
pub default_permissions: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq)]
|
||||||
|
pub struct MemberKey(pub String, pub String);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref CACHE: Arc<Mutex<LruCache<String, Guild>>> =
|
static ref CACHE: Arc<Mutex<LruCache<String, Guild>>> =
|
||||||
Arc::new(Mutex::new(LruCache::new(4_000_000)));
|
Arc::new(Mutex::new(LruCache::new(4_000_000)));
|
||||||
|
static ref MEMBER_CACHE: Arc<Mutex<LruCache<MemberKey, Member>>> =
|
||||||
|
Arc::new(Mutex::new(LruCache::new(4_000_000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_guild(id: &str) -> Result<Option<Guild>, String> {
|
pub fn fetch_guild(id: &str) -> Result<Option<Guild>, String> {
|
||||||
@@ -85,6 +90,44 @@ pub fn fetch_guild(id: &str) -> Result<Option<Guild>, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fetch_member(key: MemberKey) -> Result<Option<Member>, String> {
|
||||||
|
{
|
||||||
|
if let Ok(mut cache) = MEMBER_CACHE.lock() {
|
||||||
|
let existing = cache.get(&key);
|
||||||
|
|
||||||
|
if let Some(member) = existing {
|
||||||
|
return Ok(Some((*member).clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err("Failed to lock cache.".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let col = get_collection("members");
|
||||||
|
if let Ok(result) = col.find_one(
|
||||||
|
doc! {
|
||||||
|
"_id.guild": &key.0,
|
||||||
|
"_id.user": &key.1,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
if let Some(doc) = result {
|
||||||
|
if let Ok(member) = from_bson(Bson::Document(doc)) as Result<Member, _> {
|
||||||
|
let mut cache = MEMBER_CACHE.lock().unwrap();
|
||||||
|
cache.put(key, member.clone());
|
||||||
|
|
||||||
|
Ok(Some(member))
|
||||||
|
} else {
|
||||||
|
Err("Failed to deserialize member!".to_string())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("Failed to fetch member from database.".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for Guild {
|
impl<'r> FromParam<'r> for Guild {
|
||||||
type Error = &'r RawStr;
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
@@ -101,24 +144,6 @@ impl<'r> FromParam<'r> for Guild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_member(guild_id: &String, member: &String) -> Option<Member> {
|
|
||||||
if let Ok(result) = get_collection("members").find_one(
|
|
||||||
doc! {
|
|
||||||
"_id.guild": &guild_id,
|
|
||||||
"_id.user": &member,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
) {
|
|
||||||
if let Some(doc) = result {
|
|
||||||
Some(from_bson(Bson::Document(doc)).expect("Failed to unwrap member."))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_invite<U: Into<Option<String>>>(
|
pub fn get_invite<U: Into<Option<String>>>(
|
||||||
code: &String,
|
code: &String,
|
||||||
user: U,
|
user: U,
|
||||||
@@ -176,3 +201,60 @@ pub fn get_invite<U: Into<Option<String>>>(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::notifications::events::Notification;
|
||||||
|
|
||||||
|
pub fn process_event(event: &Notification) {
|
||||||
|
match event {
|
||||||
|
Notification::guild_channel_create(ev) => {} // ? for later use
|
||||||
|
Notification::guild_channel_create(ev) => {} // ? for later use
|
||||||
|
Notification::guild_delete(ev) => {}
|
||||||
|
Notification::guild_user_join(ev) => {}
|
||||||
|
Notification::guild_user_leave(ev) => {}
|
||||||
|
/*Notification::group_user_join(ev) => {
|
||||||
|
let mut cache = CACHE.lock().unwrap();
|
||||||
|
let entry = cache.pop(&ev.id);
|
||||||
|
|
||||||
|
if entry.is_some() {
|
||||||
|
let mut channel = entry.unwrap();
|
||||||
|
channel.recipients.as_mut().unwrap().push(ev.user.clone());
|
||||||
|
cache.put(ev.id.clone(), channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Notification::group_user_leave(ev) => {
|
||||||
|
let mut cache = CACHE.lock().unwrap();
|
||||||
|
let entry = cache.pop(&ev.id);
|
||||||
|
|
||||||
|
if entry.is_some() {
|
||||||
|
let mut channel = entry.unwrap();
|
||||||
|
let recipients = channel.recipients.as_mut().unwrap();
|
||||||
|
if let Some(pos) = recipients.iter().position(|x| *x == ev.user) {
|
||||||
|
recipients.remove(pos);
|
||||||
|
}
|
||||||
|
cache.put(ev.id.clone(), channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Notification::guild_channel_create(ev) => {
|
||||||
|
let mut cache = CACHE.lock().unwrap();
|
||||||
|
cache.put(
|
||||||
|
ev.id.clone(),
|
||||||
|
Channel {
|
||||||
|
id: ev.channel.clone(),
|
||||||
|
channel_type: 2,
|
||||||
|
active: None,
|
||||||
|
last_message: None,
|
||||||
|
recipients: None,
|
||||||
|
owner: None,
|
||||||
|
guild: Some(ev.id.clone()),
|
||||||
|
name: Some(ev.name.clone()),
|
||||||
|
description: Some(ev.description.clone())
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Notification::guild_channel_delete(ev) => {
|
||||||
|
let mut cache = CACHE.lock().unwrap();
|
||||||
|
cache.pop(&ev.channel);
|
||||||
|
}*/
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::mutual::has_mutual_connection;
|
use super::mutual::has_mutual_connection;
|
||||||
use crate::database::channel::Channel;
|
use crate::database::channel::Channel;
|
||||||
use crate::database::guild::{fetch_guild, get_member, Guild, Member};
|
use crate::database::guild::{fetch_guild, fetch_member, Guild, Member, MemberKey};
|
||||||
use crate::database::user::UserRelationship;
|
use crate::database::user::UserRelationship;
|
||||||
use crate::guards::auth::UserRef;
|
use crate::guards::auth::UserRef;
|
||||||
|
|
||||||
@@ -140,7 +140,9 @@ impl PermissionCalculator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(guild) = &guild {
|
if let Some(guild) = &guild {
|
||||||
self.member = get_member(&guild.id, &self.user.id);
|
if let Ok(result) = fetch_member(MemberKey(guild.id.clone(), self.user.id.clone())) {
|
||||||
|
self.member = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.guild = guild;
|
self.guild = guild;
|
||||||
@@ -164,21 +166,17 @@ impl PermissionCalculator {
|
|||||||
match channel.channel_type {
|
match channel.channel_type {
|
||||||
0 => {
|
0 => {
|
||||||
if let Some(arr) = &channel.recipients {
|
if let Some(arr) = &channel.recipients {
|
||||||
let mut other_user = "";
|
let mut other_user = None;
|
||||||
for item in arr {
|
for item in arr {
|
||||||
if item != &self.user.id {
|
if item != &self.user.id {
|
||||||
other_user = item;
|
other_user = Some(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ? In this case, it is a "self DM".
|
if let Some(other) = other_user {
|
||||||
if other_user == "" {
|
|
||||||
return 1024 + 128 + 32 + 16 + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let relationships = self.user.fetch_relationships();
|
let relationships = self.user.fetch_relationships();
|
||||||
let relationship =
|
let relationship =
|
||||||
get_relationship_internal(&self.user.id, &other_user, &relationships);
|
get_relationship_internal(&self.user.id, &other, &relationships);
|
||||||
|
|
||||||
if relationship == Relationship::Friend {
|
if relationship == Relationship::Friend {
|
||||||
permissions = 1024 + 128 + 32 + 16 + 1;
|
permissions = 1024 + 128 + 32 + 16 + 1;
|
||||||
@@ -186,11 +184,15 @@ impl PermissionCalculator {
|
|||||||
|| relationship == Relationship::BlockedOther
|
|| relationship == Relationship::BlockedOther
|
||||||
{
|
{
|
||||||
permissions = 1;
|
permissions = 1;
|
||||||
} else if has_mutual_connection(&self.user.id, other_user, true) {
|
} else if has_mutual_connection(&self.user.id, other, true) {
|
||||||
permissions = 1024 + 128 + 32 + 16 + 1;
|
permissions = 1024 + 128 + 32 + 16 + 1;
|
||||||
} else {
|
} else {
|
||||||
permissions = 1;
|
permissions = 1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// ? In this case, it is a "self DM".
|
||||||
|
return 1024 + 128 + 32 + 16 + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
use mongodb::bson::{doc, from_bson, Bson, Document};
|
|
||||||
use mongodb::options::FindOneOptions;
|
|
||||||
use rocket::http::RawStr;
|
|
||||||
use rocket::request::FromParam;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::database;
|
|
||||||
use crate::database::guild::{Ban, Invite, Member};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct GuildRef {
|
|
||||||
#[serde(rename = "_id")]
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub owner: String,
|
|
||||||
|
|
||||||
pub bans: Vec<Ban>,
|
|
||||||
|
|
||||||
pub default_permissions: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GuildRef {
|
|
||||||
pub fn from(id: String) -> Option<GuildRef> {
|
|
||||||
match database::get_collection("guilds").find_one(
|
|
||||||
doc! { "_id": id },
|
|
||||||
FindOneOptions::builder()
|
|
||||||
.projection(doc! {
|
|
||||||
"name": 1,
|
|
||||||
"description": 1,
|
|
||||||
"owner": 1,
|
|
||||||
"bans": 1,
|
|
||||||
"default_permissions": 1
|
|
||||||
})
|
|
||||||
.build(),
|
|
||||||
) {
|
|
||||||
Ok(result) => match result {
|
|
||||||
Some(doc) => {
|
|
||||||
Some(from_bson(mongodb::bson::mongodb::bson::Document(doc)).expect("Failed to unwrap guild."))
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetch_data(&self, projection: Document) -> Option<Document> {
|
|
||||||
database::get_collection("guilds")
|
|
||||||
.find_one(
|
|
||||||
doc! { "_id": &self.id },
|
|
||||||
FindOneOptions::builder().projection(projection).build(),
|
|
||||||
)
|
|
||||||
.expect("Failed to fetch guild from database.")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetch_data_given(&self, mut filter: Document, projection: Document) -> Option<Document> {
|
|
||||||
filter.insert("_id", self.id.clone());
|
|
||||||
database::get_collection("guilds")
|
|
||||||
.find_one(
|
|
||||||
filter,
|
|
||||||
FindOneOptions::builder().projection(projection).build(),
|
|
||||||
)
|
|
||||||
.expect("Failed to fetch guild from database.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for GuildRef {
|
|
||||||
type Error = &'r RawStr;
|
|
||||||
|
|
||||||
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
|
||||||
if let Some(guild) = GuildRef::from(param.to_string()) {
|
|
||||||
Ok(guild)
|
|
||||||
} else {
|
|
||||||
Err(param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_member(guild_id: &String, member: &String) -> Option<Member> {
|
|
||||||
if let Ok(result) = database::get_collection("members").find_one(
|
|
||||||
doc! {
|
|
||||||
"_id.guild": &guild_id,
|
|
||||||
"_id.user": &member,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
) {
|
|
||||||
if let Some(doc) = result {
|
|
||||||
Some(from_bson(mongodb::bson::Document(doc)).expect("Failed to unwrap member."))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_invite<U: Into<Option<String>>>(
|
|
||||||
code: &String,
|
|
||||||
user: U,
|
|
||||||
) -> Option<(String, String, Invite)> {
|
|
||||||
let mut doc = doc! {
|
|
||||||
"invites": {
|
|
||||||
"$elemMatch": {
|
|
||||||
"code": &code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(user_id) = user.into() {
|
|
||||||
doc.insert(
|
|
||||||
"bans",
|
|
||||||
doc! {
|
|
||||||
"$not": {
|
|
||||||
"$elemMatch": {
|
|
||||||
"id": user_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(result) = database::get_collection("guilds").find_one(
|
|
||||||
doc,
|
|
||||||
FindOneOptions::builder()
|
|
||||||
.projection(doc! {
|
|
||||||
"_id": 1,
|
|
||||||
"name": 1,
|
|
||||||
"invites.$": 1,
|
|
||||||
})
|
|
||||||
.build(),
|
|
||||||
) {
|
|
||||||
if let Some(doc) = result {
|
|
||||||
let invite = doc
|
|
||||||
.get_array("invites")
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.as_document()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Some((
|
|
||||||
doc.get_str("_id").unwrap().to_string(),
|
|
||||||
doc.get_str("name").unwrap().to_string(),
|
|
||||||
from_bson(mongodb::bson::Document(invite.clone())).unwrap(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::channel::ChannelType;
|
use super::channel::ChannelType;
|
||||||
use super::Response;
|
use super::Response;
|
||||||
use crate::database::guild::{get_invite, get_member, Guild};
|
use crate::database::guild::{fetch_member as get_member, get_invite, Guild, MemberKey};
|
||||||
use crate::database::{
|
use crate::database::{
|
||||||
self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator,
|
self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator,
|
||||||
};
|
};
|
||||||
@@ -641,11 +641,17 @@ pub fn fetch_members(user: UserRef, target: Guild) -> Option<Response> {
|
|||||||
pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Response> {
|
pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Response> {
|
||||||
with_permissions!(user, target);
|
with_permissions!(user, target);
|
||||||
|
|
||||||
if let Some(member) = get_member(&target.id, &other) {
|
if let Ok(result) = get_member(MemberKey(target.id, user.id)) {
|
||||||
|
if let Some(member) = result {
|
||||||
Some(Response::Success(json!({
|
Some(Response::Success(json!({
|
||||||
"id": member.id.user,
|
"id": member.id.user,
|
||||||
"nickname": member.nickname,
|
"nickname": member.nickname,
|
||||||
})))
|
})))
|
||||||
|
} else {
|
||||||
|
Some(Response::NotFound(
|
||||||
|
json!({ "error": "Member does not exist!" }),
|
||||||
|
))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(Response::InternalServerError(
|
Some(Response::InternalServerError(
|
||||||
json!({ "error": "Failed to fetch member or user does not exist." }),
|
json!({ "error": "Failed to fetch member or user does not exist." }),
|
||||||
@@ -668,11 +674,15 @@ pub fn kick_member(user: UserRef, target: Guild, other: String) -> Option<Respon
|
|||||||
return Some(Response::LackingPermission(Permission::KickMembers));
|
return Some(Response::LackingPermission(Permission::KickMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_member(&target.id, &other).is_none() {
|
if let Ok(result) = get_member(MemberKey( target.id.clone(), other.clone() )) {
|
||||||
|
if result.is_none() {
|
||||||
return Some(Response::BadRequest(
|
return Some(Response::BadRequest(
|
||||||
json!({ "error": "User not part of guild." }),
|
json!({ "error": "User not part of guild." }),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Some(Response::InternalServerError(json!({ "error": "Failed to fetch member." })))
|
||||||
|
}
|
||||||
|
|
||||||
if database::get_collection("members")
|
if database::get_collection("members")
|
||||||
.delete_one(
|
.delete_one(
|
||||||
@@ -734,11 +744,15 @@ pub fn ban_member(
|
|||||||
return Some(Response::LackingPermission(Permission::BanMembers));
|
return Some(Response::LackingPermission(Permission::BanMembers));
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_member(&target.id, &other).is_none() {
|
if let Ok(result) = get_member(MemberKey( target.id.clone(), other.clone() )) {
|
||||||
|
if result.is_none() {
|
||||||
return Some(Response::BadRequest(
|
return Some(Response::BadRequest(
|
||||||
json!({ "error": "User not part of guild." }),
|
json!({ "error": "User not part of guild." }),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Some(Response::InternalServerError(json!({ "error": "Failed to fetch member." })))
|
||||||
|
}
|
||||||
|
|
||||||
if database::get_collection("guilds")
|
if database::get_collection("guilds")
|
||||||
.update_one(
|
.update_one(
|
||||||
|
|||||||
Reference in New Issue
Block a user