Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GuildImpl#invalidate #1227

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.Region;
import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.exceptions.HierarchyException;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
Expand Down Expand Up @@ -1314,6 +1315,56 @@ private void checkRoles(Collection<Role> roles, String type, String preposition)
});
}

public void invalidate()
{
api.getGuildsView().remove(id);

SnowflakeCacheViewImpl<? extends GuildChannel> textView = api.getTextChannelsView();
SnowflakeCacheViewImpl<? extends GuildChannel> voiceView = api.getVoiceChannelsView();
SnowflakeCacheViewImpl<? extends GuildChannel> storeView = api.getStoreChannelsView();
SnowflakeCacheViewImpl<? extends GuildChannel> categoryView = api.getCategoriesView();
try (UnlockHook h = textView.writeLock())
{
textChannelCache.acceptStream(stream ->
stream.mapToLong(ISnowflake::getIdLong)
.forEach(textView::remove)
);
}
try (UnlockHook h = voiceView.writeLock())
{
categoryCache.acceptStream(stream ->
stream.mapToLong(ISnowflake::getIdLong)
.forEach(voiceView::remove)
);
}
try (UnlockHook h = storeView.writeLock())
{
storeChannelCache.acceptStream(stream ->
stream.mapToLong(ISnowflake::getIdLong)
.forEach(storeView::remove)
);
}
try (UnlockHook h = categoryView.writeLock())
{
categoryCache.acceptStream(stream ->
stream.mapToLong(ISnowflake::getIdLong)
.forEach(categoryView::remove)
);
}

EntityBuilder entityBuilder = api.getEntityBuilder();
getMembers().stream()
.map(MemberImpl.class::cast)
.forEach(member -> entityBuilder.updateMemberCache(member, true));

api.getClient().removeAudioConnection(id);
final AbstractCacheView<AudioManager> audioManagerView = getJDA().getAudioManagersView();
final AudioManagerImpl manager = (AudioManagerImpl) audioManagerView.get(id); //read-lock access/release
if (manager != null)
manager.closeAudioConnection(ConnectionStatus.DISCONNECTED_REMOVED_FROM_GUILD); //connection-lock access/release
audioManagerView.remove(id); //write-lock access/release
}

// ---- Setters -----

public GuildImpl setAvailable(boolean available)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,12 @@

package net.dv8tion.jda.internal.handle;

import gnu.trove.set.TLongSet;
import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.guild.GuildLeaveEvent;
import net.dv8tion.jda.api.events.guild.GuildUnavailableEvent;
import net.dv8tion.jda.api.managers.AudioManager;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.GuildImpl;
import net.dv8tion.jda.internal.entities.PrivateChannelImpl;
import net.dv8tion.jda.internal.entities.UserImpl;
import net.dv8tion.jda.internal.managers.AudioManagerImpl;
import net.dv8tion.jda.internal.requests.WebSocketClient;
import net.dv8tion.jda.internal.utils.UnlockHook;
import net.dv8tion.jda.internal.utils.cache.AbstractCacheView;
import net.dv8tion.jda.internal.utils.cache.SnowflakeCacheViewImpl;

public class GuildDeleteHandler extends SocketHandler
{
Expand Down Expand Up @@ -63,70 +53,8 @@ protected Long handleInternally(DataObject content)
if (setupController.isUnavailable(id) && unavailable)
return null;

//Remove everything from global cache
// this prevents some race-conditions for getting audio managers from guilds
SnowflakeCacheViewImpl<Guild> guildView = getJDA().getGuildsView();
SnowflakeCacheViewImpl<StoreChannel> storeView = getJDA().getStoreChannelsView();
SnowflakeCacheViewImpl<TextChannel> textView = getJDA().getTextChannelsView();
SnowflakeCacheViewImpl<VoiceChannel> voiceView = getJDA().getVoiceChannelsView();
SnowflakeCacheViewImpl<Category> categoryView = getJDA().getCategoriesView();
guildView.remove(id);
try (UnlockHook hook = storeView.writeLock())
{
guild.getStoreChannelCache()
.forEachUnordered(chan -> storeView.getMap().remove(chan.getIdLong()));
}
try (UnlockHook hook = textView.writeLock())
{
guild.getTextChannelCache()
.forEachUnordered(chan -> textView.getMap().remove(chan.getIdLong()));
}
try (UnlockHook hook = voiceView.writeLock())
{
guild.getVoiceChannelCache()
.forEachUnordered(chan -> voiceView.getMap().remove(chan.getIdLong()));
}
try (UnlockHook hook = categoryView.writeLock())
{
guild.getCategoryCache()
.forEachUnordered(chan -> categoryView.getMap().remove(chan.getIdLong()));
}

// Clear audio connection
getJDA().getClient().removeAudioConnection(id);
final AbstractCacheView<AudioManager> audioManagerView = getJDA().getAudioManagersView();
final AudioManagerImpl manager = (AudioManagerImpl) audioManagerView.get(id); //read-lock access/release
if (manager != null)
manager.closeAudioConnection(ConnectionStatus.DISCONNECTED_REMOVED_FROM_GUILD); //connection-lock access/release
audioManagerView.remove(id); //write-lock access/release

//cleaning up all users that we do not share a guild with anymore
// Anything left in memberIds will be removed from the main userMap
//Use a new HashSet so that we don't actually modify the Member map so it doesn't affect Guild#getMembers for the leave event.
TLongSet memberIds = guild.getMembersView().keySet(); // copies keys
getJDA().getGuildCache().stream()
.map(GuildImpl.class::cast)
.forEach(g -> memberIds.removeAll(g.getMembersView().keySet()));
// Remember, everything left in memberIds is removed from the userMap
SnowflakeCacheViewImpl<User> userView = getJDA().getUsersView();
try (UnlockHook hook = userView.writeLock())
{
long selfId = getJDA().getSelfUser().getIdLong();
memberIds.forEach(memberId -> {
if (memberId == selfId)
return true; // don't remove selfUser from cache
UserImpl user = (UserImpl) userView.getMap().remove(memberId);
if (user.hasPrivateChannel())
{
PrivateChannelImpl priv = (PrivateChannelImpl) user.getPrivateChannel();
user.setFake(true);
getJDA().getFakeUserMap().put(user.getIdLong(), user);
getJDA().getFakePrivateChannelMap().put(priv.getIdLong(), priv);
}
getJDA().getEventCache().clear(EventCache.Type.USER, memberId);
return true;
});
}
// Detach the guild cache from the global cache (also removes users if necessary)
guild.invalidate();

if (unavailable)
{
Expand Down