Пример #1
0
        private void Connection_OnMessage(DiscordMediaConnection connection, DiscordWebSocketMessage <DiscordMediaOpcode> message)
        {
            switch (message.Opcode)
            {
            case DiscordMediaOpcode.Speaking:
                var state = message.Data.ToObject <DiscordSpeakingState>();

                if (state.UserId.HasValue)
                {
                    _ssrcToUserDictionary[state.SSRC] = state.UserId.Value;
                }
                break;

            case DiscordMediaOpcode.SSRCUpdate:
                SSRCUpdate update = message.Data.ToObject <SSRCUpdate>();
                _ssrcToUserDictionary[update.Audio] = update.UserId;
                break;

            case DiscordMediaOpcode.UserDisconnect:
                ulong userId = message.Data.ToObject <JObject>().Value <ulong>("user_id");

                if (_ssrcToUserDictionary.TryGetKey(userId, out uint ssrc))
                {
                    _ssrcToUserDictionary.Remove(ssrc);
                }
                break;
            }
        }
Пример #2
0
        protected override void HandleMessage(DiscordWebSocketMessage <DiscordMediaOpcode> message)
        {
            if (message.Opcode == DiscordMediaOpcode.SSRCUpdate)
            {
                SSRCUpdate ssrc = message.Data.ToObject <SSRCUpdate>();

                if (!Viewers.Contains(ssrc.UserId))
                {
                    List <ulong> viewers = Viewers.ToList();
                    viewers.Add(ssrc.UserId);
                    Viewers = viewers;
                    OnUserConnected?.Invoke(this, ssrc.UserId);
                }
            }
            else if (message.Opcode == DiscordMediaOpcode.UserDisconnect)
            {
                ulong userId = message.Data.ToObject <JObject>().Value <ulong>("user_id");

                List <ulong> viewers = Viewers.ToList();
                if (viewers.Remove(userId))
                {
                    Viewers = viewers;
                }

                OnUserDisconnected?.Invoke(this, userId);
            }
        }
Пример #3
0
        protected override void HandleMessage(DiscordWebSocketMessage <DiscordMediaOpcode> message)
        {
            switch (message.Opcode)
            {
            case DiscordMediaOpcode.Speaking:
                var state = message.Data.ToObject <DiscordSpeakingState>();

                if (state.UserId.HasValue)
                {
                    _ssrcToUserDictionary[state.SSRC] = state.UserId.Value;
                }
                else
                {
                    state.UserId = _ssrcToUserDictionary[state.SSRC];
                }

                break;

            case DiscordMediaOpcode.SSRCUpdate:     // this is fired whenever a user connects to the channel or updates their ssrc
                SSRCUpdate update = message.Data.ToObject <SSRCUpdate>();

                bool newUser = !_ssrcToUserDictionary.Values.Contains(update.UserId);

                _ssrcToUserDictionary[update.Audio] = update.UserId;

                if (newUser && OnUserConnected != null)
                {
                    Task.Run(() => OnUserConnected.Invoke(this, update.UserId));
                }
                break;

            case DiscordMediaOpcode.UserDisconnect:
                ulong userId = message.Data.ToObject <JObject>().Value <ulong>("user_id");

                if (_ssrcToUserDictionary.TryGetKey(userId, out uint ssrc))
                {
                    _ssrcToUserDictionary.Remove(ssrc);
                }

                if (_receivers.TryGetValue(userId, out IncomingVoiceStream receiver))
                {
                    receiver.Close();
                    _receivers.Remove(receiver.UserId);
                }

                if (OnUserDisconnected != null)
                {
                    Task.Run(() => OnUserDisconnected.Invoke(this, userId));
                }
                break;
            }
        }
Пример #4
0
        private void HandleMessage(object sender, DiscordWebSocketMessage <DiscordMediaOpcode> message)
        {
            switch (message.Opcode)
            {
            case DiscordMediaOpcode.Ready:
                DiscordMediaReady ready = message.Data.ToObject <DiscordMediaReady>();

                SSRC = new DiscordSSRC()
                {
                    Audio = ready.SSRC
                };

                ServerEndpoint = new IPEndPoint(IPAddress.Parse(ready.IP), ready.Port);

                UdpClient = new UdpClient();
                UdpClient.Connect(ServerEndpoint);

                Task.Run(() => StartListener());

                Holepunch();
                break;

            case DiscordMediaOpcode.SessionDescription:
                var description = message.Data.ToObject <DiscordSessionDescription>();

                SecretKey = description.SecretKey;

                State = MediaConnectionState.Ready;
                OnReady?.Invoke(this);
                break;

            case DiscordMediaOpcode.Hello:
                Send(DiscordMediaOpcode.Identify, new DiscordMediaIdentify()
                {
                    ServerId  = _serverId,
                    UserId    = _parentClient.User.Id,
                    SessionId = _parentClient.SessionId,
                    Token     = _server.Token,
                    Video     = true
                });

                StartHeartbeaterAsync(message.Data.Value <int>("heartbeat_interval"));
                break;

            default:
                OnMessage?.Invoke(this, message);
                break;
            }
        }
