Exemple #1
0
        private void Reset()
        {
            SessionId = null;

            if (Config.Cache)
            {
                GuildCache.Clear();
                PrivateChannels.Clear();
                VoiceStates.Clear();
                GuildSettings.Clear();
                PrivateChannelSettings.Clear();
            }
        }
        private void Reset()
        {
            SessionId = null;

            foreach (var voiceSession in VoiceSessions)
            {
                voiceSession.Session.Disconnect();
            }

            VoiceSessions.Clear();

            if (Config.Cache)
            {
                GuildCache.Clear();
                PrivateChannels.Clear();
                PrivateVoiceStates.Clear();
                ClientGuildSettings.Clear();
            }
        }
        private void SocketDataReceived(object sender, WebSocketSharp.MessageEventArgs result)
        {
            GatewayResponse payload = result.Data.Deserialize <GatewayResponse>();

            Sequence = payload.Sequence;

            try
            {
                switch (payload.Opcode)
                {
                case GatewayOpcode.Event:
                    /*
                     * Console.WriteLine(payload.Title);
                     *
                     * File.AppendAllText("Debug.log", $"{payload.Title}: {payload.Data}\n");
                     */
                    switch (payload.Title)
                    {
                    case "READY":
                        Login login = payload.DeserializeEx <Login>().SetClient(this);

                        this.User         = login.User;
                        this.UserSettings = login.Settings;
                        this.SessionId    = login.SessionId;

                        if (Config.Cache)
                        {
                            if (this.User.Type == DiscordUserType.User)
                            {
                                PrivateChannels = login.PrivateChannels;

                                foreach (var guild in login.Guilds)
                                {
                                    GuildCache.Add(guild.Id, guild.ToSocketGuild());
                                }

                                foreach (var notifSettings in login.ClientGuildSettings)
                                {
                                    if (notifSettings["guild_id"].ToObject <JValue>().Value != null)
                                    {
                                        ClientGuildSettings notifs = notifSettings.ToObject <ClientGuildSettings>().SetClient(this);

                                        ClientGuildSettings.Add(notifs.Guild.Id, notifs);
                                    }
                                }
                            }
                            else
                            {
                                PrivateChannels.Clear();
                                GuildCache.Clear();
                                ClientGuildSettings.Clear();
                            }
                        }

                        LoggedIn = true;

                        Task.Run(() => OnLoggedIn?.Invoke(this, new LoginEventArgs(login)));
                        break;

                    case "USER_SETTINGS_UPDATE":
                        if (UserSettings != null)         // for some reason this is null sometimes :thinking:
                        {
                            var update = payload.Deserialize <JObject>();

                            foreach (var field in UserSettings.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
                            {
                                foreach (var attr in field.CustomAttributes)
                                {
                                    if (attr.AttributeType == typeof(JsonPropertyAttribute))
                                    {
                                        string propertyName = attr.ConstructorArguments[0].Value.ToString();

                                        if (update.ContainsKey(propertyName))
                                        {
                                            field.SetValue(UserSettings, update.GetValue(propertyName).ToObject(field.FieldType));
                                        }

                                        break;
                                    }
                                }
                            }

                            foreach (var property in UserSettings.GetType().GetProperties())
                            {
                                foreach (var attr in property.CustomAttributes)
                                {
                                    if (attr.AttributeType == typeof(JsonPropertyAttribute))
                                    {
                                        string propertyName = attr.ConstructorArguments[0].Value.ToString();

                                        if (update.ContainsKey(propertyName))
                                        {
                                            property.SetValue(UserSettings, update.GetValue(propertyName).ToObject(property.PropertyType));
                                        }

                                        break;
                                    }
                                }
                            }

                            Task.Run(() => OnSettingsUpdated?.Invoke(this, new DiscordSettingsEventArgs(UserSettings)));
                        }
                        break;

                    case "USER_GUILD_SETTINGS_UPDATE":
                        if (Config.Cache)
                        {
                            ClientGuildSettings notifications = payload.Deserialize <ClientGuildSettings>();

                            if (notifications.Guild != null)
                            {
                                if (ClientGuildSettings.ContainsKey(notifications.Guild.Id))
                                {
                                    ClientGuildSettings[notifications.Guild.Id] = notifications;
                                }
                                else
                                {
                                    ClientGuildSettings.Add(notifications.Guild.Id, notifications);
                                }
                            }
                        }
                        break;

                    case "USER_UPDATE":
                        DiscordUser user = payload.Deserialize <DiscordUser>().SetClient(this);

                        if (user.Id == User.Id)
                        {
                            User.Update(user);
                        }

                        if (Config.Cache)
                        {
                            foreach (var dm in PrivateChannels)
                            {
                                bool updated = false;

                                foreach (var recipient in dm.Recipients)
                                {
                                    if (recipient.Id == user.Id)
                                    {
                                        recipient.Update(user);

                                        updated = true;

                                        break;
                                    }
                                }

                                if (updated)         // this is somewhat resource intensive, so let's reduce the uses as much as possible
                                {
                                    dm.UpdateSelfJson();
                                }
                            }
                        }

                        Task.Run(() => OnUserUpdated?.Invoke(this, new UserEventArgs(user)));
                        break;

                    case "GUILD_MEMBER_LIST_UPDATE":
                        var args = new GuildMembersEventArgs(payload.Deserialize <GatewayUserMemberQueryResponse>());

                        foreach (var member in args.Members)
                        {
                            member.SetClient(this);
                            member.GuildId = args.GuildId;
                        }

                        OnGuildMembersReceived?.Invoke(this, args);
                        break;

                    case "GUILD_CREATE":
                    {
                        SocketGuild guild = payload.DeserializeEx <SocketGuild>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache.Remove(guild.Id);

                            GuildCache.Add(guild.Id, guild);
                        }

                        Task.Run(() => OnJoinedGuild?.Invoke(this, new SocketGuildEventArgs(guild, Lurking.HasValue && Lurking.Value == guild.Id)));
                    }
                    break;

                    case "GUILD_UPDATE":
                    {
                        DiscordGuild guild = payload.Deserialize <DiscordGuild>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[guild].Update(guild);
                        }

                        Task.Run(() => OnGuildUpdated?.Invoke(this, new GuildEventArgs(guild)));
                    }
                    break;

                    case "GUILD_DELETE":
                    {
                        UnavailableGuild guild = payload.Deserialize <UnavailableGuild>();

                        if (Lurking.HasValue && Lurking.Value == guild.Id)
                        {
                            Lurking = null;
                        }

                        if (Config.Cache)
                        {
                            if (guild.Unavailable)
                            {
                                GuildCache[guild.Id].Unavailable = true;
                            }
                            else
                            {
                                GuildCache.Remove(guild.Id);
                            }

                            ClientGuildSettings.Remove(guild.Id);
                        }

                        Task.Run(() => OnLeftGuild?.Invoke(this, new GuildUnavailableEventArgs(guild)));
                    }
                    break;

                    case "GUILD_MEMBER_ADD":
                        Task.Run(() => OnUserJoinedGuild?.Invoke(this, new GuildMemberEventArgs(payload.Deserialize <GuildMemberUpdate>().SetClient(this).Member)));
                        break;

                    case "GUILD_MEMBER_REMOVE":
                        Task.Run(() => OnUserLeftGuild?.Invoke(this, new GuildMemberEventArgs(payload.Deserialize <GuildMemberUpdate>().SetClient(this).Member)));
                        break;

                    case "GUILD_MEMBER_UPDATE":
                        Task.Run(() => OnGuildMemberUpdated?.Invoke(this, new GuildMemberEventArgs(payload.Deserialize <GuildMember>().SetClient(this))));
                        break;

                    case "GUILD_MEMBERS_CHUNK":
                        Task.Run(() => OnGuildMembersReceived?.Invoke(this, new GuildMembersEventArgs(payload.Deserialize <GuildMemberList>().SetClient(this))));
                        break;

                    case "GIFT_CODE_CREATE":
                        Task.Run(() => OnGiftCodeCreated?.Invoke(this, payload.Deserialize <GiftCodeCreatedEventArgs>()));
                        break;

                    case "PRESENCE_UPDATE":
                        Task.Run(() => OnUserPresenceUpdated?.Invoke(this, new PresenceUpdatedEventArgs(payload.Deserialize <DiscordPresence>().SetClient(this))));
                        break;

                    case "VOICE_STATE_UPDATE":
                        DiscordVoiceState newState = payload.Deserialize <DiscordVoiceState>().SetClient(this);

                        // TODO: figure out how the client gets the initial voice states

                        if (Config.Cache)
                        {
                            List <DiscordVoiceState> voiceStates;

                            if (newState.Guild == null)
                            {
                                voiceStates = PrivateVoiceStates[newState.Channel.Id];
                            }
                            else
                            {
                                voiceStates = GuildCache[newState.Guild]._voiceStates;
                            }

                            int i = voiceStates.FindIndex(s => s.UserId == newState.UserId);

                            if (i > -1)
                            {
                                voiceStates[i] = newState;
                            }
                            else
                            {
                                voiceStates.Add(newState);
                            }
                        }

                        Task.Run(() => OnVoiceStateUpdated?.Invoke(this, new VoiceStateEventArgs(newState)));
                        break;

                    case "VOICE_SERVER_UPDATE":
                        Task.Run(() => OnVoiceServer?.Invoke(this, payload.Deserialize <DiscordVoiceServer>()));
                        break;

                    case "GUILD_ROLE_CREATE":
                    {
                        DiscordRole role = payload.Deserialize <RoleUpdate>().Role.SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[role.GuildId]._roles.Add(role);
                        }

                        Task.Run(() => OnRoleCreated?.Invoke(this, new RoleEventArgs(role)));
                    }
                    break;

                    case "GUILD_ROLE_UPDATE":
                    {
                        DiscordRole role = payload.Deserialize <RoleUpdate>().Role.SetClient(this);

                        if (Config.Cache)
                        {
                            var roles = GuildCache[role.GuildId]._roles;
                            roles[roles.FindIndex(r => r.Id == role.Id)] = role;
                        }

                        Task.Run(() => OnRoleUpdated?.Invoke(this, new RoleEventArgs(role)));
                    }
                    break;

                    case "GUILD_ROLE_DELETE":
                    {
                        DeletedRole role = payload.Deserialize <DeletedRole>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[role.Guild]._roles.RemoveAll(r => r.Id == role.Id);
                        }

                        Task.Run(() => OnRoleDeleted?.Invoke(this, new RoleDeletedEventArgs(role)));
                    }
                    break;

                    case "GUILD_EMOJIS_UPDATE":
                        var emojis = payload.Deserialize <EmojiContainer>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[emojis.GuildId]._emojis = emojis.Emojis.ToList();
                        }

                        Task.Run(() => OnEmojisUpdated?.Invoke(this, new EmojisUpdatedEventArgs(emojis)));
                        break;

                    case "CHANNEL_CREATE":
                    {
                        var channel = payload.DeserializeEx <DiscordChannel>().SetClient(this);

                        if (Config.Cache)
                        {
                            if (channel.Type == ChannelType.DM || channel.Type == ChannelType.Group)
                            {
                                PrivateChannels.Add(channel.ToDMChannel());
                            }
                            else
                            {
                                GuildChannel guildChannel = channel.ToGuildChannel();

                                GuildCache[guildChannel.GuildId]._channels.Add(guildChannel);
                            }
                        }

                        Task.Run(() => OnChannelCreated?.Invoke(this, new ChannelEventArgs(channel)));
                    }
                    break;

                    case "CHANNEL_UPDATE":
                    {
                        var channel = payload.DeserializeEx <DiscordChannel>().SetClient(this);

                        if (Config.Cache)
                        {
                            if (channel.Type == ChannelType.DM || channel.Type == ChannelType.Group)
                            {
                                PrivateChannels[PrivateChannels.FindIndex(c => c.Id == channel.Id)] = channel.ToDMChannel();
                            }
                            else
                            {
                                GuildChannel guildChannel = channel.ToGuildChannel();

                                var channels = GuildCache[guildChannel.GuildId]._channels;

                                channels[channels.FindIndex(c => c.Id == guildChannel.Id)] = guildChannel;
                            }
                        }

                        Task.Run(() => OnChannelUpdated?.Invoke(this, new ChannelEventArgs(channel)));
                    }
                    break;

                    case "CHANNEL_DELETE":
                    {
                        var channel = payload.DeserializeEx <DiscordChannel>().SetClient(this);

                        if (Config.Cache)
                        {
                            if (channel.Type == ChannelType.DM || channel.Type == ChannelType.Group)
                            {
                                PrivateChannels.RemoveAll(c => c.Id == channel.Id);
                            }
                            else
                            {
                                GuildCache[channel.ToGuildChannel().GuildId]._channels.RemoveAll(c => c.Id == channel.Id);
                            }
                        }

                        Task.Run(() => OnChannelDeleted?.Invoke(this, new ChannelEventArgs(channel)));
                    }
                    break;

                    case "TYPING_START":
                        Task.Run(() => OnUserTyping?.Invoke(this, new UserTypingEventArgs(payload.Deserialize <UserTyping>())));
                        break;

                    case "MESSAGE_CREATE":
                        var message = payload.Deserialize <DiscordMessage>().SetClient(this);

                        if (Config.Cache)
                        {
                            try
                            {
                                var channel = PrivateChannels.First(c => c.Id == message.Channel.Id);

                                channel.LastMessageId = message.Id;
                            }
                            catch { }
                        }

                        Task.Run(() => OnMessageReceived?.Invoke(this, new MessageEventArgs(message)));
                        break;

                    case "MESSAGE_UPDATE":
                        Task.Run(() => OnMessageEdited?.Invoke(this, new MessageEventArgs(payload.Deserialize <DiscordMessage>().SetClient(this))));
                        break;

                    case "MESSAGE_DELETE":
                        Task.Run(() => OnMessageDeleted?.Invoke(this, new MessageDeletedEventArgs(payload.Deserialize <DeletedMessage>())));
                        break;

                    case "MESSAGE_REACTION_ADD":
                        Task.Run(() => OnMessageReactionAdded?.Invoke(this, new ReactionEventArgs(payload.Deserialize <MessageReactionUpdate>().SetClient(this))));
                        break;

                    case "MESSAGE_REACTION_REMOVE":
                        Task.Run(() => OnMessageReactionRemoved?.Invoke(this, new ReactionEventArgs(payload.Deserialize <MessageReactionUpdate>().SetClient(this))));
                        break;

                    case "GUILD_BAN_ADD":
                        Task.Run(() => OnUserBanned?.Invoke(this, new BanUpdateEventArgs(payload.Deserialize <BanContainer>().SetClient(this))));
                        break;

                    case "GUILD_BAN_REMOVE":
                        Task.Run(() => OnUserUnbanned?.Invoke(this, new BanUpdateEventArgs(payload.Deserialize <BanContainer>().SetClient(this))));
                        break;

                    case "INVITE_CREATE":
                        Task.Run(() => OnInviteCreated?.Invoke(this, payload.Deserialize <InviteCreatedEventArgs>()));
                        break;

                    case "INVITE_DELETE":
                        Task.Run(() => OnInviteDeleted?.Invoke(this, payload.Deserialize <InviteDeletedEventArgs>()));
                        break;

                    case "RELATIONSHIP_ADD":
                        Task.Run(() => OnRelationshipAdded?.Invoke(this, new RelationshipEventArgs(payload.Deserialize <Relationship>().SetClient(this))));
                        break;

                    case "RELATIONSHIP_REMOVE":
                        Task.Run(() => OnRelationshipRemoved?.Invoke(this, new RelationshipEventArgs(payload.Deserialize <Relationship>().SetClient(this))));
                        break;

                    case "CHANNEL_RECIPIENT_ADD":
                    {
                        var recipUpdate = payload.Deserialize <ChannelRecipientUpdate>().SetClient(this);

                        if (Config.Cache)
                        {
                            foreach (var channel in PrivateChannels)
                            {
                                if (channel.Id == recipUpdate.Channel.Id)
                                {
                                    if (channel._recipients == null)
                                    {
                                        channel._recipients = new List <DiscordUser>();
                                    }

                                    channel._recipients.Add(recipUpdate.User);

                                    channel.UpdateSelfJson();

                                    break;
                                }
                            }
                        }
                    }
                    break;

                    case "CHANNEL_RECIPIENT_REMOVE":
                    {
                        var recipUpdate = payload.Deserialize <ChannelRecipientUpdate>().SetClient(this);

                        if (Config.Cache)
                        {
                            foreach (var channel in PrivateChannels)
                            {
                                if (channel.Id == recipUpdate.Channel.Id)
                                {
                                    if (channel._recipients != null)
                                    {
                                        channel._recipients.RemoveAll(u => u.Id == recipUpdate.User.Id);

                                        channel.UpdateSelfJson();
                                    }

                                    break;
                                }
                            }
                        }
                    }
                    break;

                    case "MESSAGE_ACK":         // triggered whenever another person logged into the account acknowledges a message
                        break;

                    case "SESSIONS_REPLACE":
                        Task.Run(() => OnSessionsUpdated?.Invoke(this, new DiscordSessionsEventArgs(payload.Deserialize <List <DiscordSession> >())));
                        break;

                    case "CALL_CREATE":
                    {
                        JObject obj = payload.Deserialize <JObject>();

                        var call        = obj.ToObject <DiscordCall>().SetClient(this);
                        var voiceStates = obj.Value <IReadOnlyList <DiscordVoiceState> >("voice_states").SetClientsInList(this);

                        PrivateVoiceStates[call.Channel.Id] = voiceStates.ToList();

                        Task.Run(() => OnRinging?.Invoke(this, new RingingEventArgs(call, voiceStates)));
                    }
                    break;

                    case "CALL_UPDATE":
                        Task.Run(() => OnCallUpdated?.Invoke(this, new CallUpdateEventArgs(payload.Deserialize <DiscordCall>().SetClient(this))));
                        break;

                    case "CALL_DELETE":
                        ulong channelId = payload.Deserialize <JObject>().Value <ulong>("channel_id");

                        PrivateVoiceStates.Remove(channelId);

                        Task.Run(() => OnCallEnded?.Invoke(this, channelId));
                        break;

                    case "USER_PREMIUM_GUILD_SUBSCRIPTION_SLOT_UPDATE":
                        Task.Run(() => OnBoostUpdated?.Invoke(this, new NitroBoostUpdatedEventArgs(payload.Deserialize <DiscordNitroBoost>().SetClient(this))));
                        break;
                    }
                    break;

                case GatewayOpcode.InvalidSession:
                    LoggedIn = false;

                    this.LoginToGateway();
                    break;

                case GatewayOpcode.Connected:
                    this.LoginToGateway();

                    Task.Run(() =>
                    {
                        int interval = payload.Deserialize <JObject>().GetValue("heartbeat_interval").ToObject <int>();

                        try
                        {
                            while (true)
                            {
                                this.Send(GatewayOpcode.Heartbeat, this.Sequence);
                                Thread.Sleep(interval);
                            }
                        }
                        catch { }
                    });

                    break;
                }
            }
            catch
            {
            }
        }