Compare commits
12
Commits
20240619-1
...
20240625-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac20b6bc99 | ||
|
|
6ec8007e4e | ||
|
|
e5eea267cf | ||
|
|
de5add09d0 | ||
|
|
1ec8f46c1d | ||
|
|
80666848cc | ||
|
|
e8e9613169 | ||
|
|
eda36436a8 | ||
|
|
93e05e9f18 | ||
|
|
090d8cba71 | ||
|
|
f16e72e329 | ||
|
|
8248a4a5b8 |
No files matched your search
Generated
+8
-8
@@ -3452,7 +3452,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.3.1",
|
"async-channel 2.3.1",
|
||||||
"async-std",
|
"async-std",
|
||||||
@@ -3482,7 +3482,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"cached",
|
"cached",
|
||||||
@@ -3498,7 +3498,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
@@ -3544,7 +3544,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 1.6.1",
|
"async-channel 1.6.1",
|
||||||
"async-std",
|
"async-std",
|
||||||
@@ -3590,7 +3590,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"iso8601-timestamp 0.2.11",
|
"iso8601-timestamp 0.2.11",
|
||||||
@@ -3607,7 +3607,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3622,7 +3622,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"log",
|
"log",
|
||||||
@@ -3633,7 +3633,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"revolt_okapi",
|
"revolt_okapi",
|
||||||
"revolt_rocket_okapi",
|
"revolt_rocket_okapi",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" }
|
|||||||
revolt-models = { path = "../core/models" }
|
revolt-models = { path = "../core/models" }
|
||||||
revolt-config = { path = "../core/config" }
|
revolt-config = { path = "../core/config" }
|
||||||
revolt-database = { path = "../core/database" }
|
revolt-database = { path = "../core/database" }
|
||||||
revolt-permissions = { version = "0.7.6", path = "../core/permissions" }
|
revolt-permissions = { version = "0.7.10", path = "../core/permissions" }
|
||||||
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
||||||
|
|
||||||
# redis
|
# redis
|
||||||
|
|||||||
+134
-31
@@ -3,12 +3,13 @@ use std::{collections::HashSet, net::SocketAddr, sync::Arc};
|
|||||||
use async_tungstenite::WebSocketStream;
|
use async_tungstenite::WebSocketStream;
|
||||||
use authifier::AuthifierEvent;
|
use authifier::AuthifierEvent;
|
||||||
use fred::{
|
use fred::{
|
||||||
|
error::{RedisError, RedisErrorKind},
|
||||||
interfaces::{ClientLike, EventInterface, PubsubInterface},
|
interfaces::{ClientLike, EventInterface, PubsubInterface},
|
||||||
types::RedisConfig,
|
types::RedisConfig,
|
||||||
};
|
};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::oneshot,
|
channel::oneshot,
|
||||||
pin_mut, select,
|
join, pin_mut, select,
|
||||||
stream::{SplitSink, SplitStream},
|
stream::{SplitSink, SplitStream},
|
||||||
FutureExt, SinkExt, StreamExt, TryStreamExt,
|
FutureExt, SinkExt, StreamExt, TryStreamExt,
|
||||||
};
|
};
|
||||||
@@ -22,6 +23,7 @@ use revolt_presence::{create_session, delete_session};
|
|||||||
use async_std::{
|
use async_std::{
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
sync::{Mutex, RwLock},
|
sync::{Mutex, RwLock},
|
||||||
|
task::spawn,
|
||||||
};
|
};
|
||||||
use revolt_result::create_error;
|
use revolt_result::create_error;
|
||||||
use sentry::Level;
|
use sentry::Level;
|
||||||
@@ -127,34 +129,44 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// Setup channels and mutexes
|
||||||
let write = Mutex::new(write);
|
let write = Mutex::new(write);
|
||||||
let subscribed = state.subscribed.clone();
|
let subscribed = state.subscribed.clone();
|
||||||
let active_servers = state.active_servers.clone();
|
let active_servers = state.active_servers.clone();
|
||||||
let (signal_s, signal_r) = async_channel::unbounded();
|
let (topic_signal_s, topic_signal_r) = async_channel::unbounded();
|
||||||
|
|
||||||
|
// TODO: this needs to be rewritten
|
||||||
|
// Create channels through which the tasks can signal to each other they need to clean up
|
||||||
|
let (kill_signal_1_s, kill_signal_1_r) = async_channel::bounded(1);
|
||||||
|
let (kill_signal_2_s, kill_signal_2_r) = async_channel::bounded(1);
|
||||||
|
|
||||||
// Create a PubSub connection to poll on.
|
// Create a PubSub connection to poll on.
|
||||||
let listener = listener(db, &mut state, addr, &config, signal_r, &write).fuse();
|
let listener = listener_with_kill_signal(
|
||||||
|
db,
|
||||||
|
&mut state,
|
||||||
|
addr,
|
||||||
|
&config,
|
||||||
|
topic_signal_r,
|
||||||
|
kill_signal_1_r,
|
||||||
|
&write,
|
||||||
|
kill_signal_2_s,
|
||||||
|
);
|
||||||
|
|
||||||
// Read from WebSocket stream.
|
// Read from WebSocket stream.
|
||||||
let worker = worker(
|
let worker = worker_with_kill_signal(
|
||||||
addr,
|
addr,
|
||||||
subscribed,
|
subscribed,
|
||||||
active_servers,
|
active_servers,
|
||||||
user_id.clone(),
|
user_id.clone(),
|
||||||
&config,
|
&config,
|
||||||
signal_s,
|
topic_signal_s,
|
||||||
|
kill_signal_2_r,
|
||||||
read,
|
read,
|
||||||
&write,
|
&write,
|
||||||
)
|
kill_signal_1_s,
|
||||||
.fuse();
|
|
||||||
|
|
||||||
// Pin both tasks.
|
|
||||||
pin_mut!(listener, worker);
|
|
||||||
|
|
||||||
// Wait for either disconnect or for listener to die.
|
|
||||||
select!(
|
|
||||||
() = listener => {},
|
|
||||||
() = worker => {}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
join!(listener, worker);
|
||||||
}
|
}
|
||||||
// Clean up presence session.
|
// Clean up presence session.
|
||||||
let last_session = delete_session(&user_id, session_id).await;
|
let last_session = delete_session(&user_id, session_id).await;
|
||||||
@@ -165,16 +177,40 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn listener_with_kill_signal(
|
||||||
|
db: &'static Database,
|
||||||
|
state: &mut State,
|
||||||
|
addr: SocketAddr,
|
||||||
|
config: &ProtocolConfiguration,
|
||||||
|
topic_signal_r: async_channel::Receiver<()>,
|
||||||
|
kill_signal_r: async_channel::Receiver<()>,
|
||||||
|
write: &Mutex<WsWriter>,
|
||||||
|
kill_signal_s: async_channel::Sender<()>,
|
||||||
|
) {
|
||||||
|
listener(
|
||||||
|
db,
|
||||||
|
state,
|
||||||
|
addr,
|
||||||
|
config,
|
||||||
|
topic_signal_r,
|
||||||
|
kill_signal_r,
|
||||||
|
write,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
kill_signal_s.send(()).await.ok();
|
||||||
|
}
|
||||||
|
|
||||||
async fn listener(
|
async fn listener(
|
||||||
db: &'static Database,
|
db: &'static Database,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
config: &ProtocolConfiguration,
|
config: &ProtocolConfiguration,
|
||||||
signal_r: async_channel::Receiver<()>,
|
topic_signal_r: async_channel::Receiver<()>,
|
||||||
|
kill_signal_r: async_channel::Receiver<()>,
|
||||||
write: &Mutex<WsWriter>,
|
write: &Mutex<WsWriter>,
|
||||||
) {
|
) {
|
||||||
let redis_config = RedisConfig::from_url(&REDIS_URI).unwrap();
|
let redis_config = RedisConfig::from_url(&REDIS_URI).unwrap();
|
||||||
|
|
||||||
let subscriber = match fred::types::Builder::from_config(redis_config).build_subscriber_client()
|
let subscriber = match fred::types::Builder::from_config(redis_config).build_subscriber_client()
|
||||||
{
|
{
|
||||||
Ok(subscriber) => subscriber,
|
Ok(subscriber) => subscriber,
|
||||||
@@ -191,15 +227,29 @@ async fn listener(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle Redis connection dropping
|
||||||
|
let (clean_up_s, clean_up_r) = async_channel::bounded(1);
|
||||||
|
let clean_up_s = Arc::new(Mutex::new(clean_up_s));
|
||||||
|
subscriber.on_error(move |err| {
|
||||||
|
if let RedisErrorKind::Canceled = err.kind() {
|
||||||
|
let clean_up_s = clean_up_s.clone();
|
||||||
|
spawn(async move {
|
||||||
|
clean_up_s.lock().await.send(()).await.ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
let mut message_rx = subscriber.message_rx();
|
let mut message_rx = subscriber.message_rx();
|
||||||
loop {
|
'out: loop {
|
||||||
// Check for state changes for subscriptions.
|
// Check for state changes for subscriptions.
|
||||||
match state.apply_state().await {
|
match state.apply_state().await {
|
||||||
SubscriptionStateChange::Reset => {
|
SubscriptionStateChange::Reset => {
|
||||||
if let Err(err) = subscriber.unsubscribe_all().await {
|
if let Err(err) = subscriber.unsubscribe_all().await {
|
||||||
error!("Unsubscribe all failed: {err:?}");
|
error!("Unsubscribe all failed: {err:?}");
|
||||||
sentry::capture_error(&err);
|
sentry::capture_error(&err);
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
|
|
||||||
let subscribed = state.subscribed.read().await;
|
let subscribed = state.subscribed.read().await;
|
||||||
@@ -207,7 +257,7 @@ async fn listener(
|
|||||||
if let Err(err) = subscriber.subscribe(id).await {
|
if let Err(err) = subscriber.subscribe(id).await {
|
||||||
error!("Subscribe failed: {err:?}");
|
error!("Subscribe failed: {err:?}");
|
||||||
sentry::capture_error(&err);
|
sentry::capture_error(&err);
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +272,7 @@ async fn listener(
|
|||||||
if let Err(err) = subscriber.unsubscribe(id).await {
|
if let Err(err) = subscriber.unsubscribe(id).await {
|
||||||
error!("Unsubscribe failed: {err:?}");
|
error!("Unsubscribe failed: {err:?}");
|
||||||
sentry::capture_error(&err);
|
sentry::capture_error(&err);
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +283,7 @@ async fn listener(
|
|||||||
if let Err(err) = subscriber.subscribe(id).await {
|
if let Err(err) = subscriber.subscribe(id).await {
|
||||||
error!("Subscribe failed: {err:?}");
|
error!("Subscribe failed: {err:?}");
|
||||||
sentry::capture_error(&err);
|
sentry::capture_error(&err);
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,11 +291,19 @@ async fn listener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let t1 = message_rx.recv().fuse();
|
let t1 = message_rx.recv().fuse();
|
||||||
let t2 = signal_r.recv().fuse();
|
let t2 = topic_signal_r.recv().fuse();
|
||||||
|
let t3 = kill_signal_r.recv().fuse();
|
||||||
|
let t4 = clean_up_r.recv().fuse();
|
||||||
|
|
||||||
pin_mut!(t1, t2);
|
pin_mut!(t1, t2, t3, t4);
|
||||||
|
|
||||||
select! {
|
select! {
|
||||||
|
_ = t4 => {
|
||||||
|
break 'out;
|
||||||
|
},
|
||||||
|
_ = t3 => {
|
||||||
|
break 'out;
|
||||||
|
},
|
||||||
_ = t2 => {},
|
_ = t2 => {},
|
||||||
message = t1 => {
|
message = t1 => {
|
||||||
// Handle incoming events.
|
// Handle incoming events.
|
||||||
@@ -254,7 +312,7 @@ async fn listener(
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error while consuming pub/sub messages: {e:?}");
|
error!("Error while consuming pub/sub messages: {e:?}");
|
||||||
sentry::capture_error(&e);
|
sentry::capture_error(&e);
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -285,7 +343,7 @@ async fn listener(
|
|||||||
|
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
sentry::capture_message(&err, Level::Error);
|
sentry::capture_message(&err, Level::Error);
|
||||||
return;
|
break 'out;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let EventV1::Auth(auth) = &event {
|
if let EventV1::Auth(auth) = &event {
|
||||||
@@ -321,16 +379,49 @@ async fn listener(
|
|||||||
sentry::capture_message(&err, Level::Warning);
|
sentry::capture_message(&err, Level::Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let EventV1::Logout = event {
|
if let EventV1::Logout = event {
|
||||||
info!("User {addr:?} received log out event!");
|
info!("User {addr:?} received log out event!");
|
||||||
return;
|
break 'out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(err) = subscriber.quit().await {
|
||||||
|
error!("{}", err);
|
||||||
|
sentry::capture_error(&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn worker_with_kill_signal(
|
||||||
|
addr: SocketAddr,
|
||||||
|
subscribed: Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_servers: Arc<Mutex<lru_time_cache::LruCache<String, ()>>>,
|
||||||
|
user_id: String,
|
||||||
|
config: &ProtocolConfiguration,
|
||||||
|
topic_signal_s: async_channel::Sender<()>,
|
||||||
|
kill_signal_r: async_channel::Receiver<()>,
|
||||||
|
read: WsReader,
|
||||||
|
write: &Mutex<WsWriter>,
|
||||||
|
kill_signal_s: async_channel::Sender<()>,
|
||||||
|
) {
|
||||||
|
worker(
|
||||||
|
addr,
|
||||||
|
subscribed,
|
||||||
|
active_servers,
|
||||||
|
user_id,
|
||||||
|
config,
|
||||||
|
topic_signal_s,
|
||||||
|
kill_signal_r,
|
||||||
|
read,
|
||||||
|
write,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
kill_signal_s.send(()).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@@ -340,12 +431,22 @@ async fn worker(
|
|||||||
active_servers: Arc<Mutex<lru_time_cache::LruCache<String, ()>>>,
|
active_servers: Arc<Mutex<lru_time_cache::LruCache<String, ()>>>,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
config: &ProtocolConfiguration,
|
config: &ProtocolConfiguration,
|
||||||
signal_s: async_channel::Sender<()>,
|
topic_signal_s: async_channel::Sender<()>,
|
||||||
|
kill_signal_r: async_channel::Receiver<()>,
|
||||||
mut read: WsReader,
|
mut read: WsReader,
|
||||||
write: &Mutex<WsWriter>,
|
write: &Mutex<WsWriter>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
let result = read.try_next().await;
|
let t1 = read.try_next().fuse();
|
||||||
|
let t2 = kill_signal_r.recv().fuse();
|
||||||
|
|
||||||
|
pin_mut!(t1, t2);
|
||||||
|
|
||||||
|
select! {
|
||||||
|
_ = t2 => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
result = t1 => {
|
||||||
let msg = match result {
|
let msg = match result {
|
||||||
Ok(Some(msg)) => msg,
|
Ok(Some(msg)) => msg,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
@@ -401,7 +502,7 @@ async fn worker(
|
|||||||
|
|
||||||
if !has_item {
|
if !has_item {
|
||||||
// Poke the listener to adjust subscriptions
|
// Poke the listener to adjust subscriptions
|
||||||
signal_s.send(()).await.ok();
|
topic_signal_s.send(()).await.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientMessage::Ping { data, responded } => {
|
ClientMessage::Ping { data, responded } => {
|
||||||
@@ -417,4 +518,6 @@ async fn worker(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -46,19 +46,40 @@ webhooks_enabled = false
|
|||||||
|
|
||||||
[features.limits]
|
[features.limits]
|
||||||
|
|
||||||
[features.limits.default]
|
[features.limits.global]
|
||||||
group_size = 100
|
group_size = 100
|
||||||
bots = 5
|
|
||||||
message_length = 2000
|
|
||||||
message_embeds = 5
|
message_embeds = 5
|
||||||
message_replies = 5
|
message_replies = 5
|
||||||
message_attachments = 5
|
|
||||||
message_reactions = 20
|
message_reactions = 20
|
||||||
servers = 100
|
|
||||||
server_emoji = 100
|
server_emoji = 100
|
||||||
server_roles = 200
|
server_roles = 200
|
||||||
server_channels = 200
|
server_channels = 200
|
||||||
|
|
||||||
|
new_user_days = 3
|
||||||
|
|
||||||
|
[features.limits.new_user]
|
||||||
|
outgoing_friend_requests = 5
|
||||||
|
|
||||||
|
bots = 2
|
||||||
|
message_length = 2000
|
||||||
|
message_attachments = 5
|
||||||
|
servers = 100
|
||||||
|
|
||||||
|
attachment_size = 20000000
|
||||||
|
avatar_size = 4000000
|
||||||
|
background_size = 6000000
|
||||||
|
icon_size = 2500000
|
||||||
|
banner_size = 6000000
|
||||||
|
emoji_size = 500000
|
||||||
|
|
||||||
|
[features.limits.default]
|
||||||
|
outgoing_friend_requests = 10
|
||||||
|
|
||||||
|
bots = 5
|
||||||
|
message_length = 2000
|
||||||
|
message_attachments = 5
|
||||||
|
servers = 100
|
||||||
|
|
||||||
attachment_size = 20000000
|
attachment_size = 20000000
|
||||||
avatar_size = 4000000
|
avatar_size = 4000000
|
||||||
background_size = 6000000
|
background_size = 6000000
|
||||||
|
|||||||
@@ -105,19 +105,27 @@ pub struct Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct FeaturesLimits {
|
pub struct GlobalLimits {
|
||||||
pub group_size: usize,
|
pub group_size: usize,
|
||||||
pub bots: usize,
|
|
||||||
pub message_length: usize,
|
|
||||||
pub message_replies: usize,
|
|
||||||
pub message_attachments: usize,
|
|
||||||
pub message_embeds: usize,
|
pub message_embeds: usize,
|
||||||
|
pub message_replies: usize,
|
||||||
pub message_reactions: usize,
|
pub message_reactions: usize,
|
||||||
pub servers: usize,
|
|
||||||
pub server_emoji: usize,
|
pub server_emoji: usize,
|
||||||
pub server_roles: usize,
|
pub server_roles: usize,
|
||||||
pub server_channels: usize,
|
pub server_channels: usize,
|
||||||
|
|
||||||
|
pub new_user_days: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub struct FeaturesLimits {
|
||||||
|
pub outgoing_friend_requests: usize,
|
||||||
|
|
||||||
|
pub bots: usize,
|
||||||
|
pub message_length: usize,
|
||||||
|
pub message_attachments: usize,
|
||||||
|
pub servers: usize,
|
||||||
|
|
||||||
pub attachment_size: usize,
|
pub attachment_size: usize,
|
||||||
pub avatar_size: usize,
|
pub avatar_size: usize,
|
||||||
pub background_size: usize,
|
pub background_size: usize,
|
||||||
@@ -128,6 +136,9 @@ pub struct FeaturesLimits {
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct FeaturesLimitsCollection {
|
pub struct FeaturesLimitsCollection {
|
||||||
|
pub global: GlobalLimits,
|
||||||
|
|
||||||
|
pub new_user: FeaturesLimits,
|
||||||
pub default: FeaturesLimits,
|
pub default: FeaturesLimits,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -23,13 +23,13 @@ default = ["mongodb", "async-std-runtime", "tasks"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.7.6", path = "../config" }
|
revolt-config = { version = "0.7.10", path = "../config" }
|
||||||
revolt-result = { version = "0.7.6", path = "../result" }
|
revolt-result = { version = "0.7.10", path = "../result" }
|
||||||
revolt-models = { version = "0.7.6", path = "../models", features = [
|
revolt-models = { version = "0.7.10", path = "../models", features = [
|
||||||
"validator",
|
"validator",
|
||||||
] }
|
] }
|
||||||
revolt-presence = { version = "0.7.6", path = "../presence" }
|
revolt-presence = { version = "0.7.10", path = "../presence" }
|
||||||
revolt-permissions = { version = "0.7.6", path = "../permissions", features = [
|
revolt-permissions = { version = "0.7.10", path = "../permissions", features = [
|
||||||
"serde",
|
"serde",
|
||||||
"bson",
|
"bson",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ impl Bot {
|
|||||||
return Err(create_error!(IsBot));
|
return Err(create_error!(IsBot));
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = config().await;
|
if db.get_number_of_bots_by_user(&owner.id).await? >= owner.limits().await.bots {
|
||||||
if db.get_number_of_bots_by_user(&owner.id).await? >= config.features.limits.default.bots {
|
|
||||||
return Err(create_error!(ReachedMaximumBots));
|
return Err(create_error!(ReachedMaximumBots));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,9 +201,9 @@ impl Channel {
|
|||||||
update_server: bool,
|
update_server: bool,
|
||||||
) -> Result<Channel> {
|
) -> Result<Channel> {
|
||||||
let config = config().await;
|
let config = config().await;
|
||||||
if server.channels.len() > config.features.limits.default.server_channels {
|
if server.channels.len() > config.features.limits.global.server_channels {
|
||||||
return Err(create_error!(TooManyChannels {
|
return Err(create_error!(TooManyChannels {
|
||||||
max: config.features.limits.default.server_channels,
|
max: config.features.limits.global.server_channels,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -263,9 +263,9 @@ impl Channel {
|
|||||||
data.users.insert(owner_id.to_string());
|
data.users.insert(owner_id.to_string());
|
||||||
|
|
||||||
let config = config().await;
|
let config = config().await;
|
||||||
if data.users.len() > config.features.limits.default.group_size {
|
if data.users.len() > config.features.limits.global.group_size {
|
||||||
return Err(create_error!(GroupTooLarge {
|
return Err(create_error!(GroupTooLarge {
|
||||||
max: config.features.limits.default.group_size,
|
max: config.features.limits.global.group_size,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,9 +346,9 @@ impl Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let config = config().await;
|
let config = config().await;
|
||||||
if recipients.len() >= config.features.limits.default.group_size {
|
if recipients.len() >= config.features.limits.global.group_size {
|
||||||
return Err(create_error!(GroupTooLarge {
|
return Err(create_error!(GroupTooLarge {
|
||||||
max: config.features.limits.default.group_size
|
max: config.features.limits.global.group_size
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use iso8601_timestamp::Timestamp;
|
use iso8601_timestamp::Timestamp;
|
||||||
use revolt_config::config;
|
use revolt_config::{config, FeaturesLimits};
|
||||||
use revolt_models::v0::{
|
use revolt_models::v0::{
|
||||||
self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageSort, MessageWebhook,
|
self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageSort, MessageWebhook,
|
||||||
PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION,
|
PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION,
|
||||||
@@ -207,11 +207,13 @@ impl Default for Message {
|
|||||||
#[allow(clippy::disallowed_methods)]
|
#[allow(clippy::disallowed_methods)]
|
||||||
impl Message {
|
impl Message {
|
||||||
/// Create message from API data
|
/// Create message from API data
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn create_from_api(
|
pub async fn create_from_api(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
channel: Channel,
|
channel: Channel,
|
||||||
data: DataMessageSend,
|
data: DataMessageSend,
|
||||||
author: MessageAuthor<'_>,
|
author: MessageAuthor<'_>,
|
||||||
|
limits: FeaturesLimits,
|
||||||
mut idempotency: IdempotencyKey,
|
mut idempotency: IdempotencyKey,
|
||||||
generate_embeds: bool,
|
generate_embeds: bool,
|
||||||
allow_mentions: bool,
|
allow_mentions: bool,
|
||||||
@@ -221,7 +223,7 @@ impl Message {
|
|||||||
Message::validate_sum(
|
Message::validate_sum(
|
||||||
&data.content,
|
&data.content,
|
||||||
data.embeds.as_deref().unwrap_or_default(),
|
data.embeds.as_deref().unwrap_or_default(),
|
||||||
config.features.limits.default.message_length,
|
limits.message_length,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
idempotency
|
idempotency
|
||||||
@@ -288,9 +290,9 @@ impl Message {
|
|||||||
// Verify replies are valid.
|
// Verify replies are valid.
|
||||||
let mut replies = HashSet::new();
|
let mut replies = HashSet::new();
|
||||||
if let Some(entries) = data.replies {
|
if let Some(entries) = data.replies {
|
||||||
if entries.len() > config.features.limits.default.message_replies {
|
if entries.len() > config.features.limits.global.message_replies {
|
||||||
return Err(create_error!(TooManyReplies {
|
return Err(create_error!(TooManyReplies {
|
||||||
max: config.features.limits.default.message_replies,
|
max: config.features.limits.global.message_replies,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,20 +322,20 @@ impl Message {
|
|||||||
if data
|
if data
|
||||||
.attachments
|
.attachments
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|v| v.len() > config.features.limits.default.message_attachments)
|
.is_some_and(|v| v.len() > limits.message_attachments)
|
||||||
{
|
{
|
||||||
return Err(create_error!(TooManyAttachments {
|
return Err(create_error!(TooManyAttachments {
|
||||||
max: config.features.limits.default.message_attachments,
|
max: limits.message_attachments,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if data
|
if data
|
||||||
.embeds
|
.embeds
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|v| v.len() > config.features.limits.default.message_embeds)
|
.is_some_and(|v| v.len() > config.features.limits.global.message_embeds)
|
||||||
{
|
{
|
||||||
return Err(create_error!(TooManyEmbeds {
|
return Err(create_error!(TooManyEmbeds {
|
||||||
max: config.features.limits.default.message_embeds,
|
max: config.features.limits.global.message_embeds,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,7 +618,7 @@ impl Message {
|
|||||||
pub async fn add_reaction(&self, db: &Database, user: &User, emoji: &str) -> Result<()> {
|
pub async fn add_reaction(&self, db: &Database, user: &User, emoji: &str) -> Result<()> {
|
||||||
// Check how many reactions are already on the message
|
// Check how many reactions are already on the message
|
||||||
let config = config().await;
|
let config = config().await;
|
||||||
if self.reactions.len() >= config.features.limits.default.message_reactions
|
if self.reactions.len() >= config.features.limits.global.message_reactions
|
||||||
&& !self.reactions.contains_key(emoji)
|
&& !self.reactions.contains_key(emoji)
|
||||||
{
|
{
|
||||||
return Err(create_error!(InvalidOperation));
|
return Err(create_error!(InvalidOperation));
|
||||||
@@ -781,7 +783,7 @@ impl Interactions {
|
|||||||
if let Some(reactions) = &self.reactions {
|
if let Some(reactions) = &self.reactions {
|
||||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::React)?;
|
permissions.throw_if_lacking_channel_permission(ChannelPermission::React)?;
|
||||||
|
|
||||||
if reactions.len() > config.features.limits.default.message_reactions {
|
if reactions.len() > config.features.limits.global.message_reactions {
|
||||||
return Err(create_error!(InvalidOperation));
|
return Err(create_error!(InvalidOperation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::{collections::HashSet, time::Duration};
|
use std::{collections::HashSet, str::FromStr, time::Duration};
|
||||||
|
|
||||||
use crate::{events::client::EventV1, Database, File, RatelimitEvent};
|
use crate::{events::client::EventV1, Database, File, RatelimitEvent};
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use revolt_config::config;
|
use revolt_config::{config, FeaturesLimits};
|
||||||
use revolt_models::v0;
|
use revolt_models::v0;
|
||||||
use revolt_presence::filter_online;
|
use revolt_presence::filter_online;
|
||||||
use revolt_result::{create_error, Result};
|
use revolt_result::{create_error, Result};
|
||||||
@@ -197,6 +197,22 @@ impl User {
|
|||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get limits for this user
|
||||||
|
pub async fn limits(&self) -> FeaturesLimits {
|
||||||
|
let config = config().await;
|
||||||
|
if ulid::Ulid::from_str(&self.id)
|
||||||
|
.expect("`ulid`")
|
||||||
|
.datetime()
|
||||||
|
.elapsed()
|
||||||
|
.expect("time went backwards")
|
||||||
|
<= Duration::from_secs(86400u64 * config.features.limits.global.new_user_days as u64)
|
||||||
|
{
|
||||||
|
config.features.limits.new_user
|
||||||
|
} else {
|
||||||
|
config.features.limits.default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the relationship with another user
|
/// Get the relationship with another user
|
||||||
pub fn relationship_with(&self, user_b: &str) -> RelationshipStatus {
|
pub fn relationship_with(&self, user_b: &str) -> RelationshipStatus {
|
||||||
if self.id == user_b {
|
if self.id == user_b {
|
||||||
@@ -235,12 +251,11 @@ impl User {
|
|||||||
|
|
||||||
/// Check if this user can acquire another server
|
/// Check if this user can acquire another server
|
||||||
pub async fn can_acquire_server(&self, db: &Database) -> Result<()> {
|
pub async fn can_acquire_server(&self, db: &Database) -> Result<()> {
|
||||||
let config = config().await;
|
if db.fetch_server_count(&self.id).await? <= self.limits().await.servers {
|
||||||
if db.fetch_server_count(&self.id).await? <= config.features.limits.default.servers {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(TooManyServers {
|
Err(create_error!(TooManyServers {
|
||||||
max: config.features.limits.default.servers
|
max: self.limits().await.servers
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,6 +492,7 @@ impl User {
|
|||||||
RelationshipStatus::Blocked => Err(create_error!(Blocked)),
|
RelationshipStatus::Blocked => Err(create_error!(Blocked)),
|
||||||
RelationshipStatus::BlockedOther => Err(create_error!(BlockedByOther)),
|
RelationshipStatus::BlockedOther => Err(create_error!(BlockedByOther)),
|
||||||
RelationshipStatus::Incoming => {
|
RelationshipStatus::Incoming => {
|
||||||
|
// Accept incoming friend request
|
||||||
self.apply_relationship(
|
self.apply_relationship(
|
||||||
db,
|
db,
|
||||||
target,
|
target,
|
||||||
@@ -486,6 +502,26 @@ impl User {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
RelationshipStatus::None => {
|
RelationshipStatus::None => {
|
||||||
|
// Get this user's current count of outgoing friend requests
|
||||||
|
let count = self
|
||||||
|
.relations
|
||||||
|
.as_ref()
|
||||||
|
.map(|relations| {
|
||||||
|
relations
|
||||||
|
.iter()
|
||||||
|
.filter(|r| matches!(r.status, RelationshipStatus::Outgoing))
|
||||||
|
.count()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// If we're over the limit, don't allow creating more requests
|
||||||
|
if count >= self.limits().await.outgoing_friend_requests {
|
||||||
|
return Err(create_error!(TooManyPendingFriendRequests {
|
||||||
|
max: self.limits().await.outgoing_friend_requests
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the friend request
|
||||||
self.apply_relationship(
|
self.apply_relationship(
|
||||||
db,
|
db,
|
||||||
target,
|
target,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub async fn worker(db: Database) {
|
|||||||
let embeds = generate(
|
let embeds = generate(
|
||||||
task.content,
|
task.content,
|
||||||
&config.hosts.january,
|
&config.hosts.january,
|
||||||
config.features.limits.default.message_embeds,
|
config.features.limits.global.message_embeds,
|
||||||
semaphore,
|
semaphore,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -19,8 +19,8 @@ default = ["serde", "partials", "rocket"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.7.6", path = "../config" }
|
revolt-config = { version = "0.7.10", path = "../config" }
|
||||||
revolt-permissions = { version = "0.7.6", path = "../permissions" }
|
revolt-permissions = { version = "0.7.10", path = "../permissions" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-result = { version = "0.7.6", path = "../result" }
|
revolt-result = { version = "0.7.10", path = "../result" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
auto_ops = "0.3.0"
|
auto_ops = "0.3.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ pub enum ErrorType {
|
|||||||
Blocked,
|
Blocked,
|
||||||
BlockedByOther,
|
BlockedByOther,
|
||||||
NotFriends,
|
NotFriends,
|
||||||
|
TooManyPendingFriendRequests {
|
||||||
|
max: usize,
|
||||||
|
},
|
||||||
|
|
||||||
// ? Channel related errors
|
// ? Channel related errors
|
||||||
UnknownChannel,
|
UnknownChannel,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
ErrorType::Blocked => Status::Conflict,
|
ErrorType::Blocked => Status::Conflict,
|
||||||
ErrorType::BlockedByOther => Status::Forbidden,
|
ErrorType::BlockedByOther => Status::Forbidden,
|
||||||
ErrorType::NotFriends => Status::Forbidden,
|
ErrorType::NotFriends => Status::Forbidden,
|
||||||
|
ErrorType::TooManyPendingFriendRequests { .. } => Status::BadRequest,
|
||||||
|
|
||||||
ErrorType::UnknownChannel => Status::NotFound,
|
ErrorType::UnknownChannel => Status::NotFound,
|
||||||
ErrorType::UnknownMessage => Status::NotFound,
|
ErrorType::UnknownMessage => Status::NotFound,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.7.6"
|
version = "0.7.10"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ pub async fn web() -> Rocket<Build> {
|
|||||||
authifier::database::MongoDb(client.database("revolt")),
|
authifier::database::MongoDb(client.database("revolt")),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
config: Default::default(),
|
config: authifier_config().await,
|
||||||
// config: authifier_config().await,
|
|
||||||
event_channel: Some(sender),
|
event_channel: Some(sender),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,10 @@ pub async fn edit(
|
|||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let config = config().await;
|
|
||||||
Message::validate_sum(
|
Message::validate_sum(
|
||||||
&edit.content,
|
&edit.content,
|
||||||
edit.embeds.as_deref().unwrap_or_default(),
|
edit.embeds.as_deref().unwrap_or_default(),
|
||||||
config.features.limits.default.message_length,
|
user.limits().await.message_length,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Ensure we have permissions to send a message
|
// Ensure we have permissions to send a message
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ pub async fn message_send(
|
|||||||
channel,
|
channel,
|
||||||
data,
|
data,
|
||||||
v0::MessageAuthor::User(&author),
|
v0::MessageAuthor::User(&author),
|
||||||
|
user.limits().await,
|
||||||
idempotency,
|
idempotency,
|
||||||
permissions.has_channel_permission(ChannelPermission::SendEmbeds),
|
permissions.has_channel_permission(ChannelPermission::SendEmbeds),
|
||||||
allow_mentions,
|
allow_mentions,
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ pub async fn create_emoji(
|
|||||||
|
|
||||||
// Check that we haven't hit the emoji limit
|
// Check that we haven't hit the emoji limit
|
||||||
let emojis = db.fetch_emoji_by_parent_id(&server.id).await?;
|
let emojis = db.fetch_emoji_by_parent_id(&server.id).await?;
|
||||||
if emojis.len() >= config.features.limits.default.server_emoji {
|
if emojis.len() >= config.features.limits.global.server_emoji {
|
||||||
return Err(create_error!(TooManyEmoji {
|
return Err(create_error!(TooManyEmoji {
|
||||||
max: config.features.limits.default.server_emoji,
|
max: config.features.limits.global.server_emoji,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ pub async fn create(
|
|||||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageRole)?;
|
.throw_if_lacking_channel_permission(ChannelPermission::ManageRole)?;
|
||||||
|
|
||||||
let config = config().await;
|
let config = config().await;
|
||||||
if server.roles.len() >= config.features.limits.default.server_roles {
|
if server.roles.len() >= config.features.limits.global.server_roles {
|
||||||
return Err(create_error!(TooManyRoles {
|
return Err(create_error!(TooManyRoles {
|
||||||
max: config.features.limits.default.server_roles,
|
max: config.features.limits.global.server_roles,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use revolt_config::config;
|
||||||
use revolt_database::{
|
use revolt_database::{
|
||||||
util::{idempotency::IdempotencyKey, reference::Reference},
|
util::{idempotency::IdempotencyKey, reference::Reference},
|
||||||
Database, Message,
|
Database, Message,
|
||||||
@@ -58,6 +59,7 @@ pub async fn webhook_execute(
|
|||||||
channel,
|
channel,
|
||||||
data,
|
data,
|
||||||
v0::MessageAuthor::Webhook(&webhook.into()),
|
v0::MessageAuthor::Webhook(&webhook.into()),
|
||||||
|
config().await.features.limits.default,
|
||||||
idempotency,
|
idempotency,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
|||||||
Reference in new issue
Block a user