Skip to content

Commit

Permalink
perf: Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
abdulrahman1s committed Jul 17, 2022
1 parent e535868 commit c7ded36
Show file tree
Hide file tree
Showing 41 changed files with 225 additions and 293 deletions.
2 changes: 1 addition & 1 deletion .gitpod.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
tasks:
- init: make dev
command: cargo test
command: make test
vscode:
extensions:
- streetsidesoftware.code-spell-checker
Expand Down
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ futures = "0.3"
ctor = "0.1.22"
rs-snowflake = "0.6.0"
chrono = { version = "0.4.19", features = ["serde"] }

inter-struct = "0.2.0"

# Docs
opg = { git = "https://github.com/abdulrahman1s/opg", rev = "24f72e7cf09da7cd61b71aedaa14383502559612" }
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
start:
cargo run

test:
cargo test -- -Z unstable-options --report-time

dev:
docker run -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres
docker run -p 6379:6379 -d eqalpha/keydb
79 changes: 43 additions & 36 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
use std::env;

fn is_true(mut v: String) -> bool {
v = v.to_lowercase();
v == "true" || v == "yes"
macro_rules! config {
($($name:ident $t:tt $($default:expr)?),+) => {
lazy_static! {
$(
pub static ref $name: $t = std::env::var(stringify!($name))
.unwrap_or_else(|_| {
$( if true { return $default.to_string(); } )?
panic!("{} is required", stringify!($name));
})
.parse::<$t>()
.unwrap();
)+
}
};
}

macro_rules! get {
($key:expr) => {{
env::var($key).expect(&format!("{} is required", $key))
}};
($key:expr, $default: expr) => {{
env::var($key).unwrap_or($default.to_string())
}};
}
config! {
// Networking
PORT u32 8080,
TRUST_CLOUDFLARE bool false,

// Database
DATABASE_URI String "postgres://postgres:postgres@localhost",
REDIS_URI String "redis://localhost:6379",
REDIS_POOL_SIZE usize 100,
DATABASE_POOL_SIZE u32 100,

// Captcha
CAPTCHA_ENABLED bool false,
CAPTCHA_TOKEN String,
CAPTCHA_KEY String,

lazy_static! {
pub static ref DATABASE_URI: String = get!("DATABASE_URI", "postgres://postgres:postgres@localhost:5432");
pub static ref REDIS_URI: String = get!("REDIS_URI", "redis://localhost:6379");
pub static ref REDIS_POOL_SIZE: usize = get!("REDIS_POOL_SIZE", "100").parse().unwrap();
pub static ref CAPTCHA_ENABLED: bool = is_true(get!("CAPTCHA_ENABLED", "false"));
pub static ref CAPTCHA_TOKEN: String = get!("CAPTCHA_TOKEN");
pub static ref CAPTCHA_KEY: String = get!("CAPTCHA_KEY");
pub static ref PORT: String = get!("PORT", "8080");
pub static ref EMAIL_VERIFICATION: bool = is_true(get!("EMAIL_VERIFICATION", "false"));
pub static ref REQUIRE_INVITE_TO_REGISTER: bool =
is_true(get!("REQUIRE_INVITE_TO_REGISTER", "false"));
pub static ref SENDINBLUE_API_KEY: String = get!("SENDINBLUE_API_KEY");
pub static ref TRUST_CLOUDFLARE: bool = is_true(get!("TRUST_CLOUDFLARE", "false"));
// Email
SENDINBLUE_API_KEY String,
EMAIL_VERIFICATION bool false,
REQUIRE_INVITE_TO_REGISTER bool false,

// User related
pub static ref MAX_FRIENDS: u64 = get!("MAX_FRIENDS", "1000").parse().unwrap();
pub static ref MAX_BLOCKED: u64 = get!("MAX_BLOCKED", "1000").parse().unwrap();
pub static ref MAX_FRIEND_REQUESTS: u64 = get!("MAX_FRIEND_REQUESTS", "100").parse().unwrap();
MAX_FRIENDS u64 1000,
MAX_BLOCKED u64 1000,
MAX_FRIEND_REQUESTS u64 100,

// Group related
pub static ref MAX_GROUPS: u64 = get!("MAX_GROUPS", "100").parse().unwrap();
pub static ref MAX_GROUP_MEMBERS: u64 = get!("MAX_GROUP_MEMBERS", "50").parse().unwrap();
MAX_GROUPS u64 100,
MAX_GROUP_MEMBERS u64 50,

// Server related
pub static ref MAX_SERVERS: u64 = get!("MAX_SERVERS", "100").parse().unwrap();
pub static ref MAX_SERVER_MEMBERS: u64 = get!("MAX_SERVER_MEMBERS", "10000").parse().unwrap();
pub static ref MAX_SERVER_CHANNELS: u64 = get!("MAX_SERVER_CHANNELS", "200").parse().unwrap();
pub static ref MAX_SERVER_ROLES: u64 = get!("MAX_SERVER_ROLES", "200").parse().unwrap();
pub static ref MAX_SERVER_EMOJIS: u64 = get!("MAX_SERVER_EMOJIS", "150").parse().unwrap();
MAX_SERVERS u64 100,
MAX_SERVER_MEMBERS u64 10000,
MAX_SERVER_CHANNELS u64 100,
MAX_SERVER_ROLES u64 100,
MAX_SERVER_EMOJIS u64 150
}
10 changes: 5 additions & 5 deletions src/database/postgres.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::config::DATABASE_URI;
use crate::config::*;
use once_cell::sync::OnceCell;
use sqlx::{postgres::PgPoolOptions, Pool, Postgres};

static DB: OnceCell<Pool<Postgres>> = OnceCell::new();
static POOL: OnceCell<Pool<Postgres>> = OnceCell::new();

pub async fn connect() {
let pool = PgPoolOptions::new()
.max_connections(100)
.max_connections(*DATABASE_POOL_SIZE)
.connect(&*DATABASE_URI)
.await
.expect("Couldn't connect to database");
Expand All @@ -18,9 +18,9 @@ pub async fn connect() {
.await
.expect("Failed to run the migration");

DB.set(pool).unwrap();
POOL.set(pool).unwrap();
}

pub fn pool() -> &'static Pool<Postgres> {
DB.get().unwrap()
POOL.get().unwrap()
}
4 changes: 2 additions & 2 deletions src/database/redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ mod tests {
let value: String = REDIS.get("hello").await.unwrap();

assert_eq!(value, "world");
})
});
}

