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; } }
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); } }
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; } }
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; } }
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; } }
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; } }
protected virtual void HandleMessage(DiscordWebSocketMessage <DiscordMediaOpcode> message) { }
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) { } }