Пример #5
0
        private static async Task Ws_OnMessage(DiscordWebSocketMessage message)
        {
            if (message.s != null)
            {
                websocketSequenceId = Convert.ToUInt64(message.s);
            }

            Console.WriteLine("{0}\top = {1,3}\t{2,-30}\t{3} chars",
                              DateTime.Now.ToUniversalTime(),
                              message.op,
                              message.t,
                              message.d.Lenght
                              );

            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (message.op)
            {
            case 10:
                int interval = message.d.heartbeat_interval;
                msBetweenPing = interval;
                Dictionary <string, object> helloMessageData;
                if ((sessionID != null) && false)
                {
                    helloMessageData = new Dictionary <string, object>()
                    {
                        ["op"] = 2,
                        ["d"]  = new Dictionary <string, object>()
                        {
                            ["token"]      = Global.options.DiscordBotToken,
                            ["session_id"] = sessionID,
                            ["seq"]        = websocketSequenceId,
                        },
                    };
                }
                else
                {
                    helloMessageData = new Dictionary <string, object>()
                    {
                        ["op"] = 2,
                        ["d"]  = new Dictionary <string, object>()
                        {
                            ["token"]      = Global.options.DiscordBotToken,
                            ["properties"] = new Dictionary <string, object>()
                            {
                                ["$os"] = System.Environment.OSVersion.ToString(),
                            },
                            ["compress"]        = false,
                            ["large_threshold"] = 250,
                        },
                    };
                }

                await SendMessageToWebSocket(helloMessageData);

                break;

            case 11:
                // Incoming ping
                lastIncomingPingTime = DateTime.Now.ToUniversalTime();
                break;

            case 0:
                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (message.t)
                {
                case "READY":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#ready
                    sessionID = message.d.session_id;
                    JsonConvert.SerializeObject(message.d);
                    break;
                }

                case "GUILD_CREATE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#guild-create
                    var guild = JsonConvert.DeserializeObject <EventGuildCreate>(message.dAsString);
                    guilds[guild.id] = guild;
                    if (!channels.ContainsKey(guild.id))
                    {
                        channels[guild.id] =
                            new ConcurrentDictionary <string, EventGuildCreate.EventGuildCreate_Channel>();
                    }

                    foreach (var channel in guild.channels)
                    {
                        channels[guild.id][channel.id] = channel;
                    }

                    break;
                }

                case "MESSAGE_CREATE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#message-create
                    // https://discordapp.com/developers/docs/resources/channel#message-object
                    var messageCreate = JsonConvert.DeserializeObject <EventMessageCreate>(message.dAsString);
                    messageCreate.FixUp();
                    if (messageCreate.type != 0)
                    {
                        break;
                    }

                    if (!messages.ContainsKey(messageCreate.guild_id))
                    {
                        messages[messageCreate.guild_id] = new ConcurrentDictionary <string,
                                                                                     ConcurrentDictionary <string, EventMessageCreate> >();
                    }

                    if (!messages[messageCreate.guild_id].ContainsKey(messageCreate.channel_id))
                    {
                        messages[messageCreate.guild_id][messageCreate.channel_id] =
                            new ConcurrentDictionary <string, EventMessageCreate>();
                    }

                    messages[messageCreate.guild_id][messageCreate.channel_id][messageCreate.id] =
                        messageCreate;
                    WebsocketClientSide.UpdateMessage(messageCreate);

                    Console.WriteLine("channel_id {0} user {1} say: {2}",
                                      messageCreate.channel_id,
                                      messageCreate.author.username,
                                      messageCreate.content
                                      );
                    break;
                }

                case "MESSAGE_UPDATE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#message-update
                    // https://discordapp.com/developers/docs/resources/channel#message-object
                    var messageUpdate = JsonConvert.DeserializeObject <EventMessageCreate>(message.dAsString);
                    if (
                        !messages.ContainsKey(messageUpdate.guild_id) ||
                        !messages[messageUpdate.guild_id].ContainsKey(messageUpdate.channel_id) ||
                        !messages[messageUpdate.guild_id][messageUpdate.channel_id]
                        .ContainsKey(messageUpdate.id)
                        )
                    {
                        // Такого сообщения нет. Возможно, оно было создано раньше. Это не проблема
                        break;
                    }

                    var existedMessage =
                        messages[messageUpdate.guild_id][messageUpdate.channel_id][messageUpdate.id];

                    // При обновлении сообщения Дискорд пропускает контент, если контент не обновляется,
                    // поэтому тут нужен ===null предикат
                    var fields = new[] { "content", "embeds", "attachments", "mention_roles", "mentions" };
                    foreach (var fieldName in fields)
                    {
                        var field    = typeof(EventMessageCreate).GetField(fieldName);
                        var newValue = field.GetValue(messageUpdate);
                        if (newValue == null)
                        {
                            continue;
                        }

                        field.SetValue(existedMessage, newValue);
                    }

                    existedMessage.edited_timestamp = messageUpdate.edited_timestamp;
                    existedMessage.mention_everyone = messageUpdate.mention_everyone;
                    existedMessage.pinned           = messageUpdate.pinned;
                    WebsocketClientSide.UpdateMessage(existedMessage);

                    Console.WriteLine("channel_id {0} user {1} edited: {2}",
                                      messageUpdate.channel_id,
                                      messageUpdate.author.username,
                                      messageUpdate.content
                                      );
                    break;
                }

                case "CHANNEL_CREATE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#channel-create
                    var messageChannelCreate =
                        JsonConvert.DeserializeObject <EventGuildCreate.EventChannelCreate>(message.dAsString);
                    if (!channels.ContainsKey(messageChannelCreate.guild_id))
                    {
                        channels[messageChannelCreate.guild_id] =
                            new ConcurrentDictionary <string, EventGuildCreate.EventGuildCreate_Channel>();
                    }

                    channels[messageChannelCreate.guild_id][messageChannelCreate.id] = messageChannelCreate;

                    break;
                }

                case "MESSAGE_DELETE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#message-delete
                    var guild_id   = message.d.guild_id.ToString() as string;
                    var channel_id = message.d.channel_id.ToString() as string;
                    if (
                        messages.ContainsKey(guild_id) &&
                        messages[guild_id].ContainsKey(channel_id)
                        )
                    {
                        var messageId = message.d.id.ToString() as string;
                        messages[guild_id][channel_id].TryRemove(messageId, out _);
                        WebsocketClientSide.RemoveMessage(guild_id, channel_id, messageId);
                    }

                    // Такого сообщения нет. Возможно, оно было создано раньше. Это не проблема
                    break;
                }

                case "MESSAGE_REACTION_ADD":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#message-reaction-add
                    var reaction = JsonConvert.DeserializeObject <Reaction>(message.dAsString);
                    if (
                        !messages.ContainsKey(reaction.guild_id) ||
                        !messages[reaction.guild_id].ContainsKey(reaction.channel_id) ||
                        !messages[reaction.guild_id][reaction.channel_id].ContainsKey(reaction.message_id)
                        )
                    {
                        break;
                    }

                    messages[reaction.guild_id][reaction.channel_id][reaction.message_id]
                    .AddReaction(reaction);
                    WebsocketClientSide.UpdateMessage(
                        messages[reaction.guild_id][reaction.channel_id][reaction.message_id]);

                    break;
                }

                case "MESSAGE_REACTION_REMOVE":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#message-reaction-remove
                    var reaction = JsonConvert.DeserializeObject <Reaction>(message.dAsString);
                    if (
                        !messages.ContainsKey(reaction.guild_id) ||
                        !messages[reaction.guild_id].ContainsKey(reaction.channel_id) ||
                        !messages[reaction.guild_id][reaction.channel_id].ContainsKey(reaction.message_id)
                        )
                    {
                        break;
                    }

                    messages[reaction.guild_id][reaction.channel_id][reaction.message_id]
                    .RemoveReaction(reaction);
                    WebsocketClientSide.UpdateMessage(
                        messages[reaction.guild_id][reaction.channel_id][reaction.message_id]);

                    break;
                }

                case "GUILD_MEMBER_ADD":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#guild-member-add
                    break;
                }

                case "GUILD_BAN_ADD":
                {
                    // https://discordapp.com/developers/docs/topics/gateway#guild-ban-add
                    var banAdd = JsonConvert.DeserializeObject <EventGuildBanAdd>(message.dAsString);
                    if (!messages.ContainsKey(banAdd.guild_id))
                    {
                        break;
                    }

                    var userId = banAdd.user.id;

                    foreach (var(channelId, channelsMessages) in messages[banAdd.guild_id])
                    {
                        var forDeletions = new List <string>();
                        foreach (var(messageId, messageItem) in channelsMessages)
                        {
                            if (messageItem.author.id == userId)
                            {
                                forDeletions.Add(messageId);
                            }
                        }

                        foreach (var messageId in forDeletions)
                        {
                            channelsMessages.TryRemove(messageId, out _);
                            WebsocketClientSide.RemoveMessage(banAdd.guild_id, channelId, messageId);
                        }
                    }

                    break;
                }
                    //
                    // @todo GUILD_EMOJIS_UPDATE
                }

                break;
            }
        }