#[test]
Expand Down Expand Up @@ -86,6 +86,6 @@ mod tests {
let value: String = REDIS.get("hello").await.unwrap();

assert_eq!(value, "world");
})
});
}
}
10 changes: 6 additions & 4 deletions src/gateway/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use futures::{
use std::{collections::HashMap, sync::Arc};
use tokio::sync::Mutex;

lazy_static! {
static ref DEFAULT_PERMISSION: Permissions = Permissions::all();
}

pub struct Client {
pub permissions: Mutex<HashMap<i64, Permissions>>,
pub user: Mutex<Option<User>>,
Expand Down Expand Up @@ -42,15 +46,13 @@ impl Client {

let payload: Payload = serde_json::from_str(&payload.as_string().unwrap()).unwrap();
let mut permissions = self.permissions.lock().await;
let p = permissions
.get(&target_id)
.unwrap_or(&Permissions::ADMINISTRATOR);
let p = permissions.get(&target_id).unwrap_or(&DEFAULT_PERMISSION);

match &payload {
Payload::MessageCreate(_)
| Payload::MessageUpdate(_)
| Payload::MessageDelete(_) => {
if p.has(Permissions::VIEW_CHANNEL).is_err() {
if !p.contains(Permissions::VIEW_CHANNEL) {
continue;
}
}
Expand Down
27 changes: 19 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ use std::net::SocketAddr;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
env_logger::builder().format_timestamp(None).init();

env_logger::Builder::from_env(env_logger::Env::default().filter_or("RUST_LOG", "info"))
.format_timestamp(None)
.init();

log::info!("Connecting to database...");
database::postgres::connect().await;
Expand All @@ -49,22 +52,30 @@ async fn main() {
.unwrap();
}

#[cfg(test)]
pub mod tests {
use super::*;
use log::LevelFilter;
use once_cell::sync::Lazy;
use tokio::runtime::{Builder, Runtime};

static RUNTIME: Lazy<Runtime> =
Lazy::new(|| Builder::new_multi_thread().enable_all().build().unwrap());

pub fn run<F: std::future::Future>(f: F) -> F::Output {
static RT: Lazy<Runtime> =
Lazy::new(|| Builder::new_multi_thread().enable_all().build().unwrap());
RT.block_on(f)
RUNTIME.block_on(f)
}

#[cfg(test)]
#[ctor::ctor]
fn setup() {
dotenv::dotenv().ok();
env_logger::builder().format_timestamp(None).try_init().ok();
run(super::database::postgres::connect());
run(super::database::redis::connect());

env_logger::builder()
.filter_level(LevelFilter::Trace)
.format_timestamp(None)
.init();

run(database::postgres::connect());
run(database::redis::connect());
}
}
2 changes: 0 additions & 2 deletions src/routes/auth/sessions/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ mod tests {
)
.await
.unwrap();

session.cleanup().await.unwrap();
})
}
}
2 changes: 0 additions & 2 deletions src/routes/auth/sessions/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ mod tests {
assert_eq!(results.0.len(), 1);

fetch_one(Extension(user), Path(session.id)).await.unwrap();

session.cleanup().await.unwrap();
})
}
}
2 changes: 1 addition & 1 deletion src/routes/channels/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub async fn delete(Extension(user): Extension<User>, Path(id): Path<i64>) -> Re
let channel = id.channel(user.id.into()).await?;

