Java tutorial
/* * Copyright 2015-2017 Austin Keener & Michael Ritter & Florian Spie * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.dv8tion.jda.core.handle; import gnu.trove.TDecorators; import gnu.trove.list.TLongList; import gnu.trove.list.linked.TLongLinkedList; import gnu.trove.map.TLongObjectMap; import net.dv8tion.jda.client.entities.impl.GroupImpl; import net.dv8tion.jda.client.events.group.update.GroupUpdateIconEvent; import net.dv8tion.jda.client.events.group.update.GroupUpdateNameEvent; import net.dv8tion.jda.client.events.group.update.GroupUpdateOwnerEvent; import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.entities.impl.*; import net.dv8tion.jda.core.events.channel.text.update.*; import net.dv8tion.jda.core.events.channel.voice.update.*; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class ChannelUpdateHandler extends SocketHandler { public ChannelUpdateHandler(JDAImpl api) { super(api); } @Override protected Long handleInternally(JSONObject content) { ChannelType type = ChannelType.fromId(content.getInt("type")); if (type == ChannelType.GROUP) { handleGroup(content); return null; } List<IPermissionHolder> changed = new ArrayList<>(); List<IPermissionHolder> contained = new ArrayList<>(); final long channelId = content.getLong("id"); final int position = content.getInt("position"); final String name = content.getString("name"); final boolean nsfw = !content.isNull("nsfw") && content.getBoolean("nsfw"); JSONArray permOverwrites = content.getJSONArray("permission_overwrites"); switch (type) { case TEXT: { String topic = content.isNull("topic") ? null : content.getString("topic"); TextChannelImpl textChannel = (TextChannelImpl) api.getTextChannelMap().get(channelId); if (textChannel == null) { api.getEventCache().cache(EventCache.Type.CHANNEL, channelId, () -> handle(responseNumber, allContent)); EventCache.LOG.debug( "CHANNEL_UPDATE attempted to update a TextChannel that does not exist. JSON: " + content); return null; } //If any properties changed, update the values and fire the proper events. final String oldName = textChannel.getName(); final String oldTopic = textChannel.getTopic(); final int oldPosition = textChannel.getPositionRaw(); final boolean oldNsfw = textChannel.isNSFW(); if (!Objects.equals(oldName, name)) { textChannel.setName(name); api.getEventManager() .handle(new TextChannelUpdateNameEvent(api, responseNumber, textChannel, oldName)); } if (!Objects.equals(oldTopic, topic)) { textChannel.setTopic(topic); api.getEventManager() .handle(new TextChannelUpdateTopicEvent(api, responseNumber, textChannel, oldTopic)); } if (oldPosition != position) { textChannel.setRawPosition(position); api.getEventManager() .handle(new TextChannelUpdatePositionEvent(api, responseNumber, textChannel, oldPosition)); } if (oldNsfw != nsfw) { textChannel.setNSFW(nsfw); api.getEventManager() .handle(new TextChannelUpdateNSFWEvent(api, responseNumber, textChannel, nsfw)); } applyPermissions(textChannel, content, permOverwrites, contained, changed); //If this update modified permissions in any way. if (!changed.isEmpty()) { api.getEventManager() .handle(new TextChannelUpdatePermissionsEvent(api, responseNumber, textChannel, changed)); } break; //Finish the TextChannelUpdate case } case VOICE: { VoiceChannelImpl voiceChannel = (VoiceChannelImpl) api.getVoiceChannelMap().get(channelId); int userLimit = content.getInt("user_limit"); int bitrate = content.getInt("bitrate"); if (voiceChannel == null) { api.getEventCache().cache(EventCache.Type.CHANNEL, channelId, () -> handle(responseNumber, allContent)); EventCache.LOG.debug( "CHANNEL_UPDATE attempted to update a VoiceChannel that does not exist. JSON: " + content); return null; } //If any properties changed, update the values and fire the proper events. final String oldName = voiceChannel.getName(); final int oldPosition = voiceChannel.getPositionRaw(); final int oldLimit = voiceChannel.getUserLimit(); final int oldBitrate = voiceChannel.getBitrate(); if (!Objects.equals(oldName, name)) { voiceChannel.setName(name); api.getEventManager() .handle(new VoiceChannelUpdateNameEvent(api, responseNumber, voiceChannel, oldName)); } if (oldPosition != position) { voiceChannel.setRawPosition(position); api.getEventManager().handle( new VoiceChannelUpdatePositionEvent(api, responseNumber, voiceChannel, oldPosition)); } if (oldLimit != userLimit) { voiceChannel.setUserLimit(userLimit); api.getEventManager() .handle(new VoiceChannelUpdateUserLimitEvent(api, responseNumber, voiceChannel, oldLimit)); } if (oldBitrate != bitrate) { voiceChannel.setBitrate(bitrate); api.getEventManager() .handle(new VoiceChannelUpdateBitrateEvent(api, responseNumber, voiceChannel, oldBitrate)); } applyPermissions(voiceChannel, content, permOverwrites, contained, changed); //If this update modified permissions in any way. if (!changed.isEmpty()) { api.getEventManager() .handle(new VoiceChannelUpdatePermissionsEvent(api, responseNumber, voiceChannel, changed)); } break; //Finish the VoiceChannelUpdate case } default: throw new IllegalArgumentException( "CHANNEL_UPDATE provided an unrecognized channel type JSON: " + content); } return null; } private long getIdLong(IPermissionHolder permHolder) { if (permHolder instanceof Member) return ((Member) permHolder).getUser().getIdLong(); else return ((Role) permHolder).getIdLong(); } private void applyPermissions(AbstractChannelImpl<?> channel, JSONObject content, JSONArray permOverwrites, List<IPermissionHolder> contained, List<IPermissionHolder> changed) { //Determines if a new PermissionOverride was created or updated. //If a PermissionOverride was created or updated it stores it in the proper Map to be reported by the Event. for (int i = 0; i < permOverwrites.length(); i++) { handlePermissionOverride(permOverwrites.getJSONObject(i), channel, content, changed, contained); } //Check if any overrides were deleted because of this event. //Get the current overrides. (we copy them to a new list because the Set returned is backed by the Map, meaning our removes would remove from the Map. Not good. //Loop through all of the json defined overrides. If we find a match, remove the User or Role from our lists. //Any entries remaining in these lists after this for loop is over will be removed from the Channel's overrides. final TLongList toRemove = new TLongLinkedList(); final TLongObjectMap<PermissionOverride> overridesMap = channel.getOverrideMap(); TDecorators.wrap(overridesMap.keySet()).stream().map(id -> mapPermissionHolder(id, channel.getGuild())) .filter(Objects::nonNull).filter(permHolder -> !contained.contains(permHolder)) .forEach(permHolder -> { changed.add(permHolder); toRemove.add(getIdLong(permHolder)); }); toRemove.forEach((id) -> { overridesMap.remove(id); return true; }); } private IPermissionHolder mapPermissionHolder(long id, Guild guild) { final Role holder = guild.getRoleById(id); return holder == null ? guild.getMemberById(id) : holder; } private void handlePermissionOverride(JSONObject override, AbstractChannelImpl<?> channel, JSONObject content, List<IPermissionHolder> changedPermHolders, List<IPermissionHolder> containedPermHolders) { final long id = override.getLong("id"); final long allow = override.getLong("allow"); final long deny = override.getLong("deny"); final IPermissionHolder permHolder; switch (override.getString("type")) { case "role": { permHolder = channel.getGuild().getRoleById(id); if (permHolder == null) { api.getEventCache().cache(EventCache.Type.ROLE, id, () -> handlePermissionOverride(override, channel, content, changedPermHolders, containedPermHolders)); EventCache.LOG.debug( "CHANNEL_UPDATE attempted to create or update a PermissionOverride for a Role that doesn't exist! RoleId: " + id + " JSON: " + content); return; } break; } case "member": { permHolder = channel.getGuild().getMemberById(id); if (permHolder == null) { api.getEventCache().cache(EventCache.Type.USER, id, () -> handlePermissionOverride(override, channel, content, changedPermHolders, containedPermHolders)); EventCache.LOG.debug( "CHANNEL_UPDATE attempted to create or update a PermissionOverride for Member that doesn't exist in this Guild! MemberId: " + id + " JSON: " + content); return; } break; } default: throw new IllegalArgumentException( "CHANNEL_UPDATE provided an unrecognized PermissionOverride type. JSON: " + content); } PermissionOverrideImpl permOverride = (PermissionOverrideImpl) channel.getOverrideMap().get(id); if (permOverride == null) //Created { api.getEntityBuilder().createPermissionOverride(override, channel); changedPermHolders.add(permHolder); } else if (permOverride.getAllowedRaw() != allow || permOverride.getDeniedRaw() != deny) //Updated { permOverride.setAllow(allow); permOverride.setDeny(deny); changedPermHolders.add(permHolder); } containedPermHolders.add(permHolder); } private void handleGroup(JSONObject content) { final long groupId = content.getLong("id"); final long ownerId = content.getLong("owner_id"); final String name = content.isNull("name") ? null : content.getString("name"); final String iconId = content.isNull("icon") ? null : content.getString("icon"); GroupImpl group = (GroupImpl) api.asClient().getGroupById(groupId); if (group == null) { api.getEventCache().cache(EventCache.Type.CHANNEL, groupId, () -> handle(responseNumber, allContent)); EventCache.LOG.debug("Received CHANNEL_UPDATE for a group that was not yet cached. JSON: " + content); return; } final User owner = group.getUserMap().get(ownerId); final User oldOwner = group.getOwner(); final String oldName = group.getName(); final String oldIconId = group.getIconId(); if (owner == null) { EventCache.LOG.warn( "Received CHANNEL_UPDATE for a group with an owner_id for a user that is not cached. owner_id: " + ownerId); } else { if (!Objects.equals(owner, oldOwner)) { group.setOwner(owner); api.getEventManager().handle(new GroupUpdateOwnerEvent(api, responseNumber, group, oldOwner)); } } if (!Objects.equals(name, oldName)) { group.setName(name); api.getEventManager().handle(new GroupUpdateNameEvent(api, responseNumber, group, oldName)); } if (!Objects.equals(iconId, oldIconId)) { group.setIconId(iconId); api.getEventManager().handle(new GroupUpdateIconEvent(api, responseNumber, group, oldIconId)); } } }