use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::sync::{Arc, RwLock};
use std::mem;
use ::model::*;
use ::model::event::*;
#[derive(Clone, Debug)]
pub struct Cache {
pub channels: HashMap<ChannelId, Arc<RwLock<GuildChannel>>>,
pub groups: HashMap<ChannelId, Arc<RwLock<Group>>>,
pub guilds: HashMap<GuildId, Arc<RwLock<Guild>>>,
pub notes: HashMap<UserId, String>,
pub presences: HashMap<UserId, Presence>,
pub private_channels: HashMap<ChannelId, Arc<RwLock<PrivateChannel>>>,
pub shard_count: u64,
pub unavailable_guilds: HashSet<GuildId>,
pub user: CurrentUser,
pub users: HashMap<UserId, Arc<RwLock<User>>>,
}
impl Cache {
pub fn unknown_members(&self) -> u64 {
let mut total = 0;
for guild in self.guilds.values() {
let guild = guild.read().unwrap();
let members = guild.members.len() as u64;
if guild.member_count > members {
total += guild.member_count - members;
}
}
total
}
pub fn all_private_channels(&self) -> Vec<ChannelId> {
self.groups
.keys()
.cloned()
.chain(self.private_channels.keys().cloned())
.collect()
}
pub fn all_guilds(&self) -> Vec<GuildId> {
self.guilds
.values()
.map(|g| g.read().unwrap().id)
.chain(self.unavailable_guilds.iter().cloned())
.collect()
}
pub fn channel<C: Into<ChannelId>>(&self, id: C) -> Option<Channel> {
let id = id.into();
if let Some(channel) = self.channels.get(&id) {
return Some(Channel::Guild(channel.clone()));
}
if let Some(private_channel) = self.private_channels.get(&id) {
return Some(Channel::Private(private_channel.clone()));
}
if let Some(group) = self.groups.get(&id) {
return Some(Channel::Group(group.clone()));
}
None
}
#[inline]
pub fn guild<G: Into<GuildId>>(&self, id: G) -> Option<Arc<RwLock<Guild>>> {
self.guilds.get(&id.into()).cloned()
}
#[inline]
pub fn guild_channel<C: Into<ChannelId>>(&self, id: C) -> Option<Arc<RwLock<GuildChannel>>> {
self.channels.get(&id.into()).cloned()
}
#[inline]
pub fn group<C: Into<ChannelId>>(&self, id: C) -> Option<Arc<RwLock<Group>>> {
self.groups.get(&id.into()).cloned()
}
pub fn member<G, U>(&self, guild_id: G, user_id: U) -> Option<Member>
where G: Into<GuildId>, U: Into<UserId> {
self.guilds
.get(&guild_id.into())
.and_then(|guild| guild.write().unwrap().members.get(&user_id.into()).cloned())
}
#[inline]
pub fn private_channel<C: Into<ChannelId>>(&self, channel_id: C)
-> Option<Arc<RwLock<PrivateChannel>>> {
self.private_channels.get(&channel_id.into()).cloned()
}
pub fn role<G, R>(&self, guild_id: G, role_id: R) -> Option<Role>
where G: Into<GuildId>, R: Into<RoleId> {
self.guilds
.get(&guild_id.into())
.and_then(|g| g.read().unwrap().roles.get(&role_id.into()).cloned())
}
#[inline]
pub fn user<U: Into<UserId>>(&self, user_id: U) -> Option<Arc<RwLock<User>>> {
self.users.get(&user_id.into()).cloned()
}
#[deprecated(since="0.1.5", note="Use `channel` instead.")]
#[inline]
pub fn get_channel<C: Into<ChannelId>>(&self, id: C) -> Option<Channel> {
self.channel(id)
}
#[deprecated(since="0.1.5", note="Use `guild` instead.")]
#[inline]
pub fn get_guild<G: Into<GuildId>>(&self, id: G) -> Option<Arc<RwLock<Guild>>> {
self.guild(id)
}
#[deprecated(since="0.1.5", note="Use `guild_channel` instead.")]
#[inline]
pub fn get_guild_channel<C: Into<ChannelId>>(&self, id: C)
-> Option<Arc<RwLock<GuildChannel>>> {
self.guild_channel(id)
}
#[deprecated(since="0.1.5", note="Use `member` instead.")]
#[inline]
pub fn get_member<G, U>(&self, guild_id: G, user_id: U) -> Option<Member>
where G: Into<GuildId>, U: Into<UserId> {
self.member(guild_id, user_id)
}
#[deprecated(since="0.1.5", note="Use `private_channel` instead.")]
#[inline]
pub fn get_private_channel<C: Into<ChannelId>>(&self, id: C)
-> Option<Arc<RwLock<PrivateChannel>>> {
self.private_channel(id)
}
#[deprecated(since="0.1.5", note="Use `role` instead.")]
#[inline]
pub fn get_role<G, R>(&self, guild_id: G, role_id: R) -> Option<Role>
where G: Into<GuildId>, R: Into<RoleId> {
self.role(guild_id, role_id)
}
#[deprecated(since="0.1.5", note="Use `user` instead.")]
#[inline]
pub fn get_user<U: Into<UserId>>(&self, id: U) -> Option<Arc<RwLock<User>>> {
self.user(id)
}
pub(crate) fn update_with_channel_create(&mut self, event: &ChannelCreateEvent) -> Option<Channel> {
match event.channel {
Channel::Group(ref group) => {
let group = group.clone();
let channel_id = {
let writer = group.write().unwrap();
for (recipient_id, recipient) in &mut group.write().unwrap().recipients {
self.update_user_entry(&recipient.read().unwrap());
*recipient = self.users[recipient_id].clone();
}
writer.channel_id
};
let ch = self.groups.insert(channel_id, group);
ch.map(Channel::Group)
},
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = {
let channel = channel.read().unwrap();
(channel.guild_id, channel.id)
};
self.channels.insert(channel_id, channel.clone());
self.guilds
.get_mut(&guild_id)
.and_then(|guild| {
guild.write().unwrap().channels.insert(channel_id, channel.clone())
}).map(Channel::Guild)
},
Channel::Private(ref channel) => {
let channel = channel.clone();
let mut channel_writer = channel.write().unwrap();
let user_id = {
let user_reader = channel_writer.recipient.read().unwrap();
self.update_user_entry(&user_reader);
user_reader.id
};
channel_writer.recipient = self.users[&user_id].clone();
let ch = self.private_channels.insert(channel_writer.id, channel.clone());
ch.map(Channel::Private)
},
}
}
pub(crate) fn update_with_channel_delete(&mut self, event: &ChannelDeleteEvent) -> Option<Channel> {
match event.channel {
Channel::Group(ref group) => {
self.groups.remove(&group.read().unwrap().channel_id).map(Channel::Group)
},
Channel::Private(ref channel) => {
self.private_channels.remove(&channel.read().unwrap().id).map(Channel::Private)
},
Channel::Guild(ref channel) => {
let (channel_id, guild_id) = {
let channel = channel.read().unwrap();
(channel.id, channel.guild_id)
};
self.channels.remove(&channel_id);
self.guilds
.get_mut(&guild_id)
.and_then(|guild| guild.write().unwrap().channels.remove(&channel_id))
.map(Channel::Guild)
},
}
}
#[allow(dead_code)]
pub(crate) fn update_with_channel_pins_update(&mut self, event: &ChannelPinsUpdateEvent) {
if let Some(channel) = self.channels.get(&event.channel_id) {
channel.write().unwrap().last_pin_timestamp = event.last_pin_timestamp;
return;
}
if let Some(channel) = self.private_channels.get_mut(&event.channel_id) {
channel.write().unwrap().last_pin_timestamp = event.last_pin_timestamp;
return;
}
if let Some(group) = self.groups.get_mut(&event.channel_id) {
group.write().unwrap().last_pin_timestamp = event.last_pin_timestamp;
return;
}
}
pub(crate) fn update_with_channel_recipient_add(&mut self, event: &mut ChannelRecipientAddEvent) {
self.update_user_entry(&event.user);
let user = self.users[&event.user.id].clone();
self.groups
.get_mut(&event.channel_id)
.map(|group| {
group.write()
.unwrap()
.recipients
.insert(event.user.id, user);
});
}
pub(crate) fn update_with_channel_recipient_remove(&mut self, event: &ChannelRecipientRemoveEvent) {
self.groups
.get_mut(&event.channel_id)
.map(|group| group.write().unwrap().recipients.remove(&event.user.id));
}
pub(crate) fn update_with_channel_update(&mut self, event: &ChannelUpdateEvent) {
match event.channel {
Channel::Group(ref group) => {
let (ch_id, no_recipients) = {
let group = group.read().unwrap();
(group.channel_id, group.recipients.is_empty())
};
match self.groups.entry(ch_id) {
Entry::Vacant(e) => {
e.insert(group.clone());
},
Entry::Occupied(mut e) => {
let mut dest = e.get_mut().write().unwrap();
if no_recipients {
let recipients = mem::replace(&mut dest.recipients, HashMap::new());
dest.clone_from(&group.read().unwrap());
dest.recipients = recipients;
} else {
dest.clone_from(&group.read().unwrap());
}
},
}
},
Channel::Guild(ref channel) => {
let (channel_id, guild_id) = {
let channel = channel.read().unwrap();
(channel.id, channel.guild_id)
};
self.channels.insert(channel_id, channel.clone());
self.guilds
.get_mut(&guild_id)
.map(|guild| {
guild.write()
.unwrap()
.channels
.insert(channel_id, channel.clone())
});
},
Channel::Private(ref channel) => {
self.private_channels
.get_mut(&channel.read().unwrap().id)
.map(|private| private.clone_from(channel));
},
}
}
pub(crate) fn update_with_guild_create(&mut self, event: &GuildCreateEvent) {
self.unavailable_guilds.remove(&event.guild.id);
let mut guild = event.guild.clone();
for (user_id, member) in &mut guild.members {
self.update_user_entry(&member.user.read().unwrap());
let user = self.users[user_id].clone();
member.user = user.clone();
}
self.channels.extend(guild.channels.clone());
self.guilds.insert(event.guild.id, Arc::new(RwLock::new(guild)));
}
pub(crate) fn update_with_guild_delete(&mut self, event: &GuildDeleteEvent)
-> Option<Arc<RwLock<Guild>>> {
self.guilds.remove(&event.guild.id).map(|guild| {
for channel_id in guild.read().unwrap().channels.keys() {
self.channels.remove(channel_id);
}
guild
})
}
pub(crate) fn update_with_guild_emojis_update(&mut self, event: &GuildEmojisUpdateEvent) {
self.guilds
.get_mut(&event.guild_id)
.map(|guild| guild.write().unwrap().emojis.extend(event.emojis.clone()));
}
pub(crate) fn update_with_guild_member_add(&mut self, event: &mut GuildMemberAddEvent) {
let user_id = event.member.user.read().unwrap().id;
self.update_user_entry(&event.member.user.read().unwrap());
event.member.user = self.users[&user_id].clone();
self.guilds
.get_mut(&event.guild_id)
.map(|guild| {
let mut guild = guild.write().unwrap();
guild.member_count += 1;
guild.members.insert(user_id, event.member.clone());
});
}
pub(crate) fn update_with_guild_member_remove(&mut self, event: &GuildMemberRemoveEvent)
-> Option<Member> {
self.guilds
.get_mut(&event.guild_id)
.and_then(|guild| {
let mut guild = guild.write().unwrap();
guild.member_count -= 1;
guild.members.remove(&event.user.id)
})
}
pub(crate) fn update_with_guild_member_update(&mut self, event: &GuildMemberUpdateEvent)
-> Option<Member> {
self.update_user_entry(&event.user);
if let Some(guild) = self.guilds.get_mut(&event.guild_id) {
let mut guild = guild.write().unwrap();
let mut found = false;
let item = if let Some(member) = guild.members.get_mut(&event.user.id) {
let item = Some(member.clone());
member.nick.clone_from(&event.nick);
member.roles.clone_from(&event.roles);
member.user.write().unwrap().clone_from(&event.user);
found = true;
item
} else {
None
};
if !found {
guild.members.insert(event.user.id, Member {
deaf: false,
guild_id: event.guild_id,
joined_at: None,
mute: false,
nick: event.nick.clone(),
roles: event.roles.clone(),
user: Arc::new(RwLock::new(event.user.clone())),
});
}
item
} else {
None
}
}
pub(crate) fn update_with_guild_members_chunk(&mut self, event: &GuildMembersChunkEvent) {
for member in event.members.values() {
self.update_user_entry(&member.user.read().unwrap());
}
self.guilds
.get_mut(&event.guild_id)
.map(|guild| guild.write().unwrap().members.extend(event.members.clone()));
}
pub(crate) fn update_with_guild_role_create(&mut self, event: &GuildRoleCreateEvent) {
self.guilds
.get_mut(&event.guild_id)
.map(|guild| guild.write().unwrap().roles.insert(event.role.id, event.role.clone()));
}
pub(crate) fn update_with_guild_role_delete(&mut self, event: &GuildRoleDeleteEvent) -> Option<Role> {
self.guilds
.get_mut(&event.guild_id)
.and_then(|guild| guild.write().unwrap().roles.remove(&event.role_id))
}
pub(crate) fn update_with_guild_role_update(&mut self, event: &GuildRoleUpdateEvent) -> Option<Role> {
self.guilds
.get_mut(&event.guild_id)
.and_then(|guild| {
guild.write()
.unwrap()
.roles
.get_mut(&event.role.id)
.map(|role| mem::replace(role, event.role.clone()))
})
}
pub(crate) fn update_with_guild_unavailable(&mut self, event: &GuildUnavailableEvent) {
self.unavailable_guilds.insert(event.guild_id);
self.guilds.remove(&event.guild_id);
}
pub(crate) fn update_with_guild_update(&mut self, event: &GuildUpdateEvent) {
self.guilds
.get_mut(&event.guild.id)
.map(|guild| {
let mut guild = guild.write().unwrap();
guild.afk_timeout = event.guild.afk_timeout;
guild.afk_channel_id.clone_from(&event.guild.afk_channel_id);
guild.icon.clone_from(&event.guild.icon);
guild.name.clone_from(&event.guild.name);
guild.owner_id.clone_from(&event.guild.owner_id);
guild.region.clone_from(&event.guild.region);
guild.roles.clone_from(&event.guild.roles);
guild.verification_level = event.guild.verification_level;
});
}
pub(crate) fn update_with_presences_replace(&mut self, event: &PresencesReplaceEvent) {
self.presences.extend({
let mut p: HashMap<UserId, Presence> = HashMap::default();
for presence in &event.presences {
p.insert(presence.user_id, presence.clone());
}
p
});
}
pub(crate) fn update_with_presence_update(&mut self, event: &mut PresenceUpdateEvent) {
let user_id = event.presence.user_id;
if let Some(user) = event.presence.user.as_mut() {
self.update_user_entry(&user.read().unwrap());
*user = self.users[&user_id].clone();
}
if let Some(guild_id) = event.guild_id {
if let Some(guild) = self.guilds.get_mut(&guild_id) {
let mut guild = guild.write().unwrap();
if event.presence.status == OnlineStatus::Offline {
guild.presences.remove(&event.presence.user_id);
} else {
guild.presences.insert(event.presence.user_id, event.presence.clone());
}
}
} else if event.presence.status == OnlineStatus::Offline {
self.presences.remove(&event.presence.user_id);
} else {
self.presences.insert(event.presence.user_id, event.presence.clone());
}
}
pub(crate) fn update_with_ready(&mut self, event: &ReadyEvent) {
let mut ready = event.ready.clone();
for guild in ready.guilds {
match guild {
GuildStatus::Offline(unavailable) => {
self.guilds.remove(&unavailable.id);
self.unavailable_guilds.insert(unavailable.id);
},
GuildStatus::OnlineGuild(guild) => {
self.unavailable_guilds.remove(&guild.id);
self.guilds.insert(guild.id, Arc::new(RwLock::new(guild)));
},
GuildStatus::OnlinePartialGuild(_) => {},
}
}
for (channel_id, channel) in ready.private_channels {
match channel {
Channel::Group(group) => {
self.groups.insert(channel_id, group);
},
Channel::Private(channel) => {
self.private_channels.insert(channel_id, channel);
},
Channel::Guild(guild) => warn!("Got a guild in DMs: {:?}", guild),
}
}
for (user_id, presence) in &mut ready.presences {
if let Some(ref user) = presence.user {
self.update_user_entry(&user.read().unwrap());
}
presence.user = self.users.get(user_id).cloned();
}
self.presences.extend(ready.presences);
self.shard_count = ready.shard.map_or(1, |s| s[1]);
self.user = ready.user;
}
pub(crate) fn update_with_user_update(&mut self, event: &UserUpdateEvent) -> CurrentUser {
mem::replace(&mut self.user, event.current_user.clone())
}
pub(crate) fn update_with_voice_state_update(&mut self, event: &VoiceStateUpdateEvent) {
if let Some(guild_id) = event.guild_id {
if let Some(guild) = self.guilds.get_mut(&guild_id) {
let mut guild = guild.write().unwrap();
if event.voice_state.channel_id.is_some() {
{
let finding = guild.voice_states.get_mut(&event.voice_state.user_id);
if let Some(srv_state) = finding {
srv_state.clone_from(&event.voice_state);
return;
}
}
guild.voice_states.insert(event.voice_state.user_id, event.voice_state.clone());
} else {
guild.voice_states.remove(&event.voice_state.user_id);
}
}
return;
}
}
fn update_user_entry(&mut self, user: &User) {
match self.users.entry(user.id) {
Entry::Vacant(e) => {
e.insert(Arc::new(RwLock::new(user.clone())));
},
Entry::Occupied(mut e) => {
e.get_mut().write().unwrap().clone_from(user);
}
}
}
}
impl Default for Cache {
fn default() -> Cache {
Cache {
channels: HashMap::default(),
groups: HashMap::default(),
guilds: HashMap::default(),
notes: HashMap::default(),
presences: HashMap::default(),
private_channels: HashMap::default(),
shard_count: 1,
unavailable_guilds: HashSet::default(),
user: CurrentUser {
avatar: None,
bot: false,
discriminator: 0,
email: None,
id: UserId(0),
mfa_enabled: false,
name: String::default(),
verified: false,
},
users: HashMap::default(),
}
}
}