From 5bdd6a7ff3cf2971bcd17ef853ffb22adecd377e Mon Sep 17 00:00:00 2001 From: RogueException Date: Mon, 4 Apr 2016 20:15:16 -0300 Subject: [PATCH] Early 1.0 REST Preview --- Discord.Net.sln | 102 +- NuGet.config | 8 + docs/features/commands.rst | 2 +- docs/features/events.rst | 20 +- docs/features/logging.rst | 16 +- docs/features/permissions.rst | 40 +- docs/features/server-management.rst | 2 +- docs/features/user-management.rst | 4 +- docs/features/voice.rst | 175 +-- docs/getting_started.rst | 6 +- docs/global.txt | 4 +- docs/index.rst | 12 +- docs/samples/events.cs | 14 +- docs/samples/getting_started.cs | 9 +- docs/samples/logging.cs | 5 +- docs/samples/permissions.cs | 16 +- global.json | 8 +- ref/Discord.Net.xproj | 21 - ref/DiscordClient.cs | 75 -- ref/DiscordConfig.cs | 65 -- ref/Entities/Channels/IPublicChannel.cs | 43 - ref/Entities/Channels/PrivateChannel.cs | 55 - ref/Entities/Channels/TextChannel.cs | 91 -- ref/Entities/Channels/VoiceChannel.cs | 74 -- ref/Entities/Color.cs | 17 - ref/Entities/IModifiable.cs | 11 - ref/Entities/Invite/BasicInvite.cs | 37 - ref/Entities/Invite/Invite.cs | 18 - ref/Entities/Message.cs | 68 -- ref/Entities/Permissions/ChannelPermissions.cs | 53 - ref/Entities/Permissions/OverwritePermissions.cs | 50 - .../Permissions/PermissionOverwriteEntry.cs | 9 - ref/Entities/Permissions/ServerPermissions.cs | 55 - ref/Entities/Profile.cs | 25 - ref/Entities/Region.cs | 11 - ref/Entities/Role.cs | 29 - ref/Entities/Server.cs | 67 -- ref/Entities/Users/IUser.cs | 19 - ref/Entities/Users/PrivateUser.cs | 43 - ref/Entities/Users/ServerUser.cs | 73 -- ref/Enums/ChannelType.cs | 13 - ref/Enums/ConnectionState.cs | 10 - ref/Enums/EntityState.cs | 18 - ref/Enums/ImageType.cs | 9 - ref/Enums/LogSeverity.cs | 12 - ref/Enums/PermValue.cs | 9 - ref/Enums/PermissionTarget.cs | 8 - ref/Enums/Relative.cs | 8 - ref/Enums/UserStatus.cs | 9 - ref/Events/ChannelEventArgs.cs | 9 - ref/Events/ChannelUpdatedEventArgs.cs | 10 - ref/Events/DisconnectedEventArgs.cs | 10 - ref/Events/LogMessageEventArgs.cs | 12 - ref/Events/MessageEventArgs.cs | 11 - ref/Events/MessageUpdatedEventArgs.cs | 12 - ref/Events/ProfileUpdatedEventArgs.cs | 10 - ref/Events/RoleEventArgs.cs | 10 - ref/Events/RoleUpdatedEventArgs.cs | 11 - ref/Events/ServerEventArgs.cs | 9 - ref/Events/ServerUpdatedEventArgs.cs | 10 - ref/Events/TypingEventArgs.cs | 14 - ref/Events/UserEventArgs.cs | 8 - ref/Events/UserUpdatedEventArgs.cs | 9 - ref/Format.cs | 14 - ref/ILogger.cs | 30 - ref/MessageQueue.cs | 9 - ref/Net/HttpException.cs | 16 - ref/Net/Rest/CompletedRequestEventArgs.cs | 17 - ref/Net/Rest/IRestClient.cs | 23 - ref/Net/Rest/IRestClientProvider.cs | 10 - ref/Net/Rest/RequestEventArgs.cs | 12 - ref/Net/TimeoutException.cs | 9 - ref/Net/WebSocketException.cs | 12 - ref/Net/WebSockets/BinaryMessageEventArgs.cs | 11 - ref/Net/WebSockets/GatewaySocket.cs | 28 - ref/Net/WebSockets/IWebSocket.cs | 15 - ref/Net/WebSockets/IWebSocketEngine.cs | 18 - ref/Net/WebSockets/IWebSocketProvider.cs | 9 - ref/Net/WebSockets/TextMessageEventArgs.cs | 11 - ref/Net/WebSockets/WebSocketEventEventArgs.cs | 11 - ref/project.json | 81 -- src/Discord.Net.Audio/AudioClient.cs | 283 ----- src/Discord.Net.Audio/AudioExtensions.cs | 26 - src/Discord.Net.Audio/AudioMode.cs | 9 - src/Discord.Net.Audio/AudioService.cs | 193 --- src/Discord.Net.Audio/AudioServiceConfig.cs | 51 - src/Discord.Net.Audio/Discord.Net.Audio.xproj | 21 - src/Discord.Net.Audio/IAudioClient.cs | 46 - src/Discord.Net.Audio/InternalFrameEventArgs.cs | 22 - .../InternalIsSpeakingEventArgs.cs | 14 - src/Discord.Net.Audio/Net/VoiceSocket.cs | 516 -------- src/Discord.Net.Audio/Opus/OpusConverter.cs | 111 -- src/Discord.Net.Audio/Opus/OpusDecoder.cs | 43 - src/Discord.Net.Audio/Opus/OpusEncoder.cs | 78 -- src/Discord.Net.Audio/Sodium/SecretBox.cs | 32 - src/Discord.Net.Audio/UserIsTalkingEventArgs.cs | 13 - src/Discord.Net.Audio/VirtualClient.cs | 39 - src/Discord.Net.Audio/VoiceBuffer.cs | 140 --- .../VoiceDisconnectedEventArgs.cs | 15 - src/Discord.Net.Audio/libsodium.dll | Bin 492032 -> 0 bytes src/Discord.Net.Audio/opus.dll | Bin 271872 -> 0 bytes src/Discord.Net.Audio/project.json | 27 - src/Discord.Net.Commands/Command.cs | 83 -- src/Discord.Net.Commands/CommandBuilder.cs | 163 --- src/Discord.Net.Commands/CommandErrorEventArgs.cs | 18 - src/Discord.Net.Commands/CommandEventArgs.cs | 26 - src/Discord.Net.Commands/CommandExtensions.cs | 20 - src/Discord.Net.Commands/CommandMap.cs | 141 --- src/Discord.Net.Commands/CommandParameter.cs | 26 - src/Discord.Net.Commands/CommandParser.cs | 188 --- src/Discord.Net.Commands/CommandService.cs | 347 ------ src/Discord.Net.Commands/CommandServiceConfig.cs | 46 - .../Discord.Net.Commands.xproj | 21 - .../GenericPermissionChecker.cs | 22 - src/Discord.Net.Commands/HelpMode.cs | 12 - src/Discord.Net.Commands/IPermissionChecker.cs | 7 - src/Discord.Net.Commands/project.json | 25 - src/Discord.Net.Modules/Discord.Net.Modules.xproj | 21 - src/Discord.Net.Modules/IModule.cs | 7 - src/Discord.Net.Modules/ModuleChecker.cs | 33 - src/Discord.Net.Modules/ModuleExtensions.cs | 29 - src/Discord.Net.Modules/ModuleFilter.cs | 17 - src/Discord.Net.Modules/ModuleManager.cs | 278 ----- src/Discord.Net.Modules/ModuleService.cs | 61 - src/Discord.Net.Modules/project.json | 26 - .../Discord.Net.Shared.projitems | 16 - src/Discord.Net.Shared/Discord.Net.Shared.shproj | 13 - src/Discord.Net.Shared/EpochTime.cs | 11 - src/Discord.Net.Shared/TaskExtensions.cs | 68 -- src/Discord.Net.Shared/TaskHelper.cs | 29 - src/Discord.Net/API/Client/Common/Channel.cs | 35 - .../API/Client/Common/ChannelReference.cs | 17 - .../API/Client/Common/ExtendedMember.cs | 12 - src/Discord.Net/API/Client/Common/Guild.cs | 50 - .../API/Client/Common/GuildReference.cs | 13 - src/Discord.Net/API/Client/Common/Invite.cs | 23 - .../API/Client/Common/InviteReference.cs | 22 - src/Discord.Net/API/Client/Common/Member.cs | 14 - .../API/Client/Common/MemberPresence.cs | 20 - .../API/Client/Common/MemberReference.cs | 13 - src/Discord.Net/API/Client/Common/Message.cs | 96 -- .../API/Client/Common/MessageReference.cs | 15 - src/Discord.Net/API/Client/Common/RoleReference.cs | 13 - src/Discord.Net/API/Client/Common/User.cs | 12 - src/Discord.Net/API/Client/Common/UserReference.cs | 17 - .../API/Client/GatewaySocket/Commands/Heartbeat.cs | 12 - .../GatewaySocket/Events/GuildEmojisUpdate.cs | 4 - .../Events/GuildIntegrationsUpdate.cs | 4 - .../GatewaySocket/Events/GuildMemberRemove.cs | 4 - .../GatewaySocket/Events/GuildMemberUpdate.cs | 4 - .../Client/GatewaySocket/Events/GuildRoleCreate.cs | 13 - .../Client/GatewaySocket/Events/GuildRoleUpdate.cs | 13 - .../API/Client/GatewaySocket/Events/TypingStart.cs | 15 - .../GatewaySocket/Events/UserSettingsUpdate.cs | 4 - .../GatewaySocket/Events/VoiceServerUpdate.cs | 15 - src/Discord.Net/API/Client/ISerializable.cs | 9 - src/Discord.Net/API/Client/Rest/AcceptInvite.cs | 19 - src/Discord.Net/API/Client/Rest/AddGuildBan.cs | 23 - src/Discord.Net/API/Client/Rest/DeleteRole.cs | 21 - src/Discord.Net/API/Client/Rest/Gateway.cs | 18 - src/Discord.Net/API/Client/Rest/GetBans.cs | 19 - src/Discord.Net/API/Client/Rest/GetInvite.cs | 19 - src/Discord.Net/API/Client/Rest/GetInvites.cs | 19 - src/Discord.Net/API/Client/Rest/GetMessages.cs | 34 - src/Discord.Net/API/Client/Rest/GetWidget.cs | 60 - src/Discord.Net/API/Client/Rest/KickMember.cs | 21 - src/Discord.Net/API/Client/Rest/Login.cs | 23 - src/Discord.Net/API/Client/Rest/Logout.cs | 12 - src/Discord.Net/API/Client/Rest/PruneMembers.cs | 28 - .../API/Client/Rest/RemoveChannelPermission.cs | 21 - src/Discord.Net/API/Client/Rest/ReorderChannels.cs | 45 - src/Discord.Net/API/Client/Rest/ReorderRoles.cs | 45 - src/Discord.Net/API/Client/Rest/SendIsTyping.cs | 19 - src/Discord.Net/API/Client/Rest/UpdateGuild.cs | 33 - src/Discord.Net/API/Client/Rest/UpdateRole.cs | 30 - .../API/Client/VoiceSocket/Commands/Heartbeat.cs | 9 - .../API/Client/VoiceSocket/Commands/Identify.cs | 21 - .../Client/VoiceSocket/Commands/SelectProtocol.cs | 29 - src/Discord.Net/API/Common/Attachment.cs | 22 + src/Discord.Net/API/Common/Channel.cs | 37 + src/Discord.Net/API/Common/Embed.cs | 21 + src/Discord.Net/API/Common/EmbedProvider.cs | 12 + src/Discord.Net/API/Common/EmbedThumbnail.cs | 16 + src/Discord.Net/API/Common/Emoji.cs | 18 + src/Discord.Net/API/Common/Guild.cs | 36 + src/Discord.Net/API/Common/GuildEmbed.cs | 12 + src/Discord.Net/API/Common/GuildMember.cs | 19 + src/Discord.Net/API/Common/Integration.cs | 32 + src/Discord.Net/API/Common/IntegrationAccount.cs | 12 + src/Discord.Net/API/Common/Invite.cs | 16 + src/Discord.Net/API/Common/InviteChannel.cs | 15 + src/Discord.Net/API/Common/InviteGuild.cs | 14 + src/Discord.Net/API/Common/InviteMetadata.cs | 23 + src/Discord.Net/API/Common/Message.cs | 31 + src/Discord.Net/API/Common/ReadState.cs | 14 + .../API/Common/Unconfirmed/Connection.cs | 19 + .../Common => Common/Unconfirmed}/ExtendedGuild.cs | 2 +- .../API/Common/Unconfirmed/ExtendedMember.cs | 12 + .../API/Common/Unconfirmed/MemberPresence.cs | 15 + .../API/Common/Unconfirmed/MemberPresenceGame.cs | 10 + .../API/Common/Unconfirmed/MemberReference.cs | 12 + .../Unconfirmed}/MemberVoiceState.cs | 17 +- .../API/Common/Unconfirmed/MessageReference.cs | 14 + .../API/Common/Unconfirmed/Overwrite.cs | 16 + .../{Client/Common => Common/Unconfirmed}/Role.cs | 7 +- .../API/Common/Unconfirmed/RoleReference.cs | 12 + src/Discord.Net/API/Common/User.cs | 22 + src/Discord.Net/API/Common/UserGuild.cs | 16 + src/Discord.Net/API/Converters.cs | 89 -- src/Discord.Net/API/Extensions.cs | 19 - .../OpCodes.cs => GatewaySocket/OpCode.cs} | 14 +- .../Unconfirmed/Commands/Heartbeat.cs | 12 + .../Unconfirmed}/Commands/Identify.cs | 7 +- .../Unconfirmed}/Commands/RequestMembers.cs | 10 +- .../Unconfirmed}/Commands/Resume.cs | 5 +- .../Unconfirmed}/Commands/UpdateStatus.cs | 5 +- .../Unconfirmed}/Commands/UpdateVoice.cs | 12 +- .../Unconfirmed}/Events/ChannelCreate.cs | 2 +- .../Unconfirmed}/Events/ChannelDelete.cs | 2 +- .../Unconfirmed}/Events/ChannelUpdate.cs | 2 +- .../Unconfirmed}/Events/GuildBanAdd.cs | 2 +- .../Unconfirmed}/Events/GuildBanRemove.cs | 2 +- .../Unconfirmed}/Events/GuildCreate.cs | 2 +- .../Unconfirmed}/Events/GuildDelete.cs | 2 +- .../Unconfirmed}/Events/GuildMemberAdd.cs | 2 +- .../Unconfirmed/Events/GuildMemberRemove.cs | 4 + .../Unconfirmed/Events/GuildMemberUpdate.cs | 4 + .../Unconfirmed}/Events/GuildMembersChunk.cs | 7 +- .../Unconfirmed/Events/GuildRoleCreate.cs | 12 + .../Unconfirmed}/Events/GuildRoleDelete.cs | 2 +- .../Unconfirmed/Events/GuildRoleUpdate.cs | 12 + .../Unconfirmed}/Events/GuildUpdate.cs | 2 +- .../Unconfirmed}/Events/MessageAck.cs | 2 +- .../Unconfirmed}/Events/MessageCreate.cs | 2 +- .../Unconfirmed}/Events/MessageDelete.cs | 2 +- .../Unconfirmed}/Events/MessageUpdate.cs | 2 +- .../Unconfirmed}/Events/PresenceUpdate.cs | 2 +- .../Unconfirmed}/Events/Ready.cs | 2 +- .../Unconfirmed}/Events/Redirect.cs | 2 +- .../Unconfirmed}/Events/Resumed.cs | 2 +- .../Unconfirmed/Events/TypingStart.cs | 14 + .../Unconfirmed}/Events/UserUpdate.cs | 2 +- .../Unconfirmed/Events/VoiceServerUpdate.cs | 14 + .../Unconfirmed}/Events/VoiceStateUpdate.cs | 2 +- src/Discord.Net/API/IRestRequest.cs | 25 - .../API/{Client => }/IWebSocketMessage.cs | 3 +- src/Discord.Net/API/Rest/AcceptInvite.cs | 18 + .../API/{Client => }/Rest/AckMessage.cs | 12 +- src/Discord.Net/API/Rest/BeginGuildPrune.cs | 23 + .../CreateChannelInvite.cs} | 15 +- .../CreateDMChannel.cs} | 8 +- .../API/{Client => }/Rest/CreateGuild.cs | 11 +- src/Discord.Net/API/Rest/CreateGuildBan.cs | 24 + .../CreateGuildChannel.cs} | 9 +- src/Discord.Net/API/Rest/CreateGuildIntegration.cs | 25 + .../Rest/CreateRole.cs => Rest/CreateGuildRole.cs} | 7 +- .../Rest/SendMessage.cs => Rest/CreateMessage.cs} | 17 +- .../API/{Client => }/Rest/DeleteChannel.cs | 7 +- .../API/Rest/DeleteChannelPermission.cs | 20 + .../API/{Client => }/Rest/DeleteGuild.cs | 7 +- src/Discord.Net/API/Rest/DeleteGuildIntegration.cs | 20 + src/Discord.Net/API/Rest/DeleteGuildRole.cs | 20 + .../API/{Client => }/Rest/DeleteInvite.cs | 9 +- .../API/{Client => }/Rest/DeleteMessage.cs | 9 +- src/Discord.Net/API/Rest/GetChannel.cs | 18 + src/Discord.Net/API/Rest/GetChannelInvites.cs | 20 + src/Discord.Net/API/Rest/GetChannelMessages.cs | 34 + src/Discord.Net/API/Rest/GetCurrentUser.cs | 11 + .../API/Rest/GetCurrentUserConnections.cs | 11 + src/Discord.Net/API/Rest/GetCurrentUserDMs.cs | 11 + src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs | 11 + src/Discord.Net/API/Rest/GetGateway.cs | 18 + src/Discord.Net/API/Rest/GetGuild.cs | 18 + src/Discord.Net/API/Rest/GetGuildBans.cs | 18 + src/Discord.Net/API/Rest/GetGuildChannels.cs | 18 + src/Discord.Net/API/Rest/GetGuildEmbed.cs | 18 + src/Discord.Net/API/Rest/GetGuildIntegrations.cs | 18 + src/Discord.Net/API/Rest/GetGuildInvites.cs | 18 + src/Discord.Net/API/Rest/GetGuildMember.cs | 20 + src/Discord.Net/API/Rest/GetGuildPruneCount.cs | 29 + src/Discord.Net/API/Rest/GetGuildRoles.cs | 18 + src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs | 18 + src/Discord.Net/API/Rest/GetInvite.cs | 18 + src/Discord.Net/API/Rest/GetUser.cs | 18 + .../API/{Client => }/Rest/GetVoiceRegions.cs | 18 +- .../API/{Client => }/Rest/LeaveGuild.cs | 7 +- src/Discord.Net/API/Rest/ListGuildMembers.cs | 24 + .../ModifyChannelPermission.cs} | 16 +- .../UpdateProfile.cs => Rest/ModifyCurrentUser.cs} | 23 +- src/Discord.Net/API/Rest/ModifyGuild.cs | 39 + .../ModifyGuildChannel.cs} | 13 +- src/Discord.Net/API/Rest/ModifyGuildChannels.cs | 22 + src/Discord.Net/API/Rest/ModifyGuildEmbed.cs | 25 + src/Discord.Net/API/Rest/ModifyGuildIntegration.cs | 29 + .../UpdateMember.cs => Rest/ModifyGuildMember.cs} | 20 +- src/Discord.Net/API/Rest/ModifyGuildRole.cs | 32 + src/Discord.Net/API/Rest/ModifyGuildRoles.cs | 21 + .../UpdateMessage.cs => Rest/ModifyMessage.cs} | 9 +- src/Discord.Net/API/Rest/ModifyTextChannel.cs | 16 + src/Discord.Net/API/Rest/ModifyVoiceChannel.cs | 16 + src/Discord.Net/API/Rest/QueryUser.cs | 19 + .../API/{Client => }/Rest/RemoveGuildBan.cs | 9 +- src/Discord.Net/API/Rest/RemoveGuildMember.cs | 20 + src/Discord.Net/API/Rest/SyncGuildIntegration.cs | 21 + src/Discord.Net/API/Rest/TriggerTypingIndicator.cs | 18 + .../{Client/Rest => Rest/Unconfirmed}/SendFile.cs | 18 +- src/Discord.Net/API/Status/Common/StatusResult.cs | 80 -- .../API/Status/Rest/ActiveMaintenances.cs | 12 - src/Discord.Net/API/Status/Rest/AllIncidents.cs | 12 - .../API/Status/Rest/UnresolvedIncidents.cs | 12 - .../API/Status/Rest/UpcomingMaintenances.cs | 12 - .../OpCodes.cs => VoiceSocket/OpCode.cs} | 6 +- .../VoiceSocket/Unconfirmed/Commands/Heartbeat.cs | 10 + .../VoiceSocket/Unconfirmed/Commands/Identify.cs | 19 + .../Unconfirmed/Commands/SelectProtocol.cs | 28 + .../Unconfirmed}/Commands/SetSpeaking.cs | 5 +- .../Unconfirmed}/Events/Ready.cs | 2 +- .../Unconfirmed}/Events/SessionDescription.cs | 2 +- .../Unconfirmed}/Events/Speaking.cs | 7 +- src/Discord.Net/CDN.cs | 12 + src/Discord.Net/Discord.Net.Net45.csproj | 305 +++++ src/Discord.Net/Discord.Net.Net45.project.json | 12 + .../Discord.Net.Net45.project.lock.json | 88 ++ src/Discord.Net/Discord.Net.xproj | 12 +- src/Discord.Net/DiscordClient.Events.cs | 108 -- src/Discord.Net/DiscordClient.cs | 1227 ++++---------------- src/Discord.Net/DiscordConfig.cs | 142 +-- src/Discord.Net/DiscordSocketClient.cs | 176 +++ src/Discord.Net/DynamicIL.cs | 49 - src/Discord.Net/ETF/ETFReader.cs | 491 -------- src/Discord.Net/ETF/ETFType.cs | 32 - src/Discord.Net/ETF/ETFWriter.cs | 482 -------- src/Discord.Net/Entities/Attachment.cs | 18 + src/Discord.Net/Entities/Channel.cs | 55 - src/Discord.Net/Entities/Channels/DMChannel.cs | 99 ++ src/Discord.Net/Entities/Channels/GuildChannel.cs | 130 +++ .../Discord.Net}/Entities/Channels/IChannel.cs | 7 +- .../Entities/Channels/IMessageChannel.cs | 4 +- src/Discord.Net/Entities/Channels/TextChannel.cs | 67 ++ src/Discord.Net/Entities/Channels/VoiceChannel.cs | 39 + src/Discord.Net/Entities/Color.cs | 41 +- src/Discord.Net/Entities/Embed.cs | 25 + src/Discord.Net/Entities/EmbedProvider.cs | 16 + src/Discord.Net/Entities/EmbedThumbnail.cs | 20 + src/Discord.Net/Entities/Emoji.cs | 28 + src/Discord.Net/Entities/Guild.cs | 383 ++++++ src/Discord.Net/Entities/Helpers/InviteManager.cs | 8 + src/Discord.Net/Entities/Helpers/MentionHelper.cs | 111 ++ src/Discord.Net/Entities/Helpers/MessageManager.cs | 174 +++ .../Entities/Helpers/PermissionManager.cs | 274 +++++ .../Entities/Helpers/PermissionsHelper.cs | 61 + src/Discord.Net/Entities/IChannel.cs | 21 - {ref => src/Discord.Net}/Entities/IEntity.cs | 5 +- {ref => src/Discord.Net}/Entities/IMentionable.cs | 0 src/Discord.Net/Entities/IPrivateChannel.cs | 7 - src/Discord.Net/Entities/IPublicChannel.cs | 6 - src/Discord.Net/Entities/ITextChannel.cs | 17 - src/Discord.Net/Entities/IVoiceChannel.cs | 6 - src/Discord.Net/Entities/Invite.cs | 151 --- src/Discord.Net/Entities/Invites/GuildInvite.cs | 71 ++ src/Discord.Net/Entities/Invites/IInvite.cs | 20 + src/Discord.Net/Entities/Invites/Invite.cs | 48 + src/Discord.Net/Entities/Invites/InviteChannel.cs | 16 + src/Discord.Net/Entities/Invites/InviteGuild.cs | 16 + .../Entities/Managers/MessageManager.cs | 146 --- .../Entities/Managers/PermissionManager.cs | 223 ---- src/Discord.Net/Entities/Message.cs | 375 ++---- src/Discord.Net/Entities/Permissions.cs | 345 ------ .../Entities/Permissions/ChannelPermissions.cs | 122 ++ .../Entities/Permissions/GuildPermissions.cs | 119 ++ src/Discord.Net/Entities/Permissions/Overwrite.cs | 22 + .../Entities/Permissions/OverwritePermissions.cs | 113 ++ .../Entities/Presences/GuildPresence.cs | 33 + src/Discord.Net/Entities/Presences/Presence.cs | 18 + src/Discord.Net/Entities/Presences/VoiceState.cs | 66 ++ src/Discord.Net/Entities/PrivateChannel.cs | 66 -- src/Discord.Net/Entities/Profile.cs | 92 -- src/Discord.Net/Entities/PublicChannel.cs | 109 -- src/Discord.Net/Entities/Region.cs | 22 - src/Discord.Net/Entities/Role.cs | 143 +-- src/Discord.Net/Entities/Server.cs | 511 -------- src/Discord.Net/Entities/TextChannel.cs | 88 -- src/Discord.Net/Entities/User.cs | 356 ------ src/Discord.Net/Entities/Users/DMUser.cs | 15 + src/Discord.Net/Entities/Users/GuildUser.cs | 48 + src/Discord.Net/Entities/Users/PublicUser.cs | 13 + src/Discord.Net/Entities/Users/SelfUser.cs | 26 + src/Discord.Net/Entities/Users/User.cs | 39 + src/Discord.Net/Entities/VoiceChannel.cs | 60 - src/Discord.Net/Entities/VoiceRegion.cs | 60 + src/Discord.Net/EnumConverters.cs | 42 - src/Discord.Net/Enums/ChannelType.cs | 14 +- src/Discord.Net/Enums/ConnectionState.cs | 2 +- src/Discord.Net/Enums/ImageType.cs | 9 - src/Discord.Net/Enums/LogSeverity.cs | 3 +- src/Discord.Net/Enums/MessageState.cs | 18 - src/Discord.Net/Enums/PermissionBits.cs | 4 +- src/Discord.Net/Enums/PermissionTarget.cs | 8 +- src/Discord.Net/Enums/Relative.cs | 3 +- src/Discord.Net/Enums/StringEnum.cs | 14 - src/Discord.Net/Enums/UserStatus.cs | 41 +- src/Discord.Net/Events/ChannelEventArgs.cs | 5 +- src/Discord.Net/Events/ChannelUpdatedEventArgs.cs | 10 +- src/Discord.Net/Events/CurrentUserEventArgs.cs | 14 + .../Events/CurrentUserUpdatedEventArgs.cs | 14 + src/Discord.Net/Events/DisconnectedEventArgs.cs | 4 +- src/Discord.Net/Events/GuildEventArgs.cs | 14 + src/Discord.Net/Events/GuildUpdatedEventArgs.cs | 14 + src/Discord.Net/Events/LogMessageEventArgs.cs | 47 +- src/Discord.Net/Events/MessageEventArgs.cs | 9 +- src/Discord.Net/Events/MessageUpdatedEventArgs.cs | 14 +- src/Discord.Net/Events/ProfileUpdatedEventArgs.cs | 16 - src/Discord.Net/Events/RoleEventArgs.cs | 7 +- src/Discord.Net/Events/RoleUpdatedEventArgs.cs | 12 +- src/Discord.Net/Events/ServerEventArgs.cs | 11 - src/Discord.Net/Events/ServerUpdatedEventArgs.cs | 16 - src/Discord.Net/Events/TypingEventArgs.cs | 10 +- src/Discord.Net/Events/UserEventArgs.cs | 8 +- src/Discord.Net/Events/UserUpdatedEventArgs.cs | 11 +- src/Discord.Net/Events/VoiceChannelEventArgs.cs | 14 + src/Discord.Net/Format.cs | 189 ++- src/Discord.Net/IMentionable.cs | 7 - src/Discord.Net/IModel.cs | 11 - src/Discord.Net/IService.cs | 7 - src/Discord.Net/InternalExtensions.cs | 77 +- src/Discord.Net/Logging/ILogger.cs | 44 - src/Discord.Net/Logging/LogManager.cs | 51 +- src/Discord.Net/Logging/Logger.cs | 34 +- src/Discord.Net/MessageQueue.cs | 256 ++-- src/Discord.Net/Net/HttpException.cs | 26 +- .../Net/JsonConverters/ChannelTypeConverter.cs | 40 + .../Net/JsonConverters/ImageConverter.cs | 29 + .../Net/JsonConverters/NullableUInt64Converter.cs | 30 + .../JsonConverters/PermissionTargetConverter.cs | 40 + .../Net/JsonConverters/StringEntityConverter.cs | 25 + .../Net/JsonConverters/UInt64ArrayConverter.cs | 43 + .../Net/JsonConverters/UInt64Converter.cs | 23 + .../Net/JsonConverters/UInt64EntityConverter.cs | 25 + .../Net/JsonConverters/UserStatusConverter.cs | 45 + src/Discord.Net/Net/Rest/BuiltInEngine.cs | 145 --- .../Net/Rest/CompletedRequestEventArgs.cs | 19 - src/Discord.Net/Net/Rest/DefaultRestEngine.cs | 127 ++ src/Discord.Net/Net/Rest/ETFRestClient.cs | 27 - src/Discord.Net/Net/Rest/IRestEngine.cs | 17 +- {ref => src/Discord.Net}/Net/Rest/IRestRequest.cs | 12 +- src/Discord.Net/Net/Rest/JsonRestClient.cs | 42 - src/Discord.Net/Net/Rest/RequestEventArgs.cs | 16 - src/Discord.Net/Net/Rest/RestClient.cs | 166 +-- src/Discord.Net/Net/Rest/RestClientProvider.cs | 6 + src/Discord.Net/Net/Rest/RestParameter.cs | 19 + src/Discord.Net/Net/Rest/SentRequestEventArgs.cs | 16 + src/Discord.Net/Net/Rest/SharpRestEngine.cs | 132 --- src/Discord.Net/Net/TimeoutException.cs | 15 - src/Discord.Net/Net/WebSocketException.cs | 25 - .../Net/WebSockets/BinaryMessageEventArgs.cs | 2 +- ...{BuiltInEngine.cs => DefaultWebSocketEngine.cs} | 106 +- src/Discord.Net/Net/WebSockets/GatewaySocket.cs | 188 +-- src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs | 20 +- src/Discord.Net/Net/WebSockets/WS4NetEngine.cs | 141 --- src/Discord.Net/Net/WebSockets/WebSocket.cs | 193 +-- .../Net/WebSockets/WebSocketEventEventArgs.cs | 6 - .../Net/WebSockets/WebSocketProvider.cs | 6 + src/Discord.Net/Properties/AssemblyInfo.cs | 18 + src/Discord.Net/ServiceCollection.cs | 44 - src/Discord.Net/TaskHelper.cs | 18 + src/Discord.Net/TaskManager.cs | 179 --- src/Discord.Net/project.json | 76 +- test/Discord.Net.Tests/Discord.Net.Tests.csproj | 15 +- test/Discord.Net.Tests/Settings.cs | 32 - test/Discord.Net.Tests/Tests.cs | 641 +++++++--- 470 files changed, 6774 insertions(+), 14012 deletions(-) create mode 100644 NuGet.config delete mode 100644 ref/Discord.Net.xproj delete mode 100644 ref/DiscordClient.cs delete mode 100644 ref/DiscordConfig.cs delete mode 100644 ref/Entities/Channels/IPublicChannel.cs delete mode 100644 ref/Entities/Channels/PrivateChannel.cs delete mode 100644 ref/Entities/Channels/TextChannel.cs delete mode 100644 ref/Entities/Channels/VoiceChannel.cs delete mode 100644 ref/Entities/Color.cs delete mode 100644 ref/Entities/IModifiable.cs delete mode 100644 ref/Entities/Invite/BasicInvite.cs delete mode 100644 ref/Entities/Invite/Invite.cs delete mode 100644 ref/Entities/Message.cs delete mode 100644 ref/Entities/Permissions/ChannelPermissions.cs delete mode 100644 ref/Entities/Permissions/OverwritePermissions.cs delete mode 100644 ref/Entities/Permissions/PermissionOverwriteEntry.cs delete mode 100644 ref/Entities/Permissions/ServerPermissions.cs delete mode 100644 ref/Entities/Profile.cs delete mode 100644 ref/Entities/Region.cs delete mode 100644 ref/Entities/Role.cs delete mode 100644 ref/Entities/Server.cs delete mode 100644 ref/Entities/Users/IUser.cs delete mode 100644 ref/Entities/Users/PrivateUser.cs delete mode 100644 ref/Entities/Users/ServerUser.cs delete mode 100644 ref/Enums/ChannelType.cs delete mode 100644 ref/Enums/ConnectionState.cs delete mode 100644 ref/Enums/EntityState.cs delete mode 100644 ref/Enums/ImageType.cs delete mode 100644 ref/Enums/LogSeverity.cs delete mode 100644 ref/Enums/PermValue.cs delete mode 100644 ref/Enums/PermissionTarget.cs delete mode 100644 ref/Enums/Relative.cs delete mode 100644 ref/Enums/UserStatus.cs delete mode 100644 ref/Events/ChannelEventArgs.cs delete mode 100644 ref/Events/ChannelUpdatedEventArgs.cs delete mode 100644 ref/Events/DisconnectedEventArgs.cs delete mode 100644 ref/Events/LogMessageEventArgs.cs delete mode 100644 ref/Events/MessageEventArgs.cs delete mode 100644 ref/Events/MessageUpdatedEventArgs.cs delete mode 100644 ref/Events/ProfileUpdatedEventArgs.cs delete mode 100644 ref/Events/RoleEventArgs.cs delete mode 100644 ref/Events/RoleUpdatedEventArgs.cs delete mode 100644 ref/Events/ServerEventArgs.cs delete mode 100644 ref/Events/ServerUpdatedEventArgs.cs delete mode 100644 ref/Events/TypingEventArgs.cs delete mode 100644 ref/Events/UserEventArgs.cs delete mode 100644 ref/Events/UserUpdatedEventArgs.cs delete mode 100644 ref/Format.cs delete mode 100644 ref/ILogger.cs delete mode 100644 ref/MessageQueue.cs delete mode 100644 ref/Net/HttpException.cs delete mode 100644 ref/Net/Rest/CompletedRequestEventArgs.cs delete mode 100644 ref/Net/Rest/IRestClient.cs delete mode 100644 ref/Net/Rest/IRestClientProvider.cs delete mode 100644 ref/Net/Rest/RequestEventArgs.cs delete mode 100644 ref/Net/TimeoutException.cs delete mode 100644 ref/Net/WebSocketException.cs delete mode 100644 ref/Net/WebSockets/BinaryMessageEventArgs.cs delete mode 100644 ref/Net/WebSockets/GatewaySocket.cs delete mode 100644 ref/Net/WebSockets/IWebSocket.cs delete mode 100644 ref/Net/WebSockets/IWebSocketEngine.cs delete mode 100644 ref/Net/WebSockets/IWebSocketProvider.cs delete mode 100644 ref/Net/WebSockets/TextMessageEventArgs.cs delete mode 100644 ref/Net/WebSockets/WebSocketEventEventArgs.cs delete mode 100644 ref/project.json delete mode 100644 src/Discord.Net.Audio/AudioClient.cs delete mode 100644 src/Discord.Net.Audio/AudioExtensions.cs delete mode 100644 src/Discord.Net.Audio/AudioMode.cs delete mode 100644 src/Discord.Net.Audio/AudioService.cs delete mode 100644 src/Discord.Net.Audio/AudioServiceConfig.cs delete mode 100644 src/Discord.Net.Audio/Discord.Net.Audio.xproj delete mode 100644 src/Discord.Net.Audio/IAudioClient.cs delete mode 100644 src/Discord.Net.Audio/InternalFrameEventArgs.cs delete mode 100644 src/Discord.Net.Audio/InternalIsSpeakingEventArgs.cs delete mode 100644 src/Discord.Net.Audio/Net/VoiceSocket.cs delete mode 100644 src/Discord.Net.Audio/Opus/OpusConverter.cs delete mode 100644 src/Discord.Net.Audio/Opus/OpusDecoder.cs delete mode 100644 src/Discord.Net.Audio/Opus/OpusEncoder.cs delete mode 100644 src/Discord.Net.Audio/Sodium/SecretBox.cs delete mode 100644 src/Discord.Net.Audio/UserIsTalkingEventArgs.cs delete mode 100644 src/Discord.Net.Audio/VirtualClient.cs delete mode 100644 src/Discord.Net.Audio/VoiceBuffer.cs delete mode 100644 src/Discord.Net.Audio/VoiceDisconnectedEventArgs.cs delete mode 100644 src/Discord.Net.Audio/libsodium.dll delete mode 100644 src/Discord.Net.Audio/opus.dll delete mode 100644 src/Discord.Net.Audio/project.json delete mode 100644 src/Discord.Net.Commands/Command.cs delete mode 100644 src/Discord.Net.Commands/CommandBuilder.cs delete mode 100644 src/Discord.Net.Commands/CommandErrorEventArgs.cs delete mode 100644 src/Discord.Net.Commands/CommandEventArgs.cs delete mode 100644 src/Discord.Net.Commands/CommandExtensions.cs delete mode 100644 src/Discord.Net.Commands/CommandMap.cs delete mode 100644 src/Discord.Net.Commands/CommandParameter.cs delete mode 100644 src/Discord.Net.Commands/CommandParser.cs delete mode 100644 src/Discord.Net.Commands/CommandService.cs delete mode 100644 src/Discord.Net.Commands/CommandServiceConfig.cs delete mode 100644 src/Discord.Net.Commands/Discord.Net.Commands.xproj delete mode 100644 src/Discord.Net.Commands/GenericPermissionChecker.cs delete mode 100644 src/Discord.Net.Commands/HelpMode.cs delete mode 100644 src/Discord.Net.Commands/IPermissionChecker.cs delete mode 100644 src/Discord.Net.Commands/project.json delete mode 100644 src/Discord.Net.Modules/Discord.Net.Modules.xproj delete mode 100644 src/Discord.Net.Modules/IModule.cs delete mode 100644 src/Discord.Net.Modules/ModuleChecker.cs delete mode 100644 src/Discord.Net.Modules/ModuleExtensions.cs delete mode 100644 src/Discord.Net.Modules/ModuleFilter.cs delete mode 100644 src/Discord.Net.Modules/ModuleManager.cs delete mode 100644 src/Discord.Net.Modules/ModuleService.cs delete mode 100644 src/Discord.Net.Modules/project.json delete mode 100644 src/Discord.Net.Shared/Discord.Net.Shared.projitems delete mode 100644 src/Discord.Net.Shared/Discord.Net.Shared.shproj delete mode 100644 src/Discord.Net.Shared/EpochTime.cs delete mode 100644 src/Discord.Net.Shared/TaskExtensions.cs delete mode 100644 src/Discord.Net.Shared/TaskHelper.cs delete mode 100644 src/Discord.Net/API/Client/Common/Channel.cs delete mode 100644 src/Discord.Net/API/Client/Common/ChannelReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/ExtendedMember.cs delete mode 100644 src/Discord.Net/API/Client/Common/Guild.cs delete mode 100644 src/Discord.Net/API/Client/Common/GuildReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/Invite.cs delete mode 100644 src/Discord.Net/API/Client/Common/InviteReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/Member.cs delete mode 100644 src/Discord.Net/API/Client/Common/MemberPresence.cs delete mode 100644 src/Discord.Net/API/Client/Common/MemberReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/Message.cs delete mode 100644 src/Discord.Net/API/Client/Common/MessageReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/RoleReference.cs delete mode 100644 src/Discord.Net/API/Client/Common/User.cs delete mode 100644 src/Discord.Net/API/Client/Common/UserReference.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs delete mode 100644 src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs delete mode 100644 src/Discord.Net/API/Client/ISerializable.cs delete mode 100644 src/Discord.Net/API/Client/Rest/AcceptInvite.cs delete mode 100644 src/Discord.Net/API/Client/Rest/AddGuildBan.cs delete mode 100644 src/Discord.Net/API/Client/Rest/DeleteRole.cs delete mode 100644 src/Discord.Net/API/Client/Rest/Gateway.cs delete mode 100644 src/Discord.Net/API/Client/Rest/GetBans.cs delete mode 100644 src/Discord.Net/API/Client/Rest/GetInvite.cs delete mode 100644 src/Discord.Net/API/Client/Rest/GetInvites.cs delete mode 100644 src/Discord.Net/API/Client/Rest/GetMessages.cs delete mode 100644 src/Discord.Net/API/Client/Rest/GetWidget.cs delete mode 100644 src/Discord.Net/API/Client/Rest/KickMember.cs delete mode 100644 src/Discord.Net/API/Client/Rest/Login.cs delete mode 100644 src/Discord.Net/API/Client/Rest/Logout.cs delete mode 100644 src/Discord.Net/API/Client/Rest/PruneMembers.cs delete mode 100644 src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs delete mode 100644 src/Discord.Net/API/Client/Rest/ReorderChannels.cs delete mode 100644 src/Discord.Net/API/Client/Rest/ReorderRoles.cs delete mode 100644 src/Discord.Net/API/Client/Rest/SendIsTyping.cs delete mode 100644 src/Discord.Net/API/Client/Rest/UpdateGuild.cs delete mode 100644 src/Discord.Net/API/Client/Rest/UpdateRole.cs delete mode 100644 src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs delete mode 100644 src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs delete mode 100644 src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs create mode 100644 src/Discord.Net/API/Common/Attachment.cs create mode 100644 src/Discord.Net/API/Common/Channel.cs create mode 100644 src/Discord.Net/API/Common/Embed.cs create mode 100644 src/Discord.Net/API/Common/EmbedProvider.cs create mode 100644 src/Discord.Net/API/Common/EmbedThumbnail.cs create mode 100644 src/Discord.Net/API/Common/Emoji.cs create mode 100644 src/Discord.Net/API/Common/Guild.cs create mode 100644 src/Discord.Net/API/Common/GuildEmbed.cs create mode 100644 src/Discord.Net/API/Common/GuildMember.cs create mode 100644 src/Discord.Net/API/Common/Integration.cs create mode 100644 src/Discord.Net/API/Common/IntegrationAccount.cs create mode 100644 src/Discord.Net/API/Common/Invite.cs create mode 100644 src/Discord.Net/API/Common/InviteChannel.cs create mode 100644 src/Discord.Net/API/Common/InviteGuild.cs create mode 100644 src/Discord.Net/API/Common/InviteMetadata.cs create mode 100644 src/Discord.Net/API/Common/Message.cs create mode 100644 src/Discord.Net/API/Common/ReadState.cs create mode 100644 src/Discord.Net/API/Common/Unconfirmed/Connection.cs rename src/Discord.Net/API/{Client/Common => Common/Unconfirmed}/ExtendedGuild.cs (95%) create mode 100644 src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs create mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs create mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs create mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs rename src/Discord.Net/API/{Client/Common => Common/Unconfirmed}/MemberVoiceState.cs (55%) create mode 100644 src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs create mode 100644 src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs rename src/Discord.Net/API/{Client/Common => Common/Unconfirmed}/Role.cs (77%) create mode 100644 src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs create mode 100644 src/Discord.Net/API/Common/User.cs create mode 100644 src/Discord.Net/API/Common/UserGuild.cs delete mode 100644 src/Discord.Net/API/Converters.cs delete mode 100644 src/Discord.Net/API/Extensions.cs rename src/Discord.Net/API/{Client/GatewaySocket/OpCodes.cs => GatewaySocket/OpCode.cs} (67%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Commands/Identify.cs (73%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Commands/RequestMembers.cs (53%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Commands/Resume.cs (69%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Commands/UpdateStatus.cs (74%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Commands/UpdateVoice.cs (51%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/ChannelCreate.cs (52%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/ChannelDelete.cs (54%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/ChannelUpdate.cs (54%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildBanAdd.cs (56%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildBanRemove.cs (57%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildCreate.cs (55%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildDelete.cs (55%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildMemberAdd.cs (57%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildMembersChunk.cs (51%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildRoleDelete.cs (57%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/GuildUpdate.cs (52%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/MessageAck.cs (56%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/MessageCreate.cs (54%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/MessageDelete.cs (57%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/MessageUpdate.cs (54%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/PresenceUpdate.cs (57%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/Ready.cs (96%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/Redirect.cs (77%) rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/Resumed.cs (79%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/UserUpdate.cs (51%) create mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs rename src/Discord.Net/API/{Client/GatewaySocket => GatewaySocket/Unconfirmed}/Events/VoiceStateUpdate.cs (58%) delete mode 100644 src/Discord.Net/API/IRestRequest.cs rename src/Discord.Net/API/{Client => }/IWebSocketMessage.cs (92%) create mode 100644 src/Discord.Net/API/Rest/AcceptInvite.cs rename src/Discord.Net/API/{Client => }/Rest/AckMessage.cs (59%) create mode 100644 src/Discord.Net/API/Rest/BeginGuildPrune.cs rename src/Discord.Net/API/{Client/Rest/CreateInvite.cs => Rest/CreateChannelInvite.cs} (62%) rename src/Discord.Net/API/{Client/Rest/CreatePrivateChannel.cs => Rest/CreateDMChannel.cs} (56%) rename src/Discord.Net/API/{Client => }/Rest/CreateGuild.cs (63%) create mode 100644 src/Discord.Net/API/Rest/CreateGuildBan.cs rename src/Discord.Net/API/{Client/Rest/CreateChannel.cs => Rest/CreateGuildChannel.cs} (73%) create mode 100644 src/Discord.Net/API/Rest/CreateGuildIntegration.cs rename src/Discord.Net/API/{Client/Rest/CreateRole.cs => Rest/CreateGuildRole.cs} (69%) rename src/Discord.Net/API/{Client/Rest/SendMessage.cs => Rest/CreateMessage.cs} (51%) rename src/Discord.Net/API/{Client => }/Rest/DeleteChannel.cs (69%) create mode 100644 src/Discord.Net/API/Rest/DeleteChannelPermission.cs rename src/Discord.Net/API/{Client => }/Rest/DeleteGuild.cs (69%) create mode 100644 src/Discord.Net/API/Rest/DeleteGuildIntegration.cs create mode 100644 src/Discord.Net/API/Rest/DeleteGuildRole.cs rename src/Discord.Net/API/{Client => }/Rest/DeleteInvite.cs (56%) rename src/Discord.Net/API/{Client => }/Rest/DeleteMessage.cs (67%) create mode 100644 src/Discord.Net/API/Rest/GetChannel.cs create mode 100644 src/Discord.Net/API/Rest/GetChannelInvites.cs create mode 100644 src/Discord.Net/API/Rest/GetChannelMessages.cs create mode 100644 src/Discord.Net/API/Rest/GetCurrentUser.cs create mode 100644 src/Discord.Net/API/Rest/GetCurrentUserConnections.cs create mode 100644 src/Discord.Net/API/Rest/GetCurrentUserDMs.cs create mode 100644 src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs create mode 100644 src/Discord.Net/API/Rest/GetGateway.cs create mode 100644 src/Discord.Net/API/Rest/GetGuild.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildBans.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildChannels.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildEmbed.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildIntegrations.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildInvites.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildMember.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildPruneCount.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildRoles.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs create mode 100644 src/Discord.Net/API/Rest/GetInvite.cs create mode 100644 src/Discord.Net/API/Rest/GetUser.cs rename src/Discord.Net/API/{Client => }/Rest/GetVoiceRegions.cs (65%) rename src/Discord.Net/API/{Client => }/Rest/LeaveGuild.cs (69%) create mode 100644 src/Discord.Net/API/Rest/ListGuildMembers.cs rename src/Discord.Net/API/{Client/Rest/AddChannelPermission.cs => Rest/ModifyChannelPermission.cs} (50%) rename src/Discord.Net/API/{Client/Rest/UpdateProfile.cs => Rest/ModifyCurrentUser.cs} (57%) create mode 100644 src/Discord.Net/API/Rest/ModifyGuild.cs rename src/Discord.Net/API/{Client/Rest/UpdateChannel.cs => Rest/ModifyGuildChannel.cs} (59%) create mode 100644 src/Discord.Net/API/Rest/ModifyGuildChannels.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildEmbed.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildIntegration.cs rename src/Discord.Net/API/{Client/Rest/UpdateMember.cs => Rest/ModifyGuildMember.cs} (50%) create mode 100644 src/Discord.Net/API/Rest/ModifyGuildRole.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildRoles.cs rename src/Discord.Net/API/{Client/Rest/UpdateMessage.cs => Rest/ModifyMessage.cs} (77%) create mode 100644 src/Discord.Net/API/Rest/ModifyTextChannel.cs create mode 100644 src/Discord.Net/API/Rest/ModifyVoiceChannel.cs create mode 100644 src/Discord.Net/API/Rest/QueryUser.cs rename src/Discord.Net/API/{Client => }/Rest/RemoveGuildBan.cs (67%) create mode 100644 src/Discord.Net/API/Rest/RemoveGuildMember.cs create mode 100644 src/Discord.Net/API/Rest/SyncGuildIntegration.cs create mode 100644 src/Discord.Net/API/Rest/TriggerTypingIndicator.cs rename src/Discord.Net/API/{Client/Rest => Rest/Unconfirmed}/SendFile.cs (50%) delete mode 100644 src/Discord.Net/API/Status/Common/StatusResult.cs delete mode 100644 src/Discord.Net/API/Status/Rest/ActiveMaintenances.cs delete mode 100644 src/Discord.Net/API/Status/Rest/AllIncidents.cs delete mode 100644 src/Discord.Net/API/Status/Rest/UnresolvedIncidents.cs delete mode 100644 src/Discord.Net/API/Status/Rest/UpcomingMaintenances.cs rename src/Discord.Net/API/{Client/VoiceSocket/OpCodes.cs => VoiceSocket/OpCode.cs} (81%) create mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs create mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs create mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs rename src/Discord.Net/API/{Client/VoiceSocket => VoiceSocket/Unconfirmed}/Commands/SetSpeaking.cs (66%) rename src/Discord.Net/API/{Client/VoiceSocket => VoiceSocket/Unconfirmed}/Events/Ready.cs (90%) rename src/Discord.Net/API/{Client/VoiceSocket => VoiceSocket/Unconfirmed}/Events/SessionDescription.cs (85%) rename src/Discord.Net/API/{Client/VoiceSocket => VoiceSocket/Unconfirmed}/Events/Speaking.cs (57%) create mode 100644 src/Discord.Net/CDN.cs create mode 100644 src/Discord.Net/Discord.Net.Net45.csproj create mode 100644 src/Discord.Net/Discord.Net.Net45.project.json create mode 100644 src/Discord.Net/Discord.Net.Net45.project.lock.json delete mode 100644 src/Discord.Net/DiscordClient.Events.cs create mode 100644 src/Discord.Net/DiscordSocketClient.cs delete mode 100644 src/Discord.Net/DynamicIL.cs delete mode 100644 src/Discord.Net/ETF/ETFReader.cs delete mode 100644 src/Discord.Net/ETF/ETFType.cs delete mode 100644 src/Discord.Net/ETF/ETFWriter.cs create mode 100644 src/Discord.Net/Entities/Attachment.cs delete mode 100644 src/Discord.Net/Entities/Channel.cs create mode 100644 src/Discord.Net/Entities/Channels/DMChannel.cs create mode 100644 src/Discord.Net/Entities/Channels/GuildChannel.cs rename {ref => src/Discord.Net}/Entities/Channels/IChannel.cs (80%) rename ref/Entities/Channels/ITextChannel.cs => src/Discord.Net/Entities/Channels/IMessageChannel.cs (95%) create mode 100644 src/Discord.Net/Entities/Channels/TextChannel.cs create mode 100644 src/Discord.Net/Entities/Channels/VoiceChannel.cs create mode 100644 src/Discord.Net/Entities/Embed.cs create mode 100644 src/Discord.Net/Entities/EmbedProvider.cs create mode 100644 src/Discord.Net/Entities/EmbedThumbnail.cs create mode 100644 src/Discord.Net/Entities/Emoji.cs create mode 100644 src/Discord.Net/Entities/Guild.cs create mode 100644 src/Discord.Net/Entities/Helpers/InviteManager.cs create mode 100644 src/Discord.Net/Entities/Helpers/MentionHelper.cs create mode 100644 src/Discord.Net/Entities/Helpers/MessageManager.cs create mode 100644 src/Discord.Net/Entities/Helpers/PermissionManager.cs create mode 100644 src/Discord.Net/Entities/Helpers/PermissionsHelper.cs delete mode 100644 src/Discord.Net/Entities/IChannel.cs rename {ref => src/Discord.Net}/Entities/IEntity.cs (81%) rename {ref => src/Discord.Net}/Entities/IMentionable.cs (100%) delete mode 100644 src/Discord.Net/Entities/IPrivateChannel.cs delete mode 100644 src/Discord.Net/Entities/IPublicChannel.cs delete mode 100644 src/Discord.Net/Entities/ITextChannel.cs delete mode 100644 src/Discord.Net/Entities/IVoiceChannel.cs delete mode 100644 src/Discord.Net/Entities/Invite.cs create mode 100644 src/Discord.Net/Entities/Invites/GuildInvite.cs create mode 100644 src/Discord.Net/Entities/Invites/IInvite.cs create mode 100644 src/Discord.Net/Entities/Invites/Invite.cs create mode 100644 src/Discord.Net/Entities/Invites/InviteChannel.cs create mode 100644 src/Discord.Net/Entities/Invites/InviteGuild.cs delete mode 100644 src/Discord.Net/Entities/Managers/MessageManager.cs delete mode 100644 src/Discord.Net/Entities/Managers/PermissionManager.cs delete mode 100644 src/Discord.Net/Entities/Permissions.cs create mode 100644 src/Discord.Net/Entities/Permissions/ChannelPermissions.cs create mode 100644 src/Discord.Net/Entities/Permissions/GuildPermissions.cs create mode 100644 src/Discord.Net/Entities/Permissions/Overwrite.cs create mode 100644 src/Discord.Net/Entities/Permissions/OverwritePermissions.cs create mode 100644 src/Discord.Net/Entities/Presences/GuildPresence.cs create mode 100644 src/Discord.Net/Entities/Presences/Presence.cs create mode 100644 src/Discord.Net/Entities/Presences/VoiceState.cs delete mode 100644 src/Discord.Net/Entities/PrivateChannel.cs delete mode 100644 src/Discord.Net/Entities/Profile.cs delete mode 100644 src/Discord.Net/Entities/PublicChannel.cs delete mode 100644 src/Discord.Net/Entities/Region.cs delete mode 100644 src/Discord.Net/Entities/Server.cs delete mode 100644 src/Discord.Net/Entities/TextChannel.cs delete mode 100644 src/Discord.Net/Entities/User.cs create mode 100644 src/Discord.Net/Entities/Users/DMUser.cs create mode 100644 src/Discord.Net/Entities/Users/GuildUser.cs create mode 100644 src/Discord.Net/Entities/Users/PublicUser.cs create mode 100644 src/Discord.Net/Entities/Users/SelfUser.cs create mode 100644 src/Discord.Net/Entities/Users/User.cs delete mode 100644 src/Discord.Net/Entities/VoiceChannel.cs create mode 100644 src/Discord.Net/Entities/VoiceRegion.cs delete mode 100644 src/Discord.Net/EnumConverters.cs delete mode 100644 src/Discord.Net/Enums/ImageType.cs delete mode 100644 src/Discord.Net/Enums/MessageState.cs delete mode 100644 src/Discord.Net/Enums/StringEnum.cs create mode 100644 src/Discord.Net/Events/CurrentUserEventArgs.cs create mode 100644 src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs create mode 100644 src/Discord.Net/Events/GuildEventArgs.cs create mode 100644 src/Discord.Net/Events/GuildUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/ProfileUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/ServerEventArgs.cs delete mode 100644 src/Discord.Net/Events/ServerUpdatedEventArgs.cs create mode 100644 src/Discord.Net/Events/VoiceChannelEventArgs.cs delete mode 100644 src/Discord.Net/IMentionable.cs delete mode 100644 src/Discord.Net/IModel.cs delete mode 100644 src/Discord.Net/IService.cs delete mode 100644 src/Discord.Net/Logging/ILogger.cs create mode 100644 src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/ImageConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/UInt64Converter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs create mode 100644 src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs delete mode 100644 src/Discord.Net/Net/Rest/BuiltInEngine.cs delete mode 100644 src/Discord.Net/Net/Rest/CompletedRequestEventArgs.cs create mode 100644 src/Discord.Net/Net/Rest/DefaultRestEngine.cs delete mode 100644 src/Discord.Net/Net/Rest/ETFRestClient.cs rename {ref => src/Discord.Net}/Net/Rest/IRestRequest.cs (53%) delete mode 100644 src/Discord.Net/Net/Rest/JsonRestClient.cs delete mode 100644 src/Discord.Net/Net/Rest/RequestEventArgs.cs create mode 100644 src/Discord.Net/Net/Rest/RestClientProvider.cs create mode 100644 src/Discord.Net/Net/Rest/RestParameter.cs create mode 100644 src/Discord.Net/Net/Rest/SentRequestEventArgs.cs delete mode 100644 src/Discord.Net/Net/Rest/SharpRestEngine.cs delete mode 100644 src/Discord.Net/Net/TimeoutException.cs delete mode 100644 src/Discord.Net/Net/WebSocketException.cs rename src/Discord.Net/Net/WebSockets/{BuiltInEngine.cs => DefaultWebSocketEngine.cs} (59%) delete mode 100644 src/Discord.Net/Net/WebSockets/WS4NetEngine.cs create mode 100644 src/Discord.Net/Net/WebSockets/WebSocketProvider.cs create mode 100644 src/Discord.Net/Properties/AssemblyInfo.cs delete mode 100644 src/Discord.Net/ServiceCollection.cs create mode 100644 src/Discord.Net/TaskHelper.cs delete mode 100644 src/Discord.Net/TaskManager.cs delete mode 100644 test/Discord.Net.Tests/Settings.cs diff --git a/Discord.Net.sln b/Discord.Net.sln index db11e8b30..bfcda2fab 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -1,17 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8D7989F0-66CE-4DBB-8230-D8C811E9B1D7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "netplatform", "netplatform", "{EA68EBE2-51C8-4440-9EF7-D633C90A5D35}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{ACFB060B-EC8A-4926-B293-04C01E17EE23}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{19793545-EF89-48F4-8100-3EBAAD0A9141}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net45", "net45", "{DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{2C91BDD7-621D-460F-B768-EAD106D9BA62}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6317A2E6-8E36-4C3E-949B-3F10EC888AB9}" EndProject @@ -22,104 +18,44 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net.Net45\Discord.Net.csproj", "{8D71A857-879A-4A10-859E-5FF824ED6688}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Modules", "src\Discord.Net.Modules\Discord.Net.Modules.xproj", "{01584E8A-78DA-486F-9EF9-A894E435841B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net45", "net45", "{628A40F4-2D06-4BCE-82EF-0EE70DD5C1CA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj", "{3091164F-66AE-4543-A63D-167C1116241D}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Audio", "src\Discord.Net.Audio\Discord.Net.Audio.xproj", "{DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Discord.Net.Shared", "src\Discord.Net.Shared\Discord.Net.Shared.shproj", "{2875DEB5-F248-4105-8EA2-5141E3DE8025}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Audio", "src\Discord.Net.Audio.Net45\Discord.Net.Audio.csproj", "{7BFEF748-B934-4621-9B11-6302E3A9F6B3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Net45", "src\Discord.Net\Discord.Net.Net45.csproj", "{C6A50D24-CBD3-4E76-852C-4DCA60BBD608}" EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - src\Discord.Net.Shared\Discord.Net.Shared.projitems*{2875deb5-f248-4105-8ea2-5141e3de8025}*SharedItemsImports = 13 - src\Discord.Net.Shared\Discord.Net.Shared.projitems*{7bfef748-b934-4621-9b11-6302e3a9f6b3}*SharedItemsImports = 4 - src\Discord.Net.Shared\Discord.Net.Shared.projitems*{1b5603b4-6f8f-4289-b945-7baae523d740}*SharedItemsImports = 4 - src\Discord.Net.Shared\Discord.Net.Shared.projitems*{3091164f-66ae-4543-a63d-167c1116241d}*SharedItemsImports = 4 - src\Discord.Net.Shared\Discord.Net.Shared.projitems*{8d71a857-879a-4a10-859e-5ff824ed6688}*SharedItemsImports = 4 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU FullDebug|Any CPU = FullDebug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ACFB060B-EC8A-4926-B293-04C01E17EE23}.Release|Any CPU.Build.0 = Release|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.Release|Any CPU.ActiveCfg = Release|Any CPU - {19793545-EF89-48F4-8100-3EBAAD0A9141}.Release|Any CPU.Build.0 = Release|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C91BDD7-621D-460F-B768-EAD106D9BA62}.Release|Any CPU.Build.0 = Release|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.Debug|Any CPU.Build.0 = Debug|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.FullDebug|Any CPU.Build.0 = Debug|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.Release|Any CPU.ActiveCfg = Release|Any CPU {855D6B1D-847B-42DA-BE6A-23683EA89511}.Release|Any CPU.Build.0 = Release|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.Build.0 = Release|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648}.Release|Any CPU.Build.0 = Release|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.Build.0 = Debug|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.Build.0 = Release|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.FullDebug|Any CPU.Build.0 = Debug|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} = {8D7989F0-66CE-4DBB-8230-D8C811E9B1D7} - {ACFB060B-EC8A-4926-B293-04C01E17EE23} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} - {19793545-EF89-48F4-8100-3EBAAD0A9141} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} - {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} = {8D7989F0-66CE-4DBB-8230-D8C811E9B1D7} + {2C91BDD7-621D-460F-B768-EAD106D9BA62} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} {855D6B1D-847B-42DA-BE6A-23683EA89511} = {6317A2E6-8E36-4C3E-949B-3F10EC888AB9} - {8D71A857-879A-4A10-859E-5FF824ED6688} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} - {1B5603B4-6F8F-4289-B945-7BAAE523D740} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} - {01584E8A-78DA-486F-9EF9-A894E435841B} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} - {3091164F-66AE-4543-A63D-167C1116241D} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} - {DFF7AFE3-CA77-4109-BADE-B4B49A4F6648} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} - {2875DEB5-F248-4105-8EA2-5141E3DE8025} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} - {7BFEF748-B934-4621-9B11-6302E3A9F6B3} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} + {628A40F4-2D06-4BCE-82EF-0EE70DD5C1CA} = {8D7989F0-66CE-4DBB-8230-D8C811E9B1D7} + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608} = {628A40F4-2D06-4BCE-82EF-0EE70DD5C1CA} EndGlobalSection EndGlobal diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 000000000..91bc2845a --- /dev/null +++ b/NuGet.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/docs/features/commands.rst b/docs/features/commands.rst index e6bd6bf82..8abfb18a9 100644 --- a/docs/features/commands.rst +++ b/docs/features/commands.rst @@ -1,7 +1,7 @@ |stub| Commands =============== -The `Discord.Net.Commands`_ package extends DiscordClient with a built-in Commands Handler. +The `Discord.Net.Commands`_ package DiscordBotClient extends DiscordClient with support for commands. .. _Discord.Net.Commands: https://www.nuget.org/packages/Discord.Net.Commands diff --git a/docs/features/events.rst b/docs/features/events.rst index d782c438e..2cfe27f54 100644 --- a/docs/features/events.rst +++ b/docs/features/events.rst @@ -3,19 +3,21 @@ Events Usage ----- -Messages from the Discord server are exposed via events on the DiscordClient class and follow the standard EventHandler C# pattern. +Messages from the Discord server are exposed via events on the DiscordClient class and follow the standard EventHandler C# pattern. .. warning:: - Note that all synchronous code in an event handler will run on the gateway socket's thread and should be handled as quickly as possible. + Note that all synchronous code in an event handler will run on the gateway socket's thread and should be handled as quickly as possible. Using the async-await pattern to let the thread continue immediately is recommended and is demonstrated in the examples below. -Ready ------ - -The Ready Event is raised only once, when your client finishes processing the READY packet from Discord. +Connection State +---------------- -This has replaced the previous "Connected" event, and indicates that it is safe to begin retrieving users, channels, or servers from the cache. +Connection Events will be raised when the Connection State of your client changes. +.. warning:: + You should not use DiscordClient.Connected to run code when your client first connects to Discord. + If you lose connection and automatically reconnect, this code will be ran again, which may lead to unexpected behavior. + Messages -------- @@ -24,7 +26,7 @@ Messages Example of MessageReceived: -.. code-block:: csharp6 +.. code-block:: c# // (Preface: Echo Bots are discouraged, make sure your bot is not running in a public server if you use them) @@ -54,7 +56,7 @@ There are several user events: Examples: -.. code-block:: csharp6 +.. code-block:: c# // Register a Hook into the UserBanned event using a Lambda _client.UserBanned += async (s, e) => { diff --git a/docs/features/logging.rst b/docs/features/logging.rst index c2f9d6ce3..4b9f254a5 100644 --- a/docs/features/logging.rst +++ b/docs/features/logging.rst @@ -2,12 +2,12 @@ Logging ======= Discord.Net will log all of its events/exceptions using a built-in LogManager. -This LogManager can be accessed through ``DiscordClient.Log`` +This LogManager can be accessed through DiscordClient.Log Usage ----- -To handle Log Messages through Discord.Net's Logger, you must hook into the ``Log.Message`` Event. +To handle Log Messages through Discord.Net's Logger, you must hook into the Log.Message Event. The LogManager does not provide a string-based result for the message, you must put your own message format together using the data provided through LogMessageEventArgs See the Example for a snippet of logging. @@ -17,25 +17,19 @@ Logging Your Own Data The LogManager included in Discord.Net can also be used to log your own messages. -You can use ``DiscordClient.Log.Log(LogSeverity, Source, Message, [Exception])``, or one of the shortcut helpers, to log data. +You can use DiscordClient.Log.Log(LogSeverity, Source, Message, Exception), or one of the shortcut helpers, to log data. Example: - -.. code-block:: csharp6 +.. code-block:: c# _client.MessageReceived += async (s, e) { // Log a new Message with Severity Info, Sourced from 'MessageReceived', with the Message Contents. _client.Log.Info("MessageReceived", e.Message.Text, null); }; - -.. warning:: - - Starting in Discord.Net 1.0, you will not be able to log your own messages. You will need to create your own Logging manager, or use a pre-existing one. - Example ------- .. literalinclude:: /samples/logging.cs - :language: csharp6 + :language: c# :tab-width: 2 diff --git a/docs/features/permissions.rst b/docs/features/permissions.rst index aa3856807..058fe07cf 100644 --- a/docs/features/permissions.rst +++ b/docs/features/permissions.rst @@ -1,21 +1,8 @@ Permissions =========== -|outdated| - There are two types of permissions: *Channel Permissions* and *Server Permissions*. -Permission Overrides --------------------- - -Channel Permissions are expressed using an enum, ``PermValue``. - -The three states are fairly straightforward - - -``PermValue.Allow``: Allow the user to perform a permission. -``PermValue.Deny``: Deny the user to perform a permission. -``PermValue.Inherit``: The user will inherit the permission from its role. - Channel Permissions ------------------- Channel Permissions are controlled using a set of flags: @@ -42,24 +29,27 @@ Speak Voice Speak in a voice channel. UseVoiceActivation Voice Use Voice Activation in a text channel (for large channels where PTT is preferred) ======================= ======= ============== -Each flag is a PermValue; see the section above. +If a user has a permission, the value is true. Otherwise, it must be null. -Setting Channel Permissions ---------------------------- +Dual Channel Permissions +------------------------ +You may also access a user's permissions in a channel with the DualChannelPermissions class. +Unlike normal ChannelPermissions, DualChannelPermissions hold three values: -To set channel permissions, create a new ``ChannelPermissionOverrides``, and specify the flags/values that you want to override. +If a user has a permission, the value is true. If a user is denied a permission, it will be false. If the permission is not set, the value will return null. -Then, update the user, by doing ``Channel.AddPermissionsRule(_user, _overwrites);`` +Setting Channel Permissions +--------------------------- -Roles ------ +To set channel permissions, you may use either two ChannelPermissions, or one DualChannelPermissions. -Accessing/modifying permissions for roles is done the same way as user permissions, just using the overload for a Role. See above sections. +In the case of using two Channel Permissions, you must create one list of allowed permissions, and one list of denied permissions. +Otherwise, you can use a single DualChannelPermissions. Server Permissions ------------------ -Server Permissions can be viewed with ``User.ServerPermissions``, but **at the time of this writing** cannot be set. +Server Permissions can be accessed by ``Server.GetPermissions(User)``, and updated with ``Server.UpdatePermissions(User, ServerPermissions)`` A user's server permissions also contain the default values for it's channel permissions, so the channel permissions listed above are also valid flags for Server Permissions. There are also a few extra Server Permissions: @@ -71,7 +61,11 @@ KickMembers Server Kick users from the server. They can still rejoi ManageRoles Server Manage roles on the server, and their permissions. ManageChannels Server Manage channels that exist on the server (add, remove them) ManageServer Server Manage the server settings. -======================= ======= ============== + +Roles +----- + +Managing permissions for roles is much easier than for users in channels. For roles, just access the flag under `Role.Permissions`. Example ------- diff --git a/docs/features/server-management.rst b/docs/features/server-management.rst index 765fd4e0f..d555875a8 100644 --- a/docs/features/server-management.rst +++ b/docs/features/server-management.rst @@ -10,7 +10,7 @@ You can create Channels, Invites, and Roles on a server using the CreateChannel, You may also edit a server's name, icon, and region. -.. code-block:: csharp6 +.. code-block:: c# // Create a Channel and retrieve the Channel object var _channel = await _server.CreateChannel("announcements", ChannelType.Text); diff --git a/docs/features/user-management.rst b/docs/features/user-management.rst index cf3305312..972b3ab4b 100644 --- a/docs/features/user-management.rst +++ b/docs/features/user-management.rst @@ -6,7 +6,7 @@ Banning To ban a user, invoke the Ban function on a Server object. -.. code-block:: csharp6 +.. code-block:: c# _server.Ban(_user, 30); @@ -17,6 +17,6 @@ Kicking To kick a user, invoke the Kick function on the User. -.. code-block:: csharp6 +.. code-block:: c# _user.Kick(); diff --git a/docs/features/voice.rst b/docs/features/voice.rst index a4dddeff5..fc6867b58 100644 --- a/docs/features/voice.rst +++ b/docs/features/voice.rst @@ -1,180 +1,13 @@ -Voice -===== +|stub| Voice +================= -Installation ------------- - -Before setting up the AudioService, you must first install the package `from NuGet`_ or `GitHub`_. - -Add the package to your solution, and then import the namespace ``Discord.Audio``. - -.. _from NuGet: https://www.nuget.org/packages/Discord.Net.Audio/0.9.0-rc3 -.. _GitHub: https://github.com/RogueException/Discord.Net/tree/master/src/Discord.Net.Audio - -Setup ------ - -To use audio, you must install the AudioService to your DiscordClient. - -.. code-block:: csharp6 - - var _client = new DiscordClient(); - - _client.UsingAudio(x => // Opens an AudioConfigBuilder so we can configure our AudioService - { - x.Mode = AudioMode.Outgoing; // Tells the AudioService that we will only be sending audio - }); - -Joining a Channel ------------------ - -Joining Voice Channels is pretty straight-forward, and is required to send Audio. This will also allow us to get an IAudioClient, which we will later use to send Audio. - -.. code-block:: csharp6 - - var voiceChannel = _client.FindServers("Music Bot Server").FirstOrDefault().VoiceChannels.FirstOrDefault(); // Finds the first VoiceChannel on the server 'Music Bot Server' - - var _vClient = await _client.GetService() // We use GetService to find the AudioService that we installed earlier. In previous versions, this was equivelent to _client.Audio() - .Join(VoiceChannel); // Join the Voice Channel, and return the IAudioClient. - -The client will sustain a connection to this channel until it is kicked, disconnected from Discord, or told to Disconnect. - -The IAudioClient ----------------- - -The IAudioClient is used to connect/disconnect to/from a Voice Channel, and to send audio to that Voice Channel. - -.. function:: IAudioClient.Disconnect(); - - Disconnects the IAudioClient from the Voice Server. - - -.. function:: IAudioClient.Join(Channel); - - Moves the IAudioClient to another channel on the Voice Server, or starts a connection if one has already been terminated. - -.. note:: - - Because versions previous to 0.9 do not discretely differentiate between Text and Voice Channels, you may want to ensure that users cannot request the audio client to join a text channel, as this will throw an exception, leading to potentially unexpected behavior - -.. function:: IAudioClient.Wait(); - - Blocks the current thread until the sending audio buffer has cleared out. - -.. function:: IAudioClient.Clear(); - - Clears the sending audio buffer. - -.. function:: IAudioClient.Send(byte[] data, int offset, int count); - - Adds a stream of data to the Audio Client's internal buffer, to be sent to Discord. Follows the standard c# Stream.Send() format. +|stub-desc| Broadcasting ------------ -There are multiple approaches to broadcasting audio. Discord.Net will convert your audio packets into Opus format, so the only work you need to do is converting your audio into a format that Discord will accept. The format Discord takes is 16-bit 48000Hz PCM. - -Broadcasting with NAudio ------------------------- - -`NAudio`_ is one of the easiest approaches to sending audio, although it is not multi-platform compatible. The following example will show you how to read an mp3 file, and send it to Discord. -You can `download NAudio from NuGet`_. - -.. code-block:: csharp6 - - using NAudio; - using NAudio.Wave; - using NAudio.CoreAudioApi; - - public void SendAudio(string filePath) - { - var channelCount = _client.GetService().Config.Channels; // Get the number of AudioChannels our AudioService has been configured to use. - var OutFormat = new WaveFormat(48000, 16, channelCount); // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. - using (var MP3Reader = new Mp3FileReader(filePath)) // Create a new Disposable MP3FileReader, to read audio from the filePath parameter - using (var resampler = new MediaFoundationResampler(MP3Reader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format - { - resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality - int blockSize = outFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer - byte[] buffer = new byte[blockSize]; - int byteCount; - - while((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present - { - if (byteCount < blockSize) - { - // Incomplete Frame - for (int i = byteCount; i < blockSize; i++) - buffer[i] = 0; - } - _vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord - } - } - - } - -.. _NAudio: https://naudio.codeplex.com/ -.. _download NAudio from NuGet: https://www.nuget.org/packages/NAudio/ - -Broadcasting with FFmpeg ------------------------- - -`FFmpeg`_ allows for a more advanced approach to sending audio, although it is multiplatform safe. The following example will show you how to stream a file to Discord. - -.. code-block:: csharp6 - - public void SendAudio(string pathOrUrl) - { - var process = Process.Start(new ProcessStartInfo { // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process - FileName = "ffmpeg", - Arguments = $"-i {pathOrUrl}" + // Here we provide a list of arguments to feed into FFmpeg. -i means the location of the file/URL it will read from - "-f s16le -ar 48000 -ac 2 pipe:1", // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout. - UseShellExecute = false, - RedirectStandardOutput = true // Capture the stdout of the process - }); - Thread.Sleep(2000); // Sleep for a few seconds to FFmpeg can prebuffer. - - int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono - byte[] buffer = new byte[blockSize]; - int byteCount; - - while (true) // Loop forever, so data will always be read - { - byteCount = process.StandardOutput.BaseStream // Access the underlying MemoryStream from the stdout of FFmpeg - .Read(buffer, 0, blockSize); // Read stdout into the buffer - - if (byteCount == 0) // FFmpeg did not output anything - break; // Break out of the while(true) loop, since there was nothing to read. - - _vClient.Send(buffer, 0, byteCount); // Send our data to Discord - } - _vClient.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now. - } - -.. _FFmpeg: https://ffmpeg.org/ - -.. note:: - - The code-block above assumes that your client is configured to stream 2-channel audio. It also may prematurely end a song. FFmpeg can — especially when streaming from a URL — stop to buffer data from a source, and cause your output stream to read empty data. Because the snippet above does not safely track for failed attempts, or buffers, an empty buffer will cause playback to stop. This is also not 'memory-friendly'. - Multi-Server Broadcasting ------------------------- -.. warning:: Multi-Server broadcasting is not supported by Discord, will cause performance issues for you, and is not encouraged. Proceed with caution. - -To prepare for Multi-Server Broadcasting, you must first enable it in your config. - -.. code-block::csharp6 - - _client.UsingAudio(x => - { - x.Mode = AudioMode.Outgoing; - x.EnableMultiserver = true; // Enable Multiserver - }); - -From here on, it is as easy as creating an IAudioClient for each server you want to join. See the sections on broadcasting to proceed. - - Receiving ---------- - -**Receiving is not implemented in the latest version of Discord.Net** \ No newline at end of file +--------- \ No newline at end of file diff --git a/docs/getting_started.rst b/docs/getting_started.rst index f86b36231..f9dfd857d 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -22,12 +22,12 @@ You can get Discord.Net from NuGet: If you have trouble installing from NuGet, try installing dependencies manually. -You can also pull the latest source from `GitHub`_ +You can also pull the latest source from `GitHub`_ .. _Discord.Net: https://www.nuget.org/packages/Discord.Net .. _Discord.Net.Commands: https://www.nuget.org/packages/Discord.Net.Commands .. _Discord.Net.Modules: https://www.nuget.org/packages/Discord.Net.Modules -.. _Discord.Net.Audio: https://www.nuget.org/packages/Discord.Net.Audio +.. _Discord.Net.Modules: https://www.nuget.org/packages/Discord.Net.Audio .. _GitHub: https://github.com/RogueException/Discord.Net/ Async @@ -42,7 +42,7 @@ For more information, go to `MSDN's Await-Async section`_. Example ------- - + .. literalinclude:: samples/getting_started.cs :language: csharp6 :tab-width: 2 diff --git a/docs/global.txt b/docs/global.txt index 25b33510e..e5b572c93 100644 --- a/docs/global.txt +++ b/docs/global.txt @@ -1,4 +1,2 @@ .. |stub| unicode:: U+1F527 -.. |stub-desc| replace:: This page is a placeholder and has not been written yet. It should be coming soon! -.. |outdated| replace:: **This page is currently out-of-date. The information below may be inaccurate.** -.. |incomplete| replace:: **This page is incomplete. While the information below is accurate, it should be noted that it is not thorough.** \ No newline at end of file +.. |stub-desc| replace:: This page is a placeholder and has not been written yet. It should be coming soon! \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index bf5676406..d2ff662af 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,13 +9,13 @@ Feel free to join us in the `Discord API chat`_. .. _Discord chat service: https://discordapp.com .. _Discord API chat: https://discord.gg/0SBTUU1wZTVjAMPx -.. warning:: +.. warn:: - This is a beta! +This is a beta! - This library has been built thanks to a community effort reverse engineering the Discord client. - As the API is still unofficial, it may change at any time without notice, breaking this library as well. - Discord.Net itself is still in development (and is currently undergoing a rewrite) and you may encounter breaking changes throughout development until the official Discord API is released. +This library has been built thanks to a community effort reverse engineering the Discord client. +As the API is still unofficial, it may change at any time without notice, breaking this library as well. +Discord.Net itself is still in development (and is currently undergoing a rewrite) and you may encounter breaking changes throughout development until the official Discord API is released. It is highly recommended that you always use the latest version and please report any bugs you find to our `Discord chat`_. @@ -23,8 +23,6 @@ It is highly recommended that you always use the latest version and please repor This Documentation is **currently undergoing a rewrite**. Some pages (marked with a wrench) are not updated, or are not completed yet. -**The documentation is currently being written to reflect ``0.9-rc4``, which can be accessed via the latest git-master.** - .. toctree:: :caption: Documentation :maxdepth: 2 diff --git a/docs/samples/events.cs b/docs/samples/events.cs index 8a53c0bbc..7f68bf6cb 100644 --- a/docs/samples/events.cs +++ b/docs/samples/events.cs @@ -1,20 +1,20 @@ class Program { - private static DiscordClient _client; + private static DiscordBotClient _client; static void Main(string[] args) { - _client = new DiscordClient(); + var client = new DiscordClient(); // Handle Events using Lambdas - _client.MessageReceived += (s, e) => + client.MessageCreated += (s, e) => { if (!e.Message.IsAuthor) - await e.Channel.SendMessage("foo"); + await client.SendMessage(e.Message.ChannelId, "foo"); } // Handle Events using Event Handlers EventHandler handler = new EventHandler(HandleMessageCreated); - client.MessageReceived += handler; + client.MessageCreated += handler; } @@ -22,6 +22,6 @@ class Program static void HandleMessageCreated(object sender, EventArgs e) { if (!e.Message.IsAuthor) - await e.Channel.SendMessage("bar"); + await client.SendMessage(e.Message.ChannelId, "foo"); } -} +} \ No newline at end of file diff --git a/docs/samples/getting_started.cs b/docs/samples/getting_started.cs index d471fbc65..55f7923a4 100644 --- a/docs/samples/getting_started.cs +++ b/docs/samples/getting_started.cs @@ -2,13 +2,10 @@ class Program { static void Main(string[] args) { - var client = new DiscordClient(x => - { - LogLevel = LogSeverity.Info - }); + var client = new DiscordClient(); //Display all log messages in the console - client.Log.Message += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source}: {e.Message}"); + client.LogMessage += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source}: {e.Message}"); //Echo back any message received, provided it didn't come from the bot itself client.MessageReceived += async (s, e) => @@ -25,7 +22,7 @@ class Program //If we are not a member of any server, use our invite code (made beforehand in the official Discord Client) if (!client.Servers.Any()) - await (client.GetInvite("aaabbbcccdddeee")).Accept(); + await client.AcceptInvite(client.GetInvite("aaabbbcccdddeee")); }); } } diff --git a/docs/samples/logging.cs b/docs/samples/logging.cs index 4fd3e4959..c68b8aded 100644 --- a/docs/samples/logging.cs +++ b/docs/samples/logging.cs @@ -1,5 +1,6 @@ class Program { + private static DiscordBotClient _client; static void Main(string[] args) { var client = new DiscordClient(x => @@ -7,13 +8,13 @@ class Program LogLevel = LogSeverity.Info }); - client.Log.Message += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source}: {e.Message}"); + _client.Log.Message += (s, e) => Console.WriteLine($"[{e.Severity}] {e.Source}: {e.Message}"); client.ExecuteAndWait(async () => { await client.Connect("discordtest@email.com", "Password123"); if (!client.Servers.Any()) - await (client.GetInvite("aaabbbcccdddeee")).Accept(); + await client.AcceptInvite("aaabbbcccdddeee"); }); } } diff --git a/docs/samples/permissions.cs b/docs/samples/permissions.cs index 65681d0f9..419026714 100644 --- a/docs/samples/permissions.cs +++ b/docs/samples/permissions.cs @@ -1,8 +1,14 @@ - // Find a User's Channel Permissions -var UserPerms = _channel.GetPermissionsRule(_user); +var userChannelPermissions = user.GetPermissions(channel); + +// Find a User's Server Permissions +var userServerPermissions = user.ServerPermissions(); +var userServerPermissions = server.GetPermissions(user); -// Set a User's Channel Permissions +// Set a User's Channel Permissions (using DualChannelPermissions) -var NewOverwrites = new ChannelPermissionOverrides(sendMessages: PermValue.Deny); -await channel.AddPermissionsRule(_user, NewOverwrites); +var userPerms = user.GetPermissions(channel); +userPerms.ReadMessageHistory = false; +userPerms.AttachFiles = null; +channel.AddPermissionsRule(user, userPerms); +} diff --git a/global.json b/global.json index 4357be0d5..7f3ac9f7e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { - "projects": [ "src" ], - "sdk": { - "version": "1.0.0-rc1-update1" - } + "projects": [ "src" ], + "sdk": { + "version": "1.0.0-rc2-20221" + } } \ No newline at end of file diff --git a/ref/Discord.Net.xproj b/ref/Discord.Net.xproj deleted file mode 100644 index d3559797d..000000000 --- a/ref/Discord.Net.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 5b2afee6-fff6-4ba2-be12-61b283b72ac0 - Discord - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - True - - - \ No newline at end of file diff --git a/ref/DiscordClient.cs b/ref/DiscordClient.cs deleted file mode 100644 index aa777e04f..000000000 --- a/ref/DiscordClient.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord -{ - /// Provides a connection to the DiscordApp service. - public class DiscordClient : IDisposable - { - public event EventHandler Log = delegate { }; - - public event EventHandler LoggedIn = delegate { }; - public event EventHandler LoggedOut = delegate { }; - public event EventHandler Connected = delegate { }; - public event EventHandler Disconnected = delegate { }; - public event EventHandler VoiceConnected = delegate { }; - public event EventHandler VoiceDisconnected = delegate { }; - - public event EventHandler ChannelCreated = delegate { }; - public event EventHandler ChannelUpdated = delegate { }; - public event EventHandler ChannelDestroyed = delegate { }; - public event EventHandler MessageAcknowledged = delegate { }; - public event EventHandler MessageDeleted = delegate { }; - public event EventHandler MessageReceived = delegate { }; - public event EventHandler MessageSent = delegate { }; - public event EventHandler MessageUpdated = delegate { }; - public event EventHandler ProfileUpdated = delegate { }; - public event EventHandler RoleCreated = delegate { }; - public event EventHandler RoleUpdated = delegate { }; - public event EventHandler RoleDeleted = delegate { }; - public event EventHandler JoinedServer = delegate { }; - public event EventHandler LeftServer = delegate { }; - public event EventHandler ServerAvailable = delegate { }; - public event EventHandler ServerUpdated = delegate { }; - public event EventHandler ServerUnavailable = delegate { }; - public event EventHandler UserBanned = delegate { }; - public event EventHandler UserIsTyping = delegate { }; - public event EventHandler UserJoined = delegate { }; - public event EventHandler UserLeft = delegate { }; - public event EventHandler UserUpdated = delegate { }; - public event EventHandler UserUnbanned = delegate { }; - - public MessageQueue MessageQueue { get; } - public IRestClient RestClient { get; } - public GatewaySocket GatewaySocket { get; } - public Profile CurrentUser { get; } - - public DiscordClient() { } - public DiscordClient(DiscordConfig config) { } - - public Task Login(string token) => null; - public Task Logout() => null; - - public Task Connect() => null; - public Task Connect(int connectionId, int totalConnections) => null; - public Task Disconnect() => null; - - public Task> GetPrivateChannels() => null; - public Task GetPrivateChannel(ulong userId) => null; - public Task GetInvite(string inviteIdOrXkcd) => null; - public Task> GetRegions() => null; - public Task GetRegion(string id) => null; - public Task> GetServers() => null; - public Task GetServer(ulong id) => null; - - public Task CreatePrivateChannel(ulong userId) => null; - public Task CreateServer(string name, Region region, ImageType iconType = ImageType.None, Stream icon = null) => null; - - public void Dispose() { } - } -} \ No newline at end of file diff --git a/ref/DiscordConfig.cs b/ref/DiscordConfig.cs deleted file mode 100644 index e6b1a5568..000000000 --- a/ref/DiscordConfig.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using System.Reflection; - -namespace Discord -{ - public class DiscordConfig - { - public const int MaxMessageSize = 2000; - public const int MaxMessagesPerBatch = 100; - - public const string LibName = "Discord.Net"; - public static string LibVersion => typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; - public const string LibUrl = "https://github.com/RogueException/Discord.Net"; - - public const string ClientAPIUrl = "https://discordapp.com/api/"; - public const string CDNUrl = "https://cdn.discordapp.com/"; - public const string InviteUrl = "https://discord.gg/"; - - /// Gets or sets name of your application, used in the user agent. - public string AppName { get; set; } = null; - /// Gets or sets url to your application, used in the user agent. - public string AppUrl { get; set; } = null; - /// Gets or sets the version of your application, used in the user agent. - public string AppVersion { get; set; } = null; - - /// Gets or sets the minimum log level severity that will be sent to the LogMessage event. - public LogSeverity LogLevel { get; set; } = LogSeverity.Info; - - /// Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize. - public int ConnectionTimeout { get; set; } = 30000; - /// Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. - public int ReconnectDelay { get; set; } = 1000; - /// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. - public int FailedReconnectDelay { get; set; } = 15000; - - //Performance - - /// Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. - public int MessageCacheSize { get; set; } = 100; - /// - /// Gets or sets whether the permissions cache should be used. - /// This makes operations such as User.GetPermissions(Channel), User.ServerPermissions, Channel.GetUser, and Channel.Members much faster while increasing memory usage. - /// - public bool UsePermissionsCache { get; set; } = true; - /// Gets or sets whether the a copy of a model is generated on an update event to allow you to check which properties changed. - public bool EnablePreUpdateEvents { get; set; } = true; - /// - /// Gets or sets the max number of users a server may have for offline users to be included in the READY packet. Max is 250. - /// Decreasing this may reduce CPU usage while increasing login time and network usage. - /// - public int LargeThreshold { get; set; } = 250; - - //Engines - - /// Gets or sets the REST engine to use.. Defaults to DefaultRestClientProvider, which uses .Net's HttpClient class. - public IRestClientProvider RestClientProvider { get; set; } = null; - /// - /// Gets or sets the WebSocket engine to use. Defaults to DefaultWebSocketProvider, which uses .Net's WebSocketClient class. - /// WebSockets are only used if DiscordClient.Connect() is called. - /// - public IWebSocketProvider WebSocketProvider { get; set; } = null; - } -} - diff --git a/ref/Entities/Channels/IPublicChannel.cs b/ref/Entities/Channels/IPublicChannel.cs deleted file mode 100644 index bd005a288..000000000 --- a/ref/Entities/Channels/IPublicChannel.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public interface IPublicChannel : IChannel - { - /// Gets the server this channel is a member of. - Server Server { get; } - /// Gets a collection of permission overwrites for this channel. - IEnumerable PermissionOverwrites { get; } - /// Gets the position of this public channel relative to others of the same type. - int Position { get; } - - /// Gets a user in this channel with the given id. - new Task GetUser(ulong id); - /// Gets a collection of all users in this channel. - new Task> GetUsers(); - - /// Gets the permission overwrite for a specific user, or null if one does not exist. - OverwritePermissions? GetPermissionOverwrite(ServerUser user); - /// Gets the permission overwrite for a specific role, or null if one does not exist. - OverwritePermissions? GetPermissionOverwrite(Role role); - /// Downloads a collection of all invites to this server. - Task> GetInvites(); - - /// Adds or updates the permission overwrite for the given user. - Task UpdatePermissionOverwrite(ServerUser user, OverwritePermissions permissions); - /// Adds or updates the permission overwrite for the given role. - Task UpdatePermissionOverwrite(Role role, OverwritePermissions permissions); - /// Removes the permission overwrite for the given user, if one exists. - Task RemovePermissionOverwrite(ServerUser user); - /// Removes the permission overwrite for the given role, if one exists. - Task RemovePermissionOverwrite(Role role); - - /// Creates a new invite to this channel. - /// Time (in seconds) until the invite expires. Set to null to never expire. - /// The max amount of times this invite may be used. Set to null to have unlimited uses. - /// If true, a user accepting this invite will be kicked from the server after closing their client. - /// If true, creates a human-readable link. Not supported if maxAge is set to null. - Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false); - } -} diff --git a/ref/Entities/Channels/PrivateChannel.cs b/ref/Entities/Channels/PrivateChannel.cs deleted file mode 100644 index ee72c0828..000000000 --- a/ref/Entities/Channels/PrivateChannel.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Discord -{ - public class PrivateChannel : ITextChannel, IChannel - { - /// - public DiscordClient Discord { get; } - /// - public EntityState State { get; } - /// - public ulong Id { get; } - /// - public PrivateUser Recipient { get; } - /// - public PrivateUser CurrentUser { get; } - - /// - ChannelType IChannel.Type => ChannelType.Private | ChannelType.Text; - /// - public string Name { get; } - - /// - public Task GetUser(ulong id) => null; - /// - Task IChannel.GetUser(ulong id) => null; - /// - public Task> GetUsers() => null; - /// - Task> IChannel.GetUsers() => null; - /// - public Task GetMessage(ulong id) => null; - /// - public Task> GetMessages(int limit = 100) => null; - /// - public Task> GetMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) => null; - - /// - public Task SendMessage(string text, bool isTTS = false) => null; - /// - public Task SendFile(string filePath, string text = null, bool isTTS = false) => null; - /// - public Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) => null; - - /// - public Task SendIsTyping() => null; - - /// - public Task Update() => null; - /// - public Task Delete() => null; - } -} diff --git a/ref/Entities/Channels/TextChannel.cs b/ref/Entities/Channels/TextChannel.cs deleted file mode 100644 index 0b1b81c77..000000000 --- a/ref/Entities/Channels/TextChannel.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Discord -{ - public class TextChannel : ITextChannel, IMentionable, IModifiable - { - public sealed class Properties - { - public string Name { get; } - public string Topic { get; } - public int Position { get; } - } - - /// - public EntityState State { get; } - /// - public ulong Id { get; } - /// - public Server Server { get; } - - /// - public DiscordClient Discord { get; } - /// - public ChannelType Type => ChannelType.Public | ChannelType.Text; - - /// - public string Name { get; } - /// - public string Topic { get; } - /// - public int Position { get; } - - /// - public string Mention { get; } - /// - public IEnumerable PermissionOverwrites { get; } - - /// - public OverwritePermissions? GetPermissionOverwrite(ServerUser user) => null; - /// - public OverwritePermissions? GetPermissionOverwrite(Role role) => null; - /// - public Task GetUser(ulong id) => null; - /// - Task IChannel.GetUser(ulong id) => null; - /// - public Task> GetUsers() => null; - /// - Task> IChannel.GetUsers() => null; - /// - public Task GetMessage(ulong id) => null; - /// - public Task> GetMessages(int limit = 100) => null; - /// - public Task> GetMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) => null; - /// - public Task> GetInvites() => null; - - /// - public Task UpdatePermissionOverwrite(ServerUser user, OverwritePermissions permissions) => null; - /// - public Task UpdatePermissionOverwrite(Role role, OverwritePermissions permissions) => null; - /// - public Task RemovePermissionOverwrite(ServerUser user) => null; - /// - public Task RemovePermissionOverwrite(Role role) => null; - - /// - public Task SendMessage(string text, bool isTTS = false) => null; - /// - public Task SendFile(string filePath, string text = null, bool isTTS = false) => null; - /// - public Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) => null; - - /// - public Task SendIsTyping() => null; - - /// - public Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) => null; - - /// - public Task Update() => null; - /// - public Task Modify(Action func) => null; - /// - public Task Delete() => null; - } -} diff --git a/ref/Entities/Channels/VoiceChannel.cs b/ref/Entities/Channels/VoiceChannel.cs deleted file mode 100644 index 6552fadd7..000000000 --- a/ref/Entities/Channels/VoiceChannel.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public class VoiceChannel : IPublicChannel, IModifiable - { - public sealed class Properties - { - public string Name { get; } - public int Bitrate { get; set; } - public int Position { get; } - } - - /// - public ulong Id { get; } - /// - public EntityState State { get; } - /// - public Server Server { get; } - - /// - public DiscordClient Discord { get; } - /// - ChannelType IChannel.Type => ChannelType.Public | ChannelType.Voice; - - /// - public string Name { get; } - /// - public int Position { get; } - /// - public int Bitrate { get; } - - /// - public string Mention { get; } - /// - public IEnumerable PermissionOverwrites { get; } - - /// - public OverwritePermissions? GetPermissionOverwrite(ServerUser user) => null; - /// - public OverwritePermissions? GetPermissionOverwrite(Role role) => null; - /// - public Task GetUser(ulong id) => null; - /// - Task IChannel.GetUser(ulong id) => null; - /// - public Task> GetUsers() => null; - /// - Task> IChannel.GetUsers() => null; - /// - public Task> GetInvites() => null; - - /// - public Task UpdatePermissionOverwrite(ServerUser user, OverwritePermissions permissions) => null; - /// - public Task UpdatePermissionOverwrite(Role role, OverwritePermissions permissions) => null; - /// - public Task RemovePermissionOverwrite(ServerUser user) => null; - /// - public Task RemovePermissionOverwrite(Role role) => null; - - /// - public Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) => null; - - /// - public Task Update() => null; - /// - public Task Modify(Action func) => null; - /// - public Task Delete() => null; - } -} diff --git a/ref/Entities/Color.cs b/ref/Entities/Color.cs deleted file mode 100644 index b3c78debf..000000000 --- a/ref/Entities/Color.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Discord -{ - public class Color - { - public static readonly Color Default = new Color(0); - - public uint RawValue { get; } - - public Color(uint rawValue) { } - public Color(byte r, byte g, byte b) { } - public Color(float r, float g, float b) { } - - public byte R { get; } - public byte G { get; } - public byte B { get; } - } -} diff --git a/ref/Entities/IModifiable.cs b/ref/Entities/IModifiable.cs deleted file mode 100644 index f264c96f2..000000000 --- a/ref/Entities/IModifiable.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord -{ - public interface IModifiable - { - /// Modifies one or more of the properties of this object. - Task Modify(Action func); - } -} diff --git a/ref/Entities/Invite/BasicInvite.cs b/ref/Entities/Invite/BasicInvite.cs deleted file mode 100644 index 37cd1704d..000000000 --- a/ref/Entities/Invite/BasicInvite.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - public class BasicInvite : IEntity - { - public class TargetInfo - { - public ulong Id { get; } - public string Name { get; } - } - public class InviterInfo - { - public ulong Id { get; } - public string Name { get; } - public ushort Discriminator { get; } - public string AvatarId { get; } - public string AvatarUrl { get; } - } - - string IEntity.Id => Code; - public DiscordClient Discord { get; } - public EntityState State { get; } - - public string Code { get; } - public string XkcdCode { get; } - - public TargetInfo Server { get; } - public TargetInfo Channel { get; } - - public string Url { get; } - - public Task Accept() => null; - - public virtual Task Update() => null; - } -} diff --git a/ref/Entities/Invite/Invite.cs b/ref/Entities/Invite/Invite.cs deleted file mode 100644 index 11fead2af..000000000 --- a/ref/Entities/Invite/Invite.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord -{ - public class Invite : BasicInvite - { - public int? MaxAge { get; } - public int Uses { get; } - public int? MaxUses { get; } - public bool IsRevoked { get; } - public bool IsTemporary { get; } - public DateTime CreatedAt { get; } - - public override Task Update() => null; - public Task Delete() => null; - } -} diff --git a/ref/Entities/Message.cs b/ref/Entities/Message.cs deleted file mode 100644 index 78c4e41bd..000000000 --- a/ref/Entities/Message.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public class Message : IEntity - { - public class Attachment : File - { - public string Id { get; } - public int Size { get; } - public string Filename { get; } - } - - public class Embed - { - public string Url { get; } - public string Type { get; } - public string Title { get; } - public string Description { get; } - public EmbedLink Author { get; } - public EmbedLink Provider { get; } - public File Thumbnail { get; } - public File Video { get; } - } - - public class EmbedLink - { - public string Url { get; } - public string Name { get; } - } - - public class File - { - public string Url { get; } - public string ProxyUrl { get; } - public int? Width { get; } - public int? Height { get; } - } - - public ulong Id { get; } - public DiscordClient Discord { get; } - public EntityState State { get; } - - public ITextChannel Channel { get; } - public IUser User { get; } - public bool IsTTS { get; } - public string RawText { get; } - public string Text { get; } - public DateTime Timestamp { get; } - public DateTime? EditedTimestamp { get; } - public Attachment[] Attachments { get; } - public Embed[] Embeds { get; } - - public IReadOnlyList MentionedUsers { get; } - public IReadOnlyList MentionedChannels { get; } - public IReadOnlyList MentionedRoles { get; } - - public Server Server => null; - public bool IsAuthor => false; - - public bool IsMentioningMe(bool includeRoles = false) => false; - - public Task Update() => null; - public Task Delete() => null; - } -} diff --git a/ref/Entities/Permissions/ChannelPermissions.cs b/ref/Entities/Permissions/ChannelPermissions.cs deleted file mode 100644 index d01f0430e..000000000 --- a/ref/Entities/Permissions/ChannelPermissions.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Discord -{ - public struct ChannelPermissions - { - public static ChannelPermissions None { get; } - public static ChannelPermissions TextOnly { get; } - public static ChannelPermissions PrivateOnly { get; } - public static ChannelPermissions VoiceOnly { get; } - public static ChannelPermissions All(ChannelType channelType) => default(ChannelPermissions); - - public uint RawValue { get; } - - public bool CreateInstantInvite { get; } - public bool ManagePermission { get; } - public bool ManageChannel { get; } - - public bool ReadMessages { get; } - public bool SendMessages { get; } - public bool SendTTSMessages { get; } - public bool ManageMessages { get; } - public bool EmbedLinks { get; } - public bool AttachFiles { get; } - public bool ReadMessageHistory { get; } - public bool MentionEveryone { get; } - - public bool Connect { get; } - public bool Speak { get; } - public bool MuteMembers { get; } - public bool DeafenMembers { get; } - public bool MoveMembers { get; } - public bool UseVoiceActivation { get; } - - public ChannelPermissions(bool? createInstantInvite = null, bool? managePermissions = null, - bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, - bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, - bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - : this() - { - } - public ChannelPermissions(uint rawValue) - : this() - { - } - - public ChannelPermissions Modify(bool? createInstantInvite = null, bool? managePermissions = null, - bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, - bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, - bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - => default(ChannelPermissions); - } -} diff --git a/ref/Entities/Permissions/OverwritePermissions.cs b/ref/Entities/Permissions/OverwritePermissions.cs deleted file mode 100644 index 1cda173ec..000000000 --- a/ref/Entities/Permissions/OverwritePermissions.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Discord -{ - public struct OverwritePermissions - { - public static OverwritePermissions InheritAll { get; } - - public uint AllowValue { get; } - public uint DenyValue { get; } - - public PermValue CreateInstantInvite { get; } - public PermValue ManagePermissions { get; } - public PermValue ManageChannel { get; } - public PermValue ReadMessages { get; } - public PermValue SendMessages { get; } - public PermValue SendTTSMessages { get; } - public PermValue ManageMessages { get; } - public PermValue EmbedLinks { get; } - public PermValue AttachFiles { get; } - public PermValue ReadMessageHistory { get; } - public PermValue MentionEveryone { get; } - - public PermValue Connect { get; } - public PermValue Speak { get; } - public PermValue MuteMembers { get; } - public PermValue DeafenMembers { get; } - public PermValue MoveMembers { get; } - public PermValue UseVoiceActivation { get; } - - public OverwritePermissions(PermValue? createInstantInvite = null, PermValue? managePermissions = null, - PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, - PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, - PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, - PermValue? moveMembers = null, PermValue? useVoiceActivation = null) - : this() - { - } - - public OverwritePermissions(uint allow = 0, uint deny = 0) - : this() - { - } - - public OverwritePermissions Modify(PermValue? createInstantInvite = null, PermValue? managePermissions = null, - PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, - PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, - PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, - PermValue? moveMembers = null, PermValue? useVoiceActivation = null) - => default(OverwritePermissions); - } -} diff --git a/ref/Entities/Permissions/PermissionOverwriteEntry.cs b/ref/Entities/Permissions/PermissionOverwriteEntry.cs deleted file mode 100644 index bbc11fba8..000000000 --- a/ref/Entities/Permissions/PermissionOverwriteEntry.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public struct PermissionOverwriteEntry - { - public PermissionTarget TargetType { get; } - public ulong TargetId { get; } - public OverwritePermissions Permissions { get; } - } -} diff --git a/ref/Entities/Permissions/ServerPermissions.cs b/ref/Entities/Permissions/ServerPermissions.cs deleted file mode 100644 index fe85c07dd..000000000 --- a/ref/Entities/Permissions/ServerPermissions.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Discord -{ - public struct ServerPermissions - { - public static ServerPermissions None { get; } - public static ServerPermissions All { get; } - - public uint RawValue { get; } - - public bool CreateInstantInvite { get; } - public bool BanMembers { get; } - public bool KickMembers { get; } - public bool ManageRoles { get; } - public bool ManageChannels { get; } - public bool ManageServer { get; } - - public bool ReadMessages { get; } - public bool SendMessages { get; } - public bool SendTTSMessages { get; } - public bool ManageMessages { get; } - public bool EmbedLinks { get; } - public bool AttachFiles { get; } - public bool ReadMessageHistory { get; } - public bool MentionEveryone { get; } - - public bool Connect { get; } - public bool Speak { get; } - public bool MuteMembers { get; } - public bool DeafenMembers { get; } - public bool MoveMembers { get; } - public bool UseVoiceActivation { get; } - - public ServerPermissions(bool? createInstantInvite = null, bool? manageRoles = null, - bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageServer = null, - bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, - bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, - bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - : this() - { - } - public ServerPermissions(uint rawValue) - : this() - { - } - - public ServerPermissions Modify(bool? createInstantInvite = null, bool? manageRoles = null, - bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageServer = null, - bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, - bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, - bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - => default(ServerPermissions); - } -} diff --git a/ref/Entities/Profile.cs b/ref/Entities/Profile.cs deleted file mode 100644 index aa61e51b2..000000000 --- a/ref/Entities/Profile.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - public class Profile : IEntity - { - public ulong Id { get; } - public DiscordClient Discord { get; } - public EntityState State { get; } - - public string AvatarId { get; } - public string AvatarUrl { get; } - public ushort Discriminator { get; } - public string CurrentGame { get; } - public UserStatus Status { get; } - public string Mention { get; } - public string Email { get; } - public bool? IsVerified { get; } - - public string Name { get; set; } - - public Task Update() => null; - public Task Delete() => null; - } -} diff --git a/ref/Entities/Region.cs b/ref/Entities/Region.cs deleted file mode 100644 index fbb801eaa..000000000 --- a/ref/Entities/Region.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Discord -{ - public class Region - { - public string Id { get; } - public string Name { get; } - public string Hostname { get; } - public int Port { get; } - public bool Vip { get; } - } -} diff --git a/ref/Entities/Role.cs b/ref/Entities/Role.cs deleted file mode 100644 index f5155db2e..000000000 --- a/ref/Entities/Role.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public class Role : IEntity, IMentionable - { - public ulong Id { get; } - public DiscordClient Discord { get; } - public EntityState State { get; } - - public Server Server { get; } - - public string Name { get; } - public bool IsHoisted { get; } - public int Position { get; } - public bool IsManaged { get; } - public ServerPermissions Permissions { get; } - public Color Color { get; } - - public bool IsEveryone { get; } - public IEnumerable Members { get; } - - public string Mention { get; } - - public Task Update() => null; - public Task Delete() => null; - } -} diff --git a/ref/Entities/Server.cs b/ref/Entities/Server.cs deleted file mode 100644 index a9078cb4b..000000000 --- a/ref/Entities/Server.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public class Server : IEntity - { - public class Emoji - { - public string Id { get; } - public string Name { get; } - public bool IsManaged { get; } - public bool RequireColons { get; } - public IEnumerable Roles { get; } - } - - public ulong Id { get; } - public DiscordClient Discord { get; } - public EntityState State { get; } - - public ServerUser CurrentUser { get; } - public string IconId { get; } - public string SplashId { get; } - public string IconUrl { get; } - public string SplashUrl { get; } - public int ChannelCount { get; } - public int UserCount { get; } - public int RoleCount { get; } - public TextChannel DefaultChannel { get; } - public Role EveryoneRole { get; } - public IEnumerable Features { get; } - public IEnumerable CustomEmojis { get; } - public IEnumerable Channels { get; } - public IEnumerable TextChannels { get; } - public IEnumerable VoiceChannels { get; } - public IEnumerable Users { get; } - public IEnumerable Roles { get; } - - public string Name { get; set; } - public Region Region { get; set; } - public int AFKTimeout { get; set; } - public DateTime JoinedAt { get; set; } - public ServerUser Owner { get; set; } - public VoiceChannel AFKChannel { get; set; } - - public Task GetChannel(ulong id) => null; - public Task GetChannel(string mention) => null; - public Task GetRole(ulong id) => null; - public Task GetUser(ulong id) => null; - public Task GetUser(string name, ushort discriminator) => null; - public Task GetUser(string mention) => null; - public Task> GetBans() => null; - public Task> GetInvites() => null; - - public Task CreateTextChannel(string name) => null; - public Task CreateVoiceChannel(string name) => null; - public Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) => null; - public Task CreateRole(string name, ServerPermissions? permissions = null, Color color = null, bool isHoisted = false) => null; - - public Task PruneUsers(int days = 30, bool simulate = false) => null; - - public Task Update() => null; - public Task Leave() => null; - public Task Delete() => null; - } -} diff --git a/ref/Entities/Users/IUser.cs b/ref/Entities/Users/IUser.cs deleted file mode 100644 index 02dd2d85b..000000000 --- a/ref/Entities/Users/IUser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - public interface IUser : IEntity, IMentionable - { - bool IsPrivate { get; } - - string Name { get; } - ushort Discriminator { get; } - bool IsBot { get; } - string AvatarId { get; } - string AvatarUrl { get; } - string CurrentGame { get; } - UserStatus Status { get; } - - Task GetPrivateChannel(); - } -} diff --git a/ref/Entities/Users/PrivateUser.cs b/ref/Entities/Users/PrivateUser.cs deleted file mode 100644 index a6cc9d6e7..000000000 --- a/ref/Entities/Users/PrivateUser.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - //TODO: Should this be linked directly to the Profile when it represents us, instead of maintaining a cache of values? - public class PrivateUser : IUser - { - /// - public EntityState State { get; internal set; } - /// - public ulong Id { get; } - /// Returns the private channel for this user. - public PrivateChannel Channel { get; } - - /// - bool IUser.IsPrivate => true; - - /// - public string Name { get; } - /// - public ushort Discriminator { get; } - /// - public bool IsBot { get; } - /// - public string AvatarId { get; } - /// - public string CurrentGame { get; } - /// - public UserStatus Status { get; } - - /// - public DiscordClient Discord => Channel.Discord; - /// - public string AvatarUrl { get; } - /// - public string Mention { get; } - - /// - Task IUser.GetPrivateChannel() => Task.FromResult(Channel); - - public Task Update() => null; - } -} diff --git a/ref/Entities/Users/ServerUser.cs b/ref/Entities/Users/ServerUser.cs deleted file mode 100644 index 4ff86f67a..000000000 --- a/ref/Entities/Users/ServerUser.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord -{ - public class ServerUser : IUser - { - /// - public EntityState State { get; } - /// - public ulong Id { get; } - /// Returns the private channel for this user. - public Server Server { get; } - - /// - bool IUser.IsPrivate => false; - - /// - public string Name { get; } - /// - public ushort Discriminator { get; } - /// - public bool IsBot { get; } - /// - public string AvatarId { get; } - /// - public string CurrentGame { get; } - /// - public UserStatus Status { get; } - /// - public DateTime JoinedAt { get; } - /// - public IReadOnlyList Roles { get; } - - /// Returns true if this user has marked themselves as muted. - public bool IsSelfMuted { get; } - /// Returns true if this user has marked themselves as deafened. - public bool IsSelfDeafened { get; } - /// Returns true if the server is blocking audio from this user. - public bool IsServerMuted { get; } - /// Returns true if the server is blocking audio to this user. - public bool IsServerDeafened { get; } - /// Returns true if the server is temporarily blocking audio to/from this user. - public bool IsServerSuppressed { get; } - /// Gets this user's current voice channel. - public VoiceChannel VoiceChannel { get; } - - /// - public DiscordClient Discord { get; } - /// - public string AvatarUrl { get; } - /// - public string Mention { get; } - - public ServerPermissions ServerPermissions { get; } - - public ChannelPermissions GetPermissions(IPublicChannel channel) => default(ChannelPermissions); - /// - public Task GetPrivateChannel() => null; - public Task> GetChannels() => null; - - public bool HasRole(Role role) => false; - - public Task AddRoles(params Role[] roles) => null; - public Task RemoveRoles(params Role[] roles) => null; - - public Task Update() => null; - public Task Kick() => null; - public Task Ban(int pruneDays = 0) => null; - public Task Unban() => null; - } -} \ No newline at end of file diff --git a/ref/Enums/ChannelType.cs b/ref/Enums/ChannelType.cs deleted file mode 100644 index 5ebbf3aa6..000000000 --- a/ref/Enums/ChannelType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Discord -{ - [Flags] - public enum ChannelType : byte - { - Public = 0x01, - Private = 0x02, - Text = 0x10, - Voice = 0x20 - } -} diff --git a/ref/Enums/ConnectionState.cs b/ref/Enums/ConnectionState.cs deleted file mode 100644 index dfd4ac9eb..000000000 --- a/ref/Enums/ConnectionState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Discord -{ - public enum ConnectionState - { - Disconnected, - Connecting, - Connected, - Disconnecting - } -} diff --git a/ref/Enums/EntityState.cs b/ref/Enums/EntityState.cs deleted file mode 100644 index 6ae71e4a3..000000000 --- a/ref/Enums/EntityState.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Discord -{ - public enum EntityState : byte - { - /// Object is not attached to a cache manager nor receiving live updates. - Detached = 0, - /// Object is attached to a cache manager and receiving live updates. - Attached, - /// Object was deleted. - Deleted, - /// Object is currently waiting to be created. - Queued, - /// Object's creation was aborted. - Aborted, - /// Object's creation failed. - Failed - } -} diff --git a/ref/Enums/ImageType.cs b/ref/Enums/ImageType.cs deleted file mode 100644 index 738c67a3d..000000000 --- a/ref/Enums/ImageType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public enum ImageType - { - None, - Jpeg, - Png - } -} diff --git a/ref/Enums/LogSeverity.cs b/ref/Enums/LogSeverity.cs deleted file mode 100644 index 785b0ef46..000000000 --- a/ref/Enums/LogSeverity.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Discord -{ - public enum LogSeverity - { - Critical = 0, - Error = 1, - Warning = 2, - Info = 3, - Verbose = 4, - Debug = 5 - } -} diff --git a/ref/Enums/PermValue.cs b/ref/Enums/PermValue.cs deleted file mode 100644 index fe048b016..000000000 --- a/ref/Enums/PermValue.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public enum PermValue - { - Allow, - Deny, - Inherit - } -} diff --git a/ref/Enums/PermissionTarget.cs b/ref/Enums/PermissionTarget.cs deleted file mode 100644 index 96595fb69..000000000 --- a/ref/Enums/PermissionTarget.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Discord -{ - public enum PermissionTarget - { - Role, - User - } -} diff --git a/ref/Enums/Relative.cs b/ref/Enums/Relative.cs deleted file mode 100644 index aade047d1..000000000 --- a/ref/Enums/Relative.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Discord -{ - public enum Relative - { - Before, - After - } -} diff --git a/ref/Enums/UserStatus.cs b/ref/Enums/UserStatus.cs deleted file mode 100644 index f2fdfda7c..000000000 --- a/ref/Enums/UserStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public enum UserStatus - { - Online, - Idle, - Offline - } -} diff --git a/ref/Events/ChannelEventArgs.cs b/ref/Events/ChannelEventArgs.cs deleted file mode 100644 index 583075e08..000000000 --- a/ref/Events/ChannelEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Discord -{ - public class ChannelEventArgs : EventArgs - { - public IChannel Channel => null; - } -} diff --git a/ref/Events/ChannelUpdatedEventArgs.cs b/ref/Events/ChannelUpdatedEventArgs.cs deleted file mode 100644 index bcd809521..000000000 --- a/ref/Events/ChannelUpdatedEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Discord -{ - public class ChannelUpdatedEventArgs : EventArgs - { - public IChannel Before => null; - public IChannel After => null; - } -} diff --git a/ref/Events/DisconnectedEventArgs.cs b/ref/Events/DisconnectedEventArgs.cs deleted file mode 100644 index 616f3f09d..000000000 --- a/ref/Events/DisconnectedEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Discord -{ - public class DisconnectedEventArgs : EventArgs - { - public bool WasUnexpected => false; - public Exception Exception => null; - } -} diff --git a/ref/Events/LogMessageEventArgs.cs b/ref/Events/LogMessageEventArgs.cs deleted file mode 100644 index 7dec182d1..000000000 --- a/ref/Events/LogMessageEventArgs.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Discord -{ - public class LogMessageEventArgs : EventArgs - { - public LogSeverity Severity => default(LogSeverity); - public string Source => null; - public string Message => null; - public Exception Exception => null; - } -} diff --git a/ref/Events/MessageEventArgs.cs b/ref/Events/MessageEventArgs.cs deleted file mode 100644 index f75c7f1a8..000000000 --- a/ref/Events/MessageEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord -{ - public class MessageEventArgs : EventArgs - { - public Message Message => null; - public IUser User => null; - public ITextChannel Channel => null; - } -} diff --git a/ref/Events/MessageUpdatedEventArgs.cs b/ref/Events/MessageUpdatedEventArgs.cs deleted file mode 100644 index d323bf809..000000000 --- a/ref/Events/MessageUpdatedEventArgs.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Discord -{ - public class MessageUpdatedEventArgs : EventArgs - { - public Message Before => null; - public Message After => null; - public IUser User => null; - public ITextChannel Channel => null; - } -} diff --git a/ref/Events/ProfileUpdatedEventArgs.cs b/ref/Events/ProfileUpdatedEventArgs.cs deleted file mode 100644 index dba55af3b..000000000 --- a/ref/Events/ProfileUpdatedEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Discord -{ - public class ProfileUpdatedEventArgs : EventArgs - { - public Profile Before => null; - public Profile After => null; - } -} diff --git a/ref/Events/RoleEventArgs.cs b/ref/Events/RoleEventArgs.cs deleted file mode 100644 index db1d09cbc..000000000 --- a/ref/Events/RoleEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Discord -{ - public class RoleEventArgs : EventArgs - { - public Role Role => null; - public Server Server => null; - } -} diff --git a/ref/Events/RoleUpdatedEventArgs.cs b/ref/Events/RoleUpdatedEventArgs.cs deleted file mode 100644 index 1fa0f2a81..000000000 --- a/ref/Events/RoleUpdatedEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord -{ - public class RoleUpdatedEventArgs : EventArgs - { - public Role Before => null; - public Role After => null; - public Server Server => null; - } -} diff --git a/ref/Events/ServerEventArgs.cs b/ref/Events/ServerEventArgs.cs deleted file mode 100644 index b06993de9..000000000 --- a/ref/Events/ServerEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Discord -{ - public class ServerEventArgs : EventArgs - { - public Server Server => null; - } -} diff --git a/ref/Events/ServerUpdatedEventArgs.cs b/ref/Events/ServerUpdatedEventArgs.cs deleted file mode 100644 index 1e05f1721..000000000 --- a/ref/Events/ServerUpdatedEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Discord -{ - public class ServerUpdatedEventArgs : EventArgs - { - public Server Before => null; - public Server After => null; - } -} diff --git a/ref/Events/TypingEventArgs.cs b/ref/Events/TypingEventArgs.cs deleted file mode 100644 index f45313687..000000000 --- a/ref/Events/TypingEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public class TypingEventArgs - { - public ITextChannel Channel { get; } - public IUser User { get; } - - public TypingEventArgs(ITextChannel channel, IUser user) - { - Channel = channel; - User = user; - } - } -} diff --git a/ref/Events/UserEventArgs.cs b/ref/Events/UserEventArgs.cs deleted file mode 100644 index f1cce29fc..000000000 --- a/ref/Events/UserEventArgs.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; -namespace Discord -{ - public class UserEventArgs : EventArgs - { - public IUser User => null; - } -} diff --git a/ref/Events/UserUpdatedEventArgs.cs b/ref/Events/UserUpdatedEventArgs.cs deleted file mode 100644 index c45c60701..000000000 --- a/ref/Events/UserUpdatedEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -namespace Discord -{ - public class UserUpdatedEventArgs : EventArgs - { - public IUser Before => null; - public IUser After => null; - } -} diff --git a/ref/Format.cs b/ref/Format.cs deleted file mode 100644 index e30931ae9..000000000 --- a/ref/Format.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public static class Format - { - public static string Escape(string text) => null; - - public static string Bold(string text, bool escape = true) => null; - public static string Italics(string text, bool escape = true) => null; - public static string Underline(string text, bool escape = true) => null; - public static string Strikeout(string text, bool escape = true) => null; - - public static string Code(string text, string language = null) => null; - } -} diff --git a/ref/ILogger.cs b/ref/ILogger.cs deleted file mode 100644 index a3123edc9..000000000 --- a/ref/ILogger.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Discord.Logging -{ - public interface ILogger - { - LogSeverity Level { get; } - - void Log(LogSeverity severity, string message, Exception exception = null); - void Error(string message, Exception exception = null); - void Error(Exception exception); - void Warning(string message, Exception exception = null); - void Warning(Exception exception); - void Info(string message, Exception exception = null); - void Info(Exception exception); - void Verbose(string message, Exception exception = null); - void Verbose(Exception exception); - void Debug(string message, Exception exception = null); - void Debug(Exception exception); - -#if DOTNET5_4 - void Log(LogSeverity severity, FormattableString message, Exception exception = null); - void Error(FormattableString message, Exception exception = null); - void Warning(FormattableString message, Exception exception = null); - void Info(FormattableString message, Exception exception = null); - void Verbose(FormattableString message, Exception exception = null); - void Debug(FormattableString message, Exception exception = null); -#endif - } -} diff --git a/ref/MessageQueue.cs b/ref/MessageQueue.cs deleted file mode 100644 index 5f56abd1e..000000000 --- a/ref/MessageQueue.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public class MessageQueue - { - public int Count { get; } - - public void Clear() { } - } -} diff --git a/ref/Net/HttpException.cs b/ref/Net/HttpException.cs deleted file mode 100644 index 3704ffb83..000000000 --- a/ref/Net/HttpException.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Net; - -namespace Discord.Net -{ - public class HttpException : Exception - { - public HttpStatusCode StatusCode { get; } - - public HttpException(HttpStatusCode statusCode) - : base($"The server responded with error {(int)statusCode} ({statusCode})") - { - StatusCode = statusCode; - } - } -} diff --git a/ref/Net/Rest/CompletedRequestEventArgs.cs b/ref/Net/Rest/CompletedRequestEventArgs.cs deleted file mode 100644 index ed9d1673f..000000000 --- a/ref/Net/Rest/CompletedRequestEventArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Discord.Net.Rest -{ - public class CompletedRequestEventArgs : RequestEventArgs - { - public object Response { get; set; } - public string ResponseJson { get; set; } - public double Milliseconds { get; set; } - - public CompletedRequestEventArgs(IRestRequest request, object response, string responseJson, double milliseconds) - : base(request) - { - Response = response; - ResponseJson = responseJson; - Milliseconds = milliseconds; - } - } -} diff --git a/ref/Net/Rest/IRestClient.cs b/ref/Net/Rest/IRestClient.cs deleted file mode 100644 index 83c0405c7..000000000 --- a/ref/Net/Rest/IRestClient.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.Rest -{ - public interface IRestClient - { - event EventHandler SendingRequest; - event EventHandler SentRequest; - - CancellationToken CancelToken { get; } - string Token { get; } - - Task Send(IRestRequest request) - where ResponseT : class; - Task Send(IRestRequest request); - - Task Send(IRestFileRequest request) - where ResponseT : class; - Task Send(IRestFileRequest request); - } -} diff --git a/ref/Net/Rest/IRestClientProvider.cs b/ref/Net/Rest/IRestClientProvider.cs deleted file mode 100644 index cb22a7474..000000000 --- a/ref/Net/Rest/IRestClientProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -namespace Discord.Net.Rest -{ - public interface IRestClientProvider - { - IRestClient Create(string baseUrl, CancellationToken cancelToken); - } -} diff --git a/ref/Net/Rest/RequestEventArgs.cs b/ref/Net/Rest/RequestEventArgs.cs deleted file mode 100644 index cac734fc6..000000000 --- a/ref/Net/Rest/RequestEventArgs.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Discord.Net.Rest -{ - public class RequestEventArgs : EventArgs - { - public IRestRequest Request { get; set; } - public bool Cancel { get; set; } - - public RequestEventArgs(IRestRequest request) { } - } -} diff --git a/ref/Net/TimeoutException.cs b/ref/Net/TimeoutException.cs deleted file mode 100644 index d1a644049..000000000 --- a/ref/Net/TimeoutException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Discord.Net -{ - public class TimeoutException : OperationCanceledException - { - public TimeoutException() { } - } -} diff --git a/ref/Net/WebSocketException.cs b/ref/Net/WebSocketException.cs deleted file mode 100644 index df6377e13..000000000 --- a/ref/Net/WebSocketException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Discord.Net -{ - public class WebSocketException : Exception - { - public int Code { get; } - public string Reason { get; } - - public WebSocketException(int code, string reason) { } - } -} diff --git a/ref/Net/WebSockets/BinaryMessageEventArgs.cs b/ref/Net/WebSockets/BinaryMessageEventArgs.cs deleted file mode 100644 index 3fd4425fa..000000000 --- a/ref/Net/WebSockets/BinaryMessageEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord.Net.WebSockets -{ - public class BinaryMessageEventArgs : EventArgs - { - public byte[] Data { get; } - - public BinaryMessageEventArgs(byte[] data) { } - } -} diff --git a/ref/Net/WebSockets/GatewaySocket.cs b/ref/Net/WebSockets/GatewaySocket.cs deleted file mode 100644 index e8f2ddd3d..000000000 --- a/ref/Net/WebSockets/GatewaySocket.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Discord.Net.Rest; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public class GatewaySocket - { - public string SessionId { get; } - - public event EventHandler ReceivedDispatch = delegate { }; - - public Task Connect(IRestClient rest, CancellationToken parentCancelToken) => null; - public Task Disconnect() => null; - - public void SendIdentify(string token) { } - - public void SendResume() { } - public void SendHeartbeat() { } - public void SendUpdateStatus(long? idleSince, string gameName) { } - public void SendUpdateVoice(ulong? serverId, ulong? channelId, bool isSelfMuted, bool isSelfDeafened) { } - public void SendRequestMembers(IEnumerable serverId, string query, int limit) { } - - public void WaitForConnection(CancellationToken cancelToken) { } - } -} diff --git a/ref/Net/WebSockets/IWebSocket.cs b/ref/Net/WebSockets/IWebSocket.cs deleted file mode 100644 index 06a274305..000000000 --- a/ref/Net/WebSockets/IWebSocket.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Threading; - -namespace Discord.Net.WebSockets -{ - public interface IWebSocket - { - CancellationToken CancelToken { get; } - ConnectionState State { get; } - string Host { get; set; } - - event EventHandler Connected; - event EventHandler Disconnected; - } -} diff --git a/ref/Net/WebSockets/IWebSocketEngine.cs b/ref/Net/WebSockets/IWebSocketEngine.cs deleted file mode 100644 index 68f31f12b..000000000 --- a/ref/Net/WebSockets/IWebSocketEngine.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public interface IWebSocketEngine - { - event EventHandler BinaryMessage; - event EventHandler TextMessage; - - Task Connect(string host, CancellationToken cancelToken); - Task Disconnect(); - void QueueMessage(string message); - IEnumerable GetTasks(CancellationToken cancelToken); - } -} diff --git a/ref/Net/WebSockets/IWebSocketProvider.cs b/ref/Net/WebSockets/IWebSocketProvider.cs deleted file mode 100644 index 20f7559be..000000000 --- a/ref/Net/WebSockets/IWebSocketProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading; - -namespace Discord.Net.WebSockets -{ - public interface IWebSocketProvider - { - IWebSocket Create(CancellationToken cancelToken); - } -} diff --git a/ref/Net/WebSockets/TextMessageEventArgs.cs b/ref/Net/WebSockets/TextMessageEventArgs.cs deleted file mode 100644 index e4e186044..000000000 --- a/ref/Net/WebSockets/TextMessageEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord.Net.WebSockets -{ - public class TextMessageEventArgs : EventArgs - { - public string Message { get; } - - public TextMessageEventArgs(string msg) { Message = msg; } - } -} diff --git a/ref/Net/WebSockets/WebSocketEventEventArgs.cs b/ref/Net/WebSockets/WebSocketEventEventArgs.cs deleted file mode 100644 index 676c0ba6e..000000000 --- a/ref/Net/WebSockets/WebSocketEventEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; - -namespace Discord.Net.WebSockets -{ - public class WebSocketEventEventArgs : EventArgs - { - public string Type { get; } - public JToken Payload { get; } - } -} diff --git a/ref/project.json b/ref/project.json deleted file mode 100644 index 565bc2e86..000000000 --- a/ref/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "version": "0.9.0-rc3-3", - "description": "An unofficial .Net API wrapper for the Discord client.", - "authors": [ - "RogueException" - ], - "tags": [ - "discord", - "discordapp" - ], - "projectUrl": "https://github.com/RogueException/Discord.Net", - "licenseUrl": "http://opensource.org/licenses/MIT", - "repository": { - "type": "git", - "url": "git://github.com/RogueException/Discord.Net" - }, - "compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], - - "compilationOptions": { - "allowUnsafe": true, - "warningsAsErrors": true - }, - - "configurations": { - "TestResponses": { - "compilationOptions": { - "define": [ - "DEBUG", - "TRACE", - "TEST_RESPONSES" - ] - } - } - }, - - "dependencies": { - "Newtonsoft.Json": "8.0.1", - "Nito.AsyncEx": "3.0.1" - }, - - "frameworks": { - "dotnet5.4": { - "dependencies": { - "System.Collections": "4.0.11-beta-23516", - "System.Collections.Concurrent": "4.0.11-beta-23516", - "System.Dynamic.Runtime": "4.0.11-beta-23516", - "System.IO.FileSystem": "4.0.1-beta-23516", - "System.IO.Compression": "4.1.0-beta-23516", - "System.Linq": "4.0.1-beta-23516", - "System.Net.Http": "4.0.1-beta-23516", - "System.Net.NameResolution": "4.0.0-beta-23516", - "System.Net.Sockets": "4.1.0-beta-23409", - "System.Net.Requests": "4.0.11-beta-23516", - "System.Net.WebSockets.Client": "4.0.0-beta-23516", - "System.Reflection": "4.1.0-beta-23516", - "System.Reflection.Emit.Lightweight": "4.0.1-beta-23516", - "System.Runtime.InteropServices": "4.0.21-beta-23516", - "System.Runtime.Serialization.Primitives": "4.1.0-beta-23516", - "System.Security.Cryptography.Algorithms": "4.0.0-beta-23516", - "System.Text.RegularExpressions": "4.0.11-beta-23516", - "System.Threading": "4.0.11-beta-23516" - } - }, - "net45": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build", - "version": "" - }, - "System.Threading.Tasks": { - "type": "build", - "version": "" - } - }, - "dependencies": { - "WebSocket4Net": "0.14.1", - "RestSharp": "105.2.3" - } - } - } -} \ No newline at end of file diff --git a/src/Discord.Net.Audio/AudioClient.cs b/src/Discord.Net.Audio/AudioClient.cs deleted file mode 100644 index 882dca1fe..000000000 --- a/src/Discord.Net.Audio/AudioClient.cs +++ /dev/null @@ -1,283 +0,0 @@ -using Discord.API.Client.GatewaySocket; -using Discord.API.Client.Rest; -using Discord.Logging; -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using Newtonsoft.Json; -using Nito.AsyncEx; -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Audio -{ - internal class AudioClient : IAudioClient - { - private readonly DiscordConfig _config; - private readonly AsyncLock _connectionLock; - private readonly TaskManager _taskManager; - private ConnectionState _gatewayState; - - internal Logger Logger { get; } - - public int Id { get; } - public AudioService Service { get; } - public AudioServiceConfig Config { get; } - public RestClient ClientAPI { get; } - public GatewaySocket GatewaySocket { get; } - public VoiceSocket VoiceSocket { get; } - public JsonSerializer Serializer { get; } - - public CancellationToken CancelToken { get; private set; } - public string SessionId => GatewaySocket.SessionId; - - public ConnectionState State => VoiceSocket.State; - public Server Server => VoiceSocket.Server; - public VoiceChannel Channel => VoiceSocket.Channel; - - public AudioClient(DiscordClient client, Server server, int id) - { - Id = id; - Service = client.GetService(); - Config = Service.Config; - Serializer = client.Serializer; - _gatewayState = (int)ConnectionState.Disconnected; - - //Logging - Logger = client.Log.CreateLogger($"AudioClient #{id}"); - - //Async - _taskManager = new TaskManager(Cleanup, false); - _connectionLock = new AsyncLock(); - CancelToken = new CancellationToken(true); - - //Networking - if (Config.EnableMultiserver) - { - //TODO: We can remove this hack when official API launches - var baseConfig = client.Config; - var builder = new DiscordConfigBuilder - { - AppName = baseConfig.AppName, - AppUrl = baseConfig.AppUrl, - AppVersion = baseConfig.AppVersion, - CacheToken = baseConfig.CacheDir != null, - ConnectionTimeout = baseConfig.ConnectionTimeout, - EnablePreUpdateEvents = false, - FailedReconnectDelay = baseConfig.FailedReconnectDelay, - LargeThreshold = 1, - LogLevel = baseConfig.LogLevel, - MessageCacheSize = 0, - ReconnectDelay = baseConfig.ReconnectDelay, - UsePermissionsCache = false - }; - _config = builder.Build(); - - ClientAPI = new JsonRestClient(_config, DiscordConfig.ClientAPIUrl, client.Log.CreateLogger($"ClientAPI #{id}")); - GatewaySocket = new GatewaySocket(_config, client.Serializer, client.Log.CreateLogger($"Gateway #{id}")); - GatewaySocket.Connected += (s, e) => - { - if (_gatewayState == ConnectionState.Connecting) - EndGatewayConnect(); - }; - } - else - { - _config = client.Config; - GatewaySocket = client.GatewaySocket; - } - GatewaySocket.ReceivedDispatch += (s, e) => OnReceivedEvent(e); - VoiceSocket = new VoiceSocket(_config, Config, client.Serializer, client.Log.CreateLogger($"Voice #{id}")); - VoiceSocket.Server = server; - } - - public async Task Connect() - { - if (Config.EnableMultiserver) - await BeginGatewayConnect().ConfigureAwait(false); - else - { - var cancelSource = new CancellationTokenSource(); - CancelToken = cancelSource.Token; - await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false); - } - } - private async Task BeginGatewayConnect() - { - try - { - using (await _connectionLock.LockAsync().ConfigureAwait(false)) - { - await Disconnect().ConfigureAwait(false); - _taskManager.ClearException(); - - ClientAPI.Token = Service.Client.ClientAPI.Token; - - Stopwatch stopwatch = null; - if (_config.LogLevel >= LogSeverity.Verbose) - stopwatch = Stopwatch.StartNew(); - _gatewayState = ConnectionState.Connecting; - - var cancelSource = new CancellationTokenSource(); - CancelToken = cancelSource.Token; - ClientAPI.CancelToken = CancelToken; - - await GatewaySocket.Connect(ClientAPI, CancelToken).ConfigureAwait(false); - - await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false); - GatewaySocket.WaitForConnection(CancelToken); - - if (_config.LogLevel >= LogSeverity.Verbose) - { - stopwatch.Stop(); - double seconds = Math.Round(stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerSecond, 2); - Logger.Verbose($"Connection took {seconds} sec"); - } - } - } - catch (Exception ex) - { - await _taskManager.SignalError(ex).ConfigureAwait(false); - throw; - } - } - private void EndGatewayConnect() - { - _gatewayState = ConnectionState.Connected; - } - - public async Task Disconnect() - { - await _taskManager.Stop(true).ConfigureAwait(false); - if (Config.EnableMultiserver) - ClientAPI.Token = null; - } - private async Task Cleanup() - { - var oldState = _gatewayState; - _gatewayState = ConnectionState.Disconnecting; - - if (Config.EnableMultiserver) - { - if (oldState == ConnectionState.Connected) - { - try { await ClientAPI.Send(new LogoutRequest()).ConfigureAwait(false); } - catch (OperationCanceledException) { } - } - - await GatewaySocket.Disconnect().ConfigureAwait(false); - ClientAPI.Token = null; - } - - var server = VoiceSocket.Server; - VoiceSocket.Server = null; - VoiceSocket.Channel = null; - if (Config.EnableMultiserver) - await Service.RemoveClient(server, this).ConfigureAwait(false); - SendVoiceUpdate(server.Id, null); - - await VoiceSocket.Disconnect().ConfigureAwait(false); - if (Config.EnableMultiserver) - await GatewaySocket.Disconnect().ConfigureAwait(false); - - _gatewayState = (int)ConnectionState.Disconnected; - } - - public async Task Join(VoiceChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - if (channel.Type != ChannelType.Voice) - throw new ArgumentException("Channel must be a voice channel.", nameof(channel)); - if (channel == VoiceSocket.Channel) return; - var server = channel.Server; - if (server != VoiceSocket.Server) - throw new ArgumentException("This is channel is not part of the current server.", nameof(channel)); - if (VoiceSocket.Server == null) - throw new InvalidOperationException("This client has been closed."); - - SendVoiceUpdate(channel.Server.Id, channel.Id); - using (await _connectionLock.LockAsync().ConfigureAwait(false)) - await Task.Run(() => VoiceSocket.WaitForConnection(CancelToken)).ConfigureAwait(false); - } - - private async void OnReceivedEvent(WebSocketEventEventArgs e) - { - try - { - switch (e.Type) - { - case "VOICE_STATE_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - if (data.GuildId == VoiceSocket.Server?.Id && data.UserId == Service.Client.CurrentUser?.Id) - { - if (data.ChannelId == null) - await Disconnect().ConfigureAwait(false); - else - { - var channel = Service.Client.GetChannel(data.ChannelId.Value) as VoiceChannel; - if (channel != null) - VoiceSocket.Channel = channel; - else - { - Logger.Warning("VOICE_STATE_UPDATE referenced an unknown channel, disconnecting."); - await Disconnect().ConfigureAwait(false); - } - } - } - } - break; - case "VOICE_SERVER_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - if (data.GuildId == VoiceSocket.Server?.Id) - { - var client = Service.Client; - var id = client.CurrentUser?.Id; - if (id != null) - { - var host = "wss://" + e.Payload.Value("endpoint").Split(':')[0]; - await VoiceSocket.Connect(host, data.Token, id.Value, GatewaySocket.SessionId, CancelToken).ConfigureAwait(false); - } - } - } - break; - } - } - catch (Exception ex) - { - Logger.Error($"Error handling {e.Type} event", ex); - } - } - - public void Send(byte[] data, int offset, int count) - { - if (data == null) throw new ArgumentException(nameof(data)); - if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); - if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); - if (VoiceSocket.Server == null) return; //Has been closed - if (count == 0) return; - - VoiceSocket.SendPCMFrames(data, offset, count); - } - - public void Clear() - { - if (VoiceSocket.Server == null) return; //Has been closed - VoiceSocket.ClearPCMFrames(); - } - public void Wait() - { - if (VoiceSocket.Server == null) return; //Has been closed - VoiceSocket.WaitForQueue(); - } - - public void SendVoiceUpdate(ulong? serverId, ulong? channelId) - { - GatewaySocket.SendUpdateVoice(serverId, channelId, - (Service.Config.Mode | AudioMode.Outgoing) == 0, - (Service.Config.Mode | AudioMode.Incoming) == 0); - } - } -} diff --git a/src/Discord.Net.Audio/AudioExtensions.cs b/src/Discord.Net.Audio/AudioExtensions.cs deleted file mode 100644 index 7def445a6..000000000 --- a/src/Discord.Net.Audio/AudioExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord.Audio -{ - public static class AudioExtensions - { - public static DiscordClient UsingAudio(this DiscordClient client, AudioServiceConfig config = null) - { - client.AddService(new AudioService(config)); - return client; - } - public static DiscordClient UsingAudio(this DiscordClient client, Action configFunc = null) - { - var builder = new AudioServiceConfigBuilder(); - configFunc(builder); - client.AddService(new AudioService(builder)); - return client; - } - - public static Task JoinAudio(this VoiceChannel channel) => channel.Client.GetService().Join(channel); - public static Task LeaveAudio(this VoiceChannel channel) => channel.Client.GetService().Leave(channel); - public static Task LeaveAudio(this Server server) => server.Client.GetService().Leave(server); - public static IAudioClient GetAudioClient(this Server server) => server.Client.GetService().GetClient(server); - } -} diff --git a/src/Discord.Net.Audio/AudioMode.cs b/src/Discord.Net.Audio/AudioMode.cs deleted file mode 100644 index b9acdbf89..000000000 --- a/src/Discord.Net.Audio/AudioMode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord.Audio -{ - public enum AudioMode : byte - { - Outgoing = 1, - Incoming = 2, - Both = Outgoing | Incoming - } -} diff --git a/src/Discord.Net.Audio/AudioService.cs b/src/Discord.Net.Audio/AudioService.cs deleted file mode 100644 index e44a4a1ce..000000000 --- a/src/Discord.Net.Audio/AudioService.cs +++ /dev/null @@ -1,193 +0,0 @@ -using Nito.AsyncEx; -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.Audio -{ - public class AudioService : IService - { - private readonly AsyncLock _asyncLock; - private AudioClient _defaultClient; //Only used for single server - private VirtualClient _currentClient; //Only used for single server - private ConcurrentDictionary _voiceClients; - private ConcurrentDictionary _talkingUsers; - private int _nextClientId; - - public DiscordClient Client { get; private set; } - public AudioServiceConfig Config { get; } - - public event EventHandler Connected = delegate { }; - public event EventHandler Disconnected = delegate { }; - public event EventHandler UserIsSpeakingUpdated = delegate { }; - - private void OnConnected() - => Connected(this, EventArgs.Empty); - private void OnDisconnected(ulong serverId, bool wasUnexpected, Exception ex) - => Disconnected(this, new VoiceDisconnectedEventArgs(serverId, wasUnexpected, ex)); - private void OnUserIsSpeakingUpdated(User user, bool isSpeaking) - => UserIsSpeakingUpdated(this, new UserIsSpeakingEventArgs(user, isSpeaking)); - - public AudioService() - : this(new AudioServiceConfigBuilder()) - { - } - public AudioService(AudioServiceConfigBuilder builder) - : this(builder.Build()) - { - } - public AudioService(AudioServiceConfig config) - { - Config = config; - _asyncLock = new AsyncLock(); - - } - void IService.Install(DiscordClient client) - { - Client = client; - - if (Config.EnableMultiserver) - _voiceClients = new ConcurrentDictionary(); - else - { - var logger = Client.Log.CreateLogger("Voice"); - _defaultClient = new AudioClient(Client, null, 0); - } - _talkingUsers = new ConcurrentDictionary(); - - client.GatewaySocket.Disconnected += async (s, e) => - { - if (Config.EnableMultiserver) - { - var tasks = _voiceClients - .Select(x => - { - var val = x.Value; - if (val != null) - return x.Value.Disconnect(); - else - return TaskHelper.CompletedTask; - }) - .ToArray(); - await Task.WhenAll(tasks).ConfigureAwait(false); - _voiceClients.Clear(); - } - foreach (var member in _talkingUsers) - { - bool ignored; - if (_talkingUsers.TryRemove(member.Key, out ignored)) - OnUserIsSpeakingUpdated(member.Key, false); - } - }; - } - - public IAudioClient GetClient(Server server) - { - if (server == null) throw new ArgumentNullException(nameof(server)); - - if (Config.EnableMultiserver) - { - AudioClient client; - if (_voiceClients.TryGetValue(server.Id, out client)) - return client; - else - return null; - } - else - { - if (server == _currentClient.Server) - return _currentClient; - else - return null; - } - } - - //Called from AudioClient.Disconnect - internal async Task RemoveClient(Server server, AudioClient client) - { - using (await _asyncLock.LockAsync().ConfigureAwait(false)) - { - if (_voiceClients.TryUpdate(server.Id, null, client)) - _voiceClients.TryRemove(server.Id, out client); - } - } - - public async Task Join(VoiceChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - - var server = channel.Server; - using (await _asyncLock.LockAsync().ConfigureAwait(false)) - { - if (Config.EnableMultiserver) - { - AudioClient client; - if (!_voiceClients.TryGetValue(server.Id, out client)) - { - client = new AudioClient(Client, server, unchecked(++_nextClientId)); - _voiceClients[server.Id] = client; - - await client.Connect().ConfigureAwait(false); - - /*voiceClient.VoiceSocket.FrameReceived += (s, e) => - { - OnFrameReceieved(e); - }; - voiceClient.VoiceSocket.UserIsSpeaking += (s, e) => - { - var user = server.GetUser(e.UserId); - OnUserIsSpeakingUpdated(user, e.IsSpeaking); - };*/ - } - - await client.Join(channel).ConfigureAwait(false); - return client; - } - else - { - if (_defaultClient.Server != server) - { - await _defaultClient.Disconnect().ConfigureAwait(false); - _defaultClient.VoiceSocket.Server = server; - await _defaultClient.Connect().ConfigureAwait(false); - } - var client = new VirtualClient(_defaultClient, server); - _currentClient = client; - - await client.Join(channel).ConfigureAwait(false); - return client; - } - - } - } - - public Task Leave(Server server) => Leave(server, null); - public Task Leave(VoiceChannel channel) => Leave(channel.Server, channel); - private async Task Leave(Server server, VoiceChannel channel) - { - if (server == null) throw new ArgumentNullException(nameof(server)); - - if (Config.EnableMultiserver) - { - AudioClient client; - //Potential race condition if changing channels during this call, but that's acceptable - if (channel == null || (_voiceClients.TryGetValue(server.Id, out client) && client.Channel == channel)) - { - if (_voiceClients.TryRemove(server.Id, out client)) - await client.Disconnect().ConfigureAwait(false); - } - } - else - { - using (await _asyncLock.LockAsync().ConfigureAwait(false)) - { - var client = GetClient(server) as VirtualClient; - if (client != null && client.Channel == channel) - await _defaultClient.Disconnect().ConfigureAwait(false); - } - } - - } - } -} diff --git a/src/Discord.Net.Audio/AudioServiceConfig.cs b/src/Discord.Net.Audio/AudioServiceConfig.cs deleted file mode 100644 index 89d05d85b..000000000 --- a/src/Discord.Net.Audio/AudioServiceConfig.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace Discord.Audio -{ - public class AudioServiceConfigBuilder - { - /// Enables the voice websocket and UDP client and specifies how it will be used. - public AudioMode Mode { get; set; } = AudioMode.Outgoing; - - /// Enables the voice websocket and UDP client. This option requires the libsodium .dll or .so be in the local or system folder. - public bool EnableEncryption { get; set; } = true; - /// - /// Enables the client to be simultaneously connected to multiple channels at once (Discord still limits you to one channel per server). - /// This option uses a lot of CPU power and network bandwidth, as a new gateway connection needs to be spun up per server. Use sparingly. - /// - public bool EnableMultiserver { get; set; } = false; - - /// Gets or sets the buffer length (in milliseconds) for outgoing voice packets. - public int BufferLength { get; set; } = 1000; - /// Gets or sets the bitrate used (in kbit/s, between 1 and MaxBitrate inclusively) for outgoing voice packets. A null value will use default Opus settings. - public int? Bitrate { get; set; } = null; - /// Gets or sets the number of channels (1 or 2) used in both input provided to IAudioClient and output send to Discord. Defaults to 2 (stereo). - public int Channels { get; set; } = 2; - - public AudioServiceConfig Build() => new AudioServiceConfig(this); - } - - public class AudioServiceConfig - { - public const int MaxBitrate = 128; - - public AudioMode Mode { get; } - - public bool EnableEncryption { get; } - public bool EnableMultiserver { get; } - - public int BufferLength { get; } - public int? Bitrate { get; } - public int Channels { get; } - - internal AudioServiceConfig(AudioServiceConfigBuilder builder) - { - Mode = builder.Mode; - - EnableEncryption = builder.EnableEncryption; - EnableMultiserver = builder.EnableMultiserver; - - BufferLength = builder.BufferLength; - Bitrate = builder.Bitrate; - Channels = builder.Channels; - } - } -} diff --git a/src/Discord.Net.Audio/Discord.Net.Audio.xproj b/src/Discord.Net.Audio/Discord.Net.Audio.xproj deleted file mode 100644 index 4eb480f88..000000000 --- a/src/Discord.Net.Audio/Discord.Net.Audio.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - dff7afe3-ca77-4109-bade-b4b49a4f6648 - Discord.Audio - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - True - - - \ No newline at end of file diff --git a/src/Discord.Net.Audio/IAudioClient.cs b/src/Discord.Net.Audio/IAudioClient.cs deleted file mode 100644 index a986fad7d..000000000 --- a/src/Discord.Net.Audio/IAudioClient.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Audio -{ - public interface IAudioClient - { - /// Gets the unique identifier for this client. - int Id { get; } - /// Gets the session id for the current connection. - string SessionId { get; } - /// Gets the current state of this client. - ConnectionState State { get; } - /// Gets the channel this client is currently a member of. - VoiceChannel Channel { get; } - /// Gets the server this client is bound to. - Server Server { get; } - /// Gets a cancellation token that triggers when the client is manually disconnected. - CancellationToken CancelToken { get; } - - /// Gets the internal RestClient for the Client API endpoint. - RestClient ClientAPI { get; } - /// Gets the internal WebSocket for the Gateway event stream. - GatewaySocket GatewaySocket { get; } - /// Gets the internal WebSocket for the Voice control stream. - VoiceSocket VoiceSocket { get; } - - /// Moves the client to another channel on the same server. - Task Join(VoiceChannel channel); - /// Disconnects from the Discord server, canceling any pending requests. - Task Disconnect(); - - /// Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. - /// PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. - /// Offset . - /// Number of bytes in this frame. - void Send(byte[] data, int offset, int count); - /// Clears the PCM buffer. - void Clear(); - /// Blocks until the voice output buffer is empty. - void Wait(); - } -} diff --git a/src/Discord.Net.Audio/InternalFrameEventArgs.cs b/src/Discord.Net.Audio/InternalFrameEventArgs.cs deleted file mode 100644 index b74dc8295..000000000 --- a/src/Discord.Net.Audio/InternalFrameEventArgs.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Discord -{ - internal class InternalFrameEventArgs : EventArgs - { - public ulong UserId { get; } - public ulong ChannelId { get; } - public byte[] Buffer { get; } - public int Offset { get; } - public int Count { get; } - - public InternalFrameEventArgs(ulong userId, ulong channelId, byte[] buffer, int offset, int count) - { - UserId = userId; - ChannelId = channelId; - Buffer = buffer; - Offset = offset; - Count = count; - } - } -} diff --git a/src/Discord.Net.Audio/InternalIsSpeakingEventArgs.cs b/src/Discord.Net.Audio/InternalIsSpeakingEventArgs.cs deleted file mode 100644 index 641e863f4..000000000 --- a/src/Discord.Net.Audio/InternalIsSpeakingEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord.Audio -{ - internal class InternalIsSpeakingEventArgs - { - public ulong UserId { get; } - public bool IsSpeaking { get; } - - public InternalIsSpeakingEventArgs(ulong userId, bool isSpeaking) - { - UserId = userId; - IsSpeaking = isSpeaking; - } - } -} diff --git a/src/Discord.Net.Audio/Net/VoiceSocket.cs b/src/Discord.Net.Audio/Net/VoiceSocket.cs deleted file mode 100644 index 9ee5c60e0..000000000 --- a/src/Discord.Net.Audio/Net/VoiceSocket.cs +++ /dev/null @@ -1,516 +0,0 @@ -using Discord.API.Client; -using Discord.API.Client.VoiceSocket; -using Discord.Audio; -using Discord.Audio.Opus; -using Discord.Audio.Sodium; -using Discord.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public partial class VoiceSocket : WebSocket - { - private const int MaxOpusSize = 4000; - private const string EncryptedMode = "xsalsa20_poly1305"; - private const string UnencryptedMode = "plain"; - - private readonly int _targetAudioBufferLength; - private readonly ConcurrentDictionary _decoders; - private readonly AudioServiceConfig _audioConfig; - private Task _sendTask, _receiveTask; - private VoiceBuffer _sendBuffer; - private OpusEncoder _encoder; - private uint _ssrc; - private ConcurrentDictionary _ssrcMapping; - private UdpClient _udp; - private IPEndPoint _endpoint; - private bool _isEncrypted; - private byte[] _secretKey, _encodingBuffer; - private ushort _sequence; - private string _encryptionMode; - private int _ping; - private ulong? _userId; - private string _sessionId; - - public string Token { get; internal set; } - public Server Server { get; internal set; } - public VoiceChannel Channel { get; internal set; } - - public int Ping => _ping; - internal VoiceBuffer OutputBuffer => _sendBuffer; - - internal event EventHandler UserIsSpeaking = delegate { }; - internal event EventHandler FrameReceived = delegate { }; - - private void OnUserIsSpeaking(ulong userId, bool isSpeaking) - => UserIsSpeaking(this, new InternalIsSpeakingEventArgs(userId, isSpeaking)); - internal void OnFrameReceived(ulong userId, ulong channelId, byte[] buffer, int offset, int count) - => FrameReceived(this, new InternalFrameEventArgs(userId, channelId, buffer, offset, count)); - - internal VoiceSocket(DiscordConfig config, AudioServiceConfig audioConfig, JsonSerializer serializer, Logger logger) - : base(config, serializer, logger) - { - _audioConfig = audioConfig; - _decoders = new ConcurrentDictionary(); - _targetAudioBufferLength = _audioConfig.BufferLength / 20; //20 ms frames - _encodingBuffer = new byte[MaxOpusSize]; - _ssrcMapping = new ConcurrentDictionary(); - _encoder = new OpusEncoder(48000, _audioConfig.Channels, 20, _audioConfig.Bitrate, OpusApplication.MusicOrMixed); - _sendBuffer = new VoiceBuffer((int)Math.Ceiling(_audioConfig.BufferLength / (double)_encoder.FrameLength), _encoder.FrameSize); - } - - public Task Connect(string host, string token, ulong userId, string sessionId, CancellationToken parentCancelToken) - { - Host = host; - Token = token; - _userId = userId; - _sessionId = sessionId; - return BeginConnect(parentCancelToken); - } - private async Task Reconnect() - { - try - { - var cancelToken = _parentCancelToken; - await Task.Delay(_config.ReconnectDelay, cancelToken).ConfigureAwait(false); - while (!cancelToken.IsCancellationRequested) - { - try - { - await BeginConnect(_parentCancelToken).ConfigureAwait(false); - break; - } - catch (OperationCanceledException) { throw; } - catch (Exception ex) - { - Logger.Error("Reconnect failed", ex); - //Net is down? We can keep trying to reconnect until the user runs Disconnect() - await Task.Delay(_config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); - } - } - } - catch (OperationCanceledException) { } - } - public async Task Disconnect() - { - await _taskManager.Stop(true).ConfigureAwait(false); - _userId = null; - } - - protected override async Task Run() - { - _udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); - - List tasks = new List(); - if (_audioConfig.Mode.HasFlag(AudioMode.Outgoing)) - _sendTask = Task.Run(() => SendVoiceAsync(CancelToken)); - _receiveTask = Task.Run(() => ReceiveVoiceAsync(CancelToken)); - - SendIdentify(_userId.Value, _sessionId); - -#if !DOTNET5_4 - tasks.Add(WatcherAsync()); -#endif - tasks.AddRange(_engine.GetTasks(CancelToken)); - tasks.Add(HeartbeatAsync(CancelToken)); - await _taskManager.Start(tasks, _cancelSource).ConfigureAwait(false); - } - protected override async Task Cleanup() - { - var sendThread = _sendTask; - if (sendThread != null) - { - try { await sendThread.ConfigureAwait(false); } - catch (Exception) { } //Ignore any errors during cleanup - } - _sendTask = null; - - var receiveThread = _receiveTask; - if (receiveThread != null) - { - try { await receiveThread.ConfigureAwait(false); } - catch (Exception) { } //Ignore any errors during cleanup - } - _receiveTask = null; - - OpusDecoder decoder; - foreach (var pair in _decoders) - { - if (_decoders.TryRemove(pair.Key, out decoder)) - decoder.Dispose(); - } - - ClearPCMFrames(); - _udp = null; - - await base.Cleanup().ConfigureAwait(false); - } - - private async Task ReceiveVoiceAsync(CancellationToken cancelToken) - { - var closeTask = cancelToken.Wait(); - try - { - byte[] packet, decodingBuffer = null, nonce = null, result; - int packetLength, resultOffset, resultLength; - IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0); - - if ((_audioConfig.Mode & AudioMode.Incoming) != 0) - { - decodingBuffer = new byte[MaxOpusSize]; - nonce = new byte[24]; - } - - while (!cancelToken.IsCancellationRequested) - { - await Task.Delay(1).ConfigureAwait(false); - if (_udp.Available > 0) - { -#if !DOTNET5_4 - packet = _udp.Receive(ref endpoint); -#else - //TODO: Is this really the only way to end a Receive call in DOTNET5_4? - var receiveTask = _udp.ReceiveAsync(); - var task = Task.WhenAny(closeTask, receiveTask).Result; - if (task == closeTask) - break; - var udpPacket = receiveTask.Result; - packet = udpPacket.Buffer; - endpoint = udpPacket.RemoteEndPoint; -#endif - packetLength = packet.Length; - - if (packetLength > 0 && endpoint.Equals(_endpoint)) - { - if (State != ConnectionState.Connected) - { - if (packetLength != 70) - return; - - string ip = Encoding.UTF8.GetString(packet, 4, 70 - 6).TrimEnd('\0'); - int port = packet[68] | packet[69] << 8; - - SendSelectProtocol(ip, port); - if ((_audioConfig.Mode & AudioMode.Incoming) == 0) - return; //We dont need this thread anymore - } - else - { - //Parse RTP Data - if (packetLength < 12) return; - if (packet[0] != 0x80) return; //Flags - if (packet[1] != 0x78) return; //Payload Type - - ushort sequenceNumber = (ushort)((packet[2] << 8) | - packet[3] << 0); - uint timestamp = (uint)((packet[4] << 24) | - (packet[5] << 16) | - (packet[6] << 8) | - (packet[7] << 0)); - uint ssrc = (uint)((packet[8] << 24) | - (packet[9] << 16) | - (packet[10] << 8) | - (packet[11] << 0)); - - //Decrypt - if (_isEncrypted) - { - if (packetLength < 28) //12 + 16 (RTP + Poly1305 MAC) - return; - - Buffer.BlockCopy(packet, 0, nonce, 0, 12); - int ret = SecretBox.Decrypt(packet, 12, packetLength - 12, decodingBuffer, nonce, _secretKey); - if (ret != 0) - continue; - result = decodingBuffer; - resultOffset = 0; - resultLength = packetLength - 28; - } - else //Plain - { - result = packet; - resultOffset = 12; - resultLength = packetLength - 12; - } - - /*if (_logLevel >= LogMessageSeverity.Debug) - RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/ - - ulong userId; - if (_ssrcMapping.TryGetValue(ssrc, out userId)) - OnFrameReceived(userId, Channel.Id, result, resultOffset, resultLength); - } - } - } - } - } - catch (OperationCanceledException) { } - catch (InvalidOperationException) { } //Includes ObjectDisposedException - } - - private async Task SendVoiceAsync(CancellationToken cancelToken) - { - try - { - while (!cancelToken.IsCancellationRequested && State != ConnectionState.Connected) - await Task.Delay(1).ConfigureAwait(false); - - if (cancelToken.IsCancellationRequested) - return; - - byte[] frame = new byte[_encoder.FrameSize]; - byte[] encodedFrame = new byte[MaxOpusSize]; - byte[] voicePacket, pingPacket, nonce = null; - uint timestamp = 0; - double nextTicks = 0.0, nextPingTicks = 0.0; - long ticksPerSeconds = Stopwatch.Frequency; - double ticksPerMillisecond = Stopwatch.Frequency / 1000.0; - double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength; - double spinLockThreshold = 3 * ticksPerMillisecond; - uint samplesPerFrame = (uint)_encoder.SamplesPerFrame; - Stopwatch sw = Stopwatch.StartNew(); - - if (_isEncrypted) - { - nonce = new byte[24]; - voicePacket = new byte[MaxOpusSize + 12 + 16]; - } - else - voicePacket = new byte[MaxOpusSize + 12]; - - pingPacket = new byte[8]; - - int rtpPacketLength = 0; - voicePacket[0] = 0x80; //Flags; - voicePacket[1] = 0x78; //Payload Type - voicePacket[8] = (byte)(_ssrc >> 24); - voicePacket[9] = (byte)(_ssrc >> 16); - voicePacket[10] = (byte)(_ssrc >> 8); - voicePacket[11] = (byte)(_ssrc >> 0); - - if (_isEncrypted) - Buffer.BlockCopy(voicePacket, 0, nonce, 0, 12); - - bool hasFrame = false; - while (!cancelToken.IsCancellationRequested) - { - if (!hasFrame && _sendBuffer.Pop(frame)) - { - ushort sequence = unchecked(_sequence++); - voicePacket[2] = (byte)(sequence >> 8); - voicePacket[3] = (byte)(sequence >> 0); - voicePacket[4] = (byte)(timestamp >> 24); - voicePacket[5] = (byte)(timestamp >> 16); - voicePacket[6] = (byte)(timestamp >> 8); - voicePacket[7] = (byte)(timestamp >> 0); - - //Encode - int encodedLength = _encoder.EncodeFrame(frame, 0, encodedFrame); - - //Encrypt - if (_isEncrypted) - { - Buffer.BlockCopy(voicePacket, 2, nonce, 2, 6); //Update nonce - int ret = SecretBox.Encrypt(encodedFrame, encodedLength, voicePacket, 12, nonce, _secretKey); - if (ret != 0) - continue; - rtpPacketLength = encodedLength + 12 + 16; - } - else - { - Buffer.BlockCopy(encodedFrame, 0, voicePacket, 12, encodedLength); - rtpPacketLength = encodedLength + 12; - } - - timestamp = unchecked(timestamp + samplesPerFrame); - hasFrame = true; - } - - long currentTicks = sw.ElapsedTicks; - double ticksToNextFrame = nextTicks - currentTicks; - if (ticksToNextFrame <= 0.0) - { - if (hasFrame) - { - try - { - _udp.Send(voicePacket, rtpPacketLength); - } - catch (SocketException ex) - { - Logger.Error("Failed to send UDP packet.", ex); - } - hasFrame = false; - } - nextTicks += ticksPerFrame; - - //Is it time to send out another ping? - if (currentTicks > nextPingTicks) - { - //Increment in LE - for (int i = 0; i < 8; i++) - { - var b = pingPacket[i]; - if (b == byte.MaxValue) - pingPacket[i] = 0; - else - { - pingPacket[i] = (byte)(b + 1); - break; - } - } - await _udp.SendAsync(pingPacket, pingPacket.Length).ConfigureAwait(false); - nextPingTicks = currentTicks + 5 * ticksPerSeconds; - } - } - else - { - if (hasFrame) - { - int time = (int)Math.Floor(ticksToNextFrame / ticksPerMillisecond); - if (time > 0) - await Task.Delay(time).ConfigureAwait(false); - } - else - await Task.Delay(1).ConfigureAwait(false); //Give as much time to the encrypter as possible - } - } - } - catch (OperationCanceledException) { } - catch (InvalidOperationException) { } //Includes ObjectDisposedException - } -#if !DOTNET5_4 - //Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken - private async Task WatcherAsync() - { - await CancelToken.Wait().ConfigureAwait(false); - _udp.Close(); - } -#endif - - protected override async Task ProcessMessage(string json) - { - await base.ProcessMessage(json).ConfigureAwait(false); - - WebSocketMessage msg; - using (var reader = new JsonTextReader(new StringReader(json))) - msg = _serializer.Deserialize(reader, typeof(WebSocketMessage)) as WebSocketMessage; - - var opCode = (OpCodes)msg.Operation; - switch (opCode) - { - case OpCodes.Ready: - { - if (State != ConnectionState.Connected) - { - var payload = (msg.Payload as JToken).ToObject(_serializer); - _heartbeatInterval = payload.HeartbeatInterval; - _ssrc = payload.SSRC; - var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(); - _endpoint = new IPEndPoint(address, payload.Port); - - if (_audioConfig.EnableEncryption) - { - if (payload.Modes.Contains(EncryptedMode)) - { - _encryptionMode = EncryptedMode; - _isEncrypted = true; - } - else - throw new InvalidOperationException("Unexpected encryption format."); - } - else - { - _encryptionMode = UnencryptedMode; - _isEncrypted = false; - } - _udp.Connect(_endpoint); - - _sequence = 0;// (ushort)_rand.Next(0, ushort.MaxValue); - //No thread issue here because SendAsync doesn't start until _isReady is true - byte[] packet = new byte[70]; - packet[0] = (byte)(_ssrc >> 24); - packet[1] = (byte)(_ssrc >> 16); - packet[2] = (byte)(_ssrc >> 8); - packet[3] = (byte)(_ssrc >> 0); - await _udp.SendAsync(packet, 70).ConfigureAwait(false); - } - } - break; - case OpCodes.Heartbeat: - { - long time = EpochTime.GetMilliseconds(); - var payload = (long)msg.Payload; - _ping = (int)(payload - time); - //TODO: Use this to estimate latency - } - break; - case OpCodes.SessionDescription: - { - var payload = (msg.Payload as JToken).ToObject(_serializer); - _secretKey = payload.SecretKey; - SendSetSpeaking(true); - await EndConnect().ConfigureAwait(false); - } - break; - case OpCodes.Speaking: - { - var payload = (msg.Payload as JToken).ToObject(_serializer); - OnUserIsSpeaking(payload.UserId, payload.IsSpeaking); - } - break; - default: - Logger.Warning($"Unknown Opcode: {opCode}"); - break; - } - } - - public void SendPCMFrames(byte[] data, int offset, int count) - { - _sendBuffer.Push(data, offset, count, CancelToken); - } - public void ClearPCMFrames() - { - _sendBuffer.Clear(CancelToken); - } - - public void WaitForQueue() - { - _sendBuffer.Wait(CancelToken); - } - - public override void SendHeartbeat() - => QueueMessage(new HeartbeatCommand()); - public void SendIdentify(ulong id, string sessionId) - => QueueMessage(new IdentifyCommand - { - GuildId = Server.Id, - UserId = id, - SessionId = sessionId, - Token = Token - }); - public void SendSelectProtocol(string externalAddress, int externalPort) - => QueueMessage(new SelectProtocolCommand - { - Protocol = "udp", - ExternalAddress = externalAddress, - ExternalPort = externalPort, - EncryptionMode = _encryptionMode - }); - public void SendSetSpeaking(bool value) - => QueueMessage(new SetSpeakingCommand { IsSpeaking = value, Delay = 0 }); - - } -} \ No newline at end of file diff --git a/src/Discord.Net.Audio/Opus/OpusConverter.cs b/src/Discord.Net.Audio/Opus/OpusConverter.cs deleted file mode 100644 index d93337138..000000000 --- a/src/Discord.Net.Audio/Opus/OpusConverter.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Runtime.InteropServices; -#if NET45 -using System.Security; -#endif - -namespace Discord.Audio.Opus -{ - internal enum OpusApplication : int - { - Voice = 2048, - MusicOrMixed = 2049, - LowLatency = 2051 - } - internal enum OpusError : int - { - OK = 0, - BadArg = -1, - BufferToSmall = -2, - InternalError = -3, - InvalidPacket = -4, - Unimplemented = -5, - InvalidState = -6, - AllocFail = -7 - } - - internal abstract class OpusConverter : IDisposable - { - protected enum Ctl : int - { - SetBitrateRequest = 4002, - GetBitrateRequest = 4003, - SetInbandFECRequest = 4012, - GetInbandFECRequest = 4013 - } - -#if NET45 - [SuppressUnmanagedCodeSecurity] -#endif - protected unsafe static class UnsafeNativeMethods - { - [DllImport("opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr CreateEncoder(int Fs, int channels, int application, out OpusError error); - [DllImport("opus", EntryPoint = "opus_encoder_destroy", CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyEncoder(IntPtr encoder); - [DllImport("opus", EntryPoint = "opus_encode", CallingConvention = CallingConvention.Cdecl)] - public static extern int Encode(IntPtr st, byte* pcm, int frame_size, byte[] data, int max_data_bytes); - [DllImport("opus", EntryPoint = "opus_encoder_ctl", CallingConvention = CallingConvention.Cdecl)] - public static extern int EncoderCtl(IntPtr st, Ctl request, int value); - - [DllImport("opus", EntryPoint = "opus_decoder_create", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr CreateDecoder(int Fs, int channels, out OpusError error); - [DllImport("opus", EntryPoint = "opus_decoder_destroy", CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyDecoder(IntPtr decoder); - [DllImport("opus", EntryPoint = "opus_decode", CallingConvention = CallingConvention.Cdecl)] - public static extern int Decode(IntPtr st, byte* data, int len, byte[] pcm, int frame_size, int decode_fec); - } - - protected IntPtr _ptr; - - /// Gets the bit rate of this converter. - public const int BitsPerSample = 16; - /// Gets the input sampling rate of this converter. - public int InputSamplingRate { get; } - /// Gets the number of channels of this converter. - public int InputChannels { get; } - /// Gets the milliseconds per frame. - public int FrameLength { get; } - /// Gets the number of samples per frame. - public int SamplesPerFrame { get; } - /// Gets the bytes per frame. - public int FrameSize { get; } - /// Gets the bytes per sample. - public int SampleSize { get; } - - protected OpusConverter(int samplingRate, int channels, int frameLength) - { - if (samplingRate != 8000 && samplingRate != 12000 && - samplingRate != 16000 && samplingRate != 24000 && - samplingRate != 48000) - throw new ArgumentOutOfRangeException(nameof(samplingRate)); - if (channels != 1 && channels != 2) - throw new ArgumentOutOfRangeException(nameof(channels)); - - InputSamplingRate = samplingRate; - InputChannels = channels; - FrameLength = frameLength; - SampleSize = (BitsPerSample / 8) * channels; - SamplesPerFrame = samplingRate / 1000 * FrameLength; - FrameSize = SamplesPerFrame * SampleSize; - } - - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - disposedValue = true; - } - ~OpusConverter() { - Dispose(false); - } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - } -} diff --git a/src/Discord.Net.Audio/Opus/OpusDecoder.cs b/src/Discord.Net.Audio/Opus/OpusDecoder.cs deleted file mode 100644 index d8e6b8087..000000000 --- a/src/Discord.Net.Audio/Opus/OpusDecoder.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace Discord.Audio.Opus -{ - internal class OpusDecoder : OpusConverter - { - /// Creates a new Opus decoder. - /// Sampling rate of the input PCM (in Hz). Supported Values: 8000, 12000, 16000, 24000, or 48000 - /// Length, in milliseconds, of each frame. Supported Values: 2.5, 5, 10, 20, 40, or 60 - public OpusDecoder(int samplingRate, int channels, int frameLength) - : base(samplingRate, channels, frameLength) - { - OpusError error; - _ptr = UnsafeNativeMethods.CreateDecoder(samplingRate, channels, out error); - if (error != OpusError.OK) - throw new InvalidOperationException($"Error occured while creating decoder: {error}"); - } - - /// Produces PCM samples from Opus-encoded audio. - /// PCM samples to decode. - /// Offset of the frame in input. - /// Buffer to store the decoded frame. - public unsafe int DecodeFrame(byte[] input, int inputOffset, int inputCount, byte[] output) - { - int result = 0; - fixed (byte* inPtr = input) - result = UnsafeNativeMethods.Decode(_ptr, inPtr + inputOffset, inputCount, output, SamplesPerFrame, 0); - - if (result < 0) - throw new Exception(((OpusError)result).ToString()); - return result; - } - - protected override void Dispose(bool disposing) - { - if (_ptr != IntPtr.Zero) - { - UnsafeNativeMethods.DestroyDecoder(_ptr); - _ptr = IntPtr.Zero; - } - } - } -} \ No newline at end of file diff --git a/src/Discord.Net.Audio/Opus/OpusEncoder.cs b/src/Discord.Net.Audio/Opus/OpusEncoder.cs deleted file mode 100644 index be0623c6b..000000000 --- a/src/Discord.Net.Audio/Opus/OpusEncoder.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; - -namespace Discord.Audio.Opus -{ - internal class OpusEncoder : OpusConverter - { - /// Gets the bit rate in kbit/s. - public int? BitRate { get; } - /// Gets the coding mode of the encoder. - public OpusApplication Application { get; } - - /// Creates a new Opus encoder. - /// Sampling rate of the input signal (Hz). Supported Values: 8000, 12000, 16000, 24000, or 48000 - /// Number of channels in input signal. Supported Values: 1 or 2 - /// Length, in milliseconds, that each frame takes. Supported Values: 2.5, 5, 10, 20, 40, 60 - /// Bitrate (kbit/s) used for this encoder. Supported Values: 1-512. Null will use the recommended bitrate. - /// Coding mode. - public OpusEncoder(int samplingRate, int channels, int frameLength, int? bitrate, OpusApplication application) - : base(samplingRate, channels, frameLength) - { - if (bitrate != null && (bitrate < 1 || bitrate > AudioServiceConfig.MaxBitrate)) - throw new ArgumentOutOfRangeException(nameof(bitrate)); - - BitRate = bitrate; - Application = application; - - OpusError error; - _ptr = UnsafeNativeMethods.CreateEncoder(samplingRate, channels, (int)application, out error); - if (error != OpusError.OK) - throw new InvalidOperationException($"Error occured while creating encoder: {error}"); - - SetForwardErrorCorrection(true); - if (bitrate != null) - SetBitrate(bitrate.Value); - } - - /// Produces Opus encoded audio from PCM samples. - /// PCM samples to encode. - /// Offset of the frame in pcmSamples. - /// Buffer to store the encoded frame. - /// Length of the frame contained in outputBuffer. - public unsafe int EncodeFrame(byte[] input, int inputOffset, byte[] output) - { - int result = 0; - fixed (byte* inPtr = input) - result = UnsafeNativeMethods.Encode(_ptr, inPtr + inputOffset, SamplesPerFrame, output, output.Length); - - if (result < 0) - throw new Exception(((OpusError)result).ToString()); - return result; - } - - /// Gets or sets whether Forward Error Correction is enabled. - public void SetForwardErrorCorrection(bool value) - { - var result = UnsafeNativeMethods.EncoderCtl(_ptr, Ctl.SetInbandFECRequest, value ? 1 : 0); - if (result < 0) - throw new Exception(((OpusError)result).ToString()); - } - - /// Gets or sets whether Forward Error Correction is enabled. - public void SetBitrate(int value) - { - var result = UnsafeNativeMethods.EncoderCtl(_ptr, Ctl.SetBitrateRequest, value * 1000); - if (result < 0) - throw new Exception(((OpusError)result).ToString()); - } - - protected override void Dispose(bool disposing) - { - if (_ptr != IntPtr.Zero) - { - UnsafeNativeMethods.DestroyEncoder(_ptr); - _ptr = IntPtr.Zero; - } - } - } -} \ No newline at end of file diff --git a/src/Discord.Net.Audio/Sodium/SecretBox.cs b/src/Discord.Net.Audio/Sodium/SecretBox.cs deleted file mode 100644 index f73093316..000000000 --- a/src/Discord.Net.Audio/Sodium/SecretBox.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Runtime.InteropServices; -#if NET45 -using System.Security; -#endif - -namespace Discord.Audio.Sodium -{ - internal unsafe static class SecretBox - { -#if NET45 - [SuppressUnmanagedCodeSecurity] -#endif - private static class SafeNativeMethods - { - [DllImport("libsodium", EntryPoint = "crypto_secretbox_easy", CallingConvention = CallingConvention.Cdecl)] - public static extern int SecretBoxEasy(byte* output, byte[] input, long inputLength, byte[] nonce, byte[] secret); - [DllImport("libsodium", EntryPoint = "crypto_secretbox_open_easy", CallingConvention = CallingConvention.Cdecl)] - public static extern int SecretBoxOpenEasy(byte[] output, byte* input, long inputLength, byte[] nonce, byte[] secret); - } - - public static int Encrypt(byte[] input, long inputLength, byte[] output, int outputOffset, byte[] nonce, byte[] secret) - { - fixed (byte* outPtr = output) - return SafeNativeMethods.SecretBoxEasy(outPtr + outputOffset, input, inputLength, nonce, secret); - } - public static int Decrypt(byte[] input, int inputOffset, long inputLength, byte[] output, byte[] nonce, byte[] secret) - { - fixed (byte* inPtr = input) - return SafeNativeMethods.SecretBoxOpenEasy(output, inPtr + inputLength, inputLength, nonce, secret); - } - } -} diff --git a/src/Discord.Net.Audio/UserIsTalkingEventArgs.cs b/src/Discord.Net.Audio/UserIsTalkingEventArgs.cs deleted file mode 100644 index 698f44d4c..000000000 --- a/src/Discord.Net.Audio/UserIsTalkingEventArgs.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Discord -{ - public class UserIsSpeakingEventArgs : UserEventArgs - { - public bool IsSpeaking { get; } - - public UserIsSpeakingEventArgs(User user, bool isSpeaking) - : base(user) - { - IsSpeaking = isSpeaking; - } - } -} diff --git a/src/Discord.Net.Audio/VirtualClient.cs b/src/Discord.Net.Audio/VirtualClient.cs deleted file mode 100644 index 9c8100e47..000000000 --- a/src/Discord.Net.Audio/VirtualClient.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Audio -{ - internal class VirtualClient : IAudioClient - { - private readonly AudioClient _client; - - public Server Server { get; } - - public int Id => 0; - public string SessionId => _client.Server == Server ? _client.SessionId : null; - - public ConnectionState State => _client.Server == Server ? _client.State : ConnectionState.Disconnected; - public VoiceChannel Channel => _client.Server == Server ? _client.Channel : null; - public CancellationToken CancelToken => _client.Server == Server ? _client.CancelToken : CancellationToken.None; - - public RestClient ClientAPI => _client.Server == Server ? _client.ClientAPI : null; - public GatewaySocket GatewaySocket => _client.Server == Server ? _client.GatewaySocket : null; - public VoiceSocket VoiceSocket => _client.Server == Server ? _client.VoiceSocket : null; - - public VirtualClient(AudioClient client, Server server) - { - _client = client; - Server = server; - } - - public Task Disconnect() => _client.Service.Leave(Server); - public Task Join(VoiceChannel channel) => _client.Join(channel); - - public void Send(byte[] data, int offset, int count) => _client.Send(data, offset, count); - public void Clear() => _client.Clear(); - public void Wait() => _client.Wait(); - } -} diff --git a/src/Discord.Net.Audio/VoiceBuffer.cs b/src/Discord.Net.Audio/VoiceBuffer.cs deleted file mode 100644 index 054ab81a0..000000000 --- a/src/Discord.Net.Audio/VoiceBuffer.cs +++ /dev/null @@ -1,140 +0,0 @@ -using Nito.AsyncEx; -using System; -using System.Threading; - -namespace Discord.Audio -{ - internal class VoiceBuffer - { - private readonly int _frameSize, _frameCount, _bufferSize; - private readonly byte[] _buffer; - private readonly byte[] _blankFrame; - private ushort _readCursor, _writeCursor; - private ManualResetEventSlim _notOverflowEvent; - private bool _isClearing; - private AsyncLock _lock; - - public int FrameSize => _frameSize; - public int FrameCount => _frameCount; - public ushort ReadPos => _readCursor; - public ushort WritePos => _writeCursor; - - public VoiceBuffer(int frameCount, int frameSize) - { - _frameSize = frameSize; - _frameCount = frameCount; - _bufferSize = _frameSize * _frameCount; - _readCursor = 0; - _writeCursor = 0; - _buffer = new byte[_bufferSize]; - _blankFrame = new byte[_frameSize]; - _notOverflowEvent = new ManualResetEventSlim(); //Notifies when an overflow is solved - _lock = new AsyncLock(); - } - - public void Push(byte[] buffer, int offset, int count, CancellationToken cancelToken) - { - if (cancelToken.IsCancellationRequested) - throw new OperationCanceledException("Client is disconnected.", cancelToken); - - int wholeFrames = count / _frameSize; - int expectedBytes = wholeFrames * _frameSize; - int lastFrameSize = count - expectedBytes; - - using (_lock.Lock()) - { - for (int i = 0, pos = offset; i <= wholeFrames; i++, pos += _frameSize) - { - //If the read cursor is in the next position, wait for it to move. - ushort nextPosition = _writeCursor; - AdvanceCursorPos(ref nextPosition); - if (_readCursor == nextPosition) - { - _notOverflowEvent.Reset(); - try - { - _notOverflowEvent.Wait(cancelToken); - } - catch (OperationCanceledException ex) - { - throw new OperationCanceledException("Client is disconnected.", ex, cancelToken); - } - } - - if (i == wholeFrames) - { - //If there are no partial frames, skip this step - if (lastFrameSize == 0) - break; - - //Copy partial frame - Buffer.BlockCopy(buffer, pos, _buffer, _writeCursor * _frameSize, lastFrameSize); - - //Wipe the end of the buffer - Buffer.BlockCopy(_blankFrame, 0, _buffer, _writeCursor * _frameSize + lastFrameSize, _frameSize - lastFrameSize); - } - else - { - //Copy full frame - Buffer.BlockCopy(buffer, pos, _buffer, _writeCursor * _frameSize, _frameSize); - } - - //Advance the write cursor to the next position - AdvanceCursorPos(ref _writeCursor); - } - } - } - - public bool Pop(byte[] buffer) - { - //using (_lock.Lock()) - //{ - if (_writeCursor == _readCursor) - { - _notOverflowEvent.Set(); - return false; - } - - bool isClearing = _isClearing; - if (!isClearing) - Buffer.BlockCopy(_buffer, _readCursor * _frameSize, buffer, 0, _frameSize); - - //Advance the read cursor to the next position - AdvanceCursorPos(ref _readCursor); - _notOverflowEvent.Set(); - return !isClearing; - //} - } - - public void Clear(CancellationToken cancelToken) - { - using (_lock.Lock()) - { - _isClearing = true; - for (int i = 0; i < _frameCount; i++) - Buffer.BlockCopy(_blankFrame, 0, _buffer, i * _frameCount, i++); - - _writeCursor = 0; - _readCursor = 0; - _isClearing = false; - } - } - - public void Wait(CancellationToken cancelToken) - { - while (true) - { - _notOverflowEvent.Wait(cancelToken); - if (_writeCursor == _readCursor) - break; - } - } - - private void AdvanceCursorPos(ref ushort pos) - { - pos++; - if (pos == _frameCount) - pos = 0; - } - } -} \ No newline at end of file diff --git a/src/Discord.Net.Audio/VoiceDisconnectedEventArgs.cs b/src/Discord.Net.Audio/VoiceDisconnectedEventArgs.cs deleted file mode 100644 index 4f46abde2..000000000 --- a/src/Discord.Net.Audio/VoiceDisconnectedEventArgs.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Discord -{ - public class VoiceDisconnectedEventArgs : DisconnectedEventArgs - { - public ulong ServerId { get; } - - public VoiceDisconnectedEventArgs(ulong serverId, bool wasUnexpected, Exception ex) - : base(wasUnexpected, ex) - { - ServerId = serverId; - } - } -} diff --git a/src/Discord.Net.Audio/libsodium.dll b/src/Discord.Net.Audio/libsodium.dll deleted file mode 100644 index a9ab5078e7b8537c60a0f032e6e336b51a8f67e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 KcmV+b0RR6000031 literal 492032 zcmV+W{{#R{T95z(0000400030{{R5E000000000$0000000000000000000000000 z000000000000000000000RR9FAG!_zvMXX>K4yPg5XmZ)9aI4Gjt;0000000030N5lQQCatc!Catc!CatcrUOuk9 zCatbsf2^;$Catbsf3B~-Catbsf2gmrCatbsf2psqCatb!*=DZ3Catc!CakWDCatbX zf2FS=CatbXf32^&CatbXe^RcxCatbXf3L5)CatbgX=7-+Cataj000000000000000 z0000`MF0Ry0R;fos|Hp8000000002s00JQk0S*8FtOfu8)Bpeg0002Xum%7C5C8xG zzy<&S000mG5C8xG0ssI800000000060000000000zy|;T1ONa40000306+l%01yBG z5C8xG01yBG5C8xG0000G0001x$_4=BFaQ8_`vw4v00000pa%fp0RR910000000000 z0000000000um=E?2><|a#s&az0000000000000000000000000000000002s#s&aD z000000000000000zy<)w0000000000000000000000000000000000kbY*yS0000M zss;c65C8xGtOfu81ONa400000000000000W003Yva%5q2VE_P@KmY&$zy<&SLI3~& zum%7C00000000000000$002NPWMOn+0002kg#Z8m5C;GNga7~l@&*6^0000000000 z0000$006))a&vNH0002s0RR91pa%c|0ssI2b_W0e00000000000000$002NPa%F69 zV*mh@2><{9um=DD3IG5Acn1Ig00000000000000$002S&00000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000000000000000000010i|m8s_<`*F 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

+P$cu%{{{R0og~0y*{{xLY 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 zoFuRT000jt!DbJ0*a&71euN|-0{{RID8XhAbJz@K4}OFsBm)2d4=J1^fCT^m4=9`@ z-~<2w4=BTC4}QEP7y|$RW)E}N2xbp{ge0H<000jt!)6b2-vnk4e!L_c0{{RID10O! z4=9u*5CZ@JW)JVYB;W!70A>$&G?q(0~q$KbH000jtoFtF{003qW@0=u%0ssJuO&AX;q$I!u000ju zoFtF{000jtq$H34000juq$J=3000jtWF&BA5AUQTumJ!74=H3Ma1SV?Bp?L<01qf! zByeUA@8SZ$0000ngd|7>004`Di~s-tjf^Bf z1pojsgd|J_000juv?LG(000jutR(OR000juoFvc$000juq$D5(000juq$IEe000ju zlq3KJ000juj3mGW008L0vjG5$O&Deme(*DakN^MxiG(B&1pokxfs_CM05OCl6a@eP zi-DK`001$BBp3w%0E>Z~0001uj3f{R001$BBpd|*0O)$N0RW3l7-kQC=re(!0001q zge33;004`DqyPW_F@z-a1ONbwfv5lg05OCl_yhm|i-D{F0051QB=7_P05OCl`~(01 z=rgkc0EaN0000nge2qy004`DxBvhE zF@z-O1ONbwfxG|!0F8_!-~<2wF@z-S1ONc&ah0000nge2Gm004`D%m4rYjf^DF1ONarge2Sq008KnvH<{# zO&AX-gd`vZ003qWe!w$<&;S4ciG(Du1ONbwfz$v105OClv;+VEi-Fhx001$BB)9|s z0E>a#0001uj3lrG001$BB)kLw0O(G#0RW3l7-kQC&@+MH0001qgd_k3004`Db20000nge1fS004`D_y7O^F@z+@1ONbwf&2gf0F8_!zytsQ zF@z+{1ONc&z_9@U4=Ai8umk`AW)JVIBme~f01qgXBoGAv01qgnBtQiK01qgPB=7_P z0A>&G><=ikB;W)90A>&G$`2__BybNX*$*g8BybNX{bmpEyd=N`003qW@API5@0=t6 z1pokM5AV-r5AWU&DNH1AW)JVQB)|j!01qh5W)JVQB+vu^01qg|W)JU#B+vu^0A>&G z$`2{5B!B<_0A>&G@((CfBybNX=?^KqB#;0A0A>&G>JKSgBw%I_@AwZXbR-ZDDMTbd z4=GF}AP*>vB!B<_0A>&G&}I+s&JQTVW)JVg4=CSe5AWR%DEDR$+xTV=>+laK1Ge>;bsr-$PXw)BoJl~+u3Fh?}Q{k1pokM58KcWD1;<{0001H5AQ@IU}g{R;twfg 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�RWAZ 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 zlq6sU008I?I{^TVlq4_(008JBI{^TVlq4Vp0051QBrpX40O;>J0RWAZBwz&q0O$id z0RWAZBya@)0F8_!AO!#b=008Jl zIspKUlq8S^0051QB;W)90O&J10RWAZBrpX40F8_!00jU5=pZ@)0F8_!Km`B*=oC5u z0F9I+AO!#bjf^C)1ONc&0XhKyjf^DV1ONc&^*I3mjg%z71ONbyj3h7x008JhIspKU zlq3)Z0051QBp?L<0O&6|0RWAZB+vu^0F8_!Fa-br=)5@r0F9I+@B{z=jf^B91pol( zsW|}vjg%yC1pokzj3j^s008LrIROBTlq6sU008KUIROBTlq4_(008KoIROBTlq4Vp z0051QBrpX40O)Hu0RWAZBwz&q0O)@?0RWAZBya@)0F8_!AO!#b=xjLw0F9I+Fa-br z=s-CE0F9I+fCT^mjf^BP1pol(Eja-Ijg%x%1pokzj3kf+008KEIROBTlq8@9008I? zIROBTlqApu008JBIROBTlqB#30051QB+vu^0O;>H0RWAZB%lQV0O$ib0RWAZBv1ta z0F8_!@B{z==008K2 zHvs^Rlq9eO0051QBoGAv0O(sc0RWAZB=7_P0F8_!umk`A=twsK0E^L$j3m$m008JZ zHvs^RlqBE;0051QB=7_P0O%(-0RWAZB(MYk0F8_!-~<2w=oB{r0E^L$j3fXB008I) zHvs^Plq8S=0051QBtQiK0O<2J0RW4XB$NRF0F8_!5Cs4L=-@U10E?6)`~d&}jf^DF z1ONc&%{Bo5i`008I$ zHUR*QlqBE;0051QBp?L<0O(IP0RXxI0002!g*X8Kjg%z71ONbyj3gih008LHH30y+ zSj7eq=;$>80E^L$j3mGW008K^H30y+0RR91jf^B91pol(2{{1(jg%xH1pokzj3nR$ z008KgH30yPlqApu0051QBp?L<0O;d20RXxI0002!88`s|jg%w+1pokzj3gih008J_ zH30y+Sj7eq=zKK+0E^L$j3fXB008JtH30y+0RR91jf^B91pol(oj3sijg%xH1pokz zj3m$m008JJH30yPlq5g}0051QBp?L<0O)r$0RXxI0002!tv3Mxjg%x11pokzj3gih z008LvGywp*Sj7eq=nypl0E^L$j3f{R008LXGywp*0RR91jf^B91pol(F*pGLjg%xH z1pokzj3ht>008K|GywpOlqA3e0051QBp?L<0O$)f0RXxJ0002!K{o*ajg%y?1ONby zj3gih008KYGywp*2*m~v=%h3O0E^L$j3lrG008KAGywp*0ssI2jf^B91pol(#Ww)} zjg%xH1pokzj3mGW008JxGywpOlqBE;0051QBp?L<0O+4I0RXxJ0002!)iwbDjg%zt z1ONbyj3gih008JBGywp*2*m~v=r}Y10E^L$j3n>`008I;Gywp*0ssI2jf^B91pol( zSvLUyjg%xH1pokzj3nR$008LbGXVgNlq3)Z0051QBp?L<0O&I`0RXxJ0002!X*K}> zjg%w+1pokzj3gih008K=GXVg)2*m~v=*%+#0E^L$j3fXB008KoGXVg)0ssI2jf^B9 z1pol(?KS}bjg%xH1pokzj3f{R008KEGXVgNlq5g}0051QBp?L<0O-dv0RXxJ0002! z{WSpqjg%zN1ONbyj3gih008JpGXVg)2*m~v=wLGe0E^L$j3m$m008JRGXVg)0ssI2 zjf^B91pol(fi?jEjg%xH1pokzj3ht>008I?GXVgNlq3KJ0051QBp?L<0O(sY0RXxL z0002!ku?DTjg%y?1ONbyj3gih008LTG64X(_{0Vf==3rH0E^L$j3lrG008L5G64X( z1ONa4jf^B91pol(6*d6?jg%xH1pokzj3fXB008KsG64XMlqApu0051QBp?L<0O;>B z0RXxL0002!B{cy6jg%zt1ONbyj3gih008K6G64X(_{0Vf=!h}_0E^L$j3n>`008J( zG64X(1ONa4jf^B91pol(sWkxrjg%xH1pokzj3m$m008JVG64XMlq3)Z0051QBp?L< z0O*4<0RXxL0002!xikR)jg%z71ONbyj3gih008I)G64X(_{0Vf=o~Tu0E^L$j3mGW z008LjF#!O&1ONa4jf^B91pol(Jv9LUjg%xH1pokzj3f{R008L9F#!OLlq5g}0051Q zBp?L<0O%Jo0RXxL0002!O*8=jjg%zd1ONbyj3gih008KkF#!O&_{0Vf=&&&X0E^L$ zj3nR$008KMF#!O&1ONa4jf^B91pol((KG=7jg%xH1pokzj3ht>008J-F#!OD{||?@ zQUCvP41xZD0000FgRW8k|BZ|!yafON=zK5%0E^a(&kwB11i|S91JI3(B)kOx0O*4- z0RRsWgd{)(004`|jf^D71pojG#}5&NB*+B-01ps^BoGAv01pv_B-jN201ps^B+vu^ z01pv_BAC|Oa=e|UtTlJ=o-fY0E^{a!;Oq2yafON=#(!3 z0F8_!yafONjZg^ar7r;hi-aW50000F5QHQ^1pojK5daSmgd`9J000jWKoAcQge1@e z000jWKp+nggd_k3000jWKrjywge2eu000jWKtK-=ge1TO000jWKu`}5ge33;000jW zKwu9Lge0&8000jWKyWj_i;N^p1^@tGUNg+-gT?{?i{)Lz%*@Qp%*@Qp%vFo*gXHjm z>}Uo60HFjB2M{yFiG(C%1^@tyMF@?IBv=Ii0EvVoLhqd<6gif#FqERaG&JBtQWG0A>$<$BC3AbOitax&Z(H z0Evtwcm)6ejf^C41poju$BDEga0LJWB~?{bRWtaBgd}_g004=+Bya)%0O+qV0RW4H zBya@)0F8_!a0LJWF@z+b1polL0RR91i-aU}1pojsge0T|004`GBzOe?05OCls09E3 zi-aV61pojKD1;;c1^@stge0s5000jugd}hU008KgFaZD$D2yZk1^@tyv?Oo^000jt z!DbJB$Yu|7*aV4$Bp?F-05kB5lq7To004pJRaI40F|;Hg0{{Svj3jsk003qWe!veX z!DbJ0*a(TVBya@)0E@IFAOipZGth~IBwzvn0DtRf)7DAO-*cGslaxBwzvn03}sbRaGGJta0LJW zx&Z(H0ExULoCN>?=qxV*01qgHBmf2g0F8_!a0LJWW)FVAx&Z(H01qgHBwz&q05gOn za0LJWiG(Cj0{{Svgd|i3001+DByhqTm}FDGlV331pokvgd{Ko000jugd}hU008LnEdchqbOitaF@z*!1pokxgd}(c001$BBxnTy0E>hqd<6gi4=98rAO-*c zF@z*+1pojKDTE|&1pol({VV|hi?k$g1pokxlq7To001+zB(MPh05g;%-~j*tf#x$a zGc${fBzOe?0DhqU;+RDGlV2`1pokvgd|`B004`GB+vl>05gOncm)6eiG(E30RRAt zgd{)%001+DBzy$`0EvVoKmz~(4=IEsa0LJW=hq5CQ-Ijf^C41pojugd}hU z006oI0000FD1;<{1pokvgd`9G004`GBrpR205gOnbOitaiG(CD0{{Svge2et001+D zBzOe?0EvVo-~#{vi-aWL1ONatgd}_g004=EB;W)901qjIBya@)0O;E)0RW4%Bya@) z0E?6)bOitai;N_A1pokxgd}_g001+zB#;FF05g;%lm!3)f#x$aGcz-cB$x#N0DlByhqFa!VqGscOuBzy$` z0ExULPy+w}iM%9G1^@twgd{Ko004=EBwPjn0O->x0RW4HBya@)0F8_!a0LJWF@z*w z1polL1ONa4i-aU}1pojsgd}7I004`GBzOe?05OClXaxWOi-aV61pojKD1;=C1pojs zgd}VQ000jugd}hU008K^C;(ybOitaB@Yh|4~vu}cm)6e zi?k$s1pojuj3nRz004`;Bya)%05kV9lq5g_004pE4-XFyiG(C@1pojsge0&5004pF z4-XFyi-aVw0RRAj<_`}K4~c{%Fa`hsGyaQ&B;Wx605idfj3jgg004=EBs2y90F8_! za0LJWi-aUV0RR9q!ikh5cm)6ex�K0Ex6Dd<6giiG(CL1^@twyd*pZ008K|C;hqbOitaF@z+P1pokxgd}(c001$BB$x#N z0E>hqd<6gi4=98rPzC@1F@z+X1pojKDTE|&1pol(r6&OZihqd<6giGn6Ex1poju$1{v1s09E3f#MGj4-bp9Bya@)0D<8T4-XGBv?QPf z001Qq4-XG9lq94D004pJ4-XFyF^nXr1poju_%XC3palQ`iIgOC1polL1ONa4iHsz8 z1pokzj3jUc004=!Bya@)0EvVod<6giiM%AN1pol($tM8-i-aUl0{{Sxj3jUc001+D zBya@)0J;PK000jtgd~6k004=EBv1wb0E>hqkO2SyGlV2`1pokvgd|i3004`GB)|ax z05gOncm)6eiG(Cr1^@tygd{Ko001+DBzy$`0EvVoTm}FD4=IEsa0LJW=#(Y_0E>hq za0LJWi;N_61pokxlq7fs001+DBp?F-05gmvU;+RDGn6FI0RRAtv?P25004`;BtQcI z03{C(4-YYfBp?F-0D<8T4-XHCgd}hU001-hi-aT~0{{Sl;tvlG4~c{%AO-*cf#wen z4-bokBwzvn05kqG!HJ9{bOitaiG(C11^@t!j3jUc004`GB+vl>05igglq7fs006oK z0001qv?P25004=EBq#;|0ExULECv7o=$Iw}0E>hqa0LJWjf^C41pojsgd~6k006oK z0001sgd}tY001$BB!mS30E>hqcm)6eF@z+D1pokxgd}_g000jtgd|`E001$BB#Z?B z01qjIBya@)0O)@u0RW4HBya@)05gOn5CQ-Ii;N_61pojg4-XFyF@z)#0ssIrj3h7v z004`WBzOe?0D<8T4-XHEv?P25001+TB;W%80E@gN-~<2wf#MGj4-biiBya@)05kWC zgd`9G004pJ4-XFyiG(CT1^@sv{)>bpFarPpGr@_BByiIgOG1polL1ONa4iL@kq1pokvgd|7?004=+BuoYX0O*4y0RW4HBya@) z05OClU4-kYTAO-*c4-r664-kYTpalQ`4-r6M4-kYT zFa`hs4-r6c==3200F8_!fCT^m=;$E<0F8_!PzC@1=-eRz0F8_!kOcq$=+Gen0F8_! zKn4H+=)@rb0F8_!AO-*c=(r&P0F8_!palQ`=&T_D0F8_!Fa`hs=%6710E?6)palQ` zi-aT~1^@tyv?Qbj001+>i;N^F1^@tyyd;1H004(yPzC@1GtY@s zByfwABv=Lj0ExULpa1{>i@YR+1pokvj3jUY004`OBvb|f05i{tyd<~)004`;B!~q7 z05jK#lq84&004_rBtSEiBwz&q0Etv2K#7zjAO-*ci(ym<0d; zGmIo?1pokxyd=B;001+zB)k9s0EvVo&;bAdiA*FoGejgfi;N_k1pojuj3jIY004=U zBwzvn0Ev_&palQ`ihqFa`hsGth~IBme~f0E>hq zGzI_wGx&*wB;Wx60E>hqI0gU!F+?OdiA*FEi;N^t0ssIrOe7SEgd{)#004`GBs>NH z05L=)6p4f+Kmq^&i-aUV1^@sv&@+@Ipa1{>iG(B&0ssJugd{`;001-iiIgM&0RRAr zyd=B;004`WB)k9s05g;%xBvhEi@YRE1^@std?XZ!lq9?W004=EBrpX40E>hqNCp4^ zF+?Odi&P{yGn6Fw0001qv?Le>004=!B%}oZ0E=`aSTVFDKmh;%i*zJ#F|;H=0ssJs zj3iJ3004=MB&-Dh0Ei-aW10{{Stgd`9F004=EB=iLU0E>hqKmh;%GlV1{1pojsj3l@K z004=EBzOb>0E>hqKmq^&GslUvBme>c0E@IFhyefqGqfZ?0RRArgd~sx004`GBzOb> z0EvVo7y$qPiG(Eh1pokxgd~sx004=EB&Y)b0EvVo`~?62i-aU_0RRArv?PcD004`$ zBwzsm05h~CKmq^&iM%A>1ONbwyd(eu001+*B)9+o0Ex6DU;zLCi}EqFB%lBQ05gOn zpa1{>iZR001+*Bwzsm0ExULAOipZi@YRo0{{REyd-b} z004`OBv1kX05gmvYy|)S35+DD0{{RID3m1d1pojKD2yb)1pokvyd-b~000jt!Hc{k zi~|4w3%n#y0{{Styd;bR004`;B+vi=013P#kOKe!i@YQ#0ssIDyd*#a004=+Bq#y^ z0E>hq5CQ-IGlV2?0RRAtlq6sR001+TBwz&q0EvtwfC2yji?k#d1pojuv?OE&003qW ze#vGJe%EFXbJzrlj3l4}001-j4=I!+00sa6iM%9`0RRAtyd(q$003qWe!&kY!DbJ0 z*a!)fBrpL005kcCj3lrE004=+B)|ax0E@gN2nGNEW)FVB3A7{-0RRAI4|CZJGx=r@ zevBmW0ssJsyd*FL004`;Bn$=s05iNK@B#n;iM%9G0RRAI4}RB)gd|V|004`GBp?L< z05gOnhyefqBl?NFBwzyo01qjYB;W-A0E@gNhq&;bAdGlV2) z1pojEgd`XN004=+B=7?O0E@gN=mh`(iHsy50ssIb_=}7rpaK8@Ba9?)0ssJsydhq00961GlV2y1pokxlq66D004=M zB(MSi03*^001M5BtQcI0E>Ji6f?XeYy|)SiHs!h0ssJuj3j^p001+LBtQcI z03nPdPyqk{i;N_^0000pj3i_Q001+zBv1nY0EvtwyaWIMi%cXqGmIo?1pojcv?Ra* z004=+Bme^d05Oy#FaZDnF_a{50{{Stgd`9H004`GBya=(03*SRv?NRf001$BBp3kz z05OClkOKe!BeW#E1ONbwge2er001+DB)9+o0Evtw&;tMfi;N^70{{Rc&oQ(l5CH%H zi@YRY0ssIrd?Y|Ij3lT7001$JBq#y^0E>(y00jU5GmIpl0000nv?PoJ004{diM%Ax z0ssJuyd)R}001+*B)|Xw0ExUL-~s>ui@YSz0RR9qd?Z+jyd-D@004`;Bv1kX05g0f zaEZJmumJ!7i@YSz0ssJslqApq004{83;KzKB)|j!0E>hqKmh;%GlV4g0001qyd;1C z004`;B;W!701N(!j3h7u004`OBtQZH05gmvAOQdXiM%A30001syd-D@000a4iIgPJ z0001qyd>ZN004`;B(MPh0EvVo&;$SgiHsyL0{{Rcgd}JL000a5F@z)_0ssJugd{Kl z001+DB#;3B03(bfumJ!7F^nYe0ssJsgd{Kl004`GBoF}r05gOnzySaNi;N^N1ONar zj3gKV004`OB!B<_05gmvkO2SyiG(B&0RRAtgd}hS001+DBwzyo0EvVoa037Ui-aT~ z1ONargd`{e001$BB=7uF|;JG0ssJuv?TBY004=+B%A;M0E@gNPyqk{ zF}x(40000nge05*004`GBme;b03(DXZ~*`SiG(E30001sge1HG001L|Bme>c0EvVo zfC2yji$o+iBZMS~0RRArj3j^n004`OB$xmI05gmvzySaNiHsze0001sj3h7w001$J zB;Wu50E>(yU;_XEiG(Cz0{{SvL?jd=gd|`A004=EB=7?O0E>hq5CQ-IBZMSi1poje zlqAps001$RB%lHS05QBIr~?21iiG(D;0RRAtge1TK001L|B)9+o03*C4_y7O^iG(CD1ONbwL?m#D zyd+Qo004`;BrpL005iNK&;S4ci(yKmq^&3ydUC0ssJsyd)R_004`;B&Y)b05iNK z@B;t05OCl zAOZjYiIgOq0001slq4Vo001$RB%lHS0E?6)i~|4wGn6C{0RRAryd;nV004`;Bq#y^ z05iNKkO2SyiIgOO0ssJulq7%v001GBBrpL00E?6)m;e9(A(SK#0RRAryd)?B004`; zBv1hW05QBI-~a#si@YR|0{{Rsyd)R_004`WB;Wu503nnl7y$qPi@004`OB+vi=03nPd@Bsh-i;N`j0000Zj3j^p004(ypacK_Ba9?40RRArlq47d004`WB&Y)b05g;%C;|WgA(SMz1ONbwlq8@6004=M zB%lNU0E@^Yj3f{N001$RB%lNU0EvVom;?X-i-aV&1ONbuj3k%@001+_iZN001MDB%lHS05Mb~U@?>=fB*mhBeW#20ssJuyd>}d001$xB$xmI z05krJv?R;|001NYikS~r~v=~AxtD7iM%B60001sd?a8q zyd=;7004=6Bw#aCBw!}g001+zB=7(L05i`sL?jpwD1;=S1pojK zD2yZ^1^@sfv?Le>004ZP004`8Bp4yQBxnQx0E@gNumJ!7BYY$viBu$Ti&P{)F_a|G z0ssJulqA3a001$RB;W!70E<*4STU3&XaoQNGkhd)i$<$cwZj@Bjb+Gqfa_0000pgd_j~004=EBv1hW0E>hq)CB+l zGlV3(0001qgd`XR004`GB-jN205e1+IEjQLZ~_1Ti-aWH1pojuL?jf6gd|`B004`G zB!C0}05gOnAOrvaiG(D81ONbwge0f|001+DB)9|s0E@gNyafONGrS~h1pokvge0f| z004_bBw#ayB!B<_0Et8-V2P9@%mM%ai{*B%lNU05gmv zfB*mhiIgO80ssJulqApq004=!Bv1hW0E>hqPyqk{GlV4Y0ssIplqB#1004{8Ba|dy z1pokvlqApq004`WBoG4t03(znfB*mhiIgM|0{{Svlq9?a001MDB$xmI0E@IF7zF?T zBeW#U0ssIrv?L$`004=UB)kLw0E?6)00RI3Ba|eZ0001qlq3KH004`WBme;b03(zn zpacK_iIgM&0RRAtlq9?W001MDB$xyM0Ev_&yZ`_Ii&P{yBa|c{1ONbugd|V_004`G zBwzyo05OClC;|Wgi-aVY1ONatgd~^%004Ji z6fwLc00RI3iHs!B0RR9aj3jIY004=EBrpU305ka`gd}JM001#WBsejYB+vo?0Ev7g z6pOSZPyqk{F?1wAF|;HA0RRAtj3gie001$JB;W!705OatyaWIMi?k$A0{{Rcv?Q(y zkO2SyF+?PABhNFuBme{e05L=)6pNH3@B;t}h001$(B#;6C z0Ex6D%mV-bi@YSv0{{Rcyd>}d004`$B(MVj03&oHV2QjW%mV-bi@YRw1ONadd?Xl& zyd-!8004`;B#;6C03&=PAc?djumb=9i?k%*0{{Rcv?TBW001+zB(MVj0ExULkOBYz zi@YQd1ONadyd=y5004=+BoG7u0E@gN00aO4BfKPl1ONbuv?SmI004`$B+LT<05P;A z5Ci}Ki?k$o1ONarlqAdp004`WBwzyo05Oatcmx0diM%8L1ONarv?Kro004`;B=7_P z0E@IFPy+w}F|;JG0{{Rcydc03);{m;?X-i-aW50RR9age2eu004=+Bya=(0E@gNAOipZBfKP> z0001qv?Krm004`$Bya%$05P;APy_$~i?k#F0ssIplq3KG001$xBuoSV0E?6)fB*mh zF;paAikr7oB#j-F;pZViM%8r0{{SvyZ``z z|9>PP1ONabyd;PL004`$B!~e305Oathyefqi;N`j0RR9qj3l50004`;Bwzsm0E^Kx zR3u;{lq3KJ001MrB)9|s05P;Aa0CDVF}x%o0{{Rs_=~h8Kmz~(F|;Ib0RRAtv?R;| z001+zB$xyM0E>hqfCK;lGlV1{1ONbulqApq004`WBrpO103%c+V2P9@FaiJoiSG| z@Bsh-i_bGmBp@SBa|fY0RRArlq8@4004`W zB)9+o03(zn%mM%aiIgO`0001slqC27001MDB!C0}0Ev_&_y7O^iF}x%&0ssJuyd<~)001$xB)9+o05QBIzytsQi?k$A1ONatv?Q0Ex6Da0CDVi?k$=0ssIpv?L${004`GB+vu^05gOn zcmx0dGlV420{{Stlq4Vl004`WB+vi=05Oy#pa1{>i?k%50000pv?SmI001$JBp?9* z0E?6)FaiJoi;N_|1ONatlq9eN001+LB+LT<05g;%5CZ@JGmIp>1ONbuv?QPa004`$ zB)9+o05h~C5Ci}KiM%8*0{{Svyd-b|001+*B;W%80Ex6DxBvhEi?k&80000pv?Kro z004=+Bya%$0E@gN00IC2GrS}a1ONbuv?TZd004`$B=7_P05P;AAOQdXF|;IL0RRAt zv?QPa001+zB+vo?0ExUL00IC2i@YR=0RR9qyd(ew004=+B!~e30E@gNFarPpGrS}K z0{{Stv?QPa004`$B)9+o05h~C-~s>uiL@lR0001sv?TZd004=UBrpa50EvtwGzI_w ziG(CL1^@twyd*pZ001$BBya=(05h~CXaoQNF^nWk1ONarlq66D004`OBoG4t05Oat z&;kGeGmIpl0000nyd)q4004`WB)kLw05Oy#-~s>uGn6E_0001sgd_k1004`;BxnQx z0Ex6D_y7O^i?k#l0RR9qv?Q(yzyJUMiF71D zGejgniG(CT1^@tygd|J^004=!Bp?O=0E@IF00IC2GtP;OB)|Xw05gOnzyJUMiG(CX z1^@tygd}hT004=MBqRm^0EhqAOipZGejhCiG(Cf1^@tygd~Uo004=!Bvb|f0E=`aI5WnHOe9!|j3g)q004`O zBwzsm0EvVoSOx$9i$o+8GsuaIBwPjn05e1+aEpv200961GfX5vGn6F20001qL?jf6 zge05=004`GB+vo?05idfj3kf+000lRj3jRb004=EB%lQV0E>hq-~s>uGr}`;Bv^@r zB%}oZ05krJge0&5001*YBox8n2#JIwtOWo754MCPZUq1U3&@F-B$NdJ01vi=By9x% z0J@091`xsF2n)!Gv?Q1X000lRgd}VQ006<^2n)!GydRp`1polS=?I97 zBy9x%0Kw@9h>Rp|1polS=?I97ByR-(0F8_!UQ0F8_!PzC@1 z=ph3E0F8_!AO-*c=oJG20F8_!U0E>hqOa%Y{4-g0s5I}Gb5Ks^g5Lh4& z5MVG55NJRT5O7cr5O`o_4}QoGDTE|Y1pojKDTE{d1^@sLD8Vs=Bwz&q01qjQB+vx_ z01qjYBya@)01qjgB)|m#01qjoB=7|Q01qjwB(Mbl01qj&BoGDw01qj=B;W-A0EvVo z&;$<$T5T@Yy|)SiG(EF1pokM4}Q=wgd~6k004=E zBya@)0A>$$W)FVA4=BWD4|CWEW)E}R3^9Zxqy+!~iG(Ed1pokM4}QQ8D8*(E zbJzqige0g1004=EB=`jY0A>$<;4y?GtOWo7iG(El1pokM4}Rz|gd~s!004=EB(Mbl z0A>$$<=np82Bv1ta0E@gNC(yGzI_wW)FVA4=BcF4|CWEW)E}T3^T}ygd`LO z004=MBoG7u0E>(yI0gU!W)FVA4=BfG4|CWAGsuaABp3z&0Evtw-~j*ti;N^Z1^@tN z4}S17$ccm`90mXYiHsyb0RRAtj3iJ7003qWe)u!UiG(EJ1pokvj3ht;004`OBvb|f z0A>$$(yTm}FDW)FV&GsuaAB$<$cc<3FaiJoi;N^7 z1^@sv$ccm`00sa6W)FVA4=BNjj3mGW004`OBqRm^05iymgd_w8003qWbJz%G4}QRA z4|CZJiHs!B0{{Rs_=$uh2nGNEW)FVIiG(B!1^@sv@QsWl&;0F8_!zy$yR=v4p#0F8_!@C5(>=t%$p0F8_!umu1B=sf@d0F8_!5C#AM=rI5R z0F8_!-~|8x=p_IF0F8_!00sa6=otV30E>hq&;hq*aZLpF@z*&1pokxge2Sr001$BBy0r$0E>hqa0LJWF@z+51pokxgd}tY001$B zB!mS30E>hqcm)6eF@z+D1pokxgd}_g001$BB#Z?B0E>hqFarPpGlV3-1pokvgd{Kn z004`GB;W%805gOn#03BViG(EJ0{{Svge1@e001+DB*+B-0EvVo&;$Sgi-aUl0RR9q zge1%b004=EBv1hW0E>hq@C5(>F@z+b1pokxge3F@001$BB%}oZ0E>hq_yqs}F@z+j z1pokxge3e0001$BB&-Dh0E>hqumu1BF@z+L1pokxge0^D001$BB$NdJ0E>hqxCHhq00aO4GlV1%1^@twgd_k2004`GBoG7u05gOn z6b1kQiG(B&1ONbwge2er001+DBp3z&0EvVo-~j*ti-aUV0RR9qgd`jW004=EBtQWG z0E>hqKmq^&GlV4I1pokvgd{)$004`GBv1kX05gOn=+*rI0F8_!umu1B=*j&60F8_!5C#AM z=)L^_0F8_!-~|8x=&}6(0F8_!00sa6=%xJt0E>hq&;hq*aZLpF@z*&1pokxge2Sr001$BBy0r$0E>hqa0LJWF@z+51pokxgd}tY z001$BB!mS30E>hqcm)6eF@z+D1pokxgd}_g001$BB#Z?B0E>hqFarPpGlV3-1pokv zgd{Kn004`GB;W%805gOn#03BViG(EJ0{{Svge1@e001+DB*+B-0EvVo&;$Sgi-aUl z0RR9qge1%b004=EBv1hW0E>hq@C5(>F@z+b1pokxge3F@001$BB%}oZ0E>hq_yqs} zF@z+j1pokxge3e0001$BB&-Dh0E>hqumu1BF@z+L1pokxge0^D001$BB$NdJ0E>hq zxCHhq00aO4GlV1%1^@twgd_k2004`GBoG7u z05gOn6b1kQiG(B&1ONbwge2er001+DBp3z&0EvVo-~j*ti-aUV0RR9qgd`jW0051Q zB+vx_0EvVoKmh;%i-aUV0ssIrge2ev004=EBtQZH0E>hqPyzq|GlV4M1pojuyd($) z001+zBn$=s0EvVoPyzq|i-aVo0RR9qge2$%004=EB&Y!Z0E>hqFaiJoGlV4U1pokv zgd{Km004`GB)|j!05gOn00sa6iG(D;1ONbwge1@d001+DBm@Qk0EvVo&;tMf=!N?L z0F8_!a0LJW=z0490F8_!zy$yR=xzG|0F8_!@C5(>=wbT+0F8_!umu1B=vDgw0F8_! z5C#AM=t=tk0F8_!-~|8x=so)Y0F8_!00sa6=rQ{M0E>hq&;hq*aZLpF@z*&1pokxge2Sr001$BBy0r$0E>hqa0LJWF@z+51pokx zgd}tY001$BB!mS30E>hqcm)6eF@z+D1pokxgd}_g001$BB#Z?B0E>hqFarPpGlV3- z1pokvgd{))004`GB;W%805gOn#03BViG(CX1^@tyge1@e001+DB*+B-0EvVoNCp4^ zi-aUl0RR9qge1%b004=EBuoYX0E>hq@C5(>F@z+b1pokxge3F@001$BB%}oZ0E>hq z_yqs}F@z+j1pokxge3e0001$BB&-Dh0E>hqumu1BF@z+L1pokxge0^D001$BB$NdJ z0E>hqxCHhq00aO4GlV1%1^@twgd{Kq004=E zBme{e0E>hq5Ci}KGlV1*1^@twgd{Wu004=EBoG7u0E>hq-~j*tGlV1<1^@twgd{iy z004=EB;Wx60E>hqKmh;%GlV1@1^@sL5QHRP1pokvgd{u$004=EBtQWG0E>hqKmq^& zGlV4I1pokvgd{)$004=EBv1wb0E>hqPyzq|GlV4M1pokvgd|i3004=EBv1kX0E>hq zr~v=~GlV4Q1pokvgd|u7004=EB&Y!Z0E>hqzytsQGlV1n1^@twgd`va004`GB+vr@ z05gOn1O@;Ai;(V-GrS}S1^@svv?L4$000jW zfPer10E>(y00aO44-kYTfCT^miIgN<1^@u}(TThyC>X01ps^B%lQV01pv>umAu64-kYTkOcq$4-tUC0000F5QHQ!1^@tw zj3h7y004`OB;Wx601pv>&;S4c_t6g!gd|V~004=MBsc~D0E>(yKmq^&4-tUi0002@ z(GL)WBp?O=01pv>@Bjb+i-aT)1ONc{lq6sU008&U_mm`L1pol|lq6^c008%tBy0r$ z0QZz6fCT^m_mm`r1pol|lq84+008%tB#Z?B0EvVoGzI_wi-aUV0RRB^(20a3JO%&& zi-aUl0ssK_()ZAbj3iJ7004=EBvb|f0F8_!Uk0E?6)PzC@1 zi-aUF1^@tyv?Npp001+>i;N^V1^@tyyd;1H004NH0EvVofB*mhi-aUt1^@sv$caoO7>kS~Tm}FDGtr5RBme^d0E>(yKn4H+GtY@s zBw&k_BuEAT0ExULpa1{>i@YR+1pokvj3i(I004`OBt!-P05i{tyd<0e004`;B!~q7 z05jK#lq84&004_rBp@@CBwz&q0Etv2Ac>SDFa`hsi}d004`;B#Z?B0ExULFaZDni@YRE1^@twyd-b| z004`;BrpL005QBIZ~*`SiBu#QiIgNb1^@tyR3u(ys09E3 zGmIo?1pokxyd;hqAO-*cGth~IB)|j!0E>hq zBnAKgGx&*wBme{e0E>hqCiG(CD1pokxgd~&&001-iiIgPZ0001q zyd;i-aVM0{{Stgd`XN004=EB=iLU0E>hq5Ci}KGlV4I1ONarj3k@@ z004=EBxnQx0E>hq-~j*tGslUvB=7+M0E@IFhyefqGqfZS1ONbugd}hS004`GBxnQx z0EvVo5CH%HiG(Eh1pokxgd}hS004=EBp?C+0EvVo`~?62i-aU#0RRArv?PcD004`$ zBya%$05h~C-~j*tiM%B60{{Svyd>}e001+*B%A;M0Ex6DZ~*`Si}EqFB%lBQ05gOn zpa1{>i*zIyF|;J`0001slq4_#001*oBw&lQB!~e30EvVoFa!VqiG(DO0ssJsge1TP z004`}iG(D~0{{Stge1fT004`|GlV4Y0001qge1@b004=EB(MVj0EvVo$OQlZiM%8b z0ssJuyd-b|001-kiIgNT0RRAt$BDcoKmz~(i+m&)GkhdCiG(C50ssJsge1%b004_b zBp@?{B;Wu50EvVoZ~_1Ti@`I5B$xmI0EvVoPy+w}i$o+~Gejg5iG(D;0RRAtgd|`A z001+DBrpX40ExUL&;S4ci@YT80RR9qyd+=(004=+B)9|s0E@gNZ~*`SGrT150{{St zyd$$<*AFR_B;W-A0EvVofCK;li-aTq1poje`ZI(iXaxWO34|mN0RRAryd+=)004`; zB;*AE03-g1j3lT7004`OB;W!703(bfZ~_1TiM%900ssJuyd>xa001NSiHs!R0ssJu zj3m$k001M5Bv1nY0ExUL5CZ@Ji@YT41pojeyd;1E004=+B)kLw0E@gN&;S4cA-p80 z0{{Stj3m$k004`OB(MPh05iuUj3mGT001F`Bp3w%05g;%Z~_1TA(SNW1ONbwge2eq z001+DBwz&q0E?6)fCK;li+m&$BhWLvBy0r$0EvtwumJ!7i;N_I0ssIrj3mGT001G3 zB#;3B0E>(ym;e9(GmIo;1pojuv?Ndi004=MB&Y!Z0E(ypacK_BhN9kBp3kz0E>Ji zATzuq&;tMfF^nW20ssIpj3g)m004`OB)|j!05gmvpa1{>iM%AR0ssJuyd;1C001+* zBrpR205P;A%mV-bi|~oOB%lHS0E>Ji7&E*i00jU5iM%9u1ONbwd?a8qyd(ev004=+ zB=7hq7y$qPGlV1{ z1pokxyd;nT001$(B)9+o0E>(y7zF?TF^nV-0RRAtj3mGS001+LB=7_P0EvVo7y$qP zi-aVQ0ssIrgd|`C004=EB#;6C0E>hqyaWIMF@z*20ssIpge0&5001$BB)9+o0E>hq z-~a#sBZMSi0RRArge1@a004`GB$xmI03(DX@Bsh-iG(D80ssJuL?k#Pgd~Uo004=M zB)|Xw0E>(yyZ`_IGmIo41pokvj3m4O004`OBp3w%05Oat00961i;N^-0{{Stgd|`C z004_bBorfrBya%$0EvVoZ~_1Ti-aUF1pojegd|`E001$xB+vo?0E@IFKmq^&iG(Cj z0{{Svgd|`B001L|BxD5u05Oy#-~s>ui}d004=EB=7_P0E>hq-~<2wBZMSq1pokxlqA3e001$xB+LT< z05Oat-~s>uF|;Jm0ssIpj3mGS001$xB)k9s0EvVoAO!#bi-aWb0{{Rcgd}VQ004=E zBp3w%0EiG(DO0RRAtgd~6f001L|B%A;M0EvVoKmq^&i$o+~BZMR{ z0RR9ClqApt004=+BoG4t0EvVoyaWIMi@YQt0RR9qyd=;7004=+Bp?9*0E@gN7y$qP zGrS~#0ssJsyd)R_004`;BoF}r05iNKU;_XEiIgND1ONbwlqA3a001+TB#;3B0E@IF z00aO43$!FK0{{Rqv?S01004`OB;Wx601J#H00RI3iM%8b0RRAtyd)q3001+*Bya)% z0E@IFumJ!7iIgP30000p@r#rsyZ`_IGn6Di0ssJsyd)q3004`;B#;6C05iNKPy+w} ziIgO~0001slq9$S001+TB)kLw0ExULkOBYzi@YSv0{{Rsyd>}h004`OB#;6C05gmv zAOQdXiIgO`0001slq4Vo001$RB;W!70E>hq5Ci}K3xp&91pojsge0f~004=+B+LT< z0E@gNumb=9GrS}q1pokxlqAdp001+TBp3kz0Ev_&fC2yji(yAOZjY zGr=Q_B)9+o0Etv2Sc}$)v?Qhq00IC2 zGlV3N0ssJsj3mqg004_jBv^@*BtQZH03**cj3lrF004`;Bme;b0E?6)r~?21GuMfP zBme>c0E>hq%mM%aGlV3}0{{Stlq3)X004`WBp?9*05g;%kOBYziIgND0RRAtlq47d z001+TB+LT<0EvtwPy_$~i_SBQB)9+o0EvVo%mM%ai-aWL0ssIrge1TK004=UBp3kz z0E?6)5CH%HGn6E-0{{Stj3i71004=EBp?F-0E>(yAOipZBa9><0RRAtge1@c001+D zB)k9s0Ev_&5CH%HiuiHsy50{{Sv$Rms- z7y$qPF_a`A0{{Stgd}hT004`GBuoSV0Evtwa0CDVGscUIBoG4t03(bf5CH%HiuiG(Cf1ONbwL?l=(oBme;b05MD? zKrxIYxBvhEi-aUl1ONabL?l>?j3ht;001FOBtVJ0B=`UT0E>Jia5KCl&;S4ciF_n* zGgKsSBa|f20{{Svyd?Ml001+*B!B_{0Ev_&&;S4ci&P{aBa|cn0ssIHD1;iUSU?Y?yKmq^&iM%AR0ssJuydJiSRuS5cmx0dF_a{r z0ssJuR3sRSyd>}f001#WBp4%nBtS8gBzOb>05g0fV2hL_&;S4cF;pZVF-#<2W)FVA z4=IEsumu1B4=Ic!&;}f004=EBme^d0E>hqv;_bFGlV2$1pokv zge1HK004`GB)A0t05gOnXaxWOiG(B|1ONbwj3fX8001+LBp?F-0E?6)%mM%aGn6E7 z1ONbL4}Qptv?TZd001+zB)k9s05gOn-~a#siG(CD0{{Svge24j001+DB$xmI0EvVo z@B{z=i-aWD1pojuL?k$ggd}hR004`GB-{l605e1+6p4f+&;tMfi-aUl1ONatgd`9H z004=EBv1qZ0E>hqKmq^&GlV2e1ONbwyd=B@001+*By0r$0EvVoKmq^&i$o-FGlV3- z0001qlqAdo004`WBme;b05Mb~Sc{Y-xBvhEF;pZ#i9{rDiHsxw0ssIr$cuy|%mM%a zi_s&LBme^d05iskv?TZd004{dBeW#E1ONbugd`XR004`GBv1qZ05e1+Sc!xrkO2Sy zBZMR%1ONbuj3iJ4004`OBtQZH05eP^K#8;@fC2yji?k##0{{Rqv?Krn001MjBme>c z0EvVoU;_XEi$o-FA%r9V0{{Svge3R?004=UB+vi=0E?6)@B{z=F_a{{1ONabge1HK z004`WBya)%05Oy#AOrvai$o+?A%r9#1ONbuj3fXB001M;GrT0w0{{Rcd?Y}Lv?MSC z004`$B=7_P03);{%mM%aBa|di1ONatlq4Vo004`GBtQZH03n1V&;tMfF}x(u0{{Rs z`HO@kFarPpGlV1n0{{Svj3gif001+LB)|Xw0Ev_&Z~_1Ti(yOauS`GmIp- z0001qR3sFOlqBE)001$RBtQWG0E?6)m;e9(F_a{z0RRAtlqApq001$RB;Wu50E?6) z00RI3F|;I@0000nlq9eM004=EBwzyo0E>hq5CZ@JGlV1n0RRArj3kf(001M5By0r$ z0ExULFaiJoi+m&$F}x&D0ssIr`HPGsyaWIMF^nXj0ssJsge0&5001L|BxnTy05L=) zIE#cNAOrvaF@z*|1ONbud?XYxj3lT5004`$BrpR205NnVAThKg-~a#si?k$A0{{Rc zv?P!N001$RBtQWG0E>(yZ~_1TF-#;FF-#;li@YR&0ssIpyd>}f001$(Bv1kX05OCl zFaiJoi@YRg1ONbwlqB#3001$RB!B<_05Oy#m;e9(i-aW50{{RqL?mD_L?jf8j3kf& z004`WBp3w%03**cyd=;8001MDB#Z+90E>hq00jU5BZMSy0{{Stv?Ndi004`$BrpU3 z05P;AkOKe!i?k$+0{{Rsv?LG$004=+BxnQx0E@gNKmz~(F}x&j0{{Stv?PoJ004`; zB#Z+903*C4_y7O^i?k$=0{{RcbR=+zyd;bR004`;BxnQx03&=PSc$wOXaoQNi@YRo z0{{Rcd?Y}Lv?P!N004`$BrpU303);{00IC2Gqfa-0{{Styd-b~004`;BoG1s03*C4 z%mM%aiM%8b0ssJuyd=;8001MrBv1qZ0Ex6DFa!Vqi?k$+0{{Rqv?LG$004`$BxnQx z05Oy#i~|4wF^nW=1ONbwlq6sS004`OB(MPh03(znU;+RDBa9^A1ONbuyd=;8001$x zB+vl>0E@gNKmz~(BfKO)0ssJuv?Ndi001$xB#;9D05iNKa037Ui?k#l1pojsgd}hS z001MjBrpX40E>hqkOBYzBZMUI0{{Styd*#a004=!Bp?L<0E@gNfCK;lBfKQQ0001s zv?O2w001MjBp?F-0ExULfCK;li@YSb1ONadyd=B;004=+B)9|s0E@gNm;?X-BfKO4 z0RRArv?O2w004`$B=7+M03);{a0CDViM%A31ONbwyd(y00IC2GmIo40{{Svyd-b|004{8GgKsSBa|e-1ONadyd+En z001$xB$xyM05QBIpacK_Gx&?NBp?L<05P;AU;zLCi?k%n0ssIrv?Oo@004`GBv1qZ z05gOn5CZ@JiIgPJ0001slqBE-001LYByfq8B;W%80E?6)&;$SgBa|fg0001qlqApu z004`WBv1hW03%c+Sc#M*Pyqk{i}d001$(Bv1hW0E@gNzySaN ziL@ku1ONat`irzAxC8(IGqfa(0{{Rqge33)001+*Bya-&0Ex6DxC8(Ii?k$|1ONat zv?OQ*004=!B$xyM0E@IFa037UF|;J01ONbulq4_#004`WB+vi=05Oy#pa1{>i?k%5 z0000pv?MSD001$JBrpL00Ex6Dpa1{>i?k%10000pv?LG$004`WB;W%80E>(y&;$Sg zi-aUl0RR9qlq8S?001+LB#Z+905gOnXaoQNiL@k~0001sv?TBV001+zB+vl>05g;% zKmh;%GmIpt0RR9qgd{Km004=!B=7(L0E@IFKmz~(F|;Hw0RR9ov?Oo=004`$B%lBQ z05h~CumS)8iM%Ah0RRAtyd+=&001+*BrpU30ExULU;zLCi@YT80RR9qyd)3;004=! zB%lBQ0E@IFoB#j-Gqfb20ssJsyd>}e004`;B!~e305iNK&;bAdiL@k~0001sv?TBV z001+zBzOb>0ExULhyefqi@YSj0RR9qyd+Qp004=!B=7(L0E@IFFaZDnGqfb|0ssJs zlq4Vq004=MBqRm^0EvVoChqPyzq| zF@z-W0ssJuyd-!8004=MBwz&q0Ex6DFaZDni?k##0ssIr{)>zxFaZDnGr@_3By0r$ z0E>hqpa1{>iIgN{1pokxlqB!~001-cGgKrPiL@kW1pokxbR-}%#)*U^fCT^mi-aVc z0000pgd~6f004=EB!mS30ENH0E>hqfCK;liIgOW z1pokxlq6sQ001-cGn6FY0001qj3kT&004`OB!B<_0Eu)YATvZHAc=$|kOcq$i-aV& z1ONbuv?MSF004`$B=7+M05i^sj3j^n001+DB!B<_0EvtwGzI_wi%cXKGmIpN0RRAr zgd~&&004`GB$xyM05idflq5g~004`WB$xmI05kH5gd~^+004`GB%lNU05e1+V2Okz zoCN>?i-aVI0RRArOe7eIj3hV)004`OBya%$0Ex6DL8lq94D000lRgd~jx006p(#Rd?;;Rp-JiL@lB z1pojKwuB^%1polS;Rp-JiM%9O1^@u}(TI#Bj0FGy!RZKyj3kW(006=12#Aa%js*Y! z!RZKyj3kc*0051QBwz&q0O-uu0051QB!C3~0O-Ki0051QB#;FF0O+*W0051QBv1wb z0O+XK0051QB%lQV0O*|80051QBp?O=0O*j{0051QBtQlL0O*9*0051QBrpa50O)wv z004`GBuoVW01ps=fB*mh4-klu0000F5TKv{000jVsIUM401ptbzyJUM4-k;h0000F z5SZWq000jVxbOe~01qjIB+vx_0E@gN*aZLpW)FVB_t$0*bJzrC4}QS+(GMw%Bya@) z01qjoB)|m#0Qb-jDXb*$1pojKDYPW81pojKDU>7-1^@sLDV!wW1pojKDZC^A1^@tw zj3n>`004=EBp?L<0Evtw&;}g004`;Bwzyo0ExUL7zO|Ui@YT8 z0{{Styd)e3003qWe&1#fbK3-F4}Q+~*NKEAcm)6eiM%9m0ssJJ4}RbG)-kjsfCT^m zW)FVg_t$0*bJ+xmyd+Qq004`;Bya)%05OClkOcq$iM%A>1pokxyd+Qq004=+B;*AE z0E@gN=mh`(_t$0*e#(iwBtQcI0E@gN>;(V-_t$0*bJzrlyd>ZR008&Wi@YR20{{Rq zlq7@&004=+B}h001$(Bwz&q0E@gNAO!#bF}x&X z1pokxyd)R}001$(BxnTy0E@gNkO2SyF}x&f1pokvge1TP003qWe!veX#EG;da0LJW ziIgOC1pojsgd~&&004=MBzy$`0EvVo#03BVi;N^t1^@tN4|CWEW)FVA4=BZE4|CiM zW)E}N1Tlmpm<0d;iG(D`1pokM4}Rb=ge05=004=EB+LZ>0A>$<=rhQPge33<003qW ze!veX#fgk0zySaNi;N^x1^@sv$ccm`^aTI_W)E}N2xbp{zz-$!-3(?Ae&}WobJzqk$ccm``~?62W)FVw ziHs!R0{{Svj3h7y001$BB%lQV0EvVoumu1BW)FVA4=BcF4|CWEW)E}T3^9Zxqy+!~ ziG(Dy1pokM4}QQ8D92_GbJzqige0g1004=EB)A0t0A>$<@G*oWtOWo7iG(D)1pokx zgd`va001+DB+vi=0EvVo&;bAdi-aU31^@svgd~6h004=EB+vu^0E>hqChqNCp4^GlV2S0{{Stgd{)#004`GBuoYX05gOn z-~<2wiG(CT0ssJJ4}SPF$ccm`00sa6iHsyr0RRAtj3hJ$004`;Bsc~D0E@IFJO%&& zW)FVA4=BfG4|CWEW)E}U3^T}ygd_w8003qWe!z*0BrpO10F8_!&;{008Lc z(*OXCj3lrH008LQ(*OXCj3f{S008LE(*OXCj3nR%008L2(*OXCj3fXC008K>(*OXA zge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn001$BBxnTy0E>hq+ywvtF@z*+ z1pokxgd}hU001$BB!C3~0E>hqbOitaF@z+91pokxgd}(c001$BB!~q70E>hqd<6gi zF@z+H1pokxge1TP001$BB#;FF0E>hq#03BVF@z+P1pokxge1rX001$BB$x#N0E>hq z%mn}dF@z+X1pokxge1TL001+DB=7|Q0EvVozySaNi-aUF1ONatge3F@004=EBrpU3 z0E>hqFarPpGlV4g1pokvgd{Kn004`GB;W%805gOn`~?62iG(EJ0{{Svge0&9001$B zB%lQV0E>hqv;_bFF@z+f1pokxge15H001$BB&Y=d0E>hqyafONF@z+n1pokxge1@b z001+DBoGDw0EvVo&;bAdi-aW51ONatgd`LO004=EB+vu^0F8_!&;hq00aO4GlV1@1^@twgd_k2004`GBoG7u05gOn-~|8xiG(B& z1ONbwge2er001+DB;*AE05iNK2nGNEGqfZO1^@twge2er004`GBtQWG05gOn=mh`( ziG(CT0RRAtgd{)$001+DBhq zFaiJoGlV1r1^@twgd{Km008Kh(EtFAj3jUc008KV(EtFAj3mGX008KJ(EtFAj3n>{ z008K7(EtFAj3lrH008J`(EtFAj3f{S008J)(EtFAj3nR%008Ju(EtFAj3fXC008Ji z(EtF8ge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn001$BBxnTy0E>hq+ywvt zF@z*+1pokxgd}hU001$BB!C3~0E>hqbOitaF@z+91pokxgd}(c001$BB!~q70E>hq zd<6giF@z+H1pokxge1TP001$BB#;FF0E>hq#03BVF@z+P1pokxge1rX001$BB$x#N z0E>hq%mn}dF@z+X1pokxge1TL001+DB=7|Q0EvVozySaNi-aUF1ONatge3F@004=E zBrpU30E>hqFarPpGlV4g1pokvgd{Kn004`GB;W%805gOn`~?62iG(EJ0{{Svge0&9 z001$BB%lQV0E>hqv;_bFjf^DF1pojsge0T|004`GB)A0t05OCls09E3i-aV+1pojs zge0s5004`GB+vl>05gOn5C#AMiG(E30RRAtge1@e001+DBoqb!0EvVo&;$Sgi-aT) z0ssIrgd`XS004=EBoG1s0E>hq00aO4GlV1@1^@twgd_k2004`GBoG7u05gOn-~|8x ziG(B&1ONbwge2er001+DB;*AE05iNK2nGNEGqfZO1^@twge2er004`GBtQWG05gOn z=mh`(iG(CT0RRAtgd{)$001+DBhqFaiJoGlV1r1^@twgd{Km008JC&j0|8j3jUc008J0&j0|8j3mGX008I<&j0|8 zj3n>{008L!&Hw<7j3lrH008Lo&Hw<7j3f{S008Lc&Hw<7j3nR%008LQ&Hw<7j3fXC z008LE&Hw<5ge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn001$BBxnTy0E>hq z+ywvtF@z*+1pokxgd}hU001$BB!C3~0E>hqbOitaF@z+91pokxgd}(c001$BB!~q7 z0E>hqd<6giF@z+H1pokxge1TP001$BB#;FF0E>hq#03BVF@z+P1pokxge1rX001$B zB$x#N0E>hq%mn}dF@z+X1pokxge1TL001+DB=7|Q0EvVoPzC@1i-aUF1ONatge3F@ z004=EBvb|f0E>hqFarPpGlV4g1pokvgd|u7004`GB;W%805gOn`~?62iG(Cv1^@ty zge0&9001$BB%lQV0E>hqv;_bFF@z+f1pokxge15H001$BB&Y=d0E>hqyafONF@z+n z1pokxge1@b001+DBoGDw0EvVoAO-*ciG(E30RRAtgd`9G001+DBp3z&0EvVoCKmh;%4-kYTAO-*c4-tS+0RR9G5QHQ^1^@sL5rAL;000jVgd{Kq000jWfN%i- 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 zgd`vX004`OBp?F-03(bfAOQdXi-aW50ssIrge1HG004=MBp?F-0E@^Yj3gKV004=U zBoF}r0E?6)AOZjYGn6DK0ssIZlq5_9004`WB;W!705Oy#AOipZiG(C@1ONbwgd|J^ z004=MBya=(0E>(y00RI3Ba9>v0RRAtlq7Hj001+TB+vo?0Evtw00RI3GmIpt0{{Rs z#)*_9a0CDViHsxw0{{Stgd|J^001$RB)k9s05kcER3vbVv?L${001-AF|;JW0000Z zlqBE+001#mByfwgB=`UT05h~Ca0CDVF_a|00000Zv?S01001$BB)9+o05P;AyZ`_I zi$o+?i&_BtS8Y zB)9+o0ExUL00961i@YTG0000ngd_j~001-oi?k%n0ssIb{)>bpPy_$~Aw(oti;N^d z0ssIZOe8>wyd?Ml004`8BycmlB+vi=0Ev7ga5GdSaErVo_y7O^GrS~#0ssIblq4_$ z000jtgd{))000jtj3gii004=+B=`UT0E@gN@B;tK5BzOb>0E@gN@B#n;BYY%4iBu#Qi&P|F zBa|dS0ssIHDTE}j1pojKDU2l01pokvR3u=FR3soVlq9eM004`WB!B<_05Oy#paK8@ zi&P{SF+?O7W)FVAF_a{D1ONatd?a8qgd|`E004=EBv1kX0E>hqv;_bFGlV2$1pokv zge0f|004`GB)A0t05gOnXaxWOiG(B&0{{RqOeA27lqApq001#mBp@-gB!B<_0E>(y z00IC2GmIo40{{SvlqAdo001+TBya=(0A>$<$cwZj_y7O^GqfbU0000pge2eq004=E zB)|ax0E>hq)CB+lGlV3V0001qgd{)%004`GB-jN205e1+IEjQL@B;tP~B&Y!Z z0Evtw-~<2wi;N^d0ssIrOe8>wyd>}f004`;B)kOx05iNKYy|)SiG(B=1pojegd`9H z004=MB)|j!03*+dv?PE6004`$B)|ax05P;APyzq|iIgPJ0001qge33;001+*BrpO1 z0E?6)Kmz~(F_a{z0RRAtL?mz_gd|V`001MjBme>c0E?6)@B;thqa0CDVGlV3(0001qlq8q{004_rBse3KBme^d0Ex6DKmz~( zi?k$w0ssIpv?Qnj004{dBeW!B1pokvR3tcyR3sE5lq5_9004=MB=7_P0E>(yOauS` zGmIp-0001qgd{)#004`GBme^d05gOn00961iM%9$0ssJuyd+Qo001MrBme;b0Etv2 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 zB-8}}05OClWCZ{Ki-aWD1pojsgd}JM004`GB-{l605OClYy|)Si-aU_1pojsgd~6k z004`GBy05OCltOWo7i-aVQ z0RR9qge33<004=EB#;3B0E>hqzySaNGlV4c1pokvge1TL0051QB+vx_0E>hqFa!Vq zGlV4g1pokvgd{Ko004`GBrpR205gOn`~?62iG(CD0{{Svge2et001+DB(Mbl0EvVo z-~#{vi-aW51ONatge0^D004=EB+vu^0E>hqPyqk{GlV3#1pokvgd|V_004`GBrpO1 z05gOnyafONiG(CD0ssJugd|`B001+DBoGDw0EvVoU;+RDi-aV=1ONatgd`LO004=E zB)|j!0E>hq&;bAdGlV1<1^@twge1@b004`GBoG1s05gOn90mXYGrS}S1^@svv?L4$ z004=EBoG1s0E>hq-~|8xF@z+L1pokxge2qz001$BB$NdJ0E>hq=mh`(F@z+T1pokx zge2?*001$BB%B2R0E>hq&;tMfGlV1n1^@twge1@d004`GBme~f05gOn1O@;AiG(Bo z1pol(Dy0Abjf^C41pol(9;E;Pjf^C~1pol(5~TnDjf^Dl1pol(2BiQ1jf^C)1pol( z`lJ8=jf^A^1^@u)?xX+!jf^DV1pol(;-mlojf^A!1^@u))}#Oci-aW51pojsgd|`E z004`GB-8}}05OClWCZ{Ki-aWD1pojsgd}JM004`GB-{l605OClYy|)Si-aU_1pojs zgd~6k004`GByhq%mn}d zF@z+n1pokxgd~sw001+DB=7|Q0EvVokO2Syi-aV=0RR9qge3F@004=EB)|ax0E>hq zFa!VqGlV4g1pokvgd{Ko004`GBrpR205gOn`~?62iG(CD0{{Svge2et001+DB(Mbl z0EvVo-~#{vi-aW51ONatge0^D004=EB+vu^0E>hqPyqk{GlV3#1pokvgd|V_004`G zBrpO105gOnyafONiG(CD0ssJugd|`B001+DBoGDw0EvVoU;+RDi-aV=1ONatgd`LO z004=EB)|j!0E>hq&;bAdGlV1<1^@twge1@b004`GBoG1s05gOn90mXYGrS}S1^@sv zv?L4$004=EBoG1s0E>hq-~|8xF@z+L1pokxge2qz001$BB$NdJ0E>hq=mh`(F@z+T z1pokxge2?*001$BB%B2R0E>hq&;tMfGlV1n1^@twge1@d004`GBme~f05gOn1O@;A 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%0A>$<-}lyugd~sw004=EB-{l60E>hqcm)6e_t%NM zBv1nY0Qb;~yd-b}004=+B;W-A0E@gNPy+w}iM%A_1pokxyd>xa008&bW)FVKiM%90 z0{{Svyd>-e008&b4=JQ1zy$yR_tJ^HB;W)90E@gNKmz~(4=Jo9@C5(>4=J=Humu1B z4=KDP00sa6iL@ke1pokvlq7To004=EBzOe?0Evtwd<6giF^nXP1pojKD8w;@B!~q7 z0E>(yPzC@1iM%A}1pokxyd>ZR003qWbJzrlyd>-e004`;B=7_P05QBIU(yR0aS5W)FVA4=BWD4|CWEW)E}R3^T}yge1fT004=MB)|ax z0E>(ySOx$9W)FVA4=BZE4|CWAF_a{P1poju$ccm`$OQlZiHsyL1ONbwj3itJ003qW ze&936iG(D~1pokM4}R#0j3h7v004`OBtQlL05OClkOcq$iG(EZ1pokM4}QQ8D8*(E zbJz%G4|ClNF@z+P1pokvge3F@003qWe!veX#%2$5*aR_zB$x#N0EvVo_yqs}W)FVo zF@z+X1pokvge3e0003qWe(*EMiG(Du1pokvj3nR#004`OBt!-P0A>$$(yOa=e|iG(D)1poju$cuy|AO-*c4=Beoge1@a004=EBwzvn0E>hqBnAKgGlV37 z0ssJsge1TO004`GBq#;|05gOnU;_XEiG(E30RRAtgd{8m001+DB=7?O0E@gNI0gU! ziG(B&0ssJugd}hR001$BB%lQV0E>hqPy+w}F@z+f1pokxgd{)%001$BB&Y=d0E>hq z-~<2wF@z+n1pokxv?M$R004=MBrpO10E>(yFa`hsW)FV&W)E}N1T)Bqgd_k4003qW ze!veX$BB$2&;tMfi;N^R1^@sv$ccm`1O@;AW)E}N2xbp{z-A9~-wcV2Bme~f0F8_! z&;{008JvdjJ59j3lrH008JjdjJ59j3f{S008JXdjJ59j3nR%008JLdjJ59 zj3fXC008J9djJ57ge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn001$BBxnTy z0E>hq+ywvtF@z*+1pokxgd}hU001$BB!C3~0E>hqbOitaF@z+91pokxgd}(c001$B zB!~q70E>hqd<6giF@z+H1pokxgd~sw001+DB)|m#0EvVokO2Syi-aV=0RR9qge1fT z004=EB)|ax0F8_!&;hqFarPpGlV3}1pokv zgd{Kn004`GB=7|Q05OClkOcq$i-aWf1pojsgd~&&004`GB=`jY05OClm<0d;i-aWn z1pojsge05=004`GB;W%805gOnumu1BiG(EJ0{{Svge1@e001+DB(wzp0EvVo&;$Sg zi-aUl0RR9qge15H004=EBv1hW0E>hqFaiJoGlV3(1pokvgd{Km004`GBwzvn05gOn z5C#AMiG(Cz0ssJuge1TO001+DBoqb!0EvVozytsQi-aW50RR9qgd`XS004=EB+vl> z0E>hq5CQ-IGlV1@1^@svyd($)001+zBn$=s0EvVo5CQ-Ii-aWL1pojsge0H^004`G zB;*AE05OClqy+!~i-aWT1pojsge0g1004`GBhq00jU5GlV1r1^@twgd_k3008I!c>n;7j3jUc008LpcmM#6j3mGX z008LdcmM#6j3n>{008LRcmM#6j3lrH008LFcmM#6j3f{S008L3cmM#6j3nR%008K? zcmM#6j3fXC008K$cmM#4ge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn001$B zBxnTy0E>hq+ywvtF@z*+1pokxgd}hU001$BB!C3~0E>hqbOitajf^DF1pojsgd~Io z004`GBzOe?05OClhy?%ui-aV61pojsgd~gw004`GB#;3B05gOnzy$yRiG(DO0RRAt zge1TL001+DB*X;(0EvVozySaNi-aUF1ONatge1rX004=EBrpU30E>hqFarPpGlV3} z1pokvgd{Kn004`GB=7|Q05OClkOcq$i-aWf1pojsgd~&&004`GB=`jY05OClm<0d; zi-aWn1pojsge05=004`GB;W%805gOnumu1BiG(EJ0{{Svge1@e001+DB(wzp0EvVo z&;$Sgi-aUl0RR9qge15H004=EBv1hW0E>hqFaiJoGlV3(1pokvgd{Km004`GBwzvn z05gOn5C#AMiG(Cz0ssJuge1TO001+DBoqb!0EvVozytsQi-aW50RR9qgd`XS004=E zB+vl>0E>hq5CQ-IGlV1@1^@svyd($)001+zBn$=s0EvVo5CQ-Ii-aWL1pojsge0H^ z004`GB;*AE05OClqy+!~i-aWT1pojsge0g1004`GBhq00jU5GlV1r1^@twgd_k3008KWb^rj4j3jUc008KKb^rj4 zj3mGX008K8b^rj4j3n>{008J{b^rj4j3lrH008J*b^rj4j3f{S008Jvb^rj4j3nR% z008Jjb^rj4j3fXC008JXb^rj2ge1@f001$BBwz&q0E>hq)CB+lF@z*!1pokxge2Gn z001$BBxnTy0E>hq+ywvtF@z*+1pokxgd}hU001$BB!C3~0E>hqbOitaF@z+91pokx zgd}(c001$BB!~q70E>hqd<6giF@z+H1pokxgd~sw001+DB)|m#0EvVoPzC@1i-aV= z0RR9qge1fT004=EBvb|f0E>hqFa!VqGlV3_1pokvgd|u7004`GBrpR205gOn%mn}d ziG(Cv1^@tyge33<001$BB#;FF0E>hq^aTI_F@z+P1pokxge3R{001$BB$x#N0E>hq z`~?62F@z+X1pokxge2et001+DB(Mbl0EvVoKn4H+i-aW51ONatge0^D004=EBt!-P z0E>hqPyqk{GlV3#1pokvgd|7?004`GBrpO105gOnyafONiG(Cf1^@tygd|`B001+D zBoGDw0EvVoU;+RDiG(B|1^@tyge1@b001+DBp3z&0E?6)zytsQGn6D01^@svyd($) z004=EB+vl>0EvVoChq00jU5GlV1r1^@svv?L4$004=UBqRm^0EvVoGzI_w ziM%8@1^@sL5QHRP1pokxgd|J_008&Wi;N`D0RRArv?M$R008&V4-tR>0ssIH5QHRv z1pojK5r7Z^000jVgd|V~000jWfFJ?@01ps^B#;FF01pv>FaiJo4-kYTKn4H+4-tSs z0ssIH5QHQk1^@twj3g)q0051QBwz&q0Ev_&BnAKgx_HF~5DyW6Pyzq|4-kYTpalQ` z4-tT10ssIH5QHQ!1^@sL5rA+4004`GBwzvn0QZz6U(y zR0aS5i}d004`; zB#Z?B0ExULFaZDni@YRU1^@twyd-b|004`;BrpL005QBIZ~*`SGmIo~0RRArj3nRz z004`OB#;FF05gmvUhqL(yfB*mhF^nW&0ssJsge1@d004`GBuEAT05L=)I5R{f7%_|_&;tMfi*zIy zF|;Jm0RRAtbR=Lgv?LG$004=UB;Wu50ExULm;e9(ihqi~|4w ziG(B=0RRArge3F@004`GB+vl>05gOnAO!#biL@l}0RRAtv?PcD001+zB+vl>0EvVo zXaoQNi-aT)0ssIr$BDEghyefqi?k$g0RR9qv?LG$004=EBya-&0E>hqXaoQNiG(B& z0RRArge3R{004`GBya-&0Ex6DZ~*`Si}EqFB%lBQ0E?6)FaZDnGgKsCi*zIyF|;J` z0001qgd`vW004=EB>V*c0E>hqU;zLCGlV3d0001qyd=;7004`;B=7+M05iNKoB#j- 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 z1pokM58K>k5AVZf5AV|t5ribr1pojK5tJmb1pojKD3l~11^@sLD92_G@5W{i@8)I? z+rnlK@6l!t+ty|e+s|eX@4;pd@6ittgd{))000jWlq8S^000jtlq3KK000jt#byuN ztRxTy003qW@5E*g+rnlK@027E1^@tN58Kpc5AVfh5AW3v5tJk#1^@sL5riaw1pol( z%SZqKjf^Ca1pol(zeoT8jg%zN1pokzj3j^s008K$NB{thj3ht?008KqNB{thlq6sU z0051QBp?O=0O*ZK0051YBv1wb0F8_!fCT^m=z2&10F9I+AO-*cjf^Ca1pol(XGj15 zjg%x{1pokzj3iJ7008JzNB{thlq7%!0051QBwz&q0O&zT0051YBrpa50F8_!fCT^m z=q^YA0F9I+Kn4H+jf^BP1^@u)8%O{Ei_wjYB#;FF0O$=!0051YB%lQV0F8_!Kn4H+ z==w(h0F9I+Fa`hsjf^Cq1pol(=SKhli_wjYBv1wb0O;9A0051QBp?O=0O{008L7M*skg zj3lrH008K`M*skgj3f{S008K)M*skgj3nR%008KuM*skgj3fXC008KiM*skglqApv z0051QBwz&q0O++v0051YBya@)0F8_!fCT^m=%Pgc0F9I+zy$yRjf^Ca1pol(k3|3g zjg%zt1pokzj3iJ7008KGMF0Selq9eP0051QB%lQV0O)B&0051YBoGDw0F8_!AO-*c z=vGAl0F9I+-~|8xjf^Bf1^@u)Lqz}pjg%w+1^@t!j3h7y008JPMF0Sej3m$n008Lp zMgRbfj3jUc008LdMgRbfj3mGX008LRMgRbfj3n>{008LFMgRbfj3lrH008L3MgRbf zj3f{S008K?MgRbfj3nR%008K$MgRbfj3fXC008KqMgRbflqApv0051QBwz&q0O-9$ z0051YBya@)0F8_!fCT^m=&D2j0F9I+zy$yRjf^Ca1pol(mqY*njg%zt1pokzj3iJ7 z008KOL;wJdlq9eP0051QB%lQV0O)Z<0051YBoGDw0F8_!AO-*c=w3ts0F9I+-~|8x zjf^Bf1^@u)OGE$wjg%w+1^@t!j3h7y008JXL;wJdj3m$n008LxMF0Sej3jUc008Ll zMF0Sej3mGX008LZMF0Sej3n>{008LNMF0Sej3lrH008LBMF0Sej3f{S008K~MF0Se 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 zj3nR%008I+CjbDAj3fXC008LxCIA49lqApv0051QBwz&q0O%Pd0051YBya@)0F8_! zfCT^m=msSK0F9I+zy$yRjf^Bv1^@u)^CSQOjg%zt1pokzj3kf+008LVBme-7lq9eP z0051QBtQlL0O-vm0051YBoGDw0F8_!AO-*c=(;2T0F9I+-~|8xjf^Cq1pol(rz8LX zjg%w+1^@t!j3h7y008KeBme-7j3m$n008J%CIA49j3jUc008JrCIA49j3mGX008Jf zCIA49j3n>{008JTCIA49j3lrH008JHCIA49j3f{S008J5CIA49j3nR%008I^CIA49 zj3fXC008I&CIA49lqApv0051QBwz&q0O%nk0051YBya@)0F8_!fCT^m=nf(`8j3jUc008JzB>(`8j3mGX008JnB>(`8j3n>{008Jb zB>(`8j3lrH008JPB>(`8j3f{S008JDB>(`8j3nR%008J1B>(`8j3fXC008I=B>(`8 zlqApv0051QBwz&q0O%=sF+(0F9I+PzC@1jf^C~ z1pol(Cm;X-jg%yi1pokzj3jUc008I|AOHZ3lq5g~0051QBoGDw0O$cA0051YBwz&q z0F8_!umu1B=jf^DV1pol(J0Ji6jg%z71pokzj3m$n008JHAOHZ3 zlqB#40051QBmf2g0O%DU0051YBya@)0F8_!zy$yR=;9v$0F9I+umu1Bjf^Dl1pol( z&mRB)jg%zN1pokzj3fXC008KG9{>Q2lq9eP0051QB;W-A0O*My0051YBya@)0F8_! z&;^|0E^L$j3fXC008J*9{>Q2lq8S^0051QB(Mbl0O*My z0051YBwz&q0O%bb004{8jf^A^1^@u)FCPE^i_wjYB=7|Q0O$c90051QB)|m#0O<7| z0051YBrpa50F8_!5C#AM=t3U=0F9I+fCT^m=++(p0F9I+AO-*cjf^C)1pol(BOd?& zjg%x11^@t!j3jUc008I^9{>Q2lq8@90051QB(Mbl0O*|_004{8jf^C41pol(&mI5( zjf^A^1^@u)qaFYNi_wjYB+vx_0O)ld0051YBmf2g0F8_!@C5(>=wcoK0F9I+-~|8x zjf^C~1pol(PaXgOjg%w+1^@t!j3jUc008Jb9smH1lqBE<0051QB+vx_0O%=yDwZ0F9I+5C#AMjf^C~1pol(UmXAdjg%zd1pokz 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�K0ON&o+g(T$8GAO!#b=*UU`|GESK0051QBoGAv0O%J@ z|No7YBoGAv0F8_!-~<2w=%h*i|BaL+00jU5jf^A^1pol(@k#&xx�K0O%)7|No7Y zB=7_P0F8_!5Cs4L=yXZ{|GN0Z1`z0qN&o+g(T$8G@B{z==v+zv|GESK0051QBoGAv z0O+es|No7YBoGAv0F8_!00jU5=r~FL|BaL+a0LJWjf^A^1pol(g-QSax�K0O-3* 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%0A>$m003qW@1!J9 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 z2n+xP0uK!e4g&@U0SN>L2?GHQ3=0kd1_cTP01pTW00jpE1PTuh0SgQU2m=iQ3R3kePb3=IGP0RjUA1qKHQ2?`4g4Gs?u3IqrV4-EzZ3;+TP z2L%I25eE@vdX*B>~47~uS*ZcpUOo0AsW#RuG`~(1!46XoK@v{C3<);68-75Yb6x0AxfCB(9 z(enUzc|iX%c5c8k{!Ux#M_00000000000000000000 z00000000000000000013W@ct)W@ct)W@ct)W@ct)W@ct)W@ct)W@ct)W@csp0000R z0000J0000i0000A0001^0002x0001-0002(0001|0000f0001E00008000180000X z000060000X0002%00030000300003000030000300003000030000300003000030 z00030000300003000030000300000F000000002(0002f0002>000170000Q0001E z0000I000130002i0001-0002@0001@0002q0002_0002q0000K000000000000000 z0000000000000000000000000000000000000000000000000000000000000000G z0000F4-XFy4-XFy4-XFy4-XGBGcz+YGcz+YGcz+YGcz**0s{aB2LuHR2nh-d4Gs?j z0s#OA1_cBQ3JC}g4h;+p2m}BP2?YTT3I+lX3kL%a3IzZT2?PTT2nPZT3kCsIRaI40 zRaI40RaI40RaI3F3kL%Z3I+lV2?YTR2m}BC000aC00000000C4000OB0|NsG2L}fW z3kwSm4-XGzcyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0e zWgu&1cyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0eWgu&1 zcyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0eWgu&1cyM8EWFRv#En<0eWgu$+00000 z000010000000000000000000c0000c0000c0000c0002~0RRC00RRC00RRC00RRC1 z|NsC0|NsC0|NsC0|Ns900002is|Hp8000020001V0000)#|8jIw*~+J0002is|Hp8 z0000C0000K0002E#|8knw*~+J0002is|Hp80000D0000e0ssKa#|8k*w*~+J0002i zs|Hp80000E0000000000000000001700000000000000000000000000000000000 z00000000000000000000000000000000000000045C;%I#|97q0002Uzy=Ti00000 z00000000000RR910002%wgv!FQ$$lWYiF4Xea23*j0Qz&*i2#p0000)I$U;dY;<8< zL~nO)Y;R#?b6jj`Vsmd~X?1NaF)lDJGcI&ta$Ia_Vsmd~X?1NaF)lDJGh9M-X>4R% zQe|vqVRL0fOiWx?X>KzzTx@A#b8lp6b!{$iWMTjS0002500025000000000K0000- zLsU!v5C8xcss;cqbY*ySByDa000000zy<)w0000kX=Gt^VI(yG0002Uzy<&W0000k zFfe0gX8-`qzy<&W0000kLsC>ESVKVo0002czy<&W0000kLsC>ESVLL>0002gzy<&W z0000kLsC>ESV=(u0002kzy<&W0000kLsC>ESV>v{0002ozy<&W0000kLsC>ESWrO# z0002szy<&W0000kLsC>ESWsF30002wzy<&W0000kLsC>ESX4m(0002!zy<&W0000k zLsC>ESX5d70002+zy<(J1^@sqa%5q2VE_O?#|8id0000ka%5q2VI*^SWMOn+0000) z#|8kf0ssIma%5q2VI+EbdSqf}0002=$p!!f0000ka&%)PNkKsX0002^$p!!f0000k za&%)PNm^O}0002|$p!!f0000ka&%)PR6#)i00000$_4-g0000ka&%)PR9ad900008 z$_4;@0000kcw}L8VI+6}0001x$_4=BFaQ89Wn^J=VE_Ph`vw4b0000kX=Gt^VI(pD z0002&`vw3M0000kX=Gt^VI(sE00000{00EX0000kX=Gt^VI(vF0002U{00Ed0{{Rn zX=Gt^VI(#H000005C;Gtf&c(6WMOn+0000Wk_P~|0{{RnVsmo<00000pa%e00000k za&vNHBrq`m0001Bpa%ee0RR9la&vNHBrq}n00000000000000000000000000002~ z|Ns900002c|Ns900002~|Ns900000EuLckR0002~|Ns900002g|Ns900002~|Ns90 z0001quLckR0002~|Ns900002g|Ns900002~|NsAMum%u{um%tS0002~|Ns900002k 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 z0AFTwX>DaTGyni(0CHhzb7cTH0AFctX>@dDa%})P0AFctX>@dDa&2E_06_p>b7g2> zW@&76WpZC+Y-|8E0AFctX>@5}Y-xIBUv6P?a&LEEWo~w9a&K;JWo~o;05$+$X>MtB zX<=+>dSzd4Ze@6BbYFB~Vr*pq06qX;a%E>}b97~LUvF+@cxiNBW_503bZKvH03-lk zWq4&{b#!H4Z*FCHX>?z7VPb4$03QHfV{&v~VRU79X>NWX>DaKY%wh{Eif)*Y-|8waA_@Vb1ipiZY^VSbS-FQVQ?*MF)cAI zFfL?lYybdZaA_@Vb1ipiZY^VSbS-pgZDlQNF)cAIFfL?lYybd)1yycnVQyq>Wn@Ko zV`Xr3X>V>uX>4?5asU8B1yf~oRc>fuZe(m_WJP#mWpH$9Z*E3uY;rx0!L+ZQ+acAWo=YxZDm1oMrmwiRB3Hx z022X3X>(y>Y-Lnva%Ev;Ole|rVRCsxVQg%3080Z&ZfSIBVQgu7Wm8OPb96{$VPpVj z14(m4Wny(_XJv9wa%FR6Zgc=f0BvP$V{mx@000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000000000000000278NWnM=0Lmu|Ns9000001000010001J zZDC_`Xkj%mGBPzb0001Eb#iuPGBq_ZIe2qnY;$2UFmP{dc`-9EH2?r&Y+-95eEiWMyV&XlZI|Y;A6DaB*^Tbai%j zczJpN0001Eb#iuPGBq_ZIRF57b75?AVKOjqZ)|xnGcYv(0001UX>e#^b7(R&0001G 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 z;4|to1T+&gAv7yAH8epqS2SWYgEXr&wKTpo#5CeG>NNQ@05uaeC^a`VM>TXcfHjdd zu{FUp(KSIgyf*%^r%Q+%CJ33c7VLEm?e>$H! zuR6s#-a7F*1v?%)F*`*&UORC+fjg)>zB|V|(mUBZ`8)qR0RRI3{RKP=JP|w>JRUqH zJS;pjJUToM&Jfu9dJj6WBJODigJq$e(Js3S6JtaLX zJu^KzJwZK4Jx@JXJzqU%J#syFJ$*fgJ&`@6J*hnmK07{3K4Ly|K7>ArKB7LSKD0go zKOR3QKQ=!|KV3hYKLD@>0I&c60CX^?Fh()}RGRZRUG6XXVGZ8Z* zGc7ZYGn+HQGs-jLGaWQIG(AG}$!eH0v}DH9s}#H3>Eo zHY7GNHa0d~Heoh~Hjy^2Hv2XJHxoA@H#|2-H`X`bH|IAlI6XK-IC?mPIFLA-IHWkU zIKDWMXX>K4yPg5XmZ)9aI4Gjt;000000000`MF0Ry0SN#wotRSq000000002s z01hJy0Rk5QY6AcOA_M>c1ONbV6aWAK5C8xGfCB&k08nB85C8xG0ssI60000100004 z0000000000kOTk#1ONax0R;d90000003ZMW5C8xG01yBG5C8xG0000G00000Km-7Y z2LJ#7Py_%>1poj5000000000000000000000000000000fCK>O3;+NC0000000000 z00000000000000000004a0CDt000000000000000000000002^Py_(H0000000000 z000000000000000000000000kbY*yS0000~XafKM5C8xGY6AcO1ONa40000000000 z0001B08n5qWMOn+0000y00000fCB&k0ssI2ZUX=S00000000000000$08qd#a%5q2 zVE_PJl>h($kOKe!mH+?%a037U00000000000000$0AN5aVsmo<0002U0{{R3Fa!Vq z000000000000000000000001h0ARo_Wn^J=VE_P#2LJ#7Km-5)2mk;81_S^A00000 z000000000$05Cu%I00000000000000$05HHV zLsC=#0000i00000U<3dF0ssI26a)YO00000000000000$05HHVbZm0~0000W00000 za0CDV0ssI276bqQ00000000000000$05HHVa%F69V*mi?3;+NCfCK;l4gdfE7z6+S z00000000000000$05C!T000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000000000000000000000000000000000000}gX|c`1SEg} z008KqW&;3;1SE;W=%z{o0EOG5tTR+%qo^}fVss710{{R30E5IBF~D2HgTxrP0RR91 zTf>l5iRD*TQ-kari&YGT(sg*D05DWyg}@JvGXVeqgXjT^9VAgyVxs^sRAP%YI8jt$ z>kP*PB;%U|BnSWi0075CBm@Bf0074XB(O77V*k^F>GgM-O z_yP}v>Hq)$#{?uF0002!|78OJxB&nF0F7nzTV7vX!VCa|`T@8B0001W>|~)B0001s z9VAgyVvBGDi#<3|RATEJjkG2J0000v@DGG20RRBU1SIGK0095jgX{#yL?j3R0001q zbR-1F1SGICRAT?rgX|22z;)0u+o7~GRAPhp0S|;j0RRA@v@=v`Z004#C4}{$S005z2|5IXxz;qgmRS?HSBm@Eg004GgM;#6(~_uVz>bS004vR z2#sa*TV7vX!VCb7bS4110RR91>G=Nt|Bbc)0002TL?i?N0002T1SGICRAT=XC{a{m zgX{?D2LJ#6jdlRXL?i?dU{qqq1SAMxRAR>kv@=v<0RR91=vrh00O`v9|NqAXBp(0( z0O&bn0|4o{{{R2SL?i?RU{qqq1S9}pRAT5bWCH-l1++6%VgdjF0O_Ru|Nn{hjl3rS z00010iRD*`&sK@XQ;E}q>>P#Ci4_EZQ(|>Yp#U&cVuiqTZs?gx0|1G9BnZbuBm@8e z004RjdlPr((Ap0`vDJy z`v3p{jdlR&drboXiF_moiCiQEi8LhWi&O&ugX|22z=^_jf`j`34~2RE|Nn`6BnZbu zBm@8e004Hq%!|A~Ag2#H)I1c@{x=5BgU|BZG4jl3rS0001k>>P_!BqYZL6fjg`00000 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 z-9#iv-9#i%-9#iKBt(f+BovKQBoK)d zB>&Ls2Hn`**xlHJ#5}{0jdUgei$o*@qogxbV(DT4003r?gX}zuL?l3q5RFRzy6^y0 zVuSewcL$3UjSK=*V%01c_862**Su1ONe4Vu?f~ z454UIRAPg`K#2q-=o0_{05QOW#5}{0kdTm&|0P&aRAP{j|0R4;RAP{jRf*+;>=@{U zoc#aC1S9|zP-5tL;s5{1!;p}WkdTm&|NsC0Ab3+^00000|NsC0000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000|NsC0|NsC0P<{91^@s64FCWD0ssI23IG5A1poj5eI1Y{^8__N004ly004kH z0000u004kL(sZ5@00000?>YMZLN4Y%0002K0000#^8~d&004kK004kJ004kIQb`>; z00000b#7~JZ+C7WWpZ+FasX^;VsCJDb09G;F#vOQV`F7=a{y^>c42I3WFTR3XLW65 zZgc=*b!KK|av*eXZyN37a&BR4AZ2oLZ*l-*Z*p>VaCBv4AaitbWnpaq za%FLKWpi{OZf|rTX>D+9Wo>0{bY)}!X>N95Y-wa5b97;JWdLnuZEtdUAYp85Z)0I} zX>V>IW?^Y;Wn=&V00000000000000000000000000000000000T9H#?Vv$o~bCFYG zgppHXlaW(mq>)o%ypdC4%8^rI005mn06<X8000000KiN?007NB z00000000000000000000000000000000000000000RI600RI600RI5~0RRF20R8~| z0ssO30R8~|0{{X4004kL00000000000000000000000000000000000|NoqBRz^EB zEhr@+9~>GP7Zw#16A}>+5DyOy4Gjzo3=9hk3knJf2?+@a2?+=Y2nYxV2L}fS2L=WP z1_lNO1_lNO1_lNO1_cEL1qB5K1qB5K1q1{H1Ox;G1Ox;G1Ox;G1Ox;G1Ox;G1Ox*E z0|NsC0|NsC0|NsC0|NsB004kL004kL004kL004kL004kL004kL004kL0000$0000$ z0000$0000$0000$0000$0000$002Nh002Nh004kM005vs006*10000%0000%00000 z0000000000004kL0000$002Nh004kM005vs006*1007`X0000%004kN006*2000m| z001yT002lr003Y@004MG004$U0059e005ps006K;007iN000I<0s#OS7Xko&e0ObE zDH90<0ssI20000#004kL004l;004kT0000-&CE`}PAAB8JFUMb5xZxVw#Gcz+k&CJX_&CCox&CJZb z0000&006)}00000Gcz+YGc(gaDO``j^(gc|Na1=Eu1D!V004kJ004kO001aL001LH zWf|f-00000m~Ik-z{uIM-}%!002Ng004l%&CE`}NqnwgnD z0000um49Gg>O)SXjeh@ewqIHOZy<{93jhEB4FCWD4*&oF5dZ)H6951J6#xJL7XSbN82|tP8vpOVApigX zBLDyZB>(^bCjbBdDF6TfD*ylhEdT%jF8}}lF#rGnGXMYpH2?qrHvj+tIRF3vI{*Lx zJpcdzKL7v#K>z>%LjV8(MF0Q*M*si-NdN!O#lD@PXGV_Q2+n{Qvd(}RR910 zR{#J2SpWb4TL1t6T>t<8UjP6AVE_OCV*mgEWdHyGX8-^IX#fBKYXATMZ2$lOZvX%Q zaR2}Sa{vGUbpQYWcK`qYc>n+adjJ3ceEkg#Z8mhX4Qoi2wiq zivR!sjQ{`uj{pDwkpKVylK=n!l>h($mjD0&nE(I)n*aa+od5s;p8x;=p#T5?qW}N^ zr2qf`rvLx|sQ>@~s{jB1tpET3uK)l5u>b%7vj6}9wEzGBw*UYDxc~qFy8r+Hy#N3J zzW@LL!2kdN!vFvP#Q*>R#{d8T$p8QV%K!iX%>V!Z&j0`b(EtDd(*OVf)c^nh*8l(j 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 z07(F602}~109XKa00aOc06+j<022T)08apI00{sm07U>}02lx^08{{S01f~w07?L8 z0385309gQc000000000000000000000000y0C)hj01p650EYm>03HBZ0G0sK04)G% z0Hpxo00jU+0DS0IC4y015y`0D=I%02u&P0FeOA z04M-t0H6Te05<@00IvY+0096!0C@nl01yC70Ehs@03QHb0G9yM04@M(0Hy%q00sa; z0Db_v02KgH0F40203-ll0Gt5W05bq@0ILA!01E&|0D}O(02%;R0FnUC04V@v0HFZg z05|}20I&e;00IC$0D1tn01*I90Eqy_03ZNd0GI&O051S*0H*-s00#g=0Dl0x02TmJ z0FD6403`rn0G$BY05kw_0IUG$01N;~0E7U*02=^T0FwaE04e}x0HOfi067440I>k= z00RI&0DAzp01^OB0Ez&{03iTf0GR;Q05AY-0H^@u00;m?0Du6z02csL0FMC6044xp z0GV0agIc07e160dxTD z0AvB&0RjMe0P+B80U!XF01yF)0X_h>04@Qh0bBso089bI0TBR+009Ac0WScj03QLD z0ZjnK06hV<0c!x`09ygm0S5qo0QUfI0VM#P02Kj^0Yd=005bur0bu~y08s(S0Tuv` z00sem0W<)t03-pN0a5_U073z}0dN550AK;w0So|y0Q>-S0V)8Z02%?30Z0JA05}1# z0cHT+09FCc0UH3501E+w0XYD%04V{X0apOe07n780d)ZF0A&H)0RsSg0P_HA0U-dH z01*L+0Y3n@051Wj0bKyq08IhK0TKX;00IGe0Wbil03ZRF0ZstM06qb>0c-%|09*mo z0SEwq0QdlK0VV*R02Tp`0Ym`205k!t0b&5!08#N+0R#Yi0Q3NC0U`jJ01^R;0YCt_05Acl0bT&s z08RnM0TTd=00RMg0Wkon03iXH0Z#zO06zh@0c`-~09^sq0SN$s0QmrM0Ve>T02cv| z0Yw1405t)v0b>B$08;_W0T=*~00;qq0X6`x044#R0aO6Y07L=20dfH90Ac~!0S*9$ z0R8}W0W1Kd02~370ZIVE06GD(0cZf=09XOg0UZF901W|!0XqP*04o8b0a*ai07(JC z0e1lJ0A~T;0RRAiKL7v#fMfc9KfiTWyo>37KMHZyym`%kKj+RMy)UMJKRRAky{~hB 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 zKi2(!KL`JRKc)YFKj{B|KmGrIKL7xLKL7v#00000000000000000000003H0OGQ68 zF(@J(6cP#m000000001PWLi{CM?pF>Ehiuv6bt|W00000c5Y`~R!~buK|3`sC?6LO z1ONa40DgCHXkS@VPDnyLHZLb284(Nt004%6cyec9TUAa-LOeDvDI*;h5DEd1iGqA_ zYh_n30Nvdv$MVVq8{GN<%$2F)Jh#0iv6fj)i}Db8Kc{T2xI( zK|3`r9s#VSo|un`gMD^zYGhtlQAmfIxsgfIxsifLu;oPh3t~Pjo4BC~_!-8iX2= z5upsQ3b6|qvoMM_hc<*YhB$>cgg1meazN>@i(NnJ`^N^K}|By}QnB99S~5|R_545bRP2fYTq2(bwlvNm%+W^ zTS;3^SyoV7LR~;+J7+v-JasgCEQ%wAA7LgQ(HnS zD3&3N9bzL*Dk^zkLToEz?iKmY&$J^%oKIR1hwWk(hFKL7v#000000000000000000OL5EB&_7#bTK z9UdPbAR!_mBP1jxB@X}q015yA00jU500000Kidzn+a0000000000000000Q&Xn%SSRQCL7leO*e|~>@g@T4NbdD6XzB>Z8Yepg_yPb;3kmoZEcyp1 z2^s?l`4naO1Oxag8UXPjL;@H7H!l7U1OF8eDF6Tf00000000000000000agY2L%8C z0ssIE94QU__YW!=4gvl?DfjjzLHq;y1VRV+5Dq5&ArRG5VgS`sV&K$MVo=pnVnEeX zVj$I1VuOH&jg5_wk&%|0o12@UprD|prmd~Ez_!4^z|FwT;6+_?c7uwIik6m}mYbla zpbvwJikq9Qtq?E(000000P*3|$GfkjnT~{ea%o^#P)I;IGAt$`9T*f43<(7S0LP_} zd~IM|GCF|NsC0|H4xlN8SJb|No*% zB0{47|Nqi{Nh>+6|NsBVeMc}lg8%>jrfx|&K4{Ya|NDDEH$-Hs{{R300000000000 z0000000000000000RR5|?hXS20RaF0{MsV}0s#R3{`$~61Ofp7|Ni#EM+yP~0RQ~# zw^9fK0RaE}>$F-C0s#R3_~5Hy9s~gZ|NiW)UnK_t0000000000000000000000000 z0000001yBG003h`BqSmvA|fIpQ$-{+B6Ma(L`1M=L_{J%RYX)Ibd8vcs)W0^*olPs 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 zw!q-v;Q!#@wws1_ZD?j{Z+3%`psj-d00000000000000000000000000000000000 z0DUtW5)TXu3JC}Y1_cBI0s#QVX)P8H3=0Yg2nPlQ1OoyA0M(*&Q#&gl7!nT*2?quR z0|Ef=yL3Ao5DN+k2nPlQ1OoyA0Q%*;hgLHl6AcOo1_cBI0s#Q|>(#lOfM-)eH7X$* z6%h>z0RH*w&ZKrtE*lUE2L%KJ0s#R3{rT_QznphfIVBel3I+rM0RR2__U+%xvzUBh zOE)MT6%PRa{{8pdqH04b91;u(1_T2F00;^U5C8xG0000005Ej`0B{!o03gx-{~*!- z{{R30000000000000000001EVANC*WAJ`wlAE+OQA7URm9||AX9-tm#9wHvx9grPD z9qt^K96B7>8*&>88=M*{8nhWY8N3)g7`7KK7oZjp7Je1z6iyVd6A%+_637uA5p)p7 z4;Bw(4z3OO3_uKo3&;uz3Q7rz2*w8j2R;UP1+oO{10n-j0+IpB0000s|8D-K{oec* z{7(Cb`oj7C_&WG@_qO)-^*Hr>^uY57^HTDh@#^q8@Qm-`?l|s}?eOeS?6T_^>w@a= z>0s&7=t}6s=S1hm=1k_+Sc^2><{9000000000000000 z000000000000092|Nj600RaF30096100001000000096100961000300s#O40RRC1 z|NRI42LJ#8{{jC3{sR63{Qv;~0sjL30{#R30{{U40003100000000000000000000 z00aO6000091P25F0}KZT1^@#92Lk{B3IGBI5(*3e0KEXH{b>SccXa?^|I+&ibTk0n z0I2qKZv6id0_yVRX3+ok0*vsbU9kU&19k5PQ=R|J1A^~nN0tA_1B>t{JDLB017Y&6 zE~Wnk1JCqcBDw!#0-^Vq7SjKz0ipV|3lsH~=2;T+DIW$@AOHXW000000000000000 z000000F-NI#1Q}t00;m90QUdt|Kk7P|LXq(04xAx0H^@-06hVH0j&YY0RR9100000 z000000000000000000000OVH%#RCBH|Lp(q{{jFR03`q!0Pz30|CRr-|1tn10dE4< z0|*7U1poj500000000000000000000000000Omf%#Pk0E02BZk00jWy|JDEe|3Ls+ z00#hL{|Nuo|4{-j1~dxC3}^xk$oBsy06GBD|E&Lb0Js3f{^R`w1q2m9BLDyZ00000 z00000000000000000000000000Efpt$v^;r0EYi005$;t{YU~cBt=CG0Du4z0CN8z z0gL~i{2LH^H~;_u000000000000000000000000004lH5$KmY(hKmY&$0B;h5I&Tt#JDQmpKh4a{JpcfJ zJDQmpJ^%m!H~;{EHwxDyJOBVdKmY&$Kmb4-MgRanKL7xLKDSa*VgXZ9V$)MnVgXZ9 zVm4G#VgXZ9Vz5+FVgXZ9VgXZ9VgXZ9VjxpeV$ICVJpcdzKmY)MH~;{Ez5oCKJOBUy zKL7v#H~;{kK>z@NJ^%oKJI&0@z5oEgKmY&$0Boaq2~U#>KmY)sK+Vj|J^%nfKW`F) zIx{nKKML0)JOBWIHwxDyz5oCKKo_@BI5RUdKc4S@K+Vj|J zKW1izKh4ZcJ^%nfKxSr!K4xa7Kbn~tKbo1DJ^%oKHvj;DKL7xLJ^=pzKF!QbJz@NJ^%m!KL7xLM*skTHvj+tIL*vVy_%Vs zKh4Zcz5oD#JI&0@y#N4!I?c>XKX=S4GOWd?HUI#CM*skTIRF5FL;wH)MgRbSMgRbS zMF0Q*K>z@NNB{tUIIP7dH(zjxFaQ7mz|6diD_?MlFaQ96KXUnhKXUnhzW@LL0001b z!~j4XNB{tUInB&WJ^%oKKL7v#0Boaq2~U#>KmY&$KL7v#0Q{-((oJGeKh4ZcJpcdz z0AFy4FaQ7mzyJUMKmY&$006O4VmGoe50MG{j05Ej`0MG{j0Qf2Z0O$h%0I)Uy0O$h% z00>e50MG{j0AOtZ0MG{j0N^eF0O$h%0GK)e0O$h%08mB%0MG{j0Ps}+0MG{j0Qf2Z z0O$h%0I)Uy0O$h%0BAx00O$h%00>e50MG{j0001hFOCaGUzSO5UXK^M1CIttgLJOBWoK>z^yMF0R$ zK>z@HMgRbaK>&a|MgRbCK>z@NJ^%m!zyJUM#{mBSMgRcFLI41IM*yGLKF!QbJ^%oKH~;_uH~;_u00000000000000000000KODf7KEKl>KGFcLJ+dD& zJ+aocJgq!8JWBGnJCRN}I{*Lx0000000000000000000000000000000000000000 z00000000000000000000000000000000961000000000000000009610096100031 z0000000IC200961000630000000IC200IC2000330{{R300RI300IC2000C50s{a5 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 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAg za$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5 zMrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kR zF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTA zF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$U zG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!& zG%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZIv^-V zPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~407pYZ zIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opgFev~4 z07pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21KE@opg zFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yGE;21K zE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbXAT%yG zE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7%X>LbX zAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MrCAga$z7% zX>LbXAT%yGE;21KE@opgFev~407pYZIv^-VPE{!&G%h$UG9WTAF*7kRF*YD5MgagO z|Jh|^Z*pNEO=)gNS0FSlI4&|RF)n6fGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQ zH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7 zFflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yG zE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05K zAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTR zM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002ir zLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs z002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOh zGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_Q zGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSl zI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gN zS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNE zO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&u zZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE;1l8FflVRFfleD zC`M&uZ*pNEO=)gNS0FSlI4&|RF)n6fGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQ zH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7 zFflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yG zE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05K zAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002irLpmTR zM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs002ir zLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOhGB7Cs z002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_QGcIOh zGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSlI4&_Q zGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gNS0FSl zI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE-@f7FflVQH8U|FC`M&uZ*pNEO=)gN zS0FSlI4&_QGcIOhGB7Cs002irLpmTRM^05KAT%yGE;1l8FflVRFfleDC`M&uZ*pNE zO=)gNS0FSlI4&|RF)n6fGB7Cs0000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000000007Vv&r$#Y0025d1ONd5001=r z001=r001aJ1OWU%1OU)M1OULd0syeM0s!!@0syeE0sxS*0s!#20sxS%0syeC0sz4K z0szqb0suh90sx@>0sx=}0{~FN0swHs0sz28006Kv0|4+d0|3A)0|3A*0{}2I0{|c@ z0|0<30{|c+0|4M60{{>q0{~zn0|3A%0{|c%0{}1|0|1aa0|2l*0{{Rb0|0;?0|0Oz z0|2110ss)X0st_%0swHi0s!!`0sufd0{}3f0ss&@0|0QB0swF|0{}oZ0{~z(0|1aU z0{|d30{}2J0|4+j0|1~o0|1~!002lr1OQY*1OR421OR$M1OSUd1OT8y1OU831OU=P z1OVhh1OV_t1ONg<1OOI81OO*P1OPlk1OQS)1OQ}11OR+P1OSvn1OT!_1OU=Q1OV?t z1OO031OPHb1OQM(1ORA61OSFa1OTQ)1OUTC1OVhj1ONs_1OOyO1OPxq1OQ$|1OSIc z1OT!{1OVAZ1OW3z1ON|41OO>U1OP-v1OR461ORqM1OSLe1OS>w1OTl@1OUTE1OVJd z1OWC%1OOIC1OPEd1OP}!1OQ$~1OR$R1ONa40RRF30{{d71po#B2LK2F2>=QJ3jhoN z4FC=R4*(DV5dabZ695zd6#y0h7XTOl82}mp8vq;t9RMBx9{?Z#Apjx(BLE}-B>*M> zCjck_DF7+}D*!A2EdVY6F90wAF#s|EGXOLIY-wU|aCLJnFfL?lYyfX?b#q^2Wn*t- zWdLt*b#q^2Wn*t-WnX4&Z((!*Z*X;UUu0!tZ)9b1Ut@A*VRU5xZ*X;UUu0!tZ)9b1 zUt@G^0B>-0b6;d-V{c?-a$jU+b98cVc>r&4b#q^2Wn*t-WpZCbO3K~b#q^3Zewp` zWdLt*b#q^3Zewp`WnX4&Z((!*Z*X;UUuAA%Z)9b1Ut@A*VRU5xZ*X;UUuAA%Z)9b1 zUt@G^0B>-0b6;g{V{c?-a$jU+b98cVc>r&4b#q^3Zewp`WpZCbO3K~b#q^5WprP5WpZ<-b#q^Bb!>ELb98cL zVQpVzWn*t-WdLt*b#q^Bb!>ELb98cLVQpVzWn*t-WnX4&Z((!*Z*X;UUu|`4bZK*R za%Ev{Uu0!tZ)9b1Ut@A*VRU5xZ*X;UUu|`4bZK*Ra%Ev{Uu0!tZ)9b1Ut@G^0B>-0 zb6;(BY;r&4b#q^Bb!>ELb98cLVQpVzWn*t- zWpZCbO3K~b#q^Bb!>EL zb98cLVQpV!Zewp`WdLt*b#q^Bb!>ELb98cLVQpV!Zewp`WnX4&Z((!*Z*X;UUu|`4 zbZK*Ra%Ev{UuAA%Z)9b1Ut@A*VRU5xZ*X;UUu|`4bZK*Ra%Ev{UuAA%Z)9b1Ut@G^ z0B>-0b6;(BY;V{c?-a$jU+b98cVc>r&4b#q^Bb!>ELb98cLVQpV! zZewp`WpZCbO3K~b#q^B zb!>ELb98cLVQpVELb98cLVQpV0B>-0b6;(BY;WprO>WprO+VQyr1X=HS00B>-0b6;>_ zV{2t}UuR`>Uv6SwV`yP+Ze?t90B>-0b6;>_V{2t}UuR`>Uv6SwW^!R|Wpe;;aCLKE zaA9L>WprO>WprO|VqbG%ZE$R5a{zB}b#q^EVPk7$bYEv>bYF8}ZE$R5b6;>}a$jb0 zVQpmqZ*X;UUvOb#Yh`p_aA9NsZ*X;UUvOb#Yh`p_aA9(DWdLt*b#q^EVPk7$bYFFD zaA9NsZ*X;UUvOh>UvqC}bYEj^X>b5-0b6;|0 zaA9L>WprtJWpZC*a%Ew3WdLt*b#q^GWpH6*Yh`q4dS!B7WMy-7a&LJ6Z*X;UUvgz| zVPk7$bZL5Ja$jdbO3K~b#q^GWpH6*Yh`q4dS!B7Z*_D4Z*X;UUvgz| zVPk7$bZL5Ja$j$CbYF5|Zf9ixZ*X;UUvqSFWpZ+FasU7T00000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000000000000000000000000000000000000000000002Bt z1ONa400000007if1OWI@1OS*&1ONa400000002N$1OQY~1ONa4000000000000000 z00000006X61OUuY1OVhw1OWI^1ON_F1OOyb1OPNr1OP}<1OQr61ORkW1OS9m1OT8? z1OUEL1OU`h1OV((1ONt81OOyc1OO~k1OPx&1OQG`1ORGN1OR+f1ONa4004|r1OS>- z1OTp61OU8K1OUcU1OU=g1OVDo1OVbw1OV()1OWC^1ONb31ON(D1OO6L1OOaV1OOyd z1OP5n1OPZx1OP%*1OQA_1OQf41OQ-E1ORAM1ORYU1ONa4006X61OUuY1OVhw1OWI^ z1ON_F1OOyb1OPNr1OP}<1OQr61ORkW1OS9m1OT8?1OUEL1OU`h1OV((1ONt81OOyc z1OO~k1OPx&1OQG`1ORGN1OR+f1ONa4004|r1OS>-1OTp61OU8K1OUcU1OU=g1OVDo z1OVbw1OV()1OWC^1ONb31ON(D1OO6L1OOaV1OOyd1OP5n1OPZx1OP%*1OQA_1OQf4 z1OQ-E1ORAM1ORYU1ONa4007hgL}hGcbY(+wX>@60VQf=nV{~b6ZUFB9MQ(Iuazk=y zbZKK@Y*S@pbZKvH006`RM`d(Fb#iiLZgfy`Z)0V1a{$EwM`d(Fb#iiLZgfy`Z)0V1 zb4g?X$pJ@YbVGG=a%FCGRA_Q#VPr{U00095M`d(OVRLjva&m8S000#NM`d(PZ)A0B zWk_LeWNc+Y002b-M`d(Sa&KcnWMpz>b8`RydjdygbW?eAbY*Q+X>Daeb4F=wWmIWx zWdN4~M`d(WX=7_cZ*^{T008R(Np5L$X<=+>dSyd$X>@60VQf=nV{~b6ZUFKENp5sy za%^v7Yh`3ZZ*6d4a%Dw$V`yP+XJr5Y^a4q4bY*gEZ)0m^WJP#mXkl(=WdJ4vOl4tq zWkYglbZKK@Y*S@pbZKvH005H%QFUc zVQyq>Wn@KoV`Xr3X>V>uX>4?5asYG$Q*32rZ~%e?RAq8)X>MV3Wl(Z&V`X!5004;u zRBUrcWpq|yY;|P-mIPI9Xkl(-Y-MCccw=R7bZKvHMrmwxWpV%jwggsba&&cJY*2D< zbY)|7006lJR%vo{bzy8#b!BpS001`tUteTwY;SI5cxiM1YXDzgb7gdOb7gXEVRUF^ za&iCwjsRa_ZF6T|Wq4_H007VcUuAM~Zf^hpFacj_ZfSIMWpZr*Gyz{}Z(;xdl>uLD zZ)0l!G6G+3Ze@6BbO7)IUv+M5Z)0l!P6K0MY;131003wMW^i(8ZggeWn};W zdIM&6a%psB005-}Y;R{VFaV|lZDDL|Z({%et^;jlZDVkG006H8ZDnn3Z+2w>u>);o zZF6OG007+sb98cSWo`ff-~)4Xa&BX7Z~#CAVPbD`bO1&KVRT_`G5}r#c4lyLX>N38 z0000`1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~ z1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1ONa~1OQ7#QcguoGcqn@Y-|7k z000zF1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ z1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1OOCJ1ORPwc4KmME@W(M z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000000000000000GP+|Z800000001Cb zQ)19rQ(^!B0000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000001RRAL-(RALY?RALxlRAK-C000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000G003wJ0012@A}~=fVlZbgZ7`BBpfK7n<1iC3BQY^CJ~31=crlnU zt1;Oz<1y_q05S$LJ2F8sR5DvKVKRs^k20Dv!!pV;12cIvu{6Ro$TZwENyTO96Mb*T0E;f@H`$pK0Q=Dsy#41Qa)Hd zUOwJG0001h004LZ000CqJur(fvM|Ch$S~M2Krx>&;4&vOGc(aMLNrJ;PBdaPhBTBk zq%^@a6*cEI2R1)8mNvpR?lv4ZNjFhAU^q}Z_B#4IOFYm#^*qEq(>>um@;x6uH9kE) zNj_LUWV&M8abyt0001>000;O z005gYqcN2;r!(p|J~$IU00026001Ze006r%7&WamO*eWs%sSyZEjw2`yF1f68a!7# z<2>y=OFaO<000aC008 zU^3-0^D;LxSTiOxKr~7@sX7xoayz{{#yinF>pSy1!aO8BEIk@N0002+001Na007fB z-Zz{$$~gEq@j22vkv!Kt-8}Ls5&o=uu$2aRYUN~(yl|BFv0RSif003q)r5H|!kU^opq8#%N&LppRi z$U0v;Wjg>M0RRvH006x-lr@<*0000m0RS`r008PZNja7|(K-A%Dmwl;96Mw?mpczU zF+7JntUSp)`8+W_Q$2b;s67Ne0Y3mh0RS8T002!eQZSJ)dohbK!7;`$-ZAYl5H$c$ z0RRjD007N70001B0RTV%002WZZ8erP#xpLJkhCHJ@|2!r=#Xadg0001R0RT7v006f!zA@Y}@-g`_6*3|+Z8CH+k}{|= zu`0RRjD003(|hdcnV z0RVsi008tgpEuxjeo+9z7;K0002+0RSif005XVzcFevZ!?-R5H#X69W?0000W0suGw002BUM>kzJZa0WGnK!C8!8e0CjXJ72u{uLOeLk2z z#6HYEGe2oRl0UIO(LeD&0000m0stHU001N~E;UFsU^Z$tcs7nUJ~|OS0000$0st@o z003(;!ZV0BygAu9S30jc;5zO)KRbOpgF6pB9zHETJ3di9aXybep*{dm0swFT0018_ zGB83gUod4baWJzoZZ>o_zBa@*7B@jRM>knFUpJyRt~a_j;WzX*{Wo7YoH*Dx-Z%+4 zDLG0xUO8$xd^xB&D?4&LXgzX0oju1r&pq-z1wIWv89q2ZUp}QiB0o1jJwH!B0001B z0sve9006Qu&oCu1#4*${5;7Pv9x_5QS2ABRYchv2jWU5V*fZoa>@ylQAT=B}A~z^E zGB<)Zu{T6GemIIamN=j|s5rkk#W>42=r}VuKRIVPEIP$J0001R0su4s008wcY%$6) z0ss&I z008eaV>Wg>d^-TJ0strg007r8L^x77d^o#09y7^C_PF&+&%I=89q2Z0002c z0st%k0062qur${;>NX%ZCO5)6@;fCxFg;8?Zas)S<~^l9*+1ex^gjUL0ss^M0056L zlrSqYygI}>0002+0st@o001vBLNRqQoinR5lQ!2jC^uF&z&Y7DGCDmvNIFwG>pM$4 zlRN}HJv{&b0{{>J0031ur8wp|`8WU&0{|ER004k6mN6nSHZn*u#XieE0000W0{|QV z002)gS}J007@JA2dxr+dlw60|4Lv006@<#xc+_ z^)df35;7t(Try}ff-;OUw=%&p)H38U{xU){k~5eyq%#&YA~ZZSMl@_Rd^CbIpftZU z$u!e60yPXZIyFi)P&INj!!^$}<~8g!3N{-yAvQfWP&QmPsW$F5OgC0Hzc-j3NoECr!vDb*fJ+Gcr$`Csx!1RzBBbR zXg0Jq;5O^Jr|FgQIp^*9?jEIDU6e>s^sCOR`ZQaV^VZ93ID@H!1U zKs!-8k~_CM!8`RkMLbG`$v^Ht0001B0{{R4 z000m$CNMfMQ7~gLZ!m^1mN2C-zcA7;;xPI!7BMO@J268sOfg$AeldeFt}(PRzA?u! z%rV4+p zZ!?rLnlrgGzcb7;_A>@F4>TGyB{VBEH8ejoQ#4sL9W^mEKQ%=)Of{)Bxi!r-(lz!q z12z#h7&az0IW|W&O*T|ElQy9?uQtUt)Hdig?KUenK{rn~RX1ceb2p+lfH<)@(m3=u zG&x2&e>sym!8rgrD>^+oojOE2TRUw#n>(&Mz&kEHKs=Q^dp)u}cRm1c0{~0{|cZ006)_)H&EW+&Snu>^bl`^f~xB06GLZ2s!|;0{|ER008VU@G&ehFfwd1 za5AhiurdJ90{}n(001O2C^IZGcr$!6fHTN6%rww6)HK*M+%#x4Y&CE-bTxQ2d^LbI zs5q=RusF0hxH!Bxz&PAJ;5`7~0|00M008JX>^Sf^^f>r9{5SwP1UU#f3^@=vs5-1V zusXClxH`N#z&gY_$U4kA&^pvQ*gD)g;5y_w=sN5=@H+H5_&WSL06PRb2s;cr5IYn* z7&{z0AUh;GC_5}WFgr9mI6DCF0{{>J005*os5oFh000001OONS003MtU@#0a5Hb`p z7&06(ATj`81ON~K000ay7%&_#0001R1ON~K000Cq2rvvV5HJ7$000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 J00000005sre0u-@ diff --git a/src/Discord.Net.Audio/project.json b/src/Discord.Net.Audio/project.json deleted file mode 100644 index c41a619c7..000000000 --- a/src/Discord.Net.Audio/project.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": "1.0.0-alpha1", - "description": "A Discord.Net extension adding voice support.", - "authors": [ "RogueException" ], - "tags": [ "discord", "discordapp" ], - "projectUrl": "https://github.com/RogueException/Discord.Net", - "licenseUrl": "http://opensource.org/licenses/MIT", - "repository": { - "type": "git", - "url": "git://github.com/RogueException/Discord.Net" - }, - "compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], - "contentFiles": [ "libsodium.dll", "opus.dll" ], - - "compilationOptions": { - "allowUnsafe": true, - "warningsAsErrors": true - }, - - "dependencies": { - "Discord.Net": "1.0.0-alpha1" - }, - "frameworks": { - "net45": { }, - "dotnet5.4": { } - } -} diff --git a/src/Discord.Net.Commands/Command.cs b/src/Discord.Net.Commands/Command.cs deleted file mode 100644 index ccd62798b..000000000 --- a/src/Discord.Net.Commands/Command.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Discord.Commands.Permissions; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - //TODO: Make this more friendly and expose it to be extendable - public class Command - { - private string[] _aliases; - internal CommandParameter[] _parameters; - private IPermissionChecker[] _checks; - private Func _runFunc; - internal readonly Dictionary _parametersByName; - - public string Text { get; } - public string Category { get; internal set; } - public bool IsHidden { get; internal set; } - public string Description { get; internal set; } - - public IEnumerable Aliases => _aliases; - public IEnumerable Parameters => _parameters; - public CommandParameter this[string name] => _parametersByName[name]; - - internal Command(string text) - { - Text = text; - IsHidden = false; - _aliases = new string[0]; - _parameters = new CommandParameter[0]; - _parametersByName = new Dictionary(); - } - - - internal void SetAliases(string[] aliases) - { - _aliases = aliases; - } - internal void SetParameters(CommandParameter[] parameters) - { - _parametersByName.Clear(); - for (int i = 0; i < parameters.Length; i++) - { - parameters[i].Id = i; - _parametersByName[parameters[i].Name] = parameters[i]; - } - _parameters = parameters; - } - internal void SetChecks(IPermissionChecker[] checks) - { - _checks = checks; - } - - internal bool CanRun(User user, ITextChannel channel, out string error) - { - for (int i = 0; i < _checks.Length; i++) - { - if (!_checks[i].CanRun(this, user, channel, out error)) - return false; - } - error = null; - return true; - } - - internal void SetRunFunc(Func func) - { - _runFunc = func; - } - internal void SetRunFunc(Action func) - { - _runFunc = TaskHelper.ToAsync(func); - } - internal Task Run(CommandEventArgs args) - { - var task = _runFunc(args); - if (task != null) - return task; - else - return TaskHelper.CompletedTask; - } - } -} diff --git a/src/Discord.Net.Commands/CommandBuilder.cs b/src/Discord.Net.Commands/CommandBuilder.cs deleted file mode 100644 index 6b945841c..000000000 --- a/src/Discord.Net.Commands/CommandBuilder.cs +++ /dev/null @@ -1,163 +0,0 @@ -using Discord.Commands.Permissions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - //TODO: Make this more friendly and expose it to be extendable - public sealed class CommandBuilder - { - private readonly CommandService _service; - private readonly Command _command; - private readonly List _params; - private readonly List _checks; - private readonly List _aliases; - private readonly string _prefix; - private bool _allowRequiredParams, _areParamsClosed; - - public CommandService Service => _service; - - internal CommandBuilder(CommandService service, string text, string prefix = "", string category = "", IEnumerable initialChecks = null) - { - _service = service; - _prefix = prefix; - - _command = new Command(AppendPrefix(prefix, text)); - _command.Category = category; - - if (initialChecks != null) - _checks = new List(initialChecks); - else - _checks = new List(); - - _params = new List(); - _aliases = new List(); - - _allowRequiredParams = true; - _areParamsClosed = false; - } - - public CommandBuilder Alias(params string[] aliases) - { - _aliases.AddRange(aliases); - return this; - } - /*public CommandBuilder Category(string category) - { - _command.Category = category; - return this; - }*/ - public CommandBuilder Description(string description) - { - _command.Description = description; - return this; - } - public CommandBuilder Parameter(string name, ParameterType type = ParameterType.Required) - { - if (_areParamsClosed) - throw new Exception($"No parameters may be added after a {nameof(ParameterType.Multiple)} or {nameof(ParameterType.Unparsed)} parameter."); - if (!_allowRequiredParams && type == ParameterType.Required) - throw new Exception($"{nameof(ParameterType.Required)} parameters may not be added after an optional one"); - - _params.Add(new CommandParameter(name, type)); - - if (type == ParameterType.Optional) - _allowRequiredParams = false; - if (type == ParameterType.Multiple || type == ParameterType.Unparsed) - _areParamsClosed = true; - return this; - } - public CommandBuilder Hide() - { - _command.IsHidden = true; - return this; - } - public CommandBuilder AddCheck(IPermissionChecker check) - { - _checks.Add(check); - return this; - } - public CommandBuilder AddCheck(Func checkFunc, string errorMsg = null) - { - _checks.Add(new GenericPermissionChecker(checkFunc, errorMsg)); - return this; - } - - public void Do(Func func) - { - _command.SetRunFunc(func); - Build(); - } - public void Do(Action func) - { - _command.SetRunFunc(func); - Build(); - } - private void Build() - { - _command.SetParameters(_params.ToArray()); - _command.SetChecks(_checks.ToArray()); - _command.SetAliases(_aliases.Select(x => AppendPrefix(_prefix, x)).ToArray()); - _service.AddCommand(_command); - } - - internal static string AppendPrefix(string prefix, string cmd) - { - if (cmd != "") - { - if (prefix != "") - return prefix + ' ' + cmd; - else - return cmd; - } - else - return prefix; - } - } - public class CommandGroupBuilder - { - private readonly CommandService _service; - private readonly string _prefix; - private readonly List _checks; - private string _category; - - public CommandService Service => _service; - - internal CommandGroupBuilder(CommandService service, string prefix = "", string category = null, IEnumerable initialChecks = null) - { - _service = service; - _prefix = prefix; - _category = category; - if (initialChecks != null) - _checks = new List(initialChecks); - else - _checks = new List(); - } - - public CommandGroupBuilder Category(string category) - { - _category = category; - return this; - } - public void AddCheck(IPermissionChecker checker) - { - _checks.Add(checker); - } - public void AddCheck(Func checkFunc, string errorMsg = null) - { - _checks.Add(new GenericPermissionChecker(checkFunc, errorMsg)); - } - - public CommandGroupBuilder CreateGroup(string cmd, Action config) - { - config(new CommandGroupBuilder(_service, CommandBuilder.AppendPrefix(_prefix, cmd), _category, _checks)); - return this; - } - public CommandBuilder CreateCommand() - => CreateCommand(""); - public CommandBuilder CreateCommand(string cmd) - => new CommandBuilder(_service, cmd, _prefix, _category, _checks); - } -} diff --git a/src/Discord.Net.Commands/CommandErrorEventArgs.cs b/src/Discord.Net.Commands/CommandErrorEventArgs.cs deleted file mode 100644 index 5f47c6d7c..000000000 --- a/src/Discord.Net.Commands/CommandErrorEventArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace Discord.Commands -{ - public enum CommandErrorType { Exception, UnknownCommand, BadPermissions, BadArgCount, InvalidInput } - public class CommandErrorEventArgs : CommandEventArgs - { - public CommandErrorType ErrorType { get; } - public Exception Exception { get; } - - public CommandErrorEventArgs(CommandErrorType errorType, CommandEventArgs baseArgs, Exception ex) - : base(baseArgs.Message, baseArgs.Command, baseArgs.Args) - { - Exception = ex; - ErrorType = errorType; - } - } -} diff --git a/src/Discord.Net.Commands/CommandEventArgs.cs b/src/Discord.Net.Commands/CommandEventArgs.cs deleted file mode 100644 index 70793f5e1..000000000 --- a/src/Discord.Net.Commands/CommandEventArgs.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace Discord.Commands -{ - public class CommandEventArgs : EventArgs - { - private readonly string[] _args; - - public Message Message { get; } - public Command Command { get; } - - public User User => Message.User; - public ITextChannel Channel => Message.Channel; - - public CommandEventArgs(Message message, Command command, string[] args) - { - Message = message; - Command = command; - _args = args; - } - - public string[] Args => _args; - public string GetArg(int index) => _args[index]; - public string GetArg(string name) => _args[Command[name].Id]; - } -} diff --git a/src/Discord.Net.Commands/CommandExtensions.cs b/src/Discord.Net.Commands/CommandExtensions.cs deleted file mode 100644 index c57cf099f..000000000 --- a/src/Discord.Net.Commands/CommandExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace Discord.Commands -{ - public static class CommandExtensions - { - public static DiscordClient UsingCommands(this DiscordClient client, CommandServiceConfig config = null) - { - client.AddService(new CommandService(config)); - return client; - } - public static DiscordClient UsingCommands(this DiscordClient client, Action configFunc = null) - { - var builder = new CommandServiceConfigBuilder(); - configFunc(builder); - client.AddService(new CommandService(builder)); - return client; - } - } -} diff --git a/src/Discord.Net.Commands/CommandMap.cs b/src/Discord.Net.Commands/CommandMap.cs deleted file mode 100644 index ad280b335..000000000 --- a/src/Discord.Net.Commands/CommandMap.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Collections.Generic; - -namespace Discord.Commands -{ - //Represents either a single function, command group, or both - internal class CommandMap - { - private readonly CommandMap _parent; - private readonly string _name, _fullName; - - private readonly List _commands; - private readonly Dictionary _items; - private bool _isVisible, _hasNonAliases, _hasSubGroups; - - public string Name => _name; - public string FullName => _fullName; - public bool IsVisible => _isVisible; - public bool HasNonAliases => _hasNonAliases; - public bool HasSubGroups => _hasSubGroups; - public IEnumerable Commands => _commands; - public IEnumerable SubGroups => _items.Values; - - public CommandMap() - { - _items = new Dictionary(); - _commands = new List(); - _isVisible = false; - _hasNonAliases = false; - _hasSubGroups = false; - } - public CommandMap(CommandMap parent, string name, string fullName) - : this() - { - _parent = parent; - _name = name; - _fullName = fullName; - } - - public CommandMap GetItem(string text) - { - return GetItem(0, text.Split(' ')); - } - public CommandMap GetItem(int index, string[] parts) - { - if (index != parts.Length) - { - string nextPart = parts[index]; - CommandMap nextGroup; - if (_items.TryGetValue(nextPart.ToLowerInvariant(), out nextGroup)) - return nextGroup.GetItem(index + 1, parts); - else - return null; - } - return this; - } - - public IEnumerable GetCommands() - { - if (_commands.Count > 0) - return _commands; - else if (_parent != null) - return _parent.GetCommands(); - else - return null; - } - public IEnumerable GetCommands(string text) - { - return GetCommands(0, text.Split(' ')); - } - public IEnumerable GetCommands(int index, string[] parts) - { - if (index != parts.Length) - { - string nextPart = parts[index]; - CommandMap nextGroup; - if (_items.TryGetValue(nextPart.ToLowerInvariant(), out nextGroup)) - { - var cmd = nextGroup.GetCommands(index + 1, parts); - if (cmd != null) - return cmd; - } - } - - if (_commands != null) - return _commands; - return null; - } - - public void AddCommand(string text, Command command, bool isAlias) - { - AddCommand(0, text.Split(' '), command, isAlias); - } - private void AddCommand(int index, string[] parts, Command command, bool isAlias) - { - if (!command.IsHidden) - _isVisible = true; - - if (index != parts.Length) - { - CommandMap nextGroup; - string name = parts[index].ToLowerInvariant(); - string fullName = string.Join(" ", parts, 0, index + 1); - if (!_items.TryGetValue(name, out nextGroup)) - { - nextGroup = new CommandMap(this, name, fullName); - _items.Add(name, nextGroup); - _hasSubGroups = true; - } - nextGroup.AddCommand(index + 1, parts, command, isAlias); - } - else - { - _commands.Add(command); - if (!isAlias) - _hasNonAliases = true; - } - } - - public bool CanRun(User user, ITextChannel channel, out string error) - { - error = null; - if (_commands.Count > 0) - { - foreach (var cmd in _commands) - { - if (cmd.CanRun(user, channel, out error)) - return true; - } - } - if (_items.Count > 0) - { - foreach (var item in _items) - { - if (item.Value.CanRun(user, channel, out error)) - return true; - } - } - return false; - } - } -} diff --git a/src/Discord.Net.Commands/CommandParameter.cs b/src/Discord.Net.Commands/CommandParameter.cs deleted file mode 100644 index d7361bef4..000000000 --- a/src/Discord.Net.Commands/CommandParameter.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Discord.Commands -{ - public enum ParameterType - { - ///

Catches a single required parameter. - Required, - /// Catches a single optional parameter. - Optional, - /// Catches a zero or more optional parameters. - Multiple, - /// Catches all remaining text as a single optional parameter. - Unparsed - } - public class CommandParameter - { - public string Name { get; } - public int Id { get; internal set; } - public ParameterType Type { get; } - - internal CommandParameter(string name, ParameterType type) - { - Name = name; - Type = type; - } - } -} diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs deleted file mode 100644 index cfdbe6903..000000000 --- a/src/Discord.Net.Commands/CommandParser.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System.Collections.Generic; - -namespace Discord.Commands -{ - internal static class CommandParser - { - private enum ParserPart - { - None, - Parameter, - QuotedParameter, - DoubleQuotedParameter - } - - public static bool ParseCommand(string input, CommandMap map, out IEnumerable commands, out int endPos) - { - int startPosition = 0; - int endPosition = 0; - int inputLength = input.Length; - bool isEscaped = false; - commands = null; - endPos = 0; - - if (input == "") - return false; - - while (endPosition < inputLength) - { - char currentChar = input[endPosition++]; - if (isEscaped) - isEscaped = false; - else if (currentChar == '\\') - isEscaped = true; - - bool isWhitespace = IsWhiteSpace(currentChar); - if ((!isEscaped && isWhitespace) || endPosition >= inputLength) - { - int length = (isWhitespace ? endPosition - 1 : endPosition) - startPosition; - string temp = input.Substring(startPosition, length); - if (temp == "") - startPosition = endPosition; - else - { - var newMap = map.GetItem(temp); - if (newMap != null) - { - map = newMap; - endPos = endPosition; - } - else - break; - startPosition = endPosition; - } - } - } - commands = map.GetCommands(); //Work our way backwards to find a command that matches our input - return commands != null; - } - private static bool IsWhiteSpace(char c) => c == ' ' || c == '\n' || c == '\r' || c == '\t'; - - //TODO: Check support for escaping - public static CommandErrorType? ParseArgs(string input, int startPos, Command command, out string[] args) - { - ParserPart currentPart = ParserPart.None; - int startPosition = startPos; - int endPosition = startPos; - int inputLength = input.Length; - bool isEscaped = false; - - var expectedArgs = command._parameters; - List argList = new List(); - CommandParameter parameter = null; - - args = null; - - if (input == "") - return CommandErrorType.InvalidInput; - - while (endPosition < inputLength) - { - if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg - { - if (argList.Count >= expectedArgs.Length) - return CommandErrorType.BadArgCount; //Too many args - parameter = expectedArgs[argList.Count]; - if (parameter.Type == ParameterType.Unparsed) - { - argList.Add(input.Substring(startPosition)); - break; - } - } - - char currentChar = input[endPosition++]; - if (isEscaped) - isEscaped = false; - else if (currentChar == '\\') - isEscaped = true; - - bool isWhitespace = IsWhiteSpace(currentChar); - if (endPosition == startPosition + 1 && isWhitespace) //Has no text yet, and is another whitespace - { - startPosition = endPosition; - continue; - } - - switch (currentPart) - { - case ParserPart.None: - if ((!isEscaped && currentChar == '\"')) - { - currentPart = ParserPart.DoubleQuotedParameter; - startPosition = endPosition; - } - else if ((!isEscaped && currentChar == '\'')) - { - currentPart = ParserPart.QuotedParameter; - startPosition = endPosition; - } - else if ((!isEscaped && isWhitespace) || endPosition >= inputLength) - { - int length = (isWhitespace ? endPosition - 1 : endPosition) - startPosition; - if (length == 0) - startPosition = endPosition; - else - { - string temp = input.Substring(startPosition, length); - argList.Add(temp); - currentPart = ParserPart.None; - startPosition = endPosition; - } - } - break; - case ParserPart.QuotedParameter: - if ((!isEscaped && currentChar == '\'')) - { - string temp = input.Substring(startPosition, endPosition - startPosition - 1); - argList.Add(temp); - currentPart = ParserPart.None; - startPosition = endPosition; - } - else if (endPosition >= inputLength) - return CommandErrorType.InvalidInput; - break; - case ParserPart.DoubleQuotedParameter: - if ((!isEscaped && currentChar == '\"')) - { - string temp = input.Substring(startPosition, endPosition - startPosition - 1); - argList.Add(temp); - currentPart = ParserPart.None; - startPosition = endPosition; - } - else if (endPosition >= inputLength) - return CommandErrorType.InvalidInput; - break; - } - } - - //Unclosed quotes - if (currentPart == ParserPart.QuotedParameter || - currentPart == ParserPart.DoubleQuotedParameter) - return CommandErrorType.InvalidInput; - - //Too few args - for (int i = argList.Count; i < expectedArgs.Length; i++) - { - var param = expectedArgs[i]; - switch (param.Type) - { - case ParameterType.Required: - return CommandErrorType.BadArgCount; - case ParameterType.Optional: - case ParameterType.Unparsed: - argList.Add(""); - break; - } - } - - /*if (argList.Count > expectedArgs.Length) - { - if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple) - return CommandErrorType.BadArgCount; - }*/ - - args = argList.ToArray(); - return null; - } - } -} diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs deleted file mode 100644 index ea530d27b..000000000 --- a/src/Discord.Net.Commands/CommandService.cs +++ /dev/null @@ -1,347 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - public partial class CommandService : IService - { - private readonly List _allCommands; - private readonly Dictionary _categories; - private readonly CommandMap _map; //Command map stores all commands by their input text, used for fast resolving and parsing - - public CommandServiceConfig Config { get; } - public CommandGroupBuilder Root { get; } - public DiscordClient Client { get; private set; } - - //AllCommands store a flattened collection of all commands - public IEnumerable AllCommands => _allCommands; - //Groups store all commands by their module, used for more informative help - internal IEnumerable Categories => _categories.Values; - - public event EventHandler CommandExecuted = delegate { }; - public event EventHandler CommandErrored = delegate { }; - - private void OnCommand(CommandEventArgs args) - => CommandExecuted(this, args); - private void OnCommandError(CommandErrorType errorType, CommandEventArgs args, Exception ex = null) - => CommandErrored(this, new CommandErrorEventArgs(errorType, args, ex)); - - public CommandService() - : this(new CommandServiceConfigBuilder()) - { - } - public CommandService(CommandServiceConfigBuilder builder) - : this(builder.Build()) - { - if (builder.ExecuteHandler != null) - CommandExecuted += builder.ExecuteHandler; - if (builder.ErrorHandler != null) - CommandErrored += builder.ErrorHandler; - } - public CommandService(CommandServiceConfig config) - { - Config = config; - - _allCommands = new List(); - _map = new CommandMap(); - _categories = new Dictionary(); - Root = new CommandGroupBuilder(this); - } - - void IService.Install(DiscordClient client) - { - Client = client; - - if (Config.HelpMode != HelpMode.Disabled) - { - CreateCommand("help") - .Parameter("command", ParameterType.Multiple) - .Hide() - .Description("Returns information about commands.") - .Do(async e => - { - ITextChannel replyChannel = Config.HelpMode == HelpMode.Public ? e.Channel : await e.User.CreatePMChannel().ConfigureAwait(false); - if (e.Args.Length > 0) //Show command help - { - var map = _map.GetItem(string.Join(" ", e.Args)); - if (map != null) - await ShowCommandHelp(map, e.User, e.Channel, replyChannel).ConfigureAwait(false); - else - await replyChannel.SendMessage("Unable to display help: Unknown command.").ConfigureAwait(false); - } - else //Show general help - await ShowGeneralHelp(e.User, e.Channel, replyChannel).ConfigureAwait(false); - }); - } - - client.MessageReceived += async (s, e) => - { - if (_allCommands.Count == 0) return; - if (e.Message.User == null || e.Message.User.Id == Client.CurrentUser.Id) return; - - string msg = e.Message.RawText; - if (msg.Length == 0) return; - - string cmdMsg = null; - - //Check for command char - if (Config.PrefixChar.HasValue) - { - if (msg[0] == Config.PrefixChar.Value) - cmdMsg = msg.Substring(1); - } - - //Check for mention - if (cmdMsg == null && Config.AllowMentionPrefix) - { - string mention = client.CurrentUser.Mention; - if (msg.StartsWith(mention) && msg.Length > mention.Length) - cmdMsg = msg.Substring(mention.Length + 1); - else - { - mention = $"@{client.CurrentUser.Name}"; - if (msg.StartsWith(mention) && msg.Length > mention.Length) - cmdMsg = msg.Substring(mention.Length + 1); - } - } - - //Check using custom activator - if (cmdMsg == null && Config.CustomPrefixHandler != null) - { - int index = Config.CustomPrefixHandler(e.Message); - if (index >= 0) - cmdMsg = msg.Substring(index); - } - - if (cmdMsg == null) return; - - //Parse command - IEnumerable commands; - int argPos; - CommandParser.ParseCommand(cmdMsg, _map, out commands, out argPos); - if (commands == null) - { - CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null); - OnCommandError(CommandErrorType.UnknownCommand, errorArgs); - return; - } - else - { - foreach (var command in commands) - { - //Parse arguments - string[] args; - var error = CommandParser.ParseArgs(cmdMsg, argPos, command, out args); - if (error != null) - { - if (error == CommandErrorType.BadArgCount) - continue; - else - { - var errorArgs = new CommandEventArgs(e.Message, command, null); - OnCommandError(error.Value, errorArgs); - return; - } - } - - var eventArgs = new CommandEventArgs(e.Message, command, args); - - // Check permissions - string errorText; - if (!command.CanRun(eventArgs.User, eventArgs.Channel, out errorText)) - { - OnCommandError(CommandErrorType.BadPermissions, eventArgs, errorText != null ? new Exception(errorText) : null); - return; - } - - // Run the command - try - { - OnCommand(eventArgs); - await command.Run(eventArgs).ConfigureAwait(false); - } - catch (Exception ex) - { - OnCommandError(CommandErrorType.Exception, eventArgs, ex); - } - return; - } - var errorArgs2 = new CommandEventArgs(e.Message, null, null); - OnCommandError(CommandErrorType.BadArgCount, errorArgs2); - } - }; - } - - public Task ShowGeneralHelp(User user, ITextChannel channel, ITextChannel replyChannel = null) - { - StringBuilder output = new StringBuilder(); - bool isFirstCategory = true; - foreach (var category in _categories) - { - bool isFirstItem = true; - foreach (var group in category.Value.SubGroups) - { - string error; - if (group.IsVisible && (group.HasSubGroups || group.HasNonAliases) && group.CanRun(user, channel, out error)) - { - if (isFirstItem) - { - isFirstItem = false; - //This is called for the first item in each category. If we never get here, we dont bother writing the header for a category type (since it's empty) - if (isFirstCategory) - { - isFirstCategory = false; - //Called for the first non-empty category - output.AppendLine("These are the commands you can use:"); - } - else - output.AppendLine(); - if (category.Key != "") - { - output.Append(Format.Bold(category.Key)); - output.Append(": "); - } - } - else - output.Append(", "); - output.Append('`'); - output.Append(group.Name); - if (group.HasSubGroups) - output.Append("*"); - output.Append('`'); - } - } - } - - if (output.Length == 0) - output.Append("There are no commands you have permission to run."); - else - output.AppendLine("\n\nRun `help ` for more information."); - - return (replyChannel ?? channel).SendMessage(output.ToString()); - } - - private Task ShowCommandHelp(CommandMap map, User user, ITextChannel channel, ITextChannel replyChannel = null) - { - StringBuilder output = new StringBuilder(); - - IEnumerable cmds = map.Commands; - bool isFirstCmd = true; - string error; - if (cmds.Any()) - { - foreach (var cmd in cmds) - { - if (cmd.CanRun(user, channel, out error)) - { - if (isFirstCmd) - isFirstCmd = false; - else - output.AppendLine(); - ShowCommandHelpInternal(cmd, user, channel, output); - } - } - } - else - { - output.Append('`'); - output.Append(map.FullName); - output.Append("`\n"); - } - - bool isFirstSubCmd = true; - foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel, out error) && x.IsVisible)) - { - if (isFirstSubCmd) - { - isFirstSubCmd = false; - output.AppendLine("Sub Commands: "); - } - else - output.Append(", "); - output.Append('`'); - output.Append(subCmd.Name); - if (subCmd.SubGroups.Any()) - output.Append("*"); - output.Append('`'); - } - - if (isFirstCmd && isFirstSubCmd) //Had no commands and no subcommands - { - output.Clear(); - output.AppendLine("There are no commands you have permission to run."); - } - - return (replyChannel ?? channel).SendMessage(output.ToString()); - } - public Task ShowCommandHelp(Command command, User user, ITextChannel channel, ITextChannel replyChannel = null) - { - StringBuilder output = new StringBuilder(); - string error; - if (!command.CanRun(user, channel, out error)) - output.AppendLine(error ?? "You do not have permission to access this command."); - else - ShowCommandHelpInternal(command, user, channel, output); - return (replyChannel ?? channel).SendMessage(output.ToString()); - } - private void ShowCommandHelpInternal(Command command, User user, ITextChannel channel, StringBuilder output) - { - output.Append('`'); - output.Append(command.Text); - foreach (var param in command.Parameters) - { - switch (param.Type) - { - case ParameterType.Required: - output.Append($" <{param.Name}>"); - break; - case ParameterType.Optional: - output.Append($" [{param.Name}]"); - break; - case ParameterType.Multiple: - output.Append($" [{param.Name}...]"); - break; - case ParameterType.Unparsed: - output.Append($" [-]"); - break; - } - } - output.AppendLine("`"); - output.AppendLine($"{command.Description ?? "No description."}"); - - if (command.Aliases.Any()) - output.AppendLine($"Aliases: `" + string.Join("`, `", command.Aliases) + '`'); - } - - public void CreateGroup(string cmd, Action config = null) => Root.CreateGroup(cmd, config); - public CommandBuilder CreateCommand(string cmd) => Root.CreateCommand(cmd); - - internal void AddCommand(Command command) - { - _allCommands.Add(command); - - //Get category - CommandMap category; - string categoryName = command.Category ?? ""; - if (!_categories.TryGetValue(categoryName, out category)) - { - category = new CommandMap(); - _categories.Add(categoryName, category); - } - - //Add main command - category.AddCommand(command.Text, command, false); - _map.AddCommand(command.Text, command, false); - - //Add aliases - foreach (var alias in command.Aliases) - { - category.AddCommand(alias, command, true); - _map.AddCommand(alias, command, true); - } - } - } -} diff --git a/src/Discord.Net.Commands/CommandServiceConfig.cs b/src/Discord.Net.Commands/CommandServiceConfig.cs deleted file mode 100644 index f43c838fb..000000000 --- a/src/Discord.Net.Commands/CommandServiceConfig.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace Discord.Commands -{ - public class CommandServiceConfigBuilder - { - /// Gets or sets the prefix character used to trigger commands, if ActivationMode has the Char flag set. - public char? PrefixChar { get; set; } = null; - /// Gets or sets whether a message beginning with a mention to the logged-in user should be treated as a command. - public bool AllowMentionPrefix { get; set; } = true; - /// - /// Gets or sets a custom function used to detect messages that should be treated as commands. - /// This function should a positive one indicating the index of where the in the message's RawText the command begins, - /// and a negative value if the message should be ignored. - /// - public Func CustomPrefixHandler { get; set; } = null; - - /// Gets or sets whether a help function should be automatically generated. - public HelpMode HelpMode { get; set; } = HelpMode.Disabled; - - - /// Gets or sets a handler that is called on any successful command execution. - public EventHandler ExecuteHandler { get; set; } - /// Gets or sets a handler that is called on any error during command parsing or execution. - public EventHandler ErrorHandler { get; set; } - - public CommandServiceConfig Build() => new CommandServiceConfig(this); - } - public class CommandServiceConfig - { - public char? PrefixChar { get; } - public bool AllowMentionPrefix { get; } - public Func CustomPrefixHandler { get; } - - /// Gets or sets whether a help function should be automatically generated. - public HelpMode HelpMode { get; set; } = HelpMode.Disabled; - - internal CommandServiceConfig(CommandServiceConfigBuilder builder) - { - PrefixChar = builder.PrefixChar; - AllowMentionPrefix = builder.AllowMentionPrefix; - CustomPrefixHandler = builder.CustomPrefixHandler; - HelpMode = builder.HelpMode; - } - } -} diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.xproj b/src/Discord.Net.Commands/Discord.Net.Commands.xproj deleted file mode 100644 index 6c0d0ca91..000000000 --- a/src/Discord.Net.Commands/Discord.Net.Commands.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 19793545-ef89-48f4-8100-3ebaad0a9141 - Discord.Commands - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - True - - - \ No newline at end of file diff --git a/src/Discord.Net.Commands/GenericPermissionChecker.cs b/src/Discord.Net.Commands/GenericPermissionChecker.cs deleted file mode 100644 index 10d665811..000000000 --- a/src/Discord.Net.Commands/GenericPermissionChecker.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Discord.Commands.Permissions -{ - internal class GenericPermissionChecker : IPermissionChecker - { - private readonly Func _checkFunc; - private readonly string _error; - - public GenericPermissionChecker(Func checkFunc, string error = null) - { - _checkFunc = checkFunc; - _error = error; - } - - public bool CanRun(Command command, User user, ITextChannel channel, out string error) - { - error = _error; - return _checkFunc(command, user, channel); - } - } -} diff --git a/src/Discord.Net.Commands/HelpMode.cs b/src/Discord.Net.Commands/HelpMode.cs deleted file mode 100644 index 272403f42..000000000 --- a/src/Discord.Net.Commands/HelpMode.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Discord.Commands -{ - public enum HelpMode - { - /// Disable the automatic help command. - Disabled, - /// Use the automatic help command and respond in the channel the command is used. - Public, - /// Use the automatic help command and respond in a private message. - Private - } -} diff --git a/src/Discord.Net.Commands/IPermissionChecker.cs b/src/Discord.Net.Commands/IPermissionChecker.cs deleted file mode 100644 index 0f317ffef..000000000 --- a/src/Discord.Net.Commands/IPermissionChecker.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord.Commands.Permissions -{ - public interface IPermissionChecker - { - bool CanRun(Command command, User user, ITextChannel channel, out string error); - } -} diff --git a/src/Discord.Net.Commands/project.json b/src/Discord.Net.Commands/project.json deleted file mode 100644 index 124a29dfe..000000000 --- a/src/Discord.Net.Commands/project.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "1.0.0-alpha1", - "description": "A Discord.Net extension adding basic command support.", - "authors": [ "RogueException" ], - "tags": [ "discord", "discordapp" ], - "projectUrl": "https://github.com/RogueException/Discord.Net", - "licenseUrl": "http://opensource.org/licenses/MIT", - "repository": { - "type": "git", - "url": "git://github.com/RogueException/Discord.Net" - }, - "compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], - - "compilationOptions": { - "warningsAsErrors": true - }, - - "dependencies": { - "Discord.Net": "1.0.0-alpha1" - }, - "frameworks": { - "net45": { }, - "dotnet5.4": { } - } -} diff --git a/src/Discord.Net.Modules/Discord.Net.Modules.xproj b/src/Discord.Net.Modules/Discord.Net.Modules.xproj deleted file mode 100644 index 77112cd5d..000000000 --- a/src/Discord.Net.Modules/Discord.Net.Modules.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 01584e8a-78da-486f-9ef9-a894e435841b - Discord.Modules - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - True - - - \ No newline at end of file diff --git a/src/Discord.Net.Modules/IModule.cs b/src/Discord.Net.Modules/IModule.cs deleted file mode 100644 index 48a594eef..000000000 --- a/src/Discord.Net.Modules/IModule.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord.Modules -{ - public interface IModule - { - void Install(ModuleManager manager); - } -} diff --git a/src/Discord.Net.Modules/ModuleChecker.cs b/src/Discord.Net.Modules/ModuleChecker.cs deleted file mode 100644 index 5f9b8e116..000000000 --- a/src/Discord.Net.Modules/ModuleChecker.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Discord.Commands; -using Discord.Commands.Permissions; - -namespace Discord.Modules -{ - public class ModuleChecker : IPermissionChecker - { - private readonly ModuleManager _manager; - private readonly ModuleFilter _filterType; - - internal ModuleChecker(ModuleManager manager) - { - _manager = manager; - _filterType = manager.FilterType; - } - - public bool CanRun(Command command, User user, ITextChannel channel, out string error) - { - if (_filterType == ModuleFilter.None || - _filterType == ModuleFilter.AlwaysAllowPrivate || - (channel.IsPublic && _manager.HasChannel(channel))) - { - error = null; - return true; - } - else - { - error = "This module is currently disabled."; - return false; - } - } - } -} diff --git a/src/Discord.Net.Modules/ModuleExtensions.cs b/src/Discord.Net.Modules/ModuleExtensions.cs deleted file mode 100644 index a96517c06..000000000 --- a/src/Discord.Net.Modules/ModuleExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Discord.Modules -{ - public static class ModuleExtensions - { - public static DiscordClient UsingModules(this DiscordClient client) - { - client.AddService(new ModuleService()); - return client; - } - - public static void AddModule(this DiscordClient client, IModule instance, string name = null, ModuleFilter filter = ModuleFilter.None) - { - client.GetService().Add(instance, name, filter); - } - public static void AddModule(this DiscordClient client, string name = null, ModuleFilter filter = ModuleFilter.None) - where T : class, IModule, new() - { - client.GetService().Add(name, filter); - } - public static void AddModule(this DiscordClient client, T instance, string name = null, ModuleFilter filter = ModuleFilter.None) - where T : class, IModule - { - client.GetService().Add(instance, name, filter); - } - public static ModuleManager GetModule(this DiscordClient client) - where T : class, IModule - => client.GetService().Get(); - } -} diff --git a/src/Discord.Net.Modules/ModuleFilter.cs b/src/Discord.Net.Modules/ModuleFilter.cs deleted file mode 100644 index 08fa09a5d..000000000 --- a/src/Discord.Net.Modules/ModuleFilter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Discord.Modules -{ - [Flags] - public enum ModuleFilter - { - /// Disables the event and command filters. - None = 0x0, - /// Uses the server whitelist to filter events and commands. - ServerWhitelist = 0x1, - /// Uses the channel whitelist to filter events and commands. - ChannelWhitelist = 0x2, - /// Enables this module in all private messages. - AlwaysAllowPrivate = 0x4 - } -} diff --git a/src/Discord.Net.Modules/ModuleManager.cs b/src/Discord.Net.Modules/ModuleManager.cs deleted file mode 100644 index 71b5b0c08..000000000 --- a/src/Discord.Net.Modules/ModuleManager.cs +++ /dev/null @@ -1,278 +0,0 @@ -using Discord.Commands; -using Nito.AsyncEx; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; - -namespace Discord.Modules -{ - public class ModuleManager : ModuleManager - where T : class, IModule - { - public new T Instance => base.Instance as T; - - internal ModuleManager(DiscordClient client, T instance, string name, ModuleFilter filterType) - : base(client, instance, name, filterType) - { - } - } - - public class ModuleManager - { - public event EventHandler JoinedServer = delegate { }; - public event EventHandler LeftServer = delegate { }; - public event EventHandler ServerUpdated = delegate { }; - public event EventHandler ServerUnavailable = delegate { }; - public event EventHandler ServerAvailable = delegate { }; - - public event EventHandler ChannelCreated = delegate { }; - public event EventHandler ChannelDestroyed = delegate { }; - public event EventHandler ChannelUpdated = delegate { }; - - public event EventHandler RoleCreated = delegate { }; - public event EventHandler RoleUpdated = delegate { }; - public event EventHandler RoleDeleted = delegate { }; - - public event EventHandler UserBanned = delegate { }; - public event EventHandler UserJoined = delegate { }; - public event EventHandler UserLeft = delegate { }; - public event EventHandler UserUpdated = delegate { }; - public event EventHandler UserUnbanned = delegate { }; - public event EventHandler UserIsTyping = delegate { }; - - public event EventHandler MessageReceived = delegate { }; - public event EventHandler MessageSent = delegate { }; - public event EventHandler MessageDeleted = delegate { }; - public event EventHandler MessageUpdated = delegate { }; - public event EventHandler MessageReadRemotely = delegate { }; - - private readonly bool _useServerWhitelist, _useChannelWhitelist, _allowAll, _allowPrivate; - private readonly ConcurrentDictionary _enabledServers; - private readonly ConcurrentDictionary _enabledChannels; - private readonly ConcurrentDictionary _indirectServers; - private readonly AsyncLock _lock; - - public DiscordClient Client { get; } - public IModule Instance { get; } - public string Name { get; } - public string Id { get; } - public ModuleFilter FilterType { get; } - - public IEnumerable EnabledServers => _enabledServers.Select(x => x.Value); - public IEnumerable EnabledChannels => _enabledChannels.Select(x => x.Value); - - internal ModuleManager(DiscordClient client, IModule instance, string name, ModuleFilter filterType) - { - Client = client; - Instance = instance; - Name = name; - FilterType = filterType; - - Id = name.ToLowerInvariant(); - _lock = new AsyncLock(); - - _allowAll = filterType == ModuleFilter.None; - _useServerWhitelist = filterType.HasFlag(ModuleFilter.ServerWhitelist); - _useChannelWhitelist = filterType.HasFlag(ModuleFilter.ChannelWhitelist); - _allowPrivate = filterType.HasFlag(ModuleFilter.AlwaysAllowPrivate); - - _enabledServers = new ConcurrentDictionary(); - _enabledChannels = new ConcurrentDictionary(); - _indirectServers = new ConcurrentDictionary(); - - if (_allowAll || _useServerWhitelist) //Server-only events - { - client.ChannelCreated += (s, e) => - { - var server = (e.Channel as PublicChannel)?.Server; - if (HasServer(server)) - ChannelCreated(s, e); - }; - //TODO: This *is* a channel update if the before/after voice channel is whitelisted - //client.UserVoiceStateUpdated += (s, e) => { if (HasServer(e.Server)) UserVoiceStateUpdated(s, e); }; - } - - client.ChannelDestroyed += (s, e) => { if (HasChannel(e.Channel)) ChannelDestroyed(s, e); }; - client.ChannelUpdated += (s, e) => { if (HasChannel(e.After)) ChannelUpdated(s, e); }; - - client.MessageReceived += (s, e) => { if (HasChannel(e.Channel)) MessageReceived(s, e); }; - client.MessageSent += (s, e) => { if (HasChannel(e.Channel)) MessageSent(s, e); }; - client.MessageDeleted += (s, e) => { if (HasChannel(e.Channel)) MessageDeleted(s, e); }; - client.MessageUpdated += (s, e) => { if (HasChannel(e.Channel)) MessageUpdated(s, e); }; - client.MessageAcknowledged += (s, e) => { if (HasChannel(e.Channel)) MessageReadRemotely(s, e); }; - - client.RoleCreated += (s, e) => { if (HasIndirectServer(e.Server)) RoleCreated(s, e); }; - client.RoleUpdated += (s, e) => { if (HasIndirectServer(e.Server)) RoleUpdated(s, e); }; - client.RoleDeleted += (s, e) => { if (HasIndirectServer(e.Server)) RoleDeleted(s, e); }; - - client.JoinedServer += (s, e) => { if (_allowAll) JoinedServer(s, e); }; - client.LeftServer += (s, e) => { if (HasIndirectServer(e.Server)) LeftServer(s, e); }; - client.ServerUpdated += (s, e) => { if (HasIndirectServer(e.After)) ServerUpdated(s, e); }; - client.ServerUnavailable += (s, e) => { if (HasIndirectServer(e.Server)) ServerUnavailable(s, e); }; - client.ServerAvailable += (s, e) => { if (HasIndirectServer(e.Server)) ServerAvailable(s, e); }; - - client.UserJoined += (s, e) => { if (HasIndirectServer(e.Server)) UserJoined(s, e); }; - client.UserLeft += (s, e) => { if (HasIndirectServer(e.Server)) UserLeft(s, e); }; - //TODO: We aren't getting events from UserPresence if AllowPrivate is enabled, but the server we know that user through isn't on the whitelist - client.UserUpdated += (s, e) => { if (HasIndirectServer(e.Server)) UserUpdated(s, e); }; - client.UserIsTyping += (s, e) => { if (HasChannel(e.Channel)) UserIsTyping(s, e); }; - client.UserBanned += (s, e) => { if (HasIndirectServer(e.Server)) UserBanned(s, e); }; - client.UserUnbanned += (s, e) => { if (HasIndirectServer(e.Server)) UserUnbanned(s, e); }; - } - - public void CreateCommands(string prefix, Action config) - { - var commandService = Client.GetService(); - commandService.CreateGroup(prefix, x => - { - x.Category(Name); - x.AddCheck(new ModuleChecker(this)); - config(x); - }); - - } - public bool EnableServer(Server server) - { - if (server == null) throw new ArgumentNullException(nameof(server)); - if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); - - using (_lock.Lock()) - return EnableServerInternal(server); - } - public void EnableServers(IEnumerable servers) - { - if (servers == null) throw new ArgumentNullException(nameof(servers)); - if (servers.Contains(null)) throw new ArgumentException("Collection cannot contain null.", nameof(servers)); - if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); - - using (_lock.Lock()) - { - foreach (var server in servers) - EnableServerInternal(server); - } - } - private bool EnableServerInternal(Server server) => _enabledServers.TryAdd(server.Id, server); - - public bool DisableServer(Server server) - { - if (server == null) throw new ArgumentNullException(nameof(server)); - if (!_useServerWhitelist) return false; - - using (_lock.Lock()) - return _enabledServers.TryRemove(server.Id, out server); - } - public void DisableAllServers() - { - if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); - if (!_useServerWhitelist) return; - - using (_lock.Lock()) - _enabledServers.Clear(); - } - - public bool EnableChannel(ITextChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - if (!_useChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist."); - - using (_lock.Lock()) - return EnableChannelInternal(channel); - } - public void EnableChannels(IEnumerable channels) - { - if (channels == null) throw new ArgumentNullException(nameof(channels)); - if (channels.Contains(null)) throw new ArgumentException("Collection cannot contain null.", nameof(channels)); - if (!_useChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist."); - - using (_lock.Lock()) - { - foreach (var channel in channels) - EnableChannelInternal(channel); - } - } - private bool EnableChannelInternal(ITextChannel channel) - { - if (_enabledChannels.TryAdd(channel.Id, channel)) - { - if (channel.Type != ChannelType.Private) - { - var server = (channel as PublicChannel)?.Server; - int value = 0; - _indirectServers.TryGetValue(server.Id, out value); - value++; - _indirectServers[server.Id] = value; - } - return true; - } - return false; - } - - public bool DisableChannel(IChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - if (!_useChannelWhitelist) return false; - - IChannel ignored; - if (_enabledChannels.TryRemove(channel.Id, out ignored)) - { - using (_lock.Lock()) - { - if (channel.Type != ChannelType.Private) - { - var server = (channel as PublicChannel)?.Server; - int value = 0; - _indirectServers.TryGetValue(server.Id, out value); - value--; - if (value <= 0) - _indirectServers.TryRemove(server.Id, out value); - else - _indirectServers[server.Id] = value; - } - return true; - } - } - return false; - } - public void DisableAllChannels() - { - if (!_useChannelWhitelist) return; - - using (_lock.Lock()) - { - _enabledChannels.Clear(); - _indirectServers.Clear(); - } - } - - public void DisableAll() - { - if (_useServerWhitelist) - DisableAllServers(); - if (_useChannelWhitelist) - DisableAllChannels(); - } - - internal bool HasServer(Server server) => - _allowAll || - (_useServerWhitelist && _enabledServers.ContainsKey(server.Id)); - internal bool HasIndirectServer(Server server) => - _allowAll || - (_useServerWhitelist && _enabledServers.ContainsKey(server.Id)) || - (_useChannelWhitelist && _indirectServers.ContainsKey(server.Id)); - internal bool HasChannel(IChannel channel) - { - if (_allowAll) return true; - if (channel.Type == ChannelType.Private) return _allowPrivate; - - if (_useChannelWhitelist && _enabledChannels.ContainsKey(channel.Id)) return true; - if (_useServerWhitelist && channel.IsPublic) - { - var server = (channel as PublicChannel).Server; - if (server == null) return false; - if (_enabledServers.ContainsKey(server.Id)) return true; - } - return false; - } - } -} diff --git a/src/Discord.Net.Modules/ModuleService.cs b/src/Discord.Net.Modules/ModuleService.cs deleted file mode 100644 index 1f405a222..000000000 --- a/src/Discord.Net.Modules/ModuleService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Discord.Modules -{ - public class ModuleService : IService - { - public DiscordClient Client { get; private set; } - - private static readonly MethodInfo addMethod = typeof(ModuleService).GetTypeInfo().GetDeclaredMethods(nameof(Add)) - .Single(x => x.IsGenericMethodDefinition && x.GetParameters().Length == 3); - - public IEnumerable Modules => _modules.Values; - private readonly Dictionary _modules; - - public ModuleService() - { - _modules = new Dictionary(); - } - - void IService.Install(DiscordClient client) - { - Client = client; - } - - public void Add(IModule instance, string name, ModuleFilter filter) - { - Type type = instance.GetType(); - addMethod.MakeGenericMethod(type).Invoke(this, new object[] { instance, name, filter }); - } - public void Add(string name, ModuleFilter filter) - where T : class, IModule, new() - => Add(new T(), name, filter); - public void Add(T instance, string name, ModuleFilter filter) - where T : class, IModule - { - if (instance == null) throw new ArgumentNullException(nameof(instance)); - if (Client == null) - throw new InvalidOperationException("Service needs to be added to a DiscordClient before modules can be installed."); - - Type type = typeof(T); - if (name == null) name = type.Name; - if (_modules.ContainsKey(type)) - throw new InvalidOperationException("This module has already been added."); - - var manager = new ModuleManager(Client, instance, name, filter); - _modules.Add(type, manager); - instance.Install(manager); - } - public ModuleManager Get() - where T : class, IModule - { - ModuleManager manager; - if (_modules.TryGetValue(typeof(T), out manager)) - return manager as ModuleManager; - return null; - } - } -} diff --git a/src/Discord.Net.Modules/project.json b/src/Discord.Net.Modules/project.json deleted file mode 100644 index e8e897cac..000000000 --- a/src/Discord.Net.Modules/project.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "version": "1.0.0-alpha1", - "description": "A Discord.Net extension adding basic plugin support.", - "authors": [ "RogueException" ], - "tags": [ "discord", "discordapp" ], - "projectUrl": "https://github.com/RogueException/Discord.Net", - "licenseUrl": "http://opensource.org/licenses/MIT", - "repository": { - "type": "git", - "url": "git://github.com/RogueException/Discord.Net" - }, - "compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], - - "compilationOptions": { - "warningsAsErrors": true - }, - - "dependencies": { - "Discord.Net": "1.0.0-alpha1", - "Discord.Net.Commands": "1.0.0-alpha1" - }, - "frameworks": { - "net45": { }, - "dotnet5.4": { } - } -} diff --git a/src/Discord.Net.Shared/Discord.Net.Shared.projitems b/src/Discord.Net.Shared/Discord.Net.Shared.projitems deleted file mode 100644 index 38e4eafc8..000000000 --- a/src/Discord.Net.Shared/Discord.Net.Shared.projitems +++ /dev/null @@ -1,16 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 2875deb5-f248-4105-8ea2-5141e3de8025 - - - Discord.Net.Shared - - - - - - - \ No newline at end of file diff --git a/src/Discord.Net.Shared/Discord.Net.Shared.shproj b/src/Discord.Net.Shared/Discord.Net.Shared.shproj deleted file mode 100644 index 5d4d53951..000000000 --- a/src/Discord.Net.Shared/Discord.Net.Shared.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 2875deb5-f248-4105-8ea2-5141e3de8025 - 14.0 - - - - - - - - diff --git a/src/Discord.Net.Shared/EpochTime.cs b/src/Discord.Net.Shared/EpochTime.cs deleted file mode 100644 index b4dd03fe9..000000000 --- a/src/Discord.Net.Shared/EpochTime.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord -{ - internal class EpochTime - { - private const long epoch = 621355968000000000L; //1/1/1970 in Ticks - - public static long GetMilliseconds() => (DateTime.UtcNow.Ticks - epoch) / TimeSpan.TicksPerMillisecond; - } -} diff --git a/src/Discord.Net.Shared/TaskExtensions.cs b/src/Discord.Net.Shared/TaskExtensions.cs deleted file mode 100644 index 520114f02..000000000 --- a/src/Discord.Net.Shared/TaskExtensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord -{ - internal static class TaskExtensions - { - public static async Task Timeout(this Task task, int milliseconds) - { - Task timeoutTask = Task.Delay(milliseconds); - Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); - if (finishedTask == timeoutTask) - throw new TimeoutException(); - else - await task.ConfigureAwait(false); - } - public static async Task Timeout(this Task task, int milliseconds) - { - Task timeoutTask = Task.Delay(milliseconds); - Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); - if (finishedTask == timeoutTask) - throw new TimeoutException(); - else - return await task.ConfigureAwait(false); - } - public static async Task Timeout(this Task task, int milliseconds, CancellationTokenSource timeoutToken) - { - try - { - timeoutToken.CancelAfter(milliseconds); - await task.ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (timeoutToken.IsCancellationRequested) - throw new TimeoutException(); - throw; - } - } - public static async Task Timeout(this Task task, int milliseconds, CancellationTokenSource timeoutToken) - { - try - { - timeoutToken.CancelAfter(milliseconds); - return await task.ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (timeoutToken.IsCancellationRequested) - throw new TimeoutException(); - throw; - } - } - - public static async Task Wait(this CancellationTokenSource tokenSource) - { - var token = tokenSource.Token; - try { await Task.Delay(-1, token).ConfigureAwait(false); } - catch (OperationCanceledException) { } //Expected - } - public static async Task Wait(this CancellationToken token) - { - try { await Task.Delay(-1, token).ConfigureAwait(false); } - catch (OperationCanceledException) { } //Expected - } - } -} diff --git a/src/Discord.Net.Shared/TaskHelper.cs b/src/Discord.Net.Shared/TaskHelper.cs deleted file mode 100644 index 83408b8e9..000000000 --- a/src/Discord.Net.Shared/TaskHelper.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord -{ - internal static class TaskHelper - { -#if DOTNET54 - public static Task CompletedTask => Task.CompletedTask; -#else - public static Task CompletedTask => Task.Delay(0); -#endif - - public static Func ToAsync(Action action) - { - return () => - { - action(); return CompletedTask; - }; - } - public static Func ToAsync(Action action) - { - return x => - { - action(x); return CompletedTask; - }; - } - } -} diff --git a/src/Discord.Net/API/Client/Common/Channel.cs b/src/Discord.Net/API/Client/Common/Channel.cs deleted file mode 100644 index 37eac8e48..000000000 --- a/src/Discord.Net/API/Client/Common/Channel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class Channel : ChannelReference - { - public class PermissionOverwrite - { - [JsonProperty("type")] - public string Type { get; set; } - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("deny")] - public uint Deny { get; set; } - [JsonProperty("allow")] - public uint Allow { get; set; } - } - - [JsonProperty("last_message_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? LastMessageId { get; set; } - [JsonProperty("is_private")] - public bool? IsPrivate { get; set; } - [JsonProperty("position")] - public int? Position { get; set; } - [JsonProperty("topic")] - public string Topic { get; set; } - [JsonProperty("permission_overwrites")] - public PermissionOverwrite[] PermissionOverwrites { get; set; } - [JsonProperty("recipient")] - public UserReference Recipient { get; set; } - [JsonProperty("bitrate")] - public int Bitrate { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/ChannelReference.cs b/src/Discord.Net/API/Client/Common/ChannelReference.cs deleted file mode 100644 index a243e0f49..000000000 --- a/src/Discord.Net/API/Client/Common/ChannelReference.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class ChannelReference - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("guild_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? GuildId { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("type")] - public string Type { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/ExtendedMember.cs b/src/Discord.Net/API/Client/Common/ExtendedMember.cs deleted file mode 100644 index 890ec9de5..000000000 --- a/src/Discord.Net/API/Client/Common/ExtendedMember.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class ExtendedMember : Member - { - [JsonProperty("mute")] - public bool? IsServerMuted { get; set; } - [JsonProperty("deaf")] - public bool? IsServerDeafened { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/Guild.cs b/src/Discord.Net/API/Client/Common/Guild.cs deleted file mode 100644 index 1ee4a0b51..000000000 --- a/src/Discord.Net/API/Client/Common/Guild.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; -using System; - -namespace Discord.API.Client -{ - public class Guild : GuildReference - { - public class EmojiData - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] - public ulong[] RoleIds { get; set; } - [JsonProperty("require_colons")] - public bool RequireColons { get; set; } - [JsonProperty("managed")] - public bool IsManaged { get; set; } - } - - [JsonProperty("afk_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? AFKChannelId { get; set; } - [JsonProperty("afk_timeout")] - public int? AFKTimeout { get; set; } - [JsonProperty("embed_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? EmbedChannelId { get; set; } - [JsonProperty("embed_enabled")] - public bool EmbedEnabled { get; set; } - [JsonProperty("icon")] - public string Icon { get; set; } - [JsonProperty("joined_at")] - public DateTime? JoinedAt { get; set; } - [JsonProperty("owner_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? OwnerId { get; set; } - [JsonProperty("region")] - public string Region { get; set; } - [JsonProperty("roles")] - public Role[] Roles { get; set; } - [JsonProperty("features")] - public string[] Features { get; set; } - [JsonProperty("emojis")] - public EmojiData[] Emojis { get; set; } - [JsonProperty("splash")] - public string Splash { get; set; } - [JsonProperty("verification_level")] - public int VerificationLevel { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/GuildReference.cs b/src/Discord.Net/API/Client/Common/GuildReference.cs deleted file mode 100644 index 5b87c3cc2..000000000 --- a/src/Discord.Net/API/Client/Common/GuildReference.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class GuildReference - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/Invite.cs b/src/Discord.Net/API/Client/Common/Invite.cs deleted file mode 100644 index 571f551ee..000000000 --- a/src/Discord.Net/API/Client/Common/Invite.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace Discord.API.Client -{ - public class Invite : InviteReference - { - [JsonProperty("max_age")] - public int? MaxAge { get; set; } - [JsonProperty("max_uses")] - public int? MaxUses { get; set; } - [JsonProperty("revoked")] - public bool? IsRevoked { get; set; } - [JsonProperty("temporary")] - public bool? IsTemporary { get; set; } - [JsonProperty("uses")] - public int? Uses { get; set; } - [JsonProperty("created_at")] - public DateTime? CreatedAt { get; set; } - [JsonProperty("inviter")] - public UserReference Inviter { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/InviteReference.cs b/src/Discord.Net/API/Client/Common/InviteReference.cs deleted file mode 100644 index 194165173..000000000 --- a/src/Discord.Net/API/Client/Common/InviteReference.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class InviteReference - { - public class GuildData : GuildReference - { - [JsonProperty("splash_hash")] - public string Splash { get; set; } - } - - [JsonProperty("guild")] - public GuildData Guild { get; set; } - [JsonProperty("channel")] - public ChannelReference Channel { get; set; } - [JsonProperty("code")] - public string Code { get; set; } - [JsonProperty("xkcdpass")] - public string XkcdPass { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/Member.cs b/src/Discord.Net/API/Client/Common/Member.cs deleted file mode 100644 index 1af23c207..000000000 --- a/src/Discord.Net/API/Client/Common/Member.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; -using System; - -namespace Discord.API.Client -{ - public class Member : MemberReference - { - [JsonProperty("joined_at")] - public DateTime? JoinedAt { get; set; } - [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] - public ulong[] Roles { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/MemberPresence.cs b/src/Discord.Net/API/Client/Common/MemberPresence.cs deleted file mode 100644 index 589ad46c1..000000000 --- a/src/Discord.Net/API/Client/Common/MemberPresence.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class MemberPresence : MemberReference - { - public class GameInfo - { - [JsonProperty("name")] - public string Name { get; set; } - } - [JsonProperty("game")] - public GameInfo Game { get; set; } - [JsonProperty("status")] - public string Status { get; set; } - [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] - public ulong[] Roles { get; set; } //TODO: Might be temporary - } -} diff --git a/src/Discord.Net/API/Client/Common/MemberReference.cs b/src/Discord.Net/API/Client/Common/MemberReference.cs deleted file mode 100644 index ba6f37762..000000000 --- a/src/Discord.Net/API/Client/Common/MemberReference.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class MemberReference - { - [JsonProperty("guild_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? GuildId { get; set; } - [JsonProperty("user")] - public UserReference User { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/Message.cs b/src/Discord.Net/API/Client/Common/Message.cs deleted file mode 100644 index 7e9271dc9..000000000 --- a/src/Discord.Net/API/Client/Common/Message.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace Discord.API.Client -{ - public class Message : MessageReference - { - public class Attachment - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } - [JsonProperty("size")] - public int Size { get; set; } - [JsonProperty("filename")] - public string Filename { get; set; } - [JsonProperty("width")] - public int? Width { get; set; } - [JsonProperty("height")] - public int? Height { get; set; } - } - - public class Embed - { - public class Reference - { - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } - - public class ThumbnailInfo - { - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("proxy_url")] - public string ProxyUrl { get; set; } - [JsonProperty("width")] - public int? Width { get; set; } - [JsonProperty("height")] - public int? Height { get; set; } - } - public class VideoInfo - { - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("width")] - public int? Width { get; set; } - [JsonProperty("height")] - public int? Height { get; set; } - } - - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("type")] - public string Type { get; set; } - [JsonProperty("title")] - public string Title { get; set; } - [JsonProperty("description")] - public string Description { get; set; } - [JsonProperty("author")] - public Reference Author { get; set; } - [JsonProperty("provider")] - public Reference Provider { get; set; } - [JsonProperty("thumbnail")] - public ThumbnailInfo Thumbnail { get; set; } - [JsonProperty("video")] - public VideoInfo Video { get; set; } - } - - [JsonProperty("tts")] - public bool? IsTextToSpeech { get; set; } - [JsonProperty("mention_everyone")] - public bool? IsMentioningEveryone { get; set; } - [JsonProperty("timestamp")] - public DateTime? Timestamp { get; set; } - [JsonProperty("edited_timestamp")] - public DateTime? EditedTimestamp { get; set; } - [JsonProperty("mentions")] - public UserReference[] Mentions { get; set; } - [JsonProperty("embeds")] - public Embed[] Embeds { get; set; } //TODO: Parse this - [JsonProperty("attachments")] - public Attachment[] Attachments { get; set; } - [JsonProperty("content")] - public string Content { get; set; } - [JsonProperty("author")] - public UserReference Author { get; set; } - [JsonProperty("nonce")] - public string Nonce { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/MessageReference.cs b/src/Discord.Net/API/Client/Common/MessageReference.cs deleted file mode 100644 index c2afa6cd5..000000000 --- a/src/Discord.Net/API/Client/Common/MessageReference.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class MessageReference - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("message_id"), JsonConverter(typeof(LongStringConverter))] //Only used in MESSAGE_ACK - public ulong MessageId { get { return Id; } set { Id = value; } } - [JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] - public ulong ChannelId { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/RoleReference.cs b/src/Discord.Net/API/Client/Common/RoleReference.cs deleted file mode 100644 index ce7d25fcc..000000000 --- a/src/Discord.Net/API/Client/Common/RoleReference.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class RoleReference - { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] - public ulong GuildId { get; set; } - [JsonProperty("role_id"), JsonConverter(typeof(LongStringConverter))] - public ulong RoleId { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/User.cs b/src/Discord.Net/API/Client/Common/User.cs deleted file mode 100644 index 86c6f22f6..000000000 --- a/src/Discord.Net/API/Client/Common/User.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class User : UserReference - { - [JsonProperty("email")] - public string Email { get; set; } - [JsonProperty("verified")] - public bool? IsVerified { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Common/UserReference.cs b/src/Discord.Net/API/Client/Common/UserReference.cs deleted file mode 100644 index f2223df87..000000000 --- a/src/Discord.Net/API/Client/Common/UserReference.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client -{ - public class UserReference - { - [JsonProperty("username")] - public string Username { get; set; } - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("discriminator")] - public ushort? Discriminator { get; set; } - [JsonProperty("avatar")] - public string Avatar { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs b/src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs deleted file mode 100644 index 9f3f9cefb..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class HeartbeatCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; - object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); - bool IWebSocketMessage.IsPrivate => false; - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs deleted file mode 100644 index 06255bdcf..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.Client.GatewaySocket.Events -{ - //public class GuildEmojisUpdateEvent { } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs deleted file mode 100644 index 0767b2f8f..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.Client.GatewaySocket -{ - //public class GuildIntegrationsUpdateEvent { } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs deleted file mode 100644 index 311186b11..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.Client.GatewaySocket -{ - public class GuildMemberRemoveEvent : Member { } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs deleted file mode 100644 index 9b56a95b0..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.Client.GatewaySocket -{ - public class GuildMemberUpdateEvent : Member { } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs deleted file mode 100644 index 3d8e2f459..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.GatewaySocket -{ - public class GuildRoleCreateEvent - { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] - public ulong GuildId { get; set; } - [JsonProperty("role")] - public Role Data { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs deleted file mode 100644 index e26b65c4d..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.GatewaySocket -{ - public class GuildRoleUpdateEvent - { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] - public ulong GuildId { get; set; } - [JsonProperty("role")] - public Role Data { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs deleted file mode 100644 index 484cec1bc..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.GatewaySocket -{ - public class TypingStartEvent - { - [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] - public ulong UserId { get; set; } - [JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] - public ulong ChannelId { get; set; } - [JsonProperty("timestamp")] - public int Timestamp { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs deleted file mode 100644 index aad938157..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.Client.GatewaySocket -{ - //public class UserSettingsUpdateEvent { } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs b/src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs deleted file mode 100644 index d305642a1..000000000 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.GatewaySocket -{ - public class VoiceServerUpdateEvent - { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] - public ulong GuildId { get; set; } - [JsonProperty("endpoint")] - public string Endpoint { get; set; } - [JsonProperty("token")] - public string Token { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/ISerializable.cs b/src/Discord.Net/API/Client/ISerializable.cs deleted file mode 100644 index d23dc3c6c..000000000 --- a/src/Discord.Net/API/Client/ISerializable.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.IO; - -namespace Discord.API.Client -{ - public interface ISerializable - { - void Write(BinaryWriter writer); - } -} diff --git a/src/Discord.Net/API/Client/Rest/AcceptInvite.cs b/src/Discord.Net/API/Client/Rest/AcceptInvite.cs deleted file mode 100644 index 2940c98ac..000000000 --- a/src/Discord.Net/API/Client/Rest/AcceptInvite.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class AcceptInviteRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"invite/{InviteId}"; - object IRestRequest.Payload => null; - - public string InviteId { get; set; } - - public AcceptInviteRequest(string inviteId) - { - InviteId = inviteId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/AddGuildBan.cs b/src/Discord.Net/API/Client/Rest/AddGuildBan.cs deleted file mode 100644 index 3e0b165f5..000000000 --- a/src/Discord.Net/API/Client/Rest/AddGuildBan.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class AddGuildBanRequest : IRestRequest - { - string IRestRequest.Method => "PUT"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}?delete-message-days={PruneDays}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - public ulong UserId { get; set; } - - public int PruneDays { get; set; } = 0; - - public AddGuildBanRequest(ulong guildId, ulong userId) - { - GuildId = guildId; - UserId = userId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/DeleteRole.cs b/src/Discord.Net/API/Client/Rest/DeleteRole.cs deleted file mode 100644 index 56faf3d33..000000000 --- a/src/Discord.Net/API/Client/Rest/DeleteRole.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class DeleteRoleRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - public ulong RoleId { get; set; } - - public DeleteRoleRequest(ulong guildId, ulong roleId) - { - GuildId = guildId; - RoleId = roleId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/Gateway.cs b/src/Discord.Net/API/Client/Rest/Gateway.cs deleted file mode 100644 index 02dd71008..000000000 --- a/src/Discord.Net/API/Client/Rest/Gateway.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GatewayRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"gateway"; - object IRestRequest.Payload => null; - } - - public class GatewayResponse - { - [JsonProperty("url")] - public string Url { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Rest/GetBans.cs b/src/Discord.Net/API/Client/Rest/GetBans.cs deleted file mode 100644 index 714cdbaf8..000000000 --- a/src/Discord.Net/API/Client/Rest/GetBans.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetBansRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/bans"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - - public GetBansRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/GetInvite.cs b/src/Discord.Net/API/Client/Rest/GetInvite.cs deleted file mode 100644 index 2531ac26a..000000000 --- a/src/Discord.Net/API/Client/Rest/GetInvite.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetInviteRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"invite/{InviteCode}"; - object IRestRequest.Payload => null; - - public string InviteCode { get; set; } - - public GetInviteRequest(string inviteCode) - { - InviteCode = inviteCode; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/GetInvites.cs b/src/Discord.Net/API/Client/Rest/GetInvites.cs deleted file mode 100644 index 2b4f2f5fe..000000000 --- a/src/Discord.Net/API/Client/Rest/GetInvites.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetInvitesRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/invites"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - - public GetInvitesRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/GetMessages.cs b/src/Discord.Net/API/Client/Rest/GetMessages.cs deleted file mode 100644 index 1beadb9a9..000000000 --- a/src/Discord.Net/API/Client/Rest/GetMessages.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json; -using System.Text; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetMessagesRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint - { - get - { - StringBuilder query = new StringBuilder(); - this.AddQueryParam(query, "limit", Limit.ToString()); - if (RelativeDir != null) - this.AddQueryParam(query, RelativeDir, RelativeId.ToString()); - return $"channels/{ChannelId}/messages{query}"; - } - } - object IRestRequest.Payload => null; - - public ulong ChannelId { get; set; } - - public int Limit { get; set; } = 100; - public string RelativeDir { get; set; } = null; - public ulong RelativeId { get; set; } = 0; - - public GetMessagesRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/GetWidget.cs b/src/Discord.Net/API/Client/Rest/GetWidget.cs deleted file mode 100644 index 0437a8b6b..000000000 --- a/src/Discord.Net/API/Client/Rest/GetWidget.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetWidgetRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"servers/{GuildId}/widget.json"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - - public GetWidgetRequest(ulong guildId) - { - GuildId = guildId; - } - } - - public class GetWidgetResponse - { - public class Channel - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("position")] - public int Position { get; set; } - } - public class User : UserReference - { - [JsonProperty("avatar_url")] - public string AvatarUrl { get; set; } - [JsonProperty("status")] - public string Status { get; set; } - [JsonProperty("game")] - public UserGame Game { get; set; } - } - public class UserGame - { - [JsonProperty("id")] - public int Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } - - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("channels")] - public Channel[] Channels { get; set; } - [JsonProperty("members")] - public MemberReference[] Members { get; set; } - [JsonProperty("instant_invite")] - public string InstantInviteUrl { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Rest/KickMember.cs b/src/Discord.Net/API/Client/Rest/KickMember.cs deleted file mode 100644 index 4808f8543..000000000 --- a/src/Discord.Net/API/Client/Rest/KickMember.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class KickMemberRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - public ulong UserId { get; set; } - - public KickMemberRequest(ulong guildId, ulong userId) - { - GuildId = guildId; - UserId = userId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/Login.cs b/src/Discord.Net/API/Client/Rest/Login.cs deleted file mode 100644 index f9c89c717..000000000 --- a/src/Discord.Net/API/Client/Rest/Login.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class LoginRequest : IRestRequest - { - string IRestRequest.Method => Email != null ? "POST" : "GET"; - string IRestRequest.Endpoint => $"auth/login"; - object IRestRequest.Payload => this; - - [JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)] - public string Email { get; set; } - [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] - public string Password { get; set; } - } - - public class LoginResponse - { - [JsonProperty("token")] - public string Token { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Rest/Logout.cs b/src/Discord.Net/API/Client/Rest/Logout.cs deleted file mode 100644 index 9f4443c51..000000000 --- a/src/Discord.Net/API/Client/Rest/Logout.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class LogoutRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"auth/logout"; - object IRestRequest.Payload => null; - } -} diff --git a/src/Discord.Net/API/Client/Rest/PruneMembers.cs b/src/Discord.Net/API/Client/Rest/PruneMembers.cs deleted file mode 100644 index e80498bb1..000000000 --- a/src/Discord.Net/API/Client/Rest/PruneMembers.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class PruneMembersRequest : IRestRequest - { - string IRestRequest.Method => IsSimulation ? "GET" : "POST"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/prune?days={Days}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; set; } - - public int Days { get; set; } = 30; - public bool IsSimulation { get; set; } = false; - - public PruneMembersRequest(ulong guildId) - { - GuildId = guildId; - } - } - - public class PruneMembersResponse - { - [JsonProperty("pruned")] - public int Pruned { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs b/src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs deleted file mode 100644 index b453cba49..000000000 --- a/src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class RemoveChannelPermissionsRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; - object IRestRequest.Payload => null; - - public ulong ChannelId { get; set; } - public ulong TargetId { get; set; } - - public RemoveChannelPermissionsRequest(ulong channelId, ulong targetId) - { - ChannelId = channelId; - TargetId = targetId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/ReorderChannels.cs b/src/Discord.Net/API/Client/Rest/ReorderChannels.cs deleted file mode 100644 index c13f8b21c..000000000 --- a/src/Discord.Net/API/Client/Rest/ReorderChannels.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; -using System.Linq; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ReorderChannelsRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; - object IRestRequest.Payload - { - get - { - int pos = StartPos; - return ChannelIds.Select(x => new Channel(x, pos++)); - } - } - - public class Channel - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("position")] - public int Position { get; set; } - - public Channel(ulong id, int position) - { - Id = id; - Position = position; - } - } - - public ulong GuildId { get; set; } - - public ulong[] ChannelIds { get; set; } = new ulong[0]; - public int StartPos { get; set; } = 0; - - public ReorderChannelsRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/ReorderRoles.cs b/src/Discord.Net/API/Client/Rest/ReorderRoles.cs deleted file mode 100644 index 300176a76..000000000 --- a/src/Discord.Net/API/Client/Rest/ReorderRoles.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; -using System.Linq; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ReorderRolesRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; - object IRestRequest.Payload - { - get - { - int pos = StartPos; - return RoleIds.Select(x => new Role(x, pos++)); - } - } - - public class Role - { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong Id { get; set; } - [JsonProperty("position")] - public int Position { get; set; } - - public Role(ulong id, int pos) - { - Id = id; - Position = pos; - } - } - - public ulong GuildId { get; set; } - - public ulong[] RoleIds { get; set; } = new ulong[0]; - public int StartPos { get; set; } = 0; - - public ReorderRolesRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/SendIsTyping.cs b/src/Discord.Net/API/Client/Rest/SendIsTyping.cs deleted file mode 100644 index 4c56da0be..000000000 --- a/src/Discord.Net/API/Client/Rest/SendIsTyping.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class SendIsTypingRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/typing"; - object IRestRequest.Payload => null; - - public ulong ChannelId { get; set; } - - public SendIsTypingRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/UpdateGuild.cs b/src/Discord.Net/API/Client/Rest/UpdateGuild.cs deleted file mode 100644 index f36b18d9f..000000000 --- a/src/Discord.Net/API/Client/Rest/UpdateGuild.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class UpdateGuildRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"guilds/{GuildId}"; - object IRestRequest.Payload => this; - - public ulong GuildId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("region")] - public string Region { get; set; } - [JsonProperty("icon")] - public string IconBase64 { get; set; } - [JsonProperty("afk_channel_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? AFKChannelId { get; set; } - [JsonProperty("afk_timeout")] - public int AFKTimeout { get; set; } - [JsonProperty("splash")] - public object Splash { get; set; } - - public UpdateGuildRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Client/Rest/UpdateRole.cs b/src/Discord.Net/API/Client/Rest/UpdateRole.cs deleted file mode 100644 index 4bea0b52b..000000000 --- a/src/Discord.Net/API/Client/Rest/UpdateRole.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class UpdateRoleRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; - object IRestRequest.Payload => this; - - public ulong GuildId { get; set; } - public ulong RoleId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("permissions")] - public uint Permissions { get; set; } - [JsonProperty("hoist")] - public bool IsHoisted { get; set; } - [JsonProperty("color")] - public uint Color { get; set; } - - public UpdateRoleRequest(ulong guildId, ulong roleId) - { - GuildId = guildId; - RoleId = roleId; - } - } -} diff --git a/src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs b/src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs deleted file mode 100644 index 349a8a28b..000000000 --- a/src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord.API.Client.VoiceSocket -{ - public class HeartbeatCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; - object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); - bool IWebSocketMessage.IsPrivate => false; - } -} diff --git a/src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs b/src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs deleted file mode 100644 index fbb38b9d0..000000000 --- a/src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Discord.API.Converters; -using Newtonsoft.Json; - -namespace Discord.API.Client.VoiceSocket -{ - public class IdentifyCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCodes.Identify; - object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => true; - - [JsonProperty("server_id"), JsonConverter(typeof(LongStringConverter))] - public ulong GuildId { get; set; } - [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] - public ulong UserId { get; set; } - [JsonProperty("session_id")] - public string SessionId { get; set; } - [JsonProperty("token")] - public string Token { get; set; } - } -} diff --git a/src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs b/src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs deleted file mode 100644 index d860efe45..000000000 --- a/src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Client.VoiceSocket -{ - public class SelectProtocolCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCodes.SelectProtocol; - object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; - - public class Data - { - [JsonProperty("address")] - public string Address { get; set; } - [JsonProperty("port")] - public int Port { get; set; } - [JsonProperty("mode")] - public string Mode { get; set; } - } - [JsonProperty("protocol")] - public string Protocol { get; set; } = "udp"; - [JsonProperty("data")] - private Data ProtocolData { get; } = new Data(); - - public string ExternalAddress { get { return ProtocolData.Address; } set { ProtocolData.Address = value; } } - public int ExternalPort { get { return ProtocolData.Port; } set { ProtocolData.Port = value; } } - public string EncryptionMode { get { return ProtocolData.Mode; } set { ProtocolData.Mode = value; } } - } -} diff --git a/src/Discord.Net/API/Common/Attachment.cs b/src/Discord.Net/API/Common/Attachment.cs new file mode 100644 index 000000000..1f2c4b8b7 --- /dev/null +++ b/src/Discord.Net/API/Common/Attachment.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Attachment + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("filename")] + public string Filename { get; set; } + [JsonProperty("size")] + public int Size { get; set; } + [JsonProperty("url")] + public string Url { get; set; } + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } + [JsonProperty("height")] + public int? Height { get; set; } + [JsonProperty("width")] + public int? Width { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Channel.cs b/src/Discord.Net/API/Common/Channel.cs new file mode 100644 index 000000000..df71979a8 --- /dev/null +++ b/src/Discord.Net/API/Common/Channel.cs @@ -0,0 +1,37 @@ +#pragma warning disable CA1721 + +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Channel + { + //Shared + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("is_private")] + public bool IsPrivate { get; set; } + [JsonProperty("last_message_id")] + public ulong LastMessageId { get; set; } + + //GuildChannel + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + [JsonProperty("position")] + public int Position { get; set; } + [JsonProperty("permission_overwrites")] + public Overwrite[] PermissionOverwrites { get; set; } + [JsonProperty("topic")] + public string Topic { get; set; } + [JsonProperty("bitrate")] + public int Bitrate { get; set; } + + //DMChannel + [JsonProperty("recipient")] + public User Recipient { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Embed.cs b/src/Discord.Net/API/Common/Embed.cs new file mode 100644 index 000000000..a75bdb636 --- /dev/null +++ b/src/Discord.Net/API/Common/Embed.cs @@ -0,0 +1,21 @@ +#pragma warning disable CA1721 +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Embed + { + [JsonProperty("title")] + public string Title { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + [JsonProperty("description")] + public string Description { get; set; } + [JsonProperty("url")] + public string Url { get; set; } + [JsonProperty("thumbnail")] + public EmbedThumbnail Thumbnail { get; set; } + [JsonProperty("provider")] + public EmbedProvider Provider { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/EmbedProvider.cs b/src/Discord.Net/API/Common/EmbedProvider.cs new file mode 100644 index 000000000..22c9cbaeb --- /dev/null +++ b/src/Discord.Net/API/Common/EmbedProvider.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class EmbedProvider + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("url")] + public string Url { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/EmbedThumbnail.cs b/src/Discord.Net/API/Common/EmbedThumbnail.cs new file mode 100644 index 000000000..73fe3472d --- /dev/null +++ b/src/Discord.Net/API/Common/EmbedThumbnail.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class EmbedThumbnail + { + [JsonProperty("url")] + public string Url { get; set; } + [JsonProperty("proxy_url")] + public string ProxyUrl { get; set; } + [JsonProperty("height")] + public int? Height { get; set; } + [JsonProperty("width")] + public int? Width { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Emoji.cs b/src/Discord.Net/API/Common/Emoji.cs new file mode 100644 index 000000000..1787c430c --- /dev/null +++ b/src/Discord.Net/API/Common/Emoji.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Emoji + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("roles")] + public ulong[] Roles { get; set; } + [JsonProperty("require_colons")] + public bool RequireColons { get; set; } + [JsonProperty("managed")] + public bool Managed { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Guild.cs b/src/Discord.Net/API/Common/Guild.cs new file mode 100644 index 000000000..cbd50e390 --- /dev/null +++ b/src/Discord.Net/API/Common/Guild.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Guild + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("icon")] + public string Icon { get; set; } + [JsonProperty("splash")] + public string Splash { get; set; } + [JsonProperty("owner_id")] + public ulong OwnerId { get; set; } + [JsonProperty("region")] + public string Region { get; set; } + [JsonProperty("afk_channel_id")] + public ulong? AFKChannelId { get; set; } + [JsonProperty("afk_timeout")] + public int AFKTimeout { get; set; } + [JsonProperty("embed_enabled")] + public bool EmbedEnabled { get; set; } + [JsonProperty("embed_channel_id")] + public ulong? EmbedChannelId { get; set; } + [JsonProperty("verification_level")] + public int VerificationLevel { get; set; } + [JsonProperty("roles")] + public Role[] Roles { get; set; } + [JsonProperty("emojis")] + public Emoji[] Emojis { get; set; } + [JsonProperty("features")] + public string[] Features { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/GuildEmbed.cs b/src/Discord.Net/API/Common/GuildEmbed.cs new file mode 100644 index 000000000..9aceaa472 --- /dev/null +++ b/src/Discord.Net/API/Common/GuildEmbed.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class GuildEmbed + { + [JsonProperty("enabled")] + public bool Enabled { get; set; } + [JsonProperty("channel_id")] + public ulong? ChannelId { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/GuildMember.cs b/src/Discord.Net/API/Common/GuildMember.cs new file mode 100644 index 000000000..c28d47d34 --- /dev/null +++ b/src/Discord.Net/API/Common/GuildMember.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + public class GuildMember + { + [JsonProperty("user")] + public User User { get; set; } + [JsonProperty("roles")] + public ulong[] Roles { get; set; } + [JsonProperty("joined_at")] + public DateTime?JoinedAt { get; set; } + [JsonProperty("deaf")] + public bool Deaf { get; set; } + [JsonProperty("mute")] + public bool Mute { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Integration.cs b/src/Discord.Net/API/Common/Integration.cs new file mode 100644 index 000000000..9b14a0cd4 --- /dev/null +++ b/src/Discord.Net/API/Common/Integration.cs @@ -0,0 +1,32 @@ +#pragma warning disable CA1721 +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + public class Integration + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + [JsonProperty("enabled")] + public bool Enabled { get; set; } + [JsonProperty("syncing")] + public bool Syncing { get; set; } + [JsonProperty("role_id")] + public ulong RoleId { get; set; } + [JsonProperty("expire_behavior")] + public ulong ExpireBehavior { get; set; } + [JsonProperty("expire_grace_period")] + public ulong ExpireGracePeriod { get; set; } + [JsonProperty("user")] + public User User { get; set; } + [JsonProperty("account")] + public IntegrationAccount Account { get; set; } + [JsonProperty("synced_at")] + public DateTime SyncedAt { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/IntegrationAccount.cs b/src/Discord.Net/API/Common/IntegrationAccount.cs new file mode 100644 index 000000000..77645caaa --- /dev/null +++ b/src/Discord.Net/API/Common/IntegrationAccount.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class IntegrationAccount + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Invite.cs b/src/Discord.Net/API/Common/Invite.cs new file mode 100644 index 000000000..276314560 --- /dev/null +++ b/src/Discord.Net/API/Common/Invite.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Invite + { + [JsonProperty("code")] + public string Code { get; set; } + [JsonProperty("guild")] + public InviteGuild Guild { get; set; } + [JsonProperty("channel")] + public InviteChannel Channel { get; set; } + [JsonProperty("xkcdpass")] + public string XkcdPass { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/InviteChannel.cs b/src/Discord.Net/API/Common/InviteChannel.cs new file mode 100644 index 000000000..545d5fecd --- /dev/null +++ b/src/Discord.Net/API/Common/InviteChannel.cs @@ -0,0 +1,15 @@ +#pragma warning disable CA1721 +using Newtonsoft.Json; + +namespace Discord.API +{ + public class InviteChannel + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/InviteGuild.cs b/src/Discord.Net/API/Common/InviteGuild.cs new file mode 100644 index 000000000..7800a71ea --- /dev/null +++ b/src/Discord.Net/API/Common/InviteGuild.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class InviteGuild + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("splash_hash")] + public string SplashHash { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/InviteMetadata.cs b/src/Discord.Net/API/Common/InviteMetadata.cs new file mode 100644 index 000000000..55eeebeee --- /dev/null +++ b/src/Discord.Net/API/Common/InviteMetadata.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + public class InviteMetadata : Invite + { + [JsonProperty("inviter")] + public User Inviter { get; set; } + [JsonProperty("uses")] + public int Uses { get; set; } + [JsonProperty("max_uses")] + public int MaxUses { get; set; } + [JsonProperty("max_age")] + public int MaxAge { get; set; } + [JsonProperty("temporary")] + public bool Temporary { get; set; } + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + [JsonProperty("revoked")] + public bool Revoked { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Message.cs b/src/Discord.Net/API/Common/Message.cs new file mode 100644 index 000000000..666c73652 --- /dev/null +++ b/src/Discord.Net/API/Common/Message.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + public class Message + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + [JsonProperty("author")] + public User Author { get; set; } + [JsonProperty("content")] + public string Content { get; set; } + [JsonProperty("timestamp")] + public DateTime Timestamp { get; set; } + [JsonProperty("edited_timestamp")] + public DateTime? EditedTimestamp { get; set; } + [JsonProperty("tts")] + public bool IsTextToSpeech { get; set; } + [JsonProperty("mention_everyone")] + public bool IsMentioningEveryone { get; set; } + [JsonProperty("mentions")] + public User[] Mentions { get; set; } + [JsonProperty("attachments")] + public Attachment[] Attachments { get; set; } + [JsonProperty("embeds")] + public Embed[] Embeds { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/ReadState.cs b/src/Discord.Net/API/Common/ReadState.cs new file mode 100644 index 000000000..6fa0c9b6e --- /dev/null +++ b/src/Discord.Net/API/Common/ReadState.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class ReadState + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("mention_count")] + public int MentionCount { get; set; } + [JsonProperty("last_message_id")] + public ulong LastMentionId { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Unconfirmed/Connection.cs b/src/Discord.Net/API/Common/Unconfirmed/Connection.cs new file mode 100644 index 000000000..2c82d6cf2 --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/Connection.cs @@ -0,0 +1,19 @@ +#pragma warning disable CA1721 +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Connection + { + [JsonProperty("integrations")] + public Integration[] Integrations { get; set; } + [JsonProperty("revoked")] + public bool Revoked { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/Common/ExtendedGuild.cs b/src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs similarity index 95% rename from src/Discord.Net/API/Client/Common/ExtendedGuild.cs rename to src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs index 63c55eddb..00aaeb7b9 100644 --- a/src/Discord.Net/API/Client/Common/ExtendedGuild.cs +++ b/src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client +namespace Discord.API { public class ExtendedGuild : Guild { diff --git a/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs b/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs new file mode 100644 index 000000000..f09c12e0c --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class ExtendedMember : GuildMember + { + [JsonProperty("mute")] + public bool? IsMuted { get; set; } + [JsonProperty("deaf")] + public bool? IsDeafened { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs b/src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs new file mode 100644 index 000000000..a57630ed1 --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs @@ -0,0 +1,15 @@ +#pragma warning disable CA1721 +using Newtonsoft.Json; + +namespace Discord.API +{ + public class MemberPresence : MemberReference + { + [JsonProperty("game")] + public MemberPresenceGame Game { get; set; } + [JsonProperty("status")] + public UserStatus Status { get; set; } + [JsonProperty("roles")] + public ulong[] Roles { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs b/src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs new file mode 100644 index 000000000..acd805548 --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class MemberPresenceGame + { + [JsonProperty("name")] + public string Name { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs b/src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs new file mode 100644 index 000000000..edc41f688 --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class MemberReference + { + [JsonProperty("guild_id")] + public ulong? GuildId { get; set; } + [JsonProperty("user")] + public User User { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/Common/MemberVoiceState.cs b/src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs similarity index 55% rename from src/Discord.Net/API/Client/Common/MemberVoiceState.cs rename to src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs index 4aab1774c..b79df1790 100644 --- a/src/Discord.Net/API/Client/Common/MemberVoiceState.cs +++ b/src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs @@ -1,16 +1,15 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client +namespace Discord.API { public class MemberVoiceState { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("guild_id")] public ulong GuildId { get; set; } - [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("user_id")] public ulong UserId { get; set; } - [JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] + [JsonProperty("channel_id")] public ulong? ChannelId { get; set; } [JsonProperty("session_id")] public string SessionId { get; set; } @@ -22,10 +21,10 @@ namespace Discord.API.Client [JsonProperty("self_deaf")] public bool? IsSelfDeafened { get; set; } [JsonProperty("mute")] - public bool? IsServerMuted { get; set; } + public bool? IsMuted { get; set; } [JsonProperty("deaf")] - public bool? IsServerDeafened { get; set; } + public bool? IsDeafened { get; set; } [JsonProperty("suppress")] - public bool? IsServerSuppressed { get; set; } + public bool? IsSuppressed { get; set; } } } diff --git a/src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs b/src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs new file mode 100644 index 000000000..d2c1dd268 --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class MessageReference + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("message_id")] //Only used in MESSAGE_ACK + public ulong MessageId { get { return Id; } set { Id = value; } } + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs b/src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs new file mode 100644 index 000000000..f1da83b9e --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class Overwrite + { + [JsonProperty("id")] + public ulong TargetId { get; set; } + [JsonProperty("type")] + public PermissionTarget TargetType { get; set; } + [JsonProperty("deny")] + public uint Deny { get; set; } + [JsonProperty("allow")] + public uint Allow { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/Common/Role.cs b/src/Discord.Net/API/Common/Unconfirmed/Role.cs similarity index 77% rename from src/Discord.Net/API/Client/Common/Role.cs rename to src/Discord.Net/API/Common/Unconfirmed/Role.cs index 59431989a..e561ab355 100644 --- a/src/Discord.Net/API/Client/Common/Role.cs +++ b/src/Discord.Net/API/Common/Unconfirmed/Role.cs @@ -1,11 +1,10 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client +namespace Discord.API { public class Role { - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("id")] public ulong Id { get; set; } [JsonProperty("permissions")] public uint? Permissions { get; set; } diff --git a/src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs b/src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs new file mode 100644 index 000000000..bf516faaa --- /dev/null +++ b/src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class RoleReference + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("role_id")] + public ulong RoleId { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/User.cs b/src/Discord.Net/API/Common/User.cs new file mode 100644 index 000000000..c8e566711 --- /dev/null +++ b/src/Discord.Net/API/Common/User.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class User + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("username")] + public string Username { get; set; } + [JsonProperty("discriminator")] + public ushort Discriminator { get; set; } + [JsonProperty("avatar")] + public string Avatar { get; set; } + [JsonProperty("verified")] + public bool IsVerified { get; set; } + [JsonProperty("email")] + public string Email { get; set; } + [JsonProperty("bot")] + public bool Bot { get; set; } + } +} diff --git a/src/Discord.Net/API/Common/UserGuild.cs b/src/Discord.Net/API/Common/UserGuild.cs new file mode 100644 index 000000000..9b0819395 --- /dev/null +++ b/src/Discord.Net/API/Common/UserGuild.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + public class UserGuild + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("icon")] + public string Icon { get; set; } + [JsonProperty("owner")] + public bool Owner { get; set; } + } +} diff --git a/src/Discord.Net/API/Converters.cs b/src/Discord.Net/API/Converters.cs deleted file mode 100644 index 5d80ca99f..000000000 --- a/src/Discord.Net/API/Converters.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using Newtonsoft.Json; -using System.Collections.Generic; - -namespace Discord.API.Converters -{ - public class LongStringConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - => objectType == typeof(ulong); - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - => ((string)reader.Value).ToId(); - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - => writer.WriteValue(((ulong)value).ToIdString()); - } - - public class NullableLongStringConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - => objectType == typeof(ulong?); - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - => ((string)reader.Value).ToNullableId(); - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - => writer.WriteValue(((ulong?)value).ToIdString()); - } - - /*public class LongStringEnumerableConverter : JsonConverter - { - public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable); - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - List result = new List(); - if (reader.TokenType == JsonToken.StartArray) - { - reader.Read(); - while (reader.TokenType != JsonToken.EndArray) - { - result.Add(IdConvert.ToLong((string)reader.Value)); - reader.Read(); - } - } - return result; - } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value == null) - writer.WriteNull(); - else - { - writer.WriteStartArray(); - foreach (var v in (IEnumerable)value) - writer.WriteValue(IdConvert.ToString(v)); - writer.WriteEndArray(); - } - } - }*/ - - internal class LongStringArrayConverter : JsonConverter - { - public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable); - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var result = new List(); - if (reader.TokenType == JsonToken.StartArray) - { - reader.Read(); - while (reader.TokenType != JsonToken.EndArray) - { - result.Add(((string)reader.Value).ToId()); - reader.Read(); - } - } - return result.ToArray(); - } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value == null) - writer.WriteNull(); - else - { - writer.WriteStartArray(); - var a = (ulong[])value; - for (int i = 0; i < a.Length; i++) - writer.WriteValue(a[i].ToIdString()); - writer.WriteEndArray(); - } - } - } -} diff --git a/src/Discord.Net/API/Extensions.cs b/src/Discord.Net/API/Extensions.cs deleted file mode 100644 index 77d25fe4e..000000000 --- a/src/Discord.Net/API/Extensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Text; - -namespace Discord.API -{ - internal static class RestRequestExtensions - { - public static void AddQueryParam(this IRestRequest request, StringBuilder builder, string name, string value) - { - if (builder.Length == 0) - builder.Append('?'); - else - builder.Append('&'); - builder.Append(Uri.EscapeDataString(name)); - builder.Append('='); - builder.Append(Uri.EscapeDataString(value)); - } - } -} diff --git a/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs b/src/Discord.Net/API/GatewaySocket/OpCode.cs similarity index 67% rename from src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs rename to src/Discord.Net/API/GatewaySocket/OpCode.cs index 9942c670e..cf8e142ef 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs +++ b/src/Discord.Net/API/GatewaySocket/OpCode.cs @@ -1,6 +1,6 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { - public enum OpCodes : byte + public enum OpCode : byte { /// C←S - Used to send most events. Dispatch = 0, @@ -12,13 +12,15 @@ StatusUpdate = 3, /// C→S - Used to join a particular voice channel. VoiceStateUpdate = 4, - /// C→S - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. + /// C→S - Used to ensure the guild's voice server is alive. Only send this if voice connection fails or suddenly drops. VoiceServerPing = 5, /// C→S - Used to resume a connection after a redirect occurs. Resume = 6, /// C←S - Used to notify a client that they must reconnect to another gateway. - Redirect = 7, - /// C→S - Used to request all members that were withheld by large_threshold - RequestGuildMembers = 8 + Reconnect = 7, + /// C→S - Used to request all members that were withheld by large_threshold. + RequestGuildMembers = 8, + /// C←S - Used to notify the client of an invalid session id. + InvalidSession = 9 } } diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs new file mode 100644 index 000000000..5dac73ec5 --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API.GatewaySocket +{ + [JsonObject(MemberSerialization.OptIn)] + public class HeartbeatCommand : IWebSocketMessage + { + int IWebSocketMessage.OpCode => (int)OpCode.Heartbeat; + object IWebSocketMessage.Payload => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/Identify.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs similarity index 73% rename from src/Discord.Net/API/Client/GatewaySocket/Commands/Identify.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs index 8437f595c..235f615ef 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/Identify.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs @@ -1,21 +1,20 @@ using Newtonsoft.Json; using System.Collections.Generic; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { [JsonObject(MemberSerialization.OptIn)] public class IdentifyCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.Identify; + int IWebSocketMessage.OpCode => (int)OpCode.Identify; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; [JsonProperty("v")] public int Version { get; set; } [JsonProperty("token")] public string Token { get; set; } [JsonProperty("properties")] - public Dictionary Properties { get; set; } + public IReadOnlyDictionary Properties { get; set; } [JsonProperty("large_threshold", NullValueHandling = NullValueHandling.Ignore)] public int LargeThreshold { get; set; } [JsonProperty("compress")] diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/RequestMembers.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs similarity index 53% rename from src/Discord.Net/API/Client/GatewaySocket/Commands/RequestMembers.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs index cc3c93176..c4614284d 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/RequestMembers.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs @@ -1,16 +1,14 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { [JsonObject(MemberSerialization.OptIn)] public class RequestMembersCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.RequestGuildMembers; + int IWebSocketMessage.OpCode => (int)OpCode.RequestGuildMembers; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringArrayConverter))] + [JsonProperty("guild_id")] public ulong[] GuildId { get; set; } [JsonProperty("query")] public string Query { get; set; } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/Resume.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs similarity index 69% rename from src/Discord.Net/API/Client/GatewaySocket/Commands/Resume.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs index 15486e577..1525c6b6a 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/Resume.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { [JsonObject(MemberSerialization.OptIn)] public class ResumeCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.Resume; + int IWebSocketMessage.OpCode => (int)OpCode.Resume; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; [JsonProperty("session_id")] public string SessionId { get; set; } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateStatus.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs similarity index 74% rename from src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateStatus.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs index dff18b08c..8aa22ede5 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateStatus.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { [JsonObject(MemberSerialization.OptIn)] public class UpdateStatusCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.StatusUpdate; + int IWebSocketMessage.OpCode => (int)OpCode.StatusUpdate; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; public class GameInfo { diff --git a/src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateVoice.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs similarity index 51% rename from src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateVoice.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs index 3ccf92c65..d7befa41e 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateVoice.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs @@ -1,18 +1,16 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { [JsonObject(MemberSerialization.OptIn)] public class UpdateVoiceCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.VoiceStateUpdate; + int IWebSocketMessage.OpCode => (int)OpCode.VoiceStateUpdate; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; - [JsonProperty("guild_id"), JsonConverter(typeof(NullableLongStringConverter))] + [JsonProperty("guild_id")] public ulong? GuildId { get; set; } - [JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] + [JsonProperty("channel_id")] public ulong? ChannelId { get; set; } [JsonProperty("self_mute")] public bool IsSelfMuted { get; set; } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs similarity index 52% rename from src/Discord.Net/API/Client/GatewaySocket/Events/ChannelCreate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs index ca26fecc7..1e2769036 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelCreate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class ChannelCreateEvent : Channel { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs similarity index 54% rename from src/Discord.Net/API/Client/GatewaySocket/Events/ChannelDelete.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs index 2b61a7d78..91c57d640 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelDelete.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class ChannelDeleteEvent : Channel { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs similarity index 54% rename from src/Discord.Net/API/Client/GatewaySocket/Events/ChannelUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs index 4565ce1bc..227124291 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/ChannelUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class ChannelUpdateEvent : Channel { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanAdd.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs similarity index 56% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanAdd.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs index 7ba24473a..c1149ee15 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanAdd.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildBanAddEvent : MemberReference { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanRemove.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs similarity index 57% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanRemove.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs index a56a98494..5474146a7 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanRemove.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildBanRemoveEvent : MemberReference { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs similarity index 55% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildCreate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs index 41c1c71c7..f07adaed3 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildCreate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildCreateEvent : ExtendedGuild { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs similarity index 55% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildDelete.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs index cf824c40e..3408183ad 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildDelete.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildDeleteEvent : ExtendedGuild { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberAdd.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs similarity index 57% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberAdd.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs index a2ce6ddb2..098a2ea3b 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberAdd.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildMemberAddEvent : ExtendedMember { } } diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs new file mode 100644 index 000000000..686af9511 --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs @@ -0,0 +1,4 @@ +namespace Discord.API.GatewaySocket +{ + public class GuildMemberRemoveEvent : MemberReference { } +} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs new file mode 100644 index 000000000..339489f76 --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs @@ -0,0 +1,4 @@ +namespace Discord.API.GatewaySocket +{ + public class GuildMemberUpdateEvent : GuildMember { } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMembersChunk.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs similarity index 51% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildMembersChunk.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs index 4f2d36b8a..72936dd16 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildMembersChunk.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs @@ -1,11 +1,10 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildMembersChunkEvent { - [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("guild_id")] public ulong GuildId { get; set; } [JsonProperty("members")] public ExtendedMember[] Members { get; set; } diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs new file mode 100644 index 000000000..2740546dc --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.GatewaySocket +{ + public class GuildRoleCreateEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("role")] + public Role Data { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs similarity index 57% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleDelete.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs index 2ecd2edc5..4986f6193 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleDelete.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildRoleDeleteEvent : RoleReference { } } diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs new file mode 100644 index 000000000..56c232d06 --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.GatewaySocket +{ + public class GuildRoleUpdateEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("role")] + public Role Data { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs similarity index 52% rename from src/Discord.Net/API/Client/GatewaySocket/Events/GuildUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs index 8fc0f1350..b292c54e6 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/GuildUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class GuildUpdateEvent : Guild { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageAck.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs similarity index 56% rename from src/Discord.Net/API/Client/GatewaySocket/Events/MessageAck.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs index 64c106ef5..c8379d369 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageAck.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class MessageAckEvent : MessageReference { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs similarity index 54% rename from src/Discord.Net/API/Client/GatewaySocket/Events/MessageCreate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs index d6d2ec1cc..6b0e1e024 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageCreate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class MessageCreateEvent : Message { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs similarity index 57% rename from src/Discord.Net/API/Client/GatewaySocket/Events/MessageDelete.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs index cfc2df7ff..d932960ba 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageDelete.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class MessageDeleteEvent : MessageReference { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs similarity index 54% rename from src/Discord.Net/API/Client/GatewaySocket/Events/MessageUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs index 23521fd93..39ef7e1ba 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/MessageUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class MessageUpdateEvent : Message { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/PresenceUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs similarity index 57% rename from src/Discord.Net/API/Client/GatewaySocket/Events/PresenceUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs index c40853336..59d915354 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/PresenceUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class PresenceUpdateEvent : MemberPresence { } } diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/Ready.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs similarity index 96% rename from src/Discord.Net/API/Client/GatewaySocket/Events/Ready.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs index 744e5b4b5..51e0f3c8c 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/Ready.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class ReadyEvent { diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/Redirect.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Redirect.cs similarity index 77% rename from src/Discord.Net/API/Client/GatewaySocket/Events/Redirect.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Redirect.cs index fe9d644d4..180bf574f 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/Redirect.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Redirect.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class RedirectEvent { diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/Resumed.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs similarity index 79% rename from src/Discord.Net/API/Client/GatewaySocket/Events/Resumed.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs index 6a50fbe32..3f98b1f35 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/Resumed.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class ResumedEvent { diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs new file mode 100644 index 000000000..063011bbb --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.GatewaySocket +{ + public class TypingStartEvent + { + [JsonProperty("user_id")] + public ulong UserId { get; set; } + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + [JsonProperty("timestamp")] + public int Timestamp { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/UserUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs similarity index 51% rename from src/Discord.Net/API/Client/GatewaySocket/Events/UserUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs index 3c366310a..e49f8b292 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/UserUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class UserUpdateEvent : User { } } diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs new file mode 100644 index 000000000..75936bb93 --- /dev/null +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.GatewaySocket +{ + public class VoiceServerUpdateEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("endpoint")] + public string Endpoint { get; set; } + [JsonProperty("token")] + public string Token { get; set; } + } +} diff --git a/src/Discord.Net/API/Client/GatewaySocket/Events/VoiceStateUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs similarity index 58% rename from src/Discord.Net/API/Client/GatewaySocket/Events/VoiceStateUpdate.cs rename to src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs index f3ba96b17..c0b99c710 100644 --- a/src/Discord.Net/API/Client/GatewaySocket/Events/VoiceStateUpdate.cs +++ b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs @@ -1,4 +1,4 @@ -namespace Discord.API.Client.GatewaySocket +namespace Discord.API.GatewaySocket { public class VoiceStateUpdateEvent : MemberVoiceState { } } diff --git a/src/Discord.Net/API/IRestRequest.cs b/src/Discord.Net/API/IRestRequest.cs deleted file mode 100644 index af520370d..000000000 --- a/src/Discord.Net/API/IRestRequest.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.IO; - -namespace Discord.API -{ - public interface IRestRequest - { - string Method { get; } - string Endpoint { get; } - object Payload { get; } - } - public interface IRestRequest : IRestRequest - where ResponseT : class - { - } - - public interface IRestFileRequest : IRestRequest - { - string Filename { get; } - Stream Stream { get; } - } - public interface IRestFileRequest : IRestFileRequest, IRestRequest - where ResponseT : class - { - } -} diff --git a/src/Discord.Net/API/Client/IWebSocketMessage.cs b/src/Discord.Net/API/IWebSocketMessage.cs similarity index 92% rename from src/Discord.Net/API/Client/IWebSocketMessage.cs rename to src/Discord.Net/API/IWebSocketMessage.cs index 6f6de535a..06c51bf77 100644 --- a/src/Discord.Net/API/Client/IWebSocketMessage.cs +++ b/src/Discord.Net/API/IWebSocketMessage.cs @@ -1,12 +1,11 @@ using Newtonsoft.Json; -namespace Discord.API.Client +namespace Discord.API { public interface IWebSocketMessage { int OpCode { get; } object Payload { get; } - bool IsPrivate { get; } } public class WebSocketMessage { diff --git a/src/Discord.Net/API/Rest/AcceptInvite.cs b/src/Discord.Net/API/Rest/AcceptInvite.cs new file mode 100644 index 000000000..72350253f --- /dev/null +++ b/src/Discord.Net/API/Rest/AcceptInvite.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class AcceptInviteRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"invites/{InviteCode}"; + object IRestRequest.Payload => null; + + public string InviteCode { get; } + + public AcceptInviteRequest(string inviteCode) + { + InviteCode = inviteCode; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/AckMessage.cs b/src/Discord.Net/API/Rest/AckMessage.cs similarity index 59% rename from src/Discord.Net/API/Client/Rest/AckMessage.cs rename to src/Discord.Net/API/Rest/AckMessage.cs index 4cf238b72..387215624 100644 --- a/src/Discord.Net/API/Client/Rest/AckMessage.cs +++ b/src/Discord.Net/API/Rest/AckMessage.cs @@ -1,19 +1,15 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class AckMessageRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}/ack"; object IRestRequest.Payload => null; - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - - /*[JsonProperty("manual")] - public bool Manual { get; set; }*/ + public ulong ChannelId { get; } + public ulong MessageId { get; } public AckMessageRequest(ulong channelId, ulong messageId) { diff --git a/src/Discord.Net/API/Rest/BeginGuildPrune.cs b/src/Discord.Net/API/Rest/BeginGuildPrune.cs new file mode 100644 index 000000000..0a35bdc80 --- /dev/null +++ b/src/Discord.Net/API/Rest/BeginGuildPrune.cs @@ -0,0 +1,23 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class BeginGuildPruneRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/prune"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + + [JsonProperty("days")] + public int Days { get; set; } = 30; + + public BeginGuildPruneRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/CreateInvite.cs b/src/Discord.Net/API/Rest/CreateChannelInvite.cs similarity index 62% rename from src/Discord.Net/API/Client/Rest/CreateInvite.cs rename to src/Discord.Net/API/Rest/CreateChannelInvite.cs index 73f15c248..f60232f48 100644 --- a/src/Discord.Net/API/Client/Rest/CreateInvite.cs +++ b/src/Discord.Net/API/Rest/CreateChannelInvite.cs @@ -1,28 +1,27 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class CreateInviteRequest : IRestRequest + public class CreateChannelInviteRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"channels/{ChannelId}/invites"; object IRestRequest.Payload => this; - public ulong ChannelId { get; set; } + public ulong ChannelId { get; } [JsonProperty("max_age")] - public int MaxAge { get; set; } = 1800; + public int MaxAge { get; set; } = 86400; //24 Hours [JsonProperty("max_uses")] public int MaxUses { get; set; } = 0; [JsonProperty("temporary")] public bool IsTemporary { get; set; } = false; [JsonProperty("xkcdpass")] public bool WithXkcdPass { get; set; } = false; - /*[JsonProperty("validate")] - public bool Validate { get; set; }*/ - public CreateInviteRequest(ulong channelId) + public CreateChannelInviteRequest(ulong channelId) { ChannelId = channelId; } diff --git a/src/Discord.Net/API/Client/Rest/CreatePrivateChannel.cs b/src/Discord.Net/API/Rest/CreateDMChannel.cs similarity index 56% rename from src/Discord.Net/API/Client/Rest/CreatePrivateChannel.cs rename to src/Discord.Net/API/Rest/CreateDMChannel.cs index e1087dc36..473ecc8e2 100644 --- a/src/Discord.Net/API/Client/Rest/CreatePrivateChannel.cs +++ b/src/Discord.Net/API/Rest/CreateDMChannel.cs @@ -1,16 +1,16 @@ -using Discord.API.Converters; +using Discord.Net.Rest; using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class CreatePrivateChannelRequest : IRestRequest + public class CreateDMChannelRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"users/@me/channels"; object IRestRequest.Payload => this; - [JsonProperty("recipient_id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("recipient_id")] public ulong RecipientId { get; set; } } } diff --git a/src/Discord.Net/API/Client/Rest/CreateGuild.cs b/src/Discord.Net/API/Rest/CreateGuild.cs similarity index 63% rename from src/Discord.Net/API/Client/Rest/CreateGuild.cs rename to src/Discord.Net/API/Rest/CreateGuild.cs index a18d2bee9..c2c9532e0 100644 --- a/src/Discord.Net/API/Client/Rest/CreateGuild.cs +++ b/src/Discord.Net/API/Rest/CreateGuild.cs @@ -1,6 +1,9 @@ -using Newtonsoft.Json; +using Discord.Net.JsonConverters; +using Discord.Net.Rest; +using Newtonsoft.Json; +using System.IO; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] public class CreateGuildRequest : IRestRequest @@ -13,7 +16,7 @@ namespace Discord.API.Client.Rest public string Name { get; set; } [JsonProperty("region")] public string Region { get; set; } - [JsonProperty("icon")] - public string IconBase64 { get; set; } + [JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] + public Stream Icon { get; set; } } } diff --git a/src/Discord.Net/API/Rest/CreateGuildBan.cs b/src/Discord.Net/API/Rest/CreateGuildBan.cs new file mode 100644 index 000000000..c76122c5f --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateGuildBan.cs @@ -0,0 +1,24 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateGuildBanRequest : IRestRequest + { + string IRestRequest.Method => "PUT"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong UserId { get; } + + [JsonProperty("delete-message-days")] + public int PruneDays { get; set; } = 0; + + public CreateGuildBanRequest(ulong guildId, ulong userId) + { + GuildId = guildId; + UserId = userId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/CreateChannel.cs b/src/Discord.Net/API/Rest/CreateGuildChannel.cs similarity index 73% rename from src/Discord.Net/API/Client/Rest/CreateChannel.cs rename to src/Discord.Net/API/Rest/CreateGuildChannel.cs index 90d9afec0..839f3cc1d 100644 --- a/src/Discord.Net/API/Client/Rest/CreateChannel.cs +++ b/src/Discord.Net/API/Rest/CreateGuildChannel.cs @@ -1,6 +1,7 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] public class CreateChannelRequest : IRestRequest @@ -9,12 +10,14 @@ namespace Discord.API.Client.Rest string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; object IRestRequest.Payload => this; - public ulong GuildId { get; set; } + public ulong GuildId { get; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("type")] public ChannelType Type { get; set; } + [JsonProperty("bitrate")] + public int Bitrate { get; set; } public CreateChannelRequest(ulong guildId) { diff --git a/src/Discord.Net/API/Rest/CreateGuildIntegration.cs b/src/Discord.Net/API/Rest/CreateGuildIntegration.cs new file mode 100644 index 000000000..7cf48397d --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateGuildIntegration.cs @@ -0,0 +1,25 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class CreateGuildIntegrationRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/integrations"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + + [JsonProperty("id")] + public ulong IntegrationId { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + + public CreateGuildIntegrationRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/CreateRole.cs b/src/Discord.Net/API/Rest/CreateGuildRole.cs similarity index 69% rename from src/Discord.Net/API/Client/Rest/CreateRole.cs rename to src/Discord.Net/API/Rest/CreateGuildRole.cs index 3978c6aaa..0d21805d8 100644 --- a/src/Discord.Net/API/Client/Rest/CreateRole.cs +++ b/src/Discord.Net/API/Rest/CreateGuildRole.cs @@ -1,15 +1,14 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class CreateRoleRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; object IRestRequest.Payload => null; - public ulong GuildId { get; set; } + public ulong GuildId { get; } public CreateRoleRequest(ulong guildId) { diff --git a/src/Discord.Net/API/Client/Rest/SendMessage.cs b/src/Discord.Net/API/Rest/CreateMessage.cs similarity index 51% rename from src/Discord.Net/API/Client/Rest/SendMessage.cs rename to src/Discord.Net/API/Rest/CreateMessage.cs index 9caca991d..1018a8c66 100644 --- a/src/Discord.Net/API/Client/Rest/SendMessage.cs +++ b/src/Discord.Net/API/Rest/CreateMessage.cs @@ -1,24 +1,25 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class SendMessageRequest : IRestRequest + public class CreateMessageRequest : IRestRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages"; object IRestRequest.Payload => this; - public ulong ChannelId { get; set; } + public ulong ChannelId { get; } [JsonProperty("content")] public string Content { get; set; } [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] - public string Nonce { get; set; } - [JsonProperty("tts")] - public bool IsTTS { get; set; } + public string Nonce { get; set; } = null; + [JsonProperty("tts", DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool IsTTS { get; set; } = false; - public SendMessageRequest(ulong channelId) + public CreateMessageRequest(ulong channelId) { ChannelId = channelId; } diff --git a/src/Discord.Net/API/Client/Rest/DeleteChannel.cs b/src/Discord.Net/API/Rest/DeleteChannel.cs similarity index 69% rename from src/Discord.Net/API/Client/Rest/DeleteChannel.cs rename to src/Discord.Net/API/Rest/DeleteChannel.cs index ae56934b5..fa9b10c10 100644 --- a/src/Discord.Net/API/Client/Rest/DeleteChannel.cs +++ b/src/Discord.Net/API/Rest/DeleteChannel.cs @@ -1,15 +1,14 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class DeleteChannelRequest : IRestRequest { string IRestRequest.Method => "DELETE"; string IRestRequest.Endpoint => $"channels/{ChannelId}"; object IRestRequest.Payload => null; - public ulong ChannelId { get; set; } + public ulong ChannelId { get; } public DeleteChannelRequest(ulong channelId) { diff --git a/src/Discord.Net/API/Rest/DeleteChannelPermission.cs b/src/Discord.Net/API/Rest/DeleteChannelPermission.cs new file mode 100644 index 000000000..658388641 --- /dev/null +++ b/src/Discord.Net/API/Rest/DeleteChannelPermission.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class DeleteChannelPermissionsRequest : IRestRequest + { + string IRestRequest.Method => "DELETE"; + string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; + object IRestRequest.Payload => null; + + public ulong ChannelId { get; } + public ulong TargetId { get; } + + public DeleteChannelPermissionsRequest(ulong channelId, ulong targetId) + { + ChannelId = channelId; + TargetId = targetId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/DeleteGuild.cs b/src/Discord.Net/API/Rest/DeleteGuild.cs similarity index 69% rename from src/Discord.Net/API/Client/Rest/DeleteGuild.cs rename to src/Discord.Net/API/Rest/DeleteGuild.cs index 44df5892e..d1a14fbc9 100644 --- a/src/Discord.Net/API/Client/Rest/DeleteGuild.cs +++ b/src/Discord.Net/API/Rest/DeleteGuild.cs @@ -1,15 +1,14 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class DeleteGuildRequest : IRestRequest { string IRestRequest.Method => "DELETE"; string IRestRequest.Endpoint => $"guilds/{GuildId}"; object IRestRequest.Payload => null; - public ulong GuildId { get; set; } + public ulong GuildId { get; } public DeleteGuildRequest(ulong guildId) { diff --git a/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs b/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs new file mode 100644 index 000000000..b25418c1a --- /dev/null +++ b/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class DeleteGuildIntegrationRequest : IRestRequest + { + string IRestRequest.Method => "DELETE"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/integrations/{IntegrationId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong IntegrationId { get; } + + public DeleteGuildIntegrationRequest(ulong guildId, ulong integrationId) + { + GuildId = guildId; + IntegrationId = integrationId; + } + } +} diff --git a/src/Discord.Net/API/Rest/DeleteGuildRole.cs b/src/Discord.Net/API/Rest/DeleteGuildRole.cs new file mode 100644 index 000000000..cbb21eec3 --- /dev/null +++ b/src/Discord.Net/API/Rest/DeleteGuildRole.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class DeleteGuildRoleRequest : IRestRequest + { + string IRestRequest.Method => "DELETE"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong RoleId { get; } + + public DeleteGuildRoleRequest(ulong guildId, ulong roleId) + { + GuildId = guildId; + RoleId = roleId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/DeleteInvite.cs b/src/Discord.Net/API/Rest/DeleteInvite.cs similarity index 56% rename from src/Discord.Net/API/Client/Rest/DeleteInvite.cs rename to src/Discord.Net/API/Rest/DeleteInvite.cs index 4bfe1e0d7..388255862 100644 --- a/src/Discord.Net/API/Client/Rest/DeleteInvite.cs +++ b/src/Discord.Net/API/Rest/DeleteInvite.cs @@ -1,15 +1,14 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class DeleteInviteRequest : IRestRequest { string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"invite/{InviteCode}"; + string IRestRequest.Endpoint => $"invites/{InviteCode}"; object IRestRequest.Payload => null; - public string InviteCode { get; set; } + public string InviteCode { get; } public DeleteInviteRequest(string inviteCode) { diff --git a/src/Discord.Net/API/Client/Rest/DeleteMessage.cs b/src/Discord.Net/API/Rest/DeleteMessage.cs similarity index 67% rename from src/Discord.Net/API/Client/Rest/DeleteMessage.cs rename to src/Discord.Net/API/Rest/DeleteMessage.cs index 3f781a756..c9d95deba 100644 --- a/src/Discord.Net/API/Client/Rest/DeleteMessage.cs +++ b/src/Discord.Net/API/Rest/DeleteMessage.cs @@ -1,16 +1,15 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class DeleteMessageRequest : IRestRequest { string IRestRequest.Method => "DELETE"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; object IRestRequest.Payload => null; - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } + public ulong ChannelId { get; } + public ulong MessageId { get; } public DeleteMessageRequest(ulong channelId, ulong messageId) { diff --git a/src/Discord.Net/API/Rest/GetChannel.cs b/src/Discord.Net/API/Rest/GetChannel.cs new file mode 100644 index 000000000..12d258836 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetChannel.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetChannelRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"channels/{ChannelId}"; + object IRestRequest.Payload => null; + + public ulong ChannelId { get; } + + public GetChannelRequest(ulong channelId) + { + ChannelId = channelId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetChannelInvites.cs b/src/Discord.Net/API/Rest/GetChannelInvites.cs new file mode 100644 index 000000000..7532fb64f --- /dev/null +++ b/src/Discord.Net/API/Rest/GetChannelInvites.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class GetChannelInvitesRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"channels/{ChannelId}/invites"; + object IRestRequest.Payload => null; + + public ulong ChannelId { get; } + + public GetChannelInvitesRequest(ulong channelId) + { + ChannelId = channelId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetChannelMessages.cs b/src/Discord.Net/API/Rest/GetChannelMessages.cs new file mode 100644 index 000000000..a0e6b5afe --- /dev/null +++ b/src/Discord.Net/API/Rest/GetChannelMessages.cs @@ -0,0 +1,34 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class GetChannelMessagesRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"channels/{ChannelId}/messages?limit={Limit}&{RelativeDir}={RelativeId}"; + object IRestRequest.Payload => null; + + public ulong ChannelId { get; } + + public Relative RelativeDir { get; set; } + public ulong RelativeId { get; set; } = 0; + + [JsonProperty("limit")] + public int Limit { get; set; } = 100; + + [JsonProperty("before")] + public ulong Before => RelativeId; + private bool ShouldSerializeBefore => RelativeDir == Relative.Before; + + [JsonProperty("after")] + public ulong After => RelativeId; + private bool ShouldSerializeAfter => RelativeDir == Relative.After; + + public GetChannelMessagesRequest(ulong channelId) + { + ChannelId = channelId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetCurrentUser.cs b/src/Discord.Net/API/Rest/GetCurrentUser.cs new file mode 100644 index 000000000..76bc3e838 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetCurrentUser.cs @@ -0,0 +1,11 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetCurrentUserRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users/@me"; + object IRestRequest.Payload => null; + } +} diff --git a/src/Discord.Net/API/Rest/GetCurrentUserConnections.cs b/src/Discord.Net/API/Rest/GetCurrentUserConnections.cs new file mode 100644 index 000000000..102affaa7 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetCurrentUserConnections.cs @@ -0,0 +1,11 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetCurrentUserConnectionsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users/@me/connections"; + object IRestRequest.Payload => null; + } +} diff --git a/src/Discord.Net/API/Rest/GetCurrentUserDMs.cs b/src/Discord.Net/API/Rest/GetCurrentUserDMs.cs new file mode 100644 index 000000000..31cc1edeb --- /dev/null +++ b/src/Discord.Net/API/Rest/GetCurrentUserDMs.cs @@ -0,0 +1,11 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetCurrentUserDMsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users/@me/channels"; + object IRestRequest.Payload => null; + } +} diff --git a/src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs b/src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs new file mode 100644 index 000000000..e3423c3f8 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs @@ -0,0 +1,11 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetCurrentUserGuildsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users/@me/guilds"; + object IRestRequest.Payload => null; + } +} diff --git a/src/Discord.Net/API/Rest/GetGateway.cs b/src/Discord.Net/API/Rest/GetGateway.cs new file mode 100644 index 000000000..3581f9f00 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGateway.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class GetGatewayRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"gateway"; + object IRestRequest.Payload => null; + } + + public class GetGatewayResponse + { + [JsonProperty("url")] + public string Url { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuild.cs b/src/Discord.Net/API/Rest/GetGuild.cs new file mode 100644 index 000000000..2e83d261a --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuild.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildBans.cs b/src/Discord.Net/API/Rest/GetGuildBans.cs new file mode 100644 index 000000000..73a02b43e --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildBans.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildBansRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/bans"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildBansRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildChannels.cs b/src/Discord.Net/API/Rest/GetGuildChannels.cs new file mode 100644 index 000000000..f20e9ec4f --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildChannels.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildChannelsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guild/{GuildId}/channels"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildChannelsRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildEmbed.cs b/src/Discord.Net/API/Rest/GetGuildEmbed.cs new file mode 100644 index 000000000..0eb67e680 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildEmbed.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildEmbedRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/embed"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildEmbedRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildIntegrations.cs b/src/Discord.Net/API/Rest/GetGuildIntegrations.cs new file mode 100644 index 000000000..ba2b1ce2d --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildIntegrations.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildIntegrationsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/integrations"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildIntegrationsRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildInvites.cs b/src/Discord.Net/API/Rest/GetGuildInvites.cs new file mode 100644 index 000000000..4a20770b1 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildInvites.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildInvitesRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/invites"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildInvitesRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildMember.cs b/src/Discord.Net/API/Rest/GetGuildMember.cs new file mode 100644 index 000000000..0dc1d8077 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildMember.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildMemberRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong UserId { get; } + + public GetGuildMemberRequest(ulong guildId, ulong userId) + { + GuildId = guildId; + UserId = userId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildPruneCount.cs b/src/Discord.Net/API/Rest/GetGuildPruneCount.cs new file mode 100644 index 000000000..469b5fa01 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildPruneCount.cs @@ -0,0 +1,29 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class GetGuildPruneCountRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/prune"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + [JsonProperty("days")] + public int Days { get; set; } = 30; + + public GetGuildPruneCountRequest(ulong guildId) + { + GuildId = guildId; + } + } + + public class GetGuildPruneCountResponse + { + [JsonProperty("pruned")] + public int Pruned { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildRoles.cs b/src/Discord.Net/API/Rest/GetGuildRoles.cs new file mode 100644 index 000000000..f8ff0a9b3 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildRoles.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildRolesRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guild/{GuildId}/roles"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildRolesRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs b/src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs new file mode 100644 index 000000000..ed631e7e2 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetGuildVoiceRegionsRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/regions"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + public GetGuildVoiceRegionsRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetInvite.cs b/src/Discord.Net/API/Rest/GetInvite.cs new file mode 100644 index 000000000..fccbc79c9 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetInvite.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetInviteRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"invites/{InviteCode}"; + object IRestRequest.Payload => null; + + public string InviteCode { get; } + + public GetInviteRequest(string inviteCode) + { + InviteCode = inviteCode; + } + } +} diff --git a/src/Discord.Net/API/Rest/GetUser.cs b/src/Discord.Net/API/Rest/GetUser.cs new file mode 100644 index 000000000..1cfeb82be --- /dev/null +++ b/src/Discord.Net/API/Rest/GetUser.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class GetUserRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users/{UserId}"; + object IRestRequest.Payload => null; + + public ulong UserId { get; } + + public GetUserRequest(ulong userId) + { + UserId = userId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/GetVoiceRegions.cs b/src/Discord.Net/API/Rest/GetVoiceRegions.cs similarity index 65% rename from src/Discord.Net/API/Client/Rest/GetVoiceRegions.cs rename to src/Discord.Net/API/Rest/GetVoiceRegions.cs index df21cc203..5fdbccfd8 100644 --- a/src/Discord.Net/API/Client/Rest/GetVoiceRegions.cs +++ b/src/Discord.Net/API/Rest/GetVoiceRegions.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class GetVoiceRegionsRequest : IRestRequest { string IRestRequest.Method => "GET"; @@ -12,15 +12,17 @@ namespace Discord.API.Client.Rest public class GetVoiceRegionsResponse { - [JsonProperty("sample_hostname")] - public string Hostname { get; set; } - [JsonProperty("sample_port")] - public int Port { get; set; } [JsonProperty("id")] public string Id { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("vip")] - public bool Vip { get; set; } + public bool IsVip { get; set; } + [JsonProperty("optimal")] + public bool IsOptimal { get; set; } + [JsonProperty("sample_hostname")] + public string SampleHostname { get; set; } + [JsonProperty("sample_port")] + public int SamplePort { get; set; } } } diff --git a/src/Discord.Net/API/Client/Rest/LeaveGuild.cs b/src/Discord.Net/API/Rest/LeaveGuild.cs similarity index 69% rename from src/Discord.Net/API/Client/Rest/LeaveGuild.cs rename to src/Discord.Net/API/Rest/LeaveGuild.cs index 99fd8cbe7..a62fdd089 100644 --- a/src/Discord.Net/API/Client/Rest/LeaveGuild.cs +++ b/src/Discord.Net/API/Rest/LeaveGuild.cs @@ -1,15 +1,14 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class LeaveGuildRequest : IRestRequest { string IRestRequest.Method => "DELETE"; string IRestRequest.Endpoint => $"users/@me/guilds/{GuildId}"; object IRestRequest.Payload => null; - public ulong GuildId { get; set; } + public ulong GuildId { get; } public LeaveGuildRequest(ulong guildId) { diff --git a/src/Discord.Net/API/Rest/ListGuildMembers.cs b/src/Discord.Net/API/Rest/ListGuildMembers.cs new file mode 100644 index 000000000..4577b8910 --- /dev/null +++ b/src/Discord.Net/API/Rest/ListGuildMembers.cs @@ -0,0 +1,24 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ListGuildMembersRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"guild/{GuildId}/members"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + + [JsonProperty("limit")] + public int Limit { get; } = 1; + [JsonProperty("offset")] + public int Offset { get; } = 0; + + public ListGuildMembersRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/AddChannelPermission.cs b/src/Discord.Net/API/Rest/ModifyChannelPermission.cs similarity index 50% rename from src/Discord.Net/API/Client/Rest/AddChannelPermission.cs rename to src/Discord.Net/API/Rest/ModifyChannelPermission.cs index bf725bcaf..e38685bb7 100644 --- a/src/Discord.Net/API/Client/Rest/AddChannelPermission.cs +++ b/src/Discord.Net/API/Rest/ModifyChannelPermission.cs @@ -1,29 +1,27 @@ -using Discord.API.Converters; +using Discord.Net.Rest; using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class AddOrUpdateChannelPermissionsRequest : IRestRequest + public class ModifyChannelPermissionsRequest : IRestRequest { string IRestRequest.Method => "PUT"; string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; object IRestRequest.Payload => this; - public ulong ChannelId { get; set; } + public ulong ChannelId { get; } + public ulong TargetId { get; } - [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] - public ulong TargetId { get; set; } - [JsonProperty("type")] - public string TargetType { get; set; } [JsonProperty("allow")] public uint Allow { get; set; } [JsonProperty("deny")] public uint Deny { get; set; } - public AddOrUpdateChannelPermissionsRequest(ulong channelId) + public ModifyChannelPermissionsRequest(ulong channelId, ulong targetId) { ChannelId = channelId; + TargetId = targetId; } } } diff --git a/src/Discord.Net/API/Client/Rest/UpdateProfile.cs b/src/Discord.Net/API/Rest/ModifyCurrentUser.cs similarity index 57% rename from src/Discord.Net/API/Client/Rest/UpdateProfile.cs rename to src/Discord.Net/API/Rest/ModifyCurrentUser.cs index 0f0cdb313..afc1c3b74 100644 --- a/src/Discord.Net/API/Client/Rest/UpdateProfile.cs +++ b/src/Discord.Net/API/Rest/ModifyCurrentUser.cs @@ -1,23 +1,26 @@ -using Newtonsoft.Json; +using Discord.Net.JsonConverters; +using Discord.Net.Rest; +using Newtonsoft.Json; +using System.IO; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class UpdateProfileRequest : IRestRequest + public class ModifyCurrentUserRequest : IRestRequest { string IRestRequest.Method => "PATCH"; string IRestRequest.Endpoint => $"users/@me"; object IRestRequest.Payload => this; - [JsonProperty("password")] - public string CurrentPassword { get; set; } + [JsonProperty("username")] + public string Username { get; set; } [JsonProperty("email")] public string Email { get; set; } - [JsonProperty("new_password")] + [JsonProperty("password")] public string Password { get; set; } - [JsonProperty("username")] - public string Username { get; set; } - [JsonProperty("avatar")] - public string AvatarBase64 { get; set; } + [JsonProperty("new_password")] + public string NewPassword { get; set; } + [JsonProperty("avatar"), JsonConverter(typeof(ImageConverter))] + public Stream Avatar { get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuild.cs b/src/Discord.Net/API/Rest/ModifyGuild.cs new file mode 100644 index 000000000..1405a8144 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuild.cs @@ -0,0 +1,39 @@ +using Discord.Net.JsonConverters; +using Discord.Net.Rest; +using Newtonsoft.Json; +using System.IO; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModifyGuildRequest : IRestRequest + { + string IRestRequest.Method => "PATCH"; + string IRestRequest.Endpoint => $"guilds/{GuildId}"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("region")] + public VoiceRegion Region { get; set; } + [JsonProperty("verification_level")] + public int VerificationLevel { get; set; } + [JsonProperty("afk_channel_id")] + public ulong? AFKChannelId { get; set; } + [JsonProperty("afk_timeout")] + public int AFKTimeout { get; set; } + [JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] + public Stream Icon { get; set; } + [JsonProperty("owner_id")] + public GuildPresence Owner { get; set; } + [JsonProperty("splash"), JsonConverter(typeof(ImageConverter))] + public Stream Splash { get; set; } + + public ModifyGuildRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/UpdateChannel.cs b/src/Discord.Net/API/Rest/ModifyGuildChannel.cs similarity index 59% rename from src/Discord.Net/API/Client/Rest/UpdateChannel.cs rename to src/Discord.Net/API/Rest/ModifyGuildChannel.cs index 8a82caefd..eeb909e84 100644 --- a/src/Discord.Net/API/Client/Rest/UpdateChannel.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildChannel.cs @@ -1,9 +1,10 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] - public class UpdateChannelRequest : IRestRequest + public class ModifyGuildChannelRequest : IRestRequest { string IRestRequest.Method => "PATCH"; string IRestRequest.Endpoint => $"channels/{ChannelId}"; @@ -13,14 +14,10 @@ namespace Discord.API.Client.Rest [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("topic")] - public string Topic { get; set; } [JsonProperty("position")] public int Position { get; set; } - [JsonProperty("bitrate")] - public int Bitrate { get; set; } - public UpdateChannelRequest(ulong channelId) + public ModifyGuildChannelRequest(ulong channelId) { ChannelId = channelId; } diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannels.cs b/src/Discord.Net/API/Rest/ModifyGuildChannels.cs new file mode 100644 index 000000000..de9b97b88 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildChannels.cs @@ -0,0 +1,22 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; +using System; + +namespace Discord.API.Rest +{ + public class ModifyGuildChannelsRequest : IRestRequest + { + string IRestRequest.Method => "PATCH"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; + object IRestRequest.Payload => Requests; + + public ulong GuildId { get; } + + public ModifyGuildChannelRequest[] Requests { get; set; } = Array.Empty(); + + public ModifyGuildChannelsRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs b/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs new file mode 100644 index 000000000..c896e5a34 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs @@ -0,0 +1,25 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModifyGuildEmbedRequest : IRestRequest + { + string IRestRequest.Method => "PATCH"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/embed"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + + [JsonProperty("enabled")] + public bool Enabled { get; set; } + [JsonProperty("channel_id")] + public ulong? ChannelId { get; set; } + + public ModifyGuildEmbedRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs b/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs new file mode 100644 index 000000000..b093888da --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs @@ -0,0 +1,29 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModifyGuildIntegrationRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/integrations/{IntegrationId}"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + public ulong IntegrationId { get; } + + [JsonProperty("expire_behavior")] + public int ExpireBehavior { get; set; } + [JsonProperty("expire_grace_period")] + public int ExpireGracePeriod { get; set; } + [JsonProperty("enable_emoticons")] + public bool EnableEmoticons { get; set; } + + public ModifyGuildIntegrationRequest(ulong guildId, ulong integrationId) + { + GuildId = guildId; + IntegrationId = integrationId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/UpdateMember.cs b/src/Discord.Net/API/Rest/ModifyGuildMember.cs similarity index 50% rename from src/Discord.Net/API/Client/Rest/UpdateMember.cs rename to src/Discord.Net/API/Rest/ModifyGuildMember.cs index ce1649bdd..07a662645 100644 --- a/src/Discord.Net/API/Client/Rest/UpdateMember.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildMember.cs @@ -1,7 +1,7 @@ -using Discord.API.Converters; +using Discord.Net.Rest; using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] public class UpdateMemberRequest : IRestRequest @@ -10,17 +10,17 @@ namespace Discord.API.Client.Rest string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; object IRestRequest.Payload => this; - public ulong GuildId { get; set; } - public ulong UserId { get; set; } + public ulong GuildId { get; } + public ulong UserId { get; } + [JsonProperty("roles")] + public ulong[] Roles { get; set; } [JsonProperty("mute")] - public bool IsMuted { get; set; } + public bool Mute { get; set; } [JsonProperty("deaf")] - public bool IsDeafened { get; set; } - [JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] - public ulong? VoiceChannelId { get; set; } - [JsonProperty("roles"), JsonConverter(typeof(LongStringArrayConverter))] - public ulong[] RoleIds { get; set; } + public bool Deaf { get; set; } + [JsonProperty("channel_id")] + public ulong? ChannelId { get; set; } public UpdateMemberRequest(ulong guildId, ulong userId) { diff --git a/src/Discord.Net/API/Rest/ModifyGuildRole.cs b/src/Discord.Net/API/Rest/ModifyGuildRole.cs new file mode 100644 index 000000000..6d7e09c59 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildRole.cs @@ -0,0 +1,32 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildRoleRequest : IRestRequest + { + string IRestRequest.Method => "PATCH"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; + object IRestRequest.Payload => this; + + public ulong GuildId { get; } + public ulong RoleId { get; } + + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("permissions")] + public int Permissions { get; set; } + [JsonProperty("position")] + public int Position { get; set; } + [JsonProperty("color")] + public int Color { get; set; } + [JsonProperty("hoist")] + public bool Hoist { get; set; } + + public ModifyGuildRoleRequest(ulong guildId, ulong roleId) + { + GuildId = guildId; + RoleId = roleId; + } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildRoles.cs b/src/Discord.Net/API/Rest/ModifyGuildRoles.cs new file mode 100644 index 000000000..905f51b11 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildRoles.cs @@ -0,0 +1,21 @@ +using Discord.Net.Rest; +using System; + +namespace Discord.API.Rest +{ + public class ModifyGuildRolesRequest : IRestRequest + { + string IRestRequest.Method => "PATCH"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; + object IRestRequest.Payload => Requests; + + public ulong GuildId { get; } + + public ModifyGuildRoleRequest[] Requests { get; set; } = Array.Empty(); + + public ModifyGuildRolesRequest(ulong guildId) + { + GuildId = guildId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/UpdateMessage.cs b/src/Discord.Net/API/Rest/ModifyMessage.cs similarity index 77% rename from src/Discord.Net/API/Client/Rest/UpdateMessage.cs rename to src/Discord.Net/API/Rest/ModifyMessage.cs index fc055b2bc..0c99403a6 100644 --- a/src/Discord.Net/API/Client/Rest/UpdateMessage.cs +++ b/src/Discord.Net/API/Rest/ModifyMessage.cs @@ -1,6 +1,7 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using Newtonsoft.Json; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { [JsonObject(MemberSerialization.OptIn)] public class UpdateMessageRequest : IRestRequest @@ -9,8 +10,8 @@ namespace Discord.API.Client.Rest string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; object IRestRequest.Payload => this; - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } + public ulong ChannelId { get; } + public ulong MessageId { get; } [JsonProperty("content")] public string Content { get; set; } = ""; diff --git a/src/Discord.Net/API/Rest/ModifyTextChannel.cs b/src/Discord.Net/API/Rest/ModifyTextChannel.cs new file mode 100644 index 000000000..f3d672daf --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyTextChannel.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModifyTextChannelRequest : ModifyGuildChannelRequest + { + [JsonProperty("topic")] + public string Topic { get; set; } + + public ModifyTextChannelRequest(ulong channelId) + : base(channelId) + { + } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs b/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs new file mode 100644 index 000000000..e8bdfac8f --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + [JsonObject(MemberSerialization.OptIn)] + public class ModifyVoiceChannelRequest : ModifyGuildChannelRequest + { + [JsonProperty("bitrate")] + public int Bitrate { get; set; } + + public ModifyVoiceChannelRequest(ulong channelId) + : base(channelId) + { + } + } +} diff --git a/src/Discord.Net/API/Rest/QueryUser.cs b/src/Discord.Net/API/Rest/QueryUser.cs new file mode 100644 index 000000000..45a194805 --- /dev/null +++ b/src/Discord.Net/API/Rest/QueryUser.cs @@ -0,0 +1,19 @@ +using Discord.Net.Rest; +using System; + +namespace Discord.API.Rest +{ + public class QueryUserRequest : IRestRequest + { + string IRestRequest.Method => "GET"; + string IRestRequest.Endpoint => $"users?q={Uri.EscapeDataString(Query)}&limit={Limit}"; + object IRestRequest.Payload => null; + + public string Query { get; set; } + public int Limit { get; set; } = 25; + + public QueryUserRequest() + { + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/RemoveGuildBan.cs b/src/Discord.Net/API/Rest/RemoveGuildBan.cs similarity index 67% rename from src/Discord.Net/API/Client/Rest/RemoveGuildBan.cs rename to src/Discord.Net/API/Rest/RemoveGuildBan.cs index 5a8f4f796..4f5df1243 100644 --- a/src/Discord.Net/API/Client/Rest/RemoveGuildBan.cs +++ b/src/Discord.Net/API/Rest/RemoveGuildBan.cs @@ -1,16 +1,15 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class RemoveGuildBanRequest : IRestRequest { string IRestRequest.Method => "DELETE"; string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}"; object IRestRequest.Payload => null; - public ulong GuildId { get; set; } - public ulong UserId { get; set; } + public ulong GuildId { get; } + public ulong UserId { get; } public RemoveGuildBanRequest(ulong guildId, ulong userId) { diff --git a/src/Discord.Net/API/Rest/RemoveGuildMember.cs b/src/Discord.Net/API/Rest/RemoveGuildMember.cs new file mode 100644 index 000000000..a5b39b1db --- /dev/null +++ b/src/Discord.Net/API/Rest/RemoveGuildMember.cs @@ -0,0 +1,20 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class RemoveGuildMemberRequest : IRestRequest + { + string IRestRequest.Method => "DELETE"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong UserId { get; } + + public RemoveGuildMemberRequest(ulong guildId, ulong userId) + { + GuildId = guildId; + UserId = userId; + } + } +} diff --git a/src/Discord.Net/API/Rest/SyncGuildIntegration.cs b/src/Discord.Net/API/Rest/SyncGuildIntegration.cs new file mode 100644 index 000000000..4c7f0acfa --- /dev/null +++ b/src/Discord.Net/API/Rest/SyncGuildIntegration.cs @@ -0,0 +1,21 @@ +using Discord.Net.Rest; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class SyncGuildIntegrationRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"guilds/{GuildId}/integrations/{IntegrationId}/sync"; + object IRestRequest.Payload => null; + + public ulong GuildId { get; } + public ulong IntegrationId { get; } + + public SyncGuildIntegrationRequest(ulong guildId, ulong integrationId) + { + GuildId = guildId; + IntegrationId = integrationId; + } + } +} diff --git a/src/Discord.Net/API/Rest/TriggerTypingIndicator.cs b/src/Discord.Net/API/Rest/TriggerTypingIndicator.cs new file mode 100644 index 000000000..3c0baa855 --- /dev/null +++ b/src/Discord.Net/API/Rest/TriggerTypingIndicator.cs @@ -0,0 +1,18 @@ +using Discord.Net.Rest; + +namespace Discord.API.Rest +{ + public class TriggerTypingIndicatorRequest : IRestRequest + { + string IRestRequest.Method => "POST"; + string IRestRequest.Endpoint => $"channels/{ChannelId}/typing"; + object IRestRequest.Payload => null; + + public ulong ChannelId { get; } + + public TriggerTypingIndicatorRequest(ulong channelId) + { + ChannelId = channelId; + } + } +} diff --git a/src/Discord.Net/API/Client/Rest/SendFile.cs b/src/Discord.Net/API/Rest/Unconfirmed/SendFile.cs similarity index 50% rename from src/Discord.Net/API/Client/Rest/SendFile.cs rename to src/Discord.Net/API/Rest/Unconfirmed/SendFile.cs index 4b59e1a11..d7252e7d4 100644 --- a/src/Discord.Net/API/Client/Rest/SendFile.cs +++ b/src/Discord.Net/API/Rest/Unconfirmed/SendFile.cs @@ -1,21 +1,31 @@ -using Newtonsoft.Json; +using Discord.Net.Rest; +using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; -namespace Discord.API.Client.Rest +namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] public class SendFileRequest : IRestFileRequest { string IRestRequest.Method => "POST"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages"; object IRestRequest.Payload => null; + string IRestFileRequest.Filename => Filename; Stream IRestFileRequest.Stream => Stream; + IReadOnlyList IRestFileRequest.MultipartParameters => ImmutableArray.Create( + new RestParameter("content", Content), + new RestParameter("nonce", Nonce), + new RestParameter("tts", IsTTS) + ); - public ulong ChannelId { get; set; } + public ulong ChannelId { get; } public string Filename { get; set; } public Stream Stream { get; set; } + public string Content { get; set; } + public string Nonce { get; set; } + public bool IsTTS { get; set; } public SendFileRequest(ulong channelId) { diff --git a/src/Discord.Net/API/Status/Common/StatusResult.cs b/src/Discord.Net/API/Status/Common/StatusResult.cs deleted file mode 100644 index 74728c578..000000000 --- a/src/Discord.Net/API/Status/Common/StatusResult.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace Discord.API.Status -{ - public class StatusResult - { - public class PageData - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("url")] - public string Url { get; set; } - [JsonProperty("updated_at")] - public DateTime? UpdatedAt { get; set; } - } - - public class IncidentData - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("page_id")] - public string PageId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("status")] - public string Status { get; set; } - [JsonProperty("shortlink")] - public string Shortlink { get; set; } - [JsonProperty("impact")] - public string Impact { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - [JsonProperty("updated_at")] - public DateTime UpdatedAt { get; set; } - [JsonProperty("monitoring_at")] - public DateTime? MonitoringAt { get; set; } - [JsonProperty("resolved_at")] - public DateTime? ResolvedAt { get; set; } - [JsonProperty("scheduled_for")] - public DateTime StartTime { get; set; } - [JsonProperty("scheduled_until")] - public DateTime EndTime { get; set; } - - [JsonProperty("incident_updates")] - public IncidentUpdateData[] Updates { get; set; } - } - - public class IncidentUpdateData - { - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("incident_id")] - public string IncidentId { get; set; } - [JsonProperty("status")] - public string Status { get; set; } - [JsonProperty("body")] - public string Body { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - [JsonProperty("updated_at")] - public DateTime? UpdatedAt { get; set; } - [JsonProperty("display_at")] - public DateTime? DisplayAt { get; set; } - - } - - [JsonProperty("page")] - public PageData Page { get; set; } - [JsonProperty("scheduled_maintenances")] - public IncidentData[] ScheduledMaintenances { get; set; } - [JsonProperty("incidents")] - public IncidentData[] Incidents { get; set; } - } -} diff --git a/src/Discord.Net/API/Status/Rest/ActiveMaintenances.cs b/src/Discord.Net/API/Status/Rest/ActiveMaintenances.cs deleted file mode 100644 index 639f85f08..000000000 --- a/src/Discord.Net/API/Status/Rest/ActiveMaintenances.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Status.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetActiveMaintenancesRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"scheduled-maintenances/active.json"; - object IRestRequest.Payload => null; - } -} diff --git a/src/Discord.Net/API/Status/Rest/AllIncidents.cs b/src/Discord.Net/API/Status/Rest/AllIncidents.cs deleted file mode 100644 index 9575bbd43..000000000 --- a/src/Discord.Net/API/Status/Rest/AllIncidents.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Status.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetAllIncidentsRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"incidents.json"; - object IRestRequest.Payload => null; - } -} diff --git a/src/Discord.Net/API/Status/Rest/UnresolvedIncidents.cs b/src/Discord.Net/API/Status/Rest/UnresolvedIncidents.cs deleted file mode 100644 index 3cff11c23..000000000 --- a/src/Discord.Net/API/Status/Rest/UnresolvedIncidents.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Status.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetUnresolvedIncidentsRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"incidents/unresolved.json"; - object IRestRequest.Payload => null; - } -} diff --git a/src/Discord.Net/API/Status/Rest/UpcomingMaintenances.cs b/src/Discord.Net/API/Status/Rest/UpcomingMaintenances.cs deleted file mode 100644 index 803a8a630..000000000 --- a/src/Discord.Net/API/Status/Rest/UpcomingMaintenances.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.Status.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class GetUpcomingMaintenancesRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"scheduled-maintenances/upcoming.json"; - object IRestRequest.Payload => null; - } -} diff --git a/src/Discord.Net/API/Client/VoiceSocket/OpCodes.cs b/src/Discord.Net/API/VoiceSocket/OpCode.cs similarity index 81% rename from src/Discord.Net/API/Client/VoiceSocket/OpCodes.cs rename to src/Discord.Net/API/VoiceSocket/OpCode.cs index e82ab5286..d9174be22 100644 --- a/src/Discord.Net/API/Client/VoiceSocket/OpCodes.cs +++ b/src/Discord.Net/API/VoiceSocket/OpCode.cs @@ -1,10 +1,10 @@ -namespace Discord.API.Client.VoiceSocket +namespace Discord.API.VoiceSocket { - public enum OpCodes : byte + public enum OpCode : byte { /// C→S - Used to associate a connection with a token. Identify = 0, - /// C→S - Used to specify configuration. + /// C→S - Used to specify protocol configuration. SelectProtocol = 1, /// C←S - Used to notify that the voice connection was successful and informs the client of available protocols. Ready = 2, diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs new file mode 100644 index 000000000..f2f356854 --- /dev/null +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs @@ -0,0 +1,10 @@ +using System; + +namespace Discord.API.VoiceSocket +{ + public class HeartbeatCommand : IWebSocketMessage + { + int IWebSocketMessage.OpCode => (int)OpCode.Heartbeat; + object IWebSocketMessage.Payload => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + } +} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs new file mode 100644 index 000000000..06a63e3c2 --- /dev/null +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Discord.API.VoiceSocket +{ + public class IdentifyCommand : IWebSocketMessage + { + int IWebSocketMessage.OpCode => (int)OpCode.Identify; + object IWebSocketMessage.Payload => this; + + [JsonProperty("server_id")] + public ulong GuildId { get; set; } + [JsonProperty("user_id")] + public ulong UserId { get; set; } + [JsonProperty("session_id")] + public string SessionId { get; set; } + [JsonProperty("token")] + public string Token { get; set; } + } +} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs new file mode 100644 index 000000000..4aa71b4f3 --- /dev/null +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Discord.API.VoiceSocket +{ + public class SelectProtocolCommand : IWebSocketMessage + { + int IWebSocketMessage.OpCode => (int)OpCode.SelectProtocol; + object IWebSocketMessage.Payload => this; + + public class ProtocolData + { + [JsonProperty("address")] + public string Address { get; set; } + [JsonProperty("port")] + public int Port { get; set; } + [JsonProperty("mode")] + public string Mode { get; set; } + } + [JsonProperty("protocol")] + public string Protocol { get; set; } = "udp"; + [JsonProperty("data")] + private ProtocolData Data { get; } = new ProtocolData(); + + public string ExternalAddress { get { return Data.Address; } set { Data.Address = value; } } + public int ExternalPort { get { return Data.Port; } set { Data.Port = value; } } + public string EncryptionMode { get { return Data.Mode; } set { Data.Mode = value; } } + } +} diff --git a/src/Discord.Net/API/Client/VoiceSocket/Commands/SetSpeaking.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs similarity index 66% rename from src/Discord.Net/API/Client/VoiceSocket/Commands/SetSpeaking.cs rename to src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs index 6022c4d58..0476b9a7d 100644 --- a/src/Discord.Net/API/Client/VoiceSocket/Commands/SetSpeaking.cs +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs @@ -1,12 +1,11 @@ using Newtonsoft.Json; -namespace Discord.API.Client.VoiceSocket +namespace Discord.API.VoiceSocket { public class SetSpeakingCommand : IWebSocketMessage { - int IWebSocketMessage.OpCode => (int)OpCodes.Speaking; + int IWebSocketMessage.OpCode => (int)OpCode.Speaking; object IWebSocketMessage.Payload => this; - bool IWebSocketMessage.IsPrivate => false; [JsonProperty("speaking")] public bool IsSpeaking { get; set; } diff --git a/src/Discord.Net/API/Client/VoiceSocket/Events/Ready.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs similarity index 90% rename from src/Discord.Net/API/Client/VoiceSocket/Events/Ready.cs rename to src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs index 6fdced897..7ba700d96 100644 --- a/src/Discord.Net/API/Client/VoiceSocket/Events/Ready.cs +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client.VoiceSocket +namespace Discord.API.VoiceSocket { public class ReadyEvent { diff --git a/src/Discord.Net/API/Client/VoiceSocket/Events/SessionDescription.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs similarity index 85% rename from src/Discord.Net/API/Client/VoiceSocket/Events/SessionDescription.cs rename to src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs index 042c5278d..09bda01c1 100644 --- a/src/Discord.Net/API/Client/VoiceSocket/Events/SessionDescription.cs +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace Discord.API.Client.VoiceSocket +namespace Discord.API.VoiceSocket { public class SessionDescriptionEvent { diff --git a/src/Discord.Net/API/Client/VoiceSocket/Events/Speaking.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs similarity index 57% rename from src/Discord.Net/API/Client/VoiceSocket/Events/Speaking.cs rename to src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs index 59268c4e6..0e1271f98 100644 --- a/src/Discord.Net/API/Client/VoiceSocket/Events/Speaking.cs +++ b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs @@ -1,11 +1,10 @@ -using Discord.API.Converters; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Client.VoiceSocket +namespace Discord.API.VoiceSocket { public class SpeakingEvent { - [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] + [JsonProperty("user_id")] public ulong UserId { get; set; } [JsonProperty("ssrc")] public uint SSRC { get; set; } diff --git a/src/Discord.Net/CDN.cs b/src/Discord.Net/CDN.cs new file mode 100644 index 000000000..11786436b --- /dev/null +++ b/src/Discord.Net/CDN.cs @@ -0,0 +1,12 @@ +namespace Discord +{ + internal static class CDN + { + public static string GetUserAvatarUrl(ulong userId, string avatarId) + => avatarId != null ? $"{DiscordConfig.ClientAPIUrl}users/{userId}/avatars/{avatarId}.jpg" : null; + public static string GetGuildIconUrl(ulong guildId, string iconId) + => iconId != null ? $"{DiscordConfig.ClientAPIUrl}guilds/{guildId}/icons/{iconId}.jpg" : null; + public static string GetGuildSplashUrl(ulong guildId, string splashId) + => splashId != null ? $"{DiscordConfig.ClientAPIUrl}guilds/{guildId}/splashes/{splashId}.jpg" : null; + } +} diff --git a/src/Discord.Net/Discord.Net.Net45.csproj b/src/Discord.Net/Discord.Net.Net45.csproj new file mode 100644 index 000000000..f5d12fb3f --- /dev/null +++ b/src/Discord.Net/Discord.Net.Net45.csproj @@ -0,0 +1,305 @@ + + + + + + Debug + AnyCPU + {C6A50D24-CBD3-4E76-852C-4DCA60BBD608} + Library + Properties + Discord + Discord.Net + v4.6.1 + 512 + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + MinimumRecommendedRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/Discord.Net/Discord.Net.Net45.project.json b/src/Discord.Net/Discord.Net.Net45.project.json new file mode 100644 index 000000000..0d36751ed --- /dev/null +++ b/src/Discord.Net/Discord.Net.Net45.project.json @@ -0,0 +1,12 @@ +{ + "dependencies": { + "Newtonsoft.Json": "8.0.3", + "System.Collections.Immutable": "1.2.0-rc2-23608" + }, + "frameworks": { + "net461": {} + }, + "runtimes": { + "win": {} + } +} \ No newline at end of file diff --git a/src/Discord.Net/Discord.Net.Net45.project.lock.json b/src/Discord.Net/Discord.Net.Net45.project.lock.json new file mode 100644 index 000000000..aad5884f0 --- /dev/null +++ b/src/Discord.Net/Discord.Net.Net45.project.lock.json @@ -0,0 +1,88 @@ +{ + "locked": false, + "version": 2, + "targets": { + ".NETFramework,Version=v4.6.1": { + "Newtonsoft.Json/8.0.3": { + "type": "package", + "compile": { + "lib/net45/Newtonsoft.Json.dll": {} + }, + "runtime": { + "lib/net45/Newtonsoft.Json.dll": {} + } + }, + "System.Collections.Immutable/1.2.0-rc2-23608": { + "type": "package", + "compile": { + "lib/dotnet5.1/System.Collections.Immutable.dll": {} + }, + "runtime": { + "lib/dotnet5.1/System.Collections.Immutable.dll": {} + } + } + }, + ".NETFramework,Version=v4.6.1/win": { + "Newtonsoft.Json/8.0.3": { + "type": "package", + "compile": { + "lib/net45/Newtonsoft.Json.dll": {} + }, + "runtime": { + "lib/net45/Newtonsoft.Json.dll": {} + } + }, + "System.Collections.Immutable/1.2.0-rc2-23608": { + "type": "package", + "compile": { + "lib/dotnet5.1/System.Collections.Immutable.dll": {} + }, + "runtime": { + "lib/dotnet5.1/System.Collections.Immutable.dll": {} + } + } + } + }, + "libraries": { + "Newtonsoft.Json/8.0.3": { + "sha512": "KGsYQdS2zLH+H8x2cZaSI7e+YZ4SFIbyy1YJQYl6GYBWjf5o4H1A68nxyq+WTyVSOJQ4GqS/DiPE+UseUizgMg==", + "type": "package", + "files": [ + "Newtonsoft.Json.8.0.3.nupkg.sha512", + "Newtonsoft.Json.nuspec", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/portable-net40+sl5+wp80+win8+wpa81/Newtonsoft.Json.dll", + "lib/portable-net40+sl5+wp80+win8+wpa81/Newtonsoft.Json.xml", + "lib/portable-net45+wp80+win8+wpa81+dnxcore50/Newtonsoft.Json.dll", + "lib/portable-net45+wp80+win8+wpa81+dnxcore50/Newtonsoft.Json.xml", + "tools/install.ps1" + ] + }, + "System.Collections.Immutable/1.2.0-rc2-23608": { + "sha512": "LIodNcjmeDMzZ0P0nadxBAiZcxwTNXmiHMJoyj1xO2vvahd617xLnO8tJrWNCKgPcwDimuAC9twqsQRFiDOuDQ==", + "type": "package", + "files": [ + "System.Collections.Immutable.1.2.0-rc2-23608.nupkg.sha512", + "System.Collections.Immutable.nuspec", + "lib/dotnet5.1/System.Collections.Immutable.dll", + "lib/dotnet5.1/System.Collections.Immutable.xml", + "lib/portable-net45+win8+wp8+wpa81/System.Collections.Immutable.dll", + "lib/portable-net45+win8+wp8+wpa81/System.Collections.Immutable.xml" + ] + } + }, + "projectFileDependencyGroups": { + "": [ + "Newtonsoft.Json >= 8.0.3", + "System.Collections.Immutable >= 1.2.0-rc2-23608" + ], + ".NETFramework,Version=v4.6.1": [] + } +} \ No newline at end of file diff --git a/src/Discord.Net/Discord.Net.xproj b/src/Discord.Net/Discord.Net.xproj index be1dbc400..e5ec681b5 100644 --- a/src/Discord.Net/Discord.Net.xproj +++ b/src/Discord.Net/Discord.Net.xproj @@ -1,20 +1,20 @@  - + - 14.0 + 14.0.25123 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - acfb060b-ec8a-4926-b293-04c01e17ee23 + 2c91bdd7-621d-460f-b768-ead106d9ba62 Discord - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\..\TestBot\artifacts\obj\$(MSBuildProjectName) + ..\..\..\TestBot\artifacts\bin\$(MSBuildProjectName)\ 2.0 - + True diff --git a/src/Discord.Net/DiscordClient.Events.cs b/src/Discord.Net/DiscordClient.Events.cs deleted file mode 100644 index b05725f9b..000000000 --- a/src/Discord.Net/DiscordClient.Events.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Discord -{ - public partial class DiscordClient - { - public event EventHandler Ready = delegate { }; - //public event EventHandler LoggedOut = delegate { }; - public event EventHandler ChannelCreated = delegate { }; - public event EventHandler ChannelDestroyed = delegate { }; - public event EventHandler ChannelUpdated = delegate { }; - public event EventHandler MessageAcknowledged = delegate { }; - public event EventHandler MessageDeleted = delegate { }; - public event EventHandler MessageReceived = delegate { }; - public event EventHandler MessageSent = delegate { }; - public event EventHandler MessageUpdated = delegate { }; - public event EventHandler ProfileUpdated = delegate { }; - public event EventHandler RoleCreated = delegate { }; - public event EventHandler RoleUpdated = delegate { }; - public event EventHandler RoleDeleted = delegate { }; - public event EventHandler JoinedServer = delegate { }; - public event EventHandler LeftServer = delegate { }; - public event EventHandler ServerAvailable = delegate { }; - public event EventHandler ServerUpdated = delegate { }; - public event EventHandler ServerUnavailable = delegate { }; - public event EventHandler UserBanned = delegate { }; - public event EventHandler UserIsTyping = delegate { }; - public event EventHandler UserJoined = delegate { }; - public event EventHandler UserLeft = delegate { }; - public event EventHandler UserUpdated = delegate { }; - public event EventHandler UserUnbanned = delegate { }; - - private void OnReady() - => OnEvent(Ready); - /*private void OnLoggedOut(bool wasUnexpected, Exception ex) - => OnEvent(LoggedOut, new DisconnectedEventArgs(wasUnexpected, ex));*/ - - private void OnChannelCreated(IChannel channel) - => OnEvent(ChannelCreated, new ChannelEventArgs(channel)); - private void OnChannelDestroyed(IChannel channel) - => OnEvent(ChannelDestroyed, new ChannelEventArgs(channel)); - private void OnChannelUpdated(IChannel before, IChannel after) - => OnEvent(ChannelUpdated, new ChannelUpdatedEventArgs(before, after)); - - private void OnMessageAcknowledged(Message msg) - => OnEvent(MessageAcknowledged, new MessageEventArgs(msg)); - private void OnMessageDeleted(Message msg) - => OnEvent(MessageDeleted, new MessageEventArgs(msg)); - private void OnMessageReceived(Message msg) - => OnEvent(MessageReceived, new MessageEventArgs(msg)); - internal void OnMessageSent(Message msg) - => OnEvent(MessageSent, new MessageEventArgs(msg)); - private void OnMessageUpdated(Message before, Message after) - => OnEvent(MessageUpdated, new MessageUpdatedEventArgs(before, after)); - - private void OnProfileUpdated(Profile before, Profile after) - => OnEvent(ProfileUpdated, new ProfileUpdatedEventArgs(before, after)); - - private void OnRoleCreated(Role role) - => OnEvent(RoleCreated, new RoleEventArgs(role)); - private void OnRoleDeleted(Role role) - => OnEvent(RoleDeleted, new RoleEventArgs(role)); - private void OnRoleUpdated(Role before, Role after) - => OnEvent(RoleUpdated, new RoleUpdatedEventArgs(before, after)); - - private void OnJoinedServer(Server server) - => OnEvent(JoinedServer, new ServerEventArgs(server)); - private void OnLeftServer(Server server) - => OnEvent(LeftServer, new ServerEventArgs(server)); - private void OnServerAvailable(Server server) - => OnEvent(ServerAvailable, new ServerEventArgs(server)); - private void OnServerUpdated(Server before, Server after) - => OnEvent(ServerUpdated, new ServerUpdatedEventArgs(before, after)); - private void OnServerUnavailable(Server server) - => OnEvent(ServerUnavailable, new ServerEventArgs(server)); - - private void OnUserBanned(User user) - => OnEvent(UserBanned, new UserEventArgs(user)); - private void OnUserIsTypingUpdated(ITextChannel channel, User user) - => OnEvent(UserIsTyping, new TypingEventArgs(channel, user)); - private void OnUserJoined(User user) - => OnEvent(UserJoined, new UserEventArgs(user)); - private void OnUserLeft(User user) - => OnEvent(UserLeft, new UserEventArgs(user)); - private void OnUserUnbanned(User user) - => OnEvent(UserUnbanned, new UserEventArgs(user)); - private void OnUserUpdated(User before, User after) - => OnEvent(UserUpdated, new UserUpdatedEventArgs(before, after)); - - private void OnEvent(EventHandler handler, T eventArgs, [CallerMemberName] string callerName = null) - { - try { handler(this, eventArgs); } - catch (Exception ex) - { - Logger.Error($"{callerName.Substring(2)}'s handler encountered an error", ex); - } - } - private void OnEvent(EventHandler handler, [CallerMemberName] string callerName = null) - { - try { handler(this, EventArgs.Empty); } - catch (Exception ex) - { - Logger.Error($"{callerName.Substring(2)}'s handler encountered an error", ex); - } - } - } -} diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 5fa94bbc2..d59f7fec1 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -1,398 +1,136 @@ -using APIChannel = Discord.API.Client.Channel; -using Discord.API.Client.GatewaySocket; -using Discord.API.Client.Rest; +using Discord.API.Rest; using Discord.Logging; using Discord.Net; using Discord.Net.Rest; -using Discord.Net.WebSockets; -using Newtonsoft.Json; -using Nito.AsyncEx; using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Net; -using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Discord { - /// Provides a connection to the DiscordApp service. - public partial class DiscordClient : IDisposable + public class DiscordClient : IDisposable { - private readonly AsyncLock _connectionLock; - private readonly ManualResetEvent _disconnectedEvent; - private readonly ManualResetEventSlim _connectedEvent; - private readonly TaskManager _taskManager; - private readonly ServiceCollection _services; - private ConcurrentDictionary _servers; - private ConcurrentDictionary _channels; - private ConcurrentDictionary _privateChannels; //Key = RecipientId - private Dictionary _regions; - private Stopwatch _connectionStopwatch; - - internal Logger Logger { get; } - - /// Gets the configuration object used to make this client. - public DiscordConfig Config { get; } - /// Gets the log manager. - public LogManager Log { get; } - /// Gets the internal RestClient for the Client API endpoint. - public RestClient ClientAPI { get; } - /// Gets the internal RestClient for the Status API endpoint. - public RestClient StatusAPI { get; } - /// Gets the internal WebSocket for the Gateway event stream. - public GatewaySocket GatewaySocket { get; } + public event EventHandler Log; + public event EventHandler LoggedIn, LoggedOut; + + protected readonly RestClientProvider _restClientProvider; + protected readonly string _token; + protected readonly LogManager _logManager; + protected readonly SemaphoreSlim _connectionLock; + protected readonly Logger _restLogger; + protected CancellationTokenSource _cancelToken; + protected bool _isDisposed; + + public string UserAgent { get; } + public IReadOnlyList VoiceRegions { get; private set; } + /// Gets the internal RestClient. + public RestClient RestClient { get; protected set; } /// Gets the queue used for outgoing messages, if enabled. - public MessageQueue MessageQueue { get; } - /// Gets the JSON serializer used by this client. - public JsonSerializer Serializer { get; } - - /// Gets the current connection state of this client. - public ConnectionState State { get; private set; } - /// Gets a cancellation token that triggers when the client is manually disconnected. - public CancellationToken CancelToken { get; private set; } - /// Gets the current logged-in user used in private channels. - internal User PrivateUser { get; private set; } - /// Gets information about the current logged-in account. - public Profile CurrentUser { get; private set; } - /// Gets the session id for the current connection. - public string SessionId { get; private set; } - /// Gets the status of the current user. - public UserStatus Status { get; private set; } - /// Gets the game the current user is displayed as playing. - public string CurrentGame { get; private set; } + public MessageQueue MessageQueue { get; protected set; } + public SelfUser CurrentUser { get; protected set; } + public bool IsLoggedIn { get; private set; } - /// Gets a collection of all extensions added to this DiscordClient. - public IEnumerable Services => _services; - /// Gets a collection of all servers this client is a member of. - public IEnumerable Servers => _servers.Select(x => x.Value); - /// Gets a collection of all private channels this client is a member of. - public IEnumerable PrivateChannels => _privateChannels.Select(x => x.Value); - /// Gets a collection of all voice regions currently offered by Discord. - public IEnumerable Regions => _regions.Select(x => x.Value); + internal CancellationToken CancelToken => _cancelToken.Token; - /// Initializes a new instance of the DiscordClient class. - public DiscordClient(Action configFunc) - : this(ProcessConfig(configFunc)) - { - } - private static DiscordConfigBuilder ProcessConfig(Action func) - { - var config = new DiscordConfigBuilder(); - func(config); - return config; - } - - /// Initializes a new instance of the DiscordClient class. - public DiscordClient() - : this(new DiscordConfigBuilder()) - { - } - /// Initializes a new instance of the DiscordClient class. - public DiscordClient(DiscordConfigBuilder builder) - : this(builder.Build()) - { - if (builder.LogHandler != null) - Log.Message += builder.LogHandler; - } - /// Initializes a new instance of the DiscordClient class. - public DiscordClient(DiscordConfig config) + public DiscordClient(string token, DiscordConfig config = null) { - Config = config; - - State = (int)ConnectionState.Disconnected; - Status = UserStatus.Online; - - //Logging - Log = new LogManager(this); - Logger = Log.CreateLogger("Discord"); - if (config.LogLevel >= LogSeverity.Verbose) - _connectionStopwatch = new Stopwatch(); + if (token == null) throw new ArgumentNullException(nameof(token)); - //Async - _taskManager = new TaskManager(Cleanup); - _connectionLock = new AsyncLock(); - _disconnectedEvent = new ManualResetEvent(true); - _connectedEvent = new ManualResetEventSlim(false); - CancelToken = new CancellationToken(true); - - //Cache - //ConcurrentLevel = 2 (only REST and WebSocket can add/remove) - _servers = new ConcurrentDictionary(2, 0); - _channels = new ConcurrentDictionary(2, 0); - _privateChannels = new ConcurrentDictionary(2, 0); - - //Serialization - Serializer = new JsonSerializer(); - Serializer.DateTimeZoneHandling = DateTimeZoneHandling.Utc; -#if TEST_RESPONSES - Serializer.CheckAdditionalContent = true; - Serializer.MissingMemberHandling = MissingMemberHandling.Error; -#else - Serializer.CheckAdditionalContent = false; - Serializer.MissingMemberHandling = MissingMemberHandling.Ignore; -#endif - Serializer.Error += (s, e) => - { - e.ErrorContext.Handled = true; - Logger.Error("Serialization Failed", e.ErrorContext.Error); - }; + if (config == null) + config = new DiscordConfig(); - //Networking - ClientAPI = new JsonRestClient(Config, DiscordConfig.ClientAPIUrl, Log.CreateLogger("ClientAPI")); - StatusAPI = new JsonRestClient(Config, DiscordConfig.StatusAPIUrl, Log.CreateLogger("StatusAPI")); - GatewaySocket = new GatewaySocket(Config, Serializer, Log.CreateLogger("Gateway")); - - //GatewaySocket.Disconnected += (s, e) => OnDisconnected(e.WasUnexpected, e.Exception); - GatewaySocket.ReceivedDispatch += (s, e) => OnReceivedEvent(e); + _token = token; + _connectionLock = new SemaphoreSlim(1, 1); - MessageQueue = new MessageQueue(ClientAPI, Log.CreateLogger("MessageQueue")); - - //Extensibility - _services = new ServiceCollection(this); - } - - /// Connects to the Discord server with the provided email and password. - /// Returns a token that can be optionally stored to speed up future connections. - public async Task Connect(string email, string password, string token = null) - { - if (email == null) throw new ArgumentNullException(email); - if (password == null) throw new ArgumentNullException(password); + _restClientProvider = config.RestClientProvider; + UserAgent = GetUserAgent(config.AppName, config.AppVersion, config.AppUrl); - await BeginConnect(email, password, null).ConfigureAwait(false); - return ClientAPI.Token; - } - /// Connects to the Discord server with the provided token. - public async Task Connect(string token) - { - if (token == null) throw new ArgumentNullException(token); - - await BeginConnect(null, null, token).ConfigureAwait(false); + _logManager = new LogManager(config.LogLevel); + _logManager.Message += (s, e) => Log(this, e); + _restLogger = _logManager.CreateLogger("Rest"); } - private async Task BeginConnect(string email, string password, string token = null) + public async Task Login() { + await _connectionLock.WaitAsync().ConfigureAwait(false); try { - using (await _connectionLock.LockAsync().ConfigureAwait(false)) - { - await Disconnect().ConfigureAwait(false); - _taskManager.ClearException(); - - Stopwatch stopwatch = null; - if (Config.LogLevel >= LogSeverity.Verbose) - { - _connectionStopwatch.Restart(); - stopwatch = Stopwatch.StartNew(); - } - State = ConnectionState.Connecting; - _disconnectedEvent.Reset(); - - var cancelSource = new CancellationTokenSource(); - CancelToken = cancelSource.Token; - ClientAPI.CancelToken = CancelToken; - StatusAPI.CancelToken = CancelToken; - - await Login(email, password, token).ConfigureAwait(false); - await GatewaySocket.Connect(ClientAPI, CancelToken).ConfigureAwait(false); - - var tasks = new[] { CancelToken.Wait() } - .Concat(MessageQueue.Run(CancelToken)); - - await _taskManager.Start(tasks, cancelSource).ConfigureAwait(false); - GatewaySocket.WaitForConnection(CancelToken); - - if (Config.LogLevel >= LogSeverity.Verbose) - { - stopwatch.Stop(); - double seconds = Math.Round(stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerSecond, 2); - Logger.Verbose($"Handshake + Ready took {seconds} sec"); - } - } - } - catch (Exception ex) - { - await _taskManager.SignalError(ex).ConfigureAwait(false); - throw; + await LoginInternal().ConfigureAwait(false); } + finally { _connectionLock.Release(); } } - private async Task Login(string email = null, string password = null, string token = null) + protected virtual async Task LoginInternal() { - string tokenPath = null, oldToken = null; - byte[] cacheKey = null; + if (IsLoggedIn) + await LogoutInternal().ConfigureAwait(false); - //Get Token - if (email != null && Config.CacheDir != null) + try { - tokenPath = GetTokenCachePath(email); - if (token == null && password != null) - { - Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, - new byte[] { 0x5A, 0x2A, 0xF8, 0xCF, 0x78, 0xD3, 0x7D, 0x0D }); - cacheKey = deriveBytes.GetBytes(16); + _cancelToken = new CancellationTokenSource(); - oldToken = LoadToken(tokenPath, cacheKey); - token = oldToken; - } - } + RestClient = new RestClient(_restClientProvider(DiscordConfig.ClientAPIUrl, _cancelToken.Token)); + RestClient.SetHeader("accept", "*/*"); + RestClient.SetHeader("authorization", _token); + RestClient.SetHeader("user-agent", UserAgent); + RestClient.SentRequest += (s, e) => _restLogger.Verbose($"{e.Request.Method} {e.Request.Endpoint}: {e.Milliseconds} ms"); - ClientAPI.Token = token; - var request = new LoginRequest() { Email = email, Password = password }; - var response = await ClientAPI.Send(request).ConfigureAwait(false); - token = response.Token; - if (Config.CacheDir != null && token != oldToken && tokenPath != null) - SaveToken(tokenPath, cacheKey, token); - ClientAPI.Token = token; + MessageQueue = new MessageQueue(RestClient, _restLogger); + await MessageQueue.Start(_cancelToken.Token).ConfigureAwait(false); - //Cache other stuff - var regionsResponse = (await ClientAPI.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false)); - _regions = regionsResponse.Select(x => new Region(x.Id, x.Name, x.Hostname, x.Port, x.Vip)) - .ToDictionary(x => x.Id); - } - private void EndConnect() - { - if (State == ConnectionState.Connecting) - { - State = ConnectionState.Connected; - _connectedEvent.Set(); + var selfResponse = await RestClient.Send(new GetCurrentUserRequest()).ConfigureAwait(false); + var regionsResponse = await RestClient.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false); - if (Config.LogLevel >= LogSeverity.Verbose) - { - _connectionStopwatch.Stop(); - double seconds = Math.Round(_connectionStopwatch.ElapsedTicks / (double)TimeSpan.TicksPerSecond, 2); - Logger.Verbose($"Connection took {seconds} sec"); - } + CurrentUser = CreateSelfUser(selfResponse); + VoiceRegions = regionsResponse.Select(x => CreateVoiceRegion(x)).ToImmutableArray(); - SendStatus(); - OnReady(); + IsLoggedIn = true; + RaiseEvent(LoggedIn); } + catch (Exception) { await LogoutInternal().ConfigureAwait(false); throw; } } - /// Disconnects from the Discord server, canceling any pending requests. - public Task Disconnect() => _taskManager.Stop(true); - private async Task Cleanup() + public async Task Logout() { - var oldState = State; - State = ConnectionState.Disconnecting; - - if (oldState == ConnectionState.Connected) + _cancelToken?.Cancel(); + await _connectionLock.WaitAsync().ConfigureAwait(false); + try { - try { await ClientAPI.Send(new LogoutRequest()).ConfigureAwait(false); } - catch (OperationCanceledException) { } + await LogoutInternal().ConfigureAwait(false); } - - MessageQueue.Clear(); - - await GatewaySocket.Disconnect().ConfigureAwait(false); - ClientAPI.Token = null; - - _servers.Clear(); - _channels.Clear(); - _privateChannels.Clear(); - - PrivateUser = null; - CurrentUser = null; - - State = (int)ConnectionState.Disconnected; - _connectedEvent.Reset(); - _disconnectedEvent.Set(); + finally { _connectionLock.Release(); } } - - public void SetStatus(UserStatus status) + protected virtual async Task LogoutInternal() { - if (status == null) throw new ArgumentNullException(nameof(status)); - if (status != UserStatus.Online && status != UserStatus.Idle) - throw new ArgumentException($"Invalid status, must be {UserStatus.Online} or {UserStatus.Idle}", nameof(status)); + bool wasLoggedIn = IsLoggedIn; - Status = status; - SendStatus(); - } - public void SetGame(string game) - { - CurrentGame = game; - SendStatus(); - } - private void SendStatus() - { - PrivateUser.Status = Status; - PrivateUser.CurrentGame = CurrentGame; - foreach (var server in Servers) - { - var current = server.CurrentUser; - if (current != null) - { - current.Status = Status; - current.CurrentGame = CurrentGame; - } - } - var socket = GatewaySocket; - if (socket != null) - socket.SendUpdateStatus(Status == UserStatus.Idle ? EpochTime.GetMilliseconds() - (10 * 60 * 1000) : (long?)null, CurrentGame); - } + try { _cancelToken.Cancel(); } catch { } + try { await MessageQueue.Stop().ConfigureAwait(false); } catch { } - #region Channels - internal void AddChannel(IChannel channel) - { - _channels.GetOrAdd(channel.Id, channel); - } - private IChannel RemoveChannel(ulong id) - { - IChannel channel; - if (_channels.TryRemove(id, out channel)) + RestClient = null; + MessageQueue = null; + + if (wasLoggedIn) { - if (channel.IsPrivate) - { - PrivateChannel removed; - _privateChannels.TryRemove((channel as PrivateChannel).Recipient.Id, out removed); - } - else - (channel as PublicChannel).Server.RemoveChannel(id); + IsLoggedIn = false; + RaiseEvent(LoggedOut); } - return channel; - } - public IChannel GetChannel(ulong id) - { - IChannel channel; - _channels.TryGetValue(id, out channel); - return channel; } - private PrivateChannel AddPrivateChannel(APIChannel model) - { - IChannel channel; - if (_channels.TryGetOrAdd(model.Id, x => new PrivateChannel(x, new User(model.Recipient, this, null), model), out channel)) - _privateChannels[model.Recipient.Id] = channel as PrivateChannel; - return channel as PrivateChannel; - } - internal PrivateChannel GetPrivateChannel(ulong recipientId) + public virtual async Task> GetDMChannels() { - PrivateChannel channel; - _privateChannels.TryGetValue(recipientId, out channel); - return channel; - } - public Task CreatePrivateChannel(User user) => CreatePrivateChannel(user.Id); - public async Task CreatePrivateChannel(ulong userId) - { - var channel = GetPrivateChannel(userId); - if (channel != null) return channel; - - var request = new CreatePrivateChannelRequest() { RecipientId = userId }; - var response = await ClientAPI.Send(request).ConfigureAwait(false); - - return AddPrivateChannel(response); + var response = await RestClient.Send(new GetCurrentUserDMsRequest()).ConfigureAwait(false); + var result = ImmutableArray.CreateBuilder(response.Length); + for (int i = 0; i < response.Length; i++) + result[i] = CreateDMChannel(response[i]); + return result.ToImmutable(); } - #endregion - - #region Invites - /// Gets more info about the provided invite code. - /// Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode - /// The invite object if found, null if not. - public async Task GetInvite(string inviteIdOrXkcd) + public virtual async Task GetInvite(string inviteIdOrXkcd) { if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); @@ -406,697 +144,212 @@ namespace Discord try { - var response = await ClientAPI.Send(new GetInviteRequest(inviteIdOrXkcd)).ConfigureAwait(false); - var invite = new Invite(response, this); - invite.Update(response); - return invite; + var response = await RestClient.Send(new GetInviteRequest(inviteIdOrXkcd)).ConfigureAwait(false); + return CreatePublicInvite(response); } catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } } - #endregion - - #region Regions - public Region GetRegion(string id) + public virtual async Task GetGuild(ulong id) { - Region region; - if (_regions.TryGetValue(id, out region)) - return region; - else - return new Region(id, id, "", 0, false); + var response = await RestClient.Send(new GetGuildRequest(id)).ConfigureAwait(false); + return CreateGuild(response); } - #endregion - - #region Servers - private Server AddServer(ulong id) => _servers.GetOrAdd(id, x => new Server(x, this)); - private Server RemoveServer(ulong id) + public virtual async Task> GetGuilds() { - Server server; - if (_servers.TryRemove(id, out server)) + var response = await RestClient.Send(new GetCurrentUserGuildsRequest()).ConfigureAwait(false); + var result = ImmutableArray.CreateBuilder(response.Length); + for (int i = 0; i < response.Length; i++) + result[i] = CreateGuild(response[i]); + return result.ToImmutable(); + } + public virtual async Task GetUser(ulong id) + { + var response = await RestClient.Send(new GetUserRequest(id)); + var user = CreatePublicUser(response); + return user; + } + public virtual async Task GetUser(string username, ushort discriminator) + { + var response = await RestClient.Send(new QueryUserRequest() { Query = $"{username}#{discriminator}", Limit = 1 }); + if (response.Length > 0) { - foreach (var channel in server.AllChannels) - RemoveChannel(channel.Id); + var user = CreatePublicUser(response[0]); + return user; } - return server; + return null; } - - public Server GetServer(ulong id) + public virtual VoiceRegion GetOptimalVoiceRegion() + { + var regions = VoiceRegions; + for (int i = 0; i < regions.Count; i++) + { + if (regions[i].IsOptimal) + return regions[i]; + } + return null; + } + public virtual VoiceRegion GetVoiceRegion(string id) { - Server server; - _servers.TryGetValue(id, out server); - return server; + if (id == null) throw new ArgumentNullException(nameof(id)); + + var regions = VoiceRegions; + for (int i = 0; i < regions.Count; i++) + { + if (regions[i].Id == id) + return regions[i]; + } + return null; } - /// Creates a new server with the provided name and region. - public async Task CreateServer(string name, Region region, ImageType iconType = ImageType.None, Stream icon = null) + public virtual async Task GetOrCreateDMChannel(ulong userId) + { + var response = await RestClient.Send(new CreateDMChannelRequest + { + RecipientId = userId + }).ConfigureAwait(false); + + return CreateDMChannel(response); + } + /// Creates a new guild with the provided name and region. This function requires your bot to be whitelisted by Discord. + public virtual async Task CreateGuild(string name, VoiceRegion region, Stream jpegIcon = null) { if (name == null) throw new ArgumentNullException(nameof(name)); if (region == null) throw new ArgumentNullException(nameof(region)); - var request = new CreateGuildRequest() + var response = await RestClient.Send(new CreateGuildRequest { Name = name, Region = region.Id, - IconBase64 = icon.Base64(iconType, null) - }; - var response = await ClientAPI.Send(request).ConfigureAwait(false); + Icon = jpegIcon + }).ConfigureAwait(false); - var server = AddServer(response.Id); - server.Update(response); - return server; + return CreateGuild(response); } - #endregion - #region Gateway Events - private void OnReceivedEvent(WebSocketEventEventArgs e) + internal virtual DMChannel CreateDMChannel(API.Channel model) { - try - { - switch (e.Type) - { - //Global - case "READY": - { - //TODO: None of this is really threadsafe - should only replace the cache collections when they have been fully populated - - var data = e.Payload.ToObject(Serializer); - - int channelCount = 0; - for (int i = 0; i < data.Guilds.Length; i++) - channelCount += data.Guilds[i].Channels.Length; - - //ConcurrencyLevel = 2 (only REST and WebSocket can add/remove) - _servers = new ConcurrentDictionary(2, (int)(data.Guilds.Length * 1.05)); - _channels = new ConcurrentDictionary(2, (int)(channelCount * 1.05)); - _privateChannels = new ConcurrentDictionary(2, (int)(data.PrivateChannels.Length * 1.05)); - List largeServers = new List(); - - SessionId = data.SessionId; - PrivateUser = new User(data.User, this, null); - PrivateUser.Update(data.User); - CurrentUser = new Profile(data.User, this); - CurrentUser.Update(data.User); - - for (int i = 0; i < data.Guilds.Length; i++) - { - var model = data.Guilds[i]; - if (model.Unavailable != true) - { - var server = AddServer(model.Id); - server.Update(model); - if (model.IsLarge) - largeServers.Add(server.Id); - } - } - for (int i = 0; i < data.PrivateChannels.Length; i++) - AddPrivateChannel(data.PrivateChannels[i]); - if (largeServers.Count > 0) - GatewaySocket.SendRequestMembers(largeServers, "", 0); - else - EndConnect(); - } - break; - - //Servers - case "GUILD_CREATE": - { - var data = e.Payload.ToObject(Serializer); - if (data.Unavailable != true) - { - var server = AddServer(data.Id); - server.Update(data); - - if (data.Unavailable != false) - Logger.Info($"GUILD_CREATE: {server}"); - else - Logger.Info($"GUILD_AVAILABLE: {server}"); - - if (data.Unavailable != false) - OnJoinedServer(server); - OnServerAvailable(server); - } - } - break; - case "GUILD_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.Id); - if (server != null) - { - var before = Config.EnablePreUpdateEvents ? server.Clone() : null; - server.Update(data); - Logger.Info($"GUILD_UPDATE: {server}"); - OnServerUpdated(before, server); - } - else - Logger.Warning("GUILD_UPDATE referenced an unknown guild."); - } - break; - case "GUILD_DELETE": - { - var data = e.Payload.ToObject(Serializer); - Server server = RemoveServer(data.Id); - if (server != null) - { - if (data.Unavailable != true) - Logger.Info($"GUILD_DELETE: {server}"); - else - Logger.Info($"GUILD_UNAVAILABLE: {server}"); - - OnServerUnavailable(server); - if (data.Unavailable != true) - OnLeftServer(server); - } - else - Logger.Warning("GUILD_DELETE referenced an unknown guild."); - } - break; - - //Channels - case "CHANNEL_CREATE": - { - var data = e.Payload.ToObject(Serializer); - - IChannel channel = null; - if (data.GuildId != null) - { - var server = GetServer(data.GuildId.Value); - if (server != null) - channel = server.AddChannel(data, true); - else - { - Logger.Warning("CHANNEL_CREATE referenced an unknown guild."); - break; - } - } - else - channel = AddPrivateChannel(data); - Logger.Info($"CHANNEL_CREATE: {channel}"); - OnChannelCreated(channel); - } - break; - case "CHANNEL_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var channel = GetChannel(data.Id); - if (channel != null) - { - var before = Config.EnablePreUpdateEvents ? (channel as Channel).Clone() : null; - (channel as Channel).Update(data); - Logger.Info($"CHANNEL_UPDATE: {channel}"); - OnChannelUpdated(before, channel); - } - else - Logger.Warning("CHANNEL_UPDATE referenced an unknown channel."); - } - break; - case "CHANNEL_DELETE": - { - var data = e.Payload.ToObject(Serializer); - var channel = RemoveChannel(data.Id); - if (channel != null) - { - Logger.Info($"CHANNEL_DELETE: {channel}"); - OnChannelDestroyed(channel); - } - else - Logger.Warning("CHANNEL_DELETE referenced an unknown channel."); - } - break; - - //Members - case "GUILD_MEMBER_ADD": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId.Value); - if (server != null) - { - var user = server.AddUser(data, true, true); - user.Update(data); - user.UpdateActivity(); - Logger.Info($"GUILD_MEMBER_ADD: {user}"); - OnUserJoined(user); - } - else - Logger.Warning("GUILD_MEMBER_ADD referenced an unknown guild."); - } - break; - case "GUILD_MEMBER_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId.Value); - if (server != null) - { - var user = server.GetUser(data.User.Id); - if (user != null) - { - var before = Config.EnablePreUpdateEvents ? user.Clone() : null; - user.Update(data); - Logger.Info($"GUILD_MEMBER_UPDATE: {user}"); - OnUserUpdated(before, user); - } - else - Logger.Warning("GUILD_MEMBER_UPDATE referenced an unknown user."); - } - else - Logger.Warning("GUILD_MEMBER_UPDATE referenced an unknown guild."); - } - break; - case "GUILD_MEMBER_REMOVE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId.Value); - if (server != null) - { - var user = server.RemoveUser(data.User.Id); - if (user != null) - { - Logger.Info($"GUILD_MEMBER_REMOVE: {user}"); - OnUserLeft(user); - } - else - Logger.Warning("GUILD_MEMBER_REMOVE referenced an unknown user."); - } - else - Logger.Warning("GUILD_MEMBER_REMOVE referenced an unknown guild."); - } - break; - case "GUILD_MEMBERS_CHUNK": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId); - if (server != null) - { - foreach (var memberData in data.Members) - { - var user = server.AddUser(memberData, true, false); - user.Update(memberData); - } - Logger.Verbose($"GUILD_MEMBERS_CHUNK: {data.Members.Length} users"); - - if (server.CurrentUserCount >= server.UserCount) //Finished downloading for there - { - bool isConnectComplete = true; - foreach (var server2 in _servers.Select(x => x.Value)) - { - if (server2.CurrentUserCount < server2.UserCount) - isConnectComplete = false; - } - if (isConnectComplete) - EndConnect(); - } - } - else - Logger.Warning("GUILD_MEMBERS_CHUNK referenced an unknown guild."); - } - break; - - //Roles - case "GUILD_ROLE_CREATE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId); - if (server != null) - { - var role = server.AddRole(data.Data.Id); - role.Update(data.Data, false); - Logger.Info($"GUILD_ROLE_CREATE: {role}"); - OnRoleCreated(role); - } - else - Logger.Warning("GUILD_ROLE_CREATE referenced an unknown guild."); - } - break; - case "GUILD_ROLE_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId); - if (server != null) - { - var role = server.GetRole(data.Data.Id); - if (role != null) - { - var before = Config.EnablePreUpdateEvents ? role.Clone() : null; - role.Update(data.Data, true); - Logger.Info($"GUILD_ROLE_UPDATE: {role}"); - OnRoleUpdated(before, role); - } - else - Logger.Warning("GUILD_ROLE_UPDATE referenced an unknown role."); - } - else - Logger.Warning("GUILD_ROLE_UPDATE referenced an unknown guild."); - } - break; - case "GUILD_ROLE_DELETE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId); - if (server != null) - { - var role = server.RemoveRole(data.RoleId); - if (role != null) - { - Logger.Info($"GUILD_ROLE_DELETE: {role}"); - OnRoleDeleted(role); - } - else - Logger.Warning("GUILD_ROLE_DELETE referenced an unknown role."); - } - else - Logger.Warning("GUILD_ROLE_DELETE referenced an unknown guild."); - } - break; - - //Bans - case "GUILD_BAN_ADD": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId.Value); - if (server != null) - { - var user = server.GetUser(data.User.Id); - if (user != null) - { - Logger.Info($"GUILD_BAN_ADD: {user}"); - OnUserBanned(user); - } - else - Logger.Warning("GUILD_BAN_ADD referenced an unknown user."); - } - else - Logger.Warning("GUILD_BAN_ADD referenced an unknown guild."); - } - break; - case "GUILD_BAN_REMOVE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId.Value); - if (server != null) - { - var user = new User(data.User, this, server); - user.Update(data.User); - Logger.Info($"GUILD_BAN_REMOVE: {user}"); - OnUserUnbanned(user); - } - else - Logger.Warning("GUILD_BAN_REMOVE referenced an unknown guild."); - } - break; - - //Messages - case "MESSAGE_CREATE": - { - var data = e.Payload.ToObject(Serializer); - - var channel = GetChannel(data.ChannelId) as ITextChannel; - if (channel != null) - { - var user = (channel as Channel).GetUser(data.Author.Id); - - if (user != null) - { - Message msg = null; - msg = (channel as Channel).MessageManager.Add(data, user); - user.UpdateActivity(); - - Logger.Verbose($"MESSAGE_CREATE: {channel} ({user})"); - OnMessageReceived(msg); - } - else - Logger.Warning("MESSAGE_CREATE referenced an unknown user."); - } - else - Logger.Warning("MESSAGE_CREATE referenced an unknown channel."); - } - break; - case "MESSAGE_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var channel = GetChannel(data.ChannelId) as ITextChannel; - if (channel != null) - { - var msg = (channel as Channel).MessageManager.Get(data.Id, data.Author?.Id); - var before = Config.EnablePreUpdateEvents ? msg.Clone() : null; - msg.Update(data); - Logger.Verbose($"MESSAGE_UPDATE: {channel} ({data.Author?.Username ?? "Unknown"})"); - OnMessageUpdated(before, msg); - } - else - Logger.Warning("MESSAGE_UPDATE referenced an unknown channel."); - } - break; - case "MESSAGE_DELETE": - { - var data = e.Payload.ToObject(Serializer); - var channel = GetChannel(data.ChannelId) as ITextChannel; - if (channel != null) - { - var msg = (channel as Channel).MessageManager.Remove(data.Id); - Logger.Verbose($"MESSAGE_DELETE: {channel} ({msg.User?.Name ?? "Unknown"})"); - OnMessageDeleted(msg); - } - else - Logger.Warning("MESSAGE_DELETE referenced an unknown channel."); - } - break; - - //Statuses - case "PRESENCE_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - User user; - Server server; - if (data.GuildId == null) - { - server = null; - user = GetPrivateChannel(data.User.Id)?.Recipient; - } - else - { - server = GetServer(data.GuildId.Value); - if (server == null) - { - Logger.Warning("PRESENCE_UPDATE referenced an unknown server."); - break; - } - else - user = server.GetUser(data.User.Id); - } - - if (user != null) - { - if (Config.LogLevel == LogSeverity.Debug) - Logger.Debug($"PRESENCE_UPDATE: {user}"); - var before = Config.EnablePreUpdateEvents ? user.Clone() : null; - user.Update(data); - OnUserUpdated(before, user); - } - /*else //Occurs when a user leaves a server - Logger.Warning("PRESENCE_UPDATE referenced an unknown user.");*/ - } - break; - case "TYPING_START": - { - var data = e.Payload.ToObject(Serializer); - var channel = GetChannel(data.ChannelId) as ITextChannel; - if (channel != null) - { - User user = (channel as Channel).GetUser(data.UserId); - if (user != null) - { - if (Config.LogLevel == LogSeverity.Debug) - Logger.Debug($"TYPING_START: {user.ToString(channel)}"); - OnUserIsTypingUpdated(channel, user); - user.UpdateActivity(); - } - } - } - break; - - //Voice - case "VOICE_STATE_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - var server = GetServer(data.GuildId); - if (server != null) - { - var user = server.GetUser(data.UserId); - if (user != null) - { - if (Config.LogLevel == LogSeverity.Debug) - Logger.Debug($"VOICE_STATE_UPDATE: {user}"); - var before = Config.EnablePreUpdateEvents ? user.Clone() : null; - user.Update(data); - //Logger.Verbose($"Voice Updated: {server.Name}/{user.Name}"); - OnUserUpdated(before, user); - } - /*else //Occurs when a user leaves a server - Logger.Warning("VOICE_STATE_UPDATE referenced an unknown user.");*/ - } - else - Logger.Warning("VOICE_STATE_UPDATE referenced an unknown server."); - } - break; - - //Settings - case "USER_UPDATE": - { - var data = e.Payload.ToObject(Serializer); - if (data.Id == CurrentUser.Id) - { - var before = Config.EnablePreUpdateEvents ? CurrentUser.Clone() : null; - CurrentUser.Update(data); - PrivateUser.Update(data); - foreach (var server in _servers) - server.Value.CurrentUser.Update(data); - Logger.Info($"USER_UPDATE"); - OnProfileUpdated(before, CurrentUser); - } - } - break; - - //Handled in GatewaySocket - case "RESUMED": - break; - - //Ignored - case "USER_SETTINGS_UPDATE": - case "GUILD_INTEGRATIONS_UPDATE": - case "VOICE_SERVER_UPDATE": - case "GUILD_EMOJIS_UPDATE": - case "MESSAGE_ACK": - Logger.Debug($"{e.Type} [Ignored]"); - break; - - //Others - default: - Logger.Warning($"Unknown message type: {e.Type}"); - break; - } - } - catch (Exception ex) - { - Logger.Error($"Error handling {e.Type} event", ex); - } + var channel = new DMChannel(model.Id, this, 0); + channel.Update(model); + return channel; } - #endregion - - #region Services - public T AddService(T instance) - where T : class, IService - => _services.Add(instance); - public T AddService() - where T : class, IService, new() - => _services.Add(new T()); - public T GetService(bool isRequired = true) - where T : class, IService - => _services.Get(isRequired); - #endregion - - #region Async Wrapper - /// Blocking call that will execute the provided async method and wait until the client has been manually stopped. This is mainly intended for use in console applications. - public void ExecuteAndWait(Func asyncAction) + internal virtual TextChannel CreateTextChannel(Guild guild, API.Channel model) { - asyncAction().GetAwaiter().GetResult(); - _disconnectedEvent.WaitOne(); + var channel = new TextChannel(model.Id, guild, 0, false); + channel.Update(model); + return channel; } - /// Blocking call and wait until the client has been manually stopped. This is mainly intended for use in console applications. - public void Wait() + internal virtual VoiceChannel CreateVoiceChannel(Guild guild, API.Channel model) { - _disconnectedEvent.WaitOne(); + var channel = new VoiceChannel(model.Id, guild, false); + channel.Update(model); + return channel; } - #endregion - - #region IDisposable - private bool _isDisposed = false; - - protected virtual void Dispose(bool isDisposing) + internal virtual GuildInvite CreateGuildInvite(GuildChannel channel, API.InviteMetadata model) { - if (!_isDisposed) - { - if (isDisposing) - { - _disconnectedEvent.Dispose(); - _connectedEvent.Dispose(); - } - _isDisposed = true; - } + var invite = new GuildInvite(model.Code, channel); + invite.Update(model); + return invite; } - - public void Dispose() + internal virtual PublicInvite CreatePublicInvite(API.Invite model) { - Dispose(true); + var invite = new PublicInvite(model.Code, this); + invite.Update(model); + return invite; } - #endregion - - //Helpers - private string GetTokenCachePath(string email) + internal virtual Guild CreateGuild(API.Guild model) { - using (var md5 = MD5.Create()) - { - byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(email.ToLowerInvariant())); - StringBuilder filenameBuilder = new StringBuilder(); - for (int i = 0; i < data.Length; i++) - filenameBuilder.Append(data[i].ToString("x2")); - return Path.Combine(Config.CacheDir, filenameBuilder.ToString()); - } + var guild = new Guild(model.Id, this); + guild.Update(model); + return guild; } - private string LoadToken(string path, byte[] key) + internal virtual Message CreateMessage(IMessageChannel channel, User user, API.Message model) { - if (File.Exists(path)) - { - try - { - using (var fileStream = File.Open(path, FileMode.Open)) - using (var aes = Aes.Create()) - { - byte[] iv = new byte[aes.BlockSize / 8]; - fileStream.Read(iv, 0, iv.Length); - aes.IV = iv; - aes.Key = key; - using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read)) - { - byte[] tokenBuffer = new byte[64]; - int length = cryptoStream.Read(tokenBuffer, 0, tokenBuffer.Length); - return Encoding.UTF8.GetString(tokenBuffer, 0, length); - } - } - } - catch (Exception ex) - { - Logger.Warning("Failed to load cached token. Wrong/changed password?", ex); - } - } - return null; + var msg = new Message(model.Id, channel, user); + msg.Update(model); + return msg; } - private void SaveToken(string path, byte[] key, string token) + internal virtual Role CreateRole(Guild guild, API.Role model) { - byte[] tokenBytes = Encoding.UTF8.GetBytes(token); - try - { - string parentDir = Path.GetDirectoryName(path); - if (!Directory.Exists(parentDir)) - Directory.CreateDirectory(parentDir); + var role = new Role(model.Id, guild); + role.Update(model); + return role; + } + internal virtual GuildUser CreateBannedUser(Guild guild, API.User model) + { + var user = new GuildUser(model.Id, guild, null, null); + user.Update(model); + return user; + } + internal virtual DMUser CreateDMUser(DMChannel channel, API.User model) + { + var user = new DMUser(model.Id, channel); + user.Update(model); + return user; + } + internal virtual GuildUser CreateGuildUser(Guild guild, GuildPresence presence, VoiceState voiceState, API.GuildMember model) + { + var user = new GuildUser(model.User.Id, guild, presence, voiceState); + user.Update(model); + return user; + } + internal virtual PublicUser CreatePublicUser(API.User model) + { + var user = new PublicUser(model.Id, this); + user.Update(model); + return user; + } + internal virtual SelfUser CreateSelfUser(API.User model) + { + var user = new SelfUser(model.Id, this); + user.Update(model); + return user; + } + internal virtual VoiceRegion CreateVoiceRegion(API.Rest.GetVoiceRegionsResponse model) + { + var region = new VoiceRegion(model.Id, this); + region.Update(model); + return region; + } - using (var fileStream = File.Open(path, FileMode.Create)) - using (var aes = Aes.Create()) + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) { - aes.GenerateIV(); - aes.Key = key; - using (var cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) - { - fileStream.Write(aes.IV, 0, aes.IV.Length); - cryptoStream.Write(tokenBytes, 0, tokenBytes.Length); - } + MessageQueue.Dispose(); + RestClient.Dispose(); + _connectionLock.Dispose(); } + _isDisposed = true; } - catch (Exception ex) + } + public void Dispose() => Dispose(true); + + private static string GetUserAgent(string appName, string appVersion, string appUrl) + { + var sb = new StringBuilder(); + if (!string.IsNullOrEmpty(appName)) { - Logger.Warning("Failed to cache token", ex); + sb.Append(appName); + if (!string.IsNullOrEmpty(appVersion)) + sb.Append($"/{appVersion}"); + if (!string.IsNullOrEmpty(appUrl)) + sb.Append($" ({appUrl})"); + sb.Append(' '); } + sb.Append($"DiscordBot ({DiscordConfig.LibUrl}, v{DiscordConfig.LibVersion})"); + return sb.ToString(); } + + protected void RaiseEvent(EventHandler eventHandler) + => eventHandler?.Invoke(this, EventArgs.Empty); + protected void RaiseEvent(EventHandler eventHandler, T eventArgs) where T : EventArgs + => eventHandler?.Invoke(this, eventArgs); + protected void RaiseEvent(EventHandler eventHandler, Func eventArgs) where T : EventArgs + => eventHandler?.Invoke(this, eventArgs()); } -} \ No newline at end of file +} diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index ab6f92eba..b23bc3204 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -1,15 +1,27 @@ -using System; -using System.IO; +using Discord.Net.Rest; +using Discord.Net.WebSockets; using System.Reflection; -using System.Text; namespace Discord { - public class DiscordConfigBuilder + public class DiscordConfig { - //Global + public const int MaxMessageSize = 2000; + public const int MaxMessagesPerBatch = 100; + + public const string LibName = "Discord.Net"; + public static string LibVersion { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; + public const string LibUrl = "https://github.com/RogueException/Discord.Net"; + + public const string ClientAPIUrl = "https://discordapp.com/api/"; + public const string CDNUrl = "https://cdn.discordapp.com/"; + public const string InviteUrl = "https://discord.gg/"; - /// Gets or sets name of your application, used both for the token cache directory and user agent. + internal const int RestTimeout = 10000; + internal const int MessageQueueInterval = 100; + internal const int WebSocketQueueInterval = 100; + + /// Gets or sets name of your application, used in the user agent. public string AppName { get; set; } = null; /// Gets or sets url to your application, used in the user agent. public string AppUrl { get; set; } = null; @@ -18,124 +30,40 @@ namespace Discord /// Gets or sets the minimum log level severity that will be sent to the LogMessage event. public LogSeverity LogLevel { get; set; } = LogSeverity.Info; - - //WebSocket - + /// Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize. public int ConnectionTimeout { get; set; } = 30000; - /// Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. - public int ReconnectDelay { get; set; } = 1000; - /// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. - public int FailedReconnectDelay { get; set; } = 15000; + /// Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. + public int ReconnectDelay { get; set; } = 1000; + /// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. + public int FailedReconnectDelay { get; set; } = 15000; //Performance - - /// Gets or sets whether an encrypted login token should be saved to temp dir after successful login. - public bool CacheToken { get; set; } = true; + /// Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. public int MessageCacheSize { get; set; } = 100; /// /// Gets or sets whether the permissions cache should be used. - /// This makes operations such as User.GetPermissions(Channel), User.ServerPermissions, Channel.GetUser, and Channel.Members much faster while increasing memory usage. + /// This makes operations such as User.GetPermissions(Channel), User.GuildPermissions, Channel.GetUser, and Channel.Members much faster while increasing memory usage. /// public bool UsePermissionsCache { get; set; } = true; /// Gets or sets whether the a copy of a model is generated on an update event to allow you to check which properties changed. public bool EnablePreUpdateEvents { get; set; } = true; /// - /// Gets or sets the max number of users a server may have for offline users to be included in the READY packet. Max is 250. + /// Gets or sets the max number of users a guild may have for offline users to be included in the READY packet. Max is 250. /// Decreasing this may reduce CPU usage while increasing login time and network usage. /// public int LargeThreshold { get; set; } = 250; - //Events - - /// Gets or sets a handler for all log messages. - public EventHandler LogHandler { get; set; } - - public DiscordConfig Build() => new DiscordConfig(this); - } - - public class DiscordConfig - { - public const int MaxMessageSize = 2000; - internal const int RestTimeout = 10000; - internal const int MessageQueueInterval = 100; - internal const int WebSocketQueueInterval = 100; - - public const string LibName = "Discord.Net"; - public static string LibVersion => typeof(DiscordConfigBuilder).GetTypeInfo().Assembly.GetName().Version.ToString(3); - public const string LibUrl = "https://github.com/RogueException/Discord.Net"; - - public const string ClientAPIUrl = "https://discordapp.com/api/"; - public const string StatusAPIUrl = "https://srhpyqt94yxb.statuspage.io/api/v2/"; //"https://status.discordapp.com/api/v2/"; - public const string CDNUrl = "https://cdn.discordapp.com/"; - public const string InviteUrl = "https://discord.gg/"; + //Engines - public LogSeverity LogLevel { get; } - - public string AppName { get; } - public string AppUrl { get; } - public string AppVersion { get; } - public string UserAgent { get; } - public string CacheDir { get; } - - public int ConnectionTimeout { get; } - public int ReconnectDelay { get; } - public int FailedReconnectDelay { get; } - - public int LargeThreshold { get; } - public int MessageCacheSize { get; } - public bool UsePermissionsCache { get; } - public bool EnablePreUpdateEvents { get; } - - - internal DiscordConfig(DiscordConfigBuilder builder) - { - LogLevel = builder.LogLevel; - - AppName = builder.AppName; - AppUrl = builder.AppUrl; - AppVersion = builder.AppVersion; - UserAgent = GetUserAgent(builder); - CacheDir = GetCacheDir(builder); - - ConnectionTimeout = builder.ConnectionTimeout; - ReconnectDelay = builder.ReconnectDelay; - FailedReconnectDelay = builder.FailedReconnectDelay; - - MessageCacheSize = builder.MessageCacheSize; - UsePermissionsCache = builder.UsePermissionsCache; - EnablePreUpdateEvents = builder.EnablePreUpdateEvents; - } - - private static string GetUserAgent(DiscordConfigBuilder builder) - { - StringBuilder sb = new StringBuilder(); - if (!string.IsNullOrEmpty(builder.AppName)) - { - sb.Append(builder.AppName); - if (!string.IsNullOrEmpty(builder.AppVersion)) - { - sb.Append('/'); - sb.Append(builder.AppVersion); - } - if (!string.IsNullOrEmpty(builder.AppUrl)) - { - sb.Append(" ("); - sb.Append(builder.AppUrl); - sb.Append(')'); - } - sb.Append(' '); - } - sb.Append($"DiscordBot ({LibUrl}, v{LibVersion})"); - return sb.ToString(); - } - private static string GetCacheDir(DiscordConfigBuilder builder) - { - if (builder.CacheToken) - return Path.Combine(Path.GetTempPath(), builder.AppName ?? "Discord.Net"); - else - return null; - } + /// Gets or sets the REST engine to use. Defaults to DefaultRestClientProvider, which is built around .Net's HttpClient class. + public RestClientProvider RestClientProvider { get; set; } = (url, ct) => new DefaultRestEngine(url, ct); + /// + /// Gets or sets the WebSocket engine to use. Defaults to DefaultWebSocketProvider, which uses .Net's WebSocketClient class. + /// WebSockets are only used if DiscordClient.Connect() is called. + /// + public WebSocketProvider WebSocketProvider { get; set; } = null; } } + diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs new file mode 100644 index 000000000..40beb389e --- /dev/null +++ b/src/Discord.Net/DiscordSocketClient.cs @@ -0,0 +1,176 @@ +using Discord.Logging; +using Discord.Net.WebSockets; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Discord +{ + public class DiscordSocketClient : DiscordClient + { + public event EventHandler Connected, Disconnected; + public event EventHandler VoiceConnected, VoiceDisconnected; + + public event EventHandler ChannelCreated, ChannelDestroyed; + public event EventHandler ChannelUpdated; + public event EventHandler MessageReceived, MessageDeleted; + public event EventHandler MessageUpdated; + public event EventHandler RoleCreated, RoleDeleted; + public event EventHandler RoleUpdated; + public event EventHandler JoinedGuild, LeftGuild; + public event EventHandler GuildAvailable, GuildUnavailable; + public event EventHandler GuildUpdated; + public event EventHandler CurrentUserUpdated; + public event EventHandler UserJoined, UserLeft; + public event EventHandler UserBanned, UserUnbanned; + public event EventHandler UserUpdated; + public event EventHandler UserIsTyping; + + private readonly Logger _discordLogger, _gatewayLogger; + private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay; + private readonly bool _enablePreUpdateEvents, _usePermissionCache; + private readonly int _largeThreshold, _messageCacheSize; + private ConcurrentDictionary _guilds; + private ConcurrentDictionary _channels; + private ConcurrentDictionary _privateChannels; //Key = RecipientId + + public int ConnectionId { get; } + public int TotalConnections { get; } + /// Gets the internal WebSocket for the Gateway event stream. + public GatewaySocket GatewaySocket { get; private set; } + /*/// Gets the current logged-in account. + public CurrentUser CurrentUser { get; private set; }*/ + + public bool IsConnected => GatewaySocket.State == ConnectionState.Connected; + + public DiscordSocketClient(string token, int connectionId = 0, int totalConnections = 1, DiscordConfig config = null) + : base(token, config) + { + if (totalConnections < 1) throw new ArgumentOutOfRangeException(nameof(totalConnections)); + if (connectionId < 0) throw new ArgumentOutOfRangeException(nameof(connectionId)); + if (connectionId >= totalConnections) throw new ArgumentException($"{nameof(connectionId)} must be less than {nameof(totalConnections)}.", nameof(connectionId)); + + ConnectionId = connectionId; + TotalConnections = totalConnections; + + _connectionTimeout = config.ConnectionTimeout; + _reconnectDelay = config.ReconnectDelay; + _failedReconnectDelay = config.FailedReconnectDelay; + + _messageCacheSize = config.MessageCacheSize; + _usePermissionCache = config.UsePermissionsCache; + _enablePreUpdateEvents = config.EnablePreUpdateEvents; + _largeThreshold = config.LargeThreshold; + + _discordLogger = _logManager.CreateLogger("Discord"); + _gatewayLogger = _logManager.CreateLogger("Gateway"); + + _guilds = new ConcurrentDictionary(2, 0); + _channels = new ConcurrentDictionary(2, 0); + _privateChannels = new ConcurrentDictionary(2, 0); + } + + protected override async Task LogoutInternal() + { + await DisconnectInternal().ConfigureAwait(false); + + _guilds.Clear(); + _channels.Clear(); + _privateChannels.Clear(); + + CurrentUser = null; + + await base.LogoutInternal(); + } + + public async Task Connect() + { + await _connectionLock.WaitAsync().ConfigureAwait(false); + try + { + await ConnectInternal().ConfigureAwait(false); + } + finally { _connectionLock.Release(); } + } + protected virtual Task ConnectInternal() + { + throw new NotImplementedException(); + //GatewaySocket = new GatewaySocket(_webSocketProvider(_cancelToken.Token)); + //GatewaySocket.SetHeader("user-agent", _userAgent); + //await GatewaySocket.Connect(_cancelToken.Token).ConfigureAwait(false); + } + + public async Task Disconnect() + { + await _connectionLock.WaitAsync().ConfigureAwait(false); + try + { + await DisconnectInternal().ConfigureAwait(false); + } + finally { _connectionLock.Release(); } + } + protected virtual async Task DisconnectInternal() + { + if (GatewaySocket != null) + { + await GatewaySocket.Disconnect().ConfigureAwait(false); + GatewaySocket = null; + } + } + + public override async Task GetOrCreateDMChannel(ulong userId) + { + DMChannel channel; + if (_privateChannels.TryGetValue(userId, out channel)) + return channel; + + return await base.GetOrCreateDMChannel(userId).ConfigureAwait(false); + } + public override Task> GetDMChannels() + { + return Task.FromResult(_privateChannels.Select(x => x.Value)); + } + public override Task> GetGuilds() + { + return Task.FromResult(_guilds.Select(x => x.Value)); + } + public override Task GetGuild(ulong id) + { + Guild guild; + _guilds.TryGetValue(id, out guild); + return Task.FromResult(guild); + } + + internal override DMChannel CreateDMChannel(API.Channel model) + { + var channel = new DMChannel(model.Id, this, _messageCacheSize); + channel.Update(model); + return channel; + } + internal override TextChannel CreateTextChannel(Guild guild, API.Channel model) + { + var channel = new TextChannel(model.Id, guild, _messageCacheSize, _usePermissionCache); + channel.Update(model); + return channel; + } + internal override VoiceChannel CreateVoiceChannel(Guild guild, API.Channel model) + { + var channel = new VoiceChannel(model.Id, guild, _usePermissionCache); + channel.Update(model); + return channel; + } + + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + GatewaySocket.Dispose(); + } + } + } + } +} diff --git a/src/Discord.Net/DynamicIL.cs b/src/Discord.Net/DynamicIL.cs deleted file mode 100644 index bce89424d..000000000 --- a/src/Discord.Net/DynamicIL.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace Discord -{ - internal static class DynamicIL - { - public static Action CreateCopyMethod() - { - var method = new DynamicMethod("CopyTo", null, new[] { typeof(T), typeof(T) }, typeof(T), true); - var generator = method.GetILGenerator(); - var typeInfo = typeof(T).GetTypeInfo(); - - typeInfo.ForEachField(f => - { - generator.Emit(OpCodes.Ldarg_1); //Stack: TargetRef - generator.Emit(OpCodes.Ldarg_0); //Stack: TargetRef, SourceRef - generator.Emit(OpCodes.Ldfld, f); //Stack: TargetRef, Value - generator.Emit(OpCodes.Stfld, f); //Stack: - }); - - generator.Emit(OpCodes.Ret); - - return method.CreateDelegate(typeof(Action)) as Action; - } - - public static void ForEachField(this TypeInfo typeInfo, Action func) - { - var baseType = typeInfo.BaseType; - if (baseType != null) - baseType.GetTypeInfo().ForEachField(func); - - foreach (var field in typeInfo.DeclaredFields.Where(x => !x.IsStatic)) - func(field); - } - public static void ForEachProperty(this TypeInfo typeInfo, Action func) - { - var baseType = typeInfo.BaseType; - if (baseType != null) - baseType.GetTypeInfo().ForEachProperty(func); - - foreach (var prop in typeInfo.DeclaredProperties.Where(x => - (!x.CanRead || !x.GetMethod.IsStatic) && (!x.CanWrite || !x.SetMethod.IsStatic))) - func(prop); - } - } -} diff --git a/src/Discord.Net/ETF/ETFReader.cs b/src/Discord.Net/ETF/ETFReader.cs deleted file mode 100644 index 9e1e4e8ef..000000000 --- a/src/Discord.Net/ETF/ETFReader.cs +++ /dev/null @@ -1,491 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using System.Text; - -namespace Discord.ETF -{ - public class ETFReader : IDisposable - { - private static readonly ConcurrentDictionary _deserializers = new ConcurrentDictionary(); - private static readonly Dictionary _readMethods = GetPrimitiveReadMethods(); - - private readonly Stream _stream; - private readonly byte[] _buffer; - private readonly bool _leaveOpen; - private readonly Encoding _encoding; - - public ETFReader(Stream stream, bool leaveOpen = false) - { - if (stream == null) throw new ArgumentNullException(nameof(stream)); - - _stream = stream; - _leaveOpen = leaveOpen; - _buffer = new byte[11]; - _encoding = Encoding.UTF8; - } - - public bool ReadBool() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT) - { - _stream.Read(_buffer, 0, 1); - switch (_buffer[0]) //Length - { - case 4: - ReadTrue(); - return true; - case 5: - ReadFalse(); - return false; - } - } - throw new InvalidDataException(); - } - private void ReadTrue() - { - _stream.Read(_buffer, 0, 4); - if (_buffer[0] != 't' || _buffer[1] != 'r' || _buffer[2] != 'u' || _buffer[3] != 'e') - throw new InvalidDataException(); - } - private void ReadFalse() - { - _stream.Read(_buffer, 0, 5); - if (_buffer[0] != 'f' || _buffer[1] != 'a' || _buffer[2] != 'l' || _buffer[3] != 's' || _buffer[4] != 'e') - throw new InvalidDataException(); - } - - public int ReadSByte() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (sbyte)ReadLongInternal(type); - } - public uint ReadByte() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (byte)ReadLongInternal(type); - } - public int ReadShort() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (short)ReadLongInternal(type); - } - public uint ReadUShort() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (ushort)ReadLongInternal(type); - } - public int ReadInt() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (int)ReadLongInternal(type); - } - public uint ReadUInt() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (uint)ReadLongInternal(type); - } - public long ReadLong() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return ReadLongInternal(type); - } - public ulong ReadULong() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (ulong)ReadLongInternal(type); - } - public long ReadLongInternal(ETFType type) - { - switch (type) - { - case ETFType.SMALL_INTEGER_EXT: - _stream.Read(_buffer, 0, 1); - return _buffer[0]; - case ETFType.INTEGER_EXT: - _stream.Read(_buffer, 0, 4); - return (_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | (_buffer[3]); - case ETFType.SMALL_BIG_EXT: - _stream.Read(_buffer, 0, 2); - bool isPositive = _buffer[0] == 0; - byte count = _buffer[1]; - - int shiftValue = (count - 1) * 8; - ulong value = 0; - _stream.Read(_buffer, 0, count); - for (int i = 0; i < count; i++, shiftValue -= 8) - value = value + _buffer[i] << shiftValue; - if (!isPositive) - return -(long)value; - else - return (long)value; - } - throw new InvalidDataException(); - } - - public float ReadSingle() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return (float)ReadDoubleInternal(type); - } - public double ReadDouble() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - return ReadDoubleInternal(type); - } - public double ReadDoubleInternal(ETFType type) - { - throw new NotImplementedException(); - } - - public bool? ReadNullableBool() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT) - { - _stream.Read(_buffer, 0, 1); - switch (_buffer[0]) //Length - { - case 3: - if (ReadNil()) - return null; - break; - case 4: - ReadTrue(); - return true; - case 5: - ReadFalse(); - return false; - } - } - throw new InvalidDataException(); - } - public int? ReadNullableSByte() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (sbyte)ReadLongInternal(type); - } - public uint? ReadNullableByte() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (byte)ReadLongInternal(type); - } - public int? ReadNullableShort() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (short)ReadLongInternal(type); - } - public uint? ReadNullableUShort() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (ushort)ReadLongInternal(type); - } - public int? ReadNullableInt() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (int)ReadLongInternal(type); - } - public uint? ReadNullableUInt() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (uint)ReadLongInternal(type); - } - public long? ReadNullableLong() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return ReadLongInternal(type); - } - public ulong? ReadNullableULong() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (ulong)ReadLongInternal(type); - } - public float? ReadNullableSingle() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return (float)ReadDoubleInternal(type); - } - public double? ReadNullableDouble() - { - _stream.Read(_buffer, 0, 1); - ETFType type = (ETFType)_buffer[0]; - if (type == ETFType.SMALL_ATOM_EXT && ReadNil()) return null; - return ReadDoubleInternal(type); - } - - public string ReadString() - { - throw new NotImplementedException(); - } - public byte[] ReadByteArray() - { - throw new NotImplementedException(); - } - - public T Read() - where T : new() - { - var type = typeof(T); - var typeInfo = type.GetTypeInfo(); - var action = _deserializers.GetOrAdd(type, _ => CreateDeserializer(type, typeInfo)) as Func; - return action(this); - } - /*public void Read() - where T : Nullable - where U : struct, new() - { - }*/ - public T[] ReadArray() - { - throw new NotImplementedException(); - } - public IDictionary ReadDictionary() - { - throw new NotImplementedException(); - } - /*public object Read(object obj) - { - throw new NotImplementedException(); - }*/ - - private bool ReadNil(bool ignoreLength = false) - { - if (!ignoreLength) - { - _stream.Read(_buffer, 0, 1); - byte length = _buffer[0]; - if (length != 3) return false; - } - - _stream.Read(_buffer, 0, 3); - if (_buffer[0] == 'n' && _buffer[1] == 'i' && _buffer[2] == 'l') - return true; - - return false; - } - - #region Emit - private static Func CreateDeserializer(Type type, TypeInfo typeInfo) - where T : new() - { - var method = new DynamicMethod("DeserializeETF", type, new[] { typeof(ETFReader) }, true); - var generator = method.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) - EmitReadValue(generator, type, typeInfo, true); - - generator.Emit(OpCodes.Ret); - return method.CreateDelegate(typeof(Func)) as Func; - } - private static void EmitReadValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) - { - //Convert enum types to their base type - if (typeInfo.IsEnum) - { - type = Enum.GetUnderlyingType(type); - typeInfo = type.GetTypeInfo(); - } - //Primitives/Enums - if (!typeInfo.IsEnum && IsType(type, typeof(sbyte), typeof(byte), typeof(short), - typeof(ushort), typeof(int), typeof(uint), typeof(long), - typeof(ulong), typeof(double), typeof(bool), typeof(string), - typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), - typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), - typeof(bool?), typeof(float?), typeof(double?) - /*typeof(object), typeof(DateTime)*/)) - { - //No conversion needed - generator.EmitCall(OpCodes.Call, GetReadMethod(type), null); - } - //Dictionaries - /*else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces - .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) - { - generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Enumerable - else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces - .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) - { - generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Nullable Structs - else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && - typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) - { - generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Structs/Classes - else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) - { - if (isTop) - { - typeInfo.ForEachField(f => - { - string name; - if (!f.IsPublic || !IsETFProperty(f, out name)) return; - - generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) - generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name - generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); - generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) - generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj - generator.Emit(OpCodes.Ldfld, f); //ETFReader(this), obj.fieldValue - EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); - }); - - typeInfo.ForEachProperty(p => - { - string name; - if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; - - generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) - generator.Emit(OpCodes.Ldstr, name); //ETFReader(this), name - generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); - generator.Emit(OpCodes.Ldarg_0); //ETFReader(this) - generator.Emit(OpCodes.Ldarg_1); //ETFReader(this), obj - generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFReader(this), obj.propValue - EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); - }); - } - else - { - //While we could drill deeper and make a large serializer that also serializes all subclasses, - //it's more efficient to serialize on a per-type basis via another Write call. - generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - }*/ - //Unsupported (decimal, char) - else - throw new InvalidOperationException($"Deserializing {type.Name} is not supported."); - } - - private static bool IsType(Type type, params Type[] types) - { - for (int i = 0; i < types.Length; i++) - { - if (type == types[i]) - return true; - } - return false; - } - private static bool IsETFProperty(FieldInfo f, out string name) - { - var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); - if (attrib != null) - { - name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; - return true; - } - name = null; - return false; - } - private static bool IsETFProperty(PropertyInfo p, out string name) - { - var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); - if (attrib != null) - { - name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; - return true; - } - name = null; - return false; - } - - private static MethodInfo GetReadMethod(string name) - => typeof(ETFReader).GetTypeInfo().GetDeclaredMethods(name).Single(); - private static MethodInfo GetReadMethod(Type type) - { - MethodInfo method; - if (_readMethods.TryGetValue(type, out method)) - return method; - return null; - } - private static Dictionary GetPrimitiveReadMethods() - { - return new Dictionary - { - { typeof(bool), GetReadMethod(nameof(ReadBool)) }, - { typeof(bool?), GetReadMethod(nameof(ReadNullableBool)) }, - { typeof(byte), GetReadMethod(nameof(ReadByte)) }, - { typeof(byte?), GetReadMethod(nameof(ReadNullableByte)) }, - { typeof(sbyte), GetReadMethod(nameof(ReadSByte)) }, - { typeof(sbyte?), GetReadMethod(nameof(ReadNullableSByte)) }, - { typeof(short), GetReadMethod(nameof(ReadShort)) }, - { typeof(short?), GetReadMethod(nameof(ReadNullableShort)) }, - { typeof(ushort), GetReadMethod(nameof(ReadUShort)) }, - { typeof(ushort?), GetReadMethod(nameof(ReadNullableUShort)) }, - { typeof(int), GetReadMethod(nameof(ReadInt)) }, - { typeof(int?), GetReadMethod(nameof(ReadNullableInt)) }, - { typeof(uint), GetReadMethod(nameof(ReadUInt)) }, - { typeof(uint?), GetReadMethod(nameof(ReadNullableUInt)) }, - { typeof(long), GetReadMethod(nameof(ReadLong)) }, - { typeof(long?), GetReadMethod(nameof(ReadNullableLong)) }, - { typeof(ulong), GetReadMethod(nameof(ReadULong)) }, - { typeof(ulong?), GetReadMethod(nameof(ReadNullableULong)) }, - { typeof(float), GetReadMethod(nameof(ReadSingle)) }, - { typeof(float?), GetReadMethod(nameof(ReadNullableSingle)) }, - { typeof(double), GetReadMethod(nameof(ReadDouble)) }, - { typeof(double?), GetReadMethod(nameof(ReadNullableDouble)) }, - }; - } - #endregion - - #region IDisposable - private bool _isDisposed = false; - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - if (_leaveOpen) - _stream.Flush(); - else - _stream.Dispose(); - } - _isDisposed = true; - } - } - - public void Dispose() => Dispose(true); - #endregion - } -} \ No newline at end of file diff --git a/src/Discord.Net/ETF/ETFType.cs b/src/Discord.Net/ETF/ETFType.cs deleted file mode 100644 index 53499d5fa..000000000 --- a/src/Discord.Net/ETF/ETFType.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Discord.ETF -{ - public enum ETFType : byte - { - NEW_FLOAT_EXT = 70, - BIT_BINARY_EXT = 77, - ATOM_CACHE_REF = 82, - SMALL_INTEGER_EXT = 97, - INTEGER_EXT = 98, - FLOAT_EXT = 99, - ATOM_EXT = 100, - REFERENCE_EXT = 101, - PORT_EXT = 102, - PID_EXT = 103, - SMALL_TUPLE_EXT = 104, - LARGE_TUPLE_EXT = 105, - NIL_EXT = 106, - STRING_EXT = 107, - LIST_EXT = 108, - BINARY_EXT = 109, - SMALL_BIG_EXT = 110, - LARGE_BIG_EXT = 111, - NEW_FUN_EXT = 112, - EXPORT_EXT = 113, - NEW_REFERENCE_EXT = 114, - SMALL_ATOM_EXT = 115, - MAP_EXT = 116, - FUN_EXT = 117, - ATOM_UTF8_EXT = 118, - SMALL_ATOM_UTF8_EXT = 119 - } -} diff --git a/src/Discord.Net/ETF/ETFWriter.cs b/src/Discord.Net/ETF/ETFWriter.cs deleted file mode 100644 index 37d1553db..000000000 --- a/src/Discord.Net/ETF/ETFWriter.cs +++ /dev/null @@ -1,482 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using System.Text; - -namespace Discord.ETF -{ - public unsafe class ETFWriter : IDisposable - { - private static readonly ConcurrentDictionary _serializers = new ConcurrentDictionary(); - private static readonly ConcurrentDictionary _indirectSerializers = new ConcurrentDictionary(); - - private static readonly byte[] _nilBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 3, (byte)'n', (byte)'i', (byte)'l' }; - private static readonly byte[] _falseBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 5, (byte)'f', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; - private static readonly byte[] _trueBytes = new byte[] { (byte)ETFType.SMALL_ATOM_EXT, 4, (byte)'t', (byte)'r', (byte)'u', (byte)'e' }; - - private static readonly MethodInfo _writeTMethod = GetGenericWriteMethod(null); - private static readonly MethodInfo _writeNullableTMethod = GetGenericWriteMethod(typeof(Nullable<>)); - private static readonly MethodInfo _writeDictionaryTMethod = GetGenericWriteMethod(typeof(IDictionary<,>)); - private static readonly MethodInfo _writeEnumerableTMethod = GetGenericWriteMethod(typeof(IEnumerable<>)); - private static readonly DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - private readonly Stream _stream; - private readonly byte[] _buffer; - private readonly bool _leaveOpen; - private readonly Encoding _encoding; - - public virtual Stream BaseStream - { - get - { - Flush(); - return _stream; - } - } - - public ETFWriter(Stream stream, bool leaveOpen = false) - { - if (stream == null) throw new ArgumentNullException(nameof(stream)); - - _stream = stream; - _leaveOpen = leaveOpen; - _buffer = new byte[11]; - _encoding = Encoding.UTF8; - } - - public void Write(bool value) - { - if (value) - _stream.Write(_trueBytes, 0, _trueBytes.Length); - else - _stream.Write(_falseBytes, 0, _falseBytes.Length); - } - public void Write(sbyte value) => Write((long)value); - public void Write(byte value) => Write((ulong)value); - public void Write(short value) => Write((long)value); - public void Write(ushort value) => Write((ulong)value); - public void Write(int value) => Write((long)value); - public void Write(uint value) => Write((ulong)value); - public void Write(long value) - { - if (value >= byte.MinValue && value <= byte.MaxValue) - { - _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; - _buffer[1] = (byte)value; - _stream.Write(_buffer, 0, 2); - } - else if (value >= int.MinValue && value <= int.MaxValue) - { - //TODO: Does this encode negatives correctly? - _buffer[0] = (byte)ETFType.INTEGER_EXT; - _buffer[1] = (byte)(value >> 24); - _buffer[2] = (byte)(value >> 16); - _buffer[3] = (byte)(value >> 8); - _buffer[4] = (byte)value; - _stream.Write(_buffer, 0, 5); - } - else - { - _buffer[0] = (byte)ETFType.SMALL_BIG_EXT; - if (value < 0) - { - _buffer[2] = 1; //Is negative - value = -value; - } - - byte bytes = 0; - while (value > 0) - _buffer[3 + bytes++] = (byte)(value >>= 8); - _buffer[1] = bytes; //Encoded bytes - - _stream.Write(_buffer, 0, 3 + bytes); - } - } - public void Write(ulong value) - { - if (value <= byte.MaxValue) - { - _buffer[0] = (byte)ETFType.SMALL_INTEGER_EXT; - _buffer[1] = (byte)value; - _stream.Write(_buffer, 0, 2); - } - else if (value <= int.MaxValue) - { - _buffer[0] = (byte)ETFType.INTEGER_EXT; - _buffer[1] = (byte)(value >> 24); - _buffer[2] = (byte)(value >> 16); - _buffer[3] = (byte)(value >> 8); - _buffer[4] = (byte)value; - _stream.Write(_buffer, 0, 5); - } - else - { - _buffer[0] = (byte)ETFType.SMALL_BIG_EXT; - _buffer[2] = 0; //Always positive - - byte bytes = 0; - while (value > 0) - _buffer[3 + bytes++] = (byte)(value >>= 8); - _buffer[1] = bytes; //Encoded bytes - - _stream.Write(_buffer, 0, 3 + bytes); - } - } - - public void Write(float value) => Write((double)value); - public void Write(double value) - { - ulong value2 = *(ulong*)&value; - _buffer[0] = (byte)ETFType.NEW_FLOAT_EXT; - _buffer[1] = (byte)(value2 >> 56); - _buffer[2] = (byte)(value2 >> 48); - _buffer[3] = (byte)(value2 >> 40); - _buffer[4] = (byte)(value2 >> 32); - _buffer[5] = (byte)(value2 >> 24); - _buffer[6] = (byte)(value2 >> 16); - _buffer[7] = (byte)(value2 >> 8); - _buffer[8] = (byte)value2; - _stream.Write(_buffer, 0, 9); - } - - public void Write(DateTime value) => Write((ulong)((value.Ticks - _epochTime.Ticks) / TimeSpan.TicksPerSecond)); - - public void Write(bool? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - public void Write(sbyte? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } - public void Write(byte? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } - public void Write(short? value) { if (value.HasValue) Write((long)value.Value); else WriteNil(); } - public void Write(ushort? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } - public void Write(int? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - public void Write(uint? value) { if (value.HasValue) Write((ulong)value.Value); else WriteNil(); } - public void Write(long? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - public void Write(ulong? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - public void Write(double? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - public void Write(float? value) { if (value.HasValue) Write((double)value.Value); else WriteNil(); } - public void Write(DateTime? value) { if (value.HasValue) Write(value.Value); else WriteNil(); } - - public void Write(string value) - { - if (value != null) - { - var bytes = _encoding.GetBytes(value); - int count = bytes.Length; - _buffer[0] = (byte)ETFType.BINARY_EXT; - _buffer[1] = (byte)(count >> 24); - _buffer[2] = (byte)(count >> 16); - _buffer[3] = (byte)(count >> 8); - _buffer[4] = (byte)count; - _stream.Write(_buffer, 0, 5); - _stream.Write(bytes, 0, bytes.Length); - } - else - WriteNil(); - } - public void Write(byte[] value) - { - if (value != null) - { - int count = value.Length; - _buffer[0] = (byte)ETFType.BINARY_EXT; - _buffer[1] = (byte)(count >> 24); - _buffer[2] = (byte)(count >> 16); - _buffer[3] = (byte)(count >> 8); - _buffer[4] = (byte)count; - _stream.Write(_buffer, 0, 5); - _stream.Write(value, 0, value.Length); - } - else - WriteNil(); - } - - public void Write(T obj) - { - var type = typeof(T); - var typeInfo = type.GetTypeInfo(); - var action = _serializers.GetOrAdd(type, _ => CreateSerializer(type, typeInfo, false)) as Action; - action(this, obj); - } - public void Write(T? obj) - where T : struct - { - if (obj != null) - Write(obj.Value); - else - WriteNil(); - } - public void Write(IEnumerable obj) - { - if (obj != null) - { - var array = obj.ToArray(); - int length = array.Length; - _buffer[0] = (byte)ETFType.LIST_EXT; - _buffer[1] = (byte)(length >> 24); - _buffer[2] = (byte)(length >> 16); - _buffer[3] = (byte)(length >> 8); - _buffer[4] = (byte)length; - _stream.Write(_buffer, 0, 5); - - for (int i = 0; i < array.Length; i++) - Write(array[i]); - - _buffer[0] = (byte)ETFType.NIL_EXT; - _stream.Write(_buffer, 0, 1); - } - else - WriteNil(); - } - public void Write(IDictionary obj) - { - if (obj != null) - { - int length = obj.Count; - _buffer[0] = (byte)ETFType.MAP_EXT; - _buffer[1] = (byte)(length >> 24); - _buffer[2] = (byte)(length >> 16); - _buffer[3] = (byte)(length >> 8); - _buffer[4] = (byte)length; - _stream.Write(_buffer, 0, 5); - - foreach (var pair in obj) - { - Write(pair.Key); - Write(pair.Value); - } - } - else - WriteNil(); - } - public void Write(object obj) - { - if (obj != null) - { - var type = obj.GetType(); - var typeInfo = type.GetTypeInfo(); - var action = _indirectSerializers.GetOrAdd(type, _ => CreateSerializer(type, typeInfo, true)) as Action; - action(this, obj); - } - else - WriteNil(); - } - - private void WriteNil() => _stream.Write(_nilBytes, 0, _nilBytes.Length); - - public virtual void Flush() => _stream.Flush(); - public virtual long Seek(int offset, SeekOrigin origin) => _stream.Seek(offset, origin); - - #region Emit - private static Action CreateSerializer(Type type, TypeInfo typeInfo, bool isDirect) - { - var method = new DynamicMethod(isDirect ? "SerializeETF" : "SerializeIndirectETF", - null, new[] { typeof(ETFWriter), isDirect ? type : typeof(object) }, true); - var generator = method.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) - generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), value - if (!isDirect) - { - if (typeInfo.IsValueType) //Unbox value types - generator.Emit(OpCodes.Unbox_Any, type); //ETFWriter(this), real_value - else //Cast reference types - generator.Emit(OpCodes.Castclass, type); //ETFWriter(this), real_value - generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(type), null); //Call generic version - } - else - EmitWriteValue(generator, type, typeInfo, true); - - generator.Emit(OpCodes.Ret); - return method.CreateDelegate(typeof(Action)) as Action; - } - private static void EmitWriteValue(ILGenerator generator, Type type, TypeInfo typeInfo, bool isTop) - { - //Convert enum types to their base type - if (typeInfo.IsEnum) - { - type = Enum.GetUnderlyingType(type); - typeInfo = type.GetTypeInfo(); - } - - //Primitives/Enums - Type targetType = null; - if (!typeInfo.IsEnum && IsType(type, typeof(long), typeof(ulong), typeof(double), typeof(bool), typeof(string), - typeof(sbyte?), typeof(byte?), typeof(short?), typeof(ushort?), - typeof(int?), typeof(uint?), typeof(long?), typeof(ulong?), - typeof(bool?), typeof(float?), typeof(double?), - typeof(object), typeof(DateTime))) - { - //No conversion needed - targetType = type; - } - else if (IsType(type, typeof(sbyte), typeof(short), typeof(int))) - { - //Convert to long - generator.Emit(OpCodes.Conv_I8); - targetType = typeof(long); - } - else if (IsType(type, typeof(byte), typeof(ushort), typeof(uint))) - { - //Convert to ulong - generator.Emit(OpCodes.Conv_U8); - targetType = typeof(ulong); - } - else if (IsType(type, typeof(float))) - { - //Convert to double - generator.Emit(OpCodes.Conv_R8); - targetType = typeof(double); - } - if (targetType != null) - generator.EmitCall(OpCodes.Call, GetWriteMethod(targetType), null); - - //Dictionaries - else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces - .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>))) - { - generator.EmitCall(OpCodes.Call, _writeDictionaryTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Enumerable - else if (!typeInfo.IsValueType && typeInfo.ImplementedInterfaces - .Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) - { - generator.EmitCall(OpCodes.Call, _writeEnumerableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Nullable Structs - else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) && - typeInfo.GenericTypeParameters[0].GetTypeInfo().IsValueType) - { - generator.EmitCall(OpCodes.Call, _writeNullableTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - //Structs/Classes - else if (typeInfo.IsClass || (typeInfo.IsValueType && !typeInfo.IsPrimitive)) - { - if (isTop) - { - typeInfo.ForEachField(f => - { - string name; - if (!f.IsPublic || !IsETFProperty(f, out name)) return; - - generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) - generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name - generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); - generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) - generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj - generator.Emit(OpCodes.Ldfld, f); //ETFWriter(this), obj.fieldValue - EmitWriteValue(generator, f.FieldType, f.FieldType.GetTypeInfo(), false); - }); - - typeInfo.ForEachProperty(p => - { - string name; - if (!p.CanRead || !p.GetMethod.IsPublic || !IsETFProperty(p, out name)) return; - - generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) - generator.Emit(OpCodes.Ldstr, name); //ETFWriter(this), name - generator.EmitCall(OpCodes.Call, GetWriteMethod(typeof(string)), null); - generator.Emit(OpCodes.Ldarg_0); //ETFWriter(this) - generator.Emit(OpCodes.Ldarg_1); //ETFWriter(this), obj - generator.EmitCall(OpCodes.Callvirt, p.GetMethod, null); //ETFWriter(this), obj.propValue - EmitWriteValue(generator, p.PropertyType, p.PropertyType.GetTypeInfo(), false); - }); - } - else - { - //While we could drill deeper and make a large serializer that also serializes all subclasses, - //it's more efficient to serialize on a per-type basis via another Write call. - generator.EmitCall(OpCodes.Call, _writeTMethod.MakeGenericMethod(typeInfo.GenericTypeParameters), null); - } - } - //Unsupported (decimal, char) - else - throw new InvalidOperationException($"Serializing {type.Name} is not supported."); - } - - private static bool IsType(Type type, params Type[] types) - { - for (int i = 0; i < types.Length; i++) - { - if (type == types[i]) - return true; - } - return false; - } - private static bool IsETFProperty(FieldInfo f, out string name) - { - var attrib = f.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); - if (attrib != null) - { - name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? f.Name; - return true; - } - name = null; - return false; - } - private static bool IsETFProperty(PropertyInfo p, out string name) - { - var attrib = p.CustomAttributes.Where(x => x.AttributeType == typeof(JsonPropertyAttribute)).FirstOrDefault(); - if (attrib != null) - { - name = attrib.ConstructorArguments.FirstOrDefault().Value as string ?? p.Name; - return true; - } - name = null; - return false; - } - - private static MethodInfo GetWriteMethod(Type paramType) - { - return typeof(ETFWriter).GetTypeInfo().GetDeclaredMethods(nameof(Write)) - .Where(x => x.GetParameters()[0].ParameterType == paramType) - .Single(); - } - private static MethodInfo GetGenericWriteMethod(Type genericType) - { - if (genericType == null) - { - return typeof(ETFWriter).GetTypeInfo() - .GetDeclaredMethods(nameof(Write)) - .Where(x => x.IsGenericMethodDefinition && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0]) - .Single(); - } - else - { - return typeof(ETFWriter).GetTypeInfo() - .GetDeclaredMethods(nameof(Write)) - .Where(x => - { - if (!x.IsGenericMethodDefinition) return false; - var p = x.GetParameters()[0].ParameterType.GetTypeInfo(); - return p.IsGenericType && p.GetGenericTypeDefinition() == genericType; - }) - .Single(); - } - } - #endregion - - #region IDisposable - private bool _isDisposed = false; - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - if (_leaveOpen) - _stream.Flush(); - else - _stream.Dispose(); - } - _isDisposed = true; - } - } - - public void Dispose() => Dispose(true); - #endregion - } -} diff --git a/src/Discord.Net/Entities/Attachment.cs b/src/Discord.Net/Entities/Attachment.cs new file mode 100644 index 000000000..5f2c1ed47 --- /dev/null +++ b/src/Discord.Net/Entities/Attachment.cs @@ -0,0 +1,18 @@ +using Model = Discord.API.Attachment; + +namespace Discord +{ + public struct Attachment + { + public ulong Id { get; } + public int Size { get; } + public string Filename { get; } + + public Attachment(Model model) + { + Id = model.Id; + Size = model.Size; + Filename = model.Filename; + } + } +} diff --git a/src/Discord.Net/Entities/Channel.cs b/src/Discord.Net/Entities/Channel.cs deleted file mode 100644 index 5894ade45..000000000 --- a/src/Discord.Net/Entities/Channel.cs +++ /dev/null @@ -1,55 +0,0 @@ -using APIChannel = Discord.API.Client.Channel; -using System.Collections.Generic; - -namespace Discord -{ - public abstract class Channel : IChannel - { - /// An entry in a public channel's permissions that gives or takes permissions from a specific role or user. - public class PermissionRule - { - /// The type of object TargetId is referring to. - public PermissionTarget TargetType { get; } - /// The Id of an object, whos type is specified by TargetType, that is the target of permissions being added or taken away. - public ulong TargetId { get; } - /// A collection of permissions that are added or taken away from the target. - public ChannelTriStatePermissions Permissions { get; } - - internal PermissionRule(PermissionTarget targetType, ulong targetId, uint allow, uint deny) - { - TargetType = targetType; - TargetId = targetId; - Permissions = new ChannelTriStatePermissions(allow, deny); - } - } - - /// Gets the unique identifier for this channel. - public ulong Id { get; } - - public abstract DiscordClient Client { get; } - /// Gets the type of this channel. - public abstract ChannelType Type { get; } - public bool IsText => (Type & ChannelType.Text) != 0; - public bool IsVoice => (Type & ChannelType.Voice) != 0; - public bool IsPrivate => (Type & ChannelType.Private) != 0; - public bool IsPublic => (Type & ChannelType.Public) != 0; - - public abstract User CurrentUser { get; } - /// Gets a collection of all users in this channel. - public abstract IEnumerable Users { get; } - - internal abstract MessageManager MessageManager { get; } - internal abstract PermissionManager PermissionManager { get; } - - protected Channel(ulong id) - { - Id = id; - } - - internal abstract void Update(APIChannel model); - - internal abstract User GetUser(ulong id); - - internal abstract Channel Clone(); - } -} diff --git a/src/Discord.Net/Entities/Channels/DMChannel.cs b/src/Discord.Net/Entities/Channels/DMChannel.cs new file mode 100644 index 000000000..f8ce92dfa --- /dev/null +++ b/src/Discord.Net/Entities/Channels/DMChannel.cs @@ -0,0 +1,99 @@ +using Discord.API.Rest; +using Discord.Net; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Net; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord +{ + public class DMChannel : IEntity, IMessageChannel + { + /// + public ulong Id { get; } + /// + public DiscordClient Discord { get; } + + /// + public DMUser Recipient { get; private set; } + + /// + public string Name => $"@{Recipient.Username}#{Recipient.Discriminator}"; + /// + public IEnumerable Users => ImmutableArray.Create(Discord.CurrentUser, Recipient); + /// + ChannelType IChannel.Type => ChannelType.DM; + /// + IEnumerable IChannel.Users => Users; + + private readonly MessageManager _messages; + + internal DMChannel(ulong id, DiscordClient client, int messageCacheSize) + { + Id = id; + Discord = client; + _messages = new MessageManager(this, messageCacheSize); + } + internal void Update(Model model) + { + if (Recipient == null) + Recipient = Discord.CreateDMUser(this, model.Recipient); + else + Recipient.Update(model.Recipient); + } + + /// + public User GetUser(ulong id) + { + if (id == Recipient.Id) + return Recipient; + else if (id == Discord.CurrentUser.Id) + return Discord.CurrentUser; + else + return null; + } + + /// + public Task GetMessage(ulong id) + => _messages.Get(id); + /// + public Task> GetMessages(int limit = 100) + => _messages.GetMany(limit); + /// + public Task> GetMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) + => _messages.GetMany(limit, relativeMessageId, relativeDir); + + /// + public Task SendMessage(string text, bool isTTS = false) + => _messages.Send(text, isTTS); + /// + public Task SendFile(string filePath, string text = null, bool isTTS = false) + => _messages.SendFile(filePath, text, isTTS); + /// + public Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) + => _messages.SendFile(stream, filename, text, isTTS); + + /// + public Task TriggerTyping() + => _messages.TriggerTyping(); + + /// + public async Task Delete() + { + try { await Discord.RestClient.Send(new DeleteChannelRequest(Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + /// + public async Task Update() + { + var response = await Discord.RestClient.Send(new GetChannelRequest(Id)).ConfigureAwait(false); + if (response != null) + Update(response); + } + + /// + public override string ToString() => Name; + } +} diff --git a/src/Discord.Net/Entities/Channels/GuildChannel.cs b/src/Discord.Net/Entities/Channels/GuildChannel.cs new file mode 100644 index 000000000..862c91671 --- /dev/null +++ b/src/Discord.Net/Entities/Channels/GuildChannel.cs @@ -0,0 +1,130 @@ +using Discord.API.Rest; +using Discord.Net; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord +{ + public abstract class GuildChannel : IChannel, IEntity + { + private readonly PermissionManager _permissions; + + /// + public ulong Id { get; } + /// Gets the guild this channel is a member of. + public Guild Guild { get; } + /// + public abstract ChannelType Type { get; } + + /// + public string Name { get; private set; } + /// Gets the position of this public channel relative to others of the same type. + public int Position { get; private set; } + + /// + public DiscordClient Discord => Guild.Discord; + /// Gets a collection of all users in this channel. + public IEnumerable Users => _permissions.GetUsers(); + /// + IEnumerable IChannel.Users => _permissions.GetUsers(); + /// Gets a collection of permission overwrites for this channel. + public IEnumerable PermissionOverwrites => _permissions.Overwrites; + + internal GuildChannel(ulong id, Guild guild, bool usePermissionsCache) + { + Id = id; + Guild = guild; + + _permissions = new PermissionManager(this, usePermissionsCache); + } + + internal virtual void Update(Model model) + { + Name = model.Name; + Position = model.Position; + + _permissions.Update(model); + } + + /// Gets a user in this channel with the given id. + public GuildUser GetUser(ulong id) + => _permissions.GetUser(id); + /// + User IChannel.GetUser(ulong id) => GetUser(id); + + /// Gets the permission overwrite for a specific user, or null if one does not exist. + public OverwritePermissions? GetPermissionOverwrite(GuildUser user) + => _permissions.GetOverwrite(user); + /// Gets the permission overwrite for a specific role, or null if one does not exist. + public OverwritePermissions? GetPermissionOverwrite(Role role) + => _permissions.GetOverwrite(role); + /// Downloads a collection of all invites to this channel. + public async Task> GetInvites() + { + var response = await Discord.RestClient.Send(new GetChannelInvitesRequest(Id)).ConfigureAwait(false); + return response.Select(x => + { + var invite = Discord.CreateGuildInvite(this, x); + invite.Update(x); + return invite; + }); + } + + /// Adds or updates the permission overwrite for the given user. + public Task UpdatePermissionOverwrite(GuildUser user, OverwritePermissions permissions) + => _permissions.AddOrUpdateOverwrite(user, permissions); + /// Adds or updates the permission overwrite for the given role. + public Task UpdatePermissionOverwrite(Role role, OverwritePermissions permissions) + => _permissions.AddOrUpdateOverwrite(role, permissions); + /// Removes the permission overwrite for the given user, if one exists. + public Task RemovePermissionOverwrite(GuildUser user) + => _permissions.RemoveOverwrite(user); + /// Removes the permission overwrite for the given role, if one exists. + public Task RemovePermissionOverwrite(Role role) + => _permissions.RemoveOverwrite(role); + + internal ChannelPermissions GetPermissions(GuildUser user) + => _permissions.GetPermissions(user); + internal void UpdatePermissions() + => _permissions.UpdatePermissions(); + internal void UpdatePermissions(GuildUser user) + => _permissions.UpdatePermissions(user); + + /// Creates a new invite to this channel. + /// Time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, a user accepting this invite will be kicked from the guild after closing their client. + /// If true, creates a human-readable link. Not supported if maxAge is set to null. + public async Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool humanReadable = false) + { + var response = await Discord.RestClient.Send(new CreateChannelInviteRequest(Id) + { + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + IsTemporary = tempMembership, + WithXkcdPass = humanReadable + }).ConfigureAwait(false); + return Discord.CreatePublicInvite(response); + } + + /// + public async Task Delete() + { + try { await Discord.RestClient.Send(new DeleteChannelRequest(Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + /// + public async Task Update() + { + var response = await Discord.RestClient.Send(new GetChannelRequest(Id)).ConfigureAwait(false); + if (response != null) + Update(response); + } + + /// + public override string ToString() => $"{Guild}/{Name ?? Id.ToString()}"; + } +} diff --git a/ref/Entities/Channels/IChannel.cs b/src/Discord.Net/Entities/Channels/IChannel.cs similarity index 80% rename from ref/Entities/Channels/IChannel.cs rename to src/Discord.Net/Entities/Channels/IChannel.cs index fb82fb30d..046718f24 100644 --- a/ref/Entities/Channels/IChannel.cs +++ b/src/Discord.Net/Entities/Channels/IChannel.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading.Tasks; namespace Discord { @@ -9,10 +8,10 @@ namespace Discord ChannelType Type { get; } /// Gets the name of this channel. string Name { get; } + /// Gets a collection of all users in this channel. + IEnumerable Users { get; } /// Gets a user in this channel with the given id. - Task GetUser(ulong id); - /// Gets a collection of all users in this channel. - Task> GetUsers(); + User GetUser(ulong id); } } diff --git a/ref/Entities/Channels/ITextChannel.cs b/src/Discord.Net/Entities/Channels/IMessageChannel.cs similarity index 95% rename from ref/Entities/Channels/ITextChannel.cs rename to src/Discord.Net/Entities/Channels/IMessageChannel.cs index f3701abbf..4bb8b5690 100644 --- a/ref/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net/Entities/Channels/IMessageChannel.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Discord { - public interface ITextChannel : IChannel + public interface IMessageChannel : IChannel { /// Gets the message in this text channel with the given id, or null if none was found. Task GetMessage(ulong id); @@ -25,6 +25,6 @@ namespace Discord Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false); /// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. - Task SendIsTyping(); + Task TriggerTyping(); } } diff --git a/src/Discord.Net/Entities/Channels/TextChannel.cs b/src/Discord.Net/Entities/Channels/TextChannel.cs new file mode 100644 index 000000000..cebb1c573 --- /dev/null +++ b/src/Discord.Net/Entities/Channels/TextChannel.cs @@ -0,0 +1,67 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord +{ + public class TextChannel : GuildChannel, IMessageChannel, IMentionable + { + private readonly MessageManager _messages; + + /// + public string Topic { get; private set; } + + /// + public override ChannelType Type => ChannelType.Text; + /// + public string Mention => MentionHelper.Mention(this); + + internal TextChannel(ulong id, Guild guild, int messageCacheSize, bool usePermissionsCache) + : base(id, guild, usePermissionsCache) + { + _messages = new MessageManager(this, messageCacheSize); + } + + internal override void Update(Model model) + { + Topic = model.Topic; + base.Update(model); + } + + /// + public Task GetMessage(ulong id) + => _messages.Get(id); + /// + public Task> GetMessages(int limit = 100) + => _messages.GetMany(limit); + /// + public Task> GetMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) + => _messages.GetMany(limit, relativeMessageId, relativeDir); + + /// + public Task SendMessage(string text, bool isTTS = false) + => _messages.Send(text, isTTS); + /// + public Task SendFile(string filePath, string text = null, bool isTTS = false) + => _messages.SendFile(filePath, text, isTTS); + /// + public Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) + => _messages.SendFile(stream, filename, text, isTTS); + + /// + public Task TriggerTyping() + => _messages.TriggerTyping(); + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var req = new ModifyTextChannelRequest(Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); + } + } +} diff --git a/src/Discord.Net/Entities/Channels/VoiceChannel.cs b/src/Discord.Net/Entities/Channels/VoiceChannel.cs new file mode 100644 index 000000000..80fbae797 --- /dev/null +++ b/src/Discord.Net/Entities/Channels/VoiceChannel.cs @@ -0,0 +1,39 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord +{ + public class VoiceChannel : GuildChannel + { + /// + public int Bitrate { get; private set; } + + /// + public override ChannelType Type => ChannelType.Voice; + + internal VoiceChannel(ulong id, Guild guild, bool usePermissionsCache) + : base(id, guild, usePermissionsCache) + { + } + + internal override void Update(Model model) + { + Bitrate = model.Bitrate; + base.Update(model); + } + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var req = new ModifyVoiceChannelRequest(Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); + } + + /// + public override string ToString() => $"{Guild}/{Name ?? Id.ToString()}"; + } +} diff --git a/src/Discord.Net/Entities/Color.cs b/src/Discord.Net/Entities/Color.cs index 325aa2f39..3aecc39ac 100644 --- a/src/Discord.Net/Entities/Color.cs +++ b/src/Discord.Net/Entities/Color.cs @@ -1,24 +1,37 @@ namespace Discord { - public class Color + public class Color { + /// Gets the default user color value. public static readonly Color Default = new Color(0); - - public uint RawValue { get; } - - public Color(uint rawValue) { RawValue = rawValue; } - public Color(byte r, byte g, byte b) : this(((uint)r << 16) | ((uint)g << 8) | b) { } - public Color(float r, float g, float b) : this((byte)(r * 255.0f), (byte)(g * 255.0f), (byte)(b * 255.0f)) { } - /// Gets or sets the red component for this color. - public byte R => (byte)(RawValue >> 16); - /// Gets or sets the green component for this color. + /// Gets the encoded value for this color. + public uint RawValue { get; } + + /// Gets the red component for this color. + public byte R => (byte)(RawValue >> 16); + /// Gets the green component for this color. public byte G => (byte)(RawValue >> 8); - /// Gets or sets the blue component for this color. + /// Gets the blue component for this color. public byte B => (byte)(RawValue); - private byte GetByte(int pos) => (byte)(RawValue >> (8 * (pos - 1))); - - public override string ToString() => '#' + RawValue.ToString("X"); + public Color(uint rawValue) + { + RawValue = rawValue; + } + public Color(byte r, byte g, byte b) + { + RawValue = + ((uint)r << 16) | + ((uint)g << 8) | + b; + } + public Color(float r, float g, float b) + { + RawValue = + ((uint)(r * 255.0f) << 16) | + ((uint)(g * 255.0f) << 8) | + (uint)(b * 255.0f); + } } } diff --git a/src/Discord.Net/Entities/Embed.cs b/src/Discord.Net/Entities/Embed.cs new file mode 100644 index 000000000..271e47f66 --- /dev/null +++ b/src/Discord.Net/Entities/Embed.cs @@ -0,0 +1,25 @@ +using Model = Discord.API.Embed; + +namespace Discord +{ + public struct Embed + { + public string Url { get; } + public string Type { get; } + public string Title { get; } + public string Description { get; } + public EmbedProvider Provider { get; } + public EmbedThumbnail Thumbnail { get; } + + internal Embed(Model model) + { + Url = model.Url; + Type = model.Type; + Title = model.Title; + Description = model.Description; + + Provider = new EmbedProvider(model.Provider); + Thumbnail = new EmbedThumbnail(model.Thumbnail); + } + } +} diff --git a/src/Discord.Net/Entities/EmbedProvider.cs b/src/Discord.Net/Entities/EmbedProvider.cs new file mode 100644 index 000000000..2fce8dfe7 --- /dev/null +++ b/src/Discord.Net/Entities/EmbedProvider.cs @@ -0,0 +1,16 @@ +using Model = Discord.API.EmbedProvider; + +namespace Discord +{ + public struct EmbedProvider + { + public string Name { get; } + public string Url { get; } + + internal EmbedProvider(Model model) + { + Name = model.Name; + Url = model.Url; + } + } +} diff --git a/src/Discord.Net/Entities/EmbedThumbnail.cs b/src/Discord.Net/Entities/EmbedThumbnail.cs new file mode 100644 index 000000000..a61323ed6 --- /dev/null +++ b/src/Discord.Net/Entities/EmbedThumbnail.cs @@ -0,0 +1,20 @@ +using Model = Discord.API.EmbedThumbnail; + +namespace Discord +{ + public struct EmbedThumbnail + { + public string Url { get; } + public string ProxyUrl { get; } + public int? Height { get; } + public int? Width { get; } + + internal EmbedThumbnail(Model model) + { + Url = model.Url; + ProxyUrl = model.ProxyUrl; + Height = model.Height; + Width = model.Width; + } + } +} diff --git a/src/Discord.Net/Entities/Emoji.cs b/src/Discord.Net/Entities/Emoji.cs new file mode 100644 index 000000000..66010d968 --- /dev/null +++ b/src/Discord.Net/Entities/Emoji.cs @@ -0,0 +1,28 @@ +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.Emoji; + +namespace Discord +{ + public struct Emoji + { + private readonly Guild _guild; + private readonly ImmutableArray _roles; + + public ulong Id { get; } + public string Name { get; } + public bool IsManaged { get; } + public bool RequireColons { get; } + + internal Emoji(Model model, Guild guild) + { + Id = model.Id; + _guild = guild; + + Name = model.Name; + IsManaged = model.Managed; + RequireColons = model.RequireColons; + _roles = model.Roles.Select(x => guild.GetRole(x)).ToImmutableArray(); + } + } +} diff --git a/src/Discord.Net/Entities/Guild.cs b/src/Discord.Net/Entities/Guild.cs new file mode 100644 index 000000000..62172f47d --- /dev/null +++ b/src/Discord.Net/Entities/Guild.cs @@ -0,0 +1,383 @@ +using Discord.API.Rest; +using Discord.Net; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Model = Discord.API.Guild; + +namespace Discord +{ + /// Represents a Discord guild (called a server in the official client). + public class Guild : IEntity + { + private struct Member + { + public readonly GuildUser User; + public readonly GuildPermissions Permissions; + public Member(GuildUser user, GuildPermissions permissions) + { + User = user; + Permissions = permissions; + } + } + + private ConcurrentDictionary _channels; + private ConcurrentDictionary _members; + private ConcurrentDictionary _presences; + private ConcurrentDictionary _roles; + private ConcurrentDictionary _voiceStates; + private ulong _ownerId; + private ulong? _afkChannelId, _embedChannelId; + private int _userCount; + private string _iconId, _splashId; + + /// + public ulong Id { get; } + /// + public DiscordClient Discord { get; } + public GuildUser CurrentUser { get; } + + /// Gets the name of this guild. + public string Name { get; private set; } + /// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are automatically moved to the AFK voice channel, if one is set. + public int AFKTimeout { get; private set; } + /// Returns true if this guild is embeddable (e.g. widget) + public bool IsEmbeddable { get; private set; } + + /// Gets a list of all custom emojis for this guild. + public IReadOnlyList Emojis { get; private set; } + /// Gets a list of extra features added to this guild. + public IReadOnlyList Features { get; private set; } + + /// Gets the voice region for this guild. + public VoiceRegion Region { get; private set; } + /*/// Gets the date and time you joined this guild. + public DateTime JoinedAt { get; private set; }*/ + /// Gets the the role representing all users in a guild. + public Role EveryoneRole { get; private set; } + + /// Gets the number of channels in this guild. + public int ChannelCount => _channels.Count; + /// Gets the number of roles in this guild. + public int RoleCount => _roles.Count; + /// Gets the number of users in this guild. + public int UserCount => _userCount; + /// Gets the number of users downloaded for this guild so far. + internal int CurrentUserCount => _members.Count; + + /// Gets the URL to this guild's current icon. + public string IconUrl => CDN.GetGuildIconUrl(Id, _iconId); + /// Gets the URL to this guild's splash image. + public string SplashUrl => CDN.GetGuildSplashUrl(Id, _splashId); + + /// Gets the user that created this guild. + public GuildUser Owner => GetUser(_ownerId); + /// Gets the default channel for this guild. + public TextChannel DefaultChannel => GetChannel(Id) as TextChannel; + /// Gets the AFK voice channel for this guild. + public VoiceChannel AFKChannel => GetChannel(_afkChannelId) as VoiceChannel; + /// Gets the embed channel for this guild. + public IChannel EmbedChannel => GetChannel(_embedChannelId); //TODO: Is this text or voice? + /// Gets a collection of all channels in this guild. + public IEnumerable Channels => _channels.Select(x => x.Value); + /// Gets a collection of text channels in this guild. + public IEnumerable TextChannels => _channels.Select(x => x.Value).OfType(); + /// Gets a collection of voice channels in this guild. + public IEnumerable VoiceChannels => _channels.Select(x => x.Value).OfType(); + /// Gets a collection of all members in this guild. + public IEnumerable Users => _members.Select(x => x.Value.User); + /// Gets a collection of all roles in this guild. + public IEnumerable Roles => _roles.Select(x => x.Value); + + internal Guild(ulong id, DiscordClient client) + { + Id = id; + Discord = client; + + _channels = new ConcurrentDictionary(); + _members = new ConcurrentDictionary(); + _presences = new ConcurrentDictionary(); + _roles = new ConcurrentDictionary(); + _voiceStates = new ConcurrentDictionary(); + } + + internal void Update(Model model) + { + Name = model.Name; + AFKTimeout = model.AFKTimeout; + _ownerId = model.OwnerId; + _afkChannelId = model.AFKChannelId; + Region = Discord.GetVoiceRegion(model.Region); + _iconId = model.Icon; + _splashId = model.Splash; + Features = model.Features; + IsEmbeddable = model.EmbedEnabled; + _embedChannelId = model.EmbedChannelId; + _userCount = 0;// model.UserCount; + + _roles = new ConcurrentDictionary(2, model.Roles.Length); + foreach (var x in model.Roles) + _roles[x.Id] = Discord.CreateRole(this, x); + EveryoneRole = _roles[Id]; + + Emojis = model.Emojis.Select(x => new Emoji(x, this)).ToArray(); + } + /*internal void Update(ExtendedModel model) + { + Update(model as Model); + + //Only channels or members should have AddXXX(cachePerms: true), not both + if (model.Channels != null) + { + _channels = new ConcurrentDictionary(2, (int)(model.Channels.Length * 1.05)); + foreach (var subModel in model.Channels) + AddChannel(subModel.Id, false).Update(subModel); + DefaultChannel = _channels[Id]; + } + if (model.MemberCount != null) + { + if (_users == null) + _users = new ConcurrentDictionary(2, (int)(model.MemberCount * 1.05)); + _userCount = model.MemberCount.Value; + } + if (!model.IsLarge) + { + if (model.Members != null) + { + foreach (var subModel in model.Members) + AddUser(subModel.User.Id, true, false).Update(subModel); + } + if (model.VoiceStates != null) + { + foreach (var subModel in model.VoiceStates) + GetUser(subModel.UserId)?.Update(subModel); + } + if (model.Presences != null) + { + foreach (var subModel in model.Presences) + GetUser(subModel.User.Id)?.Update(subModel); + } + } + }*/ + + /// Gets the channel with the given id, or null if not found. + public GuildChannel GetChannel(ulong id) + { + GuildChannel result; + _channels.TryGetValue(id, out result); + return result; + } + /// Gets the channel refered to by the given mention, or null if not found. + public GuildChannel GetChannel(string mention) => GetChannel(MentionHelper.GetChannelId(mention)); + private GuildChannel GetChannel(ulong? id) => id != null ? GetChannel(id.Value) : null; + + /// Gets the channel with the given id, or null if not found. + public Role GetRole(ulong id) + { + Role result; + _roles.TryGetValue(id, out result); + return result; + } + private Role GetRole(ulong? id) => id != null ? GetRole(id.Value) : null; + + public GuildUser GetUser(ulong id) + { + Member result; + if (_members.TryGetValue(id, out result)) + return result.User; + else + return null; + } + public GuildUser GetUser(string username, ushort discriminator) + { + if (username == null) throw new ArgumentNullException(nameof(username)); + + foreach (var member in _members) + { + var user = member.Value.User; + if (user.Discriminator == discriminator && user.Username == username) + return user; + } + return null; + } + public GuildUser GetUser(string mention) => GetUser(MentionHelper.GetUserId(mention)); + private GuildUser GetUser(ulong? id) => id != null ? GetUser(id.Value) : null; + + public async Task> GetBans() + { + var discord = Discord; + var response = await Discord.RestClient.Send(new GetGuildBansRequest(Id)).ConfigureAwait(false); + return response.Select(x => Discord.CreateBannedUser(this, x)); + } + + public async Task> GetInvites() + { + var response = await Discord.RestClient.Send(new GetGuildInvitesRequest(Id)).ConfigureAwait(false); + return response.Select(x => + { + var invite = Discord.CreatePublicInvite(x); + invite.Update(x); + return invite; + }); + } + + public async Task CreateTextChannel(string name) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var request = new CreateChannelRequest(Id) { Name = name, Type = ChannelType.Text }; + var response = await Discord.RestClient.Send(request).ConfigureAwait(false); + + return Discord.CreateTextChannel(this, response); + } + public async Task CreateVoiceChannel(string name) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var request = new CreateChannelRequest(Id) { Name = name, Type = ChannelType.Voice }; + var response = await Discord.RestClient.Send(request).ConfigureAwait(false); + + return Discord.CreateVoiceChannel(this, response); + } + public Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) + { + return DefaultChannel.CreateInvite(maxAge, maxUses, tempMembership, withXkcd); + } + public async Task CreateRole(string name, GuildPermissions? permissions = null, Color color = null, bool isHoisted = false) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var createRequest = new CreateRoleRequest(Id); + var createResponse = await Discord.RestClient.Send(createRequest).ConfigureAwait(false); + var role = Discord.CreateRole(this, createResponse); + + var editRequest = new ModifyGuildRoleRequest(role.Guild.Id, role.Id) + { + Name = name, + Permissions = (int)(permissions ?? role.Permissions).RawValue, + Color = (int)(color ?? Color.Default).RawValue, + Hoist = isHoisted + }; + var editResponse = await Discord.RestClient.Send(editRequest).ConfigureAwait(false); + role.Update(editResponse); + + return role; + } + + public async Task PruneUsers(int days = 30, bool simulate = false) + { + if (simulate) + { + var response = await Discord.RestClient.Send(new GetGuildPruneCountRequest(Id) { Days = days }).ConfigureAwait(false); + return response.Pruned; + } + else + { + var response = await Discord.RestClient.Send(new BeginGuildPruneRequest(Id) { Days = days }).ConfigureAwait(false); + return response.Pruned; + } + } + + public Task Ban(GuildUser user, int pruneDays = 0) + { + return Discord.RestClient.Send(new CreateGuildBanRequest(Id, user.Id) + { + PruneDays = pruneDays + }); + } + public async Task Unban(GuildUser user) + { + try { await Discord.RestClient.Send(new RemoveGuildBanRequest(Id, user.Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + + public async Task Update() + { + var response = await Discord.RestClient.Send(new GetGuildRequest(Id)).ConfigureAwait(false); + if (response != null) + Update(response); + } + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var req = new ModifyGuildRequest(Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); + } + + /// Leaves this guild. + public async Task Leave() + { + try { await Discord.RestClient.Send(new LeaveGuildRequest(Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + /// Deletes this guild. + public async Task Delete() + { + try { await Discord.RestClient.Send(new DeleteGuildRequest(Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + + internal void UpdatePermissions(GuildUser user) + { + Member member; + if (_members.TryGetValue(user.Id, out member)) + { + var perms = member.Permissions; + if (UpdatePermissions(member.User, ref perms)) + { + _members[user.Id] = new Member(member.User, perms); + foreach (var channel in _channels) + channel.Value.UpdatePermissions(user); + } + } + } + + private bool UpdatePermissions(GuildUser user, ref GuildPermissions permissions) + { + uint newPermissions = 0; + + if (user.Id == _ownerId) + newPermissions = GuildPermissions.All.RawValue; + else + { + foreach (var role in user.Presence.Roles) + newPermissions |= role.Permissions.RawValue; + } + + if (PermissionsHelper.HasBit(ref newPermissions, (byte)PermissionBit.ManageRolesOrPermissions)) + newPermissions = GuildPermissions.All.RawValue; + + if (newPermissions != permissions.RawValue) + { + permissions = new GuildPermissions(newPermissions); + return true; + } + return false; + } + + /*internal IGuildChannel AddChannel(ulong id, bool cachePerms) + { + var channel = new Channel(Discord, id, this); + if (cachePerms && Discord.UsePermissionsCache) + { + foreach (var user in Users) + channel.AddUser(user); + } + Discord.AddChannel(channel); + return _channels.GetOrAdd(id, x => channel); + } + internal IGuildChannel RemoveChannel(ulong id) + { + IGuildChannel channel; + _channels.TryRemove(id, out channel); + return channel; + }*/ + } +} diff --git a/src/Discord.Net/Entities/Helpers/InviteManager.cs b/src/Discord.Net/Entities/Helpers/InviteManager.cs new file mode 100644 index 000000000..13058e621 --- /dev/null +++ b/src/Discord.Net/Entities/Helpers/InviteManager.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Discord +{ + public class InviteManager + { + } +} diff --git a/src/Discord.Net/Entities/Helpers/MentionHelper.cs b/src/Discord.Net/Entities/Helpers/MentionHelper.cs new file mode 100644 index 000000000..78777a518 --- /dev/null +++ b/src/Discord.Net/Entities/Helpers/MentionHelper.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Immutable; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Discord +{ + internal static class MentionHelper + { + private static readonly Regex _userRegex = new Regex(@"<@([0-9]+)>"); + private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+)>"); + private static readonly Regex _roleRegex = new Regex(@"@everyone"); + + internal static string Mention(User user) => $"<@{user.Id}>"; + internal static string Mention(IChannel channel) => $"<#{channel.Id}>"; + internal static string Mention(Role role) => role.IsEveryone ? "@everyone" : ""; + + internal static string CleanUserMentions(GuildChannel channel, string text, ImmutableArray.Builder users = null) + { + var guild = channel.Guild; + return _userRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + var user = guild.GetUser(id); //We're able to mention users outside of our channel + if (user != null) + { + if (users != null) + users.Add(user); + return '@' + user.Username; + } + } + return e.Value; //User not found or parse failed + })); + } + internal static string CleanChannelMentions(GuildChannel channel, string text, ImmutableArray.Builder channels = null) + { + var guild = channel.Guild; + return _channelRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + var mentionedChannel = guild.GetChannel(id); + if (mentionedChannel != null && mentionedChannel.Guild.Id == guild.Id) + { + if (channels != null) + channels.Add(mentionedChannel); + return '#' + mentionedChannel.Name; + } + } + return e.Value; //Channel not found or parse failed + })); + } + /*internal static string CleanRoleMentions(User user, IPublicChannel channel, string text, ImmutableArray.Builder roles = null) + { + var guild = channel.Guild; + if (guild == null) return text; + + return _roleRegex.Replace(text, new MatchEvaluator(e => + { + if (roles != null && user.GetPermissions(channel).MentionEveryone) + roles.Add(guild.EveryoneRole); + return e.Value; + })); + }*/ + + internal static ulong GetUserId(string mention) + { + mention = mention.Trim(); + if (mention.Length >= 3 && mention[0] == '<' && mention[1] == '@' && mention[mention.Length - 1] == '>') + { + mention = mention.Substring(2, mention.Length - 3); + + ulong id; + if (ulong.TryParse(mention, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + return id; + } + throw new ArgumentException("Invalid mention format", nameof(mention)); + } + internal static ulong GetChannelId(string mention) + { + mention = mention.Trim(); + if (mention.Length >= 3 && mention[0] == '<' && mention[1] == '#' && mention[mention.Length - 1] == '>') + { + mention = mention.Substring(2, mention.Length - 3); + + ulong id; + if (ulong.TryParse(mention, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + return id; + } + throw new ArgumentException("Invalid mention format", nameof(mention)); + } + + internal static string ResolveMentions(IChannel channel, string text) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + if (text == null) throw new ArgumentNullException(nameof(text)); + + var publicChannel = channel as GuildChannel; + if (publicChannel != null) + { + text = CleanUserMentions(publicChannel, text); + text = CleanChannelMentions(publicChannel, text); + //text = CleanRoleMentions(publicChannel, text); + } + return text; + } + } +} diff --git a/src/Discord.Net/Entities/Helpers/MessageManager.cs b/src/Discord.Net/Entities/Helpers/MessageManager.cs new file mode 100644 index 000000000..1285093ae --- /dev/null +++ b/src/Discord.Net/Entities/Helpers/MessageManager.cs @@ -0,0 +1,174 @@ +using Discord.API.Rest; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Message; + +namespace Discord +{ + internal class MessageManager : IEnumerable + { + private readonly IMessageChannel _channel; + private readonly ConcurrentDictionary _messages; + private readonly ConcurrentQueue _orderedMessages; + private readonly int _size; + + public MessageManager(IMessageChannel channel, int size = 0) + { + _channel = channel; + _size = (int)(size * 1.05); + if (size > 0) + { + _messages = new ConcurrentDictionary(2, size); + _orderedMessages = new ConcurrentQueue(); + } + } + + internal Message Add(Model model, User user) + => Add(_channel.Discord.CreateMessage(_channel, user, model)); + private Message Add(Message message) + { + if (_size > 0) + { + if (_messages.TryAdd(message.Id, message)) + { + _orderedMessages.Enqueue(message); + + Message msg; + while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msg)) + _messages.TryRemove(msg.Id, out msg); + } + } + return message; + } + internal void Remove(ulong id) + { + if (_size > 0) + { + Message msg; + _messages.TryRemove(id, out msg); + } + } + + public Task Get(ulong id) + { + if (_messages != null) + { + Message result; + if (_messages.TryGetValue(id, out result)) + return Task.FromResult(result); + } + else + throw new NotSupportedException(); //TODO: Not supported yet + + return Task.FromResult(null); + } + + public async Task> GetMany(int limit = DiscordConfig.MaxMessagesPerBatch, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) + { + if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); + if (limit == 0) return ImmutableArray.Empty; + + if (_messages != null) + { + ImmutableArray cachedMessages; + if (relativeMessageId == null) + cachedMessages = _orderedMessages.ToImmutableArray(); + else if (relativeDir == Relative.Before) + cachedMessages = _orderedMessages.Where(x => x.Id < relativeMessageId.Value).ToImmutableArray(); + else + cachedMessages = _orderedMessages.Where(x => x.Id > relativeMessageId.Value).ToImmutableArray(); + + if (cachedMessages.Length == limit) + return cachedMessages; + else if (cachedMessages.Length > limit) + return cachedMessages.Skip(cachedMessages.Length - limit); + else + { + var missingMessages = await Download(limit - cachedMessages.Length, cachedMessages[0].Id, Relative.Before).ConfigureAwait(false); + return missingMessages.SelectMany(x => x).Concat(cachedMessages); + } + } + return (await Download(limit, relativeMessageId, relativeDir).ConfigureAwait(false)).SelectMany(x => x); + } + private async Task>> Download(int limit = DiscordConfig.MaxMessagesPerBatch, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) + { + var request = new GetChannelMessagesRequest(_channel.Id) + { + Limit = limit, + RelativeDir = relativeDir, + RelativeId = relativeMessageId ?? 0 + }; + var guild = (_channel as GuildChannel)?.Guild; + var recipient = (_channel as DMChannel)?.Recipient; + + int runs = limit / DiscordConfig.MaxMessagesPerBatch; + int lastRunCount = limit - runs * DiscordConfig.MaxMessagesPerBatch; + var result = new Message[runs][]; + + int i = 0; + for (; i < runs; i++) + { + request.Limit = (i == runs - 1) ? lastRunCount : DiscordConfig.MaxMessagesPerBatch; + + Model[] models = await _channel.Discord.RestClient.Send(request).ConfigureAwait(false); + + //Was this an empty batch? + if (models.Length == 0) break; + + Message[] msgs = new Message[models.Length]; + for (int j = 0; j < models.Length; j++) + { + var model = models[j]; + var user = _channel.GetUser(model.Author.Id); + msgs[j] = _channel.Discord.CreateMessage(_channel, user, model); + } + result[i] = msgs; + + request.RelativeId = relativeDir == Relative.Before ? msgs[0].Id : msgs[msgs.Length - 1].Id; + + //Was this an incomplete (the last) batch? + if (models.Length != DiscordConfig.MaxMessagesPerBatch) { i++; break; } + } + + //Dont return nulls if we didnt get all the requested messages + for (; i < runs; i++) + result[i] = Array.Empty(); + + return result; + } + + public Task Send(string text, bool isTTS) + { + if (text == "") throw new ArgumentException("Value cannot be blank", nameof(text)); + if (text.Length > DiscordConfig.MaxMessageSize) + throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {DiscordConfig.MaxMessageSize} characters or less."); + return _channel.Discord.MessageQueue.QueueSend(_channel, text, isTTS); + } + public async Task SendFile(string filePath, string text = null, bool isTTS = false) + { + using (var stream = File.OpenRead(filePath)) + return await SendFile(stream, Path.GetFileName(filePath), text, isTTS).ConfigureAwait(false); + } + public async Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) + { + var request = new SendFileRequest(_channel.Id) + { + Filename = filename, + Stream = stream + }; + var response = await _channel.Discord.RestClient.Send(request).ConfigureAwait(false); + + return _channel.Discord.CreateMessage(_channel, _channel.GetCurrentUser(), response); + } + public Task TriggerTyping() => _channel.Discord.RestClient.Send(new TriggerTypingIndicatorRequest(_channel.Id)); + + public IEnumerator GetEnumerator() => _orderedMessages.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _orderedMessages.GetEnumerator(); + } +} diff --git a/src/Discord.Net/Entities/Helpers/PermissionManager.cs b/src/Discord.Net/Entities/Helpers/PermissionManager.cs new file mode 100644 index 000000000..a7047bd94 --- /dev/null +++ b/src/Discord.Net/Entities/Helpers/PermissionManager.cs @@ -0,0 +1,274 @@ +using Discord.API.Rest; +using Discord.Net; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord +{ + internal class PermissionManager + { + public struct Member + { + public GuildUser User { get; } + public ChannelPermissions Permissions { get; } + + public Member(GuildUser user, ChannelPermissions permissions) + { + User = user; + Permissions = permissions; + } + } + + private readonly GuildChannel _channel; + private readonly ConcurrentDictionary _users; + private Dictionary _rules; + + public IEnumerable Users => _users.Select(x => x.Value); + public IEnumerable Overwrites => _rules.Values; + + public PermissionManager(GuildChannel channel, bool cacheUsers) + { + _channel = channel; + if (cacheUsers) + _users = new ConcurrentDictionary(2, (int)(channel.Guild.UserCount * 1.05)); + } + + public void Update(Model model) + { + _rules = model.PermissionOverwrites + .Select(x => new Overwrite(x)) + .ToDictionary(x => x.TargetId); + UpdatePermissions(); + } + + public OverwritePermissions? GetOverwrite(GuildUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + + Overwrite rule; + if (_rules.TryGetValue(user.Id, out rule)) + return rule.Permissions; + return null; + } + public OverwritePermissions? GetOverwrite(Role role) + { + if (role == null) throw new ArgumentNullException(nameof(role)); + + Overwrite rule; + if (_rules.TryGetValue(role.Id, out rule)) + return rule.Permissions; + return null; + } + public Task AddOrUpdateOverwrite(GuildUser user, OverwritePermissions permissions) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + return AddOrUpdateOverwrite(user.Id, permissions); + } + public Task AddOrUpdateOverwrite(Role role, OverwritePermissions permissions) + { + if (role == null) throw new ArgumentNullException(nameof(role)); + return AddOrUpdateOverwrite(role.Id, permissions); + } + private Task AddOrUpdateOverwrite(ulong targetId, OverwritePermissions permissions) + { + var request = new ModifyChannelPermissionsRequest(_channel.Id, targetId) + { + Allow = permissions.AllowValue, + Deny = permissions.DenyValue + }; + return _channel.Discord.RestClient.Send(request); + } + public Task RemoveOverwrite(GuildUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + return RemoveOverwrite(user.Id); + } + public Task RemoveOverwrite(Role role) + { + if (role == null) throw new ArgumentNullException(nameof(role)); + return RemoveOverwrite(role.Id); + } + private async Task RemoveOverwrite(ulong id) + { + try { await _channel.Discord.RestClient.Send(new DeleteChannelPermissionsRequest(_channel.Id, id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + + public ChannelPermissions GetPermissions(GuildUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + + if (_users != null) + { + Member member; + if (_users.TryGetValue(user.Id, out member)) + return member.Permissions; + else + return ChannelPermissions.None; + } + else + { + var perms = new ChannelPermissions(); + ResolvePermissions(user, ref perms); + return perms; + } + } + public void UpdatePermissions() + { + if (_users != null) + { + foreach (var pair in _users) + { + var member = pair.Value; + var perms = member.Permissions; + if (ResolvePermissions(member.User, ref perms)) + _users[pair.Key] = new Member(member.User, perms); + } + } + } + public void UpdatePermissions(GuildUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + + if (_users != null) + { + Member member; + if (_users.TryGetValue(user.Id, out member)) + { + var perms = member.Permissions; + if (ResolvePermissions(member.User, ref perms)) + _users[user.Id] = new Member(member.User, perms); + } + } + } + + + public ChannelPermissions ResolvePermissions(GuildUser user) + { + var permissions = new ChannelPermissions(); + ResolvePermissions(user, ref permissions); + return permissions; + } + public bool ResolvePermissions(GuildUser user, ref ChannelPermissions permissions) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + + uint newPermissions = 0; + var guild = user.Guild; + + uint mask = ChannelPermissions.All(_channel.Type).RawValue; + if (user == guild.Owner) + newPermissions = mask; //Private messages and owners always have all permissions + else + { + //Start with this user's guild permissions + newPermissions = user.GuildPermissions.RawValue; + var rules = _rules; + + Overwrite entry; + var roles = user.Presence.Roles.ToArray(); + if (roles.Length > 0) + { + for (int i = 0; i < roles.Length; i++) + { + if (rules.TryGetValue(roles[i].Id, out entry)) + newPermissions &= ~entry.Permissions.DenyValue; + } + for (int i = 0; i < roles.Length; i++) + { + if (rules.TryGetValue(roles[i].Id, out entry)) + newPermissions |= entry.Permissions.AllowValue; + } + } + if (rules.TryGetValue(user.Id, out entry)) + newPermissions = (newPermissions & ~entry.Permissions.DenyValue) | entry.Permissions.AllowValue; + + if (PermissionsHelper.HasBit(ref newPermissions, (int)PermissionBit.ManageRolesOrPermissions)) + newPermissions = mask; //ManageRolesOrPermissions gives all permisions + else + { + var channelType = _channel.Type; + if (channelType == ChannelType.Text && !PermissionsHelper.HasBit(ref newPermissions, (int)PermissionBit.ReadMessages)) + newPermissions = 0; //No read permission on a text channel removes all other permissions + else if (channelType == ChannelType.Voice && !PermissionsHelper.HasBit(ref newPermissions, (int)PermissionBit.Connect)) + newPermissions = 0; //No connect permissions on a voice channel removes all other permissions + else + newPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from guildPerms, for example) + } + } + + if (newPermissions != permissions.RawValue) + { + permissions = new ChannelPermissions(newPermissions); + return true; + } + return false; + } + + public GuildUser GetUser(ulong id) + { + if (_users != null) + { + Member member; + if (_users.TryGetValue(id, out member)) + return member.User; + } + else + { + var user = _channel.Guild.GetUser(id); + if (_channel.Type == ChannelType.Text) + { + if (ResolvePermissions(user).ReadMessages) + return user; + } + else if (_channel.Type == ChannelType.Voice) + { + if (user.VoiceState?.VoiceChannel == _channel) + return user; + } + } + return null; + } + public IEnumerable GetUsers() + { + if (_users != null) + return _users.Select(x => x.Value.User); + else + { + var users = _channel.Guild.Users; + if (_channel.Type == ChannelType.Text) + { + var perms = new ChannelPermissions(); + return users.Where(x => ResolvePermissions(x, ref perms)); + } + else if (_channel.Type == ChannelType.Voice) + return users.Where(x => x.VoiceState?.VoiceChannel == _channel); + } + return Enumerable.Empty(); + } + + public void AddUser(GuildUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + + if (_users != null) + { + var perms = new ChannelPermissions(); + ResolvePermissions(user, ref perms); + var member = new Member(user, ChannelPermissions.None); + _users[user.Id] = new Member(user, ChannelPermissions.None); + } + } + public void RemoveUser(ulong id) + { + Member ignored; + if (_users != null) + _users.TryRemove(id, out ignored); + } + } +} diff --git a/src/Discord.Net/Entities/Helpers/PermissionsHelper.cs b/src/Discord.Net/Entities/Helpers/PermissionsHelper.cs new file mode 100644 index 000000000..e14d5e210 --- /dev/null +++ b/src/Discord.Net/Entities/Helpers/PermissionsHelper.cs @@ -0,0 +1,61 @@ +using System.Runtime.CompilerServices; + +namespace Discord +{ + internal static class PermissionsHelper + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PermValue GetValue(uint allow, uint deny, PermissionBit bit) + { + if (HasBit(ref allow, (byte)bit)) + return PermValue.Allow; + else if (HasBit(ref deny, (byte)bit)) + return PermValue.Deny; + else + return PermValue.Inherit; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetValue(uint value, PermissionBit bit) => HasBit(ref value, (byte)bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint rawValue, bool? value, PermissionBit bit) + { + if (value.HasValue) + { + if (value == true) + SetBit(ref rawValue, (byte)bit); + else + UnsetBit(ref rawValue, (byte)bit); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint allow, ref uint deny, PermValue? value, PermissionBit bit) + { + if (value.HasValue) + { + switch (value) + { + case PermValue.Allow: + SetBit(ref allow, (byte)bit); + UnsetBit(ref deny, (byte)bit); + break; + case PermValue.Deny: + UnsetBit(ref allow, (byte)bit); + SetBit(ref deny, (byte)bit); + break; + default: + UnsetBit(ref allow, (byte)bit); + UnsetBit(ref deny, (byte)bit); + break; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool HasBit(ref uint value, byte bit) => (value & (1U << bit)) != 0; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetBit(ref uint value, byte bit) => value |= (1U << bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UnsetBit(ref uint value, byte bit) => value &= ~(1U << bit); + } +} diff --git a/src/Discord.Net/Entities/IChannel.cs b/src/Discord.Net/Entities/IChannel.cs deleted file mode 100644 index f39678abb..000000000 --- a/src/Discord.Net/Entities/IChannel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace Discord -{ - public interface IChannel - { - /// Gets the unique identifier for this channel. - ulong Id { get; } - DiscordClient Client { get; } - - /// Gets the type of this channel. - ChannelType Type { get; } - bool IsText { get; } - bool IsVoice { get; } - bool IsPrivate { get; } - bool IsPublic { get; } - - /// Gets a collection of all users in this channel. - IEnumerable Users { get; } - } -} diff --git a/ref/Entities/IEntity.cs b/src/Discord.Net/Entities/IEntity.cs similarity index 81% rename from ref/Entities/IEntity.cs rename to src/Discord.Net/Entities/IEntity.cs index ac707a69e..ecdde0a56 100644 --- a/ref/Entities/IEntity.cs +++ b/src/Discord.Net/Entities/IEntity.cs @@ -7,13 +7,12 @@ namespace Discord /// Gets the unique identifier for this object. TId Id { get; } } + public interface IEntity { /// Gets the DiscordClient that manages this object. DiscordClient Discord { get; } - /// Gets the state of this object. - EntityState State { get; } - + /// Downloads the latest values and updates this object. Task Update(); } diff --git a/ref/Entities/IMentionable.cs b/src/Discord.Net/Entities/IMentionable.cs similarity index 100% rename from ref/Entities/IMentionable.cs rename to src/Discord.Net/Entities/IMentionable.cs diff --git a/src/Discord.Net/Entities/IPrivateChannel.cs b/src/Discord.Net/Entities/IPrivateChannel.cs deleted file mode 100644 index 44d55a67f..000000000 --- a/src/Discord.Net/Entities/IPrivateChannel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord -{ - public interface IPrivateChannel : IChannel - { - User Recipient { get; } - } -} diff --git a/src/Discord.Net/Entities/IPublicChannel.cs b/src/Discord.Net/Entities/IPublicChannel.cs deleted file mode 100644 index 32b8c610e..000000000 --- a/src/Discord.Net/Entities/IPublicChannel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Discord -{ - public interface IPublicChannel : IChannel - { - } -} diff --git a/src/Discord.Net/Entities/ITextChannel.cs b/src/Discord.Net/Entities/ITextChannel.cs deleted file mode 100644 index af665ab0f..000000000 --- a/src/Discord.Net/Entities/ITextChannel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.IO; -using System.Threading.Tasks; - -namespace Discord -{ - public interface ITextChannel : IChannel - { - Message GetMessage(ulong id); - Task DownloadMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before); - - Task SendMessage(string text, bool isTTS = false); - Task SendFile(string filePath); - Task SendFile(string filename, Stream stream); - - Task SendIsTyping(); - } -} diff --git a/src/Discord.Net/Entities/IVoiceChannel.cs b/src/Discord.Net/Entities/IVoiceChannel.cs deleted file mode 100644 index 7c3f2c194..000000000 --- a/src/Discord.Net/Entities/IVoiceChannel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Discord -{ - public interface IVoiceChannel : IChannel - { - } -} diff --git a/src/Discord.Net/Entities/Invite.cs b/src/Discord.Net/Entities/Invite.cs deleted file mode 100644 index a1b27ce4a..000000000 --- a/src/Discord.Net/Entities/Invite.cs +++ /dev/null @@ -1,151 +0,0 @@ -using APIInvite = Discord.API.Client.Invite; -using Discord.API.Client; -using Discord.API.Client.Rest; -using Discord.Net; -using System; -using System.Net; -using System.Threading.Tasks; - -namespace Discord -{ - public class Invite - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - public class ServerInfo - { - /// Returns the unique identifier of this server. - public ulong Id { get; } - /// Returns the name of this server. - public string Name { get; } - - internal ServerInfo(ulong id, string name) - { - Id = id; - Name = name; - } - } - public class ChannelInfo - { - /// Returns the unique identifier of this channel. - public ulong Id { get; } - /// Returns the name of this channel. - public string Name { get; } - - internal ChannelInfo(ulong id, string name) - { - Id = id; - Name = name; - } - } - public class InviterInfo - { - /// Returns the unique identifier for this user. - public ulong Id { get; } - /// Returns the name of this user. - public string Name { get; } - /// Returns the by-name unique identifier for this user. - public ushort Discriminator { get; } - /// Returns the unique identifier for this user's avatar. - public string AvatarId { get; } - - /// Returns the full path to this user's avatar. - public string AvatarUrl => User.GetAvatarUrl(Id, AvatarId); - - internal InviterInfo(ulong id, string name, ushort discriminator, string avatarId) - { - Id = id; - Name = name; - Discriminator = discriminator; - AvatarId = avatarId; - } - } - - public DiscordClient Client { get; } - - /// Gets the unique code for this invite. - public string Code { get; } - /// Gets, if enabled, an alternative human-readable invite code. - public string XkcdCode { get; } - - /// Gets information about the server this invite is attached to. - public ServerInfo Server { get; private set; } - /// Gets information about the channel this invite is attached to. - public ChannelInfo Channel { get; private set; } - /// Gets the time (in seconds) until the invite expires. - public int? MaxAge { get; private set; } - /// Gets the amount of times this invite has been used. - public int Uses { get; private set; } - /// Gets the max amount of times this invite may be used. - public int? MaxUses { get; private set; } - /// Returns true if this invite has expired, been destroyed, or you are banned from that server. - public bool IsRevoked { get; private set; } - /// If true, a user accepting this invite will be kicked from the server after closing their client. - public bool IsTemporary { get; private set; } - /// Gets when this invite was created. - public DateTime CreatedAt { get; private set; } - - /// Returns a URL for this invite using XkcdCode if available or Id if not. - public string Url => $"{DiscordConfig.InviteUrl}/{Code}"; - - internal Invite(APIInvite model, DiscordClient client) - : this(model.Code, model.XkcdPass) - { - Client = client; - Update(model); - } - internal Invite(InviteReference model, DiscordClient client) - : this(model.Code, model.XkcdPass) - { - Client = client; - Update(model); - } - private Invite(string code, string xkcdCode) - { - Code = code; - XkcdCode = xkcdCode; - } - - internal void Update(APIInvite model) - { - Update(model as InviteReference); - - if (model.IsRevoked != null) - IsRevoked = model.IsRevoked.Value; - if (model.IsTemporary != null) - IsTemporary = model.IsTemporary.Value; - if (model.MaxAge != null) - MaxAge = model.MaxAge.Value != 0 ? model.MaxAge.Value : (int?)null; - if (model.MaxUses != null) - MaxUses = model.MaxUses.Value; - if (model.Uses != null) - Uses = model.Uses.Value; - if (model.CreatedAt != null) - CreatedAt = model.CreatedAt.Value; - } - internal void Update(InviteReference model) - { - if (model.Guild != null) - Server = new ServerInfo(model.Guild.Id, model.Guild.Name); - if (model.Channel != null) - Channel = new ChannelInfo(model.Channel.Id, model.Channel.Name); - } - - public async Task Delete() - { - try { await Client.ClientAPI.Send(new DeleteInviteRequest(Code)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - public Task Accept() - => Client.ClientAPI.Send(new AcceptInviteRequest(Code)); - - internal Invite Clone() - { - var result = new Invite(Code, XkcdCode); - _cloner(this, result); - return result; - } - - public override string ToString() => $"{Server}/{XkcdCode ?? Code}"; - } -} diff --git a/src/Discord.Net/Entities/Invites/GuildInvite.cs b/src/Discord.Net/Entities/Invites/GuildInvite.cs new file mode 100644 index 000000000..d4387c744 --- /dev/null +++ b/src/Discord.Net/Entities/Invites/GuildInvite.cs @@ -0,0 +1,71 @@ +using Discord.API.Rest; +using Discord.Net; +using System; +using System.Net; +using System.Threading.Tasks; +using Model = Discord.API.InviteMetadata; + +namespace Discord +{ + public class GuildInvite : IInvite, IEntity + { + /// + public string Code { get; } + /// Gets the channel this invite is attached to. + public GuildChannel Channel { get; } + + /// + public string XkcdCode { get; private set; } + /// Gets the time (in seconds) until the invite expires, or null if it never expires. + public int? MaxAge { get; private set; } + /// Gets the amount of times this invite has been used. + public int Uses { get; private set; } + /// Gets the max amount of times this invite may be used, or null if there is no limit. + public int? MaxUses { get; private set; } + /// Returns true if this invite has expired or been deleted. + public bool IsRevoked { get; private set; } + /// Returns true if a user accepting this invite will be kicked from the guild after closing their client. + public bool IsTempMembership { get; private set; } + + /// Gets the guild this invite is attached to. + public Guild Guild => Channel.Guild; + /// + public DiscordClient Discord => Guild.Discord; + /// + public string Url => $"{DiscordConfig.InviteUrl}/{Code}"; + /// + public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; + /// + string IEntity.Id => Code; + /// + InviteChannel IInvite.Channel => new InviteChannel(Channel.Id, Channel.Name); + /// + InviteGuild IInvite.Guild => new InviteGuild(Guild.Id, Guild.Name); + + internal GuildInvite(string code, GuildChannel channel) + { + Code = code; + Channel = channel; + } + + internal void Update(Model model) + { + XkcdCode = model.XkcdPass; + IsRevoked = model.Revoked; + IsTempMembership = model.Temporary; + MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null; + MaxUses = model.MaxUses; + Uses = model.Uses; + } + + /// + public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet + + /// Deletes this invite. + public async Task Delete() + { + try { await Discord.RestClient.Send(new DeleteInviteRequest(Code)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } + } + } +} diff --git a/src/Discord.Net/Entities/Invites/IInvite.cs b/src/Discord.Net/Entities/Invites/IInvite.cs new file mode 100644 index 000000000..8765cdc93 --- /dev/null +++ b/src/Discord.Net/Entities/Invites/IInvite.cs @@ -0,0 +1,20 @@ +namespace Discord +{ + public interface IInvite : IEntity + { + /// Gets the unique code for this invite. + string Code { get; } + /// Gets, if enabled, an alternative human-readable invite code. + string XkcdCode { get; } + + /// Returns a URL for this invite using Code. + string Url { get; } + /// Returns a URL for this invite using XkcdCode if available or null if not. + string XkcdUrl { get; } + + /// Gets information about the guild this invite is attached to. + InviteGuild Guild { get; } + /// Gets information about the channel this invite is attached to. + InviteChannel Channel { get; } + } +} diff --git a/src/Discord.Net/Entities/Invites/Invite.cs b/src/Discord.Net/Entities/Invites/Invite.cs new file mode 100644 index 000000000..2dbd07ec5 --- /dev/null +++ b/src/Discord.Net/Entities/Invites/Invite.cs @@ -0,0 +1,48 @@ +using Discord.API.Rest; +using System.Threading.Tasks; +using Model = Discord.API.Invite; + +namespace Discord +{ + public class PublicInvite : IInvite, IEntity + { + /// + public string Code { get; } + /// + string IEntity.Id => Code; + /// + public DiscordClient Discord { get; } + + /// + public InviteGuild Guild { get; private set; } + /// + public InviteChannel Channel { get; private set; } + /// + public string XkcdCode { get; private set; } + + /// + public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}"; + /// + public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; + + internal PublicInvite(string code, DiscordClient client) + { + Code = code; + Discord = client; + } + + internal void Update(Model model) + { + XkcdCode = model.XkcdPass; + Guild = new InviteGuild(model.Guild.Id, model.Guild.Name); + Channel = new InviteChannel(model.Channel.Id, model.Channel.Name); + } + + /// + public async Task Update() + => Update(await Discord.RestClient.Send(new GetInviteRequest(Code)).ConfigureAwait(false)); + + /// + public override string ToString() => Url; + } +} diff --git a/src/Discord.Net/Entities/Invites/InviteChannel.cs b/src/Discord.Net/Entities/Invites/InviteChannel.cs new file mode 100644 index 000000000..45ac5b084 --- /dev/null +++ b/src/Discord.Net/Entities/Invites/InviteChannel.cs @@ -0,0 +1,16 @@ +namespace Discord +{ + public struct InviteChannel + { + /// Returns the unique identifier for this channel. + public ulong Id { get; } + /// Returns the name of this channel. + public string Name { get; } + + internal InviteChannel(ulong id, string name) + { + Id = id; + Name = name; + } + } +} diff --git a/src/Discord.Net/Entities/Invites/InviteGuild.cs b/src/Discord.Net/Entities/Invites/InviteGuild.cs new file mode 100644 index 000000000..0354bd282 --- /dev/null +++ b/src/Discord.Net/Entities/Invites/InviteGuild.cs @@ -0,0 +1,16 @@ +namespace Discord +{ + public struct InviteGuild + { + /// Returns the unique identifier for this guild. + public ulong Id { get; } + /// Returns the name of this guild. + public string Name { get; } + + internal InviteGuild(ulong id, string name) + { + Id = id; + Name = name; + } + } +} diff --git a/src/Discord.Net/Entities/Managers/MessageManager.cs b/src/Discord.Net/Entities/Managers/MessageManager.cs deleted file mode 100644 index 14b569750..000000000 --- a/src/Discord.Net/Entities/Managers/MessageManager.cs +++ /dev/null @@ -1,146 +0,0 @@ -using APIMessage = Discord.API.Client.Message; -using Discord.API.Client.Rest; -using Discord.Net; -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading.Tasks; - -namespace Discord -{ - internal class MessageManager : IEnumerable - { - private readonly ITextChannel _channel; - private readonly int _size; - private readonly ConcurrentDictionary _messages; - private readonly ConcurrentQueue _orderedMessages; - - public MessageManager(ITextChannel channel, int size = 0) - { - _channel = channel; - _size = size; - if (size > 0) - { - _messages = new ConcurrentDictionary(2, size); - _orderedMessages = new ConcurrentQueue(); - } - } - - internal Message Add(APIMessage model, User user) => Add(new Message(model, _channel, user)); - internal Message Add(ulong id, User user) => Add(new Message(id, _channel, user)); - private Message Add(Message message) - { - message.State = MessageState.Normal; - if (_size > 0) - { - if (_messages.TryAdd(message.Id, message)) - { - _orderedMessages.Enqueue(message.Id); - - ulong msgId; - while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) - { - Message msg; - if (_messages.TryRemove(msgId, out msg)) - msg.State = MessageState.Detached; - } - } - } - return message; - } - internal Message Remove(ulong id) - { - if (_size > 0) - { - Message msg; - if (_messages.TryRemove(id, out msg)) - return msg; - } - return new Message(id, _channel, null) { State = MessageState.Deleted }; - } - - public Message Get(ulong id, ulong? userId = null) - { - if (_messages != null) - { - Message result; - if (_messages.TryGetValue(id, out result)) - return result; - } - return new Message(id, _channel, userId != null ? (_channel as Channel).GetUser(userId.Value) : null) { State = MessageState.Detached }; - } - - public async Task Download(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) - { - if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); - if (limit == 0) return new Message[0]; - - try - { - var request = new GetMessagesRequest(_channel.Id) - { - Limit = limit, - RelativeDir = relativeMessageId.HasValue ? relativeDir == Relative.Before ? "before" : "after" : null, - RelativeId = relativeMessageId ?? 0 - }; - var msgs = await _channel.Client.ClientAPI.Send(request).ConfigureAwait(false); - var server = (_channel as PublicChannel)?.Server; - - return msgs.Select(x => - { - Message msg = null; - ulong id = x.Author.Id; - var user = server?.GetUser(id) ?? (_channel as Channel).GetUser(id); - msg = new Message(x, _channel, user); - return msg; - }).ToArray(); - } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) - { - return new Message[0]; - } - } - - public Task Send(string text, bool isTTS) - { - if (text == "") throw new ArgumentException("Value cannot be blank", nameof(text)); - if (text.Length > DiscordConfig.MaxMessageSize) - throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {DiscordConfig.MaxMessageSize} characters or less."); - return Task.FromResult(_channel.Client.MessageQueue.QueueSend(_channel, text, isTTS)); - } - public async Task SendFile(string filePath) - { - using (var stream = File.OpenRead(filePath)) - return await SendFile(Path.GetFileName(filePath), stream).ConfigureAwait(false); - } - public async Task SendFile(string filename, Stream stream) - { - var request = new SendFileRequest(_channel.Id) - { - Filename = filename, - Stream = stream - }; - var response = await _channel.Client.ClientAPI.Send(request).ConfigureAwait(false); - - return Add(response, (_channel as Channel).CurrentUser); - } - - public IEnumerator GetEnumerator() - { - return _orderedMessages - .Select(x => - { - Message msg; - if (_messages.TryGetValue(x, out msg)) - return msg; - return null; - }) - .Where(x => x != null).GetEnumerator(); - } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } -} diff --git a/src/Discord.Net/Entities/Managers/PermissionManager.cs b/src/Discord.Net/Entities/Managers/PermissionManager.cs deleted file mode 100644 index 4b8eb5c8c..000000000 --- a/src/Discord.Net/Entities/Managers/PermissionManager.cs +++ /dev/null @@ -1,223 +0,0 @@ -using Discord.API.Client.Rest; -using Discord.Net; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using APIChannel = Discord.API.Client.Channel; - -namespace Discord -{ - internal class PermissionManager - { - public struct Member - { - public User User { get; } - public ChannelPermissions Permissions { get; } - - public Member(User user, ChannelPermissions permissions) - { - User = user; - Permissions = permissions; - } - } - - private readonly PublicChannel _channel; - private readonly ConcurrentDictionary _users; - private Dictionary _rules; - - public IEnumerable Users => _users.Select(x => x.Value); - public IEnumerable Rules => _rules.Values; - - public PermissionManager(PublicChannel channel, APIChannel model, int initialSize = -1) - { - _channel = channel; - if (initialSize >= 0) - _users = new ConcurrentDictionary(2, initialSize); - Update(model); - } - - public void Update(APIChannel model) - { - _rules = model.PermissionOverwrites - .Select(x => new Channel.PermissionRule(EnumConverters.ToPermissionTarget(x.Type), x.Id, x.Allow, x.Deny)) - .ToDictionary(x => x.TargetId); - UpdatePermissions(); - } - - public ChannelTriStatePermissions? GetOverwrite(User user) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - Channel.PermissionRule rule; - if (_rules.TryGetValue(user.Id, out rule)) - return rule.Permissions; - return null; - } - public ChannelTriStatePermissions? GetOverwrite(Role role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - - Channel.PermissionRule rule; - if (_rules.TryGetValue(role.Id, out rule)) - return rule.Permissions; - return null; - } - public Task AddOrUpdateOverwrite(User user, ChannelTriStatePermissions permissions) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - return AddOrUpdateOverwrite(user.Id, PermissionTarget.User, permissions); - } - public Task AddOrUpdateOverwrite(Role role, ChannelTriStatePermissions permissions) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - return AddOrUpdateOverwrite(role.Id, PermissionTarget.Role, permissions); - } - private Task AddOrUpdateOverwrite(ulong id, PermissionTarget type, ChannelTriStatePermissions permissions) - { - var request = new AddOrUpdateChannelPermissionsRequest(id) - { - TargetId = id, - TargetType = EnumConverters.ToString(type), - Allow = permissions.AllowValue, - Deny = permissions.DenyValue - }; - return _channel.Client.ClientAPI.Send(request); - } - public Task RemoveOverwrite(User user) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - return RemoveOverwrite(user.Id); - } - public Task RemoveOverwrite(Role role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - return RemoveOverwrite(role.Id); - } - private async Task RemoveOverwrite(ulong id) - { - try { await _channel.Client.ClientAPI.Send(new RemoveChannelPermissionsRequest(_channel.Id, id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - - public ChannelPermissions GetPermissions(User user) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - if (_users != null) - { - Member member; - if (_users.TryGetValue(user.Id, out member)) - return member.Permissions; - else - return ChannelPermissions.None; - } - else - { - ChannelPermissions perms = new ChannelPermissions(); - ResolvePermissions(user, ref perms); - return perms; - } - } - public void UpdatePermissions() - { - if (_users != null) - { - foreach (var pair in _users) - { - var member = pair.Value; - var perms = member.Permissions; - if (ResolvePermissions(member.User, ref perms)) - _users[pair.Key] = new Member(member.User, perms); - } - } - } - public void UpdatePermissions(User user) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - if (_users != null) - { - Member member; - if (_users.TryGetValue(user.Id, out member)) - { - var perms = member.Permissions; - if (ResolvePermissions(member.User, ref perms)) - _users[user.Id] = new Member(member.User, perms); - } - } - } - public bool ResolvePermissions(User user, ref ChannelPermissions permissions) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - uint newPermissions = 0; - var server = user.Server; - - var mask = ChannelPermissions.All(_channel.Type).RawValue; - if (_channel.IsPrivate || user.IsOwner) - newPermissions = mask; //Private messages and owners always have all permissions - else - { - //Start with this user's server permissions - newPermissions = server.GetPermissions(user).RawValue; - var rules = _rules; - - Channel.PermissionRule rule; - var roles = user.Roles.ToArray(); - if (roles.Length > 0) - { - for (int i = 0; i < roles.Length; i++) - { - if (rules.TryGetValue(roles[i].Id, out rule)) - newPermissions &= ~rule.Permissions.DenyValue; - } - for (int i = 0; i < roles.Length; i++) - { - if (rules.TryGetValue(roles[i].Id, out rule)) - newPermissions |= rule.Permissions.AllowValue; - } - } - if (rules.TryGetValue(user.Id, out rule)) - newPermissions = (newPermissions & ~rule.Permissions.DenyValue) | rule.Permissions.AllowValue; - - if (newPermissions.HasBit((byte)PermissionBits.ManageRolesOrPermissions)) - newPermissions = mask; //ManageRolesOrPermissions gives all permisions - else if (_channel.IsText && !newPermissions.HasBit((byte)PermissionBits.ReadMessages)) - newPermissions = 0; //No read permission on a text channel removes all other permissions - else if (_channel.IsVoice && !newPermissions.HasBit((byte)PermissionBits.Connect)) - newPermissions = 0; //No connect permissions on a voice channel removes all other permissions - else - newPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from serverPerms, for example) - } - - if (newPermissions != permissions.RawValue) - { - permissions = new ChannelPermissions(newPermissions); - return true; - } - return false; - } - - public void AddUser(User user) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - if (_users != null) - { - var perms = new ChannelPermissions(); - ResolvePermissions(user, ref perms); - var member = new Member(user, ChannelPermissions.None); - _users[user.Id] = new Member(user, ChannelPermissions.None); - } - } - public void RemoveUser(ulong id) - { - Member ignored; - if (_users != null) - _users.TryRemove(id, out ignored); - } - } -} diff --git a/src/Discord.Net/Entities/Message.cs b/src/Discord.Net/Entities/Message.cs index a812cd897..7e255ddf7 100644 --- a/src/Discord.Net/Entities/Message.cs +++ b/src/Discord.Net/Entities/Message.cs @@ -1,327 +1,116 @@ -using System; +using Discord.API.Rest; +using Discord.Net; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; +using System.Collections.Immutable; +using System.Net; using System.Threading.Tasks; -using APIMessage = Discord.API.Client.Message; +using Model = Discord.API.Message; namespace Discord { - public class Message + public class Message : IEntity { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - private static readonly Regex _userRegex = new Regex(@"<@[0-9]+>"); - private static readonly Regex _channelRegex = new Regex(@"<#[0-9]+>"); - private static readonly Regex _roleRegex = new Regex(@"@everyone"); - private static readonly Attachment[] _initialAttachments = new Attachment[0]; - private static readonly Embed[] _initialEmbeds = new Embed[0]; - - internal static string CleanUserMentions(PublicChannel channel, string text, List users = null) - { - return _userRegex.Replace(text, new MatchEvaluator(e => - { - ulong id; - if (e.Value.Substring(2, e.Value.Length - 3).TryToId(out id)) - { - var user = channel.GetUser(id); - if (user != null) - { - if (users != null) - users.Add(user); - return '@' + user.Name; - } - } - return e.Value; //User not found or parse failed - })); - } - internal static string CleanChannelMentions(PublicChannel channel, string text, List channels = null) - { - var server = channel.Server; - if (server == null) return text; - - return _channelRegex.Replace(text, new MatchEvaluator(e => - { - ulong id; - if (e.Value.Substring(2, e.Value.Length - 3).TryToId(out id)) - { - var mentionedChannel = server.GetChannel(id); - if (mentionedChannel != null && mentionedChannel.Server.Id == server.Id) - { - if (channels != null) - channels.Add(mentionedChannel); - return '#' + mentionedChannel.Name; - } - } - return e.Value; //Channel not found or parse failed - })); - } - /*internal static string CleanRoleMentions(User user, Channel channel, string text, List roles = null) - { - var server = channel.Server; - if (server == null) return text; - - return _roleRegex.Replace(text, new MatchEvaluator(e => - { - if (roles != null && user.GetPermissions(channel).MentionEveryone) - roles.Add(server.EveryoneRole); - return e.Value; - })); - }*/ - - internal static string ResolveMentions(IChannel channel, string text) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - if (text == null) throw new ArgumentNullException(nameof(text)); - - var publicChannel = channel as PublicChannel; - if (publicChannel != null) - { - text = CleanUserMentions(publicChannel, text); - text = CleanChannelMentions(publicChannel, text); - //text = CleanRoleMentions(publicChannel, text); - } - return text; - } - - public class Attachment : File - { - /// Unique identifier for this file. - public string Id { get; internal set; } - /// Size, in bytes, of this file file. - public int Size { get; internal set; } - /// Filename of this file. - public string Filename { get; internal set; } - - internal Attachment() { } - } - - public class Embed - { - /// URL of this embed. - public string Url { get; internal set; } - /// Type of this embed. - public string Type { get; internal set; } - /// Title for this embed. - public string Title { get; internal set; } - /// Summary of this embed. - public string Description { get; internal set; } - /// Returns information about the author of this embed. - public EmbedLink Author { get; internal set; } - /// Returns information about the providing website of this embed. - public EmbedLink Provider { get; internal set; } - /// Returns the thumbnail of this embed. - public File Thumbnail { get; internal set; } - /// Returns the video information of this embed. - public File Video { get; internal set; } - - internal Embed() { } - } - - public class EmbedLink - { - /// URL of this embed provider. - public string Url { get; internal set; } - /// Name of this embed provider. - public string Name { get; internal set; } - - internal EmbedLink() { } - } - - public class File - { - /// Download url for this file. - public string Url { get; internal set; } - /// Preview url for this file. - public string ProxyUrl { get; internal set; } - /// Width of this file, if it is an image. - public int? Width { get; internal set; } - /// Height of this file, if it is an image. - public int? Height { get; internal set; } - - internal File() { } - } - - public DiscordClient Client => Channel.Client; - - /// Returns the unique identifier for this message. - public ulong Id { get; internal set; } - /// Returns the channel this message was sent to. - public ITextChannel Channel { get; } - /// Returns the author of this message. + /// + public ulong Id { get; } + public IMessageChannel Channel { get; } public User User { get; } - /// Returns true if the message was sent as text-to-speech by someone with permissions to do so. public bool IsTTS { get; internal set; } - /// Returns the state of this message. Only useful if UseMessageQueue is true. - public MessageState State { get; internal set; } - /// Returns the raw content of this message as it was received from the server. - public string RawText { get; internal set; } - /// Returns the content of this message with any special references such as mentions converted. - public string Text { get; internal set; } - /// Returns the timestamp for when this message was sent. - public DateTime Timestamp { get; private set; } - /// Returns the timestamp for when this message was last edited. - public DateTime? EditedTimestamp { get; private set; } - /// Returns the attachments included in this message. - public Attachment[] Attachments { get; private set; } - /// Returns a collection of all embeded content in this message. - public Embed[] Embeds { get; private set; } - - /// Returns a collection of all users mentioned in this message. - public IEnumerable MentionedUsers { get; internal set; } - /// Returns a collection of all channels mentioned in this message. - public IEnumerable MentionedChannels { get; internal set; } - /// Returns a collection of all roles mentioned in this message. - public IEnumerable MentionedRoles { get; internal set; } - + public string RawText { get; internal set; } + public string Text { get; internal set; } + public DateTime Timestamp { get; internal set; } + public DateTime? EditedTimestamp { get; private set; } + public IReadOnlyList Attachments { get; private set; } + public IReadOnlyList Embeds { get; private set; } + public IReadOnlyList MentionedUsers { get; private set; } + public IReadOnlyList MentionedChannels { get; private set; } + public IReadOnlyList MentionedRoles { get; private set; } internal int Nonce { get; set; } - /// Returns the server containing the channel this message was sent to. - public Server Server => (Channel as PublicChannel)?.Server; - /// Returns if this message was sent from the logged-in accounts. - public bool IsAuthor => User != null && User.Id == Client.CurrentUser?.Id; + public DiscordClient Discord => Channel.Discord; + public bool IsAuthor => false; - internal Message(APIMessage model, ITextChannel channel, User user) - : this(model.Id, channel, user) - { - Update(model); - } - internal Message(ulong id, ITextChannel channel, User user) + internal Message(ulong id, IMessageChannel channel, User user) { Id = id; Channel = channel; User = user; - Attachments = _initialAttachments; - Embeds = _initialEmbeds; } - internal void Update(APIMessage model) - { - var channel = Channel; - if (model.Attachments != null) - { - Attachments = model.Attachments - .Select(x => new Attachment() - { - Id = x.Id, - Url = x.Url, - ProxyUrl = x.ProxyUrl, - Width = x.Width, - Height = x.Height, - Size = x.Size, - Filename = x.Filename - }) - .ToArray(); - } - if (model.Embeds != null) - { - Embeds = model.Embeds.Select(x => - { - EmbedLink author = null, provider = null; - File thumbnail = null, video = null; + internal void Update(Model model) + { + var channel = Channel; + bool isPublic = channel.Type != ChannelType.DM; - if (x.Author != null) - author = new EmbedLink { Url = x.Author.Url, Name = x.Author.Name }; - if (x.Provider != null) - provider = new EmbedLink { Url = x.Provider.Url, Name = x.Provider.Name }; - if (x.Thumbnail != null) - thumbnail = new File { Url = x.Thumbnail.Url, ProxyUrl = x.Thumbnail.ProxyUrl, Width = x.Thumbnail.Width, Height = x.Thumbnail.Height }; - if (x.Video != null) - video = new File { Url = x.Video.Url, ProxyUrl = null, Width = x.Video.Width, Height = x.Video.Height }; + IsTTS = model.IsTextToSpeech; + Timestamp = model.Timestamp; + EditedTimestamp = model.EditedTimestamp; + RawText = model.Content; - return new Embed - { - Url = x.Url, - Type = x.Type, - Title = x.Title, - Description = x.Description, - Author = author, - Provider = provider, - Thumbnail = thumbnail, - Video = video - }; - }).ToArray(); - } - - if (model.IsTextToSpeech != null) - IsTTS = model.IsTextToSpeech.Value; - if (model.Timestamp != null) - Timestamp = model.Timestamp.Value; - if (model.EditedTimestamp != null) - EditedTimestamp = model.EditedTimestamp; - if (model.Mentions != null) - { - MentionedUsers = model.Mentions - .Select(x => (Channel as Channel).GetUser(x.Id)) - .Where(x => x != null) - .ToArray(); - } - if (model.IsMentioningEveryone != null) + if (model.Attachments.Length > 0) { - var server = (channel as PublicChannel).Server; - if (model.IsMentioningEveryone.Value && server != null) - MentionedRoles = new Role[] { server.EveryoneRole }; - else - MentionedRoles = Enumerable.Empty(); + var attachments = new Attachment[model.Attachments.Length]; + for (int i = 0; i < attachments.Length; i++) + attachments[i] = new Attachment(model.Attachments[i]); + Attachments = ImmutableArray.Create(attachments); } - if (model.Content != null) - { - string text = model.Content; - RawText = text; - - List mentionedChannels = null; - if (Channel.IsPublic) - mentionedChannels = new List(); - - text = CleanUserMentions(Channel as PublicChannel, text); - text = CleanChannelMentions(Channel as PublicChannel, text, mentionedChannels); - - if (Channel.IsPublic) - MentionedChannels = mentionedChannels; - - Text = text; - } - } + else + Attachments = ImmutableArray.Empty; - public Task Edit(string text) - { - if (text == null) throw new ArgumentNullException(nameof(text)); + if (model.Embeds.Length > 0) + { + var embeds = new Embed[model.Attachments.Length]; + for (int i = 0; i < embeds.Length; i++) + embeds[i] = new Embed(model.Embeds[i]); + Embeds = ImmutableArray.Create(embeds); + } + else + Embeds = ImmutableArray.Empty; - var channel = Channel; + if (model.Mentions.Length > 0) + { + var users = new GuildUser[model.Mentions.Length]; + int j = 0; + for (int i = 0; i < users.Length; i++) + { + var user = Channel.GetUser(model.Mentions[i].Id) as GuildUser; + if (user != null) + users[j++] = user; + } + MentionedUsers = ImmutableArray.Create(users, 0, j); + } + else + MentionedUsers = ImmutableArray.Empty; - if (text.Length > DiscordConfig.MaxMessageSize) - throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {DiscordConfig.MaxMessageSize} characters or less."); - - Client.MessageQueue.QueueEdit(this, text); - return TaskHelper.CompletedTask; - } - public Task Delete() - { - Client.MessageQueue.QueueDelete(this); - return TaskHelper.CompletedTask; - } + if (model.IsMentioningEveryone && isPublic) + MentionedRoles = ImmutableArray.Create((channel as GuildChannel).Guild.EveryoneRole); + else + MentionedRoles = ImmutableArray.Empty; - /// Returns true if the logged-in user was mentioned. - public bool IsMentioningMe(bool includeRoles = false) - { - User me = Server != null ? Server.CurrentUser : Channel.Client.PrivateUser; - if (includeRoles) + string text = model.Content; + if (isPublic) { - return (MentionedUsers?.Contains(me) ?? false) || - (MentionedRoles?.Any(x => me.HasRole(x)) ?? false); + var publicChannel = channel as GuildChannel; + var mentionedChannels = ImmutableArray.CreateBuilder(); + text = MentionHelper.CleanUserMentions(publicChannel, text); + text = MentionHelper.CleanChannelMentions(publicChannel, text, mentionedChannels); + MentionedChannels = mentionedChannels.ToImmutable(); } else - return MentionedUsers?.Contains(me) ?? false; + MentionedChannels = ImmutableArray.Empty; + Text = text; } - internal Message Clone() + public bool IsMentioningMe(bool includeRoles = false) => false; + + public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet + + /// Deletes this message. + public async Task Delete() { - var result = new Message(Id, Channel, User); - _cloner(this, result); - return result; + try { await Discord.RestClient.Send(new DeleteMessageRequest(Channel.Id, Id)).ConfigureAwait(false); } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } } - - public override string ToString() => $"{User}: {RawText}"; - } + } } diff --git a/src/Discord.Net/Entities/Permissions.cs b/src/Discord.Net/Entities/Permissions.cs deleted file mode 100644 index badccc116..000000000 --- a/src/Discord.Net/Entities/Permissions.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Discord -{ - public struct ServerPermissions - { - public static ServerPermissions None { get; } = new ServerPermissions(); - public static ServerPermissions All { get; } = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); - - public uint RawValue { get; } - - /// If True, a user may create invites. - public bool CreateInstantInvite => PermissionsHelper.GetValue(RawValue, PermissionBits.CreateInstantInvite); - /// If True, a user may ban users from the server. - public bool BanMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.BanMembers); - /// If True, a user may kick users from the server. - public bool KickMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.KickMembers); - /// If True, a user may adjust roles. This also implictly grants all other permissions. - public bool ManageRoles => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageRolesOrPermissions); - /// If True, a user may create, delete and modify channels. - public bool ManageChannels => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageChannel); - /// If True, a user may adjust server properties. - public bool ManageServer => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageServer); - - /// If True, a user may join channels. - public bool ReadMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.ReadMessages); - /// If True, a user may send messages. - public bool SendMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.SendMessages); - /// If True, a user may send text-to-speech messages. - public bool SendTTSMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.SendTTSMessages); - /// If True, a user may delete messages. - public bool ManageMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageMessages); - /// If True, Discord will auto-embed links sent by this user. - public bool EmbedLinks => PermissionsHelper.GetValue(RawValue, PermissionBits.EmbedLinks); - /// If True, a user may send files. - public bool AttachFiles => PermissionsHelper.GetValue(RawValue, PermissionBits.AttachFiles); - /// If True, a user may read previous messages. - public bool ReadMessageHistory => PermissionsHelper.GetValue(RawValue, PermissionBits.ReadMessageHistory); - /// If True, a user may mention @everyone. - public bool MentionEveryone => PermissionsHelper.GetValue(RawValue, PermissionBits.MentionEveryone); - - /// If True, a user may connect to a voice channel. - public bool Connect => PermissionsHelper.GetValue(RawValue, PermissionBits.Connect); - /// If True, a user may speak in a voice channel. - public bool Speak => PermissionsHelper.GetValue(RawValue, PermissionBits.Speak); - /// If True, a user may mute users. - public bool MuteMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.MuteMembers); - /// If True, a user may deafen users. - public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.DeafenMembers); - /// If True, a user may move other users between voice channels. - public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBits.UseVoiceActivation); - - public ServerPermissions(bool? createInstantInvite = null, bool? manageRoles = null, - bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageServer = null, - bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, - bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, - bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - : this(new ServerPermissions(), createInstantInvite, manageRoles, kickMembers, banMembers, manageChannel, manageServer, readMessages, - sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, - moveMembers, useVoiceActivation) - { - } - public ServerPermissions(ServerPermissions basePerms, bool? createInstantInvite = null, bool? manageRoles = null, - bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageServer = null, - bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, - bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, - bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - { - uint value = basePerms.RawValue; - - PermissionsHelper.SetValue(ref value, createInstantInvite, PermissionBits.CreateInstantInvite); - PermissionsHelper.SetValue(ref value, banMembers, PermissionBits.BanMembers); - PermissionsHelper.SetValue(ref value, kickMembers, PermissionBits.KickMembers); - PermissionsHelper.SetValue(ref value, manageRoles, PermissionBits.ManageRolesOrPermissions); - PermissionsHelper.SetValue(ref value, manageChannel, PermissionBits.ManageChannel); - PermissionsHelper.SetValue(ref value, manageServer, PermissionBits.ManageServer); - PermissionsHelper.SetValue(ref value, readMessages, PermissionBits.ReadMessages); - PermissionsHelper.SetValue(ref value, sendMessages, PermissionBits.SendMessages); - PermissionsHelper.SetValue(ref value, sendTTSMessages, PermissionBits.SendTTSMessages); - PermissionsHelper.SetValue(ref value, manageMessages, PermissionBits.ManageMessages); - PermissionsHelper.SetValue(ref value, embedLinks, PermissionBits.EmbedLinks); - PermissionsHelper.SetValue(ref value, attachFiles, PermissionBits.AttachFiles); - PermissionsHelper.SetValue(ref value, readMessageHistory, PermissionBits.ReadMessageHistory); - PermissionsHelper.SetValue(ref value, mentionEveryone, PermissionBits.MentionEveryone); - PermissionsHelper.SetValue(ref value, connect, PermissionBits.Connect); - PermissionsHelper.SetValue(ref value, speak, PermissionBits.Speak); - PermissionsHelper.SetValue(ref value, muteMembers, PermissionBits.MuteMembers); - PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBits.DeafenMembers); - PermissionsHelper.SetValue(ref value, moveMembers, PermissionBits.MoveMembers); - PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBits.UseVoiceActivation); - - RawValue = value; - } - public ServerPermissions(uint rawValue) { RawValue = rawValue; } - - public override string ToString() => Convert.ToString(RawValue, 2); - } - - public struct ChannelPermissions - { - public static ChannelPermissions None { get; } = new ChannelPermissions(); - public static ChannelPermissions TextOnly { get; } = new ChannelPermissions(Convert.ToUInt32("00000000000000111111110000011001", 2)); - public static ChannelPermissions PrivateOnly { get; } = new ChannelPermissions(Convert.ToUInt32("00000000000000011100110000000000", 2)); - public static ChannelPermissions VoiceOnly { get; } = new ChannelPermissions(Convert.ToUInt32("00000011111100000000000000011001", 2)); - public static ChannelPermissions All(ChannelType channelType) - { - switch (channelType) - { - case ChannelType.Text: return TextOnly; - case ChannelType.Voice: return VoiceOnly; - case ChannelType.Private: return PrivateOnly; - default: return None; - } - } - - public uint RawValue { get; } - - /// If True, a user may create invites. - public bool CreateInstantInvite => PermissionsHelper.GetValue(RawValue, PermissionBits.CreateInstantInvite); - /// If True, a user may adjust permissions. This also implictly grants all other permissions. - public bool ManagePermissions => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageRolesOrPermissions); - /// If True, a user may create, delete and modify this channel. - public bool ManageChannel => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageChannel); - - /// If True, a user may join channels. - public bool ReadMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.ReadMessages); - /// If True, a user may send messages. - public bool SendMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.SendMessages); - /// If True, a user may send text-to-speech messages. - public bool SendTTSMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.SendTTSMessages); - /// If True, a user may delete messages. - public bool ManageMessages => PermissionsHelper.GetValue(RawValue, PermissionBits.ManageMessages); - /// If True, Discord will auto-embed links sent by this user. - public bool EmbedLinks => PermissionsHelper.GetValue(RawValue, PermissionBits.EmbedLinks); - /// If True, a user may send files. - public bool AttachFiles => PermissionsHelper.GetValue(RawValue, PermissionBits.AttachFiles); - /// If True, a user may read previous messages. - public bool ReadMessageHistory => PermissionsHelper.GetValue(RawValue, PermissionBits.ReadMessageHistory); - /// If True, a user may mention @everyone. - public bool MentionEveryone => PermissionsHelper.GetValue(RawValue, PermissionBits.MentionEveryone); - - /// If True, a user may connect to a voice channel. - public bool Connect => PermissionsHelper.GetValue(RawValue, PermissionBits.Connect); - /// If True, a user may speak in a voice channel. - public bool Speak => PermissionsHelper.GetValue(RawValue, PermissionBits.Speak); - /// If True, a user may mute users. - public bool MuteMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.MuteMembers); - /// If True, a user may deafen users. - public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.DeafenMembers); - /// If True, a user may move other users between voice channels. - public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBits.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBits.UseVoiceActivation); - - public ChannelPermissions(bool? createInstantInvite = null, bool? managePermissions = null, - bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, - bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, - bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - : this(new ChannelPermissions(), createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, - manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation) - { - } - public ChannelPermissions(ChannelPermissions basePerms, bool? createInstantInvite = null, bool? managePermissions = null, - bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, - bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, - bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, - bool? moveMembers = null, bool? useVoiceActivation = null) - { - uint value = basePerms.RawValue; - - PermissionsHelper.SetValue(ref value, createInstantInvite, PermissionBits.CreateInstantInvite); - PermissionsHelper.SetValue(ref value, managePermissions, PermissionBits.ManageRolesOrPermissions); - PermissionsHelper.SetValue(ref value, manageChannel, PermissionBits.ManageChannel); - PermissionsHelper.SetValue(ref value, readMessages, PermissionBits.ReadMessages); - PermissionsHelper.SetValue(ref value, sendMessages, PermissionBits.SendMessages); - PermissionsHelper.SetValue(ref value, sendTTSMessages, PermissionBits.SendTTSMessages); - PermissionsHelper.SetValue(ref value, manageMessages, PermissionBits.ManageMessages); - PermissionsHelper.SetValue(ref value, embedLinks, PermissionBits.EmbedLinks); - PermissionsHelper.SetValue(ref value, attachFiles, PermissionBits.AttachFiles); - PermissionsHelper.SetValue(ref value, readMessageHistory, PermissionBits.ReadMessageHistory); - PermissionsHelper.SetValue(ref value, mentionEveryone, PermissionBits.MentionEveryone); - PermissionsHelper.SetValue(ref value, connect, PermissionBits.Connect); - PermissionsHelper.SetValue(ref value, speak, PermissionBits.Speak); - PermissionsHelper.SetValue(ref value, muteMembers, PermissionBits.MuteMembers); - PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBits.DeafenMembers); - PermissionsHelper.SetValue(ref value, moveMembers, PermissionBits.MoveMembers); - PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBits.UseVoiceActivation); - - RawValue = value; - } - public ChannelPermissions(uint rawValue) { RawValue = rawValue; } - - public override string ToString() => Convert.ToString(RawValue, 2); - } - - public struct ChannelTriStatePermissions - { - public static ChannelTriStatePermissions InheritAll { get; } = new ChannelTriStatePermissions(); - - public uint AllowValue { get; } - public uint DenyValue { get; } - - /// If True, a user may create invites. - public PermValue CreateInstantInvite => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.CreateInstantInvite); - /// If True, a user may adjust permissions. This also implictly grants all other permissions. - public PermValue ManagePermissions => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.ManageRolesOrPermissions); - /// If True, a user may create, delete and modify this channel. - public PermValue ManageChannel => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.ManageChannel); - /// If True, a user may join channels. - public PermValue ReadMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.ReadMessages); - /// If True, a user may send messages. - public PermValue SendMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.SendMessages); - /// If True, a user may send text-to-speech messages. - public PermValue SendTTSMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.SendTTSMessages); - /// If True, a user may delete messages. - public PermValue ManageMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.ManageMessages); - /// If True, Discord will auto-embed links sent by this user. - public PermValue EmbedLinks => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.EmbedLinks); - /// If True, a user may send files. - public PermValue AttachFiles => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.AttachFiles); - /// If True, a user may read previous messages. - public PermValue ReadMessageHistory => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.ReadMessageHistory); - /// If True, a user may mention @everyone. - public PermValue MentionEveryone => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.MentionEveryone); - - /// If True, a user may connect to a voice channel. - public PermValue Connect => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.Connect); - /// If True, a user may speak in a voice channel. - public PermValue Speak => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.Speak); - /// If True, a user may mute users. - public PermValue MuteMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.MuteMembers); - /// If True, a user may deafen users. - public PermValue DeafenMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.DeafenMembers); - /// If True, a user may move other users between voice channels. - public PermValue MoveMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.MoveMembers); - /// If True, a user may use voice activation rather than push-to-talk. - public PermValue UseVoiceActivation => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBits.UseVoiceActivation); - - public ChannelTriStatePermissions(PermValue? createInstantInvite = null, PermValue? managePermissions = null, - PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, - PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, - PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, - PermValue? moveMembers = null, PermValue? useVoiceActivation = null) - : this(new ChannelTriStatePermissions(), createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, - manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation) - { - } - public ChannelTriStatePermissions(ChannelTriStatePermissions basePerms, PermValue? createInstantInvite = null, PermValue? managePermissions = null, - PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, - PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, - PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, - PermValue? moveMembers = null, PermValue? useVoiceActivation = null) - { - uint allow = basePerms.AllowValue, deny = basePerms.DenyValue; - - PermissionsHelper.SetValue(ref allow, ref deny, createInstantInvite, PermissionBits.CreateInstantInvite); - PermissionsHelper.SetValue(ref allow, ref deny, managePermissions, PermissionBits.ManageRolesOrPermissions); - PermissionsHelper.SetValue(ref allow, ref deny, manageChannel, PermissionBits.ManageChannel); - PermissionsHelper.SetValue(ref allow, ref deny, readMessages, PermissionBits.ReadMessages); - PermissionsHelper.SetValue(ref allow, ref deny, sendMessages, PermissionBits.SendMessages); - PermissionsHelper.SetValue(ref allow, ref deny, sendTTSMessages, PermissionBits.SendTTSMessages); - PermissionsHelper.SetValue(ref allow, ref deny, manageMessages, PermissionBits.ManageMessages); - PermissionsHelper.SetValue(ref allow, ref deny, embedLinks, PermissionBits.EmbedLinks); - PermissionsHelper.SetValue(ref allow, ref deny, attachFiles, PermissionBits.AttachFiles); - PermissionsHelper.SetValue(ref allow, ref deny, readMessageHistory, PermissionBits.ReadMessageHistory); - PermissionsHelper.SetValue(ref allow, ref deny, mentionEveryone, PermissionBits.MentionEveryone); - PermissionsHelper.SetValue(ref allow, ref deny, connect, PermissionBits.Connect); - PermissionsHelper.SetValue(ref allow, ref deny, speak, PermissionBits.Speak); - PermissionsHelper.SetValue(ref allow, ref deny, muteMembers, PermissionBits.MuteMembers); - PermissionsHelper.SetValue(ref allow, ref deny, deafenMembers, PermissionBits.DeafenMembers); - PermissionsHelper.SetValue(ref allow, ref deny, moveMembers, PermissionBits.MoveMembers); - PermissionsHelper.SetValue(ref allow, ref deny, useVoiceActivation, PermissionBits.UseVoiceActivation); - - AllowValue = allow; - DenyValue = deny; - } - public ChannelTriStatePermissions(uint allow = 0, uint deny = 0) - { - AllowValue = allow; - DenyValue = deny; - } - - public override string ToString() => $"Allow: {Convert.ToString(AllowValue, 2)}, Deny: {Convert.ToString(DenyValue, 2)}"; - } - internal static class PermissionsHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PermValue GetValue(uint allow, uint deny, PermissionBits bit) - { - if (allow.HasBit((byte)bit)) - return PermValue.Allow; - else if (deny.HasBit((byte)bit)) - return PermValue.Deny; - else - return PermValue.Inherit; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool GetValue(uint value, PermissionBits bit) => value.HasBit((byte)bit); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetValue(ref uint rawValue, bool? value, PermissionBits bit) - { - if (value.HasValue) - { - if (value == true) - SetBit(ref rawValue, bit); - else - UnsetBit(ref rawValue, bit); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetValue(ref uint allow, ref uint deny, PermValue? value, PermissionBits bit) - { - if (value.HasValue) - { - switch (value) - { - case PermValue.Allow: - SetBit(ref allow, bit); - UnsetBit(ref deny, bit); - break; - case PermValue.Deny: - UnsetBit(ref allow, bit); - SetBit(ref deny, bit); - break; - default: - UnsetBit(ref allow, bit); - UnsetBit(ref deny, bit); - break; - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SetBit(ref uint value, PermissionBits bit) => value |= 1U << (int)bit; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void UnsetBit(ref uint value, PermissionBits bit) => value &= ~(1U << (int)bit); - } -} diff --git a/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs new file mode 100644 index 000000000..7b37fccd0 --- /dev/null +++ b/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs @@ -0,0 +1,122 @@ +using System; + +namespace Discord +{ + public struct ChannelPermissions + { + private static ChannelPermissions _allDM { get; } = new ChannelPermissions(Convert.ToUInt32("00000000000000111111110000011001", 2)); + private static ChannelPermissions _allText { get; } = new ChannelPermissions(Convert.ToUInt32("00000000000000011100110000000000", 2)); + private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(Convert.ToUInt32("00000011111100000000000000011001", 2)); + + /// Gets a blank ChannelPermissions that grants no permissions. + public static ChannelPermissions None { get; } = new ChannelPermissions(); + /// Gets a ChannelPermissions that grants all permissions for a given channelType. + public static ChannelPermissions All(ChannelType channelType) + { + switch (channelType) + { + case ChannelType.DM: + return _allText; + case ChannelType.Text: + return _allDM; + case ChannelType.Voice: + return _allVoice; + default: + throw new ArgumentOutOfRangeException(nameof(channelType)); + } + } + + /// Gets a packed value representing all the permissions in this ChannelPermissions. + public uint RawValue { get; } + + /// If True, a user may create invites. + public bool CreateInstantInvite => PermissionsHelper.GetValue(RawValue, PermissionBit.CreateInstantInvite); + /// If True, a user may adjust permissions. This also implictly grants all other permissions. + public bool ManagePermissions => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageRolesOrPermissions); + /// If True, a user may create, delete and modify this channel. + public bool ManageChannel => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageChannel); + + /// If True, a user may join channels. + public bool ReadMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.ReadMessages); + /// If True, a user may send messages. + public bool SendMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.SendMessages); + /// If True, a user may send text-to-speech messages. + public bool SendTTSMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.SendTTSMessages); + /// If True, a user may delete messages. + public bool ManageMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public bool EmbedLinks => PermissionsHelper.GetValue(RawValue, PermissionBit.EmbedLinks); + /// If True, a user may send files. + public bool AttachFiles => PermissionsHelper.GetValue(RawValue, PermissionBit.AttachFiles); + /// If True, a user may read previous messages. + public bool ReadMessageHistory => PermissionsHelper.GetValue(RawValue, PermissionBit.ReadMessageHistory); + /// If True, a user may mention @everyone. + public bool MentionEveryone => PermissionsHelper.GetValue(RawValue, PermissionBit.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public bool Connect => PermissionsHelper.GetValue(RawValue, PermissionBit.Connect); + /// If True, a user may speak in a voice channel. + public bool Speak => PermissionsHelper.GetValue(RawValue, PermissionBit.Speak); + /// If True, a user may mute users. + public bool MuteMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MuteMembers); + /// If True, a user may deafen users. + public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.DeafenMembers); + /// If True, a user may move other users between voice channels. + public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MoveMembers); + /// If True, a user may use voice activation rather than push-to-talk. + public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVoiceActivation); + + /// Creates a new ChannelPermissions with the provided packed value. + public ChannelPermissions(uint rawValue) { RawValue = rawValue; } + + private ChannelPermissions(uint initialValue, bool? createInstantInvite = null, bool? managePermissions = null, + bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, + bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, + bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, + bool? moveMembers = null, bool? useVoiceActivation = null) + { + uint value = initialValue; + + PermissionsHelper.SetValue(ref value, createInstantInvite, PermissionBit.CreateInstantInvite); + PermissionsHelper.SetValue(ref value, managePermissions, PermissionBit.ManageRolesOrPermissions); + PermissionsHelper.SetValue(ref value, manageChannel, PermissionBit.ManageChannel); + PermissionsHelper.SetValue(ref value, readMessages, PermissionBit.ReadMessages); + PermissionsHelper.SetValue(ref value, sendMessages, PermissionBit.SendMessages); + PermissionsHelper.SetValue(ref value, sendTTSMessages, PermissionBit.SendTTSMessages); + PermissionsHelper.SetValue(ref value, manageMessages, PermissionBit.ManageMessages); + PermissionsHelper.SetValue(ref value, embedLinks, PermissionBit.EmbedLinks); + PermissionsHelper.SetValue(ref value, attachFiles, PermissionBit.AttachFiles); + PermissionsHelper.SetValue(ref value, readMessageHistory, PermissionBit.ReadMessageHistory); + PermissionsHelper.SetValue(ref value, mentionEveryone, PermissionBit.MentionEveryone); + PermissionsHelper.SetValue(ref value, connect, PermissionBit.Connect); + PermissionsHelper.SetValue(ref value, speak, PermissionBit.Speak); + PermissionsHelper.SetValue(ref value, muteMembers, PermissionBit.MuteMembers); + PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBit.DeafenMembers); + PermissionsHelper.SetValue(ref value, moveMembers, PermissionBit.MoveMembers); + PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVoiceActivation); + + RawValue = value; + } + + /// Creates a new ChannelPermissions with the provided permissions. + public ChannelPermissions(bool createInstantInvite = false, bool managePermissions = false, + bool manageChannel = false, bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, + bool manageMessages = false, bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, + bool mentionEveryone = false, bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false, + bool moveMembers = false, bool useVoiceActivation = false) + : this(0, createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, + manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation) { } + + /// Creates a new ChannelPermissions from this one, changing the provided non-null permissions. + public ChannelPermissions Modify(bool? createInstantInvite = null, bool? managePermissions = null, + bool? manageChannel = null, bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, + bool? manageMessages = null, bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, + bool? mentionEveryone = null, bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, + bool? moveMembers = null, bool? useVoiceActivation = null) + => new ChannelPermissions(RawValue, createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, + manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation); + + /// + public override string ToString() => Convert.ToString(RawValue, 2); + } +} diff --git a/src/Discord.Net/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net/Entities/Permissions/GuildPermissions.cs new file mode 100644 index 000000000..7be0febe1 --- /dev/null +++ b/src/Discord.Net/Entities/Permissions/GuildPermissions.cs @@ -0,0 +1,119 @@ +using System; + +namespace Discord +{ + public struct GuildPermissions + { + /// Gets a blank GuildPermissions that grants no permissions. + public static GuildPermissions None { get; } = new GuildPermissions(); + /// Gets a GuildPermissions that grants all permissions. + public static GuildPermissions All { get; } = new GuildPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); + + /// Gets a packed value representing all the permissions in this GuildPermissions. + public uint RawValue { get; } + + /// If True, a user may create invites. + public bool CreateInstantInvite => PermissionsHelper.GetValue(RawValue, PermissionBit.CreateInstantInvite); + /// If True, a user may ban users from the guild. + public bool BanMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.BanMembers); + /// If True, a user may kick users from the guild. + public bool KickMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.KickMembers); + /// If True, a user may adjust roles. This also implictly grants all other permissions. + public bool ManageRoles => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageRolesOrPermissions); + /// If True, a user may create, delete and modify channels. + public bool ManageChannels => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageChannel); + /// If True, a user may adjust guild properties. + public bool ManageGuild => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageGuild); + + /// If True, a user may join channels. + public bool ReadMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.ReadMessages); + /// If True, a user may send messages. + public bool SendMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.SendMessages); + /// If True, a user may send text-to-speech messages. + public bool SendTTSMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.SendTTSMessages); + /// If True, a user may delete messages. + public bool ManageMessages => PermissionsHelper.GetValue(RawValue, PermissionBit.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public bool EmbedLinks => PermissionsHelper.GetValue(RawValue, PermissionBit.EmbedLinks); + /// If True, a user may send files. + public bool AttachFiles => PermissionsHelper.GetValue(RawValue, PermissionBit.AttachFiles); + /// If True, a user may read previous messages. + public bool ReadMessageHistory => PermissionsHelper.GetValue(RawValue, PermissionBit.ReadMessageHistory); + /// If True, a user may mention @everyone. + public bool MentionEveryone => PermissionsHelper.GetValue(RawValue, PermissionBit.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public bool Connect => PermissionsHelper.GetValue(RawValue, PermissionBit.Connect); + /// If True, a user may speak in a voice channel. + public bool Speak => PermissionsHelper.GetValue(RawValue, PermissionBit.Speak); + /// If True, a user may mute users. + public bool MuteMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MuteMembers); + /// If True, a user may deafen users. + public bool DeafenMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.DeafenMembers); + /// If True, a user may move other users between voice channels. + public bool MoveMembers => PermissionsHelper.GetValue(RawValue, PermissionBit.MoveMembers); + /// If True, a user may use voice activation rather than push-to-talk. + public bool UseVoiceActivation => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVoiceActivation); + + /// Creates a new GuildPermissions with the provided packed value. + public GuildPermissions(uint rawValue) { RawValue = rawValue; } + + private GuildPermissions(uint initialValue, bool? createInstantInvite = null, bool? manageRoles = null, + bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageGuild = null, + bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, + bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, + bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, + bool? moveMembers = null, bool? useVoiceActivation = null) + { + uint value = initialValue; + + PermissionsHelper.SetValue(ref value, createInstantInvite, PermissionBit.CreateInstantInvite); + PermissionsHelper.SetValue(ref value, banMembers, PermissionBit.BanMembers); + PermissionsHelper.SetValue(ref value, kickMembers, PermissionBit.KickMembers); + PermissionsHelper.SetValue(ref value, manageRoles, PermissionBit.ManageRolesOrPermissions); + PermissionsHelper.SetValue(ref value, manageChannel, PermissionBit.ManageChannel); + PermissionsHelper.SetValue(ref value, manageGuild, PermissionBit.ManageGuild); + PermissionsHelper.SetValue(ref value, readMessages, PermissionBit.ReadMessages); + PermissionsHelper.SetValue(ref value, sendMessages, PermissionBit.SendMessages); + PermissionsHelper.SetValue(ref value, sendTTSMessages, PermissionBit.SendTTSMessages); + PermissionsHelper.SetValue(ref value, manageMessages, PermissionBit.ManageMessages); + PermissionsHelper.SetValue(ref value, embedLinks, PermissionBit.EmbedLinks); + PermissionsHelper.SetValue(ref value, attachFiles, PermissionBit.AttachFiles); + PermissionsHelper.SetValue(ref value, readMessageHistory, PermissionBit.ReadMessageHistory); + PermissionsHelper.SetValue(ref value, mentionEveryone, PermissionBit.MentionEveryone); + PermissionsHelper.SetValue(ref value, connect, PermissionBit.Connect); + PermissionsHelper.SetValue(ref value, speak, PermissionBit.Speak); + PermissionsHelper.SetValue(ref value, muteMembers, PermissionBit.MuteMembers); + PermissionsHelper.SetValue(ref value, deafenMembers, PermissionBit.DeafenMembers); + PermissionsHelper.SetValue(ref value, moveMembers, PermissionBit.MoveMembers); + PermissionsHelper.SetValue(ref value, useVoiceActivation, PermissionBit.UseVoiceActivation); + + RawValue = value; + } + + /// Creates a new GuildPermissions with the provided permissions. + public GuildPermissions(bool createInstantInvite = false, bool manageRoles = false, + bool kickMembers = false, bool banMembers = false, bool manageChannel = false, bool manageGuild = false, + bool readMessages = false, bool sendMessages = false, bool sendTTSMessages = false, bool manageMessages = false, + bool embedLinks = false, bool attachFiles = false, bool readMessageHistory = false, bool mentionEveryone = false, + bool connect = false, bool speak = false, bool muteMembers = false, bool deafenMembers = false, + bool moveMembers = false, bool useVoiceActivation = false) + : this(0, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannel, manageGuild, readMessages, + sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation) { } + + /// Creates a new GuildPermissions from this one, changing the provided non-null permissions. + public GuildPermissions Modify(bool? createInstantInvite = null, bool? manageRoles = null, + bool? kickMembers = null, bool? banMembers = null, bool? manageChannel = null, bool? manageGuild = null, + bool? readMessages = null, bool? sendMessages = null, bool? sendTTSMessages = null, bool? manageMessages = null, + bool? embedLinks = null, bool? attachFiles = null, bool? readMessageHistory = null, bool? mentionEveryone = null, + bool? connect = null, bool? speak = null, bool? muteMembers = null, bool? deafenMembers = null, + bool? moveMembers = null, bool? useVoiceActivation = null) + => new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannel, manageGuild, readMessages, + sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation); + + /// + public override string ToString() => Convert.ToString(RawValue, 2); + } +} diff --git a/src/Discord.Net/Entities/Permissions/Overwrite.cs b/src/Discord.Net/Entities/Permissions/Overwrite.cs new file mode 100644 index 000000000..d964e7068 --- /dev/null +++ b/src/Discord.Net/Entities/Permissions/Overwrite.cs @@ -0,0 +1,22 @@ +using Model = Discord.API.Overwrite; + +namespace Discord +{ + public struct Overwrite + { + /// Gets the unique identifier for the object this overwrite is targeting. + public ulong TargetId { get; } + /// Gets the type of object this overwrite is targeting. + public PermissionTarget TargetType { get; } + /// Gets the permissions associated with this overwrite entry. + public OverwritePermissions Permissions { get; } + + /// Creates a new Overwrite with provided target information and modified permissions. + internal Overwrite(Model model) + { + TargetId = model.TargetId; + TargetType = model.TargetType; + Permissions = new OverwritePermissions(model.Allow, model.Deny); + } + } +} diff --git a/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs b/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs new file mode 100644 index 000000000..0a569c264 --- /dev/null +++ b/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs @@ -0,0 +1,113 @@ +using System; + +namespace Discord +{ + public struct OverwritePermissions + { + /// Gets a blank OverwritePermissions that inherits all permissions. + public static OverwritePermissions InheritAll { get; } = new OverwritePermissions(); + /// Gets a OverwritePermissions that grants all permissions for a given channelType. + public static OverwritePermissions AllowAll(ChannelType channelType) + => new OverwritePermissions(ChannelPermissions.All(channelType).RawValue, 0); + /// Gets a OverwritePermissions that denies all permissions for a given channelType. + public static OverwritePermissions DenyAll(ChannelType channelType) + => new OverwritePermissions(0, ChannelPermissions.All(channelType).RawValue); + + /// Gets a packed value representing all the allowed permissions in this OverwritePermissions. + public uint AllowValue { get; } + /// Gets a packed value representing all the denied permissions in this OverwritePermissions. + public uint DenyValue { get; } + + /// If True, a user may create invites. + public PermValue CreateInstantInvite => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.CreateInstantInvite); + /// If True, a user may adjust permissions. This also implictly grants all other permissions. + public PermValue ManagePermissions => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.ManageRolesOrPermissions); + /// If True, a user may create, delete and modify this channel. + public PermValue ManageChannel => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.ManageChannel); + /// If True, a user may join channels. + public PermValue ReadMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.ReadMessages); + /// If True, a user may send messages. + public PermValue SendMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.SendMessages); + /// If True, a user may send text-to-speech messages. + public PermValue SendTTSMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.SendTTSMessages); + /// If True, a user may delete messages. + public PermValue ManageMessages => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public PermValue EmbedLinks => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.EmbedLinks); + /// If True, a user may send files. + public PermValue AttachFiles => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.AttachFiles); + /// If True, a user may read previous messages. + public PermValue ReadMessageHistory => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.ReadMessageHistory); + /// If True, a user may mention @everyone. + public PermValue MentionEveryone => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public PermValue Connect => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.Connect); + /// If True, a user may speak in a voice channel. + public PermValue Speak => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.Speak); + /// If True, a user may mute users. + public PermValue MuteMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.MuteMembers); + /// If True, a user may deafen users. + public PermValue DeafenMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.DeafenMembers); + /// If True, a user may move other users between voice channels. + public PermValue MoveMembers => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.MoveMembers); + /// If True, a user may use voice activation rather than push-to-talk. + public PermValue UseVoiceActivation => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.UseVoiceActivation); + + /// Creates a new OverwritePermissions with the provided allow and deny packed values. + public OverwritePermissions(uint allowValue, uint denyValue) + { + AllowValue = allowValue; + DenyValue = denyValue; + } + + private OverwritePermissions(uint allowValue, uint denyValue, PermValue? createInstantInvite = null, PermValue? managePermissions = null, + PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, + PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, + PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, + PermValue? moveMembers = null, PermValue? useVoiceActivation = null) + { + PermissionsHelper.SetValue(ref allowValue, ref denyValue, createInstantInvite, PermissionBit.CreateInstantInvite); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, managePermissions, PermissionBit.ManageRolesOrPermissions); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, manageChannel, PermissionBit.ManageChannel); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, readMessages, PermissionBit.ReadMessages); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, sendMessages, PermissionBit.SendMessages); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, sendTTSMessages, PermissionBit.SendTTSMessages); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, manageMessages, PermissionBit.ManageMessages); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, embedLinks, PermissionBit.EmbedLinks); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, attachFiles, PermissionBit.AttachFiles); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, readMessageHistory, PermissionBit.ReadMessageHistory); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, mentionEveryone, PermissionBit.MentionEveryone); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, connect, PermissionBit.Connect); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, speak, PermissionBit.Speak); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, muteMembers, PermissionBit.MuteMembers); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, deafenMembers, PermissionBit.DeafenMembers); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, moveMembers, PermissionBit.MoveMembers); + PermissionsHelper.SetValue(ref allowValue, ref denyValue, useVoiceActivation, PermissionBit.UseVoiceActivation); + + AllowValue = allowValue; + DenyValue = denyValue; + } + + /// Creates a new ChannelPermissions with the provided permissions. + public OverwritePermissions(PermValue createInstantInvite = PermValue.Inherit, PermValue managePermissions = PermValue.Inherit, + PermValue manageChannel = PermValue.Inherit, PermValue readMessages = PermValue.Inherit, PermValue sendMessages = PermValue.Inherit, PermValue sendTTSMessages = PermValue.Inherit, + PermValue manageMessages = PermValue.Inherit, PermValue embedLinks = PermValue.Inherit, PermValue attachFiles = PermValue.Inherit, PermValue readMessageHistory = PermValue.Inherit, + PermValue mentionEveryone = PermValue.Inherit, PermValue connect = PermValue.Inherit, PermValue speak = PermValue.Inherit, PermValue muteMembers = PermValue.Inherit, PermValue deafenMembers = PermValue.Inherit, + PermValue moveMembers = PermValue.Inherit, PermValue useVoiceActivation = PermValue.Inherit) + : this(0, 0, createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, + manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation) { } + + /// Creates a new OverwritePermissions from this one, changing the provided non-null permissions. + public OverwritePermissions Modify(PermValue? createInstantInvite = null, PermValue? managePermissions = null, + PermValue? manageChannel = null, PermValue? readMessages = null, PermValue? sendMessages = null, PermValue? sendTTSMessages = null, + PermValue? manageMessages = null, PermValue? embedLinks = null, PermValue? attachFiles = null, PermValue? readMessageHistory = null, + PermValue? mentionEveryone = null, PermValue? connect = null, PermValue? speak = null, PermValue? muteMembers = null, PermValue? deafenMembers = null, + PermValue? moveMembers = null, PermValue? useVoiceActivation = null) + => new OverwritePermissions(AllowValue, DenyValue, createInstantInvite, managePermissions, manageChannel, readMessages, sendMessages, sendTTSMessages, + manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation); + + /// + public override string ToString() => $"Allow: {Convert.ToString(AllowValue, 2)}, Deny: {Convert.ToString(DenyValue, 2)}"; + } +} diff --git a/src/Discord.Net/Entities/Presences/GuildPresence.cs b/src/Discord.Net/Entities/Presences/GuildPresence.cs new file mode 100644 index 000000000..142e042e7 --- /dev/null +++ b/src/Discord.Net/Entities/Presences/GuildPresence.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.MemberPresence; + +namespace Discord +{ + public class GuildPresence : Presence + { + public Guild Guild { get; } + public ulong UserId { get; } + + /// + public IReadOnlyList Roles { get; private set; } + + internal GuildPresence(ulong userId, Guild guild) + { + UserId = userId; + Guild = guild; + } + internal override void Update(Model model) + { + base.Update(model); + Roles = model.Roles.Select(x => Guild.GetRole(x)).ToImmutableArray(); + } + + public bool HasRole(Role role) => false; + + //TODO: Unsure about these + /*public Task AddRoles(params Role[] roles) => xxx; + public Task RemoveRoles(params Role[] roles) => xxx;*/ + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Presences/Presence.cs b/src/Discord.Net/Entities/Presences/Presence.cs new file mode 100644 index 000000000..671f60966 --- /dev/null +++ b/src/Discord.Net/Entities/Presences/Presence.cs @@ -0,0 +1,18 @@ +using Model = Discord.API.MemberPresence; + +namespace Discord +{ + public class Presence + { + public string CurrentGame { get; private set; } + public UserStatus Status { get; private set; } + + internal Presence() { } + + internal virtual void Update(Model model) + { + CurrentGame = model.Game?.Name; + Status = model.Status; + } + } +} diff --git a/src/Discord.Net/Entities/Presences/VoiceState.cs b/src/Discord.Net/Entities/Presences/VoiceState.cs new file mode 100644 index 000000000..f6b56d7b6 --- /dev/null +++ b/src/Discord.Net/Entities/Presences/VoiceState.cs @@ -0,0 +1,66 @@ +using Discord.API.Rest; +using System; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.MemberVoiceState; + +namespace Discord +{ + public class VoiceState + { + [Flags] + private enum VoiceStates : byte + { + None = 0x0, + Muted = 0x01, + Deafened = 0x02, + Suppressed = 0x4, + SelfMuted = 0x10, + SelfDeafened = 0x20, + } + + private VoiceStates _voiceStates; + + public Guild Guild { get; } + public ulong UserId { get; } + + /// Gets this user's current voice channel. + public VoiceChannel VoiceChannel { get; internal set; } + + /// Returns true if this user has marked themselves as muted. + public bool IsSelfMuted => (_voiceStates & VoiceStates.SelfMuted) != 0; + /// Returns true if this user has marked themselves as deafened. + public bool IsSelfDeafened => (_voiceStates & VoiceStates.SelfDeafened) != 0; + /// Returns true if the guild is blocking audio from this user. + public bool IsMuted => (_voiceStates & VoiceStates.Muted) != 0; + /// Returns true if the guild is blocking audio to this user. + public bool IsDeafened => (_voiceStates & VoiceStates.Deafened) != 0; + /// Returns true if the guild is temporarily blocking audio to/from this user. + public bool IsSuppressed => (_voiceStates & VoiceStates.Suppressed) != 0; + + internal VoiceState(ulong userId, Guild guild) + { + UserId = userId; + Guild = guild; + } + + internal void Update(Model model) + { + if (model.IsMuted == true) + _voiceStates |= VoiceStates.Muted; + else if (model.IsMuted == false) + _voiceStates &= ~VoiceStates.Muted; + + if (model.IsDeafened == true) + _voiceStates |= VoiceStates.Deafened; + else if (model.IsDeafened == false) + _voiceStates &= ~VoiceStates.Deafened; + + if (model.IsSuppressed == true) + _voiceStates |= VoiceStates.Suppressed; + else if (model.IsSuppressed == false) + _voiceStates &= ~VoiceStates.Suppressed; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/PrivateChannel.cs b/src/Discord.Net/Entities/PrivateChannel.cs deleted file mode 100644 index b3f3f1faf..000000000 --- a/src/Discord.Net/Entities/PrivateChannel.cs +++ /dev/null @@ -1,66 +0,0 @@ -using APIChannel = Discord.API.Client.Channel; -using Discord.API.Client.Rest; -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Discord -{ - public class PrivateChannel : Channel, IPrivateChannel, ITextChannel - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - private readonly MessageManager _messages; - - /// Gets the target user, if this is a private chat. - public User Recipient { get; } - - public override DiscordClient Client => Recipient.Client; - - public override ChannelType Type => ChannelType.Private; - public override User CurrentUser => Client.PrivateUser; - public override IEnumerable Users => new User[] { Client.PrivateUser, Recipient }; - - internal override MessageManager MessageManager => _messages; - internal override PermissionManager PermissionManager => null; - - internal PrivateChannel(ulong id, User recipient, APIChannel model) - : this(id, recipient) - { - _messages = new MessageManager(this, Client.Config.MessageCacheSize); - Update(model); - } - private PrivateChannel(ulong id, User recipient) - :base(id) - { - Recipient = recipient; - } - - internal override User GetUser(ulong id) - { - if (id == Recipient.Id) return Recipient; - else if (id == Client.CurrentUser.Id) return Client.PrivateUser; - else return null; - } - - public Message GetMessage(ulong id) => _messages.Get(id); - public Task DownloadMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) - => _messages.Download(limit, relativeMessageId, relativeDir); - - public Task SendMessage(string text, bool isTTS = false) => _messages.Send(text, isTTS); - public Task SendFile(string filePath) => _messages.SendFile(filePath); - public Task SendFile(string filename, Stream stream) => _messages.SendFile(filename, stream); - public Task SendIsTyping() => Client.ClientAPI.Send(new SendIsTypingRequest(Id)); - - public override string ToString() => $"@{Recipient.Name}"; - - internal override void Update(APIChannel model) { } - internal override Channel Clone() - { - var result = new PrivateChannel(Id, Recipient); - _cloner(this, result); - return result; - } - } -} diff --git a/src/Discord.Net/Entities/Profile.cs b/src/Discord.Net/Entities/Profile.cs deleted file mode 100644 index 7029e4c41..000000000 --- a/src/Discord.Net/Entities/Profile.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Discord.API.Client; -using Discord.API.Client.Rest; -using System; -using System.IO; -using System.Threading.Tasks; -using APIUser = Discord.API.Client.User; - -namespace Discord -{ - public class Profile - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - public DiscordClient Client { get; } - - /// Gets the unique identifier for this user. - public ulong Id { get; } - /// Gets the global name of this user. - public string Name => Client.PrivateUser.Name; - /// Gets the unique identifier for this user's current avatar. - public string AvatarId => Client.PrivateUser.AvatarId; - /// Gets the URL to this user's current avatar. - public string AvatarUrl => Client.PrivateUser.AvatarUrl; - /// Gets an id uniquely identifying from others with the same name. - public ushort Discriminator => Client.PrivateUser.Discriminator; - /// Gets the name of the game this user is currently playing. - public string CurrentGame => Client.PrivateUser.CurrentGame; - /// Gets the current status for this user. - public UserStatus Status => Client.PrivateUser.Status; - /// Returns the string used to mention this user. - public string Mention => $"<@{Id}>"; - - /// Gets the email for this user. - public string Email { get; private set; } - /// Gets if the email for this user has been verified. - public bool? IsVerified { get; private set; } - - internal Profile(UserReference model, DiscordClient client) - : this(model.Id, client) - { - } - private Profile(ulong id, DiscordClient client) - { - Id = id; - Client = client; - } - - internal void Update(APIUser model) - { - Email = model.Email; - IsVerified = model.IsVerified; - } - - public async Task Edit(string currentPassword = "", - string username = null, string email = null, string password = null, - Stream avatar = null, ImageType avatarType = ImageType.Png) - { - if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword)); - - var request = new UpdateProfileRequest() - { - CurrentPassword = currentPassword, - Email = email ?? Email, - Password = password, - Username = username ?? Client.PrivateUser.Name, - AvatarBase64 = avatar.Base64(avatarType, Client.PrivateUser.AvatarId) - }; - - await Client.ClientAPI.Send(request).ConfigureAwait(false); - - if (password != null) - { - var loginRequest = new LoginRequest() - { - Email = Email, - Password = password - }; - var loginResponse = await Client.ClientAPI.Send(loginRequest).ConfigureAwait(false); - Client.ClientAPI.Token = loginResponse.Token; - } - } - - internal Profile Clone() - { - var result = new Profile(Id, Client); - _cloner(this, result); - return result; - } - - public override string ToString() => Name; - } -} diff --git a/src/Discord.Net/Entities/PublicChannel.cs b/src/Discord.Net/Entities/PublicChannel.cs deleted file mode 100644 index a1d5c4f41..000000000 --- a/src/Discord.Net/Entities/PublicChannel.cs +++ /dev/null @@ -1,109 +0,0 @@ -using APIChannel = Discord.API.Client.Channel; -using Discord.API.Client.Rest; -using Discord.Net; -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; - -namespace Discord -{ - /// A public Discord channel - public abstract class PublicChannel : Channel, IModel, IMentionable - { - internal readonly PermissionManager _permissions; - - /// Gets the server owning this channel. - public Server Server { get; } - - /// Gets or sets the name of this channel. - public string Name { get; set; } - /// Getsor sets the position of this channel relative to other channels of the same type in this server. - public int Position { get; set; } - - /// Gets the DiscordClient that created this model. - public override DiscordClient Client => Server.Client; - public override User CurrentUser => Server.CurrentUser; - /// Gets the string used to mention this channel. - public string Mention => $"<#{Id}>"; - /// Gets a collection of all custom permissions used for this channel. - public IEnumerable PermissionRules => _permissions.Rules; - - internal PublicChannel(APIChannel model, Server server) - : this(model.Id, server) - { - _permissions = new PermissionManager(this, model, server.Client.Config.UsePermissionsCache ? (int)(server.UserCount * 1.05) : -1); - Update(model); - } - protected PublicChannel(ulong id, Server server) - : base(id) - { - Server = server; - } - - internal override void Update(APIChannel model) - { - if (model.Name != null) Name = model.Name; - if (model.Position != null) Position = model.Position.Value; - - if (model.PermissionOverwrites != null) - _permissions.Update(model); - } - - public async Task Delete() - { - try { await Client.ClientAPI.Send(new DeleteChannelRequest(Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - public abstract Task Save(); - - internal override User GetUser(ulong id) => Server.GetUser(id); - - public ChannelTriStatePermissions? GetPermissionsRule(User user) => _permissions.GetOverwrite(user); - public ChannelTriStatePermissions? GetPermissionsRule(Role role) => _permissions.GetOverwrite(role); - public Task AddOrUpdatePermissionsRule(User user, ChannelTriStatePermissions permissions) => _permissions.AddOrUpdateOverwrite(user, permissions); - public Task AddOrUpdatePermissionsRule(Role role, ChannelTriStatePermissions permissions) => _permissions.AddOrUpdateOverwrite(role, permissions); - public Task RemovePermissionsRule(User user) => _permissions.RemoveOverwrite(user); - public async Task RemovePermissionsRule(Role role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - try { await Client.ClientAPI.Send(new RemoveChannelPermissionsRequest(Id, role.Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - - internal ChannelPermissions GetPermissions(User user) => _permissions.GetPermissions(user); - internal void UpdatePermissions() => _permissions.UpdatePermissions(); - internal void UpdatePermissions(User user) => _permissions.UpdatePermissions(user); - internal bool ResolvePermissions(User user, ref ChannelPermissions permissions) => _permissions.ResolvePermissions(user, ref permissions); - - internal override PermissionManager PermissionManager => null; - - /// Creates a new invite to this channel. - /// Time (in seconds) until the invite expires. Set to null to never expire. - /// The max amount of times this invite may be used. Set to null to have unlimited uses. - /// If true, a user accepting this invite will be kicked from the server after closing their client. - /// If true, creates a human-readable link. Not supported if maxAge is set to null. - public async Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) - { - if (maxAge < 0) throw new ArgumentOutOfRangeException(nameof(maxAge)); - if (maxUses < 0) throw new ArgumentOutOfRangeException(nameof(maxUses)); - - var request = new CreateInviteRequest(Id) - { - MaxAge = maxAge ?? 0, - MaxUses = maxUses ?? 0, - IsTemporary = tempMembership, - WithXkcdPass = withXkcd - }; - - var response = await Client.ClientAPI.Send(request).ConfigureAwait(false); - var invite = new Invite(response, Client); - return invite; - } - - internal void AddUser(User user) => _permissions.AddUser(user); - internal void RemoveUser(ulong id) => _permissions.RemoveUser(id); - - public override string ToString() => $"{Server}/{Name ?? Id.ToIdString()}"; - } -} diff --git a/src/Discord.Net/Entities/Region.cs b/src/Discord.Net/Entities/Region.cs deleted file mode 100644 index cf144a223..000000000 --- a/src/Discord.Net/Entities/Region.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Discord -{ - public class Region - { - public string Id { get; } - public string Name { get; } - public string Hostname { get; } - public int Port { get; } - public bool Vip { get; } - - internal Region(string id, string name, string hostname, int port, bool vip) - { - Id = id; - Name = name; - Hostname = hostname; - Port = port; - Vip = vip; - } - - public override string ToString() => Name; - } -} diff --git a/src/Discord.Net/Entities/Role.cs b/src/Discord.Net/Entities/Role.cs index 2f946f0b8..1e138c911 100644 --- a/src/Discord.Net/Entities/Role.cs +++ b/src/Discord.Net/Entities/Role.cs @@ -1,134 +1,85 @@ -using Discord.API.Client.Rest; +using Discord.API.Rest; using Discord.Net; using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Threading.Tasks; -using APIRole = Discord.API.Client.Role; +using Model = Discord.API.Role; namespace Discord { - public class Role : IMentionable + public class Role : IEntity, IMentionable { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - public DiscordClient Client => Server.Client; - - /// Gets the unique identifier for this role. + /// public ulong Id { get; } - /// Gets the server this role is a member of. - public Server Server { get; } + /// Returns the guild this role belongs to. + public Guild Guild { get; } /// Gets the name of this role. public string Name { get; private set; } - /// If true, this role is displayed isolated from other users. - public bool IsHoisted { get; private set; } - /// Gets the position of this channel relative to other channels in this server. + /// Returns true if members of this role are isolated in the user list. + public bool IsHoisted { get; private set; } + /// Gets the position of this role relative to other roles in this guild. public int Position { get; private set; } - /// Gets whether this role is managed by server (e.g. for Twitch integration) + /// Returns true if this role is managed by the Discord server (e.g. for Twitch integration) public bool IsManaged { get; private set; } - /// Gets the the permissions given to this role. - public ServerPermissions Permissions { get; private set; } - /// Gets the color of this role. + /// Gets the permissions given to all members of this role. + public GuildPermissions Permissions { get; private set; } + /// Gets the color assigned to members of this role. public Color Color { get; private set; } - - /// Gets true if this is the role representing all users in a server. - public bool IsEveryone => Id == Server.Id; - /// Gets a list of all members in this role. - public IEnumerable Members => IsEveryone ? Server.Users : Server.Users.Where(x => x.HasRole(this)); + /// + public DiscordClient Discord => Guild.Discord; + /// Returns true if this is the role representing all users in a server. + public bool IsEveryone => Id == Guild.Id; /// Gets the string used to mention this role. public string Mention => IsEveryone ? "@everyone" : ""; + /// Gets a collection of all members in this role. + public IEnumerable Members { get { throw new NotImplementedException(); } } //TODO: Implement - internal Role(ulong id, Server server) - { + internal Role(ulong id, Guild guild) + { Id = id; - Server = server; - - Permissions = new ServerPermissions(0); - Color = new Color(0); - } + Guild = guild; + } - internal void Update(APIRole model, bool updatePermissions) - { - if (model.Name != null) - Name = model.Name; - if (model.Hoist != null) - IsHoisted = model.Hoist.Value; - if (model.Managed != null) - IsManaged = model.Managed.Value; - if (model.Position != null && !IsEveryone) - Position = model.Position.Value; - if (model.Color != null) - Color = new Color(model.Color.Value); - if (model.Permissions != null) - { - Permissions = new ServerPermissions(model.Permissions.Value); - if (updatePermissions) //Dont update these during READY - { - foreach (var member in Members) - Server.UpdatePermissions(member); - } - } - } - - public async Task Edit(string name = null, ServerPermissions? permissions = null, Color color = null, bool? isHoisted = null, int? position = null) + internal void Update(Model model) { - var updateRequest = new UpdateRoleRequest(Server.Id, Id) - { - Name = name ?? Name, - Permissions = (permissions ?? Permissions).RawValue, - Color = (color ?? Color).RawValue, - IsHoisted = isHoisted ?? IsHoisted - }; - - var updateResponse = await Client.ClientAPI.Send(updateRequest).ConfigureAwait(false); + Name = model.Name; + IsHoisted = model.Hoist.Value; + IsManaged = model.Managed.Value; + Position = model.Position.Value; + Color = new Color(model.Color.Value); + Permissions = new GuildPermissions(model.Permissions.Value); + } - if (position != null) - { - int oldPos = Position; - int newPos = position.Value; - int minPos; - Role[] roles = Server.Roles.OrderBy(x => x.Position).ToArray(); + /// + public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet - if (oldPos < newPos) //Moving Down - { - minPos = oldPos; - for (int i = oldPos; i < newPos; i++) - roles[i] = roles[i + 1]; - roles[newPos] = this; - } - else //(oldPos > newPos) Moving Up - { - minPos = newPos; - for (int i = oldPos; i > newPos; i--) - roles[i] = roles[i - 1]; - roles[newPos] = this; - } + /// Modifies the properties of this role. + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); - var reorderRequest = new ReorderRolesRequest(Server.Id) - { - RoleIds = roles.Skip(minPos).Select(x => x.Id).ToArray(), - StartPos = minPos - }; - await Client.ClientAPI.Send(reorderRequest).ConfigureAwait(false); - } + var req = new ModifyGuildRoleRequest(Guild.Id, Id); + func(req); + await Discord.RestClient.Send(req).ConfigureAwait(false); } + /// Deletes this message. public async Task Delete() { - try { await Client.ClientAPI.Send(new DeleteRoleRequest(Server.Id, Id)).ConfigureAwait(false); } + try { await Discord.RestClient.Send(new DeleteGuildRoleRequest(Guild.Id, Id)).ConfigureAwait(false); } catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } } - internal Role Clone() + internal void UpdatePermissions() { - var result = new Role(Id, Server); - _cloner(this, result); - return result; + foreach (var member in Members) + Guild.UpdatePermissions(member); } - public override string ToString() => $"{Server}/{Name ?? Id.ToString()}"; + /// + public override string ToString() => $"{Guild}/{Name ?? Id.ToString()}"; } } diff --git a/src/Discord.Net/Entities/Server.cs b/src/Discord.Net/Entities/Server.cs deleted file mode 100644 index a5e586126..000000000 --- a/src/Discord.Net/Entities/Server.cs +++ /dev/null @@ -1,511 +0,0 @@ -using APIChannel = Discord.API.Client.Channel; -using APIMember = Discord.API.Client.Member; -using Discord.API.Client; -using Discord.API.Client.Rest; -using Discord.Net; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading.Tasks; - -namespace Discord -{ - /// Represents a Discord server (also known as a guild). - public class Server - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - internal static string GetIconUrl(ulong serverId, string iconId) - => iconId != null ? $"{DiscordConfig.ClientAPIUrl}guilds/{serverId}/icons/{iconId}.jpg" : null; - internal static string GetSplashUrl(ulong serverId, string splashId) - => splashId != null ? $"{DiscordConfig.ClientAPIUrl}guilds/{serverId}/splashes/{splashId}.jpg" : null; - - public class Emoji - { - public string Id { get; } - - public string Name { get; internal set; } - public bool IsManaged { get; internal set; } - public bool RequireColons { get; internal set; } - public IEnumerable Roles { get; internal set; } - - internal Emoji(string id) - { - Id = id; - } - } - private struct Member - { - public readonly User User; - public readonly ServerPermissions Permissions; - public Member(User user, ServerPermissions permissions) - { - User = user; - Permissions = permissions; - } - } - - private ConcurrentDictionary _roles; - private ConcurrentDictionary _users; - private ConcurrentDictionary _channels; - private ulong _ownerId; - private ulong? _afkChannelId; - private int _userCount; - - public DiscordClient Client { get; } - - /// Gets the unique identifier for this server. - public ulong Id { get; } - - /// Gets the name of this server. - public string Name { get; set; } - /// Gets the voice region for this server. - public Region Region { get; set; } - /// Gets the AFK voice channel for this server. - public VoiceChannel AFKChannel { get; set; } - /// Gets the amount of time (in seconds) a user must be inactive for until they are automatically moved to the AFK voice channel, if one is set. - public int AFKTimeout { get; set; } - - /// Gets the date and time you joined this server. - public DateTime JoinedAt { get; private set; } - /// Gets the the role representing all users in a server. - public Role EveryoneRole { get; private set; } - /// Gets all extra features added to this server. - public IEnumerable Features { get; private set; } - /// Gets all custom emojis on this server. - public IEnumerable CustomEmojis { get; private set; } - /// Gets the unique identifier for this user's current avatar. - public string IconId { get; private set; } - /// Gets the unique identifier for this server's custom splash image. - public string SplashId { get; private set; } - - /// Gets the user that created this server. - public User Owner => GetUser(_ownerId); - /// Gets the default channel for this server. - public TextChannel DefaultChannel => _channels[Id] as TextChannel; - /// Gets the current user in this server. - public User CurrentUser => GetUser(Client.CurrentUser.Id); - /// Gets the URL to this server's current icon. - public string IconUrl => GetIconUrl(Id, IconId); - /// Gets the URL to this servers's splash image. - public string SplashUrl => GetSplashUrl(Id, SplashId); - - /// Gets a collection of all channels in this server. - public IEnumerable AllChannels => _channels.Select(x => x.Value); - /// Gets a collection of text channels in this server. - public IEnumerable TextChannels => _channels.Where(x => x.Value.IsText).Select(x => x.Value as TextChannel); - /// Gets a collection of voice channels in this server. - public IEnumerable VoiceChannels => _channels.Where(x => x.Value.IsVoice).Select(x => x.Value as VoiceChannel); - /// Gets a collection of all members in this server. - public IEnumerable Users => _users.Select(x => x.Value.User); - /// Gets a collection of all roles in this server. - public IEnumerable Roles => _roles.Select(x => x.Value); - - /// Gets the number of channels in this server. - public int ChannelCount => _channels.Count; - /// Gets the number of users downloaded for this server so far. - internal int CurrentUserCount => _users.Count; - /// Gets the number of users in this server. - public int UserCount => _userCount; - /// Gets the number of roles in this server. - public int RoleCount => _roles.Count; - - internal Server(ulong id, DiscordClient client) - { - Id = id; - Client = client; - } - - internal void Update(Guild model) - { - if (model.Name != null) - Name = model.Name; - if (model.AFKTimeout != null) - AFKTimeout = model.AFKTimeout.Value; - if (model.JoinedAt != null) - JoinedAt = model.JoinedAt.Value; - if (model.OwnerId != null) - _ownerId = model.OwnerId.Value; - if (model.Region != null) - Region = Client.GetRegion(model.Region); - if (model.Icon != null) - IconId = model.Icon; - if (model.Features != null) - Features = model.Features; - if (model.Roles != null) - { - _roles = new ConcurrentDictionary(2, model.Roles.Length); - foreach (var x in model.Roles) - { - var role = AddRole(x.Id); - role.Update(x, false); - } - EveryoneRole = _roles[Id]; - } - if (model.Emojis != null) //Needs Roles - { - CustomEmojis = model.Emojis.Select(x => new Emoji(x.Id) - { - Name = x.Name, - IsManaged = x.IsManaged, - RequireColons = x.RequireColons, - Roles = x.RoleIds.Select(y => GetRole(y)).Where(y => y != null).ToArray() - }).ToArray(); - } - - //Can be null - _afkChannelId = model.AFKChannelId; - SplashId = model.Splash; - } - internal void Update(ExtendedGuild model) - { - Update(model as Guild); - - //Only channels or members should have AddXXX(cachePerms: true), not both - if (model.Channels != null) - { - _channels = new ConcurrentDictionary(2, (int)(model.Channels.Length * 1.05)); - foreach (var subModel in model.Channels) - AddChannel(subModel, false); - } - if (model.MemberCount != null) - { - if (_users == null) - _users = new ConcurrentDictionary(2, (int)(model.MemberCount * 1.05)); - _userCount = model.MemberCount.Value; - } - if (!model.IsLarge) - { - if (model.Members != null) - { - foreach (var subModel in model.Members) - AddUser(subModel, true, false).Update(subModel); - } - if (model.VoiceStates != null) - { - foreach (var subModel in model.VoiceStates) - GetUser(subModel.UserId)?.Update(subModel); - } - if (model.Presences != null) - { - foreach (var subModel in model.Presences) - GetUser(subModel.User.Id)?.Update(subModel); - } - } - } - - /// Edits this server, changing only non-null attributes. - public Task Edit(string name = null, string region = null, Stream icon = null, ImageType iconType = ImageType.Png) - { - var request = new UpdateGuildRequest(Id) - { - Name = name ?? Name, - Region = region ?? Region.Id, - IconBase64 = icon.Base64(iconType, IconId), - AFKChannelId = AFKChannel?.Id, - AFKTimeout = AFKTimeout, - Splash = SplashId - }; - return Client.ClientAPI.Send(request); - } - - /// Leaves this server. This function will fail if you're the owner - use Delete instead. - public async Task Leave() - { - try { await Client.ClientAPI.Send(new LeaveGuildRequest(Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - /// Deletes this server. This function will fail if you're not the owner - use Leave instead. - public async Task Delete() - { - try { await Client.ClientAPI.Send(new DeleteGuildRequest(Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - - #region Bans - public async Task> GetBans() - { - var response = await Client.ClientAPI.Send(new GetBansRequest(Id)).ConfigureAwait(false); - return response.Select(x => - { - var user = new User(x, Client, this); - return user; - }); - } - - public Task Ban(User user, int pruneDays = 0) - { - var request = new AddGuildBanRequest(user.Server.Id, user.Id) - { - PruneDays = pruneDays - }; - return Client.ClientAPI.Send(request); - } - public Task Unban(User user, int pruneDays = 0) - => Unban(user.Id); - public async Task Unban(ulong userId) - { - try { await Client.ClientAPI.Send(new RemoveGuildBanRequest(Id, userId)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - #endregion - - #region Channels - internal PublicChannel AddChannel(APIChannel model, bool cachePerms) - { - PublicChannel channel; - ChannelType type = EnumConverters.ToChannelType(model.Type); - if (type == ChannelType.Voice) - channel = new VoiceChannel(model, this); - else - channel = new TextChannel(model, this); - - if (cachePerms && Client.Config.UsePermissionsCache) - { - foreach (var user in Users) - channel.AddUser(user); - } - Client.AddChannel(channel); - return _channels.GetOrAdd(model.Id, x => channel); - } - internal PublicChannel RemoveChannel(ulong id) - { - PublicChannel channel; - _channels.TryRemove(id, out channel); - return channel; - } - - /// Gets the channel with the provided id and owned by this server, or null if not found. - public PublicChannel GetChannel(ulong id) - { - PublicChannel result; - _channels.TryGetValue(id, out result); - return result; - } - public TextChannel GetTextChannel(ulong id) => GetChannel(id) as TextChannel; - public VoiceChannel GetVoiceChannel(ulong id) => GetChannel(id) as VoiceChannel; - - /// Creates a new channel. - public async Task CreateChannel(string name, ChannelType type) - { - if (name == null) throw new ArgumentNullException(nameof(name)); - if (type != ChannelType.Text && type != ChannelType.Voice) throw new ArgumentException("Invalid channel type", nameof(type)); - - var request = new CreateChannelRequest(Id) { Name = name, Type = type }; - var response = await Client.ClientAPI.Send(request).ConfigureAwait(false); - - var channel = AddChannel(response, true); - channel.Update(response); - return channel; - } - #endregion - - #region Invites - /// Gets all active (non-expired) invites to this server. - public async Task> DownloadInvites() - { - var response = await Client.ClientAPI.Send(new GetInvitesRequest(Id)).ConfigureAwait(false); - return response.Select(x => - { - var invite = new Invite(x, Client); - invite.Update(x); - return invite; - }); - } - - /// Creates a new invite to the default channel of this server. - /// Time (in seconds) until the invite expires. Set to null to never expire. - /// The max amount of times this invite may be used. Set to null to have unlimited uses. - /// If true, a user accepting this invite will be kicked from the server after closing their client. - /// If true, creates a human-readable link. Not supported if maxAge is set to null. - public Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool tempMembership = false, bool withXkcd = false) - => DefaultChannel.CreateInvite(maxAge, maxUses, tempMembership, withXkcd); - #endregion - - #region Roles - internal Role AddRole(ulong id) - => _roles.GetOrAdd(id, x => new Role(x, this)); - internal Role RemoveRole(ulong id) - { - Role role; - _roles.TryRemove(id, out role); - return role; - } - - /// Gets the role with the provided id and owned by this server, or null if not found. - public Role GetRole(ulong id) - { - Role result; - _roles.TryGetValue(id, out result); - return result; - } - - /// Creates a new role. - public async Task CreateRole(string name, ServerPermissions? permissions = null, Color color = null, bool isHoisted = false) - { - if (name == null) throw new ArgumentNullException(nameof(name)); - - var createRequest = new CreateRoleRequest(Id); - var createResponse = await Client.ClientAPI.Send(createRequest).ConfigureAwait(false); - var role = AddRole(createResponse.Id); - role.Update(createResponse, false); - - var editRequest = new UpdateRoleRequest(role.Server.Id, role.Id) - { - Name = name, - Permissions = (permissions ?? role.Permissions).RawValue, - Color = (color ?? Color.Default).RawValue, - IsHoisted = isHoisted - }; - var editResponse = await Client.ClientAPI.Send(editRequest).ConfigureAwait(false); - role.Update(editResponse, true); - - return role; - } - - /// Reorders the provided roles and optionally places them after a certain role. - public Task ReorderRoles(IEnumerable roles, Role after = null) - { - if (roles == null) throw new ArgumentNullException(nameof(roles)); - - return Client.ClientAPI.Send(new ReorderRolesRequest(Id) - { - RoleIds = roles.Select(x => x.Id).ToArray(), - StartPos = after != null ? after.Position + 1 : roles.Min(x => x.Position) - }); - } - #endregion - - #region Permissions - internal ServerPermissions GetPermissions(User user) - { - Member member; - if (_users.TryGetValue(user.Id, out member)) - return member.Permissions; - else - return ServerPermissions.None; - } - - internal void UpdatePermissions(User user) - { - Member member; - if (_users.TryGetValue(user.Id, out member)) - { - var perms = member.Permissions; - if (UpdatePermissions(member.User, ref perms)) - { - _users[user.Id] = new Member(member.User, perms); - foreach (var channel in _channels) - channel.Value.UpdatePermissions(user); - } - } - } - - private bool UpdatePermissions(User user, ref ServerPermissions permissions) - { - uint newPermissions = 0; - - if (user.Id == _ownerId) - newPermissions = ServerPermissions.All.RawValue; - else - { - foreach (var serverRole in user.Roles) - newPermissions |= serverRole.Permissions.RawValue; - } - - if (newPermissions.HasBit((byte)PermissionBits.ManageRolesOrPermissions)) - newPermissions = ServerPermissions.All.RawValue; - - if (newPermissions != permissions.RawValue) - { - permissions = new ServerPermissions(newPermissions); - return true; - } - return false; - } - #endregion - - #region Users - internal User AddUser(APIMember model, bool cachePerms, bool incrementCount) - { - if (incrementCount) - _userCount++; - - Member member; - if (!_users.TryGetValue(model.User.Id, out member)) //Users can only be added from websocket thread, ignore threadsafety - { - member = new Member(new User(model, Client, this), ServerPermissions.None); - if (model.User.Id == Client.CurrentUser.Id) - { - member.User.CurrentGame = Client.CurrentGame; - member.User.Status = Client.Status; - } - - _users[model.User.Id] = member; - if (cachePerms && Client.Config.UsePermissionsCache) - { - foreach (var channel in _channels) - channel.Value.AddUser(member.User); - } - } - return member.User; - } - internal User RemoveUser(ulong id) - { - _userCount--; - Member member; - if (_users.TryRemove(id, out member)) - { - foreach (var channel in _channels) - channel.Value.RemoveUser(id); - return member.User; - } - return null; - } - - /// Gets the user with the provided id and is a member of this server, or null if not found. - public User GetUser(ulong id) - { - Member result; - if (_users.TryGetValue(id, out result)) - return result.User; - else - return null; - } - /// Gets the user with the provided username and discriminator, that is a member of this server, or null if not found. - public User GetUser(string name, ushort discriminator) - { - if (name == null) throw new ArgumentNullException(nameof(name)); - - return _users.Select(x => x.Value.User).Where(x => x.Discriminator == discriminator && x.Name == name).SingleOrDefault(); - } - - /// Kicks all users with an inactivity greater or equal to the provided number of days. - /// If true, no pruning will actually be done but instead return the number of users that would be pruned. - public async Task PruneUsers(int days = 30, bool simulate = false) - { - if (days <= 0) throw new ArgumentOutOfRangeException(nameof(days)); - - var request = new PruneMembersRequest(Id) - { - Days = days, - IsSimulation = simulate - }; - var response = await Client.ClientAPI.Send(request).ConfigureAwait(false); - return response.Pruned; - } - #endregion - - internal Server Clone() - { - var result = new Server(Id, Client); - _cloner(this, result); - return result; - } - - public override string ToString() => Name ?? Id.ToIdString(); - } -} diff --git a/src/Discord.Net/Entities/TextChannel.cs b/src/Discord.Net/Entities/TextChannel.cs deleted file mode 100644 index 8ee97aad1..000000000 --- a/src/Discord.Net/Entities/TextChannel.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Discord.API.Client.Rest; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using APIChannel = Discord.API.Client.Channel; - -namespace Discord -{ - public class TextChannel : PublicChannel, IPublicChannel, ITextChannel - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - private readonly MessageManager _messages; - - /// Gets or sets the topic of this channel. - public string Topic { get; set; } - - public override ChannelType Type => ChannelType.Text; - /// Gets a collection of all messages the client has seen posted in this channel. This collection does not guarantee any ordering. - public IEnumerable Messages => _messages != null ? _messages : Enumerable.Empty(); - /// Gets a collection of all users with read access to this channel. - public override IEnumerable Users - { - get - { - if (Client.Config.UsePermissionsCache) - return _permissions.Users.Where(x => x.Permissions.ReadMessages == true).Select(x => x.User); - else - { - ChannelPermissions perms = new ChannelPermissions(); - return Server.Users.Where(x => - { - _permissions.ResolvePermissions(x, ref perms); - return perms.ReadMessages == true; - }); - } - } - } - - internal override MessageManager MessageManager => _messages; - - internal TextChannel(APIChannel model, Server server) - : base(model, server) - { - if (Client.Config.MessageCacheSize > 0) - _messages = new MessageManager(this, (int)(Client.Config.MessageCacheSize * 1.05)); - } - private TextChannel(ulong id, Server server) - : base(id, server) - { - } - - internal override void Update(APIChannel model) - { - base.Update(model); - if (model.Topic != null) Topic = model.Topic; - } - /// Save all changes to this channel. - public override async Task Save() - { - var request = new UpdateChannelRequest(Id) - { - Name = Name, - Topic = Topic, - Position = Position - }; - await Client.ClientAPI.Send(request).ConfigureAwait(false); - } - - public Message GetMessage(ulong id) => _messages.Get(id); - public Task DownloadMessages(int limit = 100, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before) - => _messages.Download(limit, relativeMessageId, relativeDir); - - public Task SendMessage(string text, bool isTTS = false) => _messages.Send(text, isTTS); - public Task SendFile(string filePath) => _messages.SendFile(filePath); - public Task SendFile(string filename, Stream stream) => _messages.SendFile(filename, stream); - public Task SendIsTyping() => Client.ClientAPI.Send(new SendIsTypingRequest(Id)); - - internal override Channel Clone() - { - var result = new TextChannel(Id, Server); - _cloner(this, result); - return result; - } - } -} diff --git a/src/Discord.Net/Entities/User.cs b/src/Discord.Net/Entities/User.cs deleted file mode 100644 index 89a0b1133..000000000 --- a/src/Discord.Net/Entities/User.cs +++ /dev/null @@ -1,356 +0,0 @@ -using Discord.API.Client; -using Discord.API.Client.Rest; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using APIMember = Discord.API.Client.Member; - -namespace Discord -{ - public class User - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - internal static string GetAvatarUrl(ulong userId, string avatarId) - => avatarId != null ? $"{DiscordConfig.ClientAPIUrl}users/{userId}/avatars/{avatarId}.jpg" : null; - - [Flags] - private enum VoiceState : byte - { - Normal = 0x0, - SelfMuted = 0x01, - SelfDeafened = 0x02, - ServerMuted = 0x10, - ServerDeafened = 0x20, - ServerSuppressed = 0x40, - } - - internal struct CompositeKey : IEquatable - { - public ulong ServerId, UserId; - public CompositeKey(ulong userId, ulong? serverId) - { - ServerId = serverId ?? 0; - UserId = userId; - } - - public bool Equals(CompositeKey other) - => UserId == other.UserId && ServerId == other.ServerId; - public override int GetHashCode() - => unchecked(ServerId.GetHashCode() + UserId.GetHashCode() + 23); - } - - private VoiceState _voiceState; - private DateTime? _lastOnline; - private ulong? _voiceChannelId; - private Dictionary _roles; - - public DiscordClient Client { get; } - - /// Gets the unique identifier for this user. - public ulong Id { get; } - /// Gets the server this user is a member of. - public Server Server { get; } - - /// Gets the name of this user. - public string Name { get; private set; } - /// Gets an id uniquely identifying from others with the same name. - public ushort Discriminator { get; private set; } - /// Gets the unique identifier for this user's current avatar. - public string AvatarId { get; private set; } - /// Gets the name of the game this user is currently playing. - public string CurrentGame { get; internal set; } - /// Gets the current status for this user. - public UserStatus Status { get; internal set; } - /// Gets the datetime that this user joined this server. - public DateTime JoinedAt { get; private set; } - /// Returns the time this user last sent/edited a message, started typing or sent voice data in this server. - public DateTime? LastActivityAt { get; private set; } - // /// Gets this user's voice session id. - // public string SessionId { get; private set; } - // /// Gets this user's voice token. - // public string Token { get; private set; } - - /// Gets the current private channel for this user if one exists. - public PrivateChannel PrivateChannel => Client.GetPrivateChannel(Id); - /// Returns the string used to mention this user. - public string Mention => $"<@{Id}>"; - public bool IsOwner => Server == null ? false : this == Server.Owner; - /// Returns true if this user has marked themselves as muted. - public bool IsSelfMuted => (_voiceState & VoiceState.SelfMuted) != 0; - /// Returns true if this user has marked themselves as deafened. - public bool IsSelfDeafened => (_voiceState & VoiceState.SelfDeafened) != 0; - /// Returns true if the server is blocking audio from this user. - public bool IsServerMuted => (_voiceState & VoiceState.ServerMuted) != 0; - /// Returns true if the server is blocking audio to this user. - public bool IsServerDeafened => (_voiceState & VoiceState.ServerDeafened) != 0; - /// Returns true if the server is temporarily blocking audio to/from this user. - public bool IsServerSuppressed => (_voiceState & VoiceState.ServerSuppressed) != 0; - /// Returns the time this user was last seen online in this server. - public DateTime? LastOnlineAt => Status != UserStatus.Offline ? DateTime.UtcNow : _lastOnline; - /// Gets this user's current voice channel. - public VoiceChannel VoiceChannel => _voiceChannelId != null ? Server.GetVoiceChannel(_voiceChannelId.Value) : null; - /// Gets the URL to this user's current avatar. - public string AvatarUrl => GetAvatarUrl(Id, AvatarId); - /// Gets all roles that have been assigned to this user, including the everyone role. - public IEnumerable Roles => _roles.Select(x => x.Value); - public ServerPermissions ServerPermissions => Server.GetPermissions(this); - - /// Returns a collection of all channels this user has permissions to join on this server. - public IEnumerable Channels - { - get - { - if (Server != null) - { - if (Client.Config.UsePermissionsCache) - { - return Server.AllChannels.Where(x => - (x.IsText && x.GetPermissions(this).ReadMessages) || - (x.IsVoice && x.GetPermissions(this).Connect)); - } - else - { - ChannelPermissions perms = new ChannelPermissions(); - return Server.AllChannels - .Where(x => - { - x.ResolvePermissions(this, ref perms); - return (x.Type == ChannelType.Text && perms.ReadMessages) || - (x.Type == ChannelType.Voice && perms.Connect); - }); - } - } - else - { - if (this == Client.PrivateUser) - return Client.PrivateChannels; - else - { - var privateChannel = Client.GetPrivateChannel(Id); - if (privateChannel != null) - return new IChannel[] { privateChannel }; - else - return new IChannel[0]; - } - } - } - } - - internal User(ExtendedMember model, DiscordClient client, Server server) - : this(model as APIMember, client, server) - { - if (model.IsServerMuted == true) - _voiceState |= VoiceState.ServerMuted; - else if (model.IsServerMuted == false) - _voiceState &= ~VoiceState.ServerMuted; - - if (model.IsServerDeafened == true) - _voiceState |= VoiceState.ServerDeafened; - else if (model.IsServerDeafened == false) - _voiceState &= ~VoiceState.ServerDeafened; - } - internal User(APIMember model, DiscordClient client, Server server) - : this(model.User.Id, client, server) - { - if (server == null) - UpdateRoles(null); - Update(model); - } - internal User(UserReference model, DiscordClient client, Server server) - : this(model.Id, client, server) - { - if (server == null) - UpdateRoles(null); - Update(model); - } - private User(ulong id, DiscordClient client, Server server) - { - Client = client; - Id = id; - Server = server; - - _roles = new Dictionary(); - Status = UserStatus.Offline; - } - - internal void Update(UserReference model) - { - if (model.Username != null) - Name = model.Username; - if (model.Discriminator != null) - Discriminator = model.Discriminator.Value; - if (model.Avatar != null) - AvatarId = model.Avatar; - } - internal void Update(APIMember model) - { - if (model.User != null) - Update(model.User); - - if (model.JoinedAt.HasValue) - JoinedAt = model.JoinedAt.Value; - if (model.Roles != null) - UpdateRoles(model.Roles.Select(x => Server.GetRole(x))); - } - internal void Update(MemberPresence model) - { - if (model.User != null) - Update(model.User as UserReference); - - if (model.Roles != null) - UpdateRoles(model.Roles.Select(x => Server.GetRole(x))); - if (model.Status != null && Status != model.Status) - { - Status = UserStatus.FromString(model.Status); - if (Status == UserStatus.Offline) - _lastOnline = DateTime.UtcNow; - } - - CurrentGame = model.Game?.Name; //Allows null - } - internal void Update(MemberVoiceState model) - { - if (model.IsSelfMuted == true) - _voiceState |= VoiceState.SelfMuted; - else if (model.IsSelfMuted == false) - _voiceState &= ~VoiceState.SelfMuted; - if (model.IsSelfDeafened == true) - _voiceState |= VoiceState.SelfDeafened; - else if (model.IsSelfDeafened == false) - _voiceState &= ~VoiceState.SelfDeafened; - if (model.IsServerMuted == true) - _voiceState |= VoiceState.ServerMuted; - else if (model.IsServerMuted == false) - _voiceState &= ~VoiceState.ServerMuted; - if (model.IsServerDeafened == true) - _voiceState |= VoiceState.ServerDeafened; - else if (model.IsServerDeafened == false) - _voiceState &= ~VoiceState.ServerDeafened; - if (model.IsServerSuppressed == true) - _voiceState |= VoiceState.ServerSuppressed; - else if (model.IsServerSuppressed == false) - _voiceState &= ~VoiceState.ServerSuppressed; - - /*if (model.SessionId != null) - SessionId = model.SessionId; - if (model.Token != null) - Token = model.Token;*/ - - _voiceChannelId = model.ChannelId; //Allows null - } - - internal void UpdateActivity(DateTime? activity = null) - { - if (LastActivityAt == null || activity > LastActivityAt.Value) - LastActivityAt = activity ?? DateTime.UtcNow; - } - - public Task Edit(bool? isMuted = null, bool? isDeafened = null, Channel voiceChannel = null, IEnumerable roles = null) - { - if (Server == null) throw new InvalidOperationException("Unable to edit users in a private channel"); - - //Modify the roles collection and filter out the everyone role - var roleIds = (roles ?? Roles) - .Where(x => !x.IsEveryone) - .Select(x => x.Id) - .Distinct() - .ToArray(); - - var request = new UpdateMemberRequest(Server.Id, Id) - { - IsMuted = isMuted ?? IsServerMuted, - IsDeafened = isDeafened ?? IsServerDeafened, - VoiceChannelId = voiceChannel?.Id, - RoleIds = roleIds - }; - return Client.ClientAPI.Send(request); - } - - public Task Kick() - { - if (Server == null) throw new InvalidOperationException("Unable to kick users from a private channel"); - - var request = new KickMemberRequest(Server.Id, Id); - return Client.ClientAPI.Send(request); - } - - public ChannelPermissions GetPermissions(PublicChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - return channel.GetPermissions(this); - } - - public Task CreatePMChannel() => Client.CreatePrivateChannel(this); - - private void UpdateRoles(IEnumerable roles) - { - bool updated = false; - var newRoles = new Dictionary(); - - var oldRoles = _roles; - if (roles != null) - { - foreach (var r in roles) - { - if (r != null) - { - newRoles[r.Id] = r; - if (!oldRoles.ContainsKey(r.Id)) - updated = true; //Check for adds - } - } - } - - if (Server != null) - { - var everyone = Server.EveryoneRole; - newRoles[everyone.Id] = everyone; - } - if (oldRoles.Count != newRoles.Count) - updated = true; //Check for removes - - if (updated) - { - _roles = newRoles; - if (Server != null) - Server.UpdatePermissions(this); - } - } - public bool HasRole(Role role) - { - if (role == null) throw new ArgumentNullException(nameof(role)); - - return _roles.ContainsKey(role.Id); - } - - public Task AddRoles(params Role[] roles) => Edit(roles: Roles.Concat(roles)); - public Task AddRoles(IEnumerable roles) => Edit(roles: Roles.Concat(roles)); - public Task RemoveRoles(params Role[] roles) => Edit(roles: Roles.Except(roles)); - public Task RemoveRoles(IEnumerable roles) => Edit(roles: Roles.Except(roles)); - - internal User Clone() - { - var result = new User(Id, Client, Server); - _cloner(this, result); - return result; - } - - public override string ToString() - { - if (Name != null) - return $"{Server?.Name ?? "[Private]"}/{Name}#{Discriminator}"; - else - return $"{Server?.Name ?? "[Private]"}/{Id}"; - } - internal string ToString(IChannel channel) - { - if (Name != null) - return $"{channel}/{Name}#{Discriminator}"; - else - return $"{channel}/{Id}"; - } - } -} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Users/DMUser.cs b/src/Discord.Net/Entities/Users/DMUser.cs new file mode 100644 index 000000000..ed2c7d541 --- /dev/null +++ b/src/Discord.Net/Entities/Users/DMUser.cs @@ -0,0 +1,15 @@ +namespace Discord +{ + public class DMUser : User + { + public DMChannel Channel { get; } + + public override DiscordClient Discord => Channel.Discord; + + internal DMUser(ulong id, DMChannel channel) + : base(id) + { + Channel = channel; + } + } +} diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs new file mode 100644 index 000000000..bc0c8db8c --- /dev/null +++ b/src/Discord.Net/Entities/Users/GuildUser.cs @@ -0,0 +1,48 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.GuildMember; + +namespace Discord +{ + public class GuildUser : User, IMentionable + { + public Guild Guild { get; } + public GuildPresence Presence { get; } + public VoiceState VoiceState { get; } + + /// + public DateTime JoinedAt { get; private set; } + public GuildPermissions GuildPermissions { get; internal set; } + + public override DiscordClient Discord => Guild.Discord; + public IEnumerable TextChannels => Guild.TextChannels.Where(x => GetPermissions(x).ReadMessages); + + internal GuildUser(ulong id, Guild guild, GuildPresence presence, VoiceState voiceState) + : base(id) + { + Guild = guild; + Presence = presence; + VoiceState = voiceState; + } + internal void Update(Model model) + { + base.Update(model.User); + JoinedAt = model.JoinedAt.Value; + } + + public ChannelPermissions GetPermissions(GuildChannel channel) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + return channel.GetPermissions(this); + } + + /// + public override Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet + public Task Kick() => Discord.RestClient.Send(new RemoveGuildMemberRequest(Guild.Id, Id)); + public Task Ban(int pruneDays = 0) => Discord.RestClient.Send(new CreateGuildBanRequest(Guild.Id, Id) { PruneDays = pruneDays }); + public Task Unban() => Discord.RestClient.Send(new RemoveGuildBanRequest(Guild.Id, Id)); + } +} diff --git a/src/Discord.Net/Entities/Users/PublicUser.cs b/src/Discord.Net/Entities/Users/PublicUser.cs new file mode 100644 index 000000000..2ab851a25 --- /dev/null +++ b/src/Discord.Net/Entities/Users/PublicUser.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + public class PublicUser : User + { + public override DiscordClient Discord { get; } + + internal PublicUser(ulong id, DiscordClient discord) + : base(id) + { + Discord = discord; + } + } +} diff --git a/src/Discord.Net/Entities/Users/SelfUser.cs b/src/Discord.Net/Entities/Users/SelfUser.cs new file mode 100644 index 000000000..4174672cf --- /dev/null +++ b/src/Discord.Net/Entities/Users/SelfUser.cs @@ -0,0 +1,26 @@ +using Model = Discord.API.User; + +namespace Discord +{ + public class SelfUser : User + { + public override DiscordClient Discord { get; } + + public string Email { get; private set; } + public bool IsVerified { get; private set; } + + internal SelfUser(ulong id, DiscordClient discord) + : base(id) + { + Discord = discord; + } + + internal override void Update(Model model) + { + base.Update(model); + + Email = model.Email; + IsVerified = model.IsVerified; + } + } +} diff --git a/src/Discord.Net/Entities/Users/User.cs b/src/Discord.Net/Entities/Users/User.cs new file mode 100644 index 000000000..92c5a2773 --- /dev/null +++ b/src/Discord.Net/Entities/Users/User.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.User; + +namespace Discord +{ + public abstract class User : IEntity + { + private string _avatarId; + + /// + public ulong Id { get; } + /// + public abstract DiscordClient Discord { get; } + + public string Username { get; private set; } + public ushort Discriminator { get; private set; } + public bool IsBot { get; private set; } + + public string AvatarUrl => CDN.GetUserAvatarUrl(Id, _avatarId); + public string Mention => MentionHelper.Mention(this); + + internal User(ulong id) + { + Id = id; + } + internal virtual void Update(Model model) + { + Username = model.Username; + Discriminator = model.Discriminator; + IsBot = model.Bot; + _avatarId = model.Avatar; + } + + public virtual Task Update() { throw new NotSupportedException(); } + + public async Task CreateDMChannel() => await Discord.GetOrCreateDMChannel(Id); //TODO: We dont want both this and .Channel to appear on DMUser + } +} diff --git a/src/Discord.Net/Entities/VoiceChannel.cs b/src/Discord.Net/Entities/VoiceChannel.cs deleted file mode 100644 index 5b40a6aad..000000000 --- a/src/Discord.Net/Entities/VoiceChannel.cs +++ /dev/null @@ -1,60 +0,0 @@ -using APIChannel = Discord.API.Client.Channel; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Discord.API.Client.Rest; - -namespace Discord -{ - public class VoiceChannel : PublicChannel, IPublicChannel, IVoiceChannel - { - private readonly static Action _cloner = DynamicIL.CreateCopyMethod(); - - public int Bitrate { get; set; } - - public override ChannelType Type => ChannelType.Public | ChannelType.Voice; - /// Gets a collection of all users currently in this voice channel. - public override IEnumerable Users - { - get - { - if (Client.Config.UsePermissionsCache) - return _permissions.Users.Select(x => x.User).Where(x => x.VoiceChannel == this); - else - return Server.Users.Where(x => x.VoiceChannel == this); - } - } - - internal override MessageManager MessageManager => null; - - internal VoiceChannel(APIChannel model, Server server) - : base(model, server) - { - } - private VoiceChannel(ulong id, Server server) - : base(id, server) - { - } - - - /// Save all changes to this channel. - public override async Task Save() - { - var request = new UpdateChannelRequest(Id) - { - Name = Name, - Position = Position, - Bitrate = Bitrate - }; - await Client.ClientAPI.Send(request).ConfigureAwait(false); - } - - internal override Channel Clone() - { - var result = new VoiceChannel(Id, Server); - _cloner(this, result); - return result; - } - } -} diff --git a/src/Discord.Net/Entities/VoiceRegion.cs b/src/Discord.Net/Entities/VoiceRegion.cs new file mode 100644 index 000000000..bba703240 --- /dev/null +++ b/src/Discord.Net/Entities/VoiceRegion.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.Rest.GetVoiceRegionsResponse; + +namespace Discord +{ + public class VoiceRegion : IEntity + { + /// + public string Id { get; } + /// + public DiscordClient Discord { get; } + + /// Gets the name of this voice region. + public string Name { get; private set; } + /// Returns true if this voice region is exclusive to VIP accounts. + public bool IsVip { get; private set; } + /// Returns true if this voice region is the closest to your machine. + public bool IsOptimal { get; private set; } + /// Gets an example hostname for this voice region. + public string SampleHostname { get; private set; } + /// Gets an example port for this voice region. + public int SamplePort { get; private set; } + + internal VoiceRegion(string id, DiscordClient client) + { + Id = id; + Discord = client; + } + + /// + public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet + + public void Update(Model model) + { + Name = model.Name; + IsVip = model.IsVip; + IsOptimal = model.IsOptimal; + SampleHostname = model.SampleHostname; + SamplePort = model.SamplePort; + } + + public override string ToString() + { + string suffix = ""; + + if (IsVip) + { + if (IsOptimal) + suffix = " (VIP, Optimal)"; + else + suffix = " (VIP)"; + } + else if (IsOptimal) + suffix = " (Optimal)"; + + return Name + suffix; + } + } +} diff --git a/src/Discord.Net/EnumConverters.cs b/src/Discord.Net/EnumConverters.cs deleted file mode 100644 index 7448055f6..000000000 --- a/src/Discord.Net/EnumConverters.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace Discord -{ - public static class EnumConverters - { - public static ChannelType ToChannelType(string value) - { - switch (value) - { - case "text": return ChannelType.Text; - case "voice": return ChannelType.Voice; - default: throw new ArgumentException("Unknown channel type", nameof(value)); - } - } - public static string ToString(ChannelType value) - { - if ((value & ChannelType.Text) != 0) return "text"; - if ((value & ChannelType.Voice) != 0) return "voice"; - throw new ArgumentException("Invalid channel tType", nameof(value)); - } - - public static PermissionTarget ToPermissionTarget(string value) - { - switch (value) - { - case "member": return PermissionTarget.User; - case "role": return PermissionTarget.Role; - default: throw new ArgumentException("Unknown permission target", nameof(value)); - } - } - public static string ToString(PermissionTarget value) - { - switch (value) - { - case PermissionTarget.User: return "member"; - case PermissionTarget.Role: return "role"; - default: throw new ArgumentException("Invalid permission target", nameof(value)); - } - } - } -} diff --git a/src/Discord.Net/Enums/ChannelType.cs b/src/Discord.Net/Enums/ChannelType.cs index 77b0614ea..e6a3a1e00 100644 --- a/src/Discord.Net/Enums/ChannelType.cs +++ b/src/Discord.Net/Enums/ChannelType.cs @@ -1,13 +1,9 @@ -using System; - -namespace Discord +namespace Discord { - [Flags] - public enum ChannelType : byte + public enum ChannelType : byte { - Public = 0x01, - Private = 0x02, - Text = 0x10, - Voice = 0x20 + DM, + Text, + Voice } } diff --git a/src/Discord.Net/Enums/ConnectionState.cs b/src/Discord.Net/Enums/ConnectionState.cs index 42c505ccd..dfd4ac9eb 100644 --- a/src/Discord.Net/Enums/ConnectionState.cs +++ b/src/Discord.Net/Enums/ConnectionState.cs @@ -1,6 +1,6 @@ namespace Discord { - public enum ConnectionState : byte + public enum ConnectionState { Disconnected, Connecting, diff --git a/src/Discord.Net/Enums/ImageType.cs b/src/Discord.Net/Enums/ImageType.cs deleted file mode 100644 index 738c67a3d..000000000 --- a/src/Discord.Net/Enums/ImageType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - public enum ImageType - { - None, - Jpeg, - Png - } -} diff --git a/src/Discord.Net/Enums/LogSeverity.cs b/src/Discord.Net/Enums/LogSeverity.cs index c62d8c250..785b0ef46 100644 --- a/src/Discord.Net/Enums/LogSeverity.cs +++ b/src/Discord.Net/Enums/LogSeverity.cs @@ -1,7 +1,8 @@ namespace Discord { - public enum LogSeverity : byte + public enum LogSeverity { + Critical = 0, Error = 1, Warning = 2, Info = 3, diff --git a/src/Discord.Net/Enums/MessageState.cs b/src/Discord.Net/Enums/MessageState.cs deleted file mode 100644 index 59f65614d..000000000 --- a/src/Discord.Net/Enums/MessageState.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Discord -{ - public enum MessageState : byte - { - /// Message did not originate from this session, or was successfully sent. - Normal = 0, - /// Message is current queued. - Queued, - /// Message was deleted. - Deleted, - /// Message was deleted before it was sent. - Aborted, - /// Message failed to be sent. - Failed, - /// Message has been removed from cache and will no longer receive updates. - Detached - } -} diff --git a/src/Discord.Net/Enums/PermissionBits.cs b/src/Discord.Net/Enums/PermissionBits.cs index 0766dadc4..ac51dfb05 100644 --- a/src/Discord.Net/Enums/PermissionBits.cs +++ b/src/Discord.Net/Enums/PermissionBits.cs @@ -1,6 +1,6 @@ namespace Discord { - internal enum PermissionBits : byte + internal enum PermissionBit : byte { //General CreateInstantInvite = 0, @@ -8,7 +8,7 @@ BanMembers = 2, ManageRolesOrPermissions = 3, ManageChannel = 4, - ManageServer = 5, + ManageGuild = 5, //Text ReadMessages = 10, diff --git a/src/Discord.Net/Enums/PermissionTarget.cs b/src/Discord.Net/Enums/PermissionTarget.cs index d1381a5ec..96595fb69 100644 --- a/src/Discord.Net/Enums/PermissionTarget.cs +++ b/src/Discord.Net/Enums/PermissionTarget.cs @@ -1,8 +1,8 @@ namespace Discord { - public enum PermissionTarget : byte - { - User, - Role + public enum PermissionTarget + { + Role, + User } } diff --git a/src/Discord.Net/Enums/Relative.cs b/src/Discord.Net/Enums/Relative.cs index 4bd44c5ab..aade047d1 100644 --- a/src/Discord.Net/Enums/Relative.cs +++ b/src/Discord.Net/Enums/Relative.cs @@ -2,6 +2,7 @@ { public enum Relative { - Before, After + Before, + After } } diff --git a/src/Discord.Net/Enums/StringEnum.cs b/src/Discord.Net/Enums/StringEnum.cs deleted file mode 100644 index 903bdfdba..000000000 --- a/src/Discord.Net/Enums/StringEnum.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public abstract class StringEnum - { - public string Value { get; } - - protected StringEnum(string value) - { - Value = value; - } - - public override string ToString() => Value; - } -} diff --git a/src/Discord.Net/Enums/UserStatus.cs b/src/Discord.Net/Enums/UserStatus.cs index 80def4234..f2fdfda7c 100644 --- a/src/Discord.Net/Enums/UserStatus.cs +++ b/src/Discord.Net/Enums/UserStatus.cs @@ -1,40 +1,9 @@ namespace Discord { - public class UserStatus : StringEnum - { - /// User is currently online and active. - public static UserStatus Online { get; } = new UserStatus("online"); - /// User is currently online but inactive. - public static UserStatus Idle { get; } = new UserStatus("idle"); - /// User is offline. - public static UserStatus Offline { get; } = new UserStatus("offline"); - - private UserStatus(string value) - : base(value) { } - - public static UserStatus FromString(string value) - { - switch (value) - { - case null: - return null; - case "online": - return Online; - case "idle": - return Idle; - case "offline": - return Offline; - default: - return new UserStatus(value); - } - } - - - public static implicit operator UserStatus(string value) => FromString(value); - public static bool operator ==(UserStatus a, UserStatus b) => ((object)a == null && (object)b == null) || (a?.Equals(b) ?? false); - public static bool operator !=(UserStatus a, UserStatus b) => !(a == b); - public override int GetHashCode() => Value.GetHashCode(); - public override bool Equals(object obj) => (obj as UserStatus)?.Equals(this) ?? false; - public bool Equals(UserStatus type) => type != null && type.Value == Value; + public enum UserStatus + { + Online, + Idle, + Offline } } diff --git a/src/Discord.Net/Events/ChannelEventArgs.cs b/src/Discord.Net/Events/ChannelEventArgs.cs index ac31a27f5..b03db540f 100644 --- a/src/Discord.Net/Events/ChannelEventArgs.cs +++ b/src/Discord.Net/Events/ChannelEventArgs.cs @@ -6,6 +6,9 @@ namespace Discord { public IChannel Channel { get; } - public ChannelEventArgs(IChannel channel) { Channel = channel; } + public ChannelEventArgs(IChannel channel) + { + Channel = channel; + } } } diff --git a/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs b/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs index 138f2dd8e..b4fbc258f 100644 --- a/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs +++ b/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs @@ -1,16 +1,14 @@ -using System; - -namespace Discord +namespace Discord { - public class ChannelUpdatedEventArgs : EventArgs + public class ChannelUpdatedEventArgs : ChannelEventArgs { public IChannel Before { get; } - public IChannel After { get; } + public IChannel After => Channel; public ChannelUpdatedEventArgs(IChannel before, IChannel after) + : base(after) { Before = before; - After = after; } } } diff --git a/src/Discord.Net/Events/CurrentUserEventArgs.cs b/src/Discord.Net/Events/CurrentUserEventArgs.cs new file mode 100644 index 000000000..a947bbfc5 --- /dev/null +++ b/src/Discord.Net/Events/CurrentUserEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord +{ + public class CurrentUserEventArgs : EventArgs + { + public SelfUser CurrentUser { get; } + + public CurrentUserEventArgs(SelfUser currentUser) + { + CurrentUser = currentUser; + } + } +} diff --git a/src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs b/src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs new file mode 100644 index 000000000..4309f0312 --- /dev/null +++ b/src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs @@ -0,0 +1,14 @@ +namespace Discord +{ + public class CurrentUserUpdatedEventArgs : CurrentUserEventArgs + { + public SelfUser Before { get; } + public SelfUser After => CurrentUser; + + public CurrentUserUpdatedEventArgs(SelfUser before, SelfUser after) + : base(after) + { + Before = before; + } + } +} diff --git a/src/Discord.Net/Events/DisconnectedEventArgs.cs b/src/Discord.Net/Events/DisconnectedEventArgs.cs index 87f9ec955..cf7c1bf70 100644 --- a/src/Discord.Net/Events/DisconnectedEventArgs.cs +++ b/src/Discord.Net/Events/DisconnectedEventArgs.cs @@ -7,10 +7,10 @@ namespace Discord public bool WasUnexpected { get; } public Exception Exception { get; } - public DisconnectedEventArgs(bool wasUnexpected, Exception ex) + public DisconnectedEventArgs(bool wasUnexpected, Exception exception = null) { WasUnexpected = wasUnexpected; - Exception = ex; + Exception = exception; } } } diff --git a/src/Discord.Net/Events/GuildEventArgs.cs b/src/Discord.Net/Events/GuildEventArgs.cs new file mode 100644 index 000000000..50625d882 --- /dev/null +++ b/src/Discord.Net/Events/GuildEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord +{ + public class GuildEventArgs : EventArgs + { + public Guild Guild { get; } + + public GuildEventArgs(Guild guild) + { + Guild = guild; + } + } +} diff --git a/src/Discord.Net/Events/GuildUpdatedEventArgs.cs b/src/Discord.Net/Events/GuildUpdatedEventArgs.cs new file mode 100644 index 000000000..9258072f7 --- /dev/null +++ b/src/Discord.Net/Events/GuildUpdatedEventArgs.cs @@ -0,0 +1,14 @@ +namespace Discord +{ + public class GuildUpdatedEventArgs : GuildEventArgs + { + public Guild Before { get; } + public Guild After => Guild; + + public GuildUpdatedEventArgs(Guild before, Guild after) + : base(after) + { + Before = before; + } + } +} diff --git a/src/Discord.Net/Events/LogMessageEventArgs.cs b/src/Discord.Net/Events/LogMessageEventArgs.cs index bd1fa5b93..83de48616 100644 --- a/src/Discord.Net/Events/LogMessageEventArgs.cs +++ b/src/Discord.Net/Events/LogMessageEventArgs.cs @@ -1,4 +1,5 @@ using System; +using System.Text; namespace Discord { @@ -9,12 +10,54 @@ namespace Discord public string Message { get; } public Exception Exception { get; } - public LogMessageEventArgs(LogSeverity severity, string source, string msg, Exception exception) + public LogMessageEventArgs(LogSeverity severity, string source, string message, Exception exception = null) { Severity = severity; Source = source; - Message = msg; + Message = message; Exception = exception; } + + public override string ToString() => ToString(null, true); + + public string ToString(StringBuilder builder = null, bool fullException = true) + { + string sourceName = Source; + string message = Message; + string exMessage = fullException ? Exception?.ToString() : Exception?.Message; + + int maxLength = 1 + (sourceName?.Length ?? 0) + 2 + (message?.Length ?? 0) + 3 + (exMessage?.Length ?? 0); + if (builder == null) + builder = new StringBuilder(maxLength); + else + { + builder.Clear(); + builder.EnsureCapacity(maxLength); + } + + if (sourceName != null) + { + builder.Append('['); + builder.Append(sourceName); + builder.Append("] "); + } + if (!string.IsNullOrEmpty(Message)) + { + for (int i = 0; i < message.Length; i++) + { + //Strip control chars + char c = message[i]; + if (!char.IsControl(c)) + builder.Append(c); + } + } + if (exMessage != null) + { + builder.AppendLine(":"); + builder.Append(exMessage); + } + + return builder.ToString(); + } } } diff --git a/src/Discord.Net/Events/MessageEventArgs.cs b/src/Discord.Net/Events/MessageEventArgs.cs index 76c9455dc..366b16dbb 100644 --- a/src/Discord.Net/Events/MessageEventArgs.cs +++ b/src/Discord.Net/Events/MessageEventArgs.cs @@ -6,10 +6,9 @@ namespace Discord { public Message Message { get; } - public User User => Message.User; - public ITextChannel Channel => Message.Channel; - public Server Server => Message.Server; - - public MessageEventArgs(Message msg) { Message = msg; } + public MessageEventArgs(Message message) + { + Message = message; + } } } diff --git a/src/Discord.Net/Events/MessageUpdatedEventArgs.cs b/src/Discord.Net/Events/MessageUpdatedEventArgs.cs index 1583dc981..318ac9d54 100644 --- a/src/Discord.Net/Events/MessageUpdatedEventArgs.cs +++ b/src/Discord.Net/Events/MessageUpdatedEventArgs.cs @@ -1,20 +1,14 @@ -using System; - -namespace Discord +namespace Discord { - public class MessageUpdatedEventArgs : EventArgs + public class MessageUpdatedEventArgs : MessageEventArgs { public Message Before { get; } - public Message After { get; } - - public User User => After.User; - public ITextChannel Channel => After.Channel; - public Server Server => After.Server; + public Message After => Message; public MessageUpdatedEventArgs(Message before, Message after) + : base(after) { Before = before; - After = after; } } } diff --git a/src/Discord.Net/Events/ProfileUpdatedEventArgs.cs b/src/Discord.Net/Events/ProfileUpdatedEventArgs.cs deleted file mode 100644 index 2365908e8..000000000 --- a/src/Discord.Net/Events/ProfileUpdatedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Discord -{ - public class ProfileUpdatedEventArgs : EventArgs - { - public Profile Before { get; } - public Profile After { get; } - - public ProfileUpdatedEventArgs(Profile before, Profile after) - { - Before = before; - After = after; - } - } -} diff --git a/src/Discord.Net/Events/RoleEventArgs.cs b/src/Discord.Net/Events/RoleEventArgs.cs index 13eb0f7f4..887972ffe 100644 --- a/src/Discord.Net/Events/RoleEventArgs.cs +++ b/src/Discord.Net/Events/RoleEventArgs.cs @@ -6,8 +6,9 @@ namespace Discord { public Role Role { get; } - public Server Server => Role.Server; - - public RoleEventArgs(Role role) { Role = role; } + public RoleEventArgs(Role role) + { + Role = role; + } } } diff --git a/src/Discord.Net/Events/RoleUpdatedEventArgs.cs b/src/Discord.Net/Events/RoleUpdatedEventArgs.cs index 26151c98b..285ab42c5 100644 --- a/src/Discord.Net/Events/RoleUpdatedEventArgs.cs +++ b/src/Discord.Net/Events/RoleUpdatedEventArgs.cs @@ -1,18 +1,14 @@ -using System; - -namespace Discord +namespace Discord { - public class RoleUpdatedEventArgs : EventArgs + public class RoleUpdatedEventArgs : RoleEventArgs { public Role Before { get; } - public Role After { get; } - - public Server Server => After.Server; + public Role After => Role; public RoleUpdatedEventArgs(Role before, Role after) + : base(after) { Before = before; - After = after; } } } diff --git a/src/Discord.Net/Events/ServerEventArgs.cs b/src/Discord.Net/Events/ServerEventArgs.cs deleted file mode 100644 index e9e564e1b..000000000 --- a/src/Discord.Net/Events/ServerEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Discord -{ - public class ServerEventArgs : EventArgs - { - public Server Server { get; } - - public ServerEventArgs(Server server) { Server = server; } - } -} diff --git a/src/Discord.Net/Events/ServerUpdatedEventArgs.cs b/src/Discord.Net/Events/ServerUpdatedEventArgs.cs deleted file mode 100644 index 8532f72dc..000000000 --- a/src/Discord.Net/Events/ServerUpdatedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Discord -{ - public class ServerUpdatedEventArgs : EventArgs - { - public Server Before { get; } - public Server After { get; } - - public ServerUpdatedEventArgs(Server before, Server after) - { - Before = before; - After = after; - } - } -} diff --git a/src/Discord.Net/Events/TypingEventArgs.cs b/src/Discord.Net/Events/TypingEventArgs.cs index 73d47f688..797d0d9d6 100644 --- a/src/Discord.Net/Events/TypingEventArgs.cs +++ b/src/Discord.Net/Events/TypingEventArgs.cs @@ -1,11 +1,13 @@ -namespace Discord +using System; + +namespace Discord { - public class TypingEventArgs + public class TypingEventArgs : EventArgs { - public ITextChannel Channel { get; } + public IMessageChannel Channel { get; } public User User { get; } - public TypingEventArgs(ITextChannel channel, User user) + public TypingEventArgs(IMessageChannel channel, User user) { Channel = channel; User = user; diff --git a/src/Discord.Net/Events/UserEventArgs.cs b/src/Discord.Net/Events/UserEventArgs.cs index bf7dd2cac..6bbcaef01 100644 --- a/src/Discord.Net/Events/UserEventArgs.cs +++ b/src/Discord.Net/Events/UserEventArgs.cs @@ -1,12 +1,14 @@ using System; + namespace Discord { public class UserEventArgs : EventArgs { public User User { get; } - public Server Server => User.Server; - - public UserEventArgs(User user) { User = user; } + public UserEventArgs(User user) + { + User = user; + } } } diff --git a/src/Discord.Net/Events/UserUpdatedEventArgs.cs b/src/Discord.Net/Events/UserUpdatedEventArgs.cs index 89e8cce0c..35b68bc55 100644 --- a/src/Discord.Net/Events/UserUpdatedEventArgs.cs +++ b/src/Discord.Net/Events/UserUpdatedEventArgs.cs @@ -1,17 +1,14 @@ -using System; -namespace Discord +namespace Discord { - public class UserUpdatedEventArgs : EventArgs + public class UserUpdatedEventArgs : UserEventArgs { public User Before { get; } - public User After { get; } - - public Server Server => After.Server; + public User After => User; public UserUpdatedEventArgs(User before, User after) + : base(after) { Before = before; - After = after; } } } diff --git a/src/Discord.Net/Events/VoiceChannelEventArgs.cs b/src/Discord.Net/Events/VoiceChannelEventArgs.cs new file mode 100644 index 000000000..78d519d2f --- /dev/null +++ b/src/Discord.Net/Events/VoiceChannelEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord +{ + public class VoiceChannelEventArgs : EventArgs + { + public VoiceChannel Channel { get; } + + public VoiceChannelEventArgs(VoiceChannel channel) + { + Channel = channel; + } + } +} diff --git a/src/Discord.Net/Format.cs b/src/Discord.Net/Format.cs index 0ff7e0a4f..1e8ae00b9 100644 --- a/src/Discord.Net/Format.cs +++ b/src/Discord.Net/Format.cs @@ -2,109 +2,104 @@ namespace Discord { - public static class Format - { - private static readonly string[] _patterns; - private static readonly StringBuilder _builder; + public static class Format + { + private static readonly string[] _patterns = new string[] { "__", "_", "**", "*", "~~", "```", "`" }; + private static readonly StringBuilder _builder = new StringBuilder(DiscordConfig.MaxMessageSize); - static Format() - { - _patterns = new string[] { "__", "_", "**", "*", "~~", "```", "`"}; - _builder = new StringBuilder(DiscordConfig.MaxMessageSize); - } - - /// Removes all special formatting characters from the provided text. - public static string Escape(string text) - { - lock (_builder) - { - _builder.Clear(); + /// Removes all special formatting characters from the provided text. + public static string Escape(string text) + { + //TODO: Fix me + lock (_builder) + { + _builder.Clear(); - //Escape all backslashes - for (int i = 0; i < text.Length; i++) - { - _builder.Append(text[i]); - if (text[i] == '\\') - _builder.Append('\\'); - } + //Escape all backslashes + for (int i = 0; i < text.Length; i++) + { + _builder.Append(text[i]); + if (text[i] == '\\') + _builder.Append('\\'); + } - EscapeSubstring(0, _builder.Length); + EscapeSubstring(0, _builder.Length); - return _builder.ToString(); - } - } - private static int EscapeSubstring(int start, int end) - { - int totalAddedChars = 0; - for (int i = start; i < end + totalAddedChars; i++) - { - for (int p = 0; p < _patterns.Length; p++) - { - string pattern = _patterns[p]; - if (i + pattern.Length * 2 > _builder.Length) - continue; - int s = FindPattern(pattern, i, i + 1); - if (s == -1) continue; - int e = FindPattern(pattern, i + 1, end + totalAddedChars); - if (e == -1) continue; + return _builder.ToString(); + } + } + private static int EscapeSubstring(int start, int end) + { + int totalAddedChars = 0; + for (int i = start; i < end + totalAddedChars; i++) + { + for (int p = 0; p < _patterns.Length; p++) + { + string pattern = _patterns[p]; + if (i + pattern.Length * 2 > _builder.Length) + continue; + int s = FindPattern(pattern, i, i + 1); + if (s == -1) continue; + int e = FindPattern(pattern, i + 1, end + totalAddedChars); + if (e == -1) continue; - if (e - s - pattern.Length > 0) - { - //By going right to left, we dont need to adjust any offsets - for (int k = pattern.Length - 1; k >= 0; k--) - _builder.Insert(e + k, '\\'); - for (int k = pattern.Length - 1; k >= 0; k--) - _builder.Insert(s + k, '\\'); + if (e - s - pattern.Length > 0) + { + //By going right to left, we dont need to adjust any offsets + for (int k = pattern.Length - 1; k >= 0; k--) + _builder.Insert(e + k, '\\'); + for (int k = pattern.Length - 1; k >= 0; k--) + _builder.Insert(s + k, '\\'); int addedChars = pattern.Length * 2; - addedChars += EscapeSubstring(s + pattern.Length * 2, e + pattern.Length); - i = e + addedChars + pattern.Length - 1; - totalAddedChars += addedChars; - break; + addedChars += EscapeSubstring(s + pattern.Length * 2, e + pattern.Length); + i = e + addedChars + pattern.Length - 1; + totalAddedChars += addedChars; + break; } - } - } - return totalAddedChars; - } - private static int FindPattern(string pattern, int start, int end) - { - for (int j = start; j < end; j++) - { - if (_builder[j] == '\\') - { - j++; - continue; - } - for (int k = 0; k < pattern.Length; k++) - { - if (_builder[j + k] != pattern[k]) - goto nextpos; - } - return j; - nextpos:; - } - return -1; - } - - /// Returns a markdown-formatted string with bold formatting, optionally escaping the contents. - public static string Bold(string text, bool escape = true) - => escape ? $"**{Escape(text)}**" : $"**{text}**"; - /// Returns a markdown-formatted string with italics formatting, optionally escaping the contents. - public static string Italics(string text, bool escape = true) - => escape ? $"*{Escape(text)}*" : $"*{text}*"; - /// Returns a markdown-formatted string with underline formatting, optionally escaping the contents. - public static string Underline(string text, bool escape = true) - => escape ? $"__{Escape(text)}__" : $"__{text}__"; - /// Returns a markdown-formatted string with strikeout formatting, optionally escaping the contents. - public static string Strikeout(string text, bool escape = true) - => escape ? $"~~{Escape(text)}~~" : $"~~{text}~~"; + } + } + return totalAddedChars; + } + private static int FindPattern(string pattern, int start, int end) + { + for (int j = start; j < end; j++) + { + if (_builder[j] == '\\') + { + j++; + continue; + } + for (int k = 0; k < pattern.Length; k++) + { + if (_builder[j + k] != pattern[k]) + goto nextpos; + } + return j; + nextpos:; + } + return -1; + } + + /// Returns a markdown-formatted string with bold formatting, optionally escaping the contents. + public static string Bold(string text, bool escape = true) + => escape ? $"**{Escape(text)}**" : $"**{text}**"; + /// Returns a markdown-formatted string with italics formatting, optionally escaping the contents. + public static string Italics(string text, bool escape = true) + => escape ? $"*{Escape(text)}*" : $"*{text}*"; + /// Returns a markdown-formatted string with underline formatting, optionally escaping the contents. + public static string Underline(string text, bool escape = true) + => escape ? $"__{Escape(text)}__" : $"__{text}__"; + /// Returns a markdown-formatted string with strikeout formatting, optionally escaping the contents. + public static string Strikeout(string text, bool escape = true) + => escape ? $"~~{Escape(text)}~~" : $"~~{text}~~"; - /// Returns a markdown-formatted string with strikeout formatting, optionally escaping the contents. - public static string Code(string text, string language = null) - { - if (language != null || text.Contains("\n")) - return $"```{language ?? ""}\n{text}\n```"; - else - return $"`{text}`"; - } - } + /// Returns a markdown-formatted string with strikeout formatting, optionally escaping the contents. + public static string Code(string text, string language = null) + { + if (language != null || text.Contains("\n")) + return $"```{language ?? ""}\n{text}\n```"; + else + return $"`{text}`"; + } + } } diff --git a/src/Discord.Net/IMentionable.cs b/src/Discord.Net/IMentionable.cs deleted file mode 100644 index 0a4bf439c..000000000 --- a/src/Discord.Net/IMentionable.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord -{ - public interface IMentionable - { - string Mention { get; } - } -} diff --git a/src/Discord.Net/IModel.cs b/src/Discord.Net/IModel.cs deleted file mode 100644 index 8a86ceb3d..000000000 --- a/src/Discord.Net/IModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - public interface IModel - { - ulong Id { get; } - - Task Save(); - } -} diff --git a/src/Discord.Net/IService.cs b/src/Discord.Net/IService.cs deleted file mode 100644 index 15f79b0c4..000000000 --- a/src/Discord.Net/IService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord -{ - public interface IService - { - void Install(DiscordClient client); - } -} diff --git a/src/Discord.Net/InternalExtensions.cs b/src/Discord.Net/InternalExtensions.cs index 676f0f8e6..6b8342e57 100644 --- a/src/Discord.Net/InternalExtensions.cs +++ b/src/Discord.Net/InternalExtensions.cs @@ -1,75 +1,22 @@ -using System; -using System.Collections.Concurrent; -using System.Globalization; -using System.IO; -using System.Runtime.CompilerServices; - -namespace Discord +namespace Discord { internal static class InternalExtensions { - internal static readonly IFormatProvider _format = CultureInfo.InvariantCulture; - - public static ulong ToId(this string value) => ulong.Parse(value, NumberStyles.None, _format); - public static ulong? ToNullableId(this string value) => value == null ? (ulong?)null : ulong.Parse(value, NumberStyles.None, _format); - public static bool TryToId(this string value, out ulong result) => ulong.TryParse(value, NumberStyles.None, _format, out result); - - public static string ToIdString(this ulong value) => value.ToString(_format); - public static string ToIdString(this ulong? value) => value?.ToString(_format); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HasBit(this uint rawValue, byte bit) => ((rawValue >> bit) & 1U) == 1; - - public static bool TryGetOrAdd(this ConcurrentDictionary d, - TKey key, Func factory, out TValue result) - { - bool created = false; - TValue newValue = default(TValue); - while (true) - { - if (d.TryGetValue(key, out result)) - return false; - if (!created) - { - newValue = factory(key); - created = true; - } - if (d.TryAdd(key, newValue)) - { - result = newValue; - return true; - } - } - } - public static bool TryGetOrAdd(this ConcurrentDictionary d, - TKey key, TValue value, out TValue result) + public static User GetCurrentUser(this IChannel channel) { - while (true) + switch (channel.Type) { - if (d.TryGetValue(key, out result)) - return false; - if (d.TryAdd(key, value)) - { - result = value; - return true; - } + case ChannelType.Text: + case ChannelType.Voice: + return (channel as GuildChannel).Guild.CurrentUser; + default: + return channel.Discord.CurrentUser; } } - public static string Base64(this Stream stream, ImageType type, string existingId) - { - if (type == ImageType.None) - return null; - else if (stream != null) - { - byte[] bytes = new byte[stream.Length - stream.Position]; - stream.Read(bytes, 0, bytes.Length); - - string base64 = Convert.ToBase64String(bytes); - string imageType = type == ImageType.Jpeg ? "image/jpeg;base64" : "image/png;base64"; - return $"data:{imageType},{base64}"; - } - return existingId; - } +/*#if NETSTANDARD1_2 + //https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/DateTimeOffset.cs + public static long ToUnixTimeMilliseconds(this DateTimeOffset dto) => (dto.UtcDateTime.Ticks / TimeSpan.TicksPerMillisecond) - 62135596800000; +#endif*/ } } diff --git a/src/Discord.Net/Logging/ILogger.cs b/src/Discord.Net/Logging/ILogger.cs deleted file mode 100644 index abc713cc2..000000000 --- a/src/Discord.Net/Logging/ILogger.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace Discord.Logging -{ - public interface ILogger - { - LogSeverity Level { get; } - - void Log(LogSeverity severity, string message, Exception exception = null); -#if DOTNET5_4 - void Log(LogSeverity severity, FormattableString message, Exception exception = null); -#endif - - void Error(string message, Exception exception = null); -#if DOTNET5_4 - void Error(FormattableString message, Exception exception = null); -#endif - void Error(Exception exception); - - void Warning(string message, Exception exception = null); -#if DOTNET5_4 - void Warning(FormattableString message, Exception exception = null); -#endif - void Warning(Exception exception); - - void Info(string message, Exception exception = null); -#if DOTNET5_4 - void Info(FormattableString message, Exception exception = null); -#endif - void Info(Exception exception); - - void Verbose(string message, Exception exception = null); -#if DOTNET5_4 - void Verbose(FormattableString message, Exception exception = null); -#endif - void Verbose(Exception exception); - - void Debug(string message, Exception exception = null); -#if DOTNET5_4 - void Debug(FormattableString message, Exception exception = null); -#endif - void Debug(Exception exception); - } -} diff --git a/src/Discord.Net/Logging/LogManager.cs b/src/Discord.Net/Logging/LogManager.cs index 2abc4f10d..d6cc5f435 100644 --- a/src/Discord.Net/Logging/LogManager.cs +++ b/src/Discord.Net/Logging/LogManager.cs @@ -4,72 +4,61 @@ namespace Discord.Logging { public class LogManager { - private readonly DiscordClient _client; - public LogSeverity Level { get; } public event EventHandler Message = delegate { }; - internal LogManager(DiscordClient client) - { - _client = client; - Level = client.Config.LogLevel; + internal LogManager(LogSeverity minSeverity) + { + Level = minSeverity; } public void Log(LogSeverity severity, string source, string message, Exception exception = null) { if (severity <= Level) - { - try { Message(this, new LogMessageEventArgs(severity, source, message, exception)); } - catch { } //We dont want to log on log errors - } + Message(this, new LogMessageEventArgs(severity, source, message, exception)); } - -#if DOTNET5_4 public void Log(LogSeverity severity, string source, FormattableString message, Exception exception = null) { if (severity <= Level) - { - try { Message(this, new LogMessageEventArgs(severity, source, message.ToString(), exception)); } - catch { } //We dont want to log on log errors - } + Message(this, new LogMessageEventArgs(severity, source, message.ToString(), exception)); } -#endif public void Error(string source, string message, Exception ex = null) => Log(LogSeverity.Error, source, message, ex); + public void Error(string source, FormattableString message, Exception ex = null) + => Log(LogSeverity.Error, source, message, ex); public void Error(string source, Exception ex) => Log(LogSeverity.Error, source, (string)null, ex); + public void Warning(string source, string message, Exception ex = null) => Log(LogSeverity.Warning, source, message, ex); + public void Warning(string source, FormattableString message, Exception ex = null) + => Log(LogSeverity.Warning, source, message, ex); public void Warning(string source, Exception ex) => Log(LogSeverity.Warning, source, (string)null, ex); + public void Info(string source, string message, Exception ex = null) => Log(LogSeverity.Info, source, message, ex); + public void Info(string source, FormattableString message, Exception ex = null) + => Log(LogSeverity.Info, source, message, ex); public void Info(string source, Exception ex) => Log(LogSeverity.Info, source, (string)null, ex); + public void Verbose(string source, string message, Exception ex = null) => Log(LogSeverity.Verbose, source, message, ex); + public void Verbose(string source, FormattableString message, Exception ex = null) + => Log(LogSeverity.Verbose, source, message, ex); public void Verbose(string source, Exception ex) => Log(LogSeverity.Verbose, source, (string)null, ex); + public void Debug(string source, string message, Exception ex = null) => Log(LogSeverity.Debug, source, message, ex); - public void Debug(string source, Exception ex) - => Log(LogSeverity.Debug, source, (string)null, ex); - -#if DOTNET5_4 - public void Error(string source, FormattableString message, Exception ex = null) - => Log(LogSeverity.Error, source, message, ex); - public void Warning(string source, FormattableString message, Exception ex = null) - => Log(LogSeverity.Warning, source, message, ex); - public void Info(string source, FormattableString message, Exception ex = null) - => Log(LogSeverity.Info, source, message, ex); - public void Verbose(string source, FormattableString message, Exception ex = null) - => Log(LogSeverity.Verbose, source, message, ex); public void Debug(string source, FormattableString message, Exception ex = null) => Log(LogSeverity.Debug, source, message, ex); -#endif + public void Debug(string source, Exception ex) + => Log(LogSeverity.Debug, source, (string)null, ex); - public Logger CreateLogger(string name) => new Logger(this, name); + internal Logger CreateLogger(string name) => new Logger(this, name); } } diff --git a/src/Discord.Net/Logging/Logger.cs b/src/Discord.Net/Logging/Logger.cs index 59d591163..f64520591 100644 --- a/src/Discord.Net/Logging/Logger.cs +++ b/src/Discord.Net/Logging/Logger.cs @@ -2,7 +2,7 @@ namespace Discord.Logging { - public class Logger : ILogger + public class Logger { private readonly LogManager _manager; @@ -17,40 +17,42 @@ namespace Discord.Logging public void Log(LogSeverity severity, string message, Exception exception = null) => _manager.Log(severity, Name, message, exception); + public void Log(LogSeverity severity, FormattableString message, Exception exception = null) + => _manager.Log(severity, Name, message, exception); + public void Error(string message, Exception exception = null) => _manager.Error(Name, message, exception); + public void Error(FormattableString message, Exception exception = null) + => _manager.Error(Name, message, exception); public void Error(Exception exception) => _manager.Error(Name, exception); + public void Warning(string message, Exception exception = null) => _manager.Warning(Name, message, exception); + public void Warning(FormattableString message, Exception exception = null) + => _manager.Warning(Name, message, exception); public void Warning(Exception exception) => _manager.Warning(Name, exception); + public void Info(string message, Exception exception = null) => _manager.Info(Name, message, exception); + public void Info(FormattableString message, Exception exception = null) + => _manager.Info(Name, message, exception); public void Info(Exception exception) => _manager.Info(Name, exception); + public void Verbose(string message, Exception exception = null) => _manager.Verbose(Name, message, exception); + public void Verbose(FormattableString message, Exception exception = null) + => _manager.Verbose(Name, message, exception); public void Verbose(Exception exception) => _manager.Verbose(Name, exception); + public void Debug(string message, Exception exception = null) => _manager.Debug(Name, message, exception); - public void Debug(Exception exception) - => _manager.Debug(Name, exception); - -#if DOTNET5_4 - public void Log(LogSeverity severity, FormattableString message, Exception exception = null) - => _manager.Log(severity, Name, message, exception); - public void Error(FormattableString message, Exception exception = null) - => _manager.Error(Name, message, exception); - public void Warning(FormattableString message, Exception exception = null) - => _manager.Warning(Name, message, exception); - public void Info(FormattableString message, Exception exception = null) - => _manager.Info(Name, message, exception); - public void Verbose(FormattableString message, Exception exception = null) - => _manager.Verbose(Name, message, exception); public void Debug(FormattableString message, Exception exception = null) => _manager.Debug(Name, message, exception); -#endif + public void Debug(Exception exception) + => _manager.Debug(Name, exception); } } diff --git a/src/Discord.Net/MessageQueue.cs b/src/Discord.Net/MessageQueue.cs index c1a0948b0..cdbbcc251 100644 --- a/src/Discord.Net/MessageQueue.cs +++ b/src/Discord.Net/MessageQueue.cs @@ -1,5 +1,6 @@ -using Discord.API.Client.Rest; +using Discord.API.Rest; using Discord.Logging; +using Discord.Net; using Discord.Net.Rest; using System; using System.Collections.Concurrent; @@ -7,203 +8,242 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -namespace Discord.Net + +namespace Discord { /// Manages an outgoing message queue for DiscordClient. - public class MessageQueue + public class MessageQueue : IDisposable { + private struct MessageSend + { + public readonly TaskCompletionSource Promise; + public readonly IMessageChannel Channel; + public readonly bool IsTTS; + public readonly string Text; + + public MessageSend(TaskCompletionSource promise, IMessageChannel channel, bool isTTS, string text) + { + Promise = promise; + Channel = channel; + IsTTS = isTTS; + Text = text; + } + } private struct MessageEdit { + public readonly TaskCompletionSource Promise; public readonly Message Message; public readonly string NewText; - public MessageEdit(Message message, string newText) + public MessageEdit(TaskCompletionSource promise, Message message, string newText) { + Promise = promise; Message = message; NewText = newText; } } + private struct MessageDelete + { + public readonly TaskCompletionSource Promise; + public readonly Message Message; - private const int WarningStart = 30; + public MessageDelete(TaskCompletionSource promise, Message message) + { + Promise = promise; + Message = message; + } + } - private readonly Random _nonceRand; + private const int WarningStart = 30; + private readonly RestClient _rest; private readonly Logger _logger; - private readonly ConcurrentQueue _pendingSends; + private readonly ConcurrentQueue _pendingSends; private readonly ConcurrentQueue _pendingEdits; - private readonly ConcurrentQueue _pendingDeletes; - private readonly ConcurrentDictionary _pendingSendsByNonce; + private readonly ConcurrentQueue _pendingDeletes; + private readonly SemaphoreSlim _connectionLock; private int _count, _nextWarning; + private Task[] _tasks; + private bool _isDisposed = false; /// Gets the current number of queued actions. public int Count => _count; - /// Gets the current number of queued sends. - public int SendCount => _pendingSends.Count; - /// Gets the current number of queued edits. - public int EditCount => _pendingEdits.Count; - /// Gets the current number of queued deletes. - public int DeleteCount => _pendingDeletes.Count; internal MessageQueue(RestClient rest, Logger logger) { _rest = rest; _logger = logger; _nextWarning = WarningStart; - - _nonceRand = new Random(); - _pendingSends = new ConcurrentQueue(); + + _connectionLock = new SemaphoreSlim(1, 1); + _pendingSends = new ConcurrentQueue(); _pendingEdits = new ConcurrentQueue(); - _pendingDeletes = new ConcurrentQueue(); - _pendingSendsByNonce = new ConcurrentDictionary(); + _pendingDeletes = new ConcurrentQueue(); } - - internal Message QueueSend(ITextChannel channel, string text, bool isTTS) - { - Message msg = new Message(0, channel, (channel as Channel).CurrentUser); - msg.IsTTS = isTTS; - msg.RawText = text; - msg.Text = Message.ResolveMentions(msg.Channel, msg.Text); - msg.Nonce = GenerateNonce(); - if (_pendingSendsByNonce.TryAdd(msg.Nonce, text)) - { - msg.State = MessageState.Queued; - IncrementCount(); - _pendingSends.Enqueue(msg); - } - else - msg.State = MessageState.Failed; - return msg; - } - internal void QueueEdit(Message msg, string text) + protected virtual void Dispose(bool disposing) { - string msgText = msg.RawText; - if (msg.State == MessageState.Queued && _pendingSendsByNonce.TryUpdate(msg.Nonce, text, msgText)) + if (!_isDisposed) { - //Successfully edited the message before it was sent. - return; + if (disposing) + _connectionLock.Dispose(); + _isDisposed = true; } - IncrementCount(); - _pendingEdits.Enqueue(new MessageEdit(msg, text)); } - internal void QueueDelete(Message msg) + public void Dispose() => Dispose(true); + + internal async Task Start(CancellationToken cancelToken) { - string ignored; - if (msg.State == MessageState.Queued && _pendingSendsByNonce.TryRemove(msg.Nonce, out ignored)) + await _connectionLock.WaitAsync().ConfigureAwait(false); + try { - //Successfully stopped the message from being sent - msg.State = MessageState.Aborted; - return; + await StartInternal(cancelToken).ConfigureAwait(false); } - IncrementCount(); - _pendingDeletes.Enqueue(msg); + finally { _connectionLock.Release(); } } - - internal Task[] Run(CancellationToken cancelToken) + internal async Task StartInternal(CancellationToken cancelToken) { - return new[] + await StopInternal().ConfigureAwait(false); + + _tasks = new Task[] { RunSendQueue(cancelToken), RunEditQueue(cancelToken), RunDeleteQueue(cancelToken) }; } + internal async Task Stop() + { + await _connectionLock.WaitAsync().ConfigureAwait(false); + try + { + await StopInternal().ConfigureAwait(false); + } + finally { _connectionLock.Release(); } + } + private async Task StopInternal() + { + if (_tasks != null) + { + await Task.WhenAll(_tasks).ConfigureAwait(false); + _tasks = null; + } + } + + internal Task QueueSend(IMessageChannel channel, string text, bool isTTS) + { + var promise = new TaskCompletionSource(); + IncrementCount(); + _pendingSends.Enqueue(new MessageSend(promise, channel, isTTS, text)); + return promise.Task; + } + internal Task QueueEdit(Message msg, string text) + { + var promise = new TaskCompletionSource(); + IncrementCount(); + _pendingEdits.Enqueue(new MessageEdit(promise, msg, text)); + return promise.Task; + } + internal Task QueueDelete(Message msg) + { + var promise = new TaskCompletionSource(); + IncrementCount(); + _pendingDeletes.Enqueue(new MessageDelete(promise, msg)); + return promise.Task; + } + private Task RunSendQueue(CancellationToken cancelToken) { return Task.Run(async () => { - while (!cancelToken.IsCancellationRequested) + try { - Message msg; - while (_pendingSends.TryDequeue(out msg)) + while (!cancelToken.IsCancellationRequested) { - DecrementCount(); - string text; - if (_pendingSendsByNonce.TryRemove(msg.Nonce, out text)) //If it was deleted from queue, this will fail + MessageSend item; + while (_pendingSends.TryDequeue(out item)) { try { - //msg.RawText = text; - //msg.Text = Message.ResolveMentions(msg.Channel, text); - var request = new SendMessageRequest(msg.Channel.Id) + var request = new CreateMessageRequest(item.Channel.Id) { - Content = text, - Nonce = msg.Nonce.ToString(), - IsTTS = msg.IsTTS + Content = item.Text, + IsTTS = item.IsTTS }; var response = await _rest.Send(request).ConfigureAwait(false); - msg.Id = response.Id; - msg.State = MessageState.Normal; - msg.Update(response); - } - catch (Exception ex) - { - msg.State = MessageState.Failed; - _logger.Error($"Failed to send message to {msg.Channel}", ex); + item.Promise.SetResult(item.Channel.Discord.CreateMessage(item.Channel, item.Channel.GetCurrentUser(), response)); } + catch (Exception ex) { item.Promise.SetException(ex); } + DecrementCount(); } + await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); } - await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); } + catch (OperationCanceledException) { } }); } private Task RunEditQueue(CancellationToken cancelToken) { return Task.Run(async () => { - while (!cancelToken.IsCancellationRequested) + try { - MessageEdit edit; - while (_pendingEdits.TryPeek(out edit) && edit.Message.State != MessageState.Queued) + while (!cancelToken.IsCancellationRequested) { - if (_pendingEdits.TryDequeue(out edit)) + MessageEdit item; + while (_pendingEdits.TryDequeue(out item)) { - DecrementCount(); - if (edit.Message.State == MessageState.Normal) - { + var msg = item.Message; + //if (msg.State != EntityState.Deleted) + //{ try { - var request = new UpdateMessageRequest(edit.Message.Channel.Id, edit.Message.Id) + var request = new UpdateMessageRequest(msg.Channel.Id, msg.Id) { - Content = edit.NewText + Content = item.NewText }; await _rest.Send(request).ConfigureAwait(false); + item.Promise.SetResult(null); } - catch (Exception ex) { _logger.Error($"Failed to edit message {edit.Message}", ex); } - } + catch (Exception ex) { item.Promise.SetException(ex); } + //} + DecrementCount(); } + await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); } - await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); } + catch (OperationCanceledException) { } }); } private Task RunDeleteQueue(CancellationToken cancelToken) { return Task.Run(async () => { - while (!cancelToken.IsCancellationRequested) + try { - Message msg; - while (_pendingDeletes.TryPeek(out msg) && msg.State != MessageState.Queued) + while (!cancelToken.IsCancellationRequested) { - if (_pendingDeletes.TryDequeue(out msg)) + MessageDelete item; + while (_pendingDeletes.TryDequeue(out item)) { - DecrementCount(); - if (msg.State == MessageState.Normal) - { + var msg = item.Message; + //if (msg.State != EntityState.Deleted) + //{ try { var request = new DeleteMessageRequest(msg.Channel.Id, msg.Id); await _rest.Send(request).ConfigureAwait(false); - msg.State = MessageState.Deleted; + item.Promise.SetResult(null); } catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } //Ignore - catch (Exception ex) { _logger.Error($"Failed to delete message {msg}", ex); } - } + catch (Exception ex) { item.Promise.SetException(ex); } + //} + DecrementCount(); } - } - await Task.Delay(Discord.DiscordConfig.MessageQueueInterval).ConfigureAwait(false); + await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); + } } + catch (OperationCanceledException) { } }); } @@ -232,22 +272,16 @@ namespace Discord.Net /// Clears all queued message sends/edits/deletes. public void Clear() { - Message msg; + MessageSend send; MessageEdit edit; + MessageDelete delete; - while (_pendingSends.TryDequeue(out msg)) + while (_pendingSends.TryDequeue(out send)) DecrementCount(); while (_pendingEdits.TryDequeue(out edit)) DecrementCount(); - while (_pendingDeletes.TryDequeue(out msg)) + while (_pendingDeletes.TryDequeue(out delete)) DecrementCount(); - _pendingSendsByNonce.Clear(); - } - - private int GenerateNonce() - { - lock (_nonceRand) - return _nonceRand.Next(1, int.MaxValue); } } } diff --git a/src/Discord.Net/Net/HttpException.cs b/src/Discord.Net/Net/HttpException.cs index 306122ba3..6f53fae19 100644 --- a/src/Discord.Net/Net/HttpException.cs +++ b/src/Discord.Net/Net/HttpException.cs @@ -1,23 +1,17 @@ -using System; +#pragma warning disable CA1032, CA2237 +using System; using System.Net; namespace Discord.Net { -#if NET46 - [Serializable] -#endif - public class HttpException : Exception - { - public HttpStatusCode StatusCode { get; } - - public HttpException(HttpStatusCode statusCode) - : base($"The server responded with error {(int)statusCode} ({statusCode})") - { - StatusCode = statusCode; + public class HttpException : Exception + { + public HttpStatusCode StatusCode { get; } + + public HttpException(HttpStatusCode statusCode) + : base($"The server responded with error {(int)statusCode} ({statusCode})") + { + StatusCode = statusCode; } -#if NET46 - public override void GetObjectData(SerializationInfo info, StreamingContext context) - => base.GetObjectData(info, context); -#endif } } diff --git a/src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs b/src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs new file mode 100644 index 000000000..4299df7bf --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.JsonConverters +{ + public class ChannelTypeConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(ChannelType); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch ((string)reader.Value) + { + case "text": + return ChannelType.Text; + case "voice": + return ChannelType.Voice; + default: + throw new JsonSerializationException("Unknown channel type"); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + switch ((ChannelType)value) + { + case ChannelType.Text: + writer.WriteValue("text"); + break; + case ChannelType.Voice: + writer.WriteValue("voice"); + break; + default: + throw new JsonSerializationException("Invalid channel type"); + } + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/ImageConverter.cs b/src/Discord.Net/Net/JsonConverters/ImageConverter.cs new file mode 100644 index 000000000..bdbfa6915 --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/ImageConverter.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using System; +using System.IO; + +namespace Discord.Net.JsonConverters +{ + public class ImageConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(Stream); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new InvalidOperationException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var stream = value as Stream; + + byte[] bytes = new byte[stream.Length - stream.Position]; + stream.Read(bytes, 0, bytes.Length); + + string base64 = Convert.ToBase64String(bytes); + writer.WriteValue($"data:image/jpeg;base64,{base64}"); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs b/src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs new file mode 100644 index 000000000..33c7c8ce7 --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using System; +using System.Globalization; + +namespace Discord.Net.JsonConverters +{ + public class NullableUInt64Converter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(ulong?); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object value = reader.Value; + if (value != null) + return ulong.Parse((string)value, NumberStyles.None, CultureInfo.InvariantCulture); + else + return null; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + writer.WriteValue(((ulong?)value).Value.ToString(CultureInfo.InvariantCulture)); + else + writer.WriteNull(); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs b/src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs new file mode 100644 index 000000000..21a8ed8db --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.JsonConverters +{ + public class PermissionTargetConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(PermissionTarget); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch ((string)reader.Value) + { + case "member": + return PermissionTarget.User; + case "role": + return PermissionTarget.Role; + default: + throw new JsonSerializationException("Unknown permission target"); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + switch ((PermissionTarget)value) + { + case PermissionTarget.User: + writer.WriteValue("member"); + break; + case PermissionTarget.Role: + writer.WriteValue("role"); + break; + default: + throw new JsonSerializationException("Invalid permission target"); + } + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs b/src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs new file mode 100644 index 000000000..b19b5977b --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.JsonConverters +{ + public class StringEntityConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(IEntity); + public override bool CanRead => false; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new InvalidOperationException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + writer.WriteValue((value as IEntity).Id); + else + writer.WriteNull(); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs b/src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs new file mode 100644 index 000000000..4b03f6fa3 --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Discord.Net.JsonConverters +{ + internal class UInt64ArrayConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var result = new List(); + if (reader.TokenType == JsonToken.StartArray) + { + reader.Read(); + while (reader.TokenType != JsonToken.EndArray) + { + ulong id = ulong.Parse((string)reader.Value, NumberStyles.None, CultureInfo.InvariantCulture); + result.Add(id); + reader.Read(); + } + } + return result.ToArray(); + } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + { + writer.WriteStartArray(); + var a = (ulong[])value; + for (int i = 0; i < a.Length; i++) + writer.WriteValue(a[i].ToString(CultureInfo.InvariantCulture)); + writer.WriteEndArray(); + } + else + writer.WriteNull(); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/UInt64Converter.cs b/src/Discord.Net/Net/JsonConverters/UInt64Converter.cs new file mode 100644 index 000000000..49c21564a --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/UInt64Converter.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; +using System.Globalization; + +namespace Discord.Net.JsonConverters +{ + public class UInt64Converter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(ulong); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return ulong.Parse((string)reader.Value, NumberStyles.None, CultureInfo.InvariantCulture); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(((ulong)value).ToString(CultureInfo.InvariantCulture)); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs b/src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs new file mode 100644 index 000000000..84945a672 --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.JsonConverters +{ + public class UInt64EntityConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(IEntity); + public override bool CanRead => false; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new InvalidOperationException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + writer.WriteValue((value as IEntity).Id); + else + writer.WriteNull(); + } + } +} diff --git a/src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs b/src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs new file mode 100644 index 000000000..a60d75f75 --- /dev/null +++ b/src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs @@ -0,0 +1,45 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.JsonConverters +{ + public class UserStatusConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(UserStatus); + public override bool CanRead => true; + public override bool CanWrite => true; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch ((string)reader.Value) + { + case "online": + return UserStatus.Online; + case "idle": + return UserStatus.Idle; + case "offline": + return UserStatus.Offline; + default: + throw new JsonSerializationException("Unknown user status"); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + switch ((UserStatus)value) + { + case UserStatus.Online: + writer.WriteValue("online"); + break; + case UserStatus.Idle: + writer.WriteValue("idle"); + break; + case UserStatus.Offline: + writer.WriteValue("offline"); + break; + default: + throw new JsonSerializationException("Invalid user status"); + } + } + } +} diff --git a/src/Discord.Net/Net/Rest/BuiltInEngine.cs b/src/Discord.Net/Net/Rest/BuiltInEngine.cs deleted file mode 100644 index 83d12ec50..000000000 --- a/src/Discord.Net/Net/Rest/BuiltInEngine.cs +++ /dev/null @@ -1,145 +0,0 @@ -#if DOTNET5_4 -using Discord.Logging; -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Http; -using System.Net; -using System.Text; -using System.Globalization; -using Nito.AsyncEx; - -namespace Discord.Net.Rest -{ - internal class BuiltInEngine : IRestEngine - { - private const int HR_SECURECHANNELFAILED = -2146233079; - - private readonly DiscordConfig _config; - private readonly HttpClient _client; - private readonly string _baseUrl; - - private readonly AsyncLock _rateLimitLock; - private readonly ILogger _logger; - private DateTime _rateLimitTime; - - - public BuiltInEngine(DiscordConfig config, string baseUrl, ILogger logger) - { - _config = config; - _baseUrl = baseUrl; - _logger = logger; - - _rateLimitLock = new AsyncLock(); - _client = new HttpClient(new HttpClientHandler - { - AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - UseCookies = false, - UseProxy = false, - PreAuthenticate = false //We do auth ourselves - }); - _client.DefaultRequestHeaders.Add("accept", "*/*"); - _client.DefaultRequestHeaders.Add("accept-encoding", "gzip,deflate"); - _client.DefaultRequestHeaders.Add("user-agent", config.UserAgent); - } - - public void SetToken(string token) - { - _client.DefaultRequestHeaders.Remove("authorization"); - if (token != null) - _client.DefaultRequestHeaders.Add("authorization", token); - } - - public async Task Send(string method, string path, string json, CancellationToken cancelToken) - { - using (var request = new HttpRequestMessage(GetMethod(method), _baseUrl + path)) - { - if (json != null) - request.Content = new StringContent(json, Encoding.UTF8, "application/json"); - return await Send(request, cancelToken).ConfigureAwait(false); - } - } - public async Task SendFile(string method, string path, string filename, Stream stream, CancellationToken cancelToken) - { - using (var request = new HttpRequestMessage(GetMethod(method), _baseUrl + path)) - { - var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)); - content.Add(new StreamContent(File.OpenRead(path)), "file", filename); - request.Content = content; - return await Send(request, cancelToken).ConfigureAwait(false); - } - } - private async Task Send(HttpRequestMessage request, CancellationToken cancelToken) - { - int retryCount = 0; - while (true) - { - HttpResponseMessage response; - try - { - response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false); - } - catch (WebException ex) - { - //The request was aborted: Could not create SSL/TLS secure channel. - if (ex.HResult == HR_SECURECHANNELFAILED && retryCount++ < 5) - continue; //Retrying seems to fix this somehow? - throw; - } - - int statusCode = (int)response.StatusCode; - if (statusCode == 429) //Rate limit - { - var retryAfter = response.Headers - .Where(x => x.Key.Equals("Retry-After", StringComparison.OrdinalIgnoreCase)) - .Select(x => x.Value.FirstOrDefault()) - .FirstOrDefault(); - - int milliseconds; - if (retryAfter != null && int.TryParse(retryAfter, out milliseconds)) - { - if (_logger != null) - { - var now = DateTime.UtcNow; - if (now >= _rateLimitTime) - { - using (await _rateLimitLock.LockAsync().ConfigureAwait(false)) - { - if (now >= _rateLimitTime) - { - _rateLimitTime = now.AddMilliseconds(milliseconds); - _logger.Warning($"Rate limit hit, waiting {Math.Round(milliseconds / 1000.0f, 2)} seconds"); - } - } - } - } - await Task.Delay(milliseconds, cancelToken).ConfigureAwait(false); - continue; - } - throw new HttpException(response.StatusCode); - } - else if (statusCode < 200 || statusCode >= 300) //2xx = Success - throw new HttpException(response.StatusCode); - else - return await response.Content.ReadAsStringAsync().ConfigureAwait(false); - } - } - - private static readonly HttpMethod _patch = new HttpMethod("PATCH"); - private HttpMethod GetMethod(string method) - { - switch (method) - { - case "DELETE": return HttpMethod.Delete; - case "GET": return HttpMethod.Get; - case "PATCH": return _patch; - case "POST": return HttpMethod.Post; - case "PUT": return HttpMethod.Put; - default: throw new InvalidOperationException($"Unknown HttpMethod: {method}"); - } - } - } -} -#endif \ No newline at end of file diff --git a/src/Discord.Net/Net/Rest/CompletedRequestEventArgs.cs b/src/Discord.Net/Net/Rest/CompletedRequestEventArgs.cs deleted file mode 100644 index 1bee431b0..000000000 --- a/src/Discord.Net/Net/Rest/CompletedRequestEventArgs.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Discord.API; - -namespace Discord.Net.Rest -{ - public class CompletedRequestEventArgs : RequestEventArgs - { - public object Response { get; set; } - public string ResponseJson { get; set; } - public double Milliseconds { get; set; } - - public CompletedRequestEventArgs(IRestRequest request, object response, string responseJson, double milliseconds) - : base(request) - { - Response = response; - ResponseJson = responseJson; - Milliseconds = milliseconds; - } - } -} diff --git a/src/Discord.Net/Net/Rest/DefaultRestEngine.cs b/src/Discord.Net/Net/Rest/DefaultRestEngine.cs new file mode 100644 index 000000000..84ddfbbeb --- /dev/null +++ b/src/Discord.Net/Net/Rest/DefaultRestEngine.cs @@ -0,0 +1,127 @@ +using Newtonsoft.Json; +using System; +using System.Globalization; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Discord.Net.Rest +{ + public class DefaultRestEngine : IRestEngine + { + private const int HR_SECURECHANNELFAILED = -2146233079; + + protected readonly HttpClient _client; + protected readonly string _baseUrl; + protected readonly CancellationToken _cancelToken; + protected bool _isDisposed; + + public DefaultRestEngine(string baseUrl, CancellationToken cancelToken) + { + _baseUrl = baseUrl; + _cancelToken = cancelToken; + + _client = new HttpClient(new HttpClientHandler + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + UseCookies = false, + UseProxy = false, + PreAuthenticate = false + }); + SetHeader("accept-encoding", "gzip,deflate"); + } + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + _client.Dispose(); + _isDisposed = true; + } + } + public void Dispose() + { + Dispose(true); + } + + public void SetHeader(string key, string value) + { + _client.DefaultRequestHeaders.Remove(key); + _client.DefaultRequestHeaders.Add(key, value); + } + + public async Task Send(IRestRequest request) + { + string uri = Path.Combine(_baseUrl, request.Endpoint); + using (var restRequest = new HttpRequestMessage(GetMethod(request.Method), uri)) + { + object payload = request.Payload; + if (payload != null) + restRequest.Content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + return await SendInternal(restRequest, _cancelToken).ConfigureAwait(false); + } + } + + public async Task Send(IRestFileRequest request) + { + string uri = Path.Combine(_baseUrl, request.Endpoint); + using (var restRequest = new HttpRequestMessage(GetMethod(request.Method), uri)) + { + var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)); + var mpParameters = request.MultipartParameters; + if (mpParameters != null) + { + foreach (var p in mpParameters) + content.Add(new StringContent(p.Value), p.Key); + + } + content.Add(new StreamContent(request.Stream), "file", request.Filename); + restRequest.Content = content; + return await SendInternal(restRequest, _cancelToken).ConfigureAwait(false); + } + } + + private async Task SendInternal(HttpRequestMessage request, CancellationToken cancelToken) + { + int retryCount = 0; + while (true) + { + HttpResponseMessage response; + try + { + response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false); + } + catch (WebException ex) + { + //The request was aborted: Could not create SSL/TLS secure channel. + if (ex.HResult == HR_SECURECHANNELFAILED && retryCount++ < 5) + continue; //Retrying seems to fix this somehow? + throw; + } + + int statusCode = (int)response.StatusCode; + if (statusCode < 200 || statusCode >= 300) //2xx = Success + throw new HttpException(response.StatusCode); + + return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + } + } + + private static readonly HttpMethod _patch = new HttpMethod("PATCH"); + private HttpMethod GetMethod(string method) + { + switch (method) + { + case "DELETE": return HttpMethod.Delete; + case "GET": return HttpMethod.Get; + case "PATCH": return _patch; + case "POST": return HttpMethod.Post; + case "PUT": return HttpMethod.Put; + default: throw new ArgumentOutOfRangeException(nameof(method), $"Unknown HttpMethod: {method}"); + } + } + } +} diff --git a/src/Discord.Net/Net/Rest/ETFRestClient.cs b/src/Discord.Net/Net/Rest/ETFRestClient.cs deleted file mode 100644 index 5a2620e89..000000000 --- a/src/Discord.Net/Net/Rest/ETFRestClient.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Discord.ETF; -using System.IO; -using System; -using Discord.Logging; - -namespace Discord.Net.Rest -{ - public class ETFRestClient : RestClient - { - private readonly ETFWriter _serializer; - - public ETFRestClient(DiscordConfig config, string baseUrl, ILogger logger = null) - : base(config, baseUrl, logger) - { - _serializer = new ETFWriter(new MemoryStream()); - } - - protected override string Serialize(T obj) - { - throw new NotImplementedException(); - } - protected override T Deserialize(string json) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Discord.Net/Net/Rest/IRestEngine.cs b/src/Discord.Net/Net/Rest/IRestEngine.cs index faba37086..e086d79a0 100644 --- a/src/Discord.Net/Net/Rest/IRestEngine.cs +++ b/src/Discord.Net/Net/Rest/IRestEngine.cs @@ -1,13 +1,14 @@ -using System.IO; -using System.Threading; +using System; +using System.IO; using System.Threading.Tasks; namespace Discord.Net.Rest { - internal interface IRestEngine - { - void SetToken(string token); - Task Send(string method, string path, string json, CancellationToken cancelToken); - Task SendFile(string method, string path, string filename, Stream stream, CancellationToken cancelToken); - } + public interface IRestEngine : IDisposable + { + void SetHeader(string key, string value); + + Task Send(IRestRequest request); + Task Send(IRestFileRequest request); + } } diff --git a/ref/Net/Rest/IRestRequest.cs b/src/Discord.Net/Net/Rest/IRestRequest.cs similarity index 53% rename from ref/Net/Rest/IRestRequest.cs rename to src/Discord.Net/Net/Rest/IRestRequest.cs index 9d46e645f..0ec7b9a32 100644 --- a/ref/Net/Rest/IRestRequest.cs +++ b/src/Discord.Net/Net/Rest/IRestRequest.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; namespace Discord.Net.Rest { @@ -8,8 +9,8 @@ namespace Discord.Net.Rest string Endpoint { get; } object Payload { get; } } - public interface IRestRequest : IRestRequest - where ResponseT : class + public interface IRestRequest : IRestRequest + where TResponse : class { } @@ -17,9 +18,10 @@ namespace Discord.Net.Rest { string Filename { get; } Stream Stream { get; } + IReadOnlyList MultipartParameters { get; } } - public interface IRestFileRequest : IRestFileRequest, IRestRequest - where ResponseT : class + public interface IRestFileRequest : IRestFileRequest, IRestRequest + where TResponse : class { } } diff --git a/src/Discord.Net/Net/Rest/JsonRestClient.cs b/src/Discord.Net/Net/Rest/JsonRestClient.cs deleted file mode 100644 index ac18ac823..000000000 --- a/src/Discord.Net/Net/Rest/JsonRestClient.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Discord.Logging; -using Newtonsoft.Json; -#if TEST_RESPONSES -using System; -#endif -using System.IO; - -namespace Discord.Net.Rest -{ - public class JsonRestClient : RestClient - { - private JsonSerializer _serializer; - - public JsonRestClient(DiscordConfig config, string baseUrl, ILogger logger = null) - : base(config, baseUrl, logger) - { - _serializer = new JsonSerializer(); -#if TEST_RESPONSES - _serializer.CheckAdditionalContent = true; - _serializer.MissingMemberHandling = MissingMemberHandling.Error; -#else - _serializer.CheckAdditionalContent = false; - _serializer.MissingMemberHandling = MissingMemberHandling.Ignore; -#endif - } - - protected override string Serialize(T obj) - { - return JsonConvert.SerializeObject(obj); - } - - protected override T Deserialize(string json) - { -#if TEST_RESPONSES - if (string.IsNullOrEmpty(json)) - throw new Exception("API check failed: Response is empty."); -#endif - using (var reader = new JsonTextReader(new StringReader(json))) - return (T)_serializer.Deserialize(reader, typeof(T)); - } - } -} diff --git a/src/Discord.Net/Net/Rest/RequestEventArgs.cs b/src/Discord.Net/Net/Rest/RequestEventArgs.cs deleted file mode 100644 index ce6dadd83..000000000 --- a/src/Discord.Net/Net/Rest/RequestEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Discord.API; -using System; - -namespace Discord.Net.Rest -{ - public class RequestEventArgs : EventArgs - { - public IRestRequest Request { get; set; } - public bool Cancel { get; set; } - - public RequestEventArgs(IRestRequest request) - { - Request = request; - } - } -} diff --git a/src/Discord.Net/Net/Rest/RestClient.cs b/src/Discord.Net/Net/Rest/RestClient.cs index 47853f8a4..592a99d3d 100644 --- a/src/Discord.Net/Net/Rest/RestClient.cs +++ b/src/Discord.Net/Net/Rest/RestClient.cs @@ -1,140 +1,98 @@ -using Discord.API; -using Discord.ETF; -using Discord.Logging; +using Discord.Net.JsonConverters; +using Newtonsoft.Json; using System; using System.Diagnostics; -using System.Threading; +using System.IO; using System.Threading.Tasks; namespace Discord.Net.Rest { - public abstract partial class RestClient - { - private struct RestResults - { - public string Response { get; set; } - public double Milliseconds { get; set; } - - public RestResults(string response, double milliseconds) - { - Response = response; - Milliseconds = milliseconds; - } - } - - public event EventHandler SendingRequest = delegate { }; - public event EventHandler SentRequest = delegate { }; + public class RestClient + { + internal event EventHandler SentRequest; + + private readonly IRestEngine _engine; + private readonly JsonSerializer _serializer; - private bool OnSendingRequest(IRestRequest request) + internal RestClient(IRestEngine engine) { - var eventArgs = new RequestEventArgs(request); - SendingRequest(this, eventArgs); - return !eventArgs.Cancel; + _engine = engine; + _serializer = new JsonSerializer(); + _serializer.Converters.Add(new ChannelTypeConverter()); + _serializer.Converters.Add(new ImageConverter()); + _serializer.Converters.Add(new NullableUInt64Converter()); + _serializer.Converters.Add(new PermissionTargetConverter()); + _serializer.Converters.Add(new StringEntityConverter()); + _serializer.Converters.Add(new UInt64ArrayConverter()); + _serializer.Converters.Add(new UInt64Converter()); + _serializer.Converters.Add(new UInt64EntityConverter()); + _serializer.Converters.Add(new UserStatusConverter()); } - private void OnSentRequest(IRestRequest request, object response, string responseJson, double milliseconds) - => SentRequest(this, new CompletedRequestEventArgs(request, response, responseJson, milliseconds)); - - private readonly DiscordConfig _config; - private readonly IRestEngine _engine; - private readonly ETFWriter _serializer; - private readonly ILogger _logger; - private string _token; + public void Dispose() => _engine.Dispose(); - public CancellationToken CancelToken { get; set; } + public void SetHeader(string key, string value) => _engine.SetHeader(key, value); - public string Token + public async Task Send(IRestRequest request) + where TResponse : class { - get { return _token; } - set - { - _token = value; - _engine.SetToken(value); - } - } - - protected RestClient(DiscordConfig config, string baseUrl, ILogger logger = null) - { - _config = config; - _logger = logger; - -#if !DOTNET5_4 - _engine = new RestSharpEngine(config, baseUrl, logger); -#else - _engine = new BuiltInEngine(config, baseUrl, logger); -#endif - - if (logger != null && logger.Level >= LogSeverity.Verbose) - SentRequest += (s, e) => _logger.Verbose($"{e.Request.Method} {e.Request.Endpoint}: {e.Milliseconds} ms"); - } - - public async Task Send(IRestRequest request) - where ResponseT : class - { if (request == null) throw new ArgumentNullException(nameof(request)); + + var stopwatch = Stopwatch.StartNew(); + Stream response = await _engine.Send(request).ConfigureAwait(false); + TResponse responseObj = Deserialize(response); + stopwatch.Stop(); - if (!OnSendingRequest(request)) throw new OperationCanceledException(); - var results = await Send(request, true).ConfigureAwait(false); - var response = Deserialize(results.Response); - OnSentRequest(request, response, results.Response, results.Milliseconds); - - return response; + SentRequest(this, new SentRequestEventArgs(request, responseObj, ToMilliseconds(stopwatch))); + return responseObj; } public async Task Send(IRestRequest request) { if (request == null) throw new ArgumentNullException(nameof(request)); - if (!OnSendingRequest(request)) throw new OperationCanceledException(); - var results = await Send(request, false).ConfigureAwait(false); - OnSentRequest(request, null, null, results.Milliseconds); + var stopwatch = Stopwatch.StartNew(); + await _engine.Send(request).ConfigureAwait(false); + stopwatch.Stop(); + + SentRequest(this, new SentRequestEventArgs(request, null, ToMilliseconds(stopwatch))); } - public async Task Send(IRestFileRequest request) - where ResponseT : class + public async Task Send(IRestFileRequest request) + where TResponse : class { if (request == null) throw new ArgumentNullException(nameof(request)); - if (!OnSendingRequest(request)) throw new OperationCanceledException(); - var results = await SendFile(request, true).ConfigureAwait(false); - var response = Deserialize(results.Response); - OnSentRequest(request, response, results.Response, results.Milliseconds); + var stopwatch = Stopwatch.StartNew(); + Stream response = await _engine.Send(request).ConfigureAwait(false); + TResponse responseObj = Deserialize(response); + stopwatch.Stop(); - return response; + SentRequest(this, new SentRequestEventArgs(request, responseObj, ToMilliseconds(stopwatch))); + return responseObj; } public async Task Send(IRestFileRequest request) { if (request == null) throw new ArgumentNullException(nameof(request)); - if (!OnSendingRequest(request)) throw new OperationCanceledException(); - var results = await SendFile(request, false).ConfigureAwait(false); - OnSentRequest(request, null, null, results.Milliseconds); - } - - private async Task Send(IRestRequest request, bool hasResponse) - { - object payload = request.Payload; - string requestJson = null; - if (payload != null) - requestJson = Serialize(payload); - - Stopwatch stopwatch = Stopwatch.StartNew(); - string responseJson = await _engine.Send(request.Method, request.Endpoint, requestJson, CancelToken).ConfigureAwait(false); + var stopwatch = Stopwatch.StartNew(); + await _engine.Send(request).ConfigureAwait(false); stopwatch.Stop(); - double milliseconds = Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); - return new RestResults(responseJson, milliseconds); - } - - private async Task SendFile(IRestFileRequest request, bool hasResponse) - { - Stopwatch stopwatch = Stopwatch.StartNew(); - string responseJson = await _engine.SendFile(request.Method, request.Endpoint, request.Filename, request.Stream, CancelToken).ConfigureAwait(false); - stopwatch.Stop(); + SentRequest(this, new SentRequestEventArgs(request, null, ToMilliseconds(stopwatch))); + } - double milliseconds = Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); - return new RestResults(responseJson, milliseconds); + private void Serialize(Stream stream, T value) + { + using (TextWriter text = new StreamWriter(stream)) + using (JsonWriter writer = new JsonTextWriter(text)) + _serializer.Serialize(writer, value, typeof(T)); + } + private T Deserialize(Stream stream) + { + using (TextReader text = new StreamReader(stream)) + using (JsonReader reader = new JsonTextReader(text)) + return _serializer.Deserialize(reader); } - protected abstract string Serialize(T obj); - protected abstract T Deserialize(string json); - } + private static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); + } } diff --git a/src/Discord.Net/Net/Rest/RestClientProvider.cs b/src/Discord.Net/Net/Rest/RestClientProvider.cs new file mode 100644 index 000000000..942720ffb --- /dev/null +++ b/src/Discord.Net/Net/Rest/RestClientProvider.cs @@ -0,0 +1,6 @@ +using System.Threading; + +namespace Discord.Net.Rest +{ + public delegate IRestEngine RestClientProvider(string baseUrl, CancellationToken cancelToken); +} diff --git a/src/Discord.Net/Net/Rest/RestParameter.cs b/src/Discord.Net/Net/Rest/RestParameter.cs new file mode 100644 index 000000000..5fac47bf8 --- /dev/null +++ b/src/Discord.Net/Net/Rest/RestParameter.cs @@ -0,0 +1,19 @@ +namespace Discord.Net.Rest +{ + public struct RestParameter + { + public string Key { get; } + public string Value { get; } + + public RestParameter(string key, string value) + { + Key = key; + Value = value; + } + public RestParameter(string key, object value) + { + Key = key; + Value = value.ToString(); + } + } +} diff --git a/src/Discord.Net/Net/Rest/SentRequestEventArgs.cs b/src/Discord.Net/Net/Rest/SentRequestEventArgs.cs new file mode 100644 index 000000000..25f433d25 --- /dev/null +++ b/src/Discord.Net/Net/Rest/SentRequestEventArgs.cs @@ -0,0 +1,16 @@ +namespace Discord.Net.Rest +{ + public class SentRequestEventArgs + { + public IRestRequest Request { get; } + public object Response { get; } + public double Milliseconds { get; } + + public SentRequestEventArgs(IRestRequest request, object response, double milliseconds) + { + Request = request; + Response = response; + Milliseconds = milliseconds; + } + } +} diff --git a/src/Discord.Net/Net/Rest/SharpRestEngine.cs b/src/Discord.Net/Net/Rest/SharpRestEngine.cs deleted file mode 100644 index f9c54064b..000000000 --- a/src/Discord.Net/Net/Rest/SharpRestEngine.cs +++ /dev/null @@ -1,132 +0,0 @@ -#if !DOTNET5_4 -using Discord.Logging; -using Nito.AsyncEx; -using RestSharp; -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using RestSharpClient = RestSharp.RestClient; - -namespace Discord.Net.Rest -{ - internal class RestSharpEngine : IRestEngine - { - private const int HR_SECURECHANNELFAILED = -2146233079; - - private readonly DiscordConfig _config; - private readonly RestSharpClient _client; - - private readonly AsyncLock _rateLimitLock; - private readonly ILogger _logger; - private DateTime _rateLimitTime; - - public RestSharpEngine(DiscordConfig config, string baseUrl, ILogger logger) - { - _config = config; - _logger = logger; - - _rateLimitLock = new AsyncLock(); - _client = new RestSharpClient(baseUrl) - { - PreAuthenticate = false, - ReadWriteTimeout = DiscordConfig.RestTimeout, - UserAgent = config.UserAgent - }; - _client.Proxy = null; - _client.RemoveDefaultParameter("Accept"); - _client.AddDefaultHeader("accept", "*/*"); - _client.AddDefaultHeader("accept-encoding", "gzip,deflate"); - } - - public void SetToken(string token) - { - _client.RemoveDefaultParameter("authorization"); - if (token != null) - _client.AddDefaultHeader("authorization", token); - } - - public Task Send(string method, string path, string json, CancellationToken cancelToken) - { - var request = new RestRequest(path, GetMethod(method)); - if (json != null) - request.AddParameter("application/json", json, ParameterType.RequestBody); - return Send(request, cancelToken); - } - public Task SendFile(string method, string path, string filename, Stream stream, CancellationToken cancelToken) - { - var request = new RestRequest(path, GetMethod(method)); - request.AddHeader("content-length", (stream.Length - stream.Position).ToString()); - - byte[] bytes = new byte[stream.Length - stream.Position]; - stream.Read(bytes, 0, bytes.Length); - request.AddFileBytes("file", bytes, filename); - //request.AddFile("file", x => stream.CopyTo(x), filename); (Broken in latest ver) - - return Send(request, cancelToken); - } - private async Task Send(RestRequest request, CancellationToken cancelToken) - { - int retryCount = 0; - while (true) - { - var response = await _client.ExecuteTaskAsync(request, cancelToken).ConfigureAwait(false); - int statusCode = (int)response.StatusCode; - if (statusCode == 0) //Internal Error - { - //The request was aborted: Could not create SSL/TLS secure channel. - if (response.ErrorException.HResult == HR_SECURECHANNELFAILED && retryCount++ < 5) - continue; //Retrying seems to fix this somehow? - throw response.ErrorException; - } - else if (statusCode == 429) //Rate limit - { - var retryAfter = response.Headers - .FirstOrDefault(x => x.Name.Equals("Retry-After", StringComparison.OrdinalIgnoreCase)); - - int milliseconds; - if (retryAfter != null && int.TryParse((string)retryAfter.Value, out milliseconds)) - { - if (_logger != null) - { - var now = DateTime.UtcNow; - if (now >= _rateLimitTime) - { - using (await _rateLimitLock.LockAsync().ConfigureAwait(false)) - { - if (now >= _rateLimitTime) - { - _rateLimitTime = now.AddMilliseconds(milliseconds); - _logger.Warning($"Rate limit hit, waiting {Math.Round(milliseconds / 1000.0f, 2)} seconds"); - } - } - } - } - await Task.Delay(milliseconds, cancelToken).ConfigureAwait(false); - continue; - } - throw new HttpException(response.StatusCode); - } - else if (statusCode < 200 || statusCode >= 300) //2xx = Success - throw new HttpException(response.StatusCode); - else - return response.Content; - } - } - - private Method GetMethod(string method) - { - switch (method) - { - case "DELETE": return Method.DELETE; - case "GET": return Method.GET; - case "PATCH": return Method.PATCH; - case "POST": return Method.POST; - case "PUT": return Method.PUT; - default: throw new InvalidOperationException($"Unknown HttpMethod: {method}"); - } - } - } -} -#endif \ No newline at end of file diff --git a/src/Discord.Net/Net/TimeoutException.cs b/src/Discord.Net/Net/TimeoutException.cs deleted file mode 100644 index 051eeb263..000000000 --- a/src/Discord.Net/Net/TimeoutException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Discord.Net -{ -#if NET46 - [Serializable] -#endif - public class TimeoutException : OperationCanceledException - { - public TimeoutException() - : base("An operation has timed out.") - { - } - } -} diff --git a/src/Discord.Net/Net/WebSocketException.cs b/src/Discord.Net/Net/WebSocketException.cs deleted file mode 100644 index b845d90c4..000000000 --- a/src/Discord.Net/Net/WebSocketException.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Discord.Net -{ - public class WebSocketException : Exception - { - public int Code { get; } - public string Reason { get; } - - public WebSocketException(int code, string reason) - : base(GenerateMessage(code, reason)) - { - Code = code; - Reason = reason; - } - - private static string GenerateMessage(int? code, string reason) - { - if (!String.IsNullOrEmpty(reason)) - return $"Received close code {code}: {reason}"; - else - return $"Received close code {code}"; - } - } -} diff --git a/src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs b/src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs index 7c6f633e9..3fd4425fa 100644 --- a/src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs +++ b/src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs @@ -6,6 +6,6 @@ namespace Discord.Net.WebSockets { public byte[] Data { get; } - public BinaryMessageEventArgs(byte[] data) { Data = data; } + public BinaryMessageEventArgs(byte[] data) { } } } diff --git a/src/Discord.Net/Net/WebSockets/BuiltInEngine.cs b/src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs similarity index 59% rename from src/Discord.Net/Net/WebSockets/BuiltInEngine.cs rename to src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs index bda5ccb15..d9486c751 100644 --- a/src/Discord.Net/Net/WebSockets/BuiltInEngine.cs +++ b/src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs @@ -1,66 +1,87 @@ -#if DOTNET5_4 -using System; +using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using WebSocketClient = System.Net.WebSockets.ClientWebSocket; namespace Discord.Net.WebSockets { - internal class BuiltInEngine : IWebSocketEngine + public class DefaultWebSocketEngine : IWebSocketEngine { - private const int ReceiveChunkSize = 12 * 1024; //12KB - private const int SendChunkSize = 4 * 1024; //4KB - private const int HR_TIMEOUT = -2147012894; - - private readonly DiscordConfig _config; - private readonly ConcurrentQueue _sendQueue; - private WebSocketClient _webSocket; - private Task _tempTask; + public const int ReceiveChunkSize = 12 * 1024; //12KB + public const int SendChunkSize = 4 * 1024; //4KB + protected const int HR_TIMEOUT = -2147012894; public event EventHandler BinaryMessage = delegate { }; public event EventHandler TextMessage = delegate { }; - private void OnBinaryMessage(byte[] data) - => BinaryMessage(this, new BinaryMessageEventArgs(data)); - private void OnTextMessage(string msg) - => TextMessage(this, new TextMessageEventArgs(msg)); - internal BuiltInEngine(DiscordConfig config) + protected readonly ConcurrentQueue _sendQueue; + protected readonly ClientWebSocket _client; + protected Task _receiveTask, _sendTask; + protected CancellationTokenSource _cancelToken; + protected bool _isDisposed; + + public DefaultWebSocketEngine() { - _config = config; _sendQueue = new ConcurrentQueue(); + + _client = new ClientWebSocket(); + _client.Options.Proxy = null; + _client.Options.KeepAliveInterval = TimeSpan.Zero; + } + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + _client.Dispose(); + _isDisposed = true; + } + } + public void Dispose() + { + Dispose(true); } public async Task Connect(string host, CancellationToken cancelToken) { - _webSocket = new WebSocketClient(); - _webSocket.Options.Proxy = null; - _webSocket.Options.SetRequestHeader("User-Agent", _config.UserAgent); - _webSocket.Options.KeepAliveInterval = TimeSpan.Zero; - _tempTask = await _webSocket.ConnectAsync(new Uri(host), cancelToken)//.ConfigureAwait(false); - .ContinueWith(t => ReceiveAsync(cancelToken)).ConfigureAwait(false); - //TODO: ContinueWith is a temporary hack, may be a bug related to https://github.com/dotnet/corefx/issues/4429 - } + await Disconnect().ConfigureAwait(false); - public Task Disconnect() + _cancelToken = new CancellationTokenSource(); + var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelToken.Token, cancelToken).Token; + + await _client.ConnectAsync(new Uri(host), combinedToken).ConfigureAwait(false); + _receiveTask = TaskHelper.CreateLongRunning(() => ReceiveAsync(combinedToken), combinedToken); + _sendTask = TaskHelper.CreateLongRunning(() => SendAsync(combinedToken), combinedToken); + } + public async Task Disconnect() { + _cancelToken.Cancel(); + string ignored; while (_sendQueue.TryDequeue(out ignored)) { } - var socket = _webSocket; - _webSocket = null; + _client.Abort(); - return TaskHelper.CompletedTask; + var receiveTask = _receiveTask ?? TaskHelper.CompletedTask; + var sendTask = _sendTask ?? TaskHelper.CompletedTask; + await Task.WhenAll(receiveTask, sendTask).ConfigureAwait(false); } - public IEnumerable GetTasks(CancellationToken cancelToken) - => new Task[] { /*ReceiveAsync(cancelToken),*/ _tempTask, SendAsync(cancelToken) }; + public void SetHeader(string key, string value) + { + _client.Options.SetRequestHeader(key, value); + } + + public void QueueMessage(string message) + { + _sendQueue.Enqueue(message); + } + //TODO: Check this code private Task ReceiveAsync(CancellationToken cancelToken) { return Task.Run(async () => @@ -79,7 +100,7 @@ namespace Discord.Net.WebSockets try { - result = await _webSocket.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); + result = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); } catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) { @@ -96,9 +117,12 @@ namespace Discord.Net.WebSockets var array = stream.ToArray(); if (result.MessageType == WebSocketMessageType.Binary) - OnBinaryMessage(array); + BinaryMessage(this, new BinaryMessageEventArgs(array)); else if (result.MessageType == WebSocketMessageType.Text) - OnTextMessage(Encoding.UTF8.GetString(array, 0, array.Length)); + { + string text = Encoding.UTF8.GetString(array, 0, array.Length); + TextMessage(this, new TextMessageEventArgs(text)); + } stream.Position = 0; stream.SetLength(0); @@ -107,6 +131,8 @@ namespace Discord.Net.WebSockets catch (OperationCanceledException) { } }); } + + //TODO: Check this code private Task SendAsync(CancellationToken cancelToken) { return Task.Run(async () => @@ -124,7 +150,7 @@ namespace Discord.Net.WebSockets int frameCount = (int)Math.Ceiling((double)byteCount / SendChunkSize); int offset = 0; - for (var i = 0; i < frameCount; i++, offset += SendChunkSize) + for (int i = 0; i < frameCount; i++, offset += SendChunkSize) { bool isLast = i == (frameCount - 1); @@ -136,7 +162,7 @@ namespace Discord.Net.WebSockets try { - await _webSocket.SendAsync(new ArraySegment(bytes, offset, count), WebSocketMessageType.Text, isLast, cancelToken).ConfigureAwait(false); + await _client.SendAsync(new ArraySegment(bytes, offset, count), WebSocketMessageType.Text, isLast, cancelToken).ConfigureAwait(false); } catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) { @@ -150,9 +176,5 @@ namespace Discord.Net.WebSockets catch (OperationCanceledException) { } }); } - - public void QueueMessage(string message) - => _sendQueue.Enqueue(message); } } -#endif \ No newline at end of file diff --git a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs b/src/Discord.Net/Net/WebSockets/GatewaySocket.cs index 4afe5aae7..3e841de89 100644 --- a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs +++ b/src/Discord.Net/Net/WebSockets/GatewaySocket.cs @@ -1,14 +1,5 @@ -using Discord.API.Client; -using Discord.API.Client.GatewaySocket; -using Discord.API.Client.Rest; -using Discord.Logging; -using Discord.Net.Rest; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,175 +7,36 @@ namespace Discord.Net.WebSockets { public class GatewaySocket : WebSocket { - private RestClient _rest; - private uint _lastSequence; - private int _reconnects; - - //public string Token { get; private set; } - public string SessionId { get; private set; } - public event EventHandler ReceivedDispatch = delegate { }; - private void OnReceivedDispatch(string type, JToken payload) - => ReceivedDispatch(this, new WebSocketEventEventArgs(type, payload)); - - public GatewaySocket(DiscordConfig config, JsonSerializer serializer, Logger logger) - : base(config, serializer, logger) - { - Disconnected += async (s, e) => - { - if (e.WasUnexpected) - await Reconnect().ConfigureAwait(false); - }; - } - - public async Task Connect(RestClient rest, CancellationToken parentCancelToken) - { - _rest = rest; - //Token = rest.Token; - - var gatewayResponse = await rest.Send(new GatewayRequest()).ConfigureAwait(false); - Logger.Verbose($"Login successful, gateway: {gatewayResponse.Url}"); - Host = gatewayResponse.Url; - await BeginConnect(parentCancelToken).ConfigureAwait(false); - if (SessionId == null) - SendIdentify(_rest.Token); - else - SendResume(); - } - private async Task Reconnect() - { - try - { - var cancelToken = _parentCancelToken; - if (_reconnects++ == 0) - await Task.Delay(_config.ReconnectDelay, cancelToken).ConfigureAwait(false); - else - await Task.Delay(_config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); + public ConnectionState State { get; } + public string Host { get; } + public string SessionId { get; } - while (!cancelToken.IsCancellationRequested) - { - try - { - await Connect(_rest, _parentCancelToken).ConfigureAwait(false); - break; - } - catch (OperationCanceledException) { throw; } - catch (Exception ex) - { - Logger.Error("Reconnect failed", ex); - //Net is down? We can keep trying to reconnect until the user runs Disconnect() - await Task.Delay(_config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); - } - } - } - catch (OperationCanceledException) { } - } - public async Task Disconnect() + internal GatewaySocket(IWebSocketEngine engine) + : base(engine) { - await _taskManager.Stop(true).ConfigureAwait(false); - //Token = null; - SessionId = null; } - protected override async Task Run() + public void SetHeader(string key, string value) => _engine.SetHeader(key, value); + + internal Task Connect(CancellationToken cancelToken) { - List tasks = new List(); - tasks.AddRange(_engine.GetTasks(CancelToken)); - tasks.Add(HeartbeatAsync(CancelToken)); - await _taskManager.Start(tasks, _cancelSource).ConfigureAwait(false); + return Task.Delay(0); } - protected override Task Cleanup() + internal Task Disconnect() { - var ex = _taskManager.Exception; - if (ex == null || (ex as WebSocketException)?.Code != 1012) //if (ex == null || (ex as WebSocketException)?.Code != 1012) - SessionId = null; //Reset session unless close code 1012 - return base.Cleanup(); + return Task.Delay(0); } - protected override async Task ProcessMessage(string json) - { - base.ProcessMessage(json).GetAwaiter().GetResult(); //This is just a CompletedTask, and we need to avoid asyncs in here + public void SendIdentify(string token) { } - WebSocketMessage msg; - using (var reader = new JsonTextReader(new StringReader(json))) - msg = _serializer.Deserialize(reader, typeof(WebSocketMessage)) as WebSocketMessage; - - if (msg.Sequence.HasValue) - _lastSequence = msg.Sequence.Value; - - var opCode = (OpCodes?)msg.Operation; - switch (opCode) - { - case OpCodes.Dispatch: - { - if (msg.Type == "READY") - SessionId = (msg.Payload as JToken).Value("session_id"); - - OnReceivedDispatch(msg.Type, msg.Payload as JToken); - - if (msg.Type == "READY" || msg.Type == "RESUMED") - { - _heartbeatInterval = (msg.Payload as JToken).Value("heartbeat_interval"); - _reconnects = 0; - await EndConnect().ConfigureAwait(false); //Complete the connect - } - } - break; - case OpCodes.Redirect: - { - var payload = (msg.Payload as JToken).ToObject(_serializer); - if (payload.Url != null) - { - Host = payload.Url; - Logger.Info("Redirected to " + payload.Url); - await Reconnect().ConfigureAwait(false); - } - } - break; - default: - if (opCode != null) - Logger.Warning($"Unknown Opcode: {opCode}"); - else - Logger.Warning($"Received message with no opcode"); - break; - } - } - - public void SendIdentify(string token) - { - var props = new Dictionary - { - ["$device"] = "Discord.Net" - }; - var msg = new IdentifyCommand() - { - Version = 3, - Token = token, - Properties = props, - LargeThreshold = _config.LargeThreshold, - UseCompression = true - }; - QueueMessage(msg); - } - - public void SendResume() - => QueueMessage(new ResumeCommand { SessionId = SessionId, Sequence = _lastSequence }); - public override void SendHeartbeat() - => QueueMessage(new HeartbeatCommand()); - public void SendUpdateStatus(long? idleSince, string gameName) - => QueueMessage(new UpdateStatusCommand - { - IdleSince = idleSince, - Game = gameName != null ? new UpdateStatusCommand.GameInfo { Name = gameName } : null - }); - public void SendUpdateVoice(ulong? serverId, ulong? channelId, bool isSelfMuted, bool isSelfDeafened) - => QueueMessage(new UpdateVoiceCommand { GuildId = serverId, ChannelId = channelId, IsSelfMuted = isSelfMuted, IsSelfDeafened = isSelfDeafened }); - public void SendRequestMembers(IEnumerable serverId, string query, int limit) - => QueueMessage(new RequestMembersCommand { GuildId = serverId.ToArray(), Query = query, Limit = limit }); - - //Cancel if either DiscordClient.Disconnect is called, data socket errors or timeout is reached - public override void WaitForConnection(CancellationToken cancelToken) - => base.WaitForConnection(CancellationTokenSource.CreateLinkedTokenSource(cancelToken, CancelToken).Token); + public void SendResume() { } + public void SendHeartbeat() { } + public void SendUpdateStatus(long? idleSince, string gameName) { } + public void SendUpdateVoice(ulong? guildId, ulong? channelId, bool isSelfMuted, bool isSelfDeafened) { } + public void SendRequestMembers(IEnumerable guildId, string query, int limit) { } + + public void WaitForConnection(CancellationToken cancelToken) { } } } diff --git a/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs b/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs index 68f31f12b..b43109276 100644 --- a/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs +++ b/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs @@ -1,18 +1,18 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Discord.Net.WebSockets { - public interface IWebSocketEngine - { - event EventHandler BinaryMessage; - event EventHandler TextMessage; + public interface IWebSocketEngine : IDisposable + { + event EventHandler BinaryMessage; + event EventHandler TextMessage; - Task Connect(string host, CancellationToken cancelToken); - Task Disconnect(); - void QueueMessage(string message); - IEnumerable GetTasks(CancellationToken cancelToken); - } + void SetHeader(string key, string value); + + Task Connect(string host, CancellationToken cancelToken); + Task Disconnect(); + void QueueMessage(string message); + } } diff --git a/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs b/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs deleted file mode 100644 index 420299d6b..000000000 --- a/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs +++ /dev/null @@ -1,141 +0,0 @@ -#if !DOTNET5_4 -using SuperSocket.ClientEngine; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using WebSocket4Net; -using WebSocketClient = WebSocket4Net.WebSocket; - -namespace Discord.Net.WebSockets -{ - internal class WS4NetEngine : IWebSocketEngine - { - private readonly DiscordConfig _config; - private readonly ConcurrentQueue _sendQueue; - private readonly TaskManager _taskManager; - private WebSocketClient _webSocket; - private ManualResetEventSlim _waitUntilConnect, _waitUntilDisconnect; - - public event EventHandler BinaryMessage = delegate { }; - public event EventHandler TextMessage = delegate { }; - private void OnBinaryMessage(byte[] data) - => BinaryMessage(this, new BinaryMessageEventArgs(data)); - private void OnTextMessage(string msg) - => TextMessage(this, new TextMessageEventArgs(msg)); - - internal WS4NetEngine(DiscordConfig config, TaskManager taskManager) - { - _config = config; - _taskManager = taskManager; - _sendQueue = new ConcurrentQueue(); - _waitUntilConnect = new ManualResetEventSlim(); - _waitUntilDisconnect = new ManualResetEventSlim(true); - } - - public Task Connect(string host, CancellationToken cancelToken) - { - try - { - _webSocket = new WebSocketClient(host); - _webSocket.EnableAutoSendPing = false; - _webSocket.NoDelay = true; - _webSocket.Proxy = null; - - _webSocket.DataReceived += OnWebSocketBinary; - _webSocket.MessageReceived += OnWebSocketText; - _webSocket.Error += OnWebSocketError; - _webSocket.Closed += OnWebSocketClosed; - _webSocket.Opened += OnWebSocketOpened; - - _waitUntilConnect.Reset(); - _waitUntilDisconnect.Reset(); - _webSocket.Open(); - _waitUntilConnect.Wait(cancelToken); - _taskManager.ThrowException(); //In case our connection failed - } - catch - { - _waitUntilDisconnect.Set(); - throw; - } - return TaskHelper.CompletedTask; - } - - public Task Disconnect() - { - string ignored; - while (_sendQueue.TryDequeue(out ignored)) { } - - var socket = _webSocket; - _webSocket = null; - if (socket != null) - { - socket.Close(); - socket.Opened -= OnWebSocketOpened; - socket.DataReceived -= OnWebSocketBinary; - socket.MessageReceived -= OnWebSocketText; - - _waitUntilDisconnect.Wait(); //We need the next two events to raise this one - socket.Error -= OnWebSocketError; - socket.Closed -= OnWebSocketClosed; - socket.Dispose(); - } - - return TaskHelper.CompletedTask; - } - - private async void OnWebSocketError(object sender, ErrorEventArgs e) - { - await _taskManager.SignalError(e.Exception).ConfigureAwait(false); - _waitUntilConnect.Set(); - _waitUntilDisconnect.Set(); - } - private async void OnWebSocketClosed(object sender, EventArgs e) - { - Exception ex; - if (e is ClosedEventArgs) - ex = new WebSocketException((e as ClosedEventArgs).Code, (e as ClosedEventArgs).Reason); - else - ex = new Exception("Connection lost"); - await _taskManager.SignalError(ex).ConfigureAwait(false); - _waitUntilConnect.Set(); - _waitUntilDisconnect.Set(); - } - private void OnWebSocketOpened(object sender, EventArgs e) - { - _waitUntilConnect.Set(); - _waitUntilDisconnect.Reset(); - } - private void OnWebSocketText(object sender, MessageReceivedEventArgs e) - => OnTextMessage(e.Message); - private void OnWebSocketBinary(object sender, DataReceivedEventArgs e) - => OnBinaryMessage(e.Data); - - public IEnumerable GetTasks(CancellationToken cancelToken) - => new Task[] { SendAsync(cancelToken) }; - - private Task SendAsync(CancellationToken cancelToken) - { - return Task.Run(async () => - { - try - { - while (!cancelToken.IsCancellationRequested) - { - string json; - while (_sendQueue.TryDequeue(out json)) - _webSocket.Send(json); - await Task.Delay(DiscordConfig.WebSocketQueueInterval, cancelToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) { } - }); - } - - public void QueueMessage(string message) - => _sendQueue.Enqueue(message); - } -} -#endif \ No newline at end of file diff --git a/src/Discord.Net/Net/WebSockets/WebSocket.cs b/src/Discord.Net/Net/WebSockets/WebSocket.cs index aa2c9a98b..ed533883a 100644 --- a/src/Discord.Net/Net/WebSockets/WebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/WebSocket.cs @@ -1,188 +1,27 @@ -using Discord.API.Client; -using Discord.Logging; -using Newtonsoft.Json; -using Nito.AsyncEx; -using System; -using System.IO; -using System.IO.Compression; -using System.Threading; -using System.Threading.Tasks; +using System; namespace Discord.Net.WebSockets { - public abstract partial class WebSocket - { - private readonly AsyncLock _lock; + public class WebSocket : IDisposable + { protected readonly IWebSocketEngine _engine; - protected readonly DiscordConfig _config; - protected readonly ManualResetEventSlim _connectedEvent; - protected readonly TaskManager _taskManager; - protected readonly JsonSerializer _serializer; - protected CancellationTokenSource _cancelSource; - protected CancellationToken _parentCancelToken; - protected int _heartbeatInterval; - private DateTime _lastHeartbeat; + protected bool _isDisposed; - /// Gets the logger used for this client. - protected internal Logger Logger { get; } - public CancellationToken CancelToken { get; private set; } - - public string Host { get; set; } - /// Gets the current connection state of this client. - public ConnectionState State { get; private set; } - - public event EventHandler Connected = delegate { }; - private void OnConnected() - => Connected(this, EventArgs.Empty); - public event EventHandler Disconnected = delegate { }; - private void OnDisconnected(bool wasUnexpected, Exception error) - => Disconnected(this, new DisconnectedEventArgs(wasUnexpected, error)); - - public WebSocket(DiscordConfig config, JsonSerializer serializer, Logger logger) - { - _config = config; - _serializer = serializer; - Logger = logger; - - _lock = new AsyncLock(); - _taskManager = new TaskManager(Cleanup); - CancelToken = new CancellationToken(true); - _connectedEvent = new ManualResetEventSlim(false); - -#if !DOTNET5_4 - _engine = new WS4NetEngine(config, _taskManager); -#else - _engine = new BuiltInEngine(config); -#endif - _engine.BinaryMessage += (s, e) => - { - using (var compressed = new MemoryStream(e.Data, 2, e.Data.Length - 2)) - using (var decompressed = new MemoryStream()) - { - using (var zlib = new DeflateStream(compressed, CompressionMode.Decompress)) - zlib.CopyTo(decompressed); - decompressed.Position = 0; - using (var reader = new StreamReader(decompressed)) - ProcessMessage(reader.ReadToEnd()).GetAwaiter().GetResult(); - } - }; - _engine.TextMessage += (s, e) => ProcessMessage(e.Message).Wait(); - } - - protected async Task BeginConnect(CancellationToken parentCancelToken) - { - try - { - using (await _lock.LockAsync().ConfigureAwait(false)) - { - _parentCancelToken = parentCancelToken; - - await _taskManager.Stop().ConfigureAwait(false); - _taskManager.ClearException(); - State = ConnectionState.Connecting; - - _cancelSource = new CancellationTokenSource(); - CancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelSource.Token, parentCancelToken).Token; - _lastHeartbeat = DateTime.UtcNow; - - await _engine.Connect(Host, CancelToken).ConfigureAwait(false); - await Run().ConfigureAwait(false); - } - } - catch (Exception ex) - { - //TODO: Should this be inside the lock? - await _taskManager.SignalError(ex).ConfigureAwait(false); - throw; - } - } - protected async Task EndConnect() - { - try - { - State = ConnectionState.Connected; - Logger.Info($"Connected"); - - OnConnected(); - _connectedEvent.Set(); - } - catch (Exception ex) - { - await _taskManager.SignalError(ex).ConfigureAwait(false); - } - } - - protected abstract Task Run(); - protected virtual async Task Cleanup() - { - var oldState = State; - State = ConnectionState.Disconnecting; - - await _engine.Disconnect().ConfigureAwait(false); - _cancelSource = null; - _connectedEvent.Reset(); - - if (oldState == ConnectionState.Connecting || oldState == ConnectionState.Connected) - { - var ex = _taskManager.Exception; - if (ex == null) - Logger.Info("Disconnected"); - else - Logger.Error("Disconnected", ex); - State = ConnectionState.Disconnected; - OnDisconnected(!_taskManager.WasStopExpected, _taskManager.Exception); - } - else - State = ConnectionState.Disconnected; - } - - protected virtual Task ProcessMessage(string json) - { - return TaskHelper.CompletedTask; - } - protected void QueueMessage(IWebSocketMessage message) - { - string json = JsonConvert.SerializeObject(new WebSocketMessage(message)); - _engine.QueueMessage(json); - } - - protected Task HeartbeatAsync(CancellationToken cancelToken) - { - return Task.Run(async () => - { - try - { - while (!cancelToken.IsCancellationRequested) - { - if (this.State == ConnectionState.Connected && _heartbeatInterval > 0) - { - SendHeartbeat(); - await Task.Delay(_heartbeatInterval, cancelToken).ConfigureAwait(false); - } - else - await Task.Delay(1000, cancelToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) { } - }); - } - public abstract void SendHeartbeat(); + internal WebSocket(IWebSocketEngine engine) + { + _engine = engine; + } - public virtual void WaitForConnection(CancellationToken cancelToken) + protected virtual void Dispose(bool disposing) { - try + if (!_isDisposed) { - if (!_connectedEvent.Wait(_config.ConnectionTimeout, cancelToken)) - { - if (State != ConnectionState.Connected) - throw new TimeoutException(); - } - } - catch (OperationCanceledException) - { - _taskManager.ThrowException(); //Throws data socket's internal error if any occured - throw; + if (disposing) + _engine.Dispose(); + + _isDisposed = true; } } - } + public void Dispose() => Dispose(true); + } } diff --git a/src/Discord.Net/Net/WebSockets/WebSocketEventEventArgs.cs b/src/Discord.Net/Net/WebSockets/WebSocketEventEventArgs.cs index a0c60edcf..676c0ba6e 100644 --- a/src/Discord.Net/Net/WebSockets/WebSocketEventEventArgs.cs +++ b/src/Discord.Net/Net/WebSockets/WebSocketEventEventArgs.cs @@ -7,11 +7,5 @@ namespace Discord.Net.WebSockets { public string Type { get; } public JToken Payload { get; } - - internal WebSocketEventEventArgs(string type, JToken data) - { - Type = type; - Payload = data; - } } } diff --git a/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs b/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs new file mode 100644 index 000000000..7e7652dbc --- /dev/null +++ b/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs @@ -0,0 +1,6 @@ +using System.Threading; + +namespace Discord.Net.WebSockets +{ + public delegate IWebSocketEngine WebSocketProvider(CancellationToken cancelToken); +} diff --git a/src/Discord.Net/Properties/AssemblyInfo.cs b/src/Discord.Net/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..b562e546b --- /dev/null +++ b/src/Discord.Net/Properties/AssemblyInfo.cs @@ -0,0 +1,18 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Discord.Net")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Discord.Net")] +[assembly: AssemblyCopyright("Copyright © Rogue Exception 2015-2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("c6a50d24-cbd3-4e76-852c-4dca60bbd608")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Discord.Net/ServiceCollection.cs b/src/Discord.Net/ServiceCollection.cs deleted file mode 100644 index 104f91dd4..000000000 --- a/src/Discord.Net/ServiceCollection.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Discord -{ - internal class ServiceCollection : IEnumerable - { - private readonly Dictionary _services; - - internal DiscordClient Client { get; } - - internal ServiceCollection(DiscordClient client) - { - Client = client; - _services = new Dictionary(); - } - - public T Add(T service) - where T : class, IService - { - _services.Add(typeof(T), service); - service.Install(Client); - return service; - } - - public T Get(bool isRequired = true) - where T : class, IService - { - IService service; - T singletonT = null; - - if (_services.TryGetValue(typeof(T), out service)) - singletonT = service as T; - - if (singletonT == null && isRequired) - throw new InvalidOperationException($"This operation requires {typeof(T).Name} to be added to {nameof(DiscordClient)}."); - return singletonT; - } - - public IEnumerator GetEnumerator() => _services.Values.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => _services.Values.GetEnumerator(); - } -} diff --git a/src/Discord.Net/TaskHelper.cs b/src/Discord.Net/TaskHelper.cs new file mode 100644 index 000000000..17ecc4615 --- /dev/null +++ b/src/Discord.Net/TaskHelper.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Discord +{ + internal static class TaskHelper + { +#if NETSTANDARD1_4 + public static Task CompletedTask => Task.CompletedTask; +#else + public static Task CompletedTask => Task.Delay(0); +#endif + + public static Task CreateLongRunning(Action action, CancellationToken cancelToken) + => Task.Factory.StartNew(action, cancelToken, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } +} diff --git a/src/Discord.Net/TaskManager.cs b/src/Discord.Net/TaskManager.cs deleted file mode 100644 index d43372396..000000000 --- a/src/Discord.Net/TaskManager.cs +++ /dev/null @@ -1,179 +0,0 @@ -using Nito.AsyncEx; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord -{ - /// Helper class used to manage several tasks and keep them in sync. If any single task errors or stops, all other tasks will also be stopped. - public class TaskManager - { - private readonly AsyncLock _lock; - private readonly Func _stopAction; - private ExceptionDispatchInfo _stopReason; - - private CancellationTokenSource _cancelSource; - private Task _task; - - public bool StopOnCompletion { get; } - public bool WasStopExpected { get; private set; } - - public Exception Exception => _stopReason?.SourceException; - - internal TaskManager(bool stopOnCompletion) - { - _lock = new AsyncLock(); - StopOnCompletion = stopOnCompletion; - } - public TaskManager(Action stopAction, bool stopOnCompletion = true) - : this(stopOnCompletion) - { - _stopAction = TaskHelper.ToAsync(stopAction); - } - public TaskManager(Func stopAction, bool stopOnCompletion = true) - : this(stopOnCompletion) - { - _stopAction = stopAction; - } - - public async Task Start(IEnumerable tasks, CancellationTokenSource cancelSource) - { - if (tasks == null) throw new ArgumentNullException(nameof(tasks)); - if (cancelSource == null) throw new ArgumentNullException(nameof(cancelSource)); - - while (true) - { - var task = _task; - if (task != null) - await Stop().ConfigureAwait(false); - - using (await _lock.LockAsync().ConfigureAwait(false)) - { - _cancelSource = cancelSource; - - if (_task != null) - continue; //Another thread sneaked in and started this manager before we got a lock, loop and try again - - _stopReason = null; - WasStopExpected = false; - - Task[] tasksArray = tasks.ToArray(); - - _task = Task.Run(async () => - { - if (tasksArray.Length > 0) - { - Task anyTask = tasksArray.Length > 0 ? Task.WhenAny(tasksArray) : null; - Task allTasks = tasksArray.Length > 0 ? Task.WhenAll(tasksArray) : null; - //Wait for the first task to stop or error - Task firstTask = await anyTask.ConfigureAwait(false); - - //Signal the rest of the tasks to stop - if (firstTask.Exception != null) - await SignalError(firstTask.Exception).ConfigureAwait(false); - else if (StopOnCompletion) //Unless we allow for natural completions - await SignalStop().ConfigureAwait(false); - - //Wait for the other tasks, and signal their errors too just in case - try { await allTasks.ConfigureAwait(false); } - catch (AggregateException ex) { await SignalError(ex.InnerExceptions.First()).ConfigureAwait(false); } - catch (Exception ex) { await SignalError(ex).ConfigureAwait(false); } - } - - if (!StopOnCompletion && !_cancelSource.IsCancellationRequested) - { - try { await Task.Delay(-1, _cancelSource.Token).ConfigureAwait(false); } //Pause until TaskManager is stopped - catch (OperationCanceledException) { } - } - - //Run the cleanup function within our lock - if (_stopAction != null) - await _stopAction().ConfigureAwait(false); - _task = null; - _cancelSource = null; - }); - return; - } - } - } - - public async Task SignalStop(bool isExpected = false) - { - using (await _lock.LockAsync().ConfigureAwait(false)) - { - if (isExpected) - WasStopExpected = true; - - Cancel(); - } - } - public async Task Stop(bool isExpected = false) - { - Task task; - using (await _lock.LockAsync().ConfigureAwait(false)) - { - if (isExpected) - WasStopExpected = true; - - //Cache the task so we still have something to await if Cleanup is run really quickly - task = _task ?? TaskHelper.CompletedTask; - Cancel(); - } - await task.ConfigureAwait(false); - } - - public async Task SignalError(Exception ex) - { - using (await _lock.LockAsync().ConfigureAwait(false)) - { - if (_stopReason != null) return; - - Cancel(ex); - } - } - public async Task Error(Exception ex) - { - Task task; - using (await _lock.LockAsync().ConfigureAwait(false)) - { - if (_stopReason != null) return; - - //Cache the task so we still have something to await if Cleanup is run really quickly - task = _task ?? TaskHelper.CompletedTask; - Cancel(ex); - } - await task.ConfigureAwait(false); - } - private void Cancel(Exception ex = null) - { - var source = _cancelSource; - if (source != null && !source.IsCancellationRequested) - { - if (ex != null) - _stopReason = ExceptionDispatchInfo.Capture(ex); - _cancelSource.Cancel(); - } - } - - /// Throws an exception if one was captured. - public void ThrowException() - { - using (_lock.Lock()) - { - if (!WasStopExpected) - _stopReason?.Throw(); - } - } - public void ClearException() - { - using (_lock.Lock()) - { - _stopReason = null; - WasStopExpected = false; - } - } - } -} diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json index 80a6fb51d..4aa7cd55c 100644 --- a/src/Discord.Net/project.json +++ b/src/Discord.Net/project.json @@ -2,78 +2,38 @@ "version": "1.0.0-alpha1", "description": "An unofficial .Net API wrapper for the Discord client.", "authors": [ "RogueException" ], - "tags": [ - "discord", - "discordapp" - ], + "tags": [ "discord", "discordapp" ], "projectUrl": "https://github.com/RogueException/Discord.Net", "licenseUrl": "http://opensource.org/licenses/MIT", "repository": { "type": "git", "url": "git://github.com/RogueException/Discord.Net" }, - "compile": [ "**/*.cs", "../Discord.Net.Shared/*.cs" ], "compilationOptions": { - "allowUnsafe": true, - "warningsAsErrors": true - }, - - "configurations": { - "TestResponses": { - "compilationOptions": { - "define": [ - "DEBUG", - "TRACE", - "TEST_RESPONSES" - ] - } - } + "allowUnsafe": true }, "dependencies": { - "Newtonsoft.Json": "8.0.1", - "Nito.AsyncEx": "3.0.1" + "Newtonsoft.Json": "8.0.3", + "System.Collections.Concurrent": "4.0.12-rc3-*", + "System.Collections.Immutable": "1.2.0-rc3-*", + "System.IO": "4.1.0-rc3-*", + "System.IO.FileSystem": "4.0.1-rc3-*", + "System.Reflection": "4.1.0-rc3-*", + "System.Runtime": "4.1.0-rc3-*", + "System.Net.Requests": "4.0.11-rc3-*", + "System.Net.Http": "4.0.1-rc3-*", + "System.Net.Sockets": "4.1.0-rc3-*", + "System.Net.WebSockets.Client": "4.0.0-rc3-*", + "System.Text.RegularExpressions": "4.0.12-rc3-*", + "System.Threading": "4.0.11-rc3-*", + "System.Threading.Tasks": "4.0.11-rc3-*" }, "frameworks": { - "dotnet5.4": { - "dependencies": { - "System.Collections": "4.0.11-beta-23516", - "System.Collections.Concurrent": "4.0.11-beta-23516", - "System.Dynamic.Runtime": "4.0.11-beta-23516", - "System.IO.FileSystem": "4.0.1-beta-23516", - "System.IO.Compression": "4.1.0-beta-23516", - "System.Linq": "4.0.1-beta-23516", - "System.Net.Http": "4.0.1-beta-23516", - "System.Net.NameResolution": "4.0.0-beta-23516", - "System.Net.Sockets": "4.1.0-beta-23409", - "System.Net.Requests": "4.0.11-beta-23516", - "System.Net.WebSockets.Client": "4.0.0-beta-23516", - "System.Reflection": "4.1.0-beta-23516", - "System.Reflection.Emit.Lightweight": "4.0.1-beta-23516", - "System.Runtime.InteropServices": "4.0.21-beta-23516", - "System.Runtime.Serialization.Primitives": "4.1.0-beta-23516", - "System.Security.Cryptography.Algorithms": "4.0.0-beta-23516", - "System.Text.RegularExpressions": "4.0.11-beta-23516", - "System.Threading": "4.0.11-beta-23516" - } - }, - "net45": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build", - "version": "" - }, - "System.Threading.Tasks": { - "type": "build", - "version": "" - } - }, - "dependencies": { - "WebSocket4Net": "0.14.1", - "RestSharp": "105.2.3" - } + "netstandard1.4": { + "imports": "dotnet5.5" } } } \ No newline at end of file diff --git a/test/Discord.Net.Tests/Discord.Net.Tests.csproj b/test/Discord.Net.Tests/Discord.Net.Tests.csproj index 0c13b7075..2a50610cc 100644 --- a/test/Discord.Net.Tests/Discord.Net.Tests.csproj +++ b/test/Discord.Net.Tests/Discord.Net.Tests.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -8,7 +8,7 @@ Properties Discord.Tests Discord.Net.Tests - v4.5 + v4.6.1 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 @@ -56,17 +56,16 @@ - - - {8d71a857-879a-4a10-859e-5ff824ed6688} - Discord.Net - + - + + {c6a50d24-cbd3-4e76-852c-4dca60bbd608} + Discord.Net.Net45 + diff --git a/test/Discord.Net.Tests/Settings.cs b/test/Discord.Net.Tests/Settings.cs deleted file mode 100644 index 5aa37e184..000000000 --- a/test/Discord.Net.Tests/Settings.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Newtonsoft.Json; -using System.IO; - -namespace Discord.Tests -{ - internal class Settings - { - private const string path = "../../config.json"; - public static readonly Settings Instance; - static Settings() - { - if (!File.Exists(path)) - throw new FileNotFoundException("config.json is missing, rename config.json.example and add credentials for three separate unused accounts for testing."); - Instance = JsonConvert.DeserializeObject(File.ReadAllText(path)); - } - - public class Account - { - [JsonProperty("email")] - public string Email { get; set; } - [JsonProperty("password")] - public string Password { get; set; } - } - - [JsonProperty("user1")] - public Account User1 { get; set; } - [JsonProperty("user2")] - public Account User2 { get; set; } - [JsonProperty("user3")] - public Account User3 { get; set; } - } -} diff --git a/test/Discord.Net.Tests/Tests.cs b/test/Discord.Net.Tests/Tests.cs index 51c045d69..6cb0196d5 100644 --- a/test/Discord.Net.Tests/Tests.cs +++ b/test/Discord.Net.Tests/Tests.cs @@ -7,167 +7,484 @@ using System.Threading.Tasks; namespace Discord.Tests { - //TODO: Tests are massively incomplete and out of date, needing a full rewrite - - [TestClass] - public class Tests - { - private const int EventTimeout = 5000; //Max time in milliseconds to wait for an event response from our test actions - - private static DiscordClient _hostClient, _targetBot, _observerBot; - private static Server _testServer; - private static Channel _testServerChannel; - private static Random _random; - - [ClassInitialize] - public static void Initialize(TestContext testContext) - { - var settings = Settings.Instance; - _random = new Random(); - - _hostClient = new DiscordClient(); - _targetBot = new DiscordClient(); - _observerBot = new DiscordClient(); - - _hostClient.Connect(settings.User1.Email, settings.User1.Password).Wait(); - _targetBot.Connect(settings.User2.Email, settings.User2.Password).Wait(); - _observerBot.Connect(settings.User3.Email, settings.User3.Password).Wait(); - - //Cleanup existing servers - WaitMany( - _hostClient.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave()), - _targetBot.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave()), - _observerBot.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave())); - - //Create new server and invite the other bots to it - _testServer = _hostClient.CreateServer("Discord.Net Testing", _hostClient.Regions.First()).Result; - _testServerChannel = _testServer.DefaultChannel; - var invite = _testServer.CreateInvite(60, 2, false, false).Result; - WaitAll( - _targetBot.GetInvite(invite.Code).Result.Accept(), - _observerBot.GetInvite(invite.Code).Result.Accept()); - } - - //Channels - [TestMethod] - public void TestCreateTextChannel() - => TestCreateChannel(ChannelType.Text); - [TestMethod] - public void TestCreateVoiceChannel() - => TestCreateChannel(ChannelType.Voice); - private void TestCreateChannel(ChannelType type) - { - Channel channel = null; - string name = $"#test_{_random.Next()}"; - AssertEvent( - "ChannelCreated event never received", - async () => channel = await _testServer.CreateChannel(name.Substring(1), type), - x => _targetBot.ChannelCreated += x, - x => _targetBot.ChannelCreated -= x, - (s, e) => e.Channel.Name == name); - - AssertEvent( - "ChannelDestroyed event never received", - async () => await channel.Delete(), - x => _targetBot.ChannelDestroyed += x, - x => _targetBot.ChannelDestroyed -= x, - (s, e) => e.Channel.Name == name); - } - - [TestMethod] - [ExpectedException(typeof(InvalidOperationException))] - public async Task TestCreateChannel_NoName() - { - await _testServer.CreateChannel($"", ChannelType.Text); - } - [TestMethod] - [ExpectedException(typeof(InvalidOperationException))] - public async Task TestCreateChannel_NoType() - { - string name = $"#test_{_random.Next()}"; - await _testServer.CreateChannel($"", ChannelType.FromString("")); - } - [TestMethod] - [ExpectedException(typeof(InvalidOperationException))] - public async Task TestCreateChannel_BadType() - { - string name = $"#test_{_random.Next()}"; - await _testServer.CreateChannel($"", ChannelType.FromString("badtype")); - } - - //Messages - [TestMethod] - public void TestSendMessage() - { - string text = $"test_{_random.Next()}"; - AssertEvent( - "MessageCreated event never received", - () => _testServerChannel.SendMessage(text), - x => _targetBot.MessageReceived += x, - x => _targetBot.MessageReceived -= x, - (s, e) => e.Message.Text == text); - } - - [ClassCleanup] - public static void Cleanup() - { - WaitMany( - _hostClient.State == ConnectionState.Connected ? _hostClient.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave()) : null, - _targetBot.State == ConnectionState.Connected ? _targetBot.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave()) : null, - _observerBot.State == ConnectionState.Connected ? _observerBot.Servers.Select(x => x.IsOwner ? x.Delete() : x.Leave()) : null); - - WaitAll( - _hostClient.Disconnect(), - _targetBot.Disconnect(), - _observerBot.Disconnect()); - } - - // Unit Test Helpers - - private static void AssertEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test = null) - { - AssertEvent(msg, action, addEvent, removeEvent, test, true); - } - private static void AssertNoEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test = null) - { - AssertEvent(msg, action, addEvent, removeEvent, test, false); - } - private static void AssertEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test, bool assertTrue) - { - ManualResetEventSlim trigger = new ManualResetEventSlim(false); - bool result = false; - - EventHandler handler = (s, e) => - { - if (test != null) - { - result |= test(s, e); - trigger.Set(); + //TODO: Tests are massively incomplete and out of date, needing a full rewrite + + [TestClass] + public class Tests + { + private const int EventTimeout = 10000; //Max time in milliseconds to wait for an event response from our test actions + + private static DiscordSocketClient _hostBot, _targetBot, _observerBot; + private static Guild _testGuild; + private static TextChannel _testGuildChannel; + private static Random _random; + private static PublicInvite _testGuildInvite; + + private static TestContext _context; + + private static string _hostToken; + private static string _observerToken; + private static string _targetToken; + + private static string GetRandomText() + { + lock (_random) + return $"test_{_random.Next()}"; + } + + #region Initialization + + [ClassInitialize] + public static void Initialize(TestContext testContext) + { + _context = testContext; + + _hostToken = Environment.GetEnvironmentVariable("discord-unit-host_token"); + _observerToken = Environment.GetEnvironmentVariable("discord-unit-observer_token"); + _targetToken = Environment.GetEnvironmentVariable("discord-unit-target_token"); + } + + [TestMethod] + [Priority(1)] + public async Task TestInitialize() + { + _context.WriteLine("Initializing."); + + _random = new Random(); + + _hostBot = new DiscordSocketClient(_hostToken); + _targetBot = new DiscordSocketClient(_targetToken); + _observerBot = new DiscordSocketClient(_observerToken); + + await _hostBot.Login(); + + await Task.Delay(3000); + + //Cleanup existing Guilds + (await _hostBot.GetGuilds()).Select(x => x.Owner.Id == _hostBot.CurrentUser.Id ? x.Delete() : x.Leave()); + + //Create new Guild and invite the other bots to it + + _testGuild = await _hostBot.CreateGuild("Discord.Net Testing", _hostBot.GetOptimalVoiceRegion()); + + await Task.Delay(1000); + + PublicInvite invite = await _testGuild.CreateInvite(60, 3, false, false); + _testGuildInvite = invite; + + _context.WriteLine($"Host: {_hostBot.CurrentUser.Username} in {(await _hostBot.GetGuilds()).Count()}"); + } + + [TestMethod] + [Priority(2)] + public async Task TestTokenLogin_Ready() + { + AssertEvent( + "READY never received", + async () => await _observerBot.Login(), + x => _observerBot.Connected += x, + x => _observerBot.Connected -= x, + null, + true); + (await _observerBot.GetGuilds()).Select(x => x.Owner.Id == _observerBot.CurrentUser.Id ? x.Delete() : x.Leave()); + await _observerBot.RestClient.Send(new API.Rest.AcceptInviteRequest(_testGuildInvite.Code)); + } + + [TestMethod] + [Priority(2)] + public async Task TestReady() + { + AssertEvent( + "READY never received", + async () => await _targetBot.Login(), + x => _targetBot.Connected += x, + x => _targetBot.Connected -= x, + null, + true); + + (await _targetBot.GetGuilds()).Select(x => x.Owner.Id == _targetBot.CurrentUser.Id ? x.Delete() : x.Leave()); + _testGuildChannel = _testGuild.DefaultChannel; + } + + #endregion + + // Guilds + + #region Guild Tests + + [TestMethod] + [Priority(3)] + public void TestJoinedGuild() + { + AssertEvent( + "Never Got JoinedGuild", + async () => await _targetBot.RestClient.Send(new API.Rest.AcceptInviteRequest(_testGuildInvite.Code)), + x => _targetBot.JoinedGuild += x, + x => _targetBot.JoinedGuild -= x); + } + + #endregion + + #region Channel Tests + + //Channels + [TestMethod] + public void TestCreateTextChannel() + { + GuildChannel channel = null; + string name = GetRandomText(); + AssertEvent( + "ChannelCreated event never received", + async () => channel = await _testGuild.CreateTextChannel(name), + x => _targetBot.ChannelCreated += x, + x => _targetBot.ChannelCreated -= x, + (s, e) => e.Channel.Id == channel.Id); + + AssertEvent( + "ChannelDestroyed event never received", + async () => await channel.Delete(), + x => _targetBot.ChannelDestroyed += x, + x => _targetBot.ChannelDestroyed -= x, + (s, e) => e.Channel.Id == channel.Id); + } + [TestMethod] + public void TestCreateVoiceChannel() + { + GuildChannel channel = null; + string name = GetRandomText(); + AssertEvent( + "ChannelCreated event never received", + async () => channel = await _testGuild.CreateVoiceChannel(name), + x => _targetBot.ChannelCreated += x, + x => _targetBot.ChannelCreated -= x, + (s, e) => e.Channel.Id == channel.Id); + + AssertEvent( + "ChannelDestroyed event never received", + async () => await channel.Delete(), + x => _targetBot.ChannelDestroyed += x, + x => _targetBot.ChannelDestroyed -= x, + (s, e) => e.Channel.Id == channel.Id); + } + + [TestMethod] + [ExpectedException(typeof(Net.HttpException))] + public async Task TestCreateChannel_NoName() + { + await _testGuild.CreateTextChannel($""); + } + [TestMethod] + public async Task Test_CreateGetChannel() + { + var name = GetRandomText(); + var channel = await _testGuild.CreateTextChannel(name); + var get_channel = _testGuild.GetChannel(channel.Id); + Assert.AreEqual(channel.Id, get_channel.Id, "ID of Channel and GetChannel were not equal."); + } + [TestMethod] + public void TestSendTyping() + { + var channel = _testGuildChannel; + AssertEvent( + "UserUpdated event never fired.", + async () => await channel.TriggerTyping(), + x => _targetBot.UserIsTyping += x, + x => _targetBot.UserIsTyping -= x); + } + [TestMethod] + public void TestEditChannel() + { + var channel = _testGuildChannel; + AssertEvent( + "ChannelUpdated Never Received", + async () => await channel.Modify(x => + { + x.Name = GetRandomText(); + x.Topic = $"topic - {GetRandomText()}"; + x.Position = 26; + }), + x => _targetBot.ChannelUpdated += x, + x => _targetBot.ChannelUpdated -= x); + } + [TestMethod] + public void TestChannelMention() + { + var channel = _testGuildChannel; + Assert.AreEqual($"<#{channel.Id}>", channel.Mention, "Generated channel mention was not the expected channel mention."); + } + [TestMethod] + public void TestChannelUserCount() + { + Assert.AreEqual(3, _testGuildChannel.Users.Count(), "Read an incorrect number of users in a channel"); + } + + #endregion + + #region Message Tests + + //Messages + [TestMethod] + public async Task TestMessageEvents() + { + string name = GetRandomText(); + var channel = await _testGuild.CreateTextChannel(name); + _context.WriteLine($"Channel Name: {channel.Name} / {channel.Guild.Name}"); + string text = GetRandomText(); + Message message = null; + AssertEvent( + "MessageCreated event never received", + async () => message = await channel.SendMessage(text), + x => _targetBot.MessageReceived += x, + x => _targetBot.MessageReceived -= x, + (s, e) => e.Message.Text == text); + + AssertEvent( + "MessageUpdated event never received", + async () => await message.Modify(x => + { + x.Text = text + " updated"; + }), + x => _targetBot.MessageUpdated += x, + x => _targetBot.MessageUpdated -= x, + (s, e) => e.Before.Text == text && e.After.Text == text + " updated"); + + AssertEvent( + "MessageDeleted event never received", + async () => await message.Delete(), + x => _targetBot.MessageDeleted += x, + x => _targetBot.MessageDeleted -= x, + (s, e) => e.Message.Id == message.Id); + } + [TestMethod] + public async Task TestDownloadMessages() + { + string name = GetRandomText(); + var channel = await _testGuild.CreateTextChannel(name); + for (var i = 0; i < 10; i++) await channel.SendMessage(GetRandomText()); + while (channel.Discord.MessageQueue.Count > 0) await Task.Delay(100); + var messages = await channel.GetMessages(10); + Assert.AreEqual(10, messages.Count(), "Expected 10 messages in downloaded array, did not see 10."); + } + [TestMethod] + public async Task TestSendTTSMessage() + { + var channel = await _testGuild.CreateTextChannel(GetRandomText()); + AssertEvent( + "MessageCreated event never fired", + async () => await channel.SendMessage(GetRandomText(), true), + x => _targetBot.MessageReceived += x, + x => _targetBot.MessageReceived -= x, + (s, e) => e.Message.IsTTS); + } + + #endregion + + #region User Tests + + [TestMethod] + public async Task TestUserMentions() + { + var user = (await _targetBot.GetGuild(_testGuild.Id)).CurrentUser; + Assert.AreEqual($"<@{user.Id}>", user.Mention); + } + [TestMethod] + public void TestUserEdit() + { + var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); + AssertEvent( + "UserUpdated never fired", + async () => await user.Modify(true, true, null, null), + x => _targetBot.UserUpdated += x, + x => _targetBot.UserUpdated -= x); + } + [TestMethod] + public void TestEditSelf() + { + throw new NotImplementedException(); + /*var name = RandomText + AssertEvent( + "UserUpdated never fired", + async () => await _targetBot.CurrentUser.Modify(TargetPassword, name), + x => _obGuildBot.UserUpdated += x, + x => _obGuildBot.UserUpdated -= x, + (s, e) => e.After.Username == name);*/ + } + [TestMethod] + public void TestSetStatus() + { + AssertEvent( + "UserUpdated never fired", + async () => await SetStatus(_targetBot, UserStatus.Idle), + x => _observerBot.UserUpdated += x, + x => _observerBot.UserUpdated -= x, + (s, e) => e.After.Status == UserStatus.Idle); + } + private async Task SetStatus(DiscordClient _client, UserStatus status) + { + throw new NotImplementedException(); + /*_client.SetStatus(status); + await Task.Delay(50);*/ + } + [TestMethod] + public void TestSetGame() + { + AssertEvent( + "UserUpdated never fired", + async () => await SetGame(_targetBot, "test game"), + x => _observerBot.UserUpdated += x, + x => _observerBot.UserUpdated -= x, + (s, e) => _targetBot.CurrentUser.CurrentGame == "test game"); + + } + private async Task SetGame(DiscordClient _client, string game) + { + throw new NotImplementedException(); + //_client.SetGame(game); + //await Task.Delay(5); + } + + #endregion + + #region Permission Tests + + // Permissions + [TestMethod] + public async Task Test_AddGet_PermissionsRule() + { + var channel = await _testGuild.CreateTextChannel(GetRandomText()); + var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); + var perms = new OverwritePermissions(sendMessages: PermValue.Deny); + await channel.UpdatePermissionOverwrite(user, perms); + var resultPerms = channel.GetPermissionOverwrite(user); + Assert.IsNotNull(resultPerms, "Perms retrieved from Guild were null."); + } + [TestMethod] + public async Task Test_AddRemove_PermissionsRule() + { + var channel = await _testGuild.CreateTextChannel(GetRandomText()); + var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); + var perms = new OverwritePermissions(sendMessages: PermValue.Deny); + await channel.UpdatePermissionOverwrite(user, perms); + await channel.RemovePermissionOverwrite(user); + await Task.Delay(200); + Assert.AreEqual(PermValue.Inherit, channel.GetPermissionOverwrite(user)?.SendMessages); + } + [TestMethod] + public async Task Test_Permissions_Event() + { + var channel = await _testGuild.CreateTextChannel(GetRandomText()); + var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); + var perms = new OverwritePermissions(sendMessages: PermValue.Deny); + AssertEvent + ("ChannelUpdatedEvent never fired.", + async () => await channel.UpdatePermissionOverwrite(user, perms), + x => _targetBot.ChannelUpdated += x, + x => _targetBot.ChannelUpdated -= x, + (s, e) => e.Channel == channel && (e.After as GuildChannel).PermissionOverwrites.Count() != (e.Before as GuildChannel).PermissionOverwrites.Count()); + } + [TestMethod] + [ExpectedException(typeof(Net.HttpException))] + public async Task Test_Affect_Permissions_Invalid_Channel() + { + var channel = await _testGuild.CreateTextChannel(GetRandomText()); + var user = _testGuild.GetUser(_targetBot.CurrentUser.Id); + var perms = new OverwritePermissions(sendMessages: PermValue.Deny); + await channel.Delete(); + await channel.UpdatePermissionOverwrite(user, perms); + } + + #endregion + + + [ClassCleanup] + public static async Task Cleanup() + { + WaitMany( + (await _hostBot.GetGuilds()).Select(x => x.Owner.Id == _hostBot.CurrentUser.Id ? x.Delete() : x.Leave()), + (await _targetBot.GetGuilds()).Select(x => x.Owner.Id == _targetBot.CurrentUser.Id ? x.Delete() : x.Leave()), + (await _observerBot.GetGuilds()).Select(x => x.Owner.Id == _observerBot.CurrentUser.Id ? x.Delete() : x.Leave())); + + WaitAll( + _hostBot.Disconnect(), + _targetBot.Disconnect(), + _observerBot.Disconnect()); + } + + #region Helpers + + // Task Helpers + + private static void AssertEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test = null) + { + AssertEvent(msg, action, addEvent, removeEvent, test, true); + } + private static void AssertNoEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test = null) + { + AssertEvent(msg, action, addEvent, removeEvent, test, false); + } + private static void AssertEvent(string msg, Func action, Action> addEvent, Action> removeEvent, Func test, bool assertTrue) + { + ManualResetEventSlim trigger = new ManualResetEventSlim(false); + bool result = false; + + EventHandler handler = (s, e) => + { + if (test != null) + { + result |= test(s, e); + trigger.Set(); + } + else + result = true; + }; + + addEvent(handler); + var task = action(); + trigger.Wait(EventTimeout); + task.Wait(); + removeEvent(handler); + + Assert.AreEqual(assertTrue, result, msg); + } + + private static void AssertEvent(string msg, Func action, Action addEvent, Action removeEvent, Func test, bool assertTrue) + { + ManualResetEventSlim trigger = new ManualResetEventSlim(false); + bool result = false; + + EventHandler handler = (s, e) => + { + if (test != null) + { + result |= test(s); + trigger.Set(); } - else - result = true; - }; - - addEvent(handler); - var task = action(); - trigger.Wait(EventTimeout); - task.Wait(); - removeEvent(handler); - - Assert.AreEqual(assertTrue, result, msg); - } - - private static void WaitAll(params Task[] tasks) - { - Task.WaitAll(tasks); - } - private static void WaitAll(IEnumerable tasks) - { - Task.WaitAll(tasks.ToArray()); - } - private static void WaitMany(params IEnumerable[] tasks) - { - Task.WaitAll(tasks.Where(x => x != null).SelectMany(x => x).ToArray()); - } - } + else + result = true; + }; + + addEvent(handler); + var task = action(); + trigger.Wait(EventTimeout); + task.Wait(); + removeEvent(handler); + + Assert.AreEqual(assertTrue, result, msg); + } + + private static void WaitAll(params Task[] tasks) + { + Task.WaitAll(tasks); + } + private static void WaitAll(IEnumerable tasks) + { + Task.WaitAll(tasks.ToArray()); + } + private static void WaitMany(params IEnumerable[] tasks) + { + Task.WaitAll(tasks.Where(x => x != null).SelectMany(x => x).ToArray()); + } + + #endregion + } }