if channel.owner_id != Some(user.id) {
return Err(Error::MissingPermissions);
return Err(Error::MissingAccess);
}

channel.remove().await?;
Expand Down
14 changes: 7 additions & 7 deletions src/routes/channels/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use crate::extractors::*;
use crate::gateway::*;
use crate::structures::*;
use crate::utils::*;
use inter_struct::prelude::*;
use serde::Deserialize;
use validator::Validate;

#[derive(Deserialize, Validate, OpgModel)]
#[derive(Deserialize, Validate, OpgModel, StructMerge)]
#[struct_merge("crate::structures::channel::Channel")]
pub struct EditGroupOptions {
#[validate(length(min = 3, max = 32))]
name: Option<String>,
Expand All @@ -18,13 +20,11 @@ pub async fn edit(
) -> Result<Json<Channel>> {
let mut group = id.channel(user.id.into()).await?;

let permissions = Permissions::fetch(&user, None, group.id.into()).await?;
Permissions::fetch(&user, None, group.id.into())
.await?
.has(&[Permissions::MANAGE_CHANNELS])?;

permissions.has(Permissions::MANAGE_CHANNELS)?;

if let Some(name) = data.name {
group.name = name.into();
}
group.merge(data);

let group = group.update_all_fields(pool()).await?;

Expand Down
5 changes: 3 additions & 2 deletions src/routes/channels/kick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ pub async fn kick(
) -> Result<()> {
let target = target_id.user().await?;
let mut group = group_id.channel(user.id.into()).await?;
let permissions = Permissions::fetch(&user, None, group.id.into()).await?;

permissions.has(Permissions::KICK_MEMBERS)?;
Permissions::fetch_cached(&user, None, Some(&group))
.await?
.has(&[Permissions::KICK_MEMBERS])?;

if let Some(recipients) = group.recipients.as_mut() {
let exists = recipients
Expand Down
2 changes: 1 addition & 1 deletion src/routes/invites/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub async fn create(

Permissions::fetch(&user, channel.server_id, channel.id.into())
.await?
.has(Permissions::INVITE_OTHERS)?;
.has(&[Permissions::INVITE_OTHERS])?;

let invite = Invite::new(user.id, channel.id, channel.server_id);

Expand Down
7 changes: 3 additions & 4 deletions src/routes/messages/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ pub async fn create(
ValidatedJson(data): ValidatedJson<CreateMessageOptions>,
Path(channel_id): Path<i64>,
) -> Result<Json<Message>> {
let permissions = Permissions::fetch(&user, None, channel_id.into()).await?;

permissions.has(Permissions::VIEW_CHANNEL)?;
permissions.has(Permissions::SEND_MESSAGES)?;
Permissions::fetch(&user, None, channel_id.into())
.await?
.has(&[Permissions::VIEW_CHANNEL, Permissions::SEND_MESSAGES])?;

let mut msg = Message::new(channel_id, user.id);

Expand Down
8 changes: 4 additions & 4 deletions src/routes/messages/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ pub async fn delete(
Path((channel_id, id)): Path<(i64, i64)>,
) -> Result<()> {
let msg = id.message().await?;
let permissions = Permissions::fetch(&user, None, channel_id.into()).await?;

permissions.has(Permissions::VIEW_CHANNEL)?;
let p = Permissions::fetch(&user, None, channel_id.into()).await?;

if msg.author_id != user.id {
permissions.has(Permissions::MANAGE_MESSAGES)?;
p.has(&[Permissions::MANAGE_MESSAGES])?;
} else {
p.has(&[Permissions::MANAGE_MESSAGES, Permissions::VIEW_CHANNEL])?;
}

let attachment_ids: Vec<i64> = msg
Expand Down
Loading

0 comments on commit c7ded36

Please sign in to comment.