use std::collections::HashSet;
use super::{Cache, CacheUpdate};
use crate::model::channel::{Channel, GuildChannel, Message};
use crate::model::event::{
ChannelCreateEvent,
ChannelDeleteEvent,
ChannelPinsUpdateEvent,
ChannelUpdateEvent,
GuildCreateEvent,
GuildDeleteEvent,
GuildEmojisUpdateEvent,
GuildMemberAddEvent,
GuildMemberRemoveEvent,
GuildMemberUpdateEvent,
GuildMembersChunkEvent,
GuildRoleCreateEvent,
GuildRoleDeleteEvent,
GuildRoleUpdateEvent,
GuildStickersUpdateEvent,
GuildUnavailableEvent,
GuildUpdateEvent,
MessageCreateEvent,
MessageUpdateEvent,
PresenceUpdateEvent,
PresencesReplaceEvent,
ReadyEvent,
ThreadCreateEvent,
ThreadDeleteEvent,
ThreadUpdateEvent,
UserUpdateEvent,
VoiceStateUpdateEvent,
};
use crate::model::guild::{Guild, Member, Role};
use crate::model::user::{CurrentUser, OnlineStatus};
use crate::model::voice::VoiceState;
impl CacheUpdate for ChannelCreateEvent {
type Output = Channel;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
match self.channel {
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = (channel.guild_id, channel.id);
let old_channel = cache
.guilds
.get_mut(&guild_id)
.and_then(|mut g| g.channels.insert(channel_id, self.channel.clone()));
cache.channels.insert(channel_id, channel.clone());
old_channel
},
Channel::Private(ref mut channel) => {
if let Some(channel) = cache.private_channels.get(&channel.id) {
return Some(Channel::Private(channel.clone()));
}
let id = {
let user_id = {
cache.update_user_entry(&channel.recipient);
channel.recipient.id
};
if let Some(u) = cache.users.get(&user_id) {
channel.recipient = u.clone();
}
channel.id
};
cache.private_channels.insert(id, channel.clone()).map(Channel::Private)
},
Channel::Category(ref category) => {
let (guild_id, channel_id) = (category.guild_id, category.id);
let old_channel = cache
.guilds
.get_mut(&guild_id)
.and_then(|mut g| g.channels.insert(channel_id, self.channel.clone()));
cache.categories.insert(channel_id, category.clone());
old_channel
},
}
}
}
impl CacheUpdate for ChannelDeleteEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
match self.channel {
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = (channel.guild_id, channel.id);
cache.channels.remove(&channel_id);
cache.guilds.get_mut(&guild_id).map(|mut g| g.channels.remove(&channel_id));
},
Channel::Category(ref category) => {
let (guild_id, channel_id) = (category.guild_id, category.id);
cache.categories.remove(&channel_id);
cache.guilds.get_mut(&guild_id).map(|mut g| g.channels.remove(&channel_id));
},
Channel::Private(ref channel) => {
let id = { channel.id };
cache.private_channels.remove(&id);
},
};
cache.messages.remove(&self.channel.id());
None
}
}
impl CacheUpdate for ChannelUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
match self.channel {
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = (channel.guild_id, channel.id);
cache.channels.insert(channel_id, channel.clone());
cache
.guilds
.get_mut(&guild_id)
.map(|mut g| g.channels.insert(channel_id, self.channel.clone()));
},
Channel::Private(ref channel) => {
if let Some(mut c) = cache.private_channels.get_mut(&channel.id) {
c.clone_from(channel);
}
},
Channel::Category(ref category) => {
let (guild_id, channel_id) = (category.guild_id, category.id);
cache.categories.insert(channel_id, category.clone());
cache
.guilds
.get_mut(&guild_id)
.map(|mut g| g.channels.insert(channel_id, self.channel.clone()));
},
}
None
}
}
impl CacheUpdate for ChannelPinsUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
if let Some(mut channel) = cache.channels.get_mut(&self.channel_id) {
channel.last_pin_timestamp = self.last_pin_timestamp;
return None;
}
if let Some(mut channel) = cache.private_channels.get_mut(&self.channel_id) {
channel.last_pin_timestamp = self.last_pin_timestamp;
return None;
}
None
}
}
impl CacheUpdate for GuildCreateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
cache.unavailable_guilds.remove(&self.guild.id);
let mut guild = self.guild.clone();
for (user_id, member) in &mut guild.members {
cache.update_user_entry(&member.user);
if let Some(u) = cache.user(user_id) {
member.user = u;
}
}
for pair in guild.channels.clone() {
if let Channel::Guild(channel) = pair.1 {
cache.channels.insert(pair.0, channel);
}
}
for pair in guild.channels.clone() {
if let Channel::Category(category) = pair.1 {
cache.categories.insert(pair.0, category);
}
}
cache.guilds.insert(self.guild.id, guild);
None
}
}
impl CacheUpdate for GuildDeleteEvent {
type Output = Guild;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
match cache.guilds.remove(&self.guild.id) {
Some(guild) => {
for (channel_id, channel) in &guild.1.channels {
match channel {
Channel::Guild(_) => {
cache.channels.remove(channel_id);
cache.messages.remove(channel_id);
},
Channel::Category(_) => {
cache.categories.remove(channel_id);
},
_ => {},
}
}
Some(guild.1)
},
None => None,
}
}
}
impl CacheUpdate for GuildEmojisUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
guild.emojis.clone_from(&self.emojis);
}
None
}
}
impl CacheUpdate for GuildMemberAddEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
let user_id = self.member.user.id;
cache.update_user_entry(&self.member.user);
if let Some(u) = cache.user(user_id) {
self.member.user = u;
}
if let Some(mut guild) = cache.guilds.get_mut(&self.member.guild_id) {
guild.member_count += 1;
guild.members.insert(user_id, self.member.clone());
}
None
}
}
impl CacheUpdate for GuildMemberRemoveEvent {
type Output = Member;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
guild.member_count -= 1;
return guild.members.remove(&self.user.id);
}
None
}
}
impl CacheUpdate for GuildMemberUpdateEvent {
type Output = Member;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
cache.update_user_entry(&self.user);
if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
let item = if let Some(member) = guild.members.get_mut(&self.user.id) {
let item = Some(member.clone());
member.joined_at.clone_from(&Some(self.joined_at));
member.nick.clone_from(&self.nick);
member.roles.clone_from(&self.roles);
member.user.clone_from(&self.user);
member.pending.clone_from(&self.pending);
member.premium_since.clone_from(&self.premium_since);
member.deaf.clone_from(&self.deaf);
member.mute.clone_from(&self.mute);
member.avatar.clone_from(&self.avatar);
member.communication_disabled_until.clone_from(&self.communication_disabled_until);
item
} else {
None
};
if item.is_none() {
guild.members.insert(self.user.id, Member {
deaf: false,
guild_id: self.guild_id,
joined_at: Some(self.joined_at),
mute: false,
nick: self.nick.clone(),
roles: self.roles.clone(),
user: self.user.clone(),
pending: self.pending,
premium_since: self.premium_since,
permissions: None,
avatar: self.avatar.clone(),
communication_disabled_until: self.communication_disabled_until,
});
}
item
} else {
None
}
}
}
impl CacheUpdate for GuildMembersChunkEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
for member in self.members.values() {
cache.update_user_entry(&member.user);
}
if let Some(mut g) = cache.guilds.get_mut(&self.guild_id) {
g.members.extend(self.members.clone());
}
None
}
}
impl CacheUpdate for GuildRoleCreateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
cache
.guilds
.get_mut(&self.role.guild_id)
.map(|mut g| g.roles.insert(self.role.id, self.role.clone()));
None
}
}
impl CacheUpdate for GuildRoleDeleteEvent {
type Output = Role;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
cache.guilds.get_mut(&self.guild_id).and_then(|mut g| g.roles.remove(&self.role_id))
}
}
impl CacheUpdate for GuildRoleUpdateEvent {
type Output = Role;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
if let Some(mut guild) = cache.guilds.get_mut(&self.role.guild_id) {
if let Some(role) = guild.roles.get_mut(&self.role.id) {
return Some(std::mem::replace(role, self.role.clone()));
}
}
None
}
}
impl CacheUpdate for GuildStickersUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
guild.stickers.clone_from(&self.stickers);
}
None
}
}
impl CacheUpdate for GuildUnavailableEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
cache.unavailable_guilds.insert(self.guild_id);
cache.guilds.remove(&self.guild_id);
None
}
}
impl CacheUpdate for GuildUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
if let Some(mut guild) = cache.guilds.get_mut(&self.guild.id) {
guild.afk_channel_id.clone_from(&self.guild.afk_channel_id);
guild.afk_timeout = self.guild.afk_timeout;
guild.banner.clone_from(&self.guild.banner);
guild.discovery_splash.clone_from(&self.guild.discovery_splash);
guild.features.clone_from(&self.guild.features);
guild.icon.clone_from(&self.guild.icon);
guild.name.clone_from(&self.guild.name);
guild.owner_id.clone_from(&self.guild.owner_id);
guild.roles.clone_from(&self.guild.roles);
guild.splash.clone_from(&self.guild.splash);
guild.vanity_url_code.clone_from(&self.guild.vanity_url_code);
guild.welcome_screen.clone_from(&self.guild.welcome_screen);
guild.default_message_notifications = self.guild.default_message_notifications;
guild.max_members = self.guild.max_members;
guild.max_presences = self.guild.max_presences;
guild.max_video_channel_users = self.guild.max_video_channel_users;
guild.mfa_level = self.guild.mfa_level;
guild.nsfw_level = self.guild.nsfw_level;
guild.premium_subscription_count = self.guild.premium_subscription_count;
guild.premium_tier = self.guild.premium_tier;
guild.public_updates_channel_id = self.guild.public_updates_channel_id;
guild.rules_channel_id = self.guild.rules_channel_id;
guild.system_channel_flags = self.guild.system_channel_flags;
guild.system_channel_id = self.guild.system_channel_id;
guild.verification_level = self.guild.verification_level;
guild.widget_channel_id = self.guild.widget_channel_id;
guild.widget_enabled = self.guild.widget_enabled;
}
None
}
}
impl CacheUpdate for MessageCreateEvent {
type Output = Message;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
let max = cache.settings().max_messages;
if max == 0 {
return None;
}
let messages =
cache.messages.entry(self.message.channel_id).or_insert_with(Default::default);
let mut queue =
cache.message_queue.entry(self.message.channel_id).or_insert_with(Default::default);
let mut removed_msg = None;
if messages.len() == max {
if let Some(id) = queue.pop_front() {
removed_msg = messages.remove(&id);
}
}
queue.push_back(self.message.id);
messages.insert(self.message.id, self.message.clone());
removed_msg.map(|i| i.1)
}
}
impl CacheUpdate for MessageUpdateEvent {
type Output = Message;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
if let Some(messages) = cache.messages.get_mut(&self.channel_id) {
if let Some(mut message) = messages.get_mut(&self.id) {
let item = message.clone();
if let Some(attachments) = self.attachments.clone() {
message.attachments = attachments;
}
if let Some(content) = self.content.clone() {
message.content = content;
}
if let Some(edited_timestamp) = self.edited_timestamp {
message.edited_timestamp = Some(edited_timestamp);
}
if let Some(mentions) = self.mentions.clone() {
message.mentions = mentions;
}
if let Some(mention_everyone) = self.mention_everyone {
message.mention_everyone = mention_everyone;
}
if let Some(mention_roles) = self.mention_roles.clone() {
message.mention_roles = mention_roles;
}
if let Some(pinned) = self.pinned {
message.pinned = pinned;
}
if self.flags.is_some() {
message.flags = self.flags;
}
return Some(item);
}
}
None
}
}
impl CacheUpdate for PresenceUpdateEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
if let Some(user) = self.presence.user.to_user() {
cache.update_user_entry(&user);
}
if let Some(user) = cache.user(self.presence.user.id) {
self.presence.user.update_with_user(user);
}
if let Some(guild_id) = self.presence.guild_id {
if let Some(mut guild) = cache.guilds.get_mut(&guild_id) {
if self.presence.status == OnlineStatus::Offline {
guild.presences.remove(&self.presence.user.id);
} else {
guild.presences.insert(self.presence.user.id, self.presence.clone());
}
if let Some(user) = self.presence.user.to_user() {
guild.members.entry(self.presence.user.id).or_insert_with(|| Member {
deaf: false,
guild_id,
joined_at: None,
mute: false,
nick: None,
user,
roles: vec![],
pending: false,
premium_since: None,
permissions: None,
avatar: None,
communication_disabled_until: None,
});
}
}
} else if self.presence.status == OnlineStatus::Offline {
cache.presences.remove(&self.presence.user.id);
} else {
cache.presences.insert(self.presence.user.id, self.presence.clone());
}
None
}
}
impl CacheUpdate for PresencesReplaceEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
for presence in &self.presences {
cache.presences.insert(presence.user.id, presence.clone());
}
None
}
}
impl CacheUpdate for ReadyEvent {
type Output = ();
fn update(&mut self, cache: &Cache) -> Option<()> {
let mut ready = self.ready.clone();
for unavailable in ready.guilds {
cache.guilds.remove(&unavailable.id);
cache.unavailable_guilds.insert(unavailable.id);
}
let mut guilds_to_remove = vec![];
let ready_guilds_hashset =
self.ready.guilds.iter().map(|status| status.id).collect::<HashSet<_>>();
let shard_data = self.ready.shard.unwrap_or([1, 1]);
for guild_entry in cache.guilds.iter() {
let guild = guild_entry.key();
if crate::utils::shard_id(guild.0, shard_data[1]) == shard_data[0]
&& !ready_guilds_hashset.contains(guild)
{
guilds_to_remove.push(*guild);
}
}
if !guilds_to_remove.is_empty() {
for guild in guilds_to_remove {
cache.guilds.remove(&guild);
}
}
for (user_id, presence) in &mut ready.presences {
if let Some(user) = presence.user.to_user() {
cache.update_user_entry(&user);
}
if let Some(user) = cache.user(user_id) {
presence.user.update_with_user(user);
}
cache.presences.insert(*user_id, presence.clone());
}
*cache.shard_count.write() = ready.shard.map_or(1, |s| s[1]);
*cache.user.write() = ready.user;
None
}
}
impl CacheUpdate for ThreadCreateEvent {
type Output = GuildChannel;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
cache.guilds.get_mut(&guild_id).and_then(|mut g| {
if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) {
Some(std::mem::replace(&mut g.threads[i], self.thread.clone()))
} else {
g.threads.push(self.thread.clone());
None
}
})
}
}
impl CacheUpdate for ThreadUpdateEvent {
type Output = GuildChannel;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
cache.guilds.get_mut(&guild_id).and_then(|mut g| {
if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) {
Some(std::mem::replace(&mut g.threads[i], self.thread.clone()))
} else {
g.threads.push(self.thread.clone());
None
}
})
}
}
impl CacheUpdate for ThreadDeleteEvent {
type Output = GuildChannel;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
cache.guilds.get_mut(&guild_id).and_then(|mut g| {
g.threads.iter().position(|e| e.id == thread_id).map(|i| g.threads.remove(i))
})
}
}
impl CacheUpdate for UserUpdateEvent {
type Output = CurrentUser;
fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
let mut user = cache.user.write();
Some(std::mem::replace(&mut user, self.current_user.clone()))
}
}
impl CacheUpdate for VoiceStateUpdateEvent {
type Output = VoiceState;
fn update(&mut self, cache: &Cache) -> Option<VoiceState> {
if let Some(guild_id) = self.voice_state.guild_id {
if let Some(mut guild) = cache.guilds.get_mut(&guild_id) {
if let Some(member) = &self.voice_state.member {
guild.members.insert(member.user.id, member.clone());
}
if self.voice_state.channel_id.is_some() {
guild.voice_states.insert(self.voice_state.user_id, self.voice_state.clone())
} else {
guild.voice_states.remove(&self.voice_state.user_id)
}
} else {
None
}
} else {
None
}
}
}