All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dv8tion.jda.internal.handle.PresenceUpdateHandler Maven / Gradle / Ivy

Go to download

Java wrapper for the popular chat & VOIP service: Discord https://discord.com

There is a newer version: 5.1.0
Show newest version
/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * 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.internal.handle;

import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.entities.ClientType;
import net.dv8tion.jda.api.events.user.UserActivityEndEvent;
import net.dv8tion.jda.api.events.user.UserActivityStartEvent;
import net.dv8tion.jda.api.events.user.update.UserUpdateActivitiesEvent;
import net.dv8tion.jda.api.events.user.update.UserUpdateActivityOrderEvent;
import net.dv8tion.jda.api.events.user.update.UserUpdateOnlineStatusEvent;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import net.dv8tion.jda.api.utils.cache.CacheView;
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.EntityBuilder;
import net.dv8tion.jda.internal.entities.GuildImpl;
import net.dv8tion.jda.internal.entities.MemberImpl;
import net.dv8tion.jda.internal.entities.MemberPresenceImpl;
import net.dv8tion.jda.internal.utils.Helpers;
import net.dv8tion.jda.internal.utils.JDALogger;
import net.dv8tion.jda.internal.utils.UnlockHook;
import org.slf4j.Logger;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

public class PresenceUpdateHandler extends SocketHandler
{
    private static final Logger log = JDALogger.getLog(PresenceUpdateHandler.class);

    public PresenceUpdateHandler(JDAImpl api)
    {
        super(api);
    }

    @Override
    protected Long handleInternally(DataObject content)
    {
        // Ignore events for relationships, presences are guild only to us
        if (content.isNull("guild_id"))
        {
            log.debug("Received PRESENCE_UPDATE without guild_id. Ignoring event.");
            return null;
        }
        if (api.getCacheFlags().stream().noneMatch(CacheFlag::isPresence))
            return null;

        //Do a pre-check to see if this is for a Guild, and if it is, if the guild is currently locked or not cached.
        final long guildId = content.getUnsignedLong("guild_id");
        if (getJDA().getGuildSetupController().isLocked(guildId))
            return guildId;
        GuildImpl guild = (GuildImpl) getJDA().getGuildById(guildId);
        if (guild == null)
        {
            getJDA().getEventCache().cache(EventCache.Type.GUILD, guildId, responseNumber, allContent, this::handle);
            EventCache.LOG.debug("Received a PRESENCE_UPDATE for a guild that is not yet cached! GuildId:{} UserId: {}",
                                 guildId, content.getObject("user").get("id"));
            return null;
        }

        CacheView.SimpleCacheView presences = guild.getPresenceView();
        if (presences == null)
            return null; // technically this should be impossible
        DataObject jsonUser = content.getObject("user");
        final long userId = jsonUser.getUnsignedLong("id");
        MemberImpl member = (MemberImpl) guild.getMemberById(userId);
        MemberPresenceImpl presence = presences.get(userId);
        OnlineStatus status = OnlineStatus.fromKey(content.getString("status"));
        if (status == OnlineStatus.OFFLINE)
            presences.remove(userId);
        if (presence == null)
        {
            presence = new MemberPresenceImpl();
            if (status != OnlineStatus.OFFLINE)
            {
                try (UnlockHook lock = presences.writeLock())
                {
                    presences.getMap().put(userId, presence);
                }
            }
        }

        //Now that we've update the User's info, lets see if we need to set the specific Presence information.
        // This is stored in the Member objects.
        //We set the activities to null to prevent parsing if the cache was disabled
        final DataArray activityArray = !getJDA().isCacheFlagSet(CacheFlag.ACTIVITY) || content.isNull("activities") ? null : content.getArray("activities");
        List newActivities = new ArrayList<>();
        boolean parsedActivity = parseActivities(userId, activityArray, newActivities);

        if (getJDA().isCacheFlagSet(CacheFlag.CLIENT_STATUS) && !content.isNull("client_status"))
            handleClientStatus(content, presence);

        // Check if activities changed
        if (parsedActivity)
            handleActivities(newActivities, member, presence);

        //The member is already cached, so modify the presence values and fire events as needed.

        if (presence.getOnlineStatus() != status)
        {
            OnlineStatus oldStatus = presence.getOnlineStatus();
            presence.setOnlineStatus(status);
            if (member != null)
            {
                getJDA().getEntityBuilder().updateMemberCache(member);
                getJDA().handleEvent(
                    new UserUpdateOnlineStatusEvent(
                        getJDA(), responseNumber,
                        member, oldStatus));
            }
        }
        return null;
    }

    private boolean parseActivities(long userId, DataArray activityArray, List newActivities)
    {
        boolean parsedActivity = false;
        try
        {
            if (activityArray != null)
            {
                for (int i = 0; i < activityArray.length(); i++)
                    newActivities.add(EntityBuilder.createActivity(activityArray.getObject(i)));
                parsedActivity = true;
            }
        }
        catch (Exception ex)
        {
            if (EntityBuilder.LOG.isDebugEnabled())
                EntityBuilder.LOG.warn("Encountered exception trying to parse a presence! UserID: {} JSON: {}", userId, activityArray, ex);
            else
                EntityBuilder.LOG.warn("Encountered exception trying to parse a presence! UserID: {} Message: {} Enable debug for details", userId, ex.getMessage());
        }
        return parsedActivity;
    }

    private void handleActivities(List newActivities, @Nullable MemberImpl member, MemberPresenceImpl presence)
    {
        List oldActivities = presence.getActivities();
        presence.setActivities(newActivities);
        if (member == null)
            return;
        boolean unorderedEquals = Helpers.deepEqualsUnordered(oldActivities, newActivities);
        if (unorderedEquals)
        {
            boolean deepEquals = Helpers.deepEquals(oldActivities, newActivities);
            if (!deepEquals)
            {
                getJDA().handleEvent(
                    new UserUpdateActivityOrderEvent(
                        getJDA(), responseNumber,
                        oldActivities, member));
            }
        }
        else
        {
            getJDA().getEntityBuilder().updateMemberCache(member);
            List stoppedActivities = new ArrayList<>(oldActivities); // create modifiable copy
            List startedActivities = new ArrayList<>();
            for (Activity activity : newActivities)
            {
                if (!stoppedActivities.remove(activity))
                    startedActivities.add(activity);
            }

            for (Activity activity : startedActivities)
            {
                getJDA().handleEvent(
                    new UserActivityStartEvent(
                        getJDA(), responseNumber,
                        member, activity));
            }

            for (Activity activity : stoppedActivities)
            {
                getJDA().handleEvent(
                    new UserActivityEndEvent(
                        getJDA(), responseNumber,
                        member, activity));
            }

            getJDA().handleEvent(
                new UserUpdateActivitiesEvent(
                    getJDA(), responseNumber,
                    member, oldActivities));
        }
    }

    private void handleClientStatus(DataObject content, MemberPresenceImpl presence)
    {
        DataObject json = content.getObject("client_status");
        EnumSet types = EnumSet.of(ClientType.UNKNOWN);
        for (String key : json.keys())
        {
            ClientType type = ClientType.fromKey(key);
            types.add(type);
            String raw = String.valueOf(json.get(key));
            OnlineStatus clientStatus = OnlineStatus.fromKey(raw);
            presence.setOnlineStatus(type, clientStatus);
        }
        for (ClientType type : EnumSet.complementOf(types))
            presence.setOnlineStatus(type, null); // set remaining types to offline
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy