pub(crate) const BASE_MESSAGE_CHARACTER_LIMIT: usize = 2_000;
pub(crate) const NITRO_MESSAGE_CHARACTER_LIMIT: usize = 4_000;
pub const BASE_ATTACHMENT_LIMIT_BYTES: u64 = 10 * 1024 * 1024;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct MessageSendLimits {
pub(crate) max_content_chars: usize,
pub(crate) max_attachment_bytes: u64,
}
impl Default for MessageSendLimits {
fn default() -> Self {
Self {
max_content_chars: BASE_MESSAGE_CHARACTER_LIMIT,
max_attachment_bytes: BASE_ATTACHMENT_LIMIT_BYTES,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum PremiumTier {
#[default]
None,
NitroClassic,
Nitro,
NitroBasic,
}
impl PremiumTier {
pub fn from_premium_type(premium_type: u64) -> Self {
match premium_type {
1 => Self::NitroClassic,
2 => Self::Nitro,
3 => Self::NitroBasic,
_ => Self::None,
}
}
pub fn has_nitro(self) -> bool {
!matches!(self, Self::None)
}
pub fn attachment_limit_bytes(self) -> u64 {
match self {
Self::Nitro => 500 * 1024 * 1024,
Self::NitroClassic | Self::NitroBasic => 50 * 1024 * 1024,
Self::None => BASE_ATTACHMENT_LIMIT_BYTES,
}
}
pub(crate) fn message_character_limit(self) -> usize {
match self {
Self::Nitro => NITRO_MESSAGE_CHARACTER_LIMIT,
Self::None | Self::NitroClassic | Self::NitroBasic => BASE_MESSAGE_CHARACTER_LIMIT,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum GuildBoostTier {
#[default]
None,
Tier1,
Tier2,
Tier3,
}
impl GuildBoostTier {
pub fn from_premium_tier(premium_tier: u64) -> Self {
match premium_tier {
1 => Self::Tier1,
2 => Self::Tier2,
3 => Self::Tier3,
_ => Self::None,
}
}
pub fn level(self) -> u8 {
match self {
Self::None => 0,
Self::Tier1 => 1,
Self::Tier2 => 2,
Self::Tier3 => 3,
}
}
pub fn attachment_limit_bytes(self) -> u64 {
match self {
Self::Tier3 => 100 * 1024 * 1024,
Self::Tier2 => 50 * 1024 * 1024,
Self::None | Self::Tier1 => BASE_ATTACHMENT_LIMIT_BYTES,
}
}
}
pub fn effective_attachment_limit_bytes(user: PremiumTier, guild: Option<GuildBoostTier>) -> u64 {
let guild_limit = guild.map_or(
BASE_ATTACHMENT_LIMIT_BYTES,
GuildBoostTier::attachment_limit_bytes,
);
user.attachment_limit_bytes().max(guild_limit)
}
pub(crate) fn guild_attachment_limit_bytes(
boost_tier: GuildBoostTier,
features: Option<&[String]>,
) -> u64 {
let feature_limit = features
.into_iter()
.flatten()
.filter_map(|feature| match feature.as_str() {
"MAX_FILE_SIZE_50_MB" => Some(50 * 1024 * 1024),
"MAX_FILE_SIZE_100_MB" => Some(100 * 1024 * 1024),
"MAX_FILE_SIZE_250_MB" => Some(250 * 1024 * 1024),
_ => None,
})
.max()
.unwrap_or(BASE_ATTACHMENT_LIMIT_BYTES);
boost_tier.attachment_limit_bytes().max(feature_limit)
}
pub(crate) fn effective_message_send_limits(
user: PremiumTier,
guild_attachment_limit: Option<u64>,
) -> MessageSendLimits {
MessageSendLimits {
max_content_chars: user.message_character_limit(),
max_attachment_bytes: user
.attachment_limit_bytes()
.max(guild_attachment_limit.unwrap_or(BASE_ATTACHMENT_LIMIT_BYTES)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn premium_type_maps_to_account_capabilities() {
let cases = [
(
0,
PremiumTier::None,
10 * 1024 * 1024,
BASE_MESSAGE_CHARACTER_LIMIT,
false,
),
(
1,
PremiumTier::NitroClassic,
50 * 1024 * 1024,
BASE_MESSAGE_CHARACTER_LIMIT,
true,
),
(
2,
PremiumTier::Nitro,
500 * 1024 * 1024,
NITRO_MESSAGE_CHARACTER_LIMIT,
true,
),
(
3,
PremiumTier::NitroBasic,
50 * 1024 * 1024,
BASE_MESSAGE_CHARACTER_LIMIT,
true,
),
(
99,
PremiumTier::None,
10 * 1024 * 1024,
BASE_MESSAGE_CHARACTER_LIMIT,
false,
),
];
for (raw, tier, upload_limit, message_limit, has_nitro) in cases {
let parsed = PremiumTier::from_premium_type(raw);
assert_eq!(parsed, tier, "premium_type {raw}");
assert_eq!(
parsed.attachment_limit_bytes(),
upload_limit,
"upload limit for {raw}"
);
assert_eq!(
parsed.message_character_limit(),
message_limit,
"message limit for {raw}"
);
assert_eq!(parsed.has_nitro(), has_nitro, "has_nitro for {raw}");
}
}
#[test]
fn guild_boost_tier_maps_to_upload_limit() {
assert_eq!(
GuildBoostTier::from_premium_tier(0).attachment_limit_bytes(),
10 * 1024 * 1024
);
assert_eq!(
GuildBoostTier::from_premium_tier(1).attachment_limit_bytes(),
10 * 1024 * 1024
);
assert_eq!(
GuildBoostTier::from_premium_tier(2).attachment_limit_bytes(),
50 * 1024 * 1024
);
assert_eq!(
GuildBoostTier::from_premium_tier(3).attachment_limit_bytes(),
100 * 1024 * 1024
);
}
}