Пример #6
0
        private void WebSocket_OnMessageReceived(object sender, DiscordWebSocketMessage <GatewayOpcode> message)
        {
            Sequence = message.Sequence;

            switch (message.Opcode)
            {
            case GatewayOpcode.Event:
                /*
                 * Console.WriteLine(message.EventName);
                 *
                 * File.AppendAllText("Debug.log", $"{message.EventName}: {message.Data}\n");
                 */

                switch (message.EventName)
                {
                case "READY":
                    LoginEventArgs login = message.Data.ToObject <LoginEventArgs>().SetClient(this);

                    if (login.Application != null)
                    {
                        _appId = login.Application.Value <ulong>("id");
                    }

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

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

                        foreach (var presence in login.Presences)
                        {
                            Presences[presence.UserId] = presence;
                        }

                        foreach (var guild in login.Guilds)
                        {
                            ApplyGuild(GuildCache[guild.Id] = (SocketGuild)guild);
                            VoiceClients[guild.Id]          = new DiscordVoiceClient(this, guild.Id);
                        }

                        foreach (var settings in login.ClientGuildSettings)
                        {
                            if (settings.GuildId.HasValue)
                            {
                                GuildSettings.Add(settings.Guild.Id, settings);
                            }
                            else
                            {
                                PrivateChannelSettings = settings.ChannelOverrides.ToList();
                            }
                        }
                    }

                    LoggedIn = true;
                    State    = GatewayConnectionState.Connected;

                    if (OnLoggedIn != null)
                    {
                        Task.Run(() => OnLoggedIn.Invoke(this, login));
                    }
                    break;

                case "USER_SETTINGS_UPDATE":
                    if (UserSettings == null)
                    {
                    }

                    UserSettings.Update((JObject)message.Data);

                    if (OnSettingsUpdated != null)
                    {
                        Task.Run(() => OnSettingsUpdated.Invoke(this, new DiscordSettingsEventArgs(UserSettings)));
                    }
                    break;

                case "USER_GUILD_SETTINGS_UPDATE":
                    if (Config.Cache)
                    {
                        ClientGuildSettings settings = message.Data.ToObject <ClientGuildSettings>();

                        if (settings.GuildId.HasValue)
                        {
                            GuildSettings[settings.Guild.Id] = settings;
                        }
                        else
                        {
                            PrivateChannelSettings = settings.ChannelOverrides.ToList();
                        }
                    }
                    break;

                case "USER_UPDATE":
                    DiscordUser user = message.Data.ToObject <DiscordUser>().SetClient(this);

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

                    if (Config.Cache)
                    {
                        lock (PrivateChannels.Lock)
                        {
                            foreach (var dm in PrivateChannels)
                            {
                                foreach (var recipient in dm.Recipients)
                                {
                                    if (recipient.Id == user.Id)
                                    {
                                        recipient.Update(user);

                                        break;
                                    }
                                }
                            }
                        }
                    }

                    if (OnUserUpdated != null)
                    {
                        Task.Run(() => OnUserUpdated.Invoke(this, new UserEventArgs(user)));
                    }
                    break;

                case "GUILD_MEMBER_LIST_UPDATE":
                    OnMemberListUpdate?.Invoke(this, message.Data.ToObject <GuildMemberListEventArgs>());
                    break;

                case "GUILD_CREATE":
                    if (Config.Cache || OnJoinedGuild != null)
                    {
                        var guild = message.Data.ToObject <SocketGuild>().SetClient(this);

                        VoiceClients[guild.Id] = new DiscordVoiceClient(this, guild.Id);

                        if (Config.Cache)
                        {
                            ApplyGuild(GuildCache[guild.Id] = guild);
                        }

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

                case "GUILD_UPDATE":
                    if (Config.Cache || OnGuildUpdated != null)
                    {
                        DiscordGuild guild = message.Data.ToObject <DiscordGuild>().SetClient(this);

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

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

                case "GUILD_DELETE":
                {
                    UnavailableGuild guild = message.Data.ToObject <UnavailableGuild>();

                    VoiceClients.Remove(guild.Id);

                    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);
                            GuildSettings.Remove(guild.Id);
                        }
                    }

                    if (OnLeftGuild != null)
                    {
                        Task.Run(() => OnLeftGuild.Invoke(this, new GuildUnavailableEventArgs(guild)));
                    }
                }
                break;

                case "GUILD_MEMBER_ADD":
                    if (Config.Cache || OnUserJoinedGuild != null)
                    {
                        var member = message.Data.ToObject <GuildMember>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[member.GuildId].MemberCount++;
                        }

                        Task.Run(() => OnUserJoinedGuild?.Invoke(this, new GuildMemberEventArgs(member)));
                    }
                    break;

                case "GUILD_MEMBER_REMOVE":
                    if (Config.Cache || OnUserLeftGuild != null)
                    {
                        var member = message.Data.ToObject <PartialGuildMember>().SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[member.GuildId].MemberCount--;
                        }

                        Task.Run(() => OnUserLeftGuild?.Invoke(this, new MemberRemovedEventArgs(member)));
                    }
                    break;

                case "GUILD_MEMBER_UPDATE":
                    if (Config.Cache || OnGuildMemberUpdated != null)
                    {
                        GuildMember member = message.Data.ToObject <GuildMember>().SetClient(this);

                        if (Config.Cache && member.User.Id == User.Id)
                        {
                            SocketGuild guild = this.GetCachedGuild(member.GuildId);

                            // Discord doesn't send us the user's JoinedAt on updates
                            member.JoinedAt         = guild.ClientMember.JoinedAt;
                            ClientMembers[guild.Id] = member;

                            break;
                        }

                        Task.Run(() => OnGuildMemberUpdated.Invoke(this, new GuildMemberEventArgs(member)));
                    }
                    break;

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

                case "GIFT_CODE_CREATE":
                    if (OnGiftCodeCreated != null)
                    {
                        Task.Run(() => OnGiftCodeCreated.Invoke(this, message.Data.ToObject <GiftCodeCreatedEventArgs>()));
                    }
                    break;

                case "GIFT_CODE_UPDATE":
                    if (OnGiftUpdated != null)
                    {
                        var gift = message.Data.ToObject <GiftCodeUpdatedEventArgs>().SetClient(this);
                        gift.Json = (JObject)message.Data;

                        Task.Run(() => OnGiftUpdated.Invoke(this, gift));
                    }
                    break;

                case "PRESENCE_UPDATE":
                    if (Config.Cache || OnUserPresenceUpdated != null)
                    {
                        var presence = message.Data.ToObject <DiscordPresence>().SetClient(this);

                        if (Config.Cache)
                        {
                            if (Presences.TryGetValue(presence.UserId, out DiscordPresence existingPresence))
                            {
                                existingPresence.Update(presence);
                                presence = existingPresence;
                            }
                            else
                            {
                                Presences[presence.UserId] = presence;
                            }
                        }

                        if (OnUserPresenceUpdated != null)
                        {
                            Task.Run(() => OnUserPresenceUpdated.Invoke(this, new PresenceUpdatedEventArgs(presence)));
                        }
                    }
                    break;

                case "VOICE_STATE_UPDATE":
                    DiscordVoiceState newState = message.Data.ToObject <DiscordVoiceState>().SetClient(this);

                    if (Config.Cache)
                    {
                        if (newState.Guild == null)
                        {
                            VoiceStates[newState.UserId].PrivateChannelVoiceState = newState;
                        }
                        else
                        {
                            VoiceStates[newState.UserId].GuildStates[newState.Guild.Id] = newState;
                        }

                        // we also store voice states within SocketGuilds, so make sure to update those.
                        foreach (var guild in this.GetCachedGuilds())
                        {
                            if (!guild.Unavailable)
                            {
                                if (newState.Guild == null || guild.Id != newState.Guild.Id)
                                {
                                    guild._voiceStates.RemoveFirst(s => s.UserId == newState.UserId);
                                }
                                else
                                {
                                    int i = guild._voiceStates.FindIndex(s => s.UserId == newState.UserId);

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

                    if (newState.UserId == User.Id)
                    {
                        if (newState.Guild == null)
                        {
                            VoiceClients.Private.SetSessionId(newState.SessionId);
                        }
                        else
                        {
                            VoiceClients[newState.Guild.Id].SetSessionId(newState.SessionId);
                        }
                    }

                    if (OnVoiceStateUpdated != null)
                    {
                        Task.Run(() => OnVoiceStateUpdated.Invoke(this, new VoiceStateEventArgs(newState)));
                    }
                    break;

                case "VOICE_SERVER_UPDATE":
                    OnMediaServer?.Invoke(this, message.Data.ToObject <DiscordMediaServer>().SetClient(this));
                    break;

                case "GUILD_ROLE_CREATE":
                    if (Config.Cache || OnRoleCreated != null)
                    {
                        DiscordRole role = message.Data.ToObject <RoleUpdate>().Role.SetClient(this);

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

                        if (OnRoleCreated != null)
                        {
                            Task.Run(() => OnRoleCreated.Invoke(this, new RoleEventArgs(role)));
                        }
                    }
                    break;

                case "GUILD_ROLE_UPDATE":
                    if (Config.Cache || OnRoleUpdated != null)
                    {
                        DiscordRole role = message.Data.ToObject <RoleUpdate>().Role.SetClient(this);

                        if (Config.Cache)
                        {
                            GuildCache[role.GuildId]._roles.ReplaceFirst(r => r.Id == role.Id, role);
                        }

                        if (OnRoleUpdated != null)
                        {
                            Task.Run(() => OnRoleUpdated.Invoke(this, new RoleEventArgs(role)));
                        }
                    }
                    break;

                case "GUILD_ROLE_DELETE":
                    if (Config.Cache || OnRoleDeleted != null)
                    {
                        DeletedRole role = message.Data.ToObject <DeletedRole>().SetClient(this);

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

                        if (OnRoleDeleted != null)
                        {
                            Task.Run(() => OnRoleDeleted.Invoke(this, new RoleDeletedEventArgs(role)));
                        }
                    }
                    break;

                case "GUILD_EMOJIS_UPDATE":
                    if (Config.Cache || OnEmojisUpdated != null)
                    {
                        var emojis = message.Data.ToObject <EmojiContainer>().SetClient(this);

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

                        if (OnEmojisUpdated != null)
                        {
                            Task.Run(() => OnEmojisUpdated.Invoke(this, new EmojisUpdatedEventArgs(emojis)));
                        }
                    }
                    break;

                case "CHANNEL_CREATE":
                    if (Config.Cache || OnChannelCreated != null)
                    {
                        var channel = ((JObject)message.Data).ParseDeterministic <DiscordChannel>();

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

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

                        if (OnChannelCreated != null)
                        {
                            Task.Run(() => OnChannelCreated.Invoke(this, new ChannelEventArgs(channel)));
                        }
                    }
                    break;

                case "CHANNEL_UPDATE":
                    if (Config.Cache || OnChannelUpdated != null)
                    {
                        var channel = ((JObject)message.Data).ParseDeterministic <DiscordChannel>();

                        if (Config.Cache)
                        {
                            if (channel.Type == ChannelType.DM || channel.Type == ChannelType.Group)
                            {
                                PrivateChannels.ReplaceFirst(c => c.Id == channel.Id, (PrivateChannel)channel);
                            }
                            else
                            {
                                GuildChannel guildChannel = (GuildChannel)channel;
                                GuildCache[guildChannel.GuildId].ChannelsConcurrent.ReplaceFirst(c => c.Id == guildChannel.Id, guildChannel);
                            }
                        }

                        if (OnChannelUpdated != null)
                        {
                            Task.Run(() => OnChannelUpdated.Invoke(this, new ChannelEventArgs(channel)));
                        }
                    }
                    break;

                case "CHANNEL_DELETE":
                    if (Config.Cache || OnChannelDeleted != null)
                    {
                        var channel = ((JObject)message.Data).ParseDeterministic <DiscordChannel>();

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

                        if (OnChannelDeleted != null)
                        {
                            Task.Run(() => OnChannelDeleted.Invoke(this, new ChannelEventArgs(channel)));
                        }
                    }
                    break;

                case "TYPING_START":
                    if (OnUserTyping != null)
                    {
                        Task.Run(() => OnUserTyping.Invoke(this, new UserTypingEventArgs(message.Data.ToObject <UserTyping>().SetClient(this))));
                    }
                    break;

                case "MESSAGE_CREATE":
                    if (Config.Cache || OnMessageReceived != null)
                    {
                        var newMessage = message.Data.ToObject <DiscordMessage>().SetClient(this);

                        if (Config.Cache)
                        {
                            try
                            {
                                this.GetChannel(newMessage.Channel.Id).SetLastMessageId(newMessage.Id);
                            }
                            catch (DiscordHttpException) { }
                        }

                        if (OnMessageReceived != null)
                        {
                            Task.Run(() => OnMessageReceived.Invoke(this, new MessageEventArgs(newMessage)));
                        }
                    }
                    break;

                case "MESSAGE_UPDATE":
                    if (OnMessageEdited != null)
                    {
                        Task.Run(() => OnMessageEdited.Invoke(this, new MessageEventArgs(message.Data.ToObject <DiscordMessage>().SetClient(this))));
                    }
                    break;

                case "MESSAGE_DELETE":
                    if (OnMessageDeleted != null)
                    {
                        Task.Run(() => OnMessageDeleted.Invoke(this, new MessageDeletedEventArgs(message.Data.ToObject <DeletedMessage>().SetClient(this))));
                    }
                    break;

                case "MESSAGE_REACTION_ADD":
                    if (OnMessageReactionAdded != null)
                    {
                        Task.Run(() => OnMessageReactionAdded.Invoke(this, new ReactionEventArgs(message.Data.ToObject <MessageReactionUpdate>().SetClient(this))));
                    }
                    break;

                case "MESSAGE_REACTION_REMOVE":
                    if (OnMessageReactionRemoved != null)
                    {
                        Task.Run(() => OnMessageReactionRemoved.Invoke(this, new ReactionEventArgs(message.Data.ToObject <MessageReactionUpdate>().SetClient(this))));
                    }
                    break;

                case "GUILD_BAN_ADD":
                    if (OnUserBanned != null)
                    {
                        Task.Run(() => OnUserBanned.Invoke(this, message.Data.ToObject <BanUpdateEventArgs>().SetClient(this)));
                    }
                    break;

                case "GUILD_BAN_REMOVE":
                    if (OnUserUnbanned != null)
                    {
                        Task.Run(() => OnUserUnbanned.Invoke(this, message.Data.ToObject <BanUpdateEventArgs>().SetClient(this)));
                    }
                    break;

                case "INVITE_CREATE":
                    if (OnInviteCreated != null)
                    {
                        Task.Run(() => OnInviteCreated.Invoke(this, message.Data.ToObject <InviteCreatedEventArgs>().SetClient(this)));
                    }
                    break;

                case "INVITE_DELETE":
                    if (OnInviteDeleted != null)
                    {
                        Task.Run(() => OnInviteDeleted.Invoke(this, message.Data.ToObject <InviteDeletedEventArgs>().SetClient(this)));
                    }
                    break;

                case "RELATIONSHIP_ADD":
                    if (OnRelationshipAdded != null)
                    {
                        Task.Run(() => OnRelationshipAdded.Invoke(this, new RelationshipEventArgs(message.Data.ToObject <DiscordRelationship>().SetClient(this))));
                    }
                    break;

                case "RELATIONSHIP_REMOVE":
                    if (OnRelationshipRemoved != null)
                    {
                        Task.Run(() => OnRelationshipRemoved.Invoke(this, message.Data.ToObject <RemovedRelationshipEventArgs>()));
                    }
                    break;

                case "CHANNEL_RECIPIENT_ADD":
                    if (Config.Cache || OnChannelRecipientAdded != null)
                    {
                        var recipUpdate = message.Data.ToObject <ChannelRecipientEventArgs>().SetClient(this);

                        if (Config.Cache)
                        {
                            ((PrivateChannel)this.GetChannel(recipUpdate.Channel.Id))._recipients.Add(recipUpdate.User);
                        }

                        if (OnChannelRecipientAdded != null)
                        {
                            Task.Run(() => OnChannelRecipientAdded.Invoke(this, recipUpdate));
                        }
                    }
                    break;

                case "CHANNEL_RECIPIENT_REMOVE":
                    if (Config.Cache || OnChannelRecipientAdded != null)
                    {
                        var recipUpdate = message.Data.ToObject <ChannelRecipientEventArgs>().SetClient(this);

                        if (Config.Cache)
                        {
                            ((PrivateChannel)this.GetChannel(recipUpdate.Channel.Id))._recipients.RemoveFirst(u => u.Id == recipUpdate.User.Id);
                        }

                        if (OnChannelRecipientRemoved != null)
                        {
                            Task.Run(() => OnChannelRecipientRemoved.Invoke(this, recipUpdate));
                        }
                    }
                    break;

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

                case "SESSIONS_REPLACE":
                    if (OnSessionsUpdated != null)
                    {
                        Task.Run(() => OnSessionsUpdated.Invoke(this, new DiscordSessionsEventArgs(message.Data.ToObject <List <DiscordSession> >())));
                    }
                    break;

                case "CALL_CREATE":
                    if (Config.Cache || OnRinging != null)
                    {
                        var call        = message.Data.ToObject <DiscordCall>().SetClient(this);
                        var voiceStates = message.Data.Value <JToken>("voice_states").ToObject <IReadOnlyList <DiscordVoiceState> >().SetClientsInList(this);

                        if (Config.Cache)
                        {
                            foreach (var state in voiceStates)
                            {
                                VoiceStates[state.UserId].PrivateChannelVoiceState = state;
                            }
                        }

                        if (OnRinging != null)
                        {
                            Task.Run(() => OnRinging.Invoke(this, new RingingEventArgs(call, voiceStates)));
                        }
                    }
                    break;

                case "CALL_UPDATE":
                    if (OnCallUpdated != null)
                    {
                        Task.Run(() => OnCallUpdated.Invoke(this, new CallUpdateEventArgs(message.Data.ToObject <DiscordCall>().SetClient(this))));
                    }
                    break;

                case "CALL_DELETE":
                    if (Config.Cache || OnCallEnded != null)
                    {
                        ulong channelId = message.Data.Value <ulong>("channel_id");

                        if (Config.Cache)
                        {
                            foreach (var state in VoiceStates.CreateCopy().Values)
                            {
                                var privState = state.PrivateChannelVoiceState;

                                if (privState != null && privState.Channel != null && privState.Channel.Id == channelId)
                                {
                                    state.PrivateChannelVoiceState = null;
                                }
                            }
                        }

                        if (OnCallEnded != null)
                        {
                            Task.Run(() => OnCallEnded.Invoke(this, new MinimalTextChannel(channelId).SetClient(this)));
                        }
                    }
                    break;

                case "ENTITLEMENT_CREATE":
                    if (OnEntitlementCreated != null)
                    {
                        Task.Run(() => OnEntitlementCreated.Invoke(this, new EntitlementEventArgs(message.Data.ToObject <DiscordEntitlement>())));
                    }
                    break;

                case "ENTITLEMENT_UPDATE":
                    if (OnEntitlementUpdated != null)
                    {
                        Task.Run(() => OnEntitlementUpdated.Invoke(this, new EntitlementEventArgs(message.Data.ToObject <DiscordEntitlement>())));
                    }
                    break;

                case "USER_PREMIUM_GUILD_SUBSCRIPTION_SLOT_CREATE":
                    if (OnBoostSlotCreated != null)
                    {
                        Task.Run(() => OnBoostSlotCreated.Invoke(this, new NitroBoostEventArgs(message.Data.ToObject <DiscordBoostSlot>().SetClient(this))));
                    }
                    break;

                case "USER_PREMIUM_GUILD_SUBSCRIPTION_SLOT_UPDATE":
                    if (OnBoostSlotUpdated != null)
                    {
                        Task.Run(() => OnBoostSlotUpdated.Invoke(this, new NitroBoostEventArgs(message.Data.ToObject <DiscordBoostSlot>().SetClient(this))));
                    }
                    break;

                case "STREAM_SERVER_UPDATE":
                    OnMediaServer?.Invoke(this, message.Data.ToObject <DiscordMediaServer>().SetClient(this));
                    break;

                case "STREAM_CREATE":
                    var create = message.Data.ToObject <GoLiveCreate>();
                    GetVoiceClient(new StreamKey(create.StreamKey).GuildId).Livestream.CreateSession(create);
                    break;

                case "STREAM_UPDATE":
                    var update = message.Data.ToObject <GoLiveUpdate>();
                    GetVoiceClient(new StreamKey(update.StreamKey).GuildId).Livestream.UpdateSession(update);
                    break;

                case "STREAM_DELETE":
                    var delete = message.Data.ToObject <GoLiveDelete>();
                    GetVoiceClient(new StreamKey(delete.StreamKey).GuildId).Livestream.KillSession(delete);
                    break;

                case "CHANNEL_UNREAD_UPDATE":
                    if (Config.Cache || OnGuildUnreadMessagesUpdated != null)
                    {
                        var unread = message.Data.ToObject <GuildUnreadMessages>().SetClient(this);

                        if (Config.Cache)
                        {
                            foreach (var unreadChannel in unread.Channels)
                            {
                                this.GetChannel(unreadChannel.Channel.Id).SetLastMessageId(unreadChannel.LastMessageId);
                            }
                        }

                        if (OnGuildUnreadMessagesUpdated != null)
                        {
                            Task.Run(() => OnGuildUnreadMessagesUpdated.Invoke(this, new UnreadMessagesEventArgs(unread)));
                        }
                    }
                    break;

                case "INTERACTION_CREATE":
                    if (OnInteraction != null)
                    {
                        Task.Run(() => OnInteraction.Invoke(this, new DiscordInteractionEventArgs(message.Data.ToObject <DiscordInteraction>().SetClient(this))));
                    }
                    break;

                case "USER_REQUIRED_ACTION_UPDATE":
                    if (OnRequiredUserAction != null)
                    {
                        Task.Run(() => OnRequiredUserAction.Invoke(this, message.Data.ToObject <RequiredActionEventArgs>()));
                    }
                    break;

                default:
                    break;
                }
                break;

            case GatewayOpcode.InvalidSession:
                LoggedIn = false;

                this.LoginToGateway();
                break;

            case GatewayOpcode.Connected:
                this.LoginToGateway();

                Task.Run(() =>
                {
                    int interval = message.Data.ToObject <JObject>().GetValue("heartbeat_interval").ToObject <int>() - 1000;

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

                break;
            }
        }
Пример #7
0
 protected virtual void HandleMessage(DiscordWebSocketMessage <DiscordMediaOpcode> message)
 {
 }
Пример #8
0
        private void OnMessageReceived(object sender, DiscordWebSocketMessage <DiscordMediaOpcode> message)
        {
            try
            {
                switch (message.Opcode)
                {
                case DiscordMediaOpcode.Ready:
                    DiscordMediaReady ready = message.Data.ToObject <DiscordMediaReady>();

                    SSRC = new DiscordSSRC()
                    {
                        Audio = ready.SSRC
                    };

                    _serverEndpoint = new IPEndPoint(IPAddress.Parse(ready.IP), ready.Port);

                    UdpClient = new UdpClient();
                    UdpClient.Connect(_serverEndpoint);

                    Task.Run(() => StartListener());

                    Holepunch();
                    break;

                case DiscordMediaOpcode.SessionDescription:
                    var description = message.Data.ToObject <DiscordSessionDescription>();

                    if (ValidateCodecs(description))
                    {
                        if (description.EncryptionMode != Sodium.EncryptionMode)
                        {
                            Disconnect(DiscordMediaCloseCode.InvalidEncryptionMode, "Unexpected encryption mode: " + description.EncryptionMode);
                        }
                        else
                        {
                            SecretKey = description.SecretKey;
                            State     = MediaSessionState.Authenticated;

                            Log("Authenticated");

                            Task.Run(() => HandleConnect());
                        }
                    }
                    break;

                case DiscordMediaOpcode.ChangeCodecs:
                    // apparently this triggers whenever u switch channel
                    // im confused
                    //var codecs = message.Data.ToObject<MediaCodecSelection>();
                    break;

                case DiscordMediaOpcode.Hello:
                    WebSocket.Send(DiscordMediaOpcode.Identify, new DiscordMediaIdentify()
                    {
                        ServerId  = GetServerId(),
                        UserId    = Client.User.Id,
                        SessionId = Client.SessionId,
                        Token     = CurrentServer.Token,
                        Video     = true
                    });

                    WebSocket.StartHeartbeaterAsync(message.Data.Value <int>("heartbeat_interval"));
                    break;

                default:
                    HandleMessage(message);
                    break;
                }
            }
            catch (InvalidOperationException) { }